test_read_disk_directory_traversals.c revision 358088
1/*-
2 * Copyright (c) 2010-2012 Michihiro NAKAJIMA
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$");
27
28#include <limits.h>
29#if defined(_WIN32) && !defined(__CYGWIN__)
30# if !defined(__BORLANDC__)
31#  define getcwd _getcwd
32# endif
33#endif
34
35/*
36 * Test if the current filesystem is mounted with noatime option.
37 */
38static int
39atimeIsUpdated(void)
40{
41	const char *fn = "fs_noatime";
42	struct stat st;
43#if defined(_WIN32) && !defined(CYGWIN)
44	char *buff = NULL;
45	char *ptr;
46	int r;
47
48	r = systemf("fsutil behavior query disableLastAccess > query_atime");
49	if (r == 0) {
50		buff = slurpfile(NULL, "query_atime");
51		if (buff != NULL) {
52			ptr = buff;
53			while(*ptr != '\0' && !isdigit(*ptr)) {
54				ptr++;
55			}
56			if (*ptr == '0') {
57				free(buff);
58				return(1);
59			} else if (*ptr == '1' || *ptr == '2') {
60				free(buff);
61				return(0);
62			}
63			free(buff);
64		}
65	}
66#endif
67	if (!assertMakeFile(fn, 0666, "a"))
68		return (0);
69	if (!assertUtimes(fn, 1, 0, 1, 0))
70		return (0);
71	/* Test the file contents in order to update its atime. */
72	if (!assertTextFileContents("a", fn))
73		return (0);
74	if (stat(fn, &st) != 0)
75		return (0);
76	/* Is atime updated? */
77	if (st.st_atime > 1)
78		return (1);
79	return (0);
80}
81
82static void
83test_basic(void)
84{
85	struct archive *a;
86	struct archive_entry *ae;
87	const void *p;
88	char *initial_cwd, *cwd;
89	size_t size;
90	int64_t offset;
91	int file_count;
92#if defined(_WIN32) && !defined(__CYGWIN__)
93	wchar_t *wcwd, *wp, *fullpath;
94#endif
95
96	assertMakeDir("dir1", 0755);
97	assertMakeFile("dir1/file1", 0644, "0123456789");
98	assertMakeFile("dir1/file2", 0644, "hello world");
99	assertMakeDir("dir1/sub1", 0755);
100	assertMakeFile("dir1/sub1/file1", 0644, "0123456789");
101	assertMakeDir("dir1/sub2", 0755);
102	assertMakeFile("dir1/sub2/file1", 0644, "0123456789");
103	assertMakeFile("dir1/sub2/file2", 0644, "0123456789");
104	assertMakeDir("dir1/sub2/sub1", 0755);
105	assertMakeDir("dir1/sub2/sub2", 0755);
106	assertMakeDir("dir1/sub2/sub3", 0755);
107	assertMakeFile("dir1/sub2/sub3/file", 0644, "xyz");
108	file_count = 12;
109
110	assert((ae = archive_entry_new()) != NULL);
111	assert((a = archive_read_disk_new()) != NULL);
112	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "dir1"));
113
114	while (file_count--) {
115		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
116		if (strcmp(archive_entry_pathname(ae), "dir1") == 0) {
117			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
118			assertEqualInt(1, archive_read_disk_can_descend(a));
119		} else if (strcmp(archive_entry_pathname(ae),
120		    "dir1/file1") == 0) {
121			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
122			assertEqualInt(archive_entry_size(ae), 10);
123			assertEqualIntA(a, ARCHIVE_OK,
124			    archive_read_data_block(a, &p, &size, &offset));
125			assertEqualInt((int)size, 10);
126			assertEqualInt((int)offset, 0);
127			assertEqualMem(p, "0123456789", 10);
128			assertEqualInt(ARCHIVE_EOF,
129			    archive_read_data_block(a, &p, &size, &offset));
130			assertEqualInt((int)size, 0);
131			assertEqualInt((int)offset, 10);
132			assertEqualInt(0, archive_read_disk_can_descend(a));
133		} else if (strcmp(archive_entry_pathname(ae),
134		    "dir1/file2") == 0) {
135			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
136			assertEqualInt(archive_entry_size(ae), 11);
137			assertEqualIntA(a, ARCHIVE_OK,
138			    archive_read_data_block(a, &p, &size, &offset));
139			assertEqualInt((int)size, 11);
140			assertEqualInt((int)offset, 0);
141			assertEqualMem(p, "hello world", 11);
142			assertEqualInt(ARCHIVE_EOF,
143			    archive_read_data_block(a, &p, &size, &offset));
144			assertEqualInt((int)size, 0);
145			assertEqualInt((int)offset, 11);
146			assertEqualInt(0, archive_read_disk_can_descend(a));
147		} else if (strcmp(archive_entry_pathname(ae),
148		    "dir1/sub1") == 0) {
149			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
150			assertEqualInt(1, archive_read_disk_can_descend(a));
151		} else if (strcmp(archive_entry_pathname(ae),
152		    "dir1/sub1/file1") == 0) {
153			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
154			assertEqualInt(archive_entry_size(ae), 10);
155			assertEqualIntA(a, ARCHIVE_OK,
156			    archive_read_data_block(a, &p, &size, &offset));
157			assertEqualInt((int)size, 10);
158			assertEqualInt((int)offset, 0);
159			assertEqualMem(p, "0123456789", 10);
160			assertEqualInt(ARCHIVE_EOF,
161			    archive_read_data_block(a, &p, &size, &offset));
162			assertEqualInt((int)size, 0);
163			assertEqualInt((int)offset, 10);
164			assertEqualInt(0, archive_read_disk_can_descend(a));
165		} else if (strcmp(archive_entry_pathname(ae),
166		    "dir1/sub2") == 0) {
167			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
168			assertEqualInt(1, archive_read_disk_can_descend(a));
169		} else if (strcmp(archive_entry_pathname(ae),
170		    "dir1/sub2/file1") == 0) {
171			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
172			assertEqualInt(archive_entry_size(ae), 10);
173			assertEqualIntA(a, ARCHIVE_OK,
174			    archive_read_data_block(a, &p, &size, &offset));
175			assertEqualInt((int)size, 10);
176			assertEqualInt((int)offset, 0);
177			assertEqualMem(p, "0123456789", 10);
178			assertEqualInt(ARCHIVE_EOF,
179			    archive_read_data_block(a, &p, &size, &offset));
180			assertEqualInt((int)size, 0);
181			assertEqualInt((int)offset, 10);
182			assertEqualInt(0, archive_read_disk_can_descend(a));
183		} else if (strcmp(archive_entry_pathname(ae),
184		    "dir1/sub2/file2") == 0) {
185			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
186			assertEqualInt(archive_entry_size(ae), 10);
187			assertEqualIntA(a, ARCHIVE_OK,
188			    archive_read_data_block(a, &p, &size, &offset));
189			assertEqualInt((int)size, 10);
190			assertEqualInt((int)offset, 0);
191			assertEqualMem(p, "0123456789", 10);
192			assertEqualInt(ARCHIVE_EOF,
193			    archive_read_data_block(a, &p, &size, &offset));
194			assertEqualInt((int)size, 0);
195			assertEqualInt((int)offset, 10);
196			assertEqualInt(0, archive_read_disk_can_descend(a));
197		} else if (strcmp(archive_entry_pathname(ae),
198		    "dir1/sub2/sub1") == 0) {
199			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
200			assertEqualInt(1, archive_read_disk_can_descend(a));
201		} else if (strcmp(archive_entry_pathname(ae),
202		    "dir1/sub2/sub2") == 0) {
203			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
204			assertEqualInt(1, archive_read_disk_can_descend(a));
205		} else if (strcmp(archive_entry_pathname(ae),
206		    "dir1/sub2/sub3") == 0) {
207			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
208			assertEqualInt(1, archive_read_disk_can_descend(a));
209		} else if (strcmp(archive_entry_pathname(ae),
210		    "dir1/sub2/sub3/file") == 0) {
211			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
212			assertEqualInt(archive_entry_size(ae), 3);
213			assertEqualIntA(a, ARCHIVE_OK,
214			    archive_read_data_block(a, &p, &size, &offset));
215			assertEqualInt((int)size, 3);
216			assertEqualInt((int)offset, 0);
217			assertEqualMem(p, "xyz", 3);
218			assertEqualInt(ARCHIVE_EOF,
219			    archive_read_data_block(a, &p, &size, &offset));
220			assertEqualInt((int)size, 0);
221			assertEqualInt((int)offset, 3);
222			assertEqualInt(0, archive_read_disk_can_descend(a));
223		}
224		if (archive_entry_filetype(ae) == AE_IFDIR) {
225			/* Descend into the current object */
226			assertEqualIntA(a, ARCHIVE_OK,
227			    archive_read_disk_descend(a));
228		}
229	}
230	/* There is no entry. */
231	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
232
233	/* Close the disk object. */
234	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
235
236	/*
237	 * Test that call archive_read_disk_open_w, wchar_t version.
238	 */
239	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open_w(a, L"dir1"));
240
241	file_count = 12;
242	while (file_count--) {
243		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
244		if (wcscmp(archive_entry_pathname_w(ae), L"dir1") == 0) {
245			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
246			assertEqualInt(1, archive_read_disk_can_descend(a));
247		} else if (wcscmp(archive_entry_pathname_w(ae),
248		    L"dir1/file1") == 0) {
249			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
250			assertEqualInt(archive_entry_size(ae), 10);
251			assertEqualIntA(a, ARCHIVE_OK,
252			    archive_read_data_block(a, &p, &size, &offset));
253			assertEqualInt((int)size, 10);
254			assertEqualInt((int)offset, 0);
255			assertEqualMem(p, "0123456789", 10);
256			assertEqualInt(ARCHIVE_EOF,
257			    archive_read_data_block(a, &p, &size, &offset));
258			assertEqualInt((int)size, 0);
259			assertEqualInt((int)offset, 10);
260			assertEqualInt(0, archive_read_disk_can_descend(a));
261		} else if (wcscmp(archive_entry_pathname_w(ae),
262		    L"dir1/file2") == 0) {
263			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
264			assertEqualInt(archive_entry_size(ae), 11);
265			assertEqualIntA(a, ARCHIVE_OK,
266			    archive_read_data_block(a, &p, &size, &offset));
267			assertEqualInt((int)size, 11);
268			assertEqualInt((int)offset, 0);
269			assertEqualMem(p, "hello world", 11);
270			assertEqualInt(ARCHIVE_EOF,
271			    archive_read_data_block(a, &p, &size, &offset));
272			assertEqualInt((int)size, 0);
273			assertEqualInt((int)offset, 11);
274			assertEqualInt(0, archive_read_disk_can_descend(a));
275		} else if (wcscmp(archive_entry_pathname_w(ae),
276		    L"dir1/sub1") == 0) {
277			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
278			assertEqualInt(1, archive_read_disk_can_descend(a));
279		} else if (wcscmp(archive_entry_pathname_w(ae),
280		    L"dir1/sub1/file1") == 0) {
281			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
282			assertEqualInt(archive_entry_size(ae), 10);
283			assertEqualIntA(a, ARCHIVE_OK,
284			    archive_read_data_block(a, &p, &size, &offset));
285			assertEqualInt((int)size, 10);
286			assertEqualInt((int)offset, 0);
287			assertEqualMem(p, "0123456789", 10);
288			assertEqualInt(ARCHIVE_EOF,
289			    archive_read_data_block(a, &p, &size, &offset));
290			assertEqualInt((int)size, 0);
291			assertEqualInt((int)offset, 10);
292			assertEqualInt(0, archive_read_disk_can_descend(a));
293		} else if (wcscmp(archive_entry_pathname_w(ae),
294		    L"dir1/sub2") == 0) {
295			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
296			assertEqualInt(1, archive_read_disk_can_descend(a));
297		} else if (wcscmp(archive_entry_pathname_w(ae),
298		    L"dir1/sub2/file1") == 0) {
299			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
300			assertEqualInt(archive_entry_size(ae), 10);
301			assertEqualIntA(a, ARCHIVE_OK,
302			    archive_read_data_block(a, &p, &size, &offset));
303			assertEqualInt((int)size, 10);
304			assertEqualInt((int)offset, 0);
305			assertEqualMem(p, "0123456789", 10);
306			assertEqualInt(ARCHIVE_EOF,
307			    archive_read_data_block(a, &p, &size, &offset));
308			assertEqualInt((int)size, 0);
309			assertEqualInt((int)offset, 10);
310			assertEqualInt(0, archive_read_disk_can_descend(a));
311		} else if (wcscmp(archive_entry_pathname_w(ae),
312		    L"dir1/sub2/file2") == 0) {
313			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
314			assertEqualInt(archive_entry_size(ae), 10);
315			assertEqualIntA(a, ARCHIVE_OK,
316			    archive_read_data_block(a, &p, &size, &offset));
317			assertEqualInt((int)size, 10);
318			assertEqualInt((int)offset, 0);
319			assertEqualMem(p, "0123456789", 10);
320			assertEqualInt(ARCHIVE_EOF,
321			    archive_read_data_block(a, &p, &size, &offset));
322			assertEqualInt((int)size, 0);
323			assertEqualInt((int)offset, 10);
324			assertEqualInt(0, archive_read_disk_can_descend(a));
325		} else if (wcscmp(archive_entry_pathname_w(ae),
326		    L"dir1/sub2/sub1") == 0) {
327			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
328			assertEqualInt(1, archive_read_disk_can_descend(a));
329		} else if (wcscmp(archive_entry_pathname_w(ae),
330		    L"dir1/sub2/sub2") == 0) {
331			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
332			assertEqualInt(1, archive_read_disk_can_descend(a));
333		} else if (wcscmp(archive_entry_pathname_w(ae),
334		    L"dir1/sub2/sub3") == 0) {
335			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
336			assertEqualInt(1, archive_read_disk_can_descend(a));
337		} else if (wcscmp(archive_entry_pathname_w(ae),
338		    L"dir1/sub2/sub3/file") == 0) {
339			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
340			assertEqualInt(archive_entry_size(ae), 3);
341			assertEqualIntA(a, ARCHIVE_OK,
342			    archive_read_data_block(a, &p, &size, &offset));
343			assertEqualInt((int)size, 3);
344			assertEqualInt((int)offset, 0);
345			assertEqualMem(p, "xyz", 3);
346			assertEqualInt(ARCHIVE_EOF,
347			    archive_read_data_block(a, &p, &size, &offset));
348			assertEqualInt((int)size, 0);
349			assertEqualInt((int)offset, 3);
350			assertEqualInt(0, archive_read_disk_can_descend(a));
351		}
352		if (archive_entry_filetype(ae) == AE_IFDIR) {
353			/* Descend into the current object */
354			assertEqualIntA(a, ARCHIVE_OK,
355			    archive_read_disk_descend(a));
356		}
357	}
358	/* There is no entry. */
359	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
360
361	/* Close the disk object. */
362	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
363
364	/*
365	 * Test that call archive_read_disk_open with a regular file.
366	 */
367	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "dir1/file1"));
368
369	/* dir1/file1 */
370	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
371	assertEqualInt(0, archive_read_disk_can_descend(a));
372	assertEqualString(archive_entry_pathname(ae), "dir1/file1");
373	assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
374	assertEqualInt(archive_entry_size(ae), 10);
375	assertEqualIntA(a, ARCHIVE_OK,
376	    archive_read_data_block(a, &p, &size, &offset));
377	assertEqualInt((int)size, 10);
378	assertEqualInt((int)offset, 0);
379	assertEqualMem(p, "0123456789", 10);
380
381	/* There is no entry. */
382	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
383
384	/* Close the disk object. */
385	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
386
387
388#if defined(_WIN32) && !defined(__CYGWIN__)
389	/*
390	 * Test for wildcard '*' or '?'
391	 */
392	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "dir1/*1"));
393
394	/* dir1/file1 */
395	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
396	assertEqualInt(0, archive_read_disk_can_descend(a));
397	assertEqualString(archive_entry_pathname(ae), "dir1/file1");
398	assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
399	assertEqualInt(archive_entry_size(ae), 10);
400	assertEqualIntA(a, ARCHIVE_OK,
401	    archive_read_data_block(a, &p, &size, &offset));
402	assertEqualInt((int)size, 10);
403	assertEqualInt((int)offset, 0);
404	assertEqualMem(p, "0123456789", 10);
405
406	/* dir1/sub1 */
407	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
408	assertEqualInt(1, archive_read_disk_can_descend(a));
409	assertEqualString(archive_entry_pathname(ae), "dir1/sub1");
410	assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
411
412	/* Descend into the current object */
413	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_descend(a));
414
415	/* dir1/sub1/file1 */
416	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
417	assertEqualInt(0, archive_read_disk_can_descend(a));
418	assertEqualString(archive_entry_pathname(ae), "dir1/sub1/file1");
419	assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
420	assertEqualInt(archive_entry_size(ae), 10);
421	assertEqualIntA(a, ARCHIVE_OK,
422	    archive_read_data_block(a, &p, &size, &offset));
423	assertEqualInt((int)size, 10);
424	assertEqualInt((int)offset, 0);
425	assertEqualMem(p, "0123456789", 10);
426
427	/* There is no entry. */
428	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
429
430	/* Close the disk object. */
431	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
432
433	/*
434	 * Test for a full-path beginning with "//?/"
435	 */
436	wcwd = _wgetcwd(NULL, 0);
437	fullpath = malloc(sizeof(wchar_t) * (wcslen(wcwd) + 32));
438	wcscpy(fullpath, L"//?/");
439	wcscat(fullpath, wcwd);
440	wcscat(fullpath, L"/dir1/file1");
441	free(wcwd);
442	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open_w(a, fullpath));
443	while ((wcwd = wcschr(fullpath, L'\\')) != NULL)
444		*wcwd = L'/';
445
446	/* dir1/file1 */
447	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
448	assertEqualInt(0, archive_read_disk_can_descend(a));
449	assertEqualWString(archive_entry_pathname_w(ae), fullpath);
450	assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
451	assertEqualInt(archive_entry_size(ae), 10);
452	assertEqualIntA(a, ARCHIVE_OK,
453	    archive_read_data_block(a, &p, &size, &offset));
454	assertEqualInt((int)size, 10);
455	assertEqualInt((int)offset, 0);
456	assertEqualMem(p, "0123456789", 10);
457
458	/* There is no entry. */
459	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
460
461	/* Close the disk object. */
462	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
463	free(fullpath);
464
465	/*
466	 * Test for wild card '*' or '?' with "//?/" prefix.
467	 */
468	wcwd = _wgetcwd(NULL, 0);
469	fullpath = malloc(sizeof(wchar_t) * (wcslen(wcwd) + 32));
470	wcscpy(fullpath, L"//?/");
471	wcscat(fullpath, wcwd);
472	wcscat(fullpath, L"/dir1/*1");
473	free(wcwd);
474	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open_w(a, fullpath));
475	while ((wcwd = wcschr(fullpath, L'\\')) != NULL)
476		*wcwd = L'/';
477
478	/* dir1/file1 */
479	wp = wcsrchr(fullpath, L'/');
480	wcscpy(wp+1, L"file1");
481	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
482	assertEqualInt(0, archive_read_disk_can_descend(a));
483	assertEqualWString(archive_entry_pathname_w(ae), fullpath);
484	assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
485	assertEqualInt(archive_entry_size(ae), 10);
486	assertEqualIntA(a, ARCHIVE_OK,
487	    archive_read_data_block(a, &p, &size, &offset));
488	assertEqualInt((int)size, 10);
489	assertEqualInt((int)offset, 0);
490	assertEqualMem(p, "0123456789", 10);
491
492	/* dir1/sub1 */
493	wcscpy(wp+1, L"sub1");
494	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
495	assertEqualInt(1, archive_read_disk_can_descend(a));
496	assertEqualWString(archive_entry_pathname_w(ae), fullpath);
497	assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
498
499	/* Descend into the current object */
500	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_descend(a));
501
502	/* dir1/sub1/file1 */
503	wcscpy(wp+1, L"sub1/file1");
504	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
505	assertEqualInt(0, archive_read_disk_can_descend(a));
506	assertEqualWString(archive_entry_pathname_w(ae), fullpath);
507	assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
508	assertEqualInt(archive_entry_size(ae), 10);
509	assertEqualIntA(a, ARCHIVE_OK,
510	    archive_read_data_block(a, &p, &size, &offset));
511	assertEqualInt((int)size, 10);
512	assertEqualInt((int)offset, 0);
513	assertEqualMem(p, "0123456789", 10);
514
515	/* There is no entry. */
516	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
517
518	/* Close the disk object. */
519	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
520	free(fullpath);
521
522#endif
523
524	/*
525	 * We should be on the initial directory where we performed
526	 * archive_read_disk_new() after we perform archive_read_free()
527	 * even if we broke off the directory traversals.
528	 */
529
530	/* Save current working directory. */
531#ifdef PATH_MAX
532	initial_cwd = getcwd(NULL, PATH_MAX);/* Solaris getcwd needs the size. */
533#else
534	initial_cwd = getcwd(NULL, 0);
535#endif
536
537	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "dir1"));
538
539	/* Step in a deep directory. */
540	file_count = 12;
541	while (file_count--) {
542		assertEqualIntA(a, ARCHIVE_OK,
543		    archive_read_next_header2(a, ae));
544		if (strcmp(archive_entry_pathname(ae),
545		    "dir1/sub1/file1") == 0)
546			/*
547			 * We are on an another directory at this time.
548			 */
549			break;
550		if (archive_entry_filetype(ae) == AE_IFDIR) {
551			/* Descend into the current object */
552			assertEqualIntA(a, ARCHIVE_OK,
553			    archive_read_disk_descend(a));
554		}
555	}
556	/* Destroy the disk object. */
557	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
558
559	/* We should be on the initial working directory. */
560	failure(
561	    "Current working directory does not return to the initial"
562	    "directory");
563#ifdef PATH_MAX
564	cwd = getcwd(NULL, PATH_MAX);/* Solaris getcwd needs the size. */
565#else
566	cwd = getcwd(NULL, 0);
567#endif
568	assertEqualString(initial_cwd, cwd);
569	free(initial_cwd);
570	free(cwd);
571
572	archive_entry_free(ae);
573}
574
575static void
576test_symlink_hybrid(void)
577{
578	struct archive *a;
579	struct archive_entry *ae;
580	const void *p;
581	size_t size;
582	int64_t offset;
583	int file_count;
584
585	if (!canSymlink()) {
586		skipping("Can't test symlinks on this filesystem");
587		return;
588	}
589
590	/*
591	 * Create a sample archive.
592	 */
593	assertMakeDir("h", 0755);
594	assertChdir("h");
595	assertMakeDir("d1", 0755);
596	assertMakeSymlink("ld1", "d1", 1);
597	assertMakeFile("d1/file1", 0644, "d1/file1");
598	assertMakeFile("d1/file2", 0644, "d1/file2");
599	assertMakeSymlink("d1/link1", "file1", 0);
600	assertMakeSymlink("d1/linkX", "fileX", 0);
601	assertMakeSymlink("link2", "d1/file2", 0);
602	assertMakeSymlink("linkY", "d1/fileY", 0);
603	assertChdir("..");
604
605	assert((ae = archive_entry_new()) != NULL);
606	assert((a = archive_read_disk_new()) != NULL);
607	assertEqualIntA(a, ARCHIVE_OK,
608	    archive_read_disk_set_symlink_hybrid(a));
609
610	/*
611	 * Specified file is a symbolic link file.
612	 */
613	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "h/ld1"));
614	file_count = 5;
615
616	while (file_count--) {
617		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
618		if (strcmp(archive_entry_pathname(ae), "h/ld1") == 0) {
619			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
620		} else if (strcmp(archive_entry_pathname(ae),
621		    "h/ld1/file1") == 0) {
622			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
623			assertEqualInt(archive_entry_size(ae), 8);
624			assertEqualIntA(a, ARCHIVE_OK,
625			    archive_read_data_block(a, &p, &size, &offset));
626			assertEqualInt((int)size, 8);
627			assertEqualInt((int)offset, 0);
628			assertEqualMem(p, "d1/file1", 8);
629			assertEqualInt(ARCHIVE_EOF,
630			    archive_read_data_block(a, &p, &size, &offset));
631			assertEqualInt((int)size, 0);
632			assertEqualInt((int)offset, 8);
633		} else if (strcmp(archive_entry_pathname(ae),
634		    "h/ld1/file2") == 0) {
635			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
636			assertEqualInt(archive_entry_size(ae), 8);
637			assertEqualIntA(a, ARCHIVE_OK,
638			    archive_read_data_block(a, &p, &size, &offset));
639			assertEqualInt((int)size, 8);
640			assertEqualInt((int)offset, 0);
641			assertEqualMem(p, "d1/file2", 8);
642			assertEqualInt(ARCHIVE_EOF,
643			    archive_read_data_block(a, &p, &size, &offset));
644			assertEqualInt((int)size, 0);
645			assertEqualInt((int)offset, 8);
646		} else if (strcmp(archive_entry_pathname(ae),
647		    "h/ld1/link1") == 0) {
648			assertEqualInt(archive_entry_filetype(ae), AE_IFLNK);
649		} else if (strcmp(archive_entry_pathname(ae),
650		    "h/ld1/linkX") == 0) {
651			assertEqualInt(archive_entry_filetype(ae), AE_IFLNK);
652		}
653		if (archive_entry_filetype(ae) == AE_IFDIR) {
654			/* Descend into the current object */
655			assertEqualIntA(a, ARCHIVE_OK,
656			    archive_read_disk_descend(a));
657		}
658	}
659	/* There is no entry. */
660	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
661	/* Close the disk object. */
662	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
663
664	/*
665	 * Specified file is a directory and it has symbolic files.
666	 */
667	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "h"));
668	file_count = 9;
669
670	while (file_count--) {
671		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
672		if (strcmp(archive_entry_pathname(ae), "h") == 0) {
673			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
674		} else if (strcmp(archive_entry_pathname(ae), "h/d1") == 0) {
675			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
676		} else if (strcmp(archive_entry_pathname(ae),
677		    "h/d1/file1") == 0) {
678			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
679			assertEqualInt(archive_entry_size(ae), 8);
680			assertEqualIntA(a, ARCHIVE_OK,
681			    archive_read_data_block(a, &p, &size, &offset));
682			assertEqualInt((int)size, 8);
683			assertEqualInt((int)offset, 0);
684			assertEqualMem(p, "d1/file1", 8);
685			assertEqualInt(ARCHIVE_EOF,
686			    archive_read_data_block(a, &p, &size, &offset));
687			assertEqualInt((int)size, 0);
688			assertEqualInt((int)offset, 8);
689		} else if (strcmp(archive_entry_pathname(ae),
690		    "h/d1/file2") == 0) {
691			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
692			assertEqualInt(archive_entry_size(ae), 8);
693			assertEqualIntA(a, ARCHIVE_OK,
694			    archive_read_data_block(a, &p, &size, &offset));
695			assertEqualInt((int)size, 8);
696			assertEqualInt((int)offset, 0);
697			assertEqualMem(p, "d1/file2", 8);
698			assertEqualInt(ARCHIVE_EOF,
699			    archive_read_data_block(a, &p, &size, &offset));
700			assertEqualInt((int)size, 0);
701			assertEqualInt((int)offset, 8);
702		} else if (strcmp(archive_entry_pathname(ae), "h/ld1") == 0) {
703			assertEqualInt(archive_entry_filetype(ae), AE_IFLNK);
704		} else if (strcmp(archive_entry_pathname(ae),
705		    "h/d1/link1") == 0) {
706			assertEqualInt(archive_entry_filetype(ae), AE_IFLNK);
707		} else if (strcmp(archive_entry_pathname(ae),
708		    "h/d1/linkX") == 0) {
709			assertEqualInt(archive_entry_filetype(ae), AE_IFLNK);
710		} else if (strcmp(archive_entry_pathname(ae),
711		    "h/link2") == 0) {
712			assertEqualInt(archive_entry_filetype(ae), AE_IFLNK);
713		} else if (strcmp(archive_entry_pathname(ae),
714		    "h/linkY") == 0) {
715			assertEqualInt(archive_entry_filetype(ae), AE_IFLNK);
716		}
717		if (archive_entry_filetype(ae) == AE_IFDIR) {
718			/* Descend into the current object */
719			assertEqualIntA(a, ARCHIVE_OK,
720			    archive_read_disk_descend(a));
721		}
722	}
723	/* There is no entry. */
724	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
725	/* Close the disk object. */
726	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
727	/* Destroy the disk object. */
728	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
729	archive_entry_free(ae);
730}
731
732static void
733test_symlink_logical(void)
734{
735	struct archive *a;
736	struct archive_entry *ae;
737	const void *p;
738	size_t size;
739	int64_t offset;
740	int file_count;
741
742	if (!canSymlink()) {
743		skipping("Can't test symlinks on this filesystem");
744		return;
745	}
746
747	/*
748	 * Create a sample archive.
749	 */
750	assertMakeDir("l", 0755);
751	assertChdir("l");
752	assertMakeDir("d1", 0755);
753	assertMakeSymlink("ld1", "d1", 1);
754	assertMakeFile("d1/file1", 0644, "d1/file1");
755	assertMakeFile("d1/file2", 0644, "d1/file2");
756	assertMakeSymlink("d1/link1", "file1", 0);
757	assertMakeSymlink("d1/linkX", "fileX", 0);
758	assertMakeSymlink("link2", "d1/file2", 0);
759	assertMakeSymlink("linkY", "d1/fileY", 0);
760	assertChdir("..");
761
762	/* Note: this test uses archive_read_next_header()
763	   instead of archive_read_next_header2() */
764	assert((a = archive_read_disk_new()) != NULL);
765	assertEqualIntA(a, ARCHIVE_OK,
766	    archive_read_disk_set_symlink_logical(a));
767
768	/*
769	 * Specified file is a symbolic link file.
770	 */
771	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "l/ld1"));
772	file_count = 5;
773
774	while (file_count--) {
775		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
776		if (strcmp(archive_entry_pathname(ae), "l/ld1") == 0) {
777			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
778		} else if (strcmp(archive_entry_pathname(ae),
779		    "l/ld1/file1") == 0) {
780			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
781			assertEqualInt(archive_entry_size(ae), 8);
782			assertEqualIntA(a, ARCHIVE_OK,
783			    archive_read_data_block(a, &p, &size, &offset));
784			assertEqualInt((int)size, 8);
785			assertEqualInt((int)offset, 0);
786			assertEqualMem(p, "d1/file1", 8);
787			assertEqualInt(ARCHIVE_EOF,
788			    archive_read_data_block(a, &p, &size, &offset));
789			assertEqualInt((int)size, 0);
790			assertEqualInt((int)offset, 8);
791		} else if (strcmp(archive_entry_pathname(ae),
792		    "l/ld1/file2") == 0) {
793			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
794			assertEqualInt(archive_entry_size(ae), 8);
795			assertEqualIntA(a, ARCHIVE_OK,
796			    archive_read_data_block(a, &p, &size, &offset));
797			assertEqualInt((int)size, 8);
798			assertEqualInt((int)offset, 0);
799			assertEqualMem(p, "d1/file2", 8);
800			assertEqualInt(ARCHIVE_EOF,
801			    archive_read_data_block(a, &p, &size, &offset));
802			assertEqualInt((int)size, 0);
803			assertEqualInt((int)offset, 8);
804		} else if (strcmp(archive_entry_pathname(ae),
805		    "l/ld1/link1") == 0) {
806			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
807			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
808			assertEqualInt(archive_entry_size(ae), 8);
809			assertEqualIntA(a, ARCHIVE_OK,
810			    archive_read_data_block(a, &p, &size, &offset));
811			assertEqualInt((int)size, 8);
812			assertEqualInt((int)offset, 0);
813			assertEqualMem(p, "d1/file1", 8);
814			assertEqualInt(ARCHIVE_EOF,
815			    archive_read_data_block(a, &p, &size, &offset));
816			assertEqualInt((int)size, 0);
817			assertEqualInt((int)offset, 8);
818		} else if (strcmp(archive_entry_pathname(ae),
819		    "l/ld1/linkX") == 0) {
820			assertEqualInt(archive_entry_filetype(ae), AE_IFLNK);
821		}
822		if (archive_entry_filetype(ae) == AE_IFDIR) {
823			/* Descend into the current object */
824			assertEqualIntA(a, ARCHIVE_OK,
825			    archive_read_disk_descend(a));
826		}
827	}
828	/* There is no entry. */
829	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
830	/* Close the disk object. */
831	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
832
833	/*
834	 * Specified file is a directory and it has symbolic files.
835	 */
836	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "l"));
837	file_count = 13;
838
839	while (file_count--) {
840		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
841		if (strcmp(archive_entry_pathname(ae), "l") == 0) {
842			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
843		} else if (strcmp(archive_entry_pathname(ae), "l/d1") == 0) {
844			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
845		} else if (strcmp(archive_entry_pathname(ae),
846		    "l/d1/file1") == 0) {
847			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
848			assertEqualInt(archive_entry_size(ae), 8);
849			assertEqualIntA(a, ARCHIVE_OK,
850			    archive_read_data_block(a, &p, &size, &offset));
851			assertEqualInt((int)size, 8);
852			assertEqualInt((int)offset, 0);
853			assertEqualMem(p, "d1/file1", 8);
854			assertEqualInt(ARCHIVE_EOF,
855			    archive_read_data_block(a, &p, &size, &offset));
856			assertEqualInt((int)size, 0);
857			assertEqualInt((int)offset, 8);
858		} else if (strcmp(archive_entry_pathname(ae),
859		    "l/d1/file2") == 0) {
860			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
861			assertEqualInt(archive_entry_size(ae), 8);
862			assertEqualIntA(a, ARCHIVE_OK,
863			    archive_read_data_block(a, &p, &size, &offset));
864			assertEqualInt((int)size, 8);
865			assertEqualInt((int)offset, 0);
866			assertEqualMem(p, "d1/file2", 8);
867			assertEqualInt(ARCHIVE_EOF,
868			    archive_read_data_block(a, &p, &size, &offset));
869			assertEqualInt((int)size, 0);
870			assertEqualInt((int)offset, 8);
871		} else if (strcmp(archive_entry_pathname(ae),
872		    "l/d1/link1") == 0) {
873			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
874			assertEqualInt(archive_entry_size(ae), 8);
875			assertEqualIntA(a, ARCHIVE_OK,
876			    archive_read_data_block(a, &p, &size, &offset));
877			assertEqualInt((int)size, 8);
878			assertEqualInt((int)offset, 0);
879			assertEqualMem(p, "d1/file1", 8);
880			assertEqualInt(ARCHIVE_EOF,
881			    archive_read_data_block(a, &p, &size, &offset));
882			assertEqualInt((int)size, 0);
883			assertEqualInt((int)offset, 8);
884		} else if (strcmp(archive_entry_pathname(ae),
885		    "l/d1/linkX") == 0) {
886			assertEqualInt(archive_entry_filetype(ae), AE_IFLNK);
887		} else if (strcmp(archive_entry_pathname(ae), "l/ld1") == 0) {
888			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
889		} else if (strcmp(archive_entry_pathname(ae),
890		    "l/ld1/file1") == 0) {
891			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
892			assertEqualInt(archive_entry_size(ae), 8);
893			assertEqualIntA(a, ARCHIVE_OK,
894			    archive_read_data_block(a, &p, &size, &offset));
895			assertEqualInt((int)size, 8);
896			assertEqualInt((int)offset, 0);
897			assertEqualMem(p, "d1/file1", 8);
898			assertEqualInt(ARCHIVE_EOF,
899			    archive_read_data_block(a, &p, &size, &offset));
900			assertEqualInt((int)size, 0);
901			assertEqualInt((int)offset, 8);
902		} else if (strcmp(archive_entry_pathname(ae),
903		    "l/ld1/file2") == 0) {
904			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
905			assertEqualInt(archive_entry_size(ae), 8);
906			assertEqualIntA(a, ARCHIVE_OK,
907			    archive_read_data_block(a, &p, &size, &offset));
908			assertEqualInt((int)size, 8);
909			assertEqualInt((int)offset, 0);
910			assertEqualMem(p, "d1/file2", 8);
911			assertEqualInt(ARCHIVE_EOF,
912			    archive_read_data_block(a, &p, &size, &offset));
913			assertEqualInt((int)size, 0);
914			assertEqualInt((int)offset, 8);
915		} else if (strcmp(archive_entry_pathname(ae),
916		    "l/ld1/link1") == 0) {
917			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
918			assertEqualInt(archive_entry_size(ae), 8);
919			assertEqualIntA(a, ARCHIVE_OK,
920			    archive_read_data_block(a, &p, &size, &offset));
921			assertEqualInt((int)size, 8);
922			assertEqualInt((int)offset, 0);
923			assertEqualMem(p, "d1/file1", 8);
924			assertEqualInt(ARCHIVE_EOF,
925			    archive_read_data_block(a, &p, &size, &offset));
926			assertEqualInt((int)size, 0);
927			assertEqualInt((int)offset, 8);
928		} else if (strcmp(archive_entry_pathname(ae),
929		    "l/ld1/linkX") == 0) {
930			assertEqualInt(archive_entry_filetype(ae), AE_IFLNK);
931		} else if (strcmp(archive_entry_pathname(ae),
932		    "l/link2") == 0) {
933			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
934			assertEqualInt(archive_entry_size(ae), 8);
935			assertEqualIntA(a, ARCHIVE_OK,
936			    archive_read_data_block(a, &p, &size, &offset));
937			assertEqualInt((int)size, 8);
938			assertEqualInt((int)offset, 0);
939			assertEqualMem(p, "d1/file2", 8);
940			assertEqualInt(ARCHIVE_EOF,
941			    archive_read_data_block(a, &p, &size, &offset));
942			assertEqualInt((int)size, 0);
943			assertEqualInt((int)offset, 8);
944		} else if (strcmp(archive_entry_pathname(ae),
945		    "l/linkY") == 0) {
946			assertEqualInt(archive_entry_filetype(ae), AE_IFLNK);
947		}
948		if (archive_entry_filetype(ae) == AE_IFDIR) {
949			/* Descend into the current object */
950			assertEqualIntA(a, ARCHIVE_OK,
951			    archive_read_disk_descend(a));
952		}
953	}
954	/* There is no entry. */
955	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
956	/* Close the disk object. */
957	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
958	/* Destroy the disk object. */
959	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
960}
961
962static void
963test_symlink_logical_loop(void)
964{
965	struct archive *a;
966	struct archive_entry *ae;
967	const void *p;
968	size_t size;
969	int64_t offset;
970	int file_count;
971
972	if (!canSymlink()) {
973		skipping("Can't test symlinks on this filesystem");
974		return;
975	}
976
977	/*
978	 * Create a sample archive.
979	 */
980	assertMakeDir("l2", 0755);
981	assertChdir("l2");
982	assertMakeDir("d1", 0755);
983	assertMakeDir("d1/d2", 0755);
984	assertMakeDir("d1/d2/d3", 0755);
985	assertMakeDir("d2", 0755);
986	assertMakeFile("d2/file1", 0644, "d2/file1");
987	assertMakeSymlink("d1/d2/ld1", "../../d1", 1);
988	assertMakeSymlink("d1/d2/ld2", "../../d2", 1);
989	assertChdir("..");
990
991	assert((ae = archive_entry_new()) != NULL);
992	assert((a = archive_read_disk_new()) != NULL);
993	assertEqualIntA(a, ARCHIVE_OK,
994	    archive_read_disk_set_symlink_logical(a));
995
996	/*
997	 * Specified file is a symbolic link file.
998	 */
999	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "l2/d1"));
1000	file_count = 6;
1001
1002	while (file_count--) {
1003		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
1004		if (strcmp(archive_entry_pathname(ae), "l2/d1") == 0) {
1005			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1006		} else if (strcmp(archive_entry_pathname(ae), "l2/d1/d2") == 0) {
1007			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1008		} else if (strcmp(archive_entry_pathname(ae), "l2/d1/d2/d3") == 0) {
1009			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1010		} else if (strcmp(archive_entry_pathname(ae), "l2/d1/d2/ld1") == 0) {
1011			assertEqualInt(archive_entry_filetype(ae), AE_IFLNK);
1012		} else if (strcmp(archive_entry_pathname(ae), "l2/d1/d2/ld2") == 0) {
1013			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1014		} else if (strcmp(archive_entry_pathname(ae),
1015		    "l2/d1/d2/ld2/file1") == 0) {
1016			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1017			assertEqualInt(archive_entry_size(ae), 8);
1018			assertEqualIntA(a, ARCHIVE_OK,
1019			    archive_read_data_block(a, &p, &size, &offset));
1020			assertEqualInt((int)size, 8);
1021			assertEqualInt((int)offset, 0);
1022			assertEqualMem(p, "d2/file1", 8);
1023			assertEqualInt(ARCHIVE_EOF,
1024			    archive_read_data_block(a, &p, &size, &offset));
1025			assertEqualInt((int)size, 0);
1026			assertEqualInt((int)offset, 8);
1027		}
1028		if (archive_entry_filetype(ae) == AE_IFDIR) {
1029			/* Descend into the current object */
1030			assertEqualIntA(a, ARCHIVE_OK,
1031			    archive_read_disk_descend(a));
1032		}
1033	}
1034	/* There is no entry. */
1035	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
1036	/* Destroy the disk object. */
1037	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
1038	archive_entry_free(ae);
1039}
1040
1041static void
1042test_restore_atime(void)
1043{
1044	struct archive *a;
1045	struct archive_entry *ae;
1046	const void *p;
1047	size_t size;
1048	int64_t offset;
1049	int file_count;
1050
1051	if (!atimeIsUpdated()) {
1052		skipping("Can't test restoring atime on this filesystem");
1053		return;
1054	}
1055
1056	assertMakeDir("at", 0755);
1057	assertMakeFile("at/f1", 0644, "0123456789");
1058	assertMakeFile("at/f2", 0644, "hello world");
1059	assertMakeFile("at/fe", 0644, NULL);
1060	assertUtimes("at/f1", 886600, 0, 886600, 0);
1061	assertUtimes("at/f2", 886611, 0, 886611, 0);
1062	assertUtimes("at/fe", 886611, 0, 886611, 0);
1063	assertUtimes("at", 886622, 0, 886622, 0);
1064	file_count = 4;
1065
1066	assert((ae = archive_entry_new()) != NULL);
1067	assert((a = archive_read_disk_new()) != NULL);
1068
1069	/*
1070	 * Test1: Traversals without archive_read_disk_set_atime_restored().
1071	 */
1072	failure("Directory traversals should work as well");
1073	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "at"));
1074	while (file_count--) {
1075		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
1076		if (strcmp(archive_entry_pathname(ae), "at") == 0) {
1077			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1078		} else if (strcmp(archive_entry_pathname(ae), "at/f1") == 0) {
1079			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1080			assertEqualInt(archive_entry_size(ae), 10);
1081			assertEqualIntA(a, ARCHIVE_OK,
1082			    archive_read_data_block(a, &p, &size, &offset));
1083			assertEqualInt((int)size, 10);
1084			assertEqualInt((int)offset, 0);
1085			assertEqualMem(p, "0123456789", 10);
1086			assertEqualInt(ARCHIVE_EOF,
1087			    archive_read_data_block(a, &p, &size, &offset));
1088			assertEqualInt((int)size, 0);
1089			assertEqualInt((int)offset, 10);
1090		} else if (strcmp(archive_entry_pathname(ae), "at/f2") == 0) {
1091			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1092			assertEqualInt(archive_entry_size(ae), 11);
1093			assertEqualIntA(a, ARCHIVE_OK,
1094			    archive_read_data_block(a, &p, &size, &offset));
1095			assertEqualInt((int)size, 11);
1096			assertEqualInt((int)offset, 0);
1097			assertEqualMem(p, "hello world", 11);
1098			assertEqualInt(ARCHIVE_EOF,
1099			    archive_read_data_block(a, &p, &size, &offset));
1100			assertEqualInt((int)size, 0);
1101			assertEqualInt((int)offset, 11);
1102		} else if (strcmp(archive_entry_pathname(ae), "at/fe") == 0) {
1103			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1104			assertEqualInt(archive_entry_size(ae), 0);
1105		}
1106		if (archive_entry_filetype(ae) == AE_IFDIR) {
1107			/* Descend into the current object */
1108			assertEqualIntA(a, ARCHIVE_OK,
1109			    archive_read_disk_descend(a));
1110		}
1111	}
1112	/* There is no entry. */
1113	failure("There must be no entry");
1114	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
1115
1116	/* On FreeBSD (and likely other systems), atime on
1117	   dirs does not change when it is read. */
1118	/* failure("Atime should be restored"); */
1119	/* assertFileAtimeRecent("at"); */
1120	failure("Atime should be restored");
1121	assertFileAtimeRecent("at/f1");
1122	failure("Atime should be restored");
1123	assertFileAtimeRecent("at/f2");
1124	failure("The atime of a empty file should not be changed");
1125	assertFileAtime("at/fe", 886611, 0);
1126
1127	/* Close the disk object. */
1128	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
1129
1130	/*
1131	 * Test2: Traversals with archive_read_disk_set_atime_restored().
1132	 */
1133	assertUtimes("at/f1", 886600, 0, 886600, 0);
1134	assertUtimes("at/f2", 886611, 0, 886611, 0);
1135	assertUtimes("at/fe", 886611, 0, 886611, 0);
1136	assertUtimes("at", 886622, 0, 886622, 0);
1137	file_count = 4;
1138	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_set_atime_restored(a));
1139	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "at"));
1140
1141	failure("Directory traversals should work as well");
1142	while (file_count--) {
1143		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
1144		if (strcmp(archive_entry_pathname(ae), "at") == 0) {
1145			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1146		} else if (strcmp(archive_entry_pathname(ae), "at/f1") == 0) {
1147			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1148			assertEqualInt(archive_entry_size(ae), 10);
1149			assertEqualIntA(a, ARCHIVE_OK,
1150			    archive_read_data_block(a, &p, &size, &offset));
1151			assertEqualInt((int)size, 10);
1152			assertEqualInt((int)offset, 0);
1153			assertEqualMem(p, "0123456789", 10);
1154			assertEqualInt(ARCHIVE_EOF,
1155			    archive_read_data_block(a, &p, &size, &offset));
1156			assertEqualInt((int)size, 0);
1157			assertEqualInt((int)offset, 10);
1158		} else if (strcmp(archive_entry_pathname(ae), "at/f2") == 0) {
1159			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1160			assertEqualInt(archive_entry_size(ae), 11);
1161			assertEqualIntA(a, ARCHIVE_OK,
1162			    archive_read_data_block(a, &p, &size, &offset));
1163			assertEqualInt((int)size, 11);
1164			assertEqualInt((int)offset, 0);
1165			assertEqualMem(p, "hello world", 11);
1166			assertEqualInt(ARCHIVE_EOF,
1167			    archive_read_data_block(a, &p, &size, &offset));
1168			assertEqualInt((int)size, 0);
1169			assertEqualInt((int)offset, 11);
1170		} else if (strcmp(archive_entry_pathname(ae), "at/fe") == 0) {
1171			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1172			assertEqualInt(archive_entry_size(ae), 0);
1173		}
1174		if (archive_entry_filetype(ae) == AE_IFDIR) {
1175			/* Descend into the current object */
1176			assertEqualIntA(a, ARCHIVE_OK,
1177			    archive_read_disk_descend(a));
1178		}
1179	}
1180	/* There is no entry. */
1181	failure("There must be no entry");
1182	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
1183
1184	failure("Atime should be restored");
1185	assertFileAtime("at", 886622, 0);
1186	failure("Atime should be restored");
1187	assertFileAtime("at/f1", 886600, 0);
1188	failure("Atime should be restored");
1189	assertFileAtime("at/f2", 886611, 0);
1190	failure("The atime of a empty file should not be changed");
1191	assertFileAtime("at/fe", 886611, 0);
1192
1193	/* Close the disk object. */
1194	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
1195
1196	/*
1197	 * Test3: Traversals with archive_read_disk_set_atime_restored() but
1198	 * no data read as a listing.
1199	 */
1200	assertUtimes("at/f1", 886600, 0, 886600, 0);
1201	assertUtimes("at/f2", 886611, 0, 886611, 0);
1202	assertUtimes("at/fe", 886611, 0, 886611, 0);
1203	assertUtimes("at", 886622, 0, 886622, 0);
1204	file_count = 4;
1205	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_set_atime_restored(a));
1206	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "at"));
1207
1208	failure("Directory traversals should work as well");
1209	while (file_count--) {
1210		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
1211		if (strcmp(archive_entry_pathname(ae), "at") == 0) {
1212			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1213		} else if (strcmp(archive_entry_pathname(ae), "at/f1") == 0) {
1214			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1215			assertEqualInt(archive_entry_size(ae), 10);
1216		} else if (strcmp(archive_entry_pathname(ae), "at/f2") == 0) {
1217			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1218			assertEqualInt(archive_entry_size(ae), 11);
1219		} else if (strcmp(archive_entry_pathname(ae), "at/fe") == 0) {
1220			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1221			assertEqualInt(archive_entry_size(ae), 0);
1222		}
1223		if (archive_entry_filetype(ae) == AE_IFDIR) {
1224			/* Descend into the current object */
1225			assertEqualIntA(a, ARCHIVE_OK,
1226			    archive_read_disk_descend(a));
1227		}
1228	}
1229	/* There is no entry. */
1230	failure("There must be no entry");
1231	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
1232
1233	failure("Atime should be restored");
1234	assertFileAtime("at", 886622, 0);
1235	failure("Atime should be restored");
1236	assertFileAtime("at/f1", 886600, 0);
1237	failure("Atime should be restored");
1238	assertFileAtime("at/f2", 886611, 0);
1239	failure("The atime of a empty file should not be changed");
1240	assertFileAtime("at/fe", 886611, 0);
1241
1242	if (!canNodump()) {
1243		/* Destroy the disk object. */
1244		assertEqualInt(ARCHIVE_OK, archive_read_free(a));
1245		archive_entry_free(ae);
1246		skipping("Can't test atime with nodump on this filesystem");
1247		return;
1248	}
1249
1250	/* Close the disk object. */
1251	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
1252
1253	/*
1254	 * Test4: Traversals with ARCHIVE_READDISK_RESTORE_ATIME and
1255	 * ARCHIVE_READDISK_HONOR_NODUMP
1256	 */
1257	assertSetNodump("at/f1");
1258	assertSetNodump("at/f2");
1259	assertUtimes("at/f1", 886600, 0, 886600, 0);
1260	assertUtimes("at/f2", 886611, 0, 886611, 0);
1261	assertUtimes("at/fe", 886611, 0, 886611, 0);
1262	assertUtimes("at", 886622, 0, 886622, 0);
1263	file_count = 2;
1264	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_set_behavior(a,
1265		ARCHIVE_READDISK_RESTORE_ATIME | ARCHIVE_READDISK_HONOR_NODUMP));
1266	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "at"));
1267
1268	failure("Directory traversals should work as well");
1269	while (file_count--) {
1270		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
1271		if (strcmp(archive_entry_pathname(ae), "at") == 0) {
1272			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1273		} else if (strcmp(archive_entry_pathname(ae), "at/fe") == 0) {
1274			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1275			assertEqualInt(archive_entry_size(ae), 0);
1276		}
1277		if (archive_entry_filetype(ae) == AE_IFDIR) {
1278			/* Descend into the current object */
1279			assertEqualIntA(a, ARCHIVE_OK,
1280			    archive_read_disk_descend(a));
1281		}
1282	}
1283	/* There is no entry. */
1284	failure("There must be no entry");
1285	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
1286
1287	failure("Atime should be restored");
1288	assertFileAtime("at", 886622, 0);
1289	failure("Atime should be restored");
1290	assertFileAtime("at/f1", 886600, 0);
1291	failure("Atime should be restored");
1292	assertFileAtime("at/f2", 886611, 0);
1293	failure("The atime of a empty file should not be changed");
1294	assertFileAtime("at/fe", 886611, 0);
1295
1296	/* Destroy the disk object. */
1297	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
1298	archive_entry_free(ae);
1299}
1300
1301static int
1302metadata_filter(struct archive *a, void *data, struct archive_entry *ae)
1303{
1304	(void)data; /* UNUSED */
1305
1306	failure("CTime should be set");
1307	assertEqualInt(8, archive_entry_ctime_is_set(ae));
1308	failure("MTime should be set");
1309	assertEqualInt(16, archive_entry_mtime_is_set(ae));
1310
1311	if (archive_entry_mtime(ae) < 886611)
1312		return (0);
1313	if (archive_read_disk_can_descend(a)) {
1314		/* Descend into the current object */
1315		failure("archive_read_disk_can_descend should work"
1316			" in metadata filter");
1317		assertEqualIntA(a, 1, archive_read_disk_can_descend(a));
1318		failure("archive_read_disk_descend should work"
1319			" in metadata filter");
1320		assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_descend(a));
1321	}
1322	return (1);
1323}
1324
1325static void
1326test_callbacks(void)
1327{
1328	struct archive *a;
1329	struct archive *m;
1330	struct archive_entry *ae;
1331	const void *p;
1332	size_t size;
1333	int64_t offset;
1334	int file_count;
1335
1336	assertMakeDir("cb", 0755);
1337	assertMakeFile("cb/f1", 0644, "0123456789");
1338	assertMakeFile("cb/f2", 0644, "hello world");
1339	assertMakeFile("cb/fe", 0644, NULL);
1340	assertUtimes("cb/f1", 886600, 0, 886600, 0);
1341	assertUtimes("cb/f2", 886611, 0, 886611, 0);
1342	assertUtimes("cb/fe", 886611, 0, 886611, 0);
1343	assertUtimes("cb", 886622, 0, 886622, 0);
1344
1345	assert((ae = archive_entry_new()) != NULL);
1346	assert((a = archive_read_disk_new()) != NULL);
1347	if (a == NULL) {
1348		archive_entry_free(ae);
1349		return;
1350	}
1351	assert((m = archive_match_new()) != NULL);
1352	if (m == NULL) {
1353		archive_entry_free(ae);
1354		archive_read_free(a);
1355		archive_match_free(m);
1356		return;
1357	}
1358
1359	/*
1360	 * Test1: Traversals with a name filter.
1361	 */
1362	file_count = 3;
1363	assertEqualIntA(m, ARCHIVE_OK,
1364	    archive_match_exclude_pattern(m, "cb/f2"));
1365	assertEqualIntA(a, ARCHIVE_OK,
1366	    archive_read_disk_set_matching(a, m, NULL, NULL));
1367	failure("Directory traversals should work as well");
1368	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "cb"));
1369	while (file_count--) {
1370		archive_entry_clear(ae);
1371		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
1372		failure("File 'cb/f2' should be exclueded");
1373		assert(strcmp(archive_entry_pathname(ae), "cb/f2") != 0);
1374		if (strcmp(archive_entry_pathname(ae), "cb") == 0) {
1375			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1376		} else if (strcmp(archive_entry_pathname(ae), "cb/f1") == 0) {
1377			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1378			assertEqualInt(archive_entry_size(ae), 10);
1379			assertEqualIntA(a, ARCHIVE_OK,
1380			    archive_read_data_block(a, &p, &size, &offset));
1381			assertEqualInt((int)size, 10);
1382			assertEqualInt((int)offset, 0);
1383			assertEqualMem(p, "0123456789", 10);
1384			assertEqualInt(ARCHIVE_EOF,
1385			    archive_read_data_block(a, &p, &size, &offset));
1386			assertEqualInt((int)size, 0);
1387			assertEqualInt((int)offset, 10);
1388		} else if (strcmp(archive_entry_pathname(ae), "cb/fe") == 0) {
1389			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1390			assertEqualInt(archive_entry_size(ae), 0);
1391		}
1392		if (archive_read_disk_can_descend(a)) {
1393			/* Descend into the current object */
1394			assertEqualIntA(a, ARCHIVE_OK,
1395			    archive_read_disk_descend(a));
1396		}
1397	}
1398	/* There is no entry. */
1399	failure("There should be no entry");
1400	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
1401
1402	/* Close the disk object. */
1403	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
1404
1405	/* Reset name filter */
1406	assertEqualIntA(a, ARCHIVE_OK,
1407	    archive_read_disk_set_matching(a, NULL, NULL, NULL));
1408
1409	/*
1410	 * Test2: Traversals with a metadata filter.
1411	 */
1412	assertUtimes("cb/f1", 886600, 0, 886600, 0);
1413	assertUtimes("cb/f2", 886611, 0, 886611, 0);
1414	assertUtimes("cb/fe", 886611, 0, 886611, 0);
1415	assertUtimes("cb", 886622, 0, 886622, 0);
1416	file_count = 3;
1417	assertEqualIntA(a, ARCHIVE_OK,
1418	    archive_read_disk_set_metadata_filter_callback(a, metadata_filter,
1419		    NULL));
1420	failure("Directory traversals should work as well");
1421	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "cb"));
1422
1423	while (file_count--) {
1424		archive_entry_clear(ae);
1425		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
1426		failure("File 'cb/f1' should be excluded");
1427		assert(strcmp(archive_entry_pathname(ae), "cb/f1") != 0);
1428		if (strcmp(archive_entry_pathname(ae), "cb") == 0) {
1429			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1430		} else if (strcmp(archive_entry_pathname(ae), "cb/f2") == 0) {
1431			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1432			assertEqualInt(archive_entry_size(ae), 11);
1433			assertEqualIntA(a, ARCHIVE_OK,
1434			    archive_read_data_block(a, &p, &size, &offset));
1435			assertEqualInt((int)size, 11);
1436			assertEqualInt((int)offset, 0);
1437			assertEqualMem(p, "hello world", 11);
1438			assertEqualInt(ARCHIVE_EOF,
1439			    archive_read_data_block(a, &p, &size, &offset));
1440			assertEqualInt((int)size, 0);
1441			assertEqualInt((int)offset, 11);
1442		} else if (strcmp(archive_entry_pathname(ae), "cb/fe") == 0) {
1443			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1444			assertEqualInt(archive_entry_size(ae), 0);
1445		}
1446	}
1447	/* There is no entry. */
1448	failure("There should be no entry");
1449	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
1450
1451	/* Destroy the disk object. */
1452	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
1453	assertEqualInt(ARCHIVE_OK, archive_match_free(m));
1454	archive_entry_free(ae);
1455}
1456
1457static void
1458test_nodump(void)
1459{
1460	struct archive *a;
1461	struct archive_entry *ae;
1462	const void *p;
1463	size_t size;
1464	int64_t offset;
1465	int file_count;
1466
1467	if (!canNodump()) {
1468		skipping("Can't test nodump on this filesystem");
1469		return;
1470	}
1471
1472	assertMakeDir("nd", 0755);
1473	assertMakeFile("nd/f1", 0644, "0123456789");
1474	assertMakeFile("nd/f2", 0644, "hello world");
1475	assertMakeFile("nd/fe", 0644, NULL);
1476	assertSetNodump("nd/f2");
1477	assertUtimes("nd/f1", 886600, 0, 886600, 0);
1478	assertUtimes("nd/f2", 886611, 0, 886611, 0);
1479	assertUtimes("nd/fe", 886611, 0, 886611, 0);
1480	assertUtimes("nd", 886622, 0, 886622, 0);
1481
1482	assert((ae = archive_entry_new()) != NULL);
1483	assert((a = archive_read_disk_new()) != NULL);
1484
1485	/*
1486	 * Test1: Traversals without ARCHIVE_READDISK_HONOR_NODUMP
1487	 */
1488	failure("Directory traversals should work as well");
1489	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "nd"));
1490
1491	file_count = 4;
1492	while (file_count--) {
1493		archive_entry_clear(ae);
1494		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
1495		if (strcmp(archive_entry_pathname(ae), "nd") == 0) {
1496			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1497		} else if (strcmp(archive_entry_pathname(ae), "nd/f1") == 0) {
1498			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1499			assertEqualInt(archive_entry_size(ae), 10);
1500			assertEqualIntA(a, ARCHIVE_OK,
1501			    archive_read_data_block(a, &p, &size, &offset));
1502			assertEqualInt((int)size, 10);
1503			assertEqualInt((int)offset, 0);
1504			assertEqualMem(p, "0123456789", 10);
1505			assertEqualInt(ARCHIVE_EOF,
1506			    archive_read_data_block(a, &p, &size, &offset));
1507			assertEqualInt((int)size, 0);
1508			assertEqualInt((int)offset, 10);
1509		} else if (strcmp(archive_entry_pathname(ae), "nd/f2") == 0) {
1510			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1511			assertEqualInt(archive_entry_size(ae), 11);
1512			assertEqualIntA(a, ARCHIVE_OK,
1513			    archive_read_data_block(a, &p, &size, &offset));
1514			assertEqualInt((int)size, 11);
1515			assertEqualInt((int)offset, 0);
1516			assertEqualMem(p, "hello world", 11);
1517			assertEqualInt(ARCHIVE_EOF,
1518			    archive_read_data_block(a, &p, &size, &offset));
1519			assertEqualInt((int)size, 0);
1520			assertEqualInt((int)offset, 11);
1521		} else if (strcmp(archive_entry_pathname(ae), "nd/fe") == 0) {
1522			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1523			assertEqualInt(archive_entry_size(ae), 0);
1524		}
1525		if (archive_read_disk_can_descend(a)) {
1526			/* Descend into the current object */
1527			assertEqualIntA(a, ARCHIVE_OK,
1528			    archive_read_disk_descend(a));
1529		}
1530	}
1531	/* There is no entry. */
1532	failure("There should be no entry");
1533	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
1534
1535	/* Close the disk object. */
1536	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
1537
1538	/*
1539	 * Test2: Traversals with ARCHIVE_READDISK_HONOR_NODUMP
1540	 */
1541	assertUtimes("nd/f1", 886600, 0, 886600, 0);
1542	assertUtimes("nd/f2", 886611, 0, 886611, 0);
1543	assertUtimes("nd/fe", 886611, 0, 886611, 0);
1544	assertUtimes("nd", 886622, 0, 886622, 0);
1545
1546	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_set_behavior(a,
1547		ARCHIVE_READDISK_RESTORE_ATIME | ARCHIVE_READDISK_HONOR_NODUMP));
1548	failure("Directory traversals should work as well");
1549	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "nd"));
1550
1551	file_count = 3;
1552	while (file_count--) {
1553		archive_entry_clear(ae);
1554		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
1555		failure("File 'nd/f2' should be exclueded");
1556		assert(strcmp(archive_entry_pathname(ae), "nd/f2") != 0);
1557		if (strcmp(archive_entry_pathname(ae), "nd") == 0) {
1558			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1559		} else if (strcmp(archive_entry_pathname(ae), "nd/f1") == 0) {
1560			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1561			assertEqualInt(archive_entry_size(ae), 10);
1562			assertEqualIntA(a, ARCHIVE_OK,
1563			    archive_read_data_block(a, &p, &size, &offset));
1564			assertEqualInt((int)size, 10);
1565			assertEqualInt((int)offset, 0);
1566			assertEqualMem(p, "0123456789", 10);
1567			assertEqualInt(ARCHIVE_EOF,
1568			    archive_read_data_block(a, &p, &size, &offset));
1569			assertEqualInt((int)size, 0);
1570			assertEqualInt((int)offset, 10);
1571		} else if (strcmp(archive_entry_pathname(ae), "nd/fe") == 0) {
1572			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1573			assertEqualInt(archive_entry_size(ae), 0);
1574		}
1575		if (archive_read_disk_can_descend(a)) {
1576			/* Descend into the current object */
1577			assertEqualIntA(a, ARCHIVE_OK,
1578			    archive_read_disk_descend(a));
1579		}
1580	}
1581	/* There is no entry. */
1582	failure("There should be no entry");
1583	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
1584
1585	failure("Atime should be restored");
1586	assertFileAtime("nd/f2", 886611, 0);
1587
1588	/* Destroy the disk object. */
1589	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
1590	archive_entry_free(ae);
1591}
1592
1593static void
1594test_parent(void)
1595{
1596	struct archive *a;
1597	struct archive_entry *ae;
1598	const void *p;
1599	size_t size;
1600	int64_t offset;
1601	int file_count;
1602	int match_count;
1603	int r;
1604
1605	assertMakeDir("lock", 0311);
1606	assertMakeDir("lock/dir1", 0755);
1607	assertMakeFile("lock/dir1/f1", 0644, "0123456789");
1608	assertMakeDir("lock/lock2", 0311);
1609	assertMakeDir("lock/lock2/dir1", 0755);
1610	assertMakeFile("lock/lock2/dir1/f1", 0644, "0123456789");
1611
1612	assert((ae = archive_entry_new()) != NULL);
1613	assert((a = archive_read_disk_new()) != NULL);
1614
1615	/*
1616	 * Test1: Traverse lock/dir1 as .
1617	 */
1618	assertChdir("lock/dir1");
1619
1620	failure("Directory traversals should work as well");
1621	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "."));
1622
1623	file_count = 2;
1624	match_count = 0;
1625	while (file_count--) {
1626		archive_entry_clear(ae);
1627		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
1628		if (strcmp(archive_entry_pathname(ae), ".") == 0) {
1629			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1630			++match_count;
1631		} else if (strcmp(archive_entry_pathname(ae), "./f1") == 0) {
1632			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1633			assertEqualInt(archive_entry_size(ae), 10);
1634			assertEqualIntA(a, ARCHIVE_OK,
1635			    archive_read_data_block(a, &p, &size, &offset));
1636			assertEqualInt((int)size, 10);
1637			assertEqualInt((int)offset, 0);
1638			assertEqualMem(p, "0123456789", 10);
1639			assertEqualInt(ARCHIVE_EOF,
1640			    archive_read_data_block(a, &p, &size, &offset));
1641			assertEqualInt((int)size, 0);
1642			assertEqualInt((int)offset, 10);
1643			++match_count;
1644		}
1645		if (archive_read_disk_can_descend(a)) {
1646			/* Descend into the current object */
1647			assertEqualIntA(a, ARCHIVE_OK,
1648			    archive_read_disk_descend(a));
1649		}
1650	}
1651	failure("Did not match expected filenames");
1652	assertEqualInt(match_count, 2);
1653	/*
1654	 * There is no entry. This will however fail if the directory traverse
1655	 * tries to ascend past the initial directory, since it lacks permission
1656	 * to do so.
1657	 */
1658	failure("There should be no entry and no error");
1659	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
1660
1661	/* Close the disk object. */
1662	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
1663
1664	assertChdir("../..");
1665
1666	/*
1667	 * Test2: Traverse lock/dir1 directly
1668	 */
1669	failure("Directory traversals should work as well");
1670	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "lock/dir1"));
1671
1672	file_count = 2;
1673	match_count = 0;
1674	while (file_count--) {
1675		archive_entry_clear(ae);
1676		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
1677		if (strcmp(archive_entry_pathname(ae), "lock/dir1") == 0) {
1678			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1679			++match_count;
1680		} else if (strcmp(archive_entry_pathname(ae), "lock/dir1/f1") == 0) {
1681			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1682			assertEqualInt(archive_entry_size(ae), 10);
1683			assertEqualIntA(a, ARCHIVE_OK,
1684			    archive_read_data_block(a, &p, &size, &offset));
1685			assertEqualInt((int)size, 10);
1686			assertEqualInt((int)offset, 0);
1687			assertEqualMem(p, "0123456789", 10);
1688			assertEqualInt(ARCHIVE_EOF,
1689			    archive_read_data_block(a, &p, &size, &offset));
1690			assertEqualInt((int)size, 0);
1691			assertEqualInt((int)offset, 10);
1692			++match_count;
1693		}
1694		if (archive_read_disk_can_descend(a)) {
1695			/* Descend into the current object */
1696			assertEqualIntA(a, ARCHIVE_OK,
1697			    archive_read_disk_descend(a));
1698		}
1699	}
1700	failure("Did not match expected filenames");
1701	assertEqualInt(match_count, 2);
1702	/*
1703	 * There is no entry. This will however fail if the directory traverse
1704	 * tries to ascend past the initial directory, since it lacks permission
1705	 * to do so.
1706	 */
1707	failure("There should be no entry and no error");
1708	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
1709
1710	/* Close the disk object. */
1711	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
1712
1713	/*
1714	 * Test3: Traverse lock/dir1/.
1715	 */
1716	failure("Directory traversals should work as well");
1717	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "lock/dir1/."));
1718
1719	file_count = 2;
1720	match_count = 0;
1721	while (file_count--) {
1722		archive_entry_clear(ae);
1723		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
1724		if (strcmp(archive_entry_pathname(ae), "lock/dir1/.") == 0) {
1725			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1726			++match_count;
1727		} else if (strcmp(archive_entry_pathname(ae), "lock/dir1/./f1") == 0) {
1728			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1729			assertEqualInt(archive_entry_size(ae), 10);
1730			assertEqualIntA(a, ARCHIVE_OK,
1731			    archive_read_data_block(a, &p, &size, &offset));
1732			assertEqualInt((int)size, 10);
1733			assertEqualInt((int)offset, 0);
1734			assertEqualMem(p, "0123456789", 10);
1735			assertEqualInt(ARCHIVE_EOF,
1736			    archive_read_data_block(a, &p, &size, &offset));
1737			assertEqualInt((int)size, 0);
1738			assertEqualInt((int)offset, 10);
1739			++match_count;
1740		}
1741		if (archive_read_disk_can_descend(a)) {
1742			/* Descend into the current object */
1743			assertEqualIntA(a, ARCHIVE_OK,
1744			    archive_read_disk_descend(a));
1745		}
1746	}
1747	failure("Did not match expected filenames");
1748	assertEqualInt(match_count, 2);
1749	/*
1750	 * There is no entry. This will however fail if the directory traverse
1751	 * tries to ascend past the initial directory, since it lacks permission
1752	 * to do so.
1753	 */
1754	failure("There should be no entry and no error");
1755	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
1756
1757	/* Close the disk object. */
1758	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
1759
1760	/*
1761	 * Test4: Traverse lock/lock2/dir1 from inside lock.
1762	 *
1763	 * This test is expected to fail on platforms with no O_EXEC or
1764	 * equivalent (e.g. O_PATH on Linux or O_SEARCH on SunOS), because
1765	 * the current traversal code can't handle the case where it can't
1766	 * obtain an open fd for the initial current directory. We need to
1767	 * check that condition here, because if O_EXEC _does_ exist, we don't
1768	 * want to overlook any failure.
1769	 */
1770	assertChdir("lock");
1771
1772	failure("Directory traversals should work as well");
1773	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "lock2/dir1"));
1774
1775	archive_entry_clear(ae);
1776	r = archive_read_next_header2(a, ae);
1777	if (r == ARCHIVE_FAILED) {
1778#if defined(O_PATH) || defined(O_SEARCH) || \
1779 (defined(__FreeBSD__) && defined(O_EXEC))
1780		assertEqualIntA(a, ARCHIVE_OK, r);
1781#endif
1782		/* Close the disk object. */
1783		archive_read_close(a);
1784	} else {
1785		file_count = 2;
1786		match_count = 0;
1787		while (file_count--) {
1788			if (file_count == 0)
1789				assertEqualIntA(a, ARCHIVE_OK,
1790				    archive_read_next_header2(a, ae));
1791			if (strcmp(archive_entry_pathname(ae),
1792				"lock2/dir1") == 0) {
1793				assertEqualInt(archive_entry_filetype(ae),
1794				    AE_IFDIR);
1795				++match_count;
1796			} else if (strcmp(archive_entry_pathname(ae),
1797				"lock2/dir1/f1") == 0) {
1798				assertEqualInt(archive_entry_filetype(ae),
1799				    AE_IFREG);
1800				assertEqualInt(archive_entry_size(ae), 10);
1801				assertEqualIntA(a, ARCHIVE_OK,
1802				    archive_read_data_block(a, &p, &size,
1803					&offset));
1804				assertEqualInt((int)size, 10);
1805				assertEqualInt((int)offset, 0);
1806				assertEqualMem(p, "0123456789", 10);
1807				assertEqualInt(ARCHIVE_EOF,
1808				    archive_read_data_block(a, &p, &size,
1809					&offset));
1810				assertEqualInt((int)size, 0);
1811				assertEqualInt((int)offset, 10);
1812				++match_count;
1813			}
1814			if (archive_read_disk_can_descend(a)) {
1815				/* Descend into the current object */
1816				assertEqualIntA(a, ARCHIVE_OK,
1817				    archive_read_disk_descend(a));
1818			}
1819		}
1820		failure("Did not match expected filenames");
1821		assertEqualInt(match_count, 2);
1822		/*
1823		 * There is no entry. This will however fail if the directory
1824		 * traverse tries to ascend past the initial directory, since
1825		 * it lacks permission to do so.
1826		 */
1827		failure("There should be no entry and no error");
1828		assertEqualIntA(a, ARCHIVE_EOF,
1829		    archive_read_next_header2(a, ae));
1830
1831		/* Close the disk object. */
1832		assertEqualInt(ARCHIVE_OK, archive_read_close(a));
1833	}
1834
1835	assertChdir("..");
1836
1837	/* Destroy the disk object. */
1838	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
1839	archive_entry_free(ae);
1840}
1841
1842DEFINE_TEST(test_read_disk_directory_traversals)
1843{
1844	/* Basic test. */
1845	test_basic();
1846	/* Test hybrid mode; follow symlink initially, then not. */
1847	test_symlink_hybrid();
1848	/* Test logical mode; follow all symlinks. */
1849	test_symlink_logical();
1850	/* Test logical mode; prevent loop in symlinks. */
1851	test_symlink_logical_loop();
1852	/* Test to restore atime. */
1853	test_restore_atime();
1854	/* Test callbacks. */
1855	test_callbacks();
1856	/* Test nodump. */
1857	test_nodump();
1858	/* Test parent overshoot. */
1859	test_parent();
1860}
1861