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