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