109ade360Sjoerg /*-
209ade360Sjoerg * Copyright (c) 2003-2007 Tim Kientzle
309ade360Sjoerg * All rights reserved.
409ade360Sjoerg *
509ade360Sjoerg * Redistribution and use in source and binary forms, with or without
609ade360Sjoerg * modification, are permitted provided that the following conditions
709ade360Sjoerg * are met:
809ade360Sjoerg * 1. Redistributions of source code must retain the above copyright
909ade360Sjoerg * notice, this list of conditions and the following disclaimer.
1009ade360Sjoerg * 2. Redistributions in binary form must reproduce the above copyright
1109ade360Sjoerg * notice, this list of conditions and the following disclaimer in the
1209ade360Sjoerg * documentation and/or other materials provided with the distribution.
1309ade360Sjoerg *
1409ade360Sjoerg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
1509ade360Sjoerg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1609ade360Sjoerg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1709ade360Sjoerg * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
1809ade360Sjoerg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
1909ade360Sjoerg * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2009ade360Sjoerg * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2109ade360Sjoerg * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2209ade360Sjoerg * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2309ade360Sjoerg * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2409ade360Sjoerg */
2509ade360Sjoerg #include "test.h"
269fde5391Sjoerg __FBSDID("$FreeBSD: src/usr.bin/tar/test/test_copy.c,v 1.3 2008/08/15 06:12:02 kientzle Exp $");
279fde5391Sjoerg
289fde5391Sjoerg #if defined(__CYGWIN__)
299fde5391Sjoerg # include <limits.h>
309fde5391Sjoerg # include <sys/cygwin.h>
319fde5391Sjoerg #endif
32d05f0226Sjoerg #if defined(_WIN32) && !defined(__CYGWIN__)
33d05f0226Sjoerg # include <direct.h>
34d05f0226Sjoerg #endif
359fde5391Sjoerg
369fde5391Sjoerg /*
379fde5391Sjoerg * Try to figure out how deep we can go in our tests. Assumes that
389fde5391Sjoerg * the first call to this function has the longest starting cwd (which
399fde5391Sjoerg * is currently "<testdir>/original"). This is mostly to work around
409fde5391Sjoerg * limits in our Win32 support.
419fde5391Sjoerg *
429fde5391Sjoerg * Background: On Posix systems, PATH_MAX is merely a limit on the
439fde5391Sjoerg * length of the string passed into a system call. By repeatedly
449fde5391Sjoerg * calling chdir(), you can work with arbitrarily long paths on such
459fde5391Sjoerg * systems. In contrast, Win32 APIs apply PATH_MAX limits to the full
469fde5391Sjoerg * absolute path, so the permissible length of a system call argument
479fde5391Sjoerg * varies with the cwd. Some APIs actually enforce limits
489fde5391Sjoerg * significantly less than PATH_MAX to ensure that you can create
499fde5391Sjoerg * files within the current working directory. The Win32 limits also
509fde5391Sjoerg * apply to Cygwin before 1.7.
519fde5391Sjoerg *
529fde5391Sjoerg * Someday, I want to convert the Win32 support to use newer
539fde5391Sjoerg * wide-character paths with '\\?\' prefix, which has a 32k PATH_MAX
549fde5391Sjoerg * instead of the rather anemic 260 character limit of the older
559fde5391Sjoerg * system calls. Then we can drop this mess (unless we want to
569fde5391Sjoerg * continue to special-case Cygwin 1.5 and earlier).
579fde5391Sjoerg */
589fde5391Sjoerg static int
compute_loop_max(void)599fde5391Sjoerg compute_loop_max(void)
609fde5391Sjoerg {
619fde5391Sjoerg #if defined(_WIN32) && !defined(__CYGWIN__)
629fde5391Sjoerg static int LOOP_MAX = 0;
639fde5391Sjoerg char buf[MAX_PATH];
649fde5391Sjoerg size_t cwdlen;
659fde5391Sjoerg
669fde5391Sjoerg if (LOOP_MAX == 0) {
679fde5391Sjoerg assert(_getcwd(buf, MAX_PATH) != NULL);
689fde5391Sjoerg cwdlen = strlen(buf);
699fde5391Sjoerg /* 12 characters = length of 8.3 filename */
709fde5391Sjoerg /* 4 characters = length of "/../" used in symlink tests */
719fde5391Sjoerg /* 1 character = length of extra "/" separator */
729fde5391Sjoerg LOOP_MAX = MAX_PATH - (int)cwdlen - 12 - 4 - 1;
739fde5391Sjoerg }
749fde5391Sjoerg return LOOP_MAX;
759fde5391Sjoerg #elif defined(__CYGWIN__) && !defined(HAVE_CYGWIN_CONV_PATH)
769fde5391Sjoerg static int LOOP_MAX = 0;
779fde5391Sjoerg if (LOOP_MAX == 0) {
789fde5391Sjoerg char wbuf[PATH_MAX];
799fde5391Sjoerg char pbuf[PATH_MAX];
809fde5391Sjoerg size_t wcwdlen;
819fde5391Sjoerg size_t pcwdlen;
829fde5391Sjoerg size_t cwdlen;
839fde5391Sjoerg assert(getcwd(pbuf, PATH_MAX) != NULL);
849fde5391Sjoerg pcwdlen = strlen(pbuf);
859fde5391Sjoerg cygwin_conv_to_full_win32_path(pbuf, wbuf);
869fde5391Sjoerg wcwdlen = strlen(wbuf);
879fde5391Sjoerg cwdlen = ((wcwdlen > pcwdlen) ? wcwdlen : pcwdlen);
889fde5391Sjoerg /* Cygwin helper needs an extra few characters. */
899fde5391Sjoerg LOOP_MAX = PATH_MAX - (int)cwdlen - 12 - 4 - 4;
909fde5391Sjoerg }
919fde5391Sjoerg return LOOP_MAX;
929fde5391Sjoerg #else
939fde5391Sjoerg /* cygwin-1.7 ends up here, along with "normal" unix */
949fde5391Sjoerg return 200; /* restore pre-r278 depth */
959fde5391Sjoerg #endif
969fde5391Sjoerg }
979fde5391Sjoerg
989fde5391Sjoerg /* filenames[i] is a distinctive filename of length i. */
999fde5391Sjoerg /* To simplify interpreting failures, each filename ends with a
1009fde5391Sjoerg * decimal integer which is the length of the filename. E.g., A
1019fde5391Sjoerg * filename ending in "_92" is 92 characters long. To detect errors
1029fde5391Sjoerg * which drop or misplace characters, the filenames use a repeating
1039fde5391Sjoerg * "abcdefghijklmnopqrstuvwxyz..." pattern. */
1049fde5391Sjoerg static char *filenames[201];
1059fde5391Sjoerg
1069fde5391Sjoerg static void
compute_filenames(void)1079fde5391Sjoerg compute_filenames(void)
1089fde5391Sjoerg {
1099fde5391Sjoerg char buff[250];
1109fde5391Sjoerg size_t i,j;
1119fde5391Sjoerg
1129fde5391Sjoerg filenames[0] = strdup("");
1139fde5391Sjoerg filenames[1] = strdup("1");
1149fde5391Sjoerg filenames[2] = strdup("a2");
1159fde5391Sjoerg for (i = 3; i < sizeof(filenames)/sizeof(filenames[0]); ++i) {
1169fde5391Sjoerg /* Fill with "abcdefghij..." */
1179fde5391Sjoerg for (j = 0; j < i; ++j)
1189fde5391Sjoerg buff[j] = 'a' + (j % 26);
1199fde5391Sjoerg buff[j--] = '\0';
1209fde5391Sjoerg /* Work from the end to fill in the number portion. */
1219fde5391Sjoerg buff[j--] = '0' + (i % 10);
1229fde5391Sjoerg if (i > 9) {
1239fde5391Sjoerg buff[j--] = '0' + ((i / 10) % 10);
1249fde5391Sjoerg if (i > 99)
125d05f0226Sjoerg buff[j--] = '0' + (char)(i / 100);
1269fde5391Sjoerg }
1279fde5391Sjoerg buff[j] = '_';
1289fde5391Sjoerg /* Guard against obvious screwups in the above code. */
1299fde5391Sjoerg assertEqualInt(strlen(buff), i);
1309fde5391Sjoerg filenames[i] = strdup(buff);
1319fde5391Sjoerg }
1329fde5391Sjoerg }
13309ade360Sjoerg
13409ade360Sjoerg static void
create_tree(void)13509ade360Sjoerg create_tree(void)
13609ade360Sjoerg {
13709ade360Sjoerg char buff[260];
13809ade360Sjoerg char buff2[260];
13909ade360Sjoerg int i;
1409fde5391Sjoerg int LOOP_MAX;
14109ade360Sjoerg
1429fde5391Sjoerg compute_filenames();
14309ade360Sjoerg
1449fde5391Sjoerg /* Log that we'll be omitting some checks. */
1459fde5391Sjoerg if (!canSymlink()) {
1469fde5391Sjoerg skipping("Symlink checks");
1479fde5391Sjoerg }
1489fde5391Sjoerg
1499fde5391Sjoerg assertMakeDir("original", 0775);
1509fde5391Sjoerg assertEqualInt(0, chdir("original"));
1519fde5391Sjoerg LOOP_MAX = compute_loop_max();
1529fde5391Sjoerg
1539fde5391Sjoerg assertMakeDir("f", 0775);
1549fde5391Sjoerg assertMakeDir("l", 0775);
1559fde5391Sjoerg assertMakeDir("m", 0775);
1569fde5391Sjoerg assertMakeDir("s", 0775);
1579fde5391Sjoerg assertMakeDir("d", 0775);
1589fde5391Sjoerg
1599fde5391Sjoerg for (i = 1; i < LOOP_MAX; i++) {
1609fde5391Sjoerg failure("Internal sanity check failed: i = %d", i);
1619fde5391Sjoerg assert(filenames[i] != NULL);
1629fde5391Sjoerg
1639fde5391Sjoerg sprintf(buff, "f/%s", filenames[i]);
1649fde5391Sjoerg assertMakeFile(buff, 0777, buff);
16509ade360Sjoerg
16609ade360Sjoerg /* Create a link named "l/abcdef..." to the above. */
1679fde5391Sjoerg sprintf(buff2, "l/%s", filenames[i]);
1689fde5391Sjoerg assertMakeHardlink(buff2, buff);
16909ade360Sjoerg
17009ade360Sjoerg /* Create a link named "m/abcdef..." to the above. */
1719fde5391Sjoerg sprintf(buff2, "m/%s", filenames[i]);
1729fde5391Sjoerg assertMakeHardlink(buff2, buff);
17309ade360Sjoerg
1749fde5391Sjoerg if (canSymlink()) {
17509ade360Sjoerg /* Create a symlink named "s/abcdef..." to the above. */
1769fde5391Sjoerg sprintf(buff, "s/%s", filenames[i]);
1779fde5391Sjoerg sprintf(buff2, "../f/%s", filenames[i]);
1789fde5391Sjoerg failure("buff=\"%s\" buff2=\"%s\"", buff, buff2);
179efdd4e46Sjoerg assertMakeSymlink(buff, buff2, 0);
1809fde5391Sjoerg }
18109ade360Sjoerg /* Create a dir named "d/abcdef...". */
18209ade360Sjoerg buff[0] = 'd';
1839fde5391Sjoerg failure("buff=\"%s\"", buff);
1849fde5391Sjoerg assertMakeDir(buff, 0775);
18509ade360Sjoerg }
18609ade360Sjoerg
1879fde5391Sjoerg assertEqualInt(0, chdir(".."));
18809ade360Sjoerg }
18909ade360Sjoerg
1909fde5391Sjoerg #define LIMIT_NONE 200
1919fde5391Sjoerg #define LIMIT_USTAR 100
19209ade360Sjoerg
19309ade360Sjoerg static void
verify_tree(size_t limit)1949fde5391Sjoerg verify_tree(size_t limit)
19509ade360Sjoerg {
19609ade360Sjoerg char name1[260];
19709ade360Sjoerg char name2[260];
1989fde5391Sjoerg size_t i, LOOP_MAX;
1999fde5391Sjoerg
2009fde5391Sjoerg LOOP_MAX = compute_loop_max();
20109ade360Sjoerg
20209ade360Sjoerg /* Generate the names we know should be there and verify them. */
2039fde5391Sjoerg for (i = 1; i < LOOP_MAX; i++) {
20409ade360Sjoerg /* Verify a file named "f/abcdef..." */
2059fde5391Sjoerg sprintf(name1, "f/%s", filenames[i]);
2069fde5391Sjoerg if (i <= limit) {
2079fde5391Sjoerg assertFileExists(name1);
208d05f0226Sjoerg assertFileContents(name1, (int)strlen(name1), name1);
20909ade360Sjoerg }
21009ade360Sjoerg
2119fde5391Sjoerg sprintf(name2, "l/%s", filenames[i]);
2129fde5391Sjoerg if (i + 2 <= limit) {
21309ade360Sjoerg /* Verify hardlink "l/abcdef..." */
2149fde5391Sjoerg assertIsHardlink(name1, name2);
2159fde5391Sjoerg /* Verify hardlink "m/abcdef..." */
21609ade360Sjoerg name2[0] = 'm';
2179fde5391Sjoerg assertIsHardlink(name1, name2);
21809ade360Sjoerg }
21909ade360Sjoerg
2209fde5391Sjoerg if (canSymlink()) {
22109ade360Sjoerg /* Verify symlink "s/abcdef..." */
2229fde5391Sjoerg sprintf(name1, "s/%s", filenames[i]);
2239fde5391Sjoerg sprintf(name2, "../f/%s", filenames[i]);
2249fde5391Sjoerg if (strlen(name2) <= limit)
225efdd4e46Sjoerg assertIsSymlink(name1, name2, 0);
22609ade360Sjoerg }
22709ade360Sjoerg
22809ade360Sjoerg /* Verify dir "d/abcdef...". */
2299fde5391Sjoerg sprintf(name1, "d/%s", filenames[i]);
2309fde5391Sjoerg if (i + 1 <= limit) { /* +1 for trailing slash */
2319fde5391Sjoerg if (assertIsDir(name1, -1)) {
23209ade360Sjoerg /* TODO: opendir/readdir this
23309ade360Sjoerg * directory and make sure
23409ade360Sjoerg * it's empty.
23509ade360Sjoerg */
23609ade360Sjoerg }
23709ade360Sjoerg }
23809ade360Sjoerg }
23909ade360Sjoerg
2409fde5391Sjoerg #if !defined(_WIN32) || defined(__CYGWIN__)
2419fde5391Sjoerg {
2429fde5391Sjoerg const char *dp;
24309ade360Sjoerg /* Now make sure nothing is there that shouldn't be. */
24409ade360Sjoerg for (dp = "dflms"; *dp != '\0'; ++dp) {
2459fde5391Sjoerg DIR *d;
2469fde5391Sjoerg struct dirent *de;
24709ade360Sjoerg char dir[2];
24809ade360Sjoerg dir[0] = *dp; dir[1] = '\0';
24909ade360Sjoerg d = opendir(dir);
2509fde5391Sjoerg failure("Unable to open dir '%s'", dir);
2519fde5391Sjoerg if (!assert(d != NULL))
2529fde5391Sjoerg continue;
25309ade360Sjoerg while ((de = readdir(d)) != NULL) {
2549fde5391Sjoerg char *p = de->d_name;
2559fde5391Sjoerg if (p[0] == '.')
2569fde5391Sjoerg continue;
25709ade360Sjoerg switch(dp[0]) {
2589fde5391Sjoerg case 'l': case 'm': case 'd':
259*1a7b189bSchristos failure("strlen(p)=%zu", strlen(p));
2609fde5391Sjoerg assert(strlen(p) < limit);
2619fde5391Sjoerg assertEqualString(p,
2629fde5391Sjoerg filenames[strlen(p)]);
26309ade360Sjoerg break;
2649fde5391Sjoerg case 'f': case 's':
265*1a7b189bSchristos failure("strlen(p)=%zu", strlen(p));
2669fde5391Sjoerg assert(strlen(p) < limit + 1);
2679fde5391Sjoerg assertEqualString(p,
2689fde5391Sjoerg filenames[strlen(p)]);
26909ade360Sjoerg break;
27009ade360Sjoerg default:
27109ade360Sjoerg failure("File %s shouldn't be here", p);
27209ade360Sjoerg assert(0);
27309ade360Sjoerg }
27409ade360Sjoerg }
27509ade360Sjoerg closedir(d);
27609ade360Sjoerg }
27709ade360Sjoerg }
2789fde5391Sjoerg #endif
2799fde5391Sjoerg }
28009ade360Sjoerg
28109ade360Sjoerg static void
copy_basic(void)28209ade360Sjoerg copy_basic(void)
28309ade360Sjoerg {
28409ade360Sjoerg int r;
28509ade360Sjoerg
2869fde5391Sjoerg /* NOTE: for proper operation on cygwin-1.5 and windows, the
2879fde5391Sjoerg * length of the name of the directory below, "plain", must be
288d05f0226Sjoerg * less than or equal to the length of the name of the original
2899fde5391Sjoerg * directory, "original" This restriction derives from the
2909fde5391Sjoerg * extremely limited pathname lengths on those platforms.
2919fde5391Sjoerg */
2929fde5391Sjoerg assertMakeDir("plain", 0775);
29309ade360Sjoerg assertEqualInt(0, chdir("plain"));
29409ade360Sjoerg
29509ade360Sjoerg /*
29609ade360Sjoerg * Use the tar program to create an archive.
29709ade360Sjoerg */
29809ade360Sjoerg r = systemf("%s cf archive -C ../original f d l m s >pack.out 2>pack.err",
29909ade360Sjoerg testprog);
30009ade360Sjoerg failure("Error invoking \"%s cf\"", testprog);
30109ade360Sjoerg assertEqualInt(r, 0);
30209ade360Sjoerg
30309ade360Sjoerg /* Verify that nothing went to stdout or stderr. */
30409ade360Sjoerg assertEmptyFile("pack.err");
30509ade360Sjoerg assertEmptyFile("pack.out");
30609ade360Sjoerg
30709ade360Sjoerg /*
30809ade360Sjoerg * Use tar to unpack the archive into another directory.
30909ade360Sjoerg */
31009ade360Sjoerg r = systemf("%s xf archive >unpack.out 2>unpack.err", testprog);
31109ade360Sjoerg failure("Error invoking %s xf archive", testprog);
31209ade360Sjoerg assertEqualInt(r, 0);
31309ade360Sjoerg
31409ade360Sjoerg /* Verify that nothing went to stdout or stderr. */
31509ade360Sjoerg assertEmptyFile("unpack.err");
31609ade360Sjoerg assertEmptyFile("unpack.out");
31709ade360Sjoerg
31809ade360Sjoerg verify_tree(LIMIT_NONE);
3190c8b3e90Schristos
3200c8b3e90Schristos /*
3210c8b3e90Schristos * Unpack a second time to make sure that things are still ok
3220c8b3e90Schristos */
3230c8b3e90Schristos r = systemf("%s xf archive >unpack.out 2>unpack.err", testprog);
3240c8b3e90Schristos failure("Error invoking %s xf archive", testprog);
3250c8b3e90Schristos assertEqualInt(r, 0);
3260c8b3e90Schristos
3270c8b3e90Schristos /* Verify that nothing went to stdout or stderr. */
3280c8b3e90Schristos assertEmptyFile("unpack.err");
3290c8b3e90Schristos assertEmptyFile("unpack.out");
3300c8b3e90Schristos
3310c8b3e90Schristos verify_tree(LIMIT_NONE);
33209ade360Sjoerg assertEqualInt(0, chdir(".."));
33309ade360Sjoerg }
33409ade360Sjoerg
33509ade360Sjoerg static void
copy_ustar(void)33609ade360Sjoerg copy_ustar(void)
33709ade360Sjoerg {
33809ade360Sjoerg const char *target = "ustar";
33909ade360Sjoerg int r;
34009ade360Sjoerg
3419fde5391Sjoerg /* NOTE: for proper operation on cygwin-1.5 and windows, the
3429fde5391Sjoerg * length of the name of the directory below, "ustar", must be
343d05f0226Sjoerg * less than or equal to the length of the name of the original
3449fde5391Sjoerg * directory, "original" This restriction derives from the
3459fde5391Sjoerg * extremely limited pathname lengths on those platforms.
3469fde5391Sjoerg */
3479fde5391Sjoerg assertMakeDir(target, 0775);
34809ade360Sjoerg assertEqualInt(0, chdir(target));
34909ade360Sjoerg
35009ade360Sjoerg /*
35109ade360Sjoerg * Use the tar program to create an archive.
35209ade360Sjoerg */
35309ade360Sjoerg r = systemf("%s cf archive --format=ustar -C ../original f d l m s >pack.out 2>pack.err",
35409ade360Sjoerg testprog);
35509ade360Sjoerg failure("Error invoking \"%s cf archive --format=ustar\"", testprog);
35609ade360Sjoerg assertEqualInt(r, 0);
35709ade360Sjoerg
35809ade360Sjoerg /* Verify that nothing went to stdout. */
35909ade360Sjoerg assertEmptyFile("pack.out");
36009ade360Sjoerg /* Stderr is non-empty, since there are a bunch of files
36109ade360Sjoerg * with filenames too long to archive. */
36209ade360Sjoerg
36309ade360Sjoerg /*
36409ade360Sjoerg * Use tar to unpack the archive into another directory.
36509ade360Sjoerg */
36609ade360Sjoerg r = systemf("%s xf archive >unpack.out 2>unpack.err", testprog);
36709ade360Sjoerg failure("Error invoking %s xf archive", testprog);
36809ade360Sjoerg assertEqualInt(r, 0);
36909ade360Sjoerg
37009ade360Sjoerg /* Verify that nothing went to stdout or stderr. */
37109ade360Sjoerg assertEmptyFile("unpack.err");
37209ade360Sjoerg assertEmptyFile("unpack.out");
37309ade360Sjoerg
37409ade360Sjoerg verify_tree(LIMIT_USTAR);
3759fde5391Sjoerg assertEqualInt(0, chdir("../.."));
37609ade360Sjoerg }
37709ade360Sjoerg
DEFINE_TEST(test_copy)37809ade360Sjoerg DEFINE_TEST(test_copy)
37909ade360Sjoerg {
3809fde5391Sjoerg assertUmask(0);
38109ade360Sjoerg create_tree(); /* Create sample files in "original" dir. */
38209ade360Sjoerg
38309ade360Sjoerg /* Test simple "tar -c | tar -x" pipeline copy. */
38409ade360Sjoerg copy_basic();
38509ade360Sjoerg
38609ade360Sjoerg /* Same, but constrain to ustar format. */
38709ade360Sjoerg copy_ustar();
38809ade360Sjoerg }
389