SYSENTER/SYSCALL support
[minix.git] / commands / tar / test / test_copy.c
blob69112900e536c0d0035803f7664f556cade94b59
1 /*-
2 * Copyright (c) 2003-2007 Tim Kientzle
3 * All rights reserved.
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.
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.
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 $");
28 #if defined(__CYGWIN__)
29 # include <limits.h>
30 # include <sys/cygwin.h>
31 #endif
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.
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.
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).
55 static int
56 compute_loop_max(void)
58 #if defined(_WIN32) && !defined(__CYGWIN__)
59 static int LOOP_MAX = 0;
60 char buf[MAX_PATH];
61 size_t cwdlen;
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;
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;
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
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. */
101 static char *filenames[201];
103 static void
104 compute_filenames(void)
106 char buff[250];
107 size_t i,j;
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);
124 buff[j] = '_';
125 /* Guard against obvious screwups in the above code. */
126 assertEqualInt(strlen(buff), i);
127 filenames[i] = strdup(buff);
131 static void
132 create_tree(void)
134 char buff[260];
135 char buff2[260];
136 int i;
137 int LOOP_MAX;
139 compute_filenames();
141 /* Log that we'll be omitting some checks. */
142 if (!canSymlink()) {
143 skipping("Symlink checks");
146 assertMakeDir("original", 0775);
147 assertEqualInt(0, chdir("original"));
148 LOOP_MAX = compute_loop_max();
150 assertMakeDir("f", 0775);
151 assertMakeDir("l", 0775);
152 assertMakeDir("m", 0775);
153 assertMakeDir("s", 0775);
154 assertMakeDir("d", 0775);
156 for (i = 1; i < LOOP_MAX; i++) {
157 failure("Internal sanity check failed: i = %d", i);
158 assert(filenames[i] != NULL);
160 sprintf(buff, "f/%s", filenames[i]);
161 assertMakeFile(buff, 0777, buff);
163 /* Create a link named "l/abcdef..." to the above. */
164 sprintf(buff2, "l/%s", filenames[i]);
165 assertMakeHardlink(buff2, buff);
167 /* Create a link named "m/abcdef..." to the above. */
168 sprintf(buff2, "m/%s", filenames[i]);
169 assertMakeHardlink(buff2, buff);
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);
178 /* Create a dir named "d/abcdef...". */
179 buff[0] = 'd';
180 failure("buff=\"%s\"", buff);
181 assertMakeDir(buff, 0775);
184 assertEqualInt(0, chdir(".."));
187 #define LIMIT_NONE 200
188 #define LIMIT_USTAR 100
190 static void
191 verify_tree(size_t limit)
193 char name1[260];
194 char name2[260];
195 size_t i, LOOP_MAX;
197 LOOP_MAX = compute_loop_max();
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);
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);
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);
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.
237 #if !defined(_WIN32) || defined(__CYGWIN__)
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);
272 closedir(d);
275 #endif
278 static void
279 copy_basic(void)
281 int r;
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.
289 assertMakeDir("plain", 0775);
290 assertEqualInt(0, chdir("plain"));
293 * Use the tar program to create an archive.
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);
300 /* Verify that nothing went to stdout or stderr. */
301 assertEmptyFile("pack.err");
302 assertEmptyFile("pack.out");
305 * Use tar to unpack the archive into another directory.
307 r = systemf("%s xf archive >unpack.out 2>unpack.err", testprog);
308 failure("Error invoking %s xf archive", testprog);
309 assertEqualInt(r, 0);
311 /* Verify that nothing went to stdout or stderr. */
312 assertEmptyFile("unpack.err");
313 assertEmptyFile("unpack.out");
315 verify_tree(LIMIT_NONE);
316 assertEqualInt(0, chdir(".."));
319 static void
320 copy_ustar(void)
322 const char *target = "ustar";
323 int r;
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.
331 assertMakeDir(target, 0775);
332 assertEqualInt(0, chdir(target));
335 * Use the tar program to create an archive.
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);
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. */
348 * Use tar to unpack the archive into another directory.
350 r = systemf("%s xf archive >unpack.out 2>unpack.err", testprog);
351 failure("Error invoking %s xf archive", testprog);
352 assertEqualInt(r, 0);
354 /* Verify that nothing went to stdout or stderr. */
355 assertEmptyFile("unpack.err");
356 assertEmptyFile("unpack.out");
358 verify_tree(LIMIT_USTAR);
359 assertEqualInt(0, chdir("../.."));
362 DEFINE_TEST(test_copy)
364 assertUmask(0);
365 create_tree(); /* Create sample files in "original" dir. */
367 /* Test simple "tar -c | tar -x" pipeline copy. */
368 copy_basic();
370 /* Same, but constrain to ustar format. */
371 copy_ustar();