xref: /netbsd-src/external/bsd/libarchive/dist/tar/test/test_copy.c (revision 274254cdae52594c1aa480a736aef78313d15c9c)
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 __FBSDID("$FreeBSD: src/usr.bin/tar/test/test_copy.c,v 1.2 2008/05/26 17:10:10 kientzle Exp $");
27 
28 static void
29 create_tree(void)
30 {
31 	char buff[260];
32 	char buff2[260];
33 	int i;
34 	int fd;
35 
36 	assertEqualInt(0, mkdir("original", 0775));
37 	chdir("original");
38 	assertEqualInt(0, mkdir("f", 0775));
39 	assertEqualInt(0, mkdir("l", 0775));
40 	assertEqualInt(0, mkdir("m", 0775));
41 	assertEqualInt(0, mkdir("s", 0775));
42 	assertEqualInt(0, mkdir("d", 0775));
43 
44 	for (i = 0; i < 200; i++) {
45 		buff[0] = 'f';
46 		buff[1] = '/';
47 		/* Create a file named "f/abcdef..." */
48 		buff[i + 2] = 'a' + (i % 26);
49 		buff[i + 3] = '\0';
50 		fd = open(buff, O_CREAT | O_WRONLY, 0644);
51 		assert(fd >= 0);
52 		assertEqualInt(i + 3, write(fd, buff, strlen(buff)));
53 		close(fd);
54 
55 		/* Create a link named "l/abcdef..." to the above. */
56 		strcpy(buff2, buff);
57 		buff2[0] = 'l';
58 		assertEqualInt(0, link(buff, buff2));
59 
60 		/* Create a link named "m/abcdef..." to the above. */
61 		strcpy(buff2, buff);
62 		buff2[0] = 'm';
63 		assertEqualInt(0, link(buff, buff2));
64 
65 		/* Create a symlink named "s/abcdef..." to the above. */
66 		strcpy(buff2 + 3, buff);
67 		buff[0] = 's';
68 		buff2[0] = '.';
69 		buff2[1] = '.';
70 		buff2[2] = '/';
71 		assertEqualInt(0, symlink(buff2, buff));
72 
73 		/* Create a dir named "d/abcdef...". */
74 		buff[0] = 'd';
75 		assertEqualInt(0, mkdir(buff, 0775));
76 	}
77 
78 	chdir("..");
79 }
80 
81 #define LIMIT_NONE 0
82 #define LIMIT_USTAR 1
83 
84 static void
85 verify_tree(int limit)
86 {
87 	struct stat st, st2;
88 	char filename[260];
89 	char name1[260];
90 	char name2[260];
91 	char contents[260];
92 	int i, j, r;
93 	int fd;
94 	int len;
95 	const char *p, *dp;
96 	DIR *d;
97 	struct dirent *de;
98 
99 	/* Generate the names we know should be there and verify them. */
100 	for (i = 1; i < 200; i++) {
101 		/* Generate a base name of the correct length. */
102 		for (j = 0; j < i; ++j)
103 			filename[j] = 'a' + (j % 26);
104 #if 0
105 		for (n = i; n > 0; n /= 10)
106 			filename[--j] = '0' + (n % 10);
107 #endif
108 		filename[i] = '\0';
109 
110 		/* Verify a file named "f/abcdef..." */
111 		strcpy(name1, "f/");
112 		strcat(name1, filename);
113 		if (limit != LIMIT_USTAR || strlen(filename) <= 100) {
114 			fd = open(name1, O_RDONLY);
115 			failure("Couldn't open \"%s\": %s",
116 			    name1, strerror(errno));
117 			if (assert(fd >= 0)) {
118 				len = read(fd, contents, i + 10);
119 				close(fd);
120 				assertEqualInt(len, i + 2);
121 				/* Verify contents of 'contents' */
122 				contents[len] = '\0';
123 				failure("Each test file contains its own name");
124 				assertEqualString(name1, contents);
125 				/* stat() for dev/ino for next check */
126 				assertEqualInt(0, lstat(name1, &st));
127 			}
128 		}
129 
130 		/*
131 		 * ustar allows 100 chars for links, and we have
132 		 * "original/" as part of the name, so the link
133 		 * names here can't exceed 91 chars.
134 		 */
135 		strcpy(name2, "l/");
136 		strcat(name2, filename);
137 		if (limit != LIMIT_USTAR || strlen(name2) <= 100) {
138 			/* Verify hardlink "l/abcdef..." */
139 			assertEqualInt(0, (r = lstat(name2, &st2)));
140 			if (r == 0) {
141 				assertEqualInt(st2.st_dev, st.st_dev);
142 				assertEqualInt(st2.st_ino, st.st_ino);
143 			}
144 
145 			/* Verify hardlink "m_abcdef..." */
146 			name2[0] = 'm';
147 			assertEqualInt(0, (r = lstat(name2, &st2)));
148 			if (r == 0) {
149 				assertEqualInt(st2.st_dev, st.st_dev);
150 				assertEqualInt(st2.st_ino, st.st_ino);
151 			}
152 		}
153 
154 		/*
155 		 * Symlink text doesn't include the 'original/' prefix,
156 		 * so the limit here is 100 characters.
157 		 */
158 		/* Verify symlink "s/abcdef..." */
159 		strcpy(name2, "../s/");
160 		strcat(name2, filename);
161 		if (limit != LIMIT_USTAR || strlen(name2) <= 100) {
162 			/* This is a symlink. */
163 			failure("Couldn't stat %s (length %d)",
164 			    filename, strlen(filename));
165 			if (assertEqualInt(0, lstat(name2 + 3, &st2))) {
166 				assert(S_ISLNK(st2.st_mode));
167 				/* This is a symlink to the file above. */
168 				failure("Couldn't stat %s", name2 + 3);
169 				if (assertEqualInt(0, stat(name2 + 3, &st2))) {
170 					assertEqualInt(st2.st_dev, st.st_dev);
171 					assertEqualInt(st2.st_ino, st.st_ino);
172 				}
173 			}
174 		}
175 
176 		/* Verify dir "d/abcdef...". */
177 		strcpy(name1, "d/");
178 		strcat(name1, filename);
179 		if (limit != LIMIT_USTAR || strlen(filename) < 100) {
180 			/* This is a dir. */
181 			failure("Couldn't stat %s (length %d)",
182 			    name1, strlen(filename));
183 			if (assertEqualInt(0, lstat(name1, &st2))) {
184 				if (assert(S_ISDIR(st2.st_mode))) {
185 					/* TODO: opendir/readdir this
186 					 * directory and make sure
187 					 * it's empty.
188 					 */
189 				}
190 			}
191 		}
192 	}
193 
194 	/* Now make sure nothing is there that shouldn't be. */
195 	for (dp = "dflms"; *dp != '\0'; ++dp) {
196 		char dir[2];
197 		dir[0] = *dp; dir[1] = '\0';
198 		d = opendir(dir);
199 		while ((de = readdir(d)) != NULL) {
200 			p = de->d_name;
201 			switch(dp[0]) {
202 			case 'l': case 'm':
203 				if (limit == LIMIT_USTAR) {
204 					failure("strlen(p) = %d", strlen(p));
205 					assert(strlen(p) <= 100);
206 				}
207 			case 'd':
208 				if (limit == LIMIT_USTAR) {
209 					failure("strlen(p)=%d", strlen(p));
210 					assert(strlen(p) < 100);
211 				}
212 			case 'f': case 's':
213 				if (limit == LIMIT_USTAR) {
214 					failure("strlen(p)=%d", strlen(p));
215 					assert(strlen(p) < 101);
216 				}
217 				/* Our files have very particular filename patterns. */
218 				if (p[0] != '.' || (p[1] != '.' && p[1] != '\0')) {
219 					for (i = 0; p[i] != '\0' && i < 200; i++) {
220 						failure("i=%d, p[i]='%c' 'a'+(i%%26)='%c'", i, p[i], 'a' + (i % 26));
221 						assertEqualInt(p[i], 'a' + (i % 26));
222 					}
223 					assert(p[i] == '\0');
224 				}
225 				break;
226 			case '.':
227 				assert(p[1] == '\0' || (p[1] == '.' && p[2] == '\0'));
228 				break;
229 			default:
230 				failure("File %s shouldn't be here", p);
231 				assert(0);
232 			}
233 		}
234 		closedir(d);
235 	}
236 }
237 
238 static void
239 copy_basic(void)
240 {
241 	int r;
242 
243 	assertEqualInt(0, mkdir("plain", 0775));
244 	assertEqualInt(0, chdir("plain"));
245 
246 	/*
247 	 * Use the tar program to create an archive.
248 	 */
249 	r = systemf("%s cf archive -C ../original f d l m s >pack.out 2>pack.err",
250 	    testprog);
251 	failure("Error invoking \"%s cf\"", testprog);
252 	assertEqualInt(r, 0);
253 
254 	/* Verify that nothing went to stdout or stderr. */
255 	assertEmptyFile("pack.err");
256 	assertEmptyFile("pack.out");
257 
258 	/*
259 	 * Use tar to unpack the archive into another directory.
260 	 */
261 	r = systemf("%s xf archive >unpack.out 2>unpack.err", testprog);
262 	failure("Error invoking %s xf archive", testprog);
263 	assertEqualInt(r, 0);
264 
265 	/* Verify that nothing went to stdout or stderr. */
266 	assertEmptyFile("unpack.err");
267 	assertEmptyFile("unpack.out");
268 
269 	verify_tree(LIMIT_NONE);
270 	assertEqualInt(0, chdir(".."));
271 }
272 
273 static void
274 copy_ustar(void)
275 {
276 	const char *target = "ustar";
277 	int r;
278 
279 	assertEqualInt(0, mkdir(target, 0775));
280 	assertEqualInt(0, chdir(target));
281 
282 	/*
283 	 * Use the tar program to create an archive.
284 	 */
285 	r = systemf("%s cf archive --format=ustar -C ../original f d l m s >pack.out 2>pack.err",
286 	    testprog);
287 	failure("Error invoking \"%s cf archive --format=ustar\"", testprog);
288 	assertEqualInt(r, 0);
289 
290 	/* Verify that nothing went to stdout. */
291 	assertEmptyFile("pack.out");
292 	/* Stderr is non-empty, since there are a bunch of files
293 	 * with filenames too long to archive. */
294 
295 	/*
296 	 * Use tar to unpack the archive into another directory.
297 	 */
298 	r = systemf("%s xf archive >unpack.out 2>unpack.err", testprog);
299 	failure("Error invoking %s xf archive", testprog);
300 	assertEqualInt(r, 0);
301 
302 	/* Verify that nothing went to stdout or stderr. */
303 	assertEmptyFile("unpack.err");
304 	assertEmptyFile("unpack.out");
305 
306 	chdir("original");
307 	verify_tree(LIMIT_USTAR);
308 	chdir("../..");
309 }
310 
311 DEFINE_TEST(test_copy)
312 {
313 	int oldumask;
314 
315 	oldumask = umask(0);
316 
317 	create_tree(); /* Create sample files in "original" dir. */
318 
319 	/* Test simple "tar -c | tar -x" pipeline copy. */
320 	copy_basic();
321 
322 	/* Same, but constrain to ustar format. */
323 	copy_ustar();
324 
325 	umask(oldumask);
326 }
327