1 /*- 2 * Copyright (c) 2003-2007 Tim Kientzle 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 #include "test.h" 26 __FBSDID("$FreeBSD$"); 27 28 #if defined(__CYGWIN__) 29 # include <limits.h> 30 # include <sys/cygwin.h> 31 #endif 32 #if defined(_WIN32) && !defined(__CYGWIN__) 33 # include <direct.h> 34 #endif 35 36 /* 37 * Try to figure out how deep we can go in our tests. Assumes that 38 * the first call to this function has the longest starting cwd (which 39 * is currently "<testdir>/original"). This is mostly to work around 40 * limits in our Win32 support. 41 * 42 * Background: On Posix systems, PATH_MAX is merely a limit on the 43 * length of the string passed into a system call. By repeatedly 44 * calling chdir(), you can work with arbitrarily long paths on such 45 * systems. In contrast, Win32 APIs apply PATH_MAX limits to the full 46 * absolute path, so the permissible length of a system call argument 47 * varies with the cwd. Some APIs actually enforce limits 48 * significantly less than PATH_MAX to ensure that you can create 49 * files within the current working directory. The Win32 limits also 50 * apply to Cygwin before 1.7. 51 * 52 * Someday, I want to convert the Win32 support to use newer 53 * wide-character paths with '\\?\' prefix, which has a 32k PATH_MAX 54 * instead of the rather anemic 260 character limit of the older 55 * system calls. Then we can drop this mess (unless we want to 56 * continue to special-case Cygwin 1.5 and earlier). 57 */ 58 static int 59 compute_loop_max(void) 60 { 61 #if defined(_WIN32) && !defined(__CYGWIN__) 62 static int LOOP_MAX = 0; 63 char buf[MAX_PATH]; 64 size_t cwdlen; 65 66 if (LOOP_MAX == 0) { 67 assert(_getcwd(buf, MAX_PATH) != NULL); 68 cwdlen = strlen(buf); 69 /* 12 characters = length of 8.3 filename */ 70 /* 4 characters = length of "/../" used in symlink tests */ 71 /* 1 character = length of extra "/" separator */ 72 LOOP_MAX = MAX_PATH - (int)cwdlen - 12 - 4 - 1; 73 } 74 return LOOP_MAX; 75 #elif defined(__CYGWIN__) && !defined(HAVE_CYGWIN_CONV_PATH) 76 static int LOOP_MAX = 0; 77 if (LOOP_MAX == 0) { 78 char wbuf[PATH_MAX]; 79 char pbuf[PATH_MAX]; 80 size_t wcwdlen; 81 size_t pcwdlen; 82 size_t cwdlen; 83 assert(getcwd(pbuf, PATH_MAX) != NULL); 84 pcwdlen = strlen(pbuf); 85 cygwin_conv_to_full_win32_path(pbuf, wbuf); 86 wcwdlen = strlen(wbuf); 87 cwdlen = ((wcwdlen > pcwdlen) ? wcwdlen : pcwdlen); 88 /* Cygwin helper needs an extra few characters. */ 89 LOOP_MAX = PATH_MAX - (int)cwdlen - 12 - 4 - 4; 90 } 91 return LOOP_MAX; 92 #else 93 /* cygwin-1.7 ends up here, along with "normal" unix */ 94 return 200; /* restore pre-r278 depth */ 95 #endif 96 } 97 98 /* filenames[i] is a distinctive filename of length i. */ 99 /* To simplify interpreting failures, each filename ends with a 100 * decimal integer which is the length of the filename. E.g., A 101 * filename ending in "_92" is 92 characters long. To detect errors 102 * which drop or misplace characters, the filenames use a repeating 103 * "abcdefghijklmnopqrstuvwxyz..." pattern. */ 104 static char *filenames[201]; 105 106 static void 107 compute_filenames(void) 108 { 109 char buff[250]; 110 size_t i,j; 111 112 filenames[0] = strdup(""); 113 filenames[1] = strdup("1"); 114 filenames[2] = strdup("a2"); 115 for (i = 3; i < sizeof(filenames)/sizeof(filenames[0]); ++i) { 116 /* Fill with "abcdefghij..." */ 117 for (j = 0; j < i; ++j) 118 buff[j] = 'a' + (j % 26); 119 buff[j--] = '\0'; 120 /* Work from the end to fill in the number portion. */ 121 buff[j--] = '0' + (i % 10); 122 if (i > 9) { 123 buff[j--] = '0' + ((i / 10) % 10); 124 if (i > 99) 125 buff[j--] = '0' + (char)(i / 100); 126 } 127 buff[j] = '_'; 128 /* Guard against obvious screwups in the above code. */ 129 assertEqualInt(strlen(buff), i); 130 filenames[i] = strdup(buff); 131 } 132 } 133 134 static void 135 create_tree(void) 136 { 137 char buff[260]; 138 char buff2[260]; 139 int i; 140 int LOOP_MAX; 141 142 compute_filenames(); 143 144 /* Log that we'll be omitting some checks. */ 145 if (!canSymlink()) { 146 skipping("Symlink checks"); 147 } 148 149 assertMakeDir("original", 0775); 150 assertEqualInt(0, chdir("original")); 151 LOOP_MAX = compute_loop_max(); 152 153 assertMakeDir("f", 0775); 154 assertMakeDir("l", 0775); 155 assertMakeDir("m", 0775); 156 assertMakeDir("s", 0775); 157 assertMakeDir("d", 0775); 158 159 for (i = 1; i < LOOP_MAX; i++) { 160 failure("Internal sanity check failed: i = %d", i); 161 assert(filenames[i] != NULL); 162 163 sprintf(buff, "f/%s", filenames[i]); 164 assertMakeFile(buff, 0777, buff); 165 166 /* Create a link named "l/abcdef..." to the above. */ 167 sprintf(buff2, "l/%s", filenames[i]); 168 assertMakeHardlink(buff2, buff); 169 170 /* Create a link named "m/abcdef..." to the above. */ 171 sprintf(buff2, "m/%s", filenames[i]); 172 assertMakeHardlink(buff2, buff); 173 174 if (canSymlink()) { 175 /* Create a symlink named "s/abcdef..." to the above. */ 176 sprintf(buff, "s/%s", filenames[i]); 177 sprintf(buff2, "../f/%s", filenames[i]); 178 failure("buff=\"%s\" buff2=\"%s\"", buff, buff2); 179 assertMakeSymlink(buff, buff2, 0); 180 } 181 /* Create a dir named "d/abcdef...". */ 182 buff[0] = 'd'; 183 failure("buff=\"%s\"", buff); 184 assertMakeDir(buff, 0775); 185 } 186 187 assertEqualInt(0, chdir("..")); 188 } 189 190 #define LIMIT_NONE 200 191 #define LIMIT_USTAR 100 192 193 static void 194 verify_tree(size_t limit) 195 { 196 char name1[260]; 197 char name2[260]; 198 size_t i, LOOP_MAX; 199 200 LOOP_MAX = compute_loop_max(); 201 202 /* Generate the names we know should be there and verify them. */ 203 for (i = 1; i < LOOP_MAX; i++) { 204 /* Verify a file named "f/abcdef..." */ 205 sprintf(name1, "f/%s", filenames[i]); 206 if (i <= limit) { 207 assertFileExists(name1); 208 assertFileContents(name1, (int)strlen(name1), name1); 209 } 210 211 sprintf(name2, "l/%s", filenames[i]); 212 if (i + 2 <= limit) { 213 /* Verify hardlink "l/abcdef..." */ 214 assertIsHardlink(name1, name2); 215 /* Verify hardlink "m/abcdef..." */ 216 name2[0] = 'm'; 217 assertIsHardlink(name1, name2); 218 } 219 220 if (canSymlink()) { 221 /* Verify symlink "s/abcdef..." */ 222 sprintf(name1, "s/%s", filenames[i]); 223 sprintf(name2, "../f/%s", filenames[i]); 224 if (strlen(name2) <= limit) 225 assertIsSymlink(name1, name2, 0); 226 } 227 228 /* Verify dir "d/abcdef...". */ 229 sprintf(name1, "d/%s", filenames[i]); 230 if (i + 1 <= limit) { /* +1 for trailing slash */ 231 if (assertIsDir(name1, -1)) { 232 /* TODO: opendir/readdir this 233 * directory and make sure 234 * it's empty. 235 */ 236 } 237 } 238 } 239 240 #if !defined(_WIN32) || defined(__CYGWIN__) 241 { 242 const char *dp; 243 /* Now make sure nothing is there that shouldn't be. */ 244 for (dp = "dflms"; *dp != '\0'; ++dp) { 245 DIR *d; 246 struct dirent *de; 247 char dir[2]; 248 dir[0] = *dp; dir[1] = '\0'; 249 d = opendir(dir); 250 failure("Unable to open dir '%s'", dir); 251 if (!assert(d != NULL)) 252 continue; 253 while ((de = readdir(d)) != NULL) { 254 char *p = de->d_name; 255 if (p[0] == '.') 256 continue; 257 switch(dp[0]) { 258 case 'l': case 'm': case 'd': 259 failure("strlen(p)=%zu", strlen(p)); 260 assert(strlen(p) < limit); 261 assertEqualString(p, 262 filenames[strlen(p)]); 263 break; 264 case 'f': case 's': 265 failure("strlen(p)=%zu", strlen(p)); 266 assert(strlen(p) < limit + 1); 267 assertEqualString(p, 268 filenames[strlen(p)]); 269 break; 270 default: 271 failure("File %s shouldn't be here", p); 272 assert(0); 273 } 274 } 275 closedir(d); 276 } 277 } 278 #endif 279 } 280 281 static void 282 copy_basic(void) 283 { 284 int r; 285 286 /* NOTE: for proper operation on cygwin-1.5 and windows, the 287 * length of the name of the directory below, "plain", must be 288 * less than or equal to the length of the name of the original 289 * directory, "original" This restriction derives from the 290 * extremely limited pathname lengths on those platforms. 291 */ 292 assertMakeDir("plain", 0775); 293 assertEqualInt(0, chdir("plain")); 294 295 /* 296 * Use the tar program to create an archive. 297 */ 298 r = systemf("%s cf archive -C ../original f d l m s >pack.out 2>pack.err", 299 testprog); 300 failure("Error invoking \"%s cf\"", testprog); 301 assertEqualInt(r, 0); 302 303 /* Verify that nothing went to stdout or stderr. */ 304 assertEmptyFile("pack.err"); 305 assertEmptyFile("pack.out"); 306 307 /* 308 * Use tar to unpack the archive into another directory. 309 */ 310 r = systemf("%s xf archive >unpack.out 2>unpack.err", testprog); 311 failure("Error invoking %s xf archive", testprog); 312 assertEqualInt(r, 0); 313 314 /* Verify that nothing went to stdout or stderr. */ 315 assertEmptyFile("unpack.err"); 316 assertEmptyFile("unpack.out"); 317 318 verify_tree(LIMIT_NONE); 319 assertEqualInt(0, chdir("..")); 320 } 321 322 static void 323 copy_ustar(void) 324 { 325 const char *target = "ustar"; 326 int r; 327 328 /* NOTE: for proper operation on cygwin-1.5 and windows, the 329 * length of the name of the directory below, "ustar", must be 330 * less than or equal to the length of the name of the original 331 * directory, "original" This restriction derives from the 332 * extremely limited pathname lengths on those platforms. 333 */ 334 assertMakeDir(target, 0775); 335 assertEqualInt(0, chdir(target)); 336 337 /* 338 * Use the tar program to create an archive. 339 */ 340 r = systemf("%s cf archive --format=ustar -C ../original f d l m s >pack.out 2>pack.err", 341 testprog); 342 failure("Error invoking \"%s cf archive --format=ustar\"", testprog); 343 assertEqualInt(r, 0); 344 345 /* Verify that nothing went to stdout. */ 346 assertEmptyFile("pack.out"); 347 /* Stderr is non-empty, since there are a bunch of files 348 * with filenames too long to archive. */ 349 350 /* 351 * Use tar to unpack the archive into another directory. 352 */ 353 r = systemf("%s xf archive >unpack.out 2>unpack.err", testprog); 354 failure("Error invoking %s xf archive", testprog); 355 assertEqualInt(r, 0); 356 357 /* Verify that nothing went to stdout or stderr. */ 358 assertEmptyFile("unpack.err"); 359 assertEmptyFile("unpack.out"); 360 361 verify_tree(LIMIT_USTAR); 362 assertEqualInt(0, chdir("../..")); 363 } 364 365 DEFINE_TEST(test_copy) 366 { 367 assertUmask(0); 368 create_tree(); /* Create sample files in "original" dir. */ 369 370 /* Test simple "tar -c | tar -x" pipeline copy. */ 371 copy_basic(); 372 373 /* Same, but constrain to ustar format. */ 374 copy_ustar(); 375 } 376