test_copy.c revision 248616
1139823Simp/*- 21541Srgrimes * Copyright (c) 2003-2007 Tim Kientzle 31541Srgrimes * All rights reserved. 4137668Smlaier * 51541Srgrimes * Redistribution and use in source and binary forms, with or without 61541Srgrimes * modification, are permitted provided that the following conditions 71541Srgrimes * are met: 81541Srgrimes * 1. Redistributions of source code must retain the above copyright 91541Srgrimes * notice, this list of conditions and the following disclaimer. 101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111541Srgrimes * notice, this list of conditions and the following disclaimer in the 121541Srgrimes * documentation and/or other materials provided with the distribution. 131541Srgrimes * 141541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 151541Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 161541Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 171541Srgrimes * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 181541Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 191541Srgrimes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 201541Srgrimes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 211541Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 221541Srgrimes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 231541Srgrimes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 241541Srgrimes */ 251541Srgrimes#include "test.h" 261541Srgrimes__FBSDID("$FreeBSD: head/contrib/libarchive/tar/test/test_copy.c 248616 2013-03-22 13:36:03Z mm $"); 271541Srgrimes 281541Srgrimes#if defined(__CYGWIN__) 291541Srgrimes# include <limits.h> 3010939Swollman# include <sys/cygwin.h> 311541Srgrimes#endif 321541Srgrimes#if defined(_WIN32) && !defined(__CYGWIN__) 33172467Ssilby# include <direct.h> 34172467Ssilby#endif 35172467Ssilby 36204902Sqingli/* 37143868Sglebius * Try to figure out how deep we can go in our tests. Assumes that 381541Srgrimes * the first call to this function has the longest starting cwd (which 391549Srgrimes * is currently "<testdir>/original"). This is mostly to work around 4024204Sbde * limits in our Win32 support. 411541Srgrimes * 42164033Srwatson * Background: On Posix systems, PATH_MAX is merely a limit on the 431541Srgrimes * length of the string passed into a system call. By repeatedly 44186948Sbz * calling chdir(), you can work with arbitrarily long paths on such 4512704Sphk * systems. In contrast, Win32 APIs apply PATH_MAX limits to the full 46186948Sbz * absolute path, so the permissible length of a system call argument 4712704Sphk * varies with the cwd. Some APIs actually enforce limits 48192011Sqingli * significantly less than PATH_MAX to ensure that you can create 491541Srgrimes * files within the current working directory. The Win32 limits also 501541Srgrimes * apply to Cygwin before 1.7. 51195914Sqingli * 52215207Sgnn * Someday, I want to convert the Win32 support to use newer 53192011Sqingli * wide-character paths with '\\?\' prefix, which has a 32k PATH_MAX 54186119Sqingli * instead of the rather anemic 260 character limit of the older 5555009Sshin * system calls. Then we can drop this mess (unless we want to 561541Srgrimes * continue to special-case Cygwin 1.5 and earlier). 57192011Sqingli */ 581541Srgrimesstatic int 59228571Sglebiuscompute_loop_max(void) 601541Srgrimes{ 611541Srgrimes#if defined(_WIN32) && !defined(__CYGWIN__) 6281127Sume static int LOOP_MAX = 0; 63170613Sbms char buf[MAX_PATH]; 64228571Sglebius size_t cwdlen; 65189592Sbms 66195699Srwatson if (LOOP_MAX == 0) { 67195699Srwatson assert(_getcwd(buf, MAX_PATH) != NULL); 681541Srgrimes cwdlen = strlen(buf); 6992723Salfred /* 12 characters = length of 8.3 filename */ 7092723Salfred /* 4 characters = length of "/../" used in symlink tests */ 7192723Salfred /* 1 character = length of extra "/" separator */ 7292723Salfred LOOP_MAX = MAX_PATH - (int)cwdlen - 12 - 4 - 1; 7355009Sshin } 7492723Salfred return LOOP_MAX; 75228571Sglebius#elif defined(__CYGWIN__) && !defined(HAVE_CYGWIN_CONV_PATH) 76230207Sglebius static int LOOP_MAX = 0; 77167729Sbms if (LOOP_MAX == 0) { 781541Srgrimes char wbuf[PATH_MAX]; 79228571Sglebius char pbuf[PATH_MAX]; 80228571Sglebius size_t wcwdlen; 81228571Sglebius size_t pcwdlen; 82228571Sglebius size_t cwdlen; 83149221Sglebius assert(getcwd(pbuf, PATH_MAX) != NULL); 8421666Swollman pcwdlen = strlen(pbuf); 85207369Sbz cygwin_conv_to_full_win32_path(pbuf, wbuf); 86207369Sbz wcwdlen = strlen(wbuf); 87207369Sbz cwdlen = ((wcwdlen > pcwdlen) ? wcwdlen : pcwdlen); 88215207Sgnn /* Cygwin helper needs an extra few characters. */ 89215207Sgnn LOOP_MAX = PATH_MAX - (int)cwdlen - 12 - 4 - 4; 90215207Sgnn } 911541Srgrimes return LOOP_MAX; 921541Srgrimes#else 93226401Sglebius /* cygwin-1.7 ends up here, along with "normal" unix */ 941541Srgrimes return 200; /* restore pre-r278 depth */ 951549Srgrimes#endif 96169454Srwatson} 971541Srgrimes 981541Srgrimes/* filenames[i] is a distinctive filename of length i. */ 991541Srgrimes/* To simplify interpreting failures, each filename ends with a 1001541Srgrimes * decimal integer which is the length of the filename. E.g., A 101194951Srwatson * filename ending in "_92" is 92 characters long. To detect errors 102226401Sglebius * which drop or misplace characters, the filenames use a repeating 103226401Sglebius * "abcdefghijklmnopqrstuvwxyz..." pattern. */ 104226401Sglebiusstatic char *filenames[201]; 105226401Sglebius 106194951Srwatsonstatic void 1071541Srgrimescompute_filenames(void) 108194951Srwatson{ 1091541Srgrimes char buff[250]; 1101541Srgrimes size_t i,j; 1111541Srgrimes 1121541Srgrimes filenames[0] = strdup(""); 113133486Sandre filenames[1] = strdup("1"); 114133486Sandre filenames[2] = strdup("a2"); 115133486Sandre for (i = 3; i < sizeof(filenames)/sizeof(filenames[0]); ++i) { 116133486Sandre /* Fill with "abcdefghij..." */ 117169454Srwatson for (j = 0; j < i; ++j) 118133486Sandre buff[j] = 'a' + (j % 26); 119133486Sandre buff[j--] = '\0'; 120133486Sandre /* Work from the end to fill in the number portion. */ 121194951Srwatson buff[j--] = '0' + (i % 10); 122133486Sandre if (i > 9) { 123194951Srwatson buff[j--] = '0' + ((i / 10) % 10); 124194951Srwatson if (i > 99) 125184295Sbz buff[j--] = '0' + (char)(i / 100); 126194951Srwatson } 127133486Sandre buff[j] = '_'; 128194951Srwatson /* Guard against obvious screwups in the above code. */ 129184295Sbz assertEqualInt(strlen(buff), i); 130133486Sandre filenames[i] = strdup(buff); 131133486Sandre } 132133486Sandre} 1331541Srgrimes 1341541Srgrimesstatic void 1351541Srgrimescreate_tree(void) 1361541Srgrimes{ 1371549Srgrimes char buff[260]; 138169454Srwatson char buff2[260]; 1391541Srgrimes int i; 1401541Srgrimes int LOOP_MAX; 1411541Srgrimes 1421541Srgrimes compute_filenames(); 143166450Sbms 1441541Srgrimes /* Log that we'll be omitting some checks. */ 1451541Srgrimes if (!canSymlink()) { 1461541Srgrimes skipping("Symlink checks"); 1471541Srgrimes } 1481541Srgrimes 1491541Srgrimes assertMakeDir("original", 0775); 1501541Srgrimes assertEqualInt(0, chdir("original")); 1511541Srgrimes LOOP_MAX = compute_loop_max(); 1521541Srgrimes 1531541Srgrimes assertMakeDir("f", 0775); 1541541Srgrimes assertMakeDir("l", 0775); 1551541Srgrimes assertMakeDir("m", 0775); 15612296Sphk assertMakeDir("s", 0775); 157169454Srwatson assertMakeDir("d", 0775); 1581541Srgrimes 1591541Srgrimes for (i = 1; i < LOOP_MAX; i++) { 1601541Srgrimes failure("Internal sanity check failed: i = %d", i); 1611541Srgrimes assert(filenames[i] != NULL); 1621541Srgrimes 1634127Swollman sprintf(buff, "f/%s", filenames[i]); 164133874Srwatson assertMakeFile(buff, 0777, buff); 1651541Srgrimes 1661541Srgrimes /* Create a link named "l/abcdef..." to the above. */ 1671541Srgrimes sprintf(buff2, "l/%s", filenames[i]); 1681541Srgrimes assertMakeHardlink(buff2, buff); 1691541Srgrimes 17055009Sshin /* Create a link named "m/abcdef..." to the above. */ 17155009Sshin sprintf(buff2, "m/%s", filenames[i]); 17255009Sshin assertMakeHardlink(buff2, buff); 17355009Sshin 17455009Sshin if (canSymlink()) { 17555009Sshin /* Create a symlink named "s/abcdef..." to the above. */ 17655009Sshin sprintf(buff, "s/%s", filenames[i]); 17755009Sshin sprintf(buff2, "../f/%s", filenames[i]); 17855009Sshin failure("buff=\"%s\" buff2=\"%s\"", buff, buff2); 17955009Sshin assertMakeSymlink(buff, buff2); 18055009Sshin } 18155009Sshin /* Create a dir named "d/abcdef...". */ 18255009Sshin buff[0] = 'd'; 18355009Sshin failure("buff=\"%s\"", buff); 18455009Sshin assertMakeDir(buff, 0775); 18555009Sshin } 18655009Sshin 18755009Sshin assertEqualInt(0, chdir("..")); 18855009Sshin} 189184295Sbz 19055009Sshin#define LIMIT_NONE 200 19155009Sshin#define LIMIT_USTAR 100 19255009Sshin 193169454Srwatsonstatic void 19455009Sshinverify_tree(size_t limit) 19555009Sshin{ 19655009Sshin char name1[260]; 19755009Sshin char name2[260]; 19855009Sshin size_t i, LOOP_MAX; 19955009Sshin 20055009Sshin LOOP_MAX = compute_loop_max(); 20155009Sshin 20255009Sshin /* Generate the names we know should be there and verify them. */ 20355009Sshin for (i = 1; i < LOOP_MAX; i++) { 20455009Sshin /* Verify a file named "f/abcdef..." */ 20555009Sshin sprintf(name1, "f/%s", filenames[i]); 2061541Srgrimes if (i <= limit) { 2071541Srgrimes assertFileExists(name1); 208191443Srwatson assertFileContents(name1, (int)strlen(name1), name1); 209191443Srwatson } 2101541Srgrimes 2111541Srgrimes sprintf(name2, "l/%s", filenames[i]); 2121549Srgrimes if (i + 2 <= limit) { 213169454Srwatson /* Verify hardlink "l/abcdef..." */ 214169454Srwatson assertIsHardlink(name1, name2); 2151541Srgrimes /* Verify hardlink "m/abcdef..." */ 2161541Srgrimes name2[0] = 'm'; 217184295Sbz assertIsHardlink(name1, name2); 2181541Srgrimes } 219168032Sbms 22084102Sjlemon if (canSymlink()) { 221189592Sbms /* Verify symlink "s/abcdef..." */ 2221541Srgrimes sprintf(name1, "s/%s", filenames[i]); 223194951Srwatson sprintf(name2, "../f/%s", filenames[i]); 224168032Sbms if (strlen(name2) <= limit) 225228768Sglebius assertIsSymlink(name1, name2); 2261541Srgrimes } 227228768Sglebius 228228768Sglebius /* Verify dir "d/abcdef...". */ 229228768Sglebius sprintf(name1, "d/%s", filenames[i]); 230228768Sglebius if (i + 1 <= limit) { /* +1 for trailing slash */ 231228768Sglebius if (assertIsDir(name1, -1)) { 232228768Sglebius /* TODO: opendir/readdir this 233228768Sglebius * directory and make sure 234184295Sbz * it's empty. 235168032Sbms */ 23687124Sbrian } 237168032Sbms } 23887124Sbrian } 239191443Srwatson 240191443Srwatson#if !defined(_WIN32) || defined(__CYGWIN__) 241191443Srwatson { 242191443Srwatson const char *dp; 24355009Sshin /* Now make sure nothing is there that shouldn't be. */ 244191443Srwatson for (dp = "dflms"; *dp != '\0'; ++dp) { 245191443Srwatson DIR *d; 246191443Srwatson struct dirent *de; 247191443Srwatson char dir[2]; 248227791Sglebius dir[0] = *dp; dir[1] = '\0'; 249227791Sglebius d = opendir(dir); 250227791Sglebius failure("Unable to open dir '%s'", dir); 251227791Sglebius if (!assert(d != NULL)) 252227791Sglebius continue; 253227791Sglebius while ((de = readdir(d)) != NULL) { 254227791Sglebius char *p = de->d_name; 255227791Sglebius if (p[0] == '.') 256227791Sglebius continue; 257227791Sglebius switch(dp[0]) { 258227791Sglebius case 'l': case 'm': case 'd': 259227831Sglebius failure("strlen(p)=%d", strlen(p)); 260227831Sglebius assert(strlen(p) < limit); 261227791Sglebius assertEqualString(p, 262227791Sglebius filenames[strlen(p)]); 263228768Sglebius break; 264228768Sglebius case 'f': case 's': 265228768Sglebius failure("strlen(p)=%d", strlen(p)); 266228768Sglebius assert(strlen(p) < limit + 1); 267228768Sglebius assertEqualString(p, 268228768Sglebius filenames[strlen(p)]); 269228768Sglebius break; 270227791Sglebius default: 271227791Sglebius failure("File %s shouldn't be here", p); 272227791Sglebius assert(0); 273227791Sglebius } 274228768Sglebius } 275227791Sglebius closedir(d); 276191443Srwatson } 277191443Srwatson } 278191443Srwatson#endif 279191443Srwatson} 280230207Sglebius 281230207Sglebiusstatic void 282191443Srwatsoncopy_basic(void) 28355009Sshin{ 284164033Srwatson int r; 285164033Srwatson 286164033Srwatson /* NOTE: for proper operation on cygwin-1.5 and windows, the 287164033Srwatson * length of the name of the directory below, "plain", must be 288164033Srwatson * less than or equal to the lengthe of the name of the original 289184295Sbz * directory, "original" This restriction derives from the 290184295Sbz * extremely limited pathname lengths on those platforms. 291164033Srwatson */ 292164033Srwatson assertMakeDir("plain", 0775); 29355009Sshin assertEqualInt(0, chdir("plain")); 294164033Srwatson 295164033Srwatson /* 296164033Srwatson * Use the tar program to create an archive. 297164033Srwatson */ 298164033Srwatson r = systemf("%s cf archive -C ../original f d l m s >pack.out 2>pack.err", 299184295Sbz testprog); 300184295Sbz failure("Error invoking \"%s cf\"", testprog); 301164033Srwatson assertEqualInt(r, 0); 302164033Srwatson 30355009Sshin /* Verify that nothing went to stdout or stderr. */ 304184295Sbz assertEmptyFile("pack.err"); 305184295Sbz assertEmptyFile("pack.out"); 30683366Sjulian 307191443Srwatson /* 308191443Srwatson * Use tar to unpack the archive into another directory. 309191443Srwatson */ 310191443Srwatson r = systemf("%s xf archive >unpack.out 2>unpack.err", testprog); 311191443Srwatson failure("Error invoking %s xf archive", testprog); 31255009Sshin assertEqualInt(r, 0); 31355009Sshin 314191443Srwatson /* Verify that nothing went to stdout or stderr. */ 315191443Srwatson assertEmptyFile("unpack.err"); 316191443Srwatson assertEmptyFile("unpack.out"); 3171541Srgrimes 318191456Srwatson verify_tree(LIMIT_NONE); 319191456Srwatson assertEqualInt(0, chdir("..")); 320191456Srwatson} 321191456Srwatson 322191456Srwatsonstatic void 323191456Srwatsoncopy_ustar(void) 324191456Srwatson{ 325191456Srwatson const char *target = "ustar"; 326191456Srwatson int r; 327191456Srwatson 328191456Srwatson /* NOTE: for proper operation on cygwin-1.5 and windows, the 329191456Srwatson * length of the name of the directory below, "ustar", must be 330191456Srwatson * less than or equal to the lengthe of the name of the original 331191456Srwatson * directory, "original" This restriction derives from the 332191456Srwatson * extremely limited pathname lengths on those platforms. 333191456Srwatson */ 334191456Srwatson assertMakeDir(target, 0775); 335191456Srwatson assertEqualInt(0, chdir(target)); 336191456Srwatson 337191456Srwatson /* 338191456Srwatson * Use the tar program to create an archive. 3391541Srgrimes */ 34014632Sfenner r = systemf("%s cf archive --format=ustar -C ../original f d l m s >pack.out 2>pack.err", 341191443Srwatson testprog); 342191443Srwatson failure("Error invoking \"%s cf archive --format=ustar\"", testprog); 3431541Srgrimes assertEqualInt(r, 0); 344191443Srwatson 345194951Srwatson /* Verify that nothing went to stdout. */ 346191443Srwatson assertEmptyFile("pack.out"); 347191443Srwatson /* Stderr is non-empty, since there are a bunch of files 348191443Srwatson * with filenames too long to archive. */ 349191443Srwatson 350191443Srwatson /* 351191443Srwatson * Use tar to unpack the archive into another directory. 352191443Srwatson */ 353191443Srwatson r = systemf("%s xf archive >unpack.out 2>unpack.err", testprog); 354191443Srwatson failure("Error invoking %s xf archive", testprog); 355194760Srwatson assertEqualInt(r, 0); 356194760Srwatson 357194951Srwatson /* Verify that nothing went to stdout or stderr. */ 358191443Srwatson assertEmptyFile("unpack.err"); 359229621Sjhb assertEmptyFile("unpack.out"); 360191443Srwatson 361191443Srwatson verify_tree(LIMIT_USTAR); 362191443Srwatson assertEqualInt(0, chdir("../..")); 363191443Srwatson} 364191443Srwatson 365191443SrwatsonDEFINE_TEST(test_copy) 366191443Srwatson{ 367191443Srwatson assertUmask(0); 36884102Sjlemon create_tree(); /* Create sample files in "original" dir. */ 36984102Sjlemon 370191443Srwatson /* Test simple "tar -c | tar -x" pipeline copy. */ 371194760Srwatson copy_basic(); 372194760Srwatson 373229621Sjhb /* Same, but constrain to ustar format. */ 37484102Sjlemon copy_ustar(); 375191443Srwatson} 376191443Srwatson