test_copy.c revision 228753
140090Smsmith/*- 240090Smsmith * Copyright (c) 2003-2007 Tim Kientzle 340090Smsmith * All rights reserved. 440090Smsmith * 540090Smsmith * Redistribution and use in source and binary forms, with or without 640090Smsmith * modification, are permitted provided that the following conditions 740090Smsmith * are met: 840090Smsmith * 1. Redistributions of source code must retain the above copyright 940090Smsmith * notice, this list of conditions and the following disclaimer. 1040090Smsmith * 2. Redistributions in binary form must reproduce the above copyright 1140090Smsmith * notice, this list of conditions and the following disclaimer in the 1240090Smsmith * documentation and/or other materials provided with the distribution. 1340090Smsmith * 1440090Smsmith * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR 1540090Smsmith * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1640090Smsmith * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1740090Smsmith * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, 1840090Smsmith * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 1940090Smsmith * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2040090Smsmith * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2140090Smsmith * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2240090Smsmith * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2340090Smsmith * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2440090Smsmith */ 2540090Smsmith#include "test.h" 2650477Speter__FBSDID("$FreeBSD: src/usr.bin/tar/test/test_copy.c,v 1.3 2008/08/15 06:12:02 kientzle Exp $"); 2740116Sjkh 2840090Smsmith#if defined(__CYGWIN__) 2940090Smsmith# include <limits.h> 3040090Smsmith# include <sys/cygwin.h> 3194936Smux#endif 3294936Smux 3340090Smsmith/* 3494936Smux * Try to figure out how deep we can go in our tests. Assumes that 3594936Smux * the first call to this function has the longest starting cwd (which 3694936Smux * is currently "<testdir>/original"). This is mostly to work around 3740090Smsmith * limits in our Win32 support. 3840090Smsmith * 39106308Srwatson * Background: On Posix systems, PATH_MAX is merely a limit on the 40106308Srwatson * length of the string passed into a system call. By repeatedly 4194936Smux * calling chdir(), you can work with arbitrarily long paths on such 4240090Smsmith * systems. In contrast, Win32 APIs apply PATH_MAX limits to the full 4394936Smux * absolute path, so the permissible length of a system call argument 4494936Smux * varies with the cwd. Some APIs actually enforce limits 4594936Smux * significantly less than PATH_MAX to ensure that you can create 46106308Srwatson * files within the current working directory. The Win32 limits also 4794936Smux * apply to Cygwin before 1.7. 4894936Smux * 4940090Smsmith * Someday, I want to convert the Win32 support to use newer 5094936Smux * wide-character paths with '\\?\' prefix, which has a 32k PATH_MAX 5140090Smsmith * instead of the rather anemic 260 character limit of the older 5294936Smux * system calls. Then we can drop this mess (unless we want to 5394936Smux * continue to special-case Cygwin 1.5 and earlier). 5440090Smsmith */ 5594936Smuxstatic int 5640090Smsmithcompute_loop_max(void) 5794936Smux{ 5840090Smsmith#if defined(_WIN32) && !defined(__CYGWIN__) 5994936Smux static int LOOP_MAX = 0; 6040090Smsmith char buf[MAX_PATH]; 6194936Smux size_t cwdlen; 6294936Smux 6394936Smux if (LOOP_MAX == 0) { 6494936Smux assert(_getcwd(buf, MAX_PATH) != NULL); 6594936Smux cwdlen = strlen(buf); 6694936Smux /* 12 characters = length of 8.3 filename */ 6794936Smux /* 4 characters = length of "/../" used in symlink tests */ 6894936Smux /* 1 character = length of extra "/" separator */ 6985385Sjhb LOOP_MAX = MAX_PATH - (int)cwdlen - 12 - 4 - 1; 7094936Smux } 7194936Smux return LOOP_MAX; 7294936Smux#elif defined(__CYGWIN__) && !defined(HAVE_CYGWIN_CONV_PATH) 7394936Smux static int LOOP_MAX = 0; 7494936Smux if (LOOP_MAX == 0) { 7594936Smux char wbuf[PATH_MAX]; 7694936Smux char pbuf[PATH_MAX]; 7794936Smux size_t wcwdlen; 7894936Smux size_t pcwdlen; 7994936Smux size_t cwdlen; 8094936Smux assert(getcwd(pbuf, PATH_MAX) != NULL); 8194936Smux pcwdlen = strlen(pbuf); 8294936Smux cygwin_conv_to_full_win32_path(pbuf, wbuf); 8394936Smux wcwdlen = strlen(wbuf); 8494936Smux cwdlen = ((wcwdlen > pcwdlen) ? wcwdlen : pcwdlen); 8594936Smux /* Cygwin helper needs an extra few characters. */ 8694936Smux LOOP_MAX = PATH_MAX - (int)cwdlen - 12 - 4 - 4; 8794936Smux } 8894936Smux return LOOP_MAX; 8994936Smux#else 9094936Smux /* cygwin-1.7 ends up here, along with "normal" unix */ 9195839Speter return 200; /* restore pre-r278 depth */ 9294936Smux#endif 9394936Smux} 9494936Smux 95107849Salfred/* filenames[i] is a distinctive filename of length i. */ 96106308Srwatson/* To simplify interpreting failures, each filename ends with a 97106308Srwatson * decimal integer which is the length of the filename. E.g., A 98106308Srwatson * filename ending in "_92" is 92 characters long. To detect errors 99106308Srwatson * which drop or misplace characters, the filenames use a repeating 100106308Srwatson * "abcdefghijklmnopqrstuvwxyz..." pattern. */ 10194936Smuxstatic char *filenames[201]; 10294936Smux 103107849Salfredstatic void 10494936Smuxcompute_filenames(void) 10594936Smux{ 10694936Smux char buff[250]; 10794936Smux size_t i,j; 10894936Smux 10994936Smux filenames[0] = strdup(""); 11094936Smux filenames[1] = strdup("1"); 11194936Smux filenames[2] = strdup("a2"); 11294936Smux for (i = 3; i < sizeof(filenames)/sizeof(filenames[0]); ++i) { 113107849Salfred /* Fill with "abcdefghij..." */ 114107849Salfred for (j = 0; j < i; ++j) 115107849Salfred buff[j] = 'a' + (j % 26); 11694936Smux buff[j--] = '\0'; 11794936Smux /* Work from the end to fill in the number portion. */ 11894936Smux buff[j--] = '0' + (i % 10); 11994936Smux if (i > 9) { 12094936Smux buff[j--] = '0' + ((i / 10) % 10); 12194936Smux if (i > 99) 12294936Smux buff[j--] = '0' + (i / 100); 12394936Smux } 12494936Smux buff[j] = '_'; 12594936Smux /* Guard against obvious screwups in the above code. */ 12694936Smux assertEqualInt(strlen(buff), i); 127107849Salfred filenames[i] = strdup(buff); 128107849Salfred } 12994936Smux} 13094936Smux 13194936Smuxstatic void 13294936Smuxcreate_tree(void) 13394936Smux{ 13494936Smux char buff[260]; 13594936Smux char buff2[260]; 136107849Salfred int i; 13794936Smux int LOOP_MAX; 13894936Smux 13994936Smux compute_filenames(); 140107849Salfred 14194936Smux /* Log that we'll be omitting some checks. */ 142106308Srwatson if (!canSymlink()) { 143106308Srwatson skipping("Symlink checks"); 144106308Srwatson } 145106308Srwatson 146106308Srwatson assertMakeDir("original", 0775); 14794936Smux assertEqualInt(0, chdir("original")); 14894936Smux LOOP_MAX = compute_loop_max(); 14994936Smux 15094936Smux assertMakeDir("f", 0775); 15194936Smux assertMakeDir("l", 0775); 15294936Smux assertMakeDir("m", 0775); 153107849Salfred assertMakeDir("s", 0775); 154107849Salfred assertMakeDir("d", 0775); 155107849Salfred 15694936Smux for (i = 1; i < LOOP_MAX; i++) { 15794936Smux failure("Internal sanity check failed: i = %d", i); 15894936Smux assert(filenames[i] != NULL); 15994936Smux 16094936Smux sprintf(buff, "f/%s", filenames[i]); 16194936Smux assertMakeFile(buff, 0777, buff); 162107849Salfred 16394936Smux /* Create a link named "l/abcdef..." to the above. */ 16494936Smux sprintf(buff2, "l/%s", filenames[i]); 16594936Smux assertMakeHardlink(buff2, buff); 16694936Smux 16794936Smux /* Create a link named "m/abcdef..." to the above. */ 16894936Smux sprintf(buff2, "m/%s", filenames[i]); 16994936Smux assertMakeHardlink(buff2, buff); 170107849Salfred 17194936Smux if (canSymlink()) { 17294936Smux /* Create a symlink named "s/abcdef..." to the above. */ 17394936Smux sprintf(buff, "s/%s", filenames[i]); 17494936Smux sprintf(buff2, "../f/%s", filenames[i]); 175106308Srwatson failure("buff=\"%s\" buff2=\"%s\"", buff, buff2); 176106308Srwatson assertMakeSymlink(buff, buff2); 177106308Srwatson } 178106308Srwatson /* Create a dir named "d/abcdef...". */ 179106308Srwatson buff[0] = 'd'; 18094936Smux failure("buff=\"%s\"", buff); 18194936Smux assertMakeDir(buff, 0775); 18294936Smux } 183106308Srwatson 184106308Srwatson assertEqualInt(0, chdir("..")); 185106308Srwatson} 186106308Srwatson 187106308Srwatson#define LIMIT_NONE 200 18894936Smux#define LIMIT_USTAR 100 18994936Smux 19094936Smuxstatic void 19194936Smuxverify_tree(size_t limit) 19294936Smux{ 19394936Smux char name1[260]; 19494936Smux char name2[260]; 19594936Smux size_t i, LOOP_MAX; 19694936Smux 19794936Smux LOOP_MAX = compute_loop_max(); 19894936Smux 19994936Smux /* Generate the names we know should be there and verify them. */ 20094936Smux for (i = 1; i < LOOP_MAX; i++) { 20194936Smux /* Verify a file named "f/abcdef..." */ 20294936Smux sprintf(name1, "f/%s", filenames[i]); 20394936Smux if (i <= limit) { 20494936Smux assertFileExists(name1); 20594936Smux assertFileContents(name1, strlen(name1), name1); 20694936Smux } 20794936Smux 20894936Smux sprintf(name2, "l/%s", filenames[i]); 20994936Smux if (i + 2 <= limit) { 21094936Smux /* Verify hardlink "l/abcdef..." */ 21194936Smux assertIsHardlink(name1, name2); 21294936Smux /* Verify hardlink "m/abcdef..." */ 21394936Smux name2[0] = 'm'; 21494936Smux assertIsHardlink(name1, name2); 21594936Smux } 21694936Smux 21794936Smux if (canSymlink()) { 21894936Smux /* Verify symlink "s/abcdef..." */ 21994936Smux sprintf(name1, "s/%s", filenames[i]); 22094936Smux sprintf(name2, "../f/%s", filenames[i]); 22194936Smux if (strlen(name2) <= limit) 22294936Smux assertIsSymlink(name1, name2); 22394936Smux } 22494936Smux 22594936Smux /* Verify dir "d/abcdef...". */ 22694936Smux sprintf(name1, "d/%s", filenames[i]); 22794936Smux if (i + 1 <= limit) { /* +1 for trailing slash */ 22894936Smux if (assertIsDir(name1, -1)) { 22994936Smux /* TODO: opendir/readdir this 23094936Smux * directory and make sure 23194936Smux * it's empty. 23294936Smux */ 23394936Smux } 23494936Smux } 23594936Smux } 23694936Smux 23794936Smux#if !defined(_WIN32) || defined(__CYGWIN__) 23894936Smux { 23994936Smux const char *dp; 24094936Smux /* Now make sure nothing is there that shouldn't be. */ 24194936Smux for (dp = "dflms"; *dp != '\0'; ++dp) { 24294936Smux DIR *d; 24394936Smux struct dirent *de; 24494936Smux char dir[2]; 24594936Smux dir[0] = *dp; dir[1] = '\0'; 24694936Smux d = opendir(dir); 24794936Smux failure("Unable to open dir '%s'", dir); 24894936Smux if (!assert(d != NULL)) 24994936Smux continue; 25094936Smux while ((de = readdir(d)) != NULL) { 25194936Smux char *p = de->d_name; 25294936Smux if (p[0] == '.') 25394936Smux continue; 25494936Smux switch(dp[0]) { 25594936Smux case 'l': case 'm': case 'd': 25694936Smux failure("strlen(p)=%d", strlen(p)); 25794936Smux assert(strlen(p) < limit); 25894936Smux assertEqualString(p, 25994936Smux filenames[strlen(p)]); 26094936Smux break; 26194936Smux case 'f': case 's': 26294936Smux failure("strlen(p)=%d", strlen(p)); 26395467Sbde assert(strlen(p) < limit + 1); 26495467Sbde assertEqualString(p, 26594936Smux filenames[strlen(p)]); 26695467Sbde break; 26795467Sbde default: 26894936Smux failure("File %s shouldn't be here", p); 26994936Smux assert(0); 27094936Smux } 27194936Smux } 27294936Smux closedir(d); 27394936Smux } 27485385Sjhb } 27594936Smux#endif 27694936Smux} 27794936Smux 27885385Sjhbstatic void 27940090Smsmithcopy_basic(void) 28078247Speter{ 28140090Smsmith int r; 28294959Smux 28394936Smux /* NOTE: for proper operation on cygwin-1.5 and windows, the 28494936Smux * length of the name of the directory below, "plain", must be 28594936Smux * less than or equal to the lengthe of the name of the original 28694936Smux * directory, "original" This restriction derives from the 28794936Smux * extremely limited pathname lengths on those platforms. 28894936Smux */ 28994936Smux assertMakeDir("plain", 0775); 29094959Smux assertEqualInt(0, chdir("plain")); 29194959Smux 29294959Smux /* 29394936Smux * Use the tar program to create an archive. 29494959Smux */ 29594959Smux r = systemf("%s cf archive -C ../original f d l m s >pack.out 2>pack.err", 29694959Smux testprog); 29794936Smux failure("Error invoking \"%s cf\"", testprog); 29894959Smux assertEqualInt(r, 0); 29994936Smux 30094936Smux /* Verify that nothing went to stdout or stderr. */ 30194936Smux assertEmptyFile("pack.err"); 30240090Smsmith assertEmptyFile("pack.out"); 30340090Smsmith 30442706Smsmith /* 30594936Smux * Use tar to unpack the archive into another directory. 30694936Smux */ 30794936Smux r = systemf("%s xf archive >unpack.out 2>unpack.err", testprog); 30894936Smux failure("Error invoking %s xf archive", testprog); 30994936Smux assertEqualInt(r, 0); 31094936Smux 31194936Smux /* Verify that nothing went to stdout or stderr. */ 31294936Smux assertEmptyFile("unpack.err"); 31394936Smux assertEmptyFile("unpack.out"); 31494936Smux 31594936Smux verify_tree(LIMIT_NONE); 31694936Smux assertEqualInt(0, chdir("..")); 31794936Smux} 31894936Smux 31994936Smuxstatic void 32094936Smuxcopy_ustar(void) 32194936Smux{ 32294936Smux const char *target = "ustar"; 32394936Smux int r; 32494936Smux 32594936Smux /* NOTE: for proper operation on cygwin-1.5 and windows, the 32694959Smux * length of the name of the directory below, "ustar", must be 32794936Smux * less than or equal to the lengthe of the name of the original 32894936Smux * directory, "original" This restriction derives from the 32994959Smux * extremely limited pathname lengths on those platforms. 33094959Smux */ 33194936Smux assertMakeDir(target, 0775); 33294936Smux assertEqualInt(0, chdir(target)); 33394936Smux 33494959Smux /* 33594959Smux * Use the tar program to create an archive. 33694959Smux */ 33794959Smux r = systemf("%s cf archive --format=ustar -C ../original f d l m s >pack.out 2>pack.err", 33894959Smux testprog); 33994959Smux failure("Error invoking \"%s cf archive --format=ustar\"", testprog); 34094959Smux assertEqualInt(r, 0); 34194936Smux 34294936Smux /* Verify that nothing went to stdout. */ 34394936Smux assertEmptyFile("pack.out"); 34494936Smux /* Stderr is non-empty, since there are a bunch of files 34594936Smux * with filenames too long to archive. */ 34694959Smux 34794936Smux /* 34894959Smux * Use tar to unpack the archive into another directory. 34994959Smux */ 35094936Smux r = systemf("%s xf archive >unpack.out 2>unpack.err", testprog); 35194936Smux failure("Error invoking %s xf archive", testprog); 35294936Smux assertEqualInt(r, 0); 35394936Smux 35494936Smux /* Verify that nothing went to stdout or stderr. */ 35594936Smux assertEmptyFile("unpack.err"); 35694959Smux assertEmptyFile("unpack.out"); 35794936Smux 35894959Smux verify_tree(LIMIT_USTAR); 35994936Smux assertEqualInt(0, chdir("../..")); 36094936Smux} 36194936Smux 36294936SmuxDEFINE_TEST(test_copy) 36394936Smux{ 36494936Smux assertUmask(0); 36594936Smux create_tree(); /* Create sample files in "original" dir. */ 36694936Smux 36794959Smux /* Test simple "tar -c | tar -x" pipeline copy. */ 36894936Smux copy_basic(); 36994936Smux 37094936Smux /* Same, but constrain to ustar format. */ 37194936Smux copy_ustar(); 37294936Smux} 37394936Smux