1167465Smp/*-
259243Sobrien * Copyright (c) 2010-2012 Michihiro NAKAJIMA
359243Sobrien * All rights reserved.
459243Sobrien *
559243Sobrien * Redistribution and use in source and binary forms, with or without
659243Sobrien * modification, are permitted provided that the following conditions
759243Sobrien * are met:
859243Sobrien * 1. Redistributions of source code must retain the above copyright
959243Sobrien *    notice, this list of conditions and the following disclaimer.
1059243Sobrien * 2. Redistributions in binary form must reproduce the above copyright
1159243Sobrien *    notice, this list of conditions and the following disclaimer in the
1259243Sobrien *    documentation and/or other materials provided with the distribution.
1359243Sobrien *
1459243Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
1559243Sobrien * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1659243Sobrien * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1759243Sobrien * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
1859243Sobrien * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19100616Smp * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2059243Sobrien * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2159243Sobrien * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2259243Sobrien * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2359243Sobrien * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2459243Sobrien */
2559243Sobrien#include "test.h"
2659243Sobrien
2759243Sobrien#include <limits.h>
2859243Sobrien#if defined(_WIN32) && !defined(__CYGWIN__)
2959243Sobrien# if !defined(__BORLANDC__)
3059243Sobrien#  define getcwd _getcwd
3159243Sobrien# endif
3259243Sobrien#endif
3359243Sobrien
3459243Sobrien/*
3559243Sobrien * Test if the current filesystem is mounted with noatime option.
3659243Sobrien */
37167465Smpstatic int
3859243SobrienatimeIsUpdated(void)
3959243Sobrien{
4059243Sobrien	const char *fn = "fs_noatime";
4159243Sobrien	struct stat st;
4259243Sobrien#if defined(_WIN32) && !defined(CYGWIN)
4359243Sobrien	char *buff = NULL;
44167465Smp	char *ptr;
4559243Sobrien	int r;
46145479Smp
4759243Sobrien	r = systemf("fsutil behavior query disableLastAccess > query_atime");
48167465Smp	if (r == 0) {
49167465Smp		buff = slurpfile(NULL, "query_atime");
5059243Sobrien		if (buff != NULL) {
5159243Sobrien			ptr = buff;
52167465Smp			while(*ptr != '\0' && !isdigit(*ptr)) {
5359243Sobrien				ptr++;
54100616Smp			}
55100616Smp			if (*ptr == '0') {
5659243Sobrien				free(buff);
57167465Smp				return(1);
5859243Sobrien			} else if (*ptr == '1' || *ptr == '2') {
59145479Smp				free(buff);
60100616Smp				return(0);
61100616Smp			}
62100616Smp			free(buff);
63100616Smp		}
64100616Smp	}
65100616Smp#endif
66167465Smp	if (!assertMakeFile(fn, 0666, "a"))
67100616Smp		return (0);
68100616Smp	if (!assertUtimes(fn, 1, 0, 1, 0))
69100616Smp		return (0);
70167465Smp	/* Test the file contents in order to update its atime. */
71167465Smp	if (!assertTextFileContents("a", fn))
7259243Sobrien		return (0);
7359243Sobrien	if (stat(fn, &st) != 0)
7459243Sobrien		return (0);
7559243Sobrien	/* Is atime updated? */
7659243Sobrien	if (st.st_atime > 1)
7759243Sobrien		return (1);
7859243Sobrien	return (0);
79167465Smp}
8059243Sobrien
8159243Sobrienstatic void
8259243Sobrientest_basic(void)
8359243Sobrien{
8459243Sobrien	struct archive *a;
8559243Sobrien	struct archive_entry *ae;
8659243Sobrien	const void *p;
8759243Sobrien	char *initial_cwd, *cwd;
8859243Sobrien	size_t size;
8959243Sobrien	int64_t offset;
9059243Sobrien	int file_count;
9159243Sobrien#if defined(_WIN32) && !defined(__CYGWIN__)
9259243Sobrien	wchar_t *wcwd, *wp, *fullpath;
9359243Sobrien#endif
9459243Sobrien
9559243Sobrien	assertMakeDir("dir1", 0755);
9659243Sobrien	assertMakeFile("dir1/file1", 0644, "0123456789");
9759243Sobrien	assertMakeFile("dir1/file2", 0644, "hello world");
98145479Smp	assertMakeDir("dir1/sub1", 0755);
9959243Sobrien	assertMakeFile("dir1/sub1/file1", 0644, "0123456789");
100145479Smp	assertMakeDir("dir1/sub2", 0755);
10159243Sobrien	assertMakeFile("dir1/sub2/file1", 0644, "0123456789");
10259243Sobrien	assertMakeFile("dir1/sub2/file2", 0644, "0123456789");
10359243Sobrien	assertMakeDir("dir1/sub2/sub1", 0755);
10459243Sobrien	assertMakeDir("dir1/sub2/sub2", 0755);
10559243Sobrien	assertMakeDir("dir1/sub2/sub3", 0755);
10659243Sobrien	assertMakeFile("dir1/sub2/sub3/file", 0644, "xyz");
10759243Sobrien	file_count = 12;
10859243Sobrien
10959243Sobrien	assert((ae = archive_entry_new()) != NULL);
110145479Smp	assert((a = archive_read_disk_new()) != NULL);
111145479Smp	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "dir1"));
112145479Smp
11359243Sobrien	while (file_count--) {
11459243Sobrien		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
11559243Sobrien		if (strcmp(archive_entry_pathname(ae), "dir1") == 0) {
11659243Sobrien			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
11759243Sobrien			assertEqualInt(1, archive_read_disk_can_descend(a));
11859243Sobrien		} else if (strcmp(archive_entry_pathname(ae),
11959243Sobrien		    "dir1/file1") == 0) {
12059243Sobrien			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
12159243Sobrien			assertEqualInt(archive_entry_size(ae), 10);
12259243Sobrien			assertEqualIntA(a, ARCHIVE_OK,
123100616Smp			    archive_read_data_block(a, &p, &size, &offset));
12459243Sobrien			assertEqualInt((int)size, 10);
125100616Smp			assertEqualInt((int)offset, 0);
126100616Smp			assertEqualMem(p, "0123456789", 10);
127100616Smp			assertEqualInt(ARCHIVE_EOF,
128100616Smp			    archive_read_data_block(a, &p, &size, &offset));
12959243Sobrien			assertEqualInt((int)size, 0);
130167465Smp			assertEqualInt((int)offset, 10);
131167465Smp			assertEqualInt(0, archive_read_disk_can_descend(a));
132167465Smp		} else if (strcmp(archive_entry_pathname(ae),
133167465Smp		    "dir1/file2") == 0) {
13459243Sobrien			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
13559243Sobrien			assertEqualInt(archive_entry_size(ae), 11);
136145479Smp			assertEqualIntA(a, ARCHIVE_OK,
13759243Sobrien			    archive_read_data_block(a, &p, &size, &offset));
138145479Smp			assertEqualInt((int)size, 11);
13959243Sobrien			assertEqualInt((int)offset, 0);
14059243Sobrien			assertEqualMem(p, "hello world", 11);
14159243Sobrien			assertEqualInt(ARCHIVE_EOF,
14259243Sobrien			    archive_read_data_block(a, &p, &size, &offset));
143100616Smp			assertEqualInt((int)size, 0);
144100616Smp			assertEqualInt((int)offset, 11);
145167465Smp			assertEqualInt(0, archive_read_disk_can_descend(a));
146167465Smp		} else if (strcmp(archive_entry_pathname(ae),
147167465Smp		    "dir1/sub1") == 0) {
148167465Smp			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
149100616Smp			assertEqualInt(1, archive_read_disk_can_descend(a));
150100616Smp		} else if (strcmp(archive_entry_pathname(ae),
151145479Smp		    "dir1/sub1/file1") == 0) {
152100616Smp			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
153100616Smp			assertEqualInt(archive_entry_size(ae), 10);
15459243Sobrien			assertEqualIntA(a, ARCHIVE_OK,
155100616Smp			    archive_read_data_block(a, &p, &size, &offset));
156145479Smp			assertEqualInt((int)size, 10);
157100616Smp			assertEqualInt((int)offset, 0);
158100616Smp			assertEqualMem(p, "0123456789", 10);
159100616Smp			assertEqualInt(ARCHIVE_EOF,
160100616Smp			    archive_read_data_block(a, &p, &size, &offset));
161100616Smp			assertEqualInt((int)size, 0);
162100616Smp			assertEqualInt((int)offset, 10);
16359243Sobrien			assertEqualInt(0, archive_read_disk_can_descend(a));
16459243Sobrien		} else if (strcmp(archive_entry_pathname(ae),
16559243Sobrien		    "dir1/sub2") == 0) {
16659243Sobrien			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
16759243Sobrien			assertEqualInt(1, archive_read_disk_can_descend(a));
16859243Sobrien		} else if (strcmp(archive_entry_pathname(ae),
16959243Sobrien		    "dir1/sub2/file1") == 0) {
17059243Sobrien			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
17159243Sobrien			assertEqualInt(archive_entry_size(ae), 10);
17259243Sobrien			assertEqualIntA(a, ARCHIVE_OK,
17359243Sobrien			    archive_read_data_block(a, &p, &size, &offset));
17459243Sobrien			assertEqualInt((int)size, 10);
175167465Smp			assertEqualInt((int)offset, 0);
17659243Sobrien			assertEqualMem(p, "0123456789", 10);
177167465Smp			assertEqualInt(ARCHIVE_EOF,
17859243Sobrien			    archive_read_data_block(a, &p, &size, &offset));
17959243Sobrien			assertEqualInt((int)size, 0);
180167465Smp			assertEqualInt((int)offset, 10);
18159243Sobrien			assertEqualInt(0, archive_read_disk_can_descend(a));
18259243Sobrien		} else if (strcmp(archive_entry_pathname(ae),
183131962Smp		    "dir1/sub2/file2") == 0) {
184131962Smp			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
185131962Smp			assertEqualInt(archive_entry_size(ae), 10);
186131962Smp			assertEqualIntA(a, ARCHIVE_OK,
187131962Smp			    archive_read_data_block(a, &p, &size, &offset));
18859243Sobrien			assertEqualInt((int)size, 10);
18959243Sobrien			assertEqualInt((int)offset, 0);
19059243Sobrien			assertEqualMem(p, "0123456789", 10);
191100616Smp			assertEqualInt(ARCHIVE_EOF,
192100616Smp			    archive_read_data_block(a, &p, &size, &offset));
193167465Smp			assertEqualInt((int)size, 0);
194167465Smp			assertEqualInt((int)offset, 10);
195167465Smp			assertEqualInt(0, archive_read_disk_can_descend(a));
196167465Smp		} else if (strcmp(archive_entry_pathname(ae),
197100616Smp		    "dir1/sub2/sub1") == 0) {
198100616Smp			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
199145479Smp			assertEqualInt(1, archive_read_disk_can_descend(a));
200100616Smp		} else if (strcmp(archive_entry_pathname(ae),
201100616Smp		    "dir1/sub2/sub2") == 0) {
20259243Sobrien			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
203100616Smp			assertEqualInt(1, archive_read_disk_can_descend(a));
204145479Smp		} else if (strcmp(archive_entry_pathname(ae),
205100616Smp		    "dir1/sub2/sub3") == 0) {
206100616Smp			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
207100616Smp			assertEqualInt(1, archive_read_disk_can_descend(a));
208100616Smp		} else if (strcmp(archive_entry_pathname(ae),
209100616Smp		    "dir1/sub2/sub3/file") == 0) {
21059243Sobrien			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
21159243Sobrien			assertEqualInt(archive_entry_size(ae), 3);
21259243Sobrien			assertEqualIntA(a, ARCHIVE_OK,
21359243Sobrien			    archive_read_data_block(a, &p, &size, &offset));
21459243Sobrien			assertEqualInt((int)size, 3);
21559243Sobrien			assertEqualInt((int)offset, 0);
21659243Sobrien			assertEqualMem(p, "xyz", 3);
21759243Sobrien			assertEqualInt(ARCHIVE_EOF,
21859243Sobrien			    archive_read_data_block(a, &p, &size, &offset));
21959243Sobrien			assertEqualInt((int)size, 0);
22059243Sobrien			assertEqualInt((int)offset, 3);
22159243Sobrien			assertEqualInt(0, archive_read_disk_can_descend(a));
22259243Sobrien		}
22359243Sobrien		if (archive_entry_filetype(ae) == AE_IFDIR) {
22459243Sobrien			/* Descend into the current object */
22559243Sobrien			assertEqualIntA(a, ARCHIVE_OK,
22659243Sobrien			    archive_read_disk_descend(a));
22759243Sobrien		}
22859243Sobrien	}
22959243Sobrien	/* There is no entry. */
23059243Sobrien	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
23159243Sobrien
23259243Sobrien	/* Close the disk object. */
23359243Sobrien	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
23459243Sobrien
23559243Sobrien	/*
23659243Sobrien	 * Test that call archive_read_disk_open_w, wchar_t version.
23759243Sobrien	 */
238167465Smp	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open_w(a, L"dir1"));
23959243Sobrien
240167465Smp	file_count = 12;
24159243Sobrien	while (file_count--) {
24259243Sobrien		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
243167465Smp		if (wcscmp(archive_entry_pathname_w(ae), L"dir1") == 0) {
24459243Sobrien			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
24559243Sobrien			assertEqualInt(1, archive_read_disk_can_descend(a));
24659243Sobrien		} else if (wcscmp(archive_entry_pathname_w(ae),
24759243Sobrien		    L"dir1/file1") == 0) {
24859243Sobrien			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
249167465Smp			assertEqualInt(archive_entry_size(ae), 10);
25059243Sobrien			assertEqualIntA(a, ARCHIVE_OK,
25159243Sobrien			    archive_read_data_block(a, &p, &size, &offset));
25259243Sobrien			assertEqualInt((int)size, 10);
25359243Sobrien			assertEqualInt((int)offset, 0);
25483098Smp			assertEqualMem(p, "0123456789", 10);
25559243Sobrien			assertEqualInt(ARCHIVE_EOF,
25659243Sobrien			    archive_read_data_block(a, &p, &size, &offset));
25759243Sobrien			assertEqualInt((int)size, 0);
25859243Sobrien			assertEqualInt((int)offset, 10);
25959243Sobrien			assertEqualInt(0, archive_read_disk_can_descend(a));
26059243Sobrien		} else if (wcscmp(archive_entry_pathname_w(ae),
26159243Sobrien		    L"dir1/file2") == 0) {
26259243Sobrien			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
26359243Sobrien			assertEqualInt(archive_entry_size(ae), 11);
26459243Sobrien			assertEqualIntA(a, ARCHIVE_OK,
265145479Smp			    archive_read_data_block(a, &p, &size, &offset));
266145479Smp			assertEqualInt((int)size, 11);
267145479Smp			assertEqualInt((int)offset, 0);
26859243Sobrien			assertEqualMem(p, "hello world", 11);
269167465Smp			assertEqualInt(ARCHIVE_EOF,
270145479Smp			    archive_read_data_block(a, &p, &size, &offset));
271145479Smp			assertEqualInt((int)size, 0);
272167465Smp			assertEqualInt((int)offset, 11);
273167465Smp			assertEqualInt(0, archive_read_disk_can_descend(a));
27459243Sobrien		} else if (wcscmp(archive_entry_pathname_w(ae),
27559243Sobrien		    L"dir1/sub1") == 0) {
27659243Sobrien			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
27759243Sobrien			assertEqualInt(1, archive_read_disk_can_descend(a));
278167465Smp		} else if (wcscmp(archive_entry_pathname_w(ae),
27959243Sobrien		    L"dir1/sub1/file1") == 0) {
28083098Smp			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
28159243Sobrien			assertEqualInt(archive_entry_size(ae), 10);
28259243Sobrien			assertEqualIntA(a, ARCHIVE_OK,
28359243Sobrien			    archive_read_data_block(a, &p, &size, &offset));
28459243Sobrien			assertEqualInt((int)size, 10);
28559243Sobrien			assertEqualInt((int)offset, 0);
28659243Sobrien			assertEqualMem(p, "0123456789", 10);
287145479Smp			assertEqualInt(ARCHIVE_EOF,
288167465Smp			    archive_read_data_block(a, &p, &size, &offset));
28959243Sobrien			assertEqualInt((int)size, 0);
29059243Sobrien			assertEqualInt((int)offset, 10);
291167465Smp			assertEqualInt(0, archive_read_disk_can_descend(a));
29259243Sobrien		} else if (wcscmp(archive_entry_pathname_w(ae),
29359243Sobrien		    L"dir1/sub2") == 0) {
294167465Smp			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
295167465Smp			assertEqualInt(1, archive_read_disk_can_descend(a));
29659243Sobrien		} else if (wcscmp(archive_entry_pathname_w(ae),
29759243Sobrien		    L"dir1/sub2/file1") == 0) {
29859243Sobrien			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
29959243Sobrien			assertEqualInt(archive_entry_size(ae), 10);
300167465Smp			assertEqualIntA(a, ARCHIVE_OK,
30159243Sobrien			    archive_read_data_block(a, &p, &size, &offset));
30259243Sobrien			assertEqualInt((int)size, 10);
30359243Sobrien			assertEqualInt((int)offset, 0);
30459243Sobrien			assertEqualMem(p, "0123456789", 10);
30559243Sobrien			assertEqualInt(ARCHIVE_EOF,
30659243Sobrien			    archive_read_data_block(a, &p, &size, &offset));
30759243Sobrien			assertEqualInt((int)size, 0);
308167465Smp			assertEqualInt((int)offset, 10);
30959243Sobrien			assertEqualInt(0, archive_read_disk_can_descend(a));
31059243Sobrien		} else if (wcscmp(archive_entry_pathname_w(ae),
31159243Sobrien		    L"dir1/sub2/file2") == 0) {
31259243Sobrien			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
31359243Sobrien			assertEqualInt(archive_entry_size(ae), 10);
314167465Smp			assertEqualIntA(a, ARCHIVE_OK,
315167465Smp			    archive_read_data_block(a, &p, &size, &offset));
31659243Sobrien			assertEqualInt((int)size, 10);
31759243Sobrien			assertEqualInt((int)offset, 0);
31859243Sobrien			assertEqualMem(p, "0123456789", 10);
31959243Sobrien			assertEqualInt(ARCHIVE_EOF,
32059243Sobrien			    archive_read_data_block(a, &p, &size, &offset));
32159243Sobrien			assertEqualInt((int)size, 0);
32259243Sobrien			assertEqualInt((int)offset, 10);
32359243Sobrien			assertEqualInt(0, archive_read_disk_can_descend(a));
32459243Sobrien		} else if (wcscmp(archive_entry_pathname_w(ae),
325167465Smp		    L"dir1/sub2/sub1") == 0) {
32659243Sobrien			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
32759243Sobrien			assertEqualInt(1, archive_read_disk_can_descend(a));
32859243Sobrien		} else if (wcscmp(archive_entry_pathname_w(ae),
32959243Sobrien		    L"dir1/sub2/sub2") == 0) {
33059243Sobrien			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
33159243Sobrien			assertEqualInt(1, archive_read_disk_can_descend(a));
33259243Sobrien		} else if (wcscmp(archive_entry_pathname_w(ae),
33359243Sobrien		    L"dir1/sub2/sub3") == 0) {
33459243Sobrien			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
33559243Sobrien			assertEqualInt(1, archive_read_disk_can_descend(a));
33659243Sobrien		} else if (wcscmp(archive_entry_pathname_w(ae),
33759243Sobrien		    L"dir1/sub2/sub3/file") == 0) {
33859243Sobrien			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
33959243Sobrien			assertEqualInt(archive_entry_size(ae), 3);
34059243Sobrien			assertEqualIntA(a, ARCHIVE_OK,
34159243Sobrien			    archive_read_data_block(a, &p, &size, &offset));
34259243Sobrien			assertEqualInt((int)size, 3);
34359243Sobrien			assertEqualInt((int)offset, 0);
34459243Sobrien			assertEqualMem(p, "xyz", 3);
34559243Sobrien			assertEqualInt(ARCHIVE_EOF,
34659243Sobrien			    archive_read_data_block(a, &p, &size, &offset));
34759243Sobrien			assertEqualInt((int)size, 0);
34859243Sobrien			assertEqualInt((int)offset, 3);
34959243Sobrien			assertEqualInt(0, archive_read_disk_can_descend(a));
35059243Sobrien		}
35159243Sobrien		if (archive_entry_filetype(ae) == AE_IFDIR) {
35259243Sobrien			/* Descend into the current object */
35359243Sobrien			assertEqualIntA(a, ARCHIVE_OK,
35459243Sobrien			    archive_read_disk_descend(a));
35559243Sobrien		}
35659243Sobrien	}
35759243Sobrien	/* There is no entry. */
35859243Sobrien	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
35959243Sobrien
36059243Sobrien	/* Close the disk object. */
36159243Sobrien	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
36259243Sobrien
36359243Sobrien	/*
36459243Sobrien	 * Test that call archive_read_disk_open with a regular file.
36559243Sobrien	 */
366167465Smp	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "dir1/file1"));
36759243Sobrien
36859243Sobrien	/* dir1/file1 */
36959243Sobrien	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
37059243Sobrien	assertEqualInt(0, archive_read_disk_can_descend(a));
37159243Sobrien	assertEqualString(archive_entry_pathname(ae), "dir1/file1");
37259243Sobrien	assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
37359243Sobrien	assertEqualInt(archive_entry_size(ae), 10);
37459243Sobrien	assertEqualIntA(a, ARCHIVE_OK,
375167465Smp	    archive_read_data_block(a, &p, &size, &offset));
37659243Sobrien	assertEqualInt((int)size, 10);
37759243Sobrien	assertEqualInt((int)offset, 0);
37859243Sobrien	assertEqualMem(p, "0123456789", 10);
37959243Sobrien
38059243Sobrien	/* There is no entry. */
38159243Sobrien	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
38259243Sobrien
38359243Sobrien	/* Close the disk object. */
38459243Sobrien	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
38559243Sobrien
386167465Smp
387167465Smp#if defined(_WIN32) && !defined(__CYGWIN__)
388167465Smp	/*
389167465Smp	 * Test for wildcard '*' or '?'
390167465Smp	 */
39159243Sobrien	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "dir1/*1"));
392167465Smp
393167465Smp	/* dir1/file1 */
394167465Smp	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
395167465Smp	assertEqualInt(0, archive_read_disk_can_descend(a));
39659243Sobrien	assertEqualString(archive_entry_pathname(ae), "dir1/file1");
397167465Smp	assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
398167465Smp	assertEqualInt(archive_entry_size(ae), 10);
399167465Smp	assertEqualIntA(a, ARCHIVE_OK,
400167465Smp	    archive_read_data_block(a, &p, &size, &offset));
401167465Smp	assertEqualInt((int)size, 10);
402167465Smp	assertEqualInt((int)offset, 0);
403167465Smp	assertEqualMem(p, "0123456789", 10);
404167465Smp
405167465Smp	/* dir1/sub1 */
406167465Smp	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
407167465Smp	assertEqualInt(1, archive_read_disk_can_descend(a));
408167465Smp	assertEqualString(archive_entry_pathname(ae), "dir1/sub1");
409167465Smp	assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
410167465Smp
411167465Smp	/* Descend into the current object */
412167465Smp	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_descend(a));
413167465Smp
414167465Smp	/* dir1/sub1/file1 */
415167465Smp	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
416167465Smp	assertEqualInt(0, archive_read_disk_can_descend(a));
417167465Smp	assertEqualString(archive_entry_pathname(ae), "dir1/sub1/file1");
418167465Smp	assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
419167465Smp	assertEqualInt(archive_entry_size(ae), 10);
420167465Smp	assertEqualIntA(a, ARCHIVE_OK,
421167465Smp	    archive_read_data_block(a, &p, &size, &offset));
422167465Smp	assertEqualInt((int)size, 10);
423167465Smp	assertEqualInt((int)offset, 0);
42459243Sobrien	assertEqualMem(p, "0123456789", 10);
42559243Sobrien
42659243Sobrien	/* There is no entry. */
42759243Sobrien	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
42859243Sobrien
42959243Sobrien	/* Close the disk object. */
43059243Sobrien	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
43159243Sobrien
43259243Sobrien	/*
43359243Sobrien	 * Test for a full-path beginning with "//?/"
43459243Sobrien	 */
43559243Sobrien	wcwd = _wgetcwd(NULL, 0);
43659243Sobrien	fullpath = malloc(sizeof(wchar_t) * (wcslen(wcwd) + 32));
43759243Sobrien	wcscpy(fullpath, L"//?/");
43859243Sobrien	wcscat(fullpath, wcwd);
43959243Sobrien	wcscat(fullpath, L"/dir1/file1");
44059243Sobrien	free(wcwd);
44159243Sobrien	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open_w(a, fullpath));
44259243Sobrien	while ((wcwd = wcschr(fullpath, L'\\')) != NULL)
44359243Sobrien		*wcwd = L'/';
44459243Sobrien
44559243Sobrien	/* dir1/file1 */
446167465Smp	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
44759243Sobrien	assertEqualInt(0, archive_read_disk_can_descend(a));
44859243Sobrien	assertEqualWString(archive_entry_pathname_w(ae), fullpath);
44959243Sobrien	assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
45059243Sobrien	assertEqualInt(archive_entry_size(ae), 10);
45159243Sobrien	assertEqualIntA(a, ARCHIVE_OK,
45259243Sobrien	    archive_read_data_block(a, &p, &size, &offset));
453	assertEqualInt((int)size, 10);
454	assertEqualInt((int)offset, 0);
455	assertEqualMem(p, "0123456789", 10);
456
457	/* There is no entry. */
458	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
459
460	/* Close the disk object. */
461	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
462	free(fullpath);
463
464	/*
465	 * Test for wild card '*' or '?' with "//?/" prefix.
466	 */
467	wcwd = _wgetcwd(NULL, 0);
468	fullpath = malloc(sizeof(wchar_t) * (wcslen(wcwd) + 32));
469	wcscpy(fullpath, L"//?/");
470	wcscat(fullpath, wcwd);
471	wcscat(fullpath, L"/dir1/*1");
472	free(wcwd);
473	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open_w(a, fullpath));
474	while ((wcwd = wcschr(fullpath, L'\\')) != NULL)
475		*wcwd = L'/';
476
477	/* dir1/file1 */
478	wp = wcsrchr(fullpath, L'/');
479	wcscpy(wp+1, L"file1");
480	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
481	assertEqualInt(0, archive_read_disk_can_descend(a));
482	assertEqualWString(archive_entry_pathname_w(ae), fullpath);
483	assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
484	assertEqualInt(archive_entry_size(ae), 10);
485	assertEqualIntA(a, ARCHIVE_OK,
486	    archive_read_data_block(a, &p, &size, &offset));
487	assertEqualInt((int)size, 10);
488	assertEqualInt((int)offset, 0);
489	assertEqualMem(p, "0123456789", 10);
490
491	/* dir1/sub1 */
492	wcscpy(wp+1, L"sub1");
493	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
494	assertEqualInt(1, archive_read_disk_can_descend(a));
495	assertEqualWString(archive_entry_pathname_w(ae), fullpath);
496	assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
497
498	/* Descend into the current object */
499	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_descend(a));
500
501	/* dir1/sub1/file1 */
502	wcscpy(wp+1, L"sub1/file1");
503	assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
504	assertEqualInt(0, archive_read_disk_can_descend(a));
505	assertEqualWString(archive_entry_pathname_w(ae), fullpath);
506	assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
507	assertEqualInt(archive_entry_size(ae), 10);
508	assertEqualIntA(a, ARCHIVE_OK,
509	    archive_read_data_block(a, &p, &size, &offset));
510	assertEqualInt((int)size, 10);
511	assertEqualInt((int)offset, 0);
512	assertEqualMem(p, "0123456789", 10);
513
514	/* There is no entry. */
515	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
516
517	/* Close the disk object. */
518	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
519	free(fullpath);
520
521#endif
522
523	/*
524	 * We should be on the initial directory where we performed
525	 * archive_read_disk_new() after we perform archive_read_free()
526	 * even if we broke off the directory traversals.
527	 */
528
529	/* Save current working directory. */
530#if defined(PATH_MAX) && !defined(__GLIBC__)
531	initial_cwd = getcwd(NULL, PATH_MAX);/* Solaris getcwd needs the size. */
532#else
533	initial_cwd = getcwd(NULL, 0);
534#endif
535
536	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "dir1"));
537
538	/* Step in a deep directory. */
539	file_count = 12;
540	while (file_count--) {
541		assertEqualIntA(a, ARCHIVE_OK,
542		    archive_read_next_header2(a, ae));
543		if (strcmp(archive_entry_pathname(ae),
544		    "dir1/sub1/file1") == 0)
545			/*
546			 * We are on an another directory at this time.
547			 */
548			break;
549		if (archive_entry_filetype(ae) == AE_IFDIR) {
550			/* Descend into the current object */
551			assertEqualIntA(a, ARCHIVE_OK,
552			    archive_read_disk_descend(a));
553		}
554	}
555	/* Destroy the disk object. */
556	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
557
558	/* We should be on the initial working directory. */
559	failure(
560	    "Current working directory does not return to the initial"
561	    "directory");
562#if defined(PATH_MAX) && !defined(__GLIBC__)
563	cwd = getcwd(NULL, PATH_MAX);/* Solaris getcwd needs the size. */
564#else
565	cwd = getcwd(NULL, 0);
566#endif
567	assertEqualString(initial_cwd, cwd);
568	free(initial_cwd);
569	free(cwd);
570
571	archive_entry_free(ae);
572}
573
574static void
575test_symlink_hybrid(void)
576{
577	struct archive *a;
578	struct archive_entry *ae;
579	const void *p;
580	size_t size;
581	int64_t offset;
582	int file_count;
583
584	if (!canSymlink()) {
585		skipping("Can't test symlinks on this filesystem");
586		return;
587	}
588
589	/*
590	 * Create a sample archive.
591	 */
592	assertMakeDir("h", 0755);
593	assertChdir("h");
594	assertMakeDir("d1", 0755);
595	assertMakeSymlink("ld1", "d1", 1);
596	assertMakeFile("d1/file1", 0644, "d1/file1");
597	assertMakeFile("d1/file2", 0644, "d1/file2");
598	assertMakeSymlink("d1/link1", "file1", 0);
599	assertMakeSymlink("d1/linkX", "fileX", 0);
600	assertMakeSymlink("link2", "d1/file2", 0);
601	assertMakeSymlink("linkY", "d1/fileY", 0);
602	assertChdir("..");
603
604	assert((ae = archive_entry_new()) != NULL);
605	assert((a = archive_read_disk_new()) != NULL);
606	assertEqualIntA(a, ARCHIVE_OK,
607	    archive_read_disk_set_symlink_hybrid(a));
608
609	/*
610	 * Specified file is a symbolic link file.
611	 */
612	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "h/ld1"));
613	file_count = 5;
614
615	while (file_count--) {
616		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
617		if (strcmp(archive_entry_pathname(ae), "h/ld1") == 0) {
618			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
619		} else if (strcmp(archive_entry_pathname(ae),
620		    "h/ld1/file1") == 0) {
621			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
622			assertEqualInt(archive_entry_size(ae), 8);
623			assertEqualIntA(a, ARCHIVE_OK,
624			    archive_read_data_block(a, &p, &size, &offset));
625			assertEqualInt((int)size, 8);
626			assertEqualInt((int)offset, 0);
627			assertEqualMem(p, "d1/file1", 8);
628			assertEqualInt(ARCHIVE_EOF,
629			    archive_read_data_block(a, &p, &size, &offset));
630			assertEqualInt((int)size, 0);
631			assertEqualInt((int)offset, 8);
632		} else if (strcmp(archive_entry_pathname(ae),
633		    "h/ld1/file2") == 0) {
634			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
635			assertEqualInt(archive_entry_size(ae), 8);
636			assertEqualIntA(a, ARCHIVE_OK,
637			    archive_read_data_block(a, &p, &size, &offset));
638			assertEqualInt((int)size, 8);
639			assertEqualInt((int)offset, 0);
640			assertEqualMem(p, "d1/file2", 8);
641			assertEqualInt(ARCHIVE_EOF,
642			    archive_read_data_block(a, &p, &size, &offset));
643			assertEqualInt((int)size, 0);
644			assertEqualInt((int)offset, 8);
645		} else if (strcmp(archive_entry_pathname(ae),
646		    "h/ld1/link1") == 0) {
647			assertEqualInt(archive_entry_filetype(ae), AE_IFLNK);
648		} else if (strcmp(archive_entry_pathname(ae),
649		    "h/ld1/linkX") == 0) {
650			assertEqualInt(archive_entry_filetype(ae), AE_IFLNK);
651		}
652		if (archive_entry_filetype(ae) == AE_IFDIR) {
653			/* Descend into the current object */
654			assertEqualIntA(a, ARCHIVE_OK,
655			    archive_read_disk_descend(a));
656		}
657	}
658	/* There is no entry. */
659	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
660	/* Close the disk object. */
661	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
662
663	/*
664	 * Specified file is a directory and it has symbolic files.
665	 */
666	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "h"));
667	file_count = 9;
668
669	while (file_count--) {
670		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
671		if (strcmp(archive_entry_pathname(ae), "h") == 0) {
672			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
673		} else if (strcmp(archive_entry_pathname(ae), "h/d1") == 0) {
674			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
675		} else if (strcmp(archive_entry_pathname(ae),
676		    "h/d1/file1") == 0) {
677			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
678			assertEqualInt(archive_entry_size(ae), 8);
679			assertEqualIntA(a, ARCHIVE_OK,
680			    archive_read_data_block(a, &p, &size, &offset));
681			assertEqualInt((int)size, 8);
682			assertEqualInt((int)offset, 0);
683			assertEqualMem(p, "d1/file1", 8);
684			assertEqualInt(ARCHIVE_EOF,
685			    archive_read_data_block(a, &p, &size, &offset));
686			assertEqualInt((int)size, 0);
687			assertEqualInt((int)offset, 8);
688		} else if (strcmp(archive_entry_pathname(ae),
689		    "h/d1/file2") == 0) {
690			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
691			assertEqualInt(archive_entry_size(ae), 8);
692			assertEqualIntA(a, ARCHIVE_OK,
693			    archive_read_data_block(a, &p, &size, &offset));
694			assertEqualInt((int)size, 8);
695			assertEqualInt((int)offset, 0);
696			assertEqualMem(p, "d1/file2", 8);
697			assertEqualInt(ARCHIVE_EOF,
698			    archive_read_data_block(a, &p, &size, &offset));
699			assertEqualInt((int)size, 0);
700			assertEqualInt((int)offset, 8);
701		} else if (strcmp(archive_entry_pathname(ae), "h/ld1") == 0) {
702			assertEqualInt(archive_entry_filetype(ae), AE_IFLNK);
703		} else if (strcmp(archive_entry_pathname(ae),
704		    "h/d1/link1") == 0) {
705			assertEqualInt(archive_entry_filetype(ae), AE_IFLNK);
706		} else if (strcmp(archive_entry_pathname(ae),
707		    "h/d1/linkX") == 0) {
708			assertEqualInt(archive_entry_filetype(ae), AE_IFLNK);
709		} else if (strcmp(archive_entry_pathname(ae),
710		    "h/link2") == 0) {
711			assertEqualInt(archive_entry_filetype(ae), AE_IFLNK);
712		} else if (strcmp(archive_entry_pathname(ae),
713		    "h/linkY") == 0) {
714			assertEqualInt(archive_entry_filetype(ae), AE_IFLNK);
715		}
716		if (archive_entry_filetype(ae) == AE_IFDIR) {
717			/* Descend into the current object */
718			assertEqualIntA(a, ARCHIVE_OK,
719			    archive_read_disk_descend(a));
720		}
721	}
722	/* There is no entry. */
723	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
724	/* Close the disk object. */
725	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
726	/* Destroy the disk object. */
727	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
728	archive_entry_free(ae);
729}
730
731static void
732test_symlink_logical(void)
733{
734	struct archive *a;
735	struct archive_entry *ae;
736	const void *p;
737	size_t size;
738	int64_t offset;
739	int file_count;
740
741	if (!canSymlink()) {
742		skipping("Can't test symlinks on this filesystem");
743		return;
744	}
745
746	/*
747	 * Create a sample archive.
748	 */
749	assertMakeDir("l", 0755);
750	assertChdir("l");
751	assertMakeDir("d1", 0755);
752	assertMakeSymlink("ld1", "d1", 1);
753	assertMakeFile("d1/file1", 0644, "d1/file1");
754	assertMakeFile("d1/file2", 0644, "d1/file2");
755	assertMakeSymlink("d1/link1", "file1", 0);
756	assertMakeSymlink("d1/linkX", "fileX", 0);
757	assertMakeSymlink("link2", "d1/file2", 0);
758	assertMakeSymlink("linkY", "d1/fileY", 0);
759	assertChdir("..");
760
761	/* Note: this test uses archive_read_next_header()
762	   instead of archive_read_next_header2() */
763	assert((a = archive_read_disk_new()) != NULL);
764	assertEqualIntA(a, ARCHIVE_OK,
765	    archive_read_disk_set_symlink_logical(a));
766
767	/*
768	 * Specified file is a symbolic link file.
769	 */
770	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "l/ld1"));
771	file_count = 5;
772
773	while (file_count--) {
774		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
775		if (strcmp(archive_entry_pathname(ae), "l/ld1") == 0) {
776			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
777		} else if (strcmp(archive_entry_pathname(ae),
778		    "l/ld1/file1") == 0) {
779			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
780			assertEqualInt(archive_entry_size(ae), 8);
781			assertEqualIntA(a, ARCHIVE_OK,
782			    archive_read_data_block(a, &p, &size, &offset));
783			assertEqualInt((int)size, 8);
784			assertEqualInt((int)offset, 0);
785			assertEqualMem(p, "d1/file1", 8);
786			assertEqualInt(ARCHIVE_EOF,
787			    archive_read_data_block(a, &p, &size, &offset));
788			assertEqualInt((int)size, 0);
789			assertEqualInt((int)offset, 8);
790		} else if (strcmp(archive_entry_pathname(ae),
791		    "l/ld1/file2") == 0) {
792			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
793			assertEqualInt(archive_entry_size(ae), 8);
794			assertEqualIntA(a, ARCHIVE_OK,
795			    archive_read_data_block(a, &p, &size, &offset));
796			assertEqualInt((int)size, 8);
797			assertEqualInt((int)offset, 0);
798			assertEqualMem(p, "d1/file2", 8);
799			assertEqualInt(ARCHIVE_EOF,
800			    archive_read_data_block(a, &p, &size, &offset));
801			assertEqualInt((int)size, 0);
802			assertEqualInt((int)offset, 8);
803		} else if (strcmp(archive_entry_pathname(ae),
804		    "l/ld1/link1") == 0) {
805			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
806			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
807			assertEqualInt(archive_entry_size(ae), 8);
808			assertEqualIntA(a, ARCHIVE_OK,
809			    archive_read_data_block(a, &p, &size, &offset));
810			assertEqualInt((int)size, 8);
811			assertEqualInt((int)offset, 0);
812			assertEqualMem(p, "d1/file1", 8);
813			assertEqualInt(ARCHIVE_EOF,
814			    archive_read_data_block(a, &p, &size, &offset));
815			assertEqualInt((int)size, 0);
816			assertEqualInt((int)offset, 8);
817		} else if (strcmp(archive_entry_pathname(ae),
818		    "l/ld1/linkX") == 0) {
819			assertEqualInt(archive_entry_filetype(ae), AE_IFLNK);
820		}
821		if (archive_entry_filetype(ae) == AE_IFDIR) {
822			/* Descend into the current object */
823			assertEqualIntA(a, ARCHIVE_OK,
824			    archive_read_disk_descend(a));
825		}
826	}
827	/* There is no entry. */
828	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
829	/* Close the disk object. */
830	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
831
832	/*
833	 * Specified file is a directory and it has symbolic files.
834	 */
835	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "l"));
836	file_count = 13;
837
838	while (file_count--) {
839		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
840		if (strcmp(archive_entry_pathname(ae), "l") == 0) {
841			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
842		} else if (strcmp(archive_entry_pathname(ae), "l/d1") == 0) {
843			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
844		} else if (strcmp(archive_entry_pathname(ae),
845		    "l/d1/file1") == 0) {
846			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
847			assertEqualInt(archive_entry_size(ae), 8);
848			assertEqualIntA(a, ARCHIVE_OK,
849			    archive_read_data_block(a, &p, &size, &offset));
850			assertEqualInt((int)size, 8);
851			assertEqualInt((int)offset, 0);
852			assertEqualMem(p, "d1/file1", 8);
853			assertEqualInt(ARCHIVE_EOF,
854			    archive_read_data_block(a, &p, &size, &offset));
855			assertEqualInt((int)size, 0);
856			assertEqualInt((int)offset, 8);
857		} else if (strcmp(archive_entry_pathname(ae),
858		    "l/d1/file2") == 0) {
859			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
860			assertEqualInt(archive_entry_size(ae), 8);
861			assertEqualIntA(a, ARCHIVE_OK,
862			    archive_read_data_block(a, &p, &size, &offset));
863			assertEqualInt((int)size, 8);
864			assertEqualInt((int)offset, 0);
865			assertEqualMem(p, "d1/file2", 8);
866			assertEqualInt(ARCHIVE_EOF,
867			    archive_read_data_block(a, &p, &size, &offset));
868			assertEqualInt((int)size, 0);
869			assertEqualInt((int)offset, 8);
870		} else if (strcmp(archive_entry_pathname(ae),
871		    "l/d1/link1") == 0) {
872			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
873			assertEqualInt(archive_entry_size(ae), 8);
874			assertEqualIntA(a, ARCHIVE_OK,
875			    archive_read_data_block(a, &p, &size, &offset));
876			assertEqualInt((int)size, 8);
877			assertEqualInt((int)offset, 0);
878			assertEqualMem(p, "d1/file1", 8);
879			assertEqualInt(ARCHIVE_EOF,
880			    archive_read_data_block(a, &p, &size, &offset));
881			assertEqualInt((int)size, 0);
882			assertEqualInt((int)offset, 8);
883		} else if (strcmp(archive_entry_pathname(ae),
884		    "l/d1/linkX") == 0) {
885			assertEqualInt(archive_entry_filetype(ae), AE_IFLNK);
886		} else if (strcmp(archive_entry_pathname(ae), "l/ld1") == 0) {
887			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
888		} else if (strcmp(archive_entry_pathname(ae),
889		    "l/ld1/file1") == 0) {
890			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
891			assertEqualInt(archive_entry_size(ae), 8);
892			assertEqualIntA(a, ARCHIVE_OK,
893			    archive_read_data_block(a, &p, &size, &offset));
894			assertEqualInt((int)size, 8);
895			assertEqualInt((int)offset, 0);
896			assertEqualMem(p, "d1/file1", 8);
897			assertEqualInt(ARCHIVE_EOF,
898			    archive_read_data_block(a, &p, &size, &offset));
899			assertEqualInt((int)size, 0);
900			assertEqualInt((int)offset, 8);
901		} else if (strcmp(archive_entry_pathname(ae),
902		    "l/ld1/file2") == 0) {
903			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
904			assertEqualInt(archive_entry_size(ae), 8);
905			assertEqualIntA(a, ARCHIVE_OK,
906			    archive_read_data_block(a, &p, &size, &offset));
907			assertEqualInt((int)size, 8);
908			assertEqualInt((int)offset, 0);
909			assertEqualMem(p, "d1/file2", 8);
910			assertEqualInt(ARCHIVE_EOF,
911			    archive_read_data_block(a, &p, &size, &offset));
912			assertEqualInt((int)size, 0);
913			assertEqualInt((int)offset, 8);
914		} else if (strcmp(archive_entry_pathname(ae),
915		    "l/ld1/link1") == 0) {
916			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
917			assertEqualInt(archive_entry_size(ae), 8);
918			assertEqualIntA(a, ARCHIVE_OK,
919			    archive_read_data_block(a, &p, &size, &offset));
920			assertEqualInt((int)size, 8);
921			assertEqualInt((int)offset, 0);
922			assertEqualMem(p, "d1/file1", 8);
923			assertEqualInt(ARCHIVE_EOF,
924			    archive_read_data_block(a, &p, &size, &offset));
925			assertEqualInt((int)size, 0);
926			assertEqualInt((int)offset, 8);
927		} else if (strcmp(archive_entry_pathname(ae),
928		    "l/ld1/linkX") == 0) {
929			assertEqualInt(archive_entry_filetype(ae), AE_IFLNK);
930		} else if (strcmp(archive_entry_pathname(ae),
931		    "l/link2") == 0) {
932			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
933			assertEqualInt(archive_entry_size(ae), 8);
934			assertEqualIntA(a, ARCHIVE_OK,
935			    archive_read_data_block(a, &p, &size, &offset));
936			assertEqualInt((int)size, 8);
937			assertEqualInt((int)offset, 0);
938			assertEqualMem(p, "d1/file2", 8);
939			assertEqualInt(ARCHIVE_EOF,
940			    archive_read_data_block(a, &p, &size, &offset));
941			assertEqualInt((int)size, 0);
942			assertEqualInt((int)offset, 8);
943		} else if (strcmp(archive_entry_pathname(ae),
944		    "l/linkY") == 0) {
945			assertEqualInt(archive_entry_filetype(ae), AE_IFLNK);
946		}
947		if (archive_entry_filetype(ae) == AE_IFDIR) {
948			/* Descend into the current object */
949			assertEqualIntA(a, ARCHIVE_OK,
950			    archive_read_disk_descend(a));
951		}
952	}
953	/* There is no entry. */
954	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
955	/* Close the disk object. */
956	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
957	/* Destroy the disk object. */
958	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
959}
960
961static void
962test_symlink_logical_loop(void)
963{
964	struct archive *a;
965	struct archive_entry *ae;
966	const void *p;
967	size_t size;
968	int64_t offset;
969	int file_count;
970
971	if (!canSymlink()) {
972		skipping("Can't test symlinks on this filesystem");
973		return;
974	}
975
976	/*
977	 * Create a sample archive.
978	 */
979	assertMakeDir("l2", 0755);
980	assertChdir("l2");
981	assertMakeDir("d1", 0755);
982	assertMakeDir("d1/d2", 0755);
983	assertMakeDir("d1/d2/d3", 0755);
984	assertMakeDir("d2", 0755);
985	assertMakeFile("d2/file1", 0644, "d2/file1");
986	assertMakeSymlink("d1/d2/ld1", "../../d1", 1);
987	assertMakeSymlink("d1/d2/ld2", "../../d2", 1);
988	assertChdir("..");
989
990	assert((ae = archive_entry_new()) != NULL);
991	assert((a = archive_read_disk_new()) != NULL);
992	assertEqualIntA(a, ARCHIVE_OK,
993	    archive_read_disk_set_symlink_logical(a));
994
995	/*
996	 * Specified file is a symbolic link file.
997	 */
998	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "l2/d1"));
999	file_count = 6;
1000
1001	while (file_count--) {
1002		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
1003		if (strcmp(archive_entry_pathname(ae), "l2/d1") == 0) {
1004			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1005		} else if (strcmp(archive_entry_pathname(ae), "l2/d1/d2") == 0) {
1006			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1007		} else if (strcmp(archive_entry_pathname(ae), "l2/d1/d2/d3") == 0) {
1008			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1009		} else if (strcmp(archive_entry_pathname(ae), "l2/d1/d2/ld1") == 0) {
1010			assertEqualInt(archive_entry_filetype(ae), AE_IFLNK);
1011		} else if (strcmp(archive_entry_pathname(ae), "l2/d1/d2/ld2") == 0) {
1012			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1013		} else if (strcmp(archive_entry_pathname(ae),
1014		    "l2/d1/d2/ld2/file1") == 0) {
1015			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1016			assertEqualInt(archive_entry_size(ae), 8);
1017			assertEqualIntA(a, ARCHIVE_OK,
1018			    archive_read_data_block(a, &p, &size, &offset));
1019			assertEqualInt((int)size, 8);
1020			assertEqualInt((int)offset, 0);
1021			assertEqualMem(p, "d2/file1", 8);
1022			assertEqualInt(ARCHIVE_EOF,
1023			    archive_read_data_block(a, &p, &size, &offset));
1024			assertEqualInt((int)size, 0);
1025			assertEqualInt((int)offset, 8);
1026		}
1027		if (archive_entry_filetype(ae) == AE_IFDIR) {
1028			/* Descend into the current object */
1029			assertEqualIntA(a, ARCHIVE_OK,
1030			    archive_read_disk_descend(a));
1031		}
1032	}
1033	/* There is no entry. */
1034	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
1035	/* Destroy the disk object. */
1036	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
1037	archive_entry_free(ae);
1038}
1039
1040static void
1041test_restore_atime(void)
1042{
1043	struct archive *a;
1044	struct archive_entry *ae;
1045	const void *p;
1046	size_t size;
1047	int64_t offset;
1048	int file_count;
1049	const char *skip_test_restore_atime;
1050
1051        skip_test_restore_atime = getenv("SKIP_TEST_RESTORE_ATIME");
1052        if (skip_test_restore_atime != NULL) {
1053                skipping("Skipping restore atime tests due to "
1054                    "SKIP_TEST_RESTORE_ATIME environment variable");
1055                return;
1056        }
1057	if (!atimeIsUpdated()) {
1058		skipping("Can't test restoring atime on this filesystem");
1059		return;
1060	}
1061
1062	assertMakeDir("at", 0755);
1063	assertMakeFile("at/f1", 0644, "0123456789");
1064	assertMakeFile("at/f2", 0644, "hello world");
1065	assertMakeFile("at/fe", 0644, NULL);
1066	assertUtimes("at/f1", 886600, 0, 886600, 0);
1067	assertUtimes("at/f2", 886611, 0, 886611, 0);
1068	assertUtimes("at/fe", 886611, 0, 886611, 0);
1069	assertUtimes("at", 886622, 0, 886622, 0);
1070	file_count = 4;
1071
1072	assert((ae = archive_entry_new()) != NULL);
1073	assert((a = archive_read_disk_new()) != NULL);
1074
1075	/*
1076	 * Test1: Traversals without archive_read_disk_set_atime_restored().
1077	 */
1078	failure("Directory traversals should work as well");
1079	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "at"));
1080	while (file_count--) {
1081		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
1082		if (strcmp(archive_entry_pathname(ae), "at") == 0) {
1083			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1084		} else if (strcmp(archive_entry_pathname(ae), "at/f1") == 0) {
1085			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1086			assertEqualInt(archive_entry_size(ae), 10);
1087			assertEqualIntA(a, ARCHIVE_OK,
1088			    archive_read_data_block(a, &p, &size, &offset));
1089			assertEqualInt((int)size, 10);
1090			assertEqualInt((int)offset, 0);
1091			assertEqualMem(p, "0123456789", 10);
1092			assertEqualInt(ARCHIVE_EOF,
1093			    archive_read_data_block(a, &p, &size, &offset));
1094			assertEqualInt((int)size, 0);
1095			assertEqualInt((int)offset, 10);
1096		} else if (strcmp(archive_entry_pathname(ae), "at/f2") == 0) {
1097			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1098			assertEqualInt(archive_entry_size(ae), 11);
1099			assertEqualIntA(a, ARCHIVE_OK,
1100			    archive_read_data_block(a, &p, &size, &offset));
1101			assertEqualInt((int)size, 11);
1102			assertEqualInt((int)offset, 0);
1103			assertEqualMem(p, "hello world", 11);
1104			assertEqualInt(ARCHIVE_EOF,
1105			    archive_read_data_block(a, &p, &size, &offset));
1106			assertEqualInt((int)size, 0);
1107			assertEqualInt((int)offset, 11);
1108		} else if (strcmp(archive_entry_pathname(ae), "at/fe") == 0) {
1109			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1110			assertEqualInt(archive_entry_size(ae), 0);
1111		}
1112		if (archive_entry_filetype(ae) == AE_IFDIR) {
1113			/* Descend into the current object */
1114			assertEqualIntA(a, ARCHIVE_OK,
1115			    archive_read_disk_descend(a));
1116		}
1117	}
1118	/* There is no entry. */
1119	failure("There must be no entry");
1120	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
1121
1122	/* On FreeBSD (and likely other systems), atime on
1123	   dirs does not change when it is read. */
1124	/* failure("Atime should be restored"); */
1125	/* assertFileAtimeRecent("at"); */
1126	failure("Atime should be restored");
1127	assertFileAtimeRecent("at/f1");
1128	failure("Atime should be restored");
1129	assertFileAtimeRecent("at/f2");
1130	failure("The atime of a empty file should not be changed");
1131	assertFileAtime("at/fe", 886611, 0);
1132
1133	/* Close the disk object. */
1134	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
1135
1136	/*
1137	 * Test2: Traversals with archive_read_disk_set_atime_restored().
1138	 */
1139	assertUtimes("at/f1", 886600, 0, 886600, 0);
1140	assertUtimes("at/f2", 886611, 0, 886611, 0);
1141	assertUtimes("at/fe", 886611, 0, 886611, 0);
1142	assertUtimes("at", 886622, 0, 886622, 0);
1143	file_count = 4;
1144	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_set_atime_restored(a));
1145	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "at"));
1146
1147	failure("Directory traversals should work as well");
1148	while (file_count--) {
1149		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
1150		if (strcmp(archive_entry_pathname(ae), "at") == 0) {
1151			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1152		} else if (strcmp(archive_entry_pathname(ae), "at/f1") == 0) {
1153			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1154			assertEqualInt(archive_entry_size(ae), 10);
1155			assertEqualIntA(a, ARCHIVE_OK,
1156			    archive_read_data_block(a, &p, &size, &offset));
1157			assertEqualInt((int)size, 10);
1158			assertEqualInt((int)offset, 0);
1159			assertEqualMem(p, "0123456789", 10);
1160			assertEqualInt(ARCHIVE_EOF,
1161			    archive_read_data_block(a, &p, &size, &offset));
1162			assertEqualInt((int)size, 0);
1163			assertEqualInt((int)offset, 10);
1164		} else if (strcmp(archive_entry_pathname(ae), "at/f2") == 0) {
1165			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1166			assertEqualInt(archive_entry_size(ae), 11);
1167			assertEqualIntA(a, ARCHIVE_OK,
1168			    archive_read_data_block(a, &p, &size, &offset));
1169			assertEqualInt((int)size, 11);
1170			assertEqualInt((int)offset, 0);
1171			assertEqualMem(p, "hello world", 11);
1172			assertEqualInt(ARCHIVE_EOF,
1173			    archive_read_data_block(a, &p, &size, &offset));
1174			assertEqualInt((int)size, 0);
1175			assertEqualInt((int)offset, 11);
1176		} else if (strcmp(archive_entry_pathname(ae), "at/fe") == 0) {
1177			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1178			assertEqualInt(archive_entry_size(ae), 0);
1179		}
1180		if (archive_entry_filetype(ae) == AE_IFDIR) {
1181			/* Descend into the current object */
1182			assertEqualIntA(a, ARCHIVE_OK,
1183			    archive_read_disk_descend(a));
1184		}
1185	}
1186	/* There is no entry. */
1187	failure("There must be no entry");
1188	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
1189
1190	failure("Atime should be restored");
1191	assertFileAtime("at", 886622, 0);
1192	failure("Atime should be restored");
1193	assertFileAtime("at/f1", 886600, 0);
1194	failure("Atime should be restored");
1195	assertFileAtime("at/f2", 886611, 0);
1196	failure("The atime of a empty file should not be changed");
1197	assertFileAtime("at/fe", 886611, 0);
1198
1199	/* Close the disk object. */
1200	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
1201
1202	/*
1203	 * Test3: Traversals with archive_read_disk_set_atime_restored() but
1204	 * no data read as a listing.
1205	 */
1206	assertUtimes("at/f1", 886600, 0, 886600, 0);
1207	assertUtimes("at/f2", 886611, 0, 886611, 0);
1208	assertUtimes("at/fe", 886611, 0, 886611, 0);
1209	assertUtimes("at", 886622, 0, 886622, 0);
1210	file_count = 4;
1211	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_set_atime_restored(a));
1212	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "at"));
1213
1214	failure("Directory traversals should work as well");
1215	while (file_count--) {
1216		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
1217		if (strcmp(archive_entry_pathname(ae), "at") == 0) {
1218			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1219		} else if (strcmp(archive_entry_pathname(ae), "at/f1") == 0) {
1220			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1221			assertEqualInt(archive_entry_size(ae), 10);
1222		} else if (strcmp(archive_entry_pathname(ae), "at/f2") == 0) {
1223			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1224			assertEqualInt(archive_entry_size(ae), 11);
1225		} else if (strcmp(archive_entry_pathname(ae), "at/fe") == 0) {
1226			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1227			assertEqualInt(archive_entry_size(ae), 0);
1228		}
1229		if (archive_entry_filetype(ae) == AE_IFDIR) {
1230			/* Descend into the current object */
1231			assertEqualIntA(a, ARCHIVE_OK,
1232			    archive_read_disk_descend(a));
1233		}
1234	}
1235	/* There is no entry. */
1236	failure("There must be no entry");
1237	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
1238
1239	failure("Atime should be restored");
1240	assertFileAtime("at", 886622, 0);
1241	failure("Atime should be restored");
1242	assertFileAtime("at/f1", 886600, 0);
1243	failure("Atime should be restored");
1244	assertFileAtime("at/f2", 886611, 0);
1245	failure("The atime of a empty file should not be changed");
1246	assertFileAtime("at/fe", 886611, 0);
1247
1248	if (!canNodump()) {
1249		/* Destroy the disk object. */
1250		assertEqualInt(ARCHIVE_OK, archive_read_free(a));
1251		archive_entry_free(ae);
1252		skipping("Can't test atime with nodump on this filesystem");
1253		return;
1254	}
1255
1256	/* Close the disk object. */
1257	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
1258
1259	/*
1260	 * Test4: Traversals with ARCHIVE_READDISK_RESTORE_ATIME and
1261	 * ARCHIVE_READDISK_HONOR_NODUMP
1262	 */
1263	assertSetNodump("at/f1");
1264	assertSetNodump("at/f2");
1265	assertUtimes("at/f1", 886600, 0, 886600, 0);
1266	assertUtimes("at/f2", 886611, 0, 886611, 0);
1267	assertUtimes("at/fe", 886611, 0, 886611, 0);
1268	assertUtimes("at", 886622, 0, 886622, 0);
1269	file_count = 2;
1270	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_set_behavior(a,
1271		ARCHIVE_READDISK_RESTORE_ATIME | ARCHIVE_READDISK_HONOR_NODUMP));
1272	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "at"));
1273
1274	failure("Directory traversals should work as well");
1275	while (file_count--) {
1276		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
1277		if (strcmp(archive_entry_pathname(ae), "at") == 0) {
1278			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1279		} else if (strcmp(archive_entry_pathname(ae), "at/fe") == 0) {
1280			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1281			assertEqualInt(archive_entry_size(ae), 0);
1282		}
1283		if (archive_entry_filetype(ae) == AE_IFDIR) {
1284			/* Descend into the current object */
1285			assertEqualIntA(a, ARCHIVE_OK,
1286			    archive_read_disk_descend(a));
1287		}
1288	}
1289	/* There is no entry. */
1290	failure("There must be no entry");
1291	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
1292
1293	failure("Atime should be restored");
1294	assertFileAtime("at", 886622, 0);
1295	failure("Atime should be restored");
1296	assertFileAtime("at/f1", 886600, 0);
1297	failure("Atime should be restored");
1298	assertFileAtime("at/f2", 886611, 0);
1299	failure("The atime of a empty file should not be changed");
1300	assertFileAtime("at/fe", 886611, 0);
1301
1302	/* Destroy the disk object. */
1303	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
1304	archive_entry_free(ae);
1305}
1306
1307static int
1308metadata_filter(struct archive *a, void *data, struct archive_entry *ae)
1309{
1310	(void)data; /* UNUSED */
1311
1312	failure("CTime should be set");
1313	assertEqualInt(8, archive_entry_ctime_is_set(ae));
1314	failure("MTime should be set");
1315	assertEqualInt(16, archive_entry_mtime_is_set(ae));
1316
1317	if (archive_entry_mtime(ae) < 886611)
1318		return (0);
1319	if (archive_read_disk_can_descend(a)) {
1320		/* Descend into the current object */
1321		failure("archive_read_disk_can_descend should work"
1322			" in metadata filter");
1323		assertEqualIntA(a, 1, archive_read_disk_can_descend(a));
1324		failure("archive_read_disk_descend should work"
1325			" in metadata filter");
1326		assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_descend(a));
1327	}
1328	return (1);
1329}
1330
1331static void
1332test_callbacks(void)
1333{
1334	struct archive *a;
1335	struct archive *m;
1336	struct archive_entry *ae;
1337	const void *p;
1338	size_t size;
1339	int64_t offset;
1340	int file_count;
1341
1342	assertMakeDir("cb", 0755);
1343	assertMakeFile("cb/f1", 0644, "0123456789");
1344	assertMakeFile("cb/f2", 0644, "hello world");
1345	assertMakeFile("cb/fe", 0644, NULL);
1346	assertUtimes("cb/f1", 886600, 0, 886600, 0);
1347	assertUtimes("cb/f2", 886611, 0, 886611, 0);
1348	assertUtimes("cb/fe", 886611, 0, 886611, 0);
1349	assertUtimes("cb", 886622, 0, 886622, 0);
1350
1351	assert((ae = archive_entry_new()) != NULL);
1352	assert((a = archive_read_disk_new()) != NULL);
1353	if (a == NULL) {
1354		archive_entry_free(ae);
1355		return;
1356	}
1357	assert((m = archive_match_new()) != NULL);
1358	if (m == NULL) {
1359		archive_entry_free(ae);
1360		archive_read_free(a);
1361		archive_match_free(m);
1362		return;
1363	}
1364
1365	/*
1366	 * Test1: Traversals with a name filter.
1367	 */
1368	file_count = 3;
1369	assertEqualIntA(m, ARCHIVE_OK,
1370	    archive_match_exclude_pattern(m, "cb/f2"));
1371	assertEqualIntA(a, ARCHIVE_OK,
1372	    archive_read_disk_set_matching(a, m, NULL, NULL));
1373	failure("Directory traversals should work as well");
1374	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "cb"));
1375	while (file_count--) {
1376		archive_entry_clear(ae);
1377		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
1378		failure("File 'cb/f2' should be exclueded");
1379		assert(strcmp(archive_entry_pathname(ae), "cb/f2") != 0);
1380		if (strcmp(archive_entry_pathname(ae), "cb") == 0) {
1381			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1382		} else if (strcmp(archive_entry_pathname(ae), "cb/f1") == 0) {
1383			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1384			assertEqualInt(archive_entry_size(ae), 10);
1385			assertEqualIntA(a, ARCHIVE_OK,
1386			    archive_read_data_block(a, &p, &size, &offset));
1387			assertEqualInt((int)size, 10);
1388			assertEqualInt((int)offset, 0);
1389			assertEqualMem(p, "0123456789", 10);
1390			assertEqualInt(ARCHIVE_EOF,
1391			    archive_read_data_block(a, &p, &size, &offset));
1392			assertEqualInt((int)size, 0);
1393			assertEqualInt((int)offset, 10);
1394		} else if (strcmp(archive_entry_pathname(ae), "cb/fe") == 0) {
1395			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1396			assertEqualInt(archive_entry_size(ae), 0);
1397		}
1398		if (archive_read_disk_can_descend(a)) {
1399			/* Descend into the current object */
1400			assertEqualIntA(a, ARCHIVE_OK,
1401			    archive_read_disk_descend(a));
1402		}
1403	}
1404	/* There is no entry. */
1405	failure("There should be no entry");
1406	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
1407
1408	/* Close the disk object. */
1409	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
1410
1411	/* Reset name filter */
1412	assertEqualIntA(a, ARCHIVE_OK,
1413	    archive_read_disk_set_matching(a, NULL, NULL, NULL));
1414
1415	/*
1416	 * Test2: Traversals with a metadata filter.
1417	 */
1418	assertUtimes("cb/f1", 886600, 0, 886600, 0);
1419	assertUtimes("cb/f2", 886611, 0, 886611, 0);
1420	assertUtimes("cb/fe", 886611, 0, 886611, 0);
1421	assertUtimes("cb", 886622, 0, 886622, 0);
1422	file_count = 3;
1423	assertEqualIntA(a, ARCHIVE_OK,
1424	    archive_read_disk_set_metadata_filter_callback(a, metadata_filter,
1425		    NULL));
1426	failure("Directory traversals should work as well");
1427	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "cb"));
1428
1429	while (file_count--) {
1430		archive_entry_clear(ae);
1431		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
1432		failure("File 'cb/f1' should be excluded");
1433		assert(strcmp(archive_entry_pathname(ae), "cb/f1") != 0);
1434		if (strcmp(archive_entry_pathname(ae), "cb") == 0) {
1435			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1436		} else if (strcmp(archive_entry_pathname(ae), "cb/f2") == 0) {
1437			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1438			assertEqualInt(archive_entry_size(ae), 11);
1439			assertEqualIntA(a, ARCHIVE_OK,
1440			    archive_read_data_block(a, &p, &size, &offset));
1441			assertEqualInt((int)size, 11);
1442			assertEqualInt((int)offset, 0);
1443			assertEqualMem(p, "hello world", 11);
1444			assertEqualInt(ARCHIVE_EOF,
1445			    archive_read_data_block(a, &p, &size, &offset));
1446			assertEqualInt((int)size, 0);
1447			assertEqualInt((int)offset, 11);
1448		} else if (strcmp(archive_entry_pathname(ae), "cb/fe") == 0) {
1449			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1450			assertEqualInt(archive_entry_size(ae), 0);
1451		}
1452	}
1453	/* There is no entry. */
1454	failure("There should be no entry");
1455	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
1456
1457	/* Destroy the disk object. */
1458	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
1459	assertEqualInt(ARCHIVE_OK, archive_match_free(m));
1460	archive_entry_free(ae);
1461}
1462
1463static void
1464test_nodump(void)
1465{
1466	struct archive *a;
1467	struct archive_entry *ae;
1468	const void *p;
1469	size_t size;
1470	int64_t offset;
1471	int file_count;
1472
1473	if (!canNodump()) {
1474		skipping("Can't test nodump on this filesystem");
1475		return;
1476	}
1477
1478	assertMakeDir("nd", 0755);
1479	assertMakeFile("nd/f1", 0644, "0123456789");
1480	assertMakeFile("nd/f2", 0644, "hello world");
1481	assertMakeFile("nd/fe", 0644, NULL);
1482	assertSetNodump("nd/f2");
1483	assertUtimes("nd/f1", 886600, 0, 886600, 0);
1484	assertUtimes("nd/f2", 886611, 0, 886611, 0);
1485	assertUtimes("nd/fe", 886611, 0, 886611, 0);
1486	assertUtimes("nd", 886622, 0, 886622, 0);
1487
1488	assert((ae = archive_entry_new()) != NULL);
1489	assert((a = archive_read_disk_new()) != NULL);
1490
1491	/*
1492	 * Test1: Traversals without ARCHIVE_READDISK_HONOR_NODUMP
1493	 */
1494	failure("Directory traversals should work as well");
1495	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "nd"));
1496
1497	file_count = 4;
1498	while (file_count--) {
1499		archive_entry_clear(ae);
1500		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
1501		if (strcmp(archive_entry_pathname(ae), "nd") == 0) {
1502			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1503		} else if (strcmp(archive_entry_pathname(ae), "nd/f1") == 0) {
1504			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1505			assertEqualInt(archive_entry_size(ae), 10);
1506			assertEqualIntA(a, ARCHIVE_OK,
1507			    archive_read_data_block(a, &p, &size, &offset));
1508			assertEqualInt((int)size, 10);
1509			assertEqualInt((int)offset, 0);
1510			assertEqualMem(p, "0123456789", 10);
1511			assertEqualInt(ARCHIVE_EOF,
1512			    archive_read_data_block(a, &p, &size, &offset));
1513			assertEqualInt((int)size, 0);
1514			assertEqualInt((int)offset, 10);
1515		} else if (strcmp(archive_entry_pathname(ae), "nd/f2") == 0) {
1516			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1517			assertEqualInt(archive_entry_size(ae), 11);
1518			assertEqualIntA(a, ARCHIVE_OK,
1519			    archive_read_data_block(a, &p, &size, &offset));
1520			assertEqualInt((int)size, 11);
1521			assertEqualInt((int)offset, 0);
1522			assertEqualMem(p, "hello world", 11);
1523			assertEqualInt(ARCHIVE_EOF,
1524			    archive_read_data_block(a, &p, &size, &offset));
1525			assertEqualInt((int)size, 0);
1526			assertEqualInt((int)offset, 11);
1527		} else if (strcmp(archive_entry_pathname(ae), "nd/fe") == 0) {
1528			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1529			assertEqualInt(archive_entry_size(ae), 0);
1530		}
1531		if (archive_read_disk_can_descend(a)) {
1532			/* Descend into the current object */
1533			assertEqualIntA(a, ARCHIVE_OK,
1534			    archive_read_disk_descend(a));
1535		}
1536	}
1537	/* There is no entry. */
1538	failure("There should be no entry");
1539	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
1540
1541	/* Close the disk object. */
1542	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
1543
1544	/*
1545	 * Test2: Traversals with ARCHIVE_READDISK_HONOR_NODUMP
1546	 */
1547	assertUtimes("nd/f1", 886600, 0, 886600, 0);
1548	assertUtimes("nd/f2", 886611, 0, 886611, 0);
1549	assertUtimes("nd/fe", 886611, 0, 886611, 0);
1550	assertUtimes("nd", 886622, 0, 886622, 0);
1551
1552	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_set_behavior(a,
1553		ARCHIVE_READDISK_RESTORE_ATIME | ARCHIVE_READDISK_HONOR_NODUMP));
1554	failure("Directory traversals should work as well");
1555	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "nd"));
1556
1557	file_count = 3;
1558	while (file_count--) {
1559		archive_entry_clear(ae);
1560		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
1561		failure("File 'nd/f2' should be exclueded");
1562		assert(strcmp(archive_entry_pathname(ae), "nd/f2") != 0);
1563		if (strcmp(archive_entry_pathname(ae), "nd") == 0) {
1564			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1565		} else if (strcmp(archive_entry_pathname(ae), "nd/f1") == 0) {
1566			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1567			assertEqualInt(archive_entry_size(ae), 10);
1568			assertEqualIntA(a, ARCHIVE_OK,
1569			    archive_read_data_block(a, &p, &size, &offset));
1570			assertEqualInt((int)size, 10);
1571			assertEqualInt((int)offset, 0);
1572			assertEqualMem(p, "0123456789", 10);
1573			assertEqualInt(ARCHIVE_EOF,
1574			    archive_read_data_block(a, &p, &size, &offset));
1575			assertEqualInt((int)size, 0);
1576			assertEqualInt((int)offset, 10);
1577		} else if (strcmp(archive_entry_pathname(ae), "nd/fe") == 0) {
1578			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1579			assertEqualInt(archive_entry_size(ae), 0);
1580		}
1581		if (archive_read_disk_can_descend(a)) {
1582			/* Descend into the current object */
1583			assertEqualIntA(a, ARCHIVE_OK,
1584			    archive_read_disk_descend(a));
1585		}
1586	}
1587	/* There is no entry. */
1588	failure("There should be no entry");
1589	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
1590
1591	failure("Atime should be restored");
1592	assertFileAtime("nd/f2", 886611, 0);
1593
1594	/* Destroy the disk object. */
1595	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
1596	archive_entry_free(ae);
1597}
1598
1599static void
1600test_parent(void)
1601{
1602	struct archive *a;
1603	struct archive_entry *ae;
1604	const void *p;
1605	size_t size;
1606	int64_t offset;
1607	int file_count;
1608	int match_count;
1609	int r;
1610#if defined(O_PATH) || (defined(O_SEARCH) && !defined(__NetBSD__)) || \
1611 (defined(__FreeBSD__) && defined(O_EXEC))
1612#define IGNORE_TRAVERSALS_TEST4
1613	const char *ignore_traversals_test4;
1614
1615	ignore_traversals_test4 = getenv("IGNORE_TRAVERSALS_TEST4");
1616#endif
1617
1618	assertMakeDir("lock", 0311);
1619	assertMakeDir("lock/dir1", 0755);
1620	assertMakeFile("lock/dir1/f1", 0644, "0123456789");
1621	assertMakeDir("lock/lock2", 0311);
1622	assertMakeDir("lock/lock2/dir1", 0755);
1623	assertMakeFile("lock/lock2/dir1/f1", 0644, "0123456789");
1624
1625	assert((ae = archive_entry_new()) != NULL);
1626	assert((a = archive_read_disk_new()) != NULL);
1627
1628	/*
1629	 * Test1: Traverse lock/dir1 as .
1630	 */
1631	assertChdir("lock/dir1");
1632
1633	failure("Directory traversals should work as well");
1634	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "."));
1635
1636	file_count = 2;
1637	match_count = 0;
1638	while (file_count--) {
1639		archive_entry_clear(ae);
1640		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
1641		if (strcmp(archive_entry_pathname(ae), ".") == 0) {
1642			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1643			++match_count;
1644		} else if (strcmp(archive_entry_pathname(ae), "./f1") == 0) {
1645			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1646			assertEqualInt(archive_entry_size(ae), 10);
1647			assertEqualIntA(a, ARCHIVE_OK,
1648			    archive_read_data_block(a, &p, &size, &offset));
1649			assertEqualInt((int)size, 10);
1650			assertEqualInt((int)offset, 0);
1651			assertEqualMem(p, "0123456789", 10);
1652			assertEqualInt(ARCHIVE_EOF,
1653			    archive_read_data_block(a, &p, &size, &offset));
1654			assertEqualInt((int)size, 0);
1655			assertEqualInt((int)offset, 10);
1656			++match_count;
1657		}
1658		if (archive_read_disk_can_descend(a)) {
1659			/* Descend into the current object */
1660			assertEqualIntA(a, ARCHIVE_OK,
1661			    archive_read_disk_descend(a));
1662		}
1663	}
1664	failure("Did not match expected filenames");
1665	assertEqualInt(match_count, 2);
1666	/*
1667	 * There is no entry. This will however fail if the directory traverse
1668	 * tries to ascend past the initial directory, since it lacks permission
1669	 * to do so.
1670	 */
1671	failure("There should be no entry and no error");
1672	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
1673
1674	/* Close the disk object. */
1675	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
1676
1677	assertChdir("../..");
1678
1679	/*
1680	 * Test2: Traverse lock/dir1 directly
1681	 */
1682	failure("Directory traversals should work as well");
1683	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "lock/dir1"));
1684
1685	file_count = 2;
1686	match_count = 0;
1687	while (file_count--) {
1688		archive_entry_clear(ae);
1689		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
1690		if (strcmp(archive_entry_pathname(ae), "lock/dir1") == 0) {
1691			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1692			++match_count;
1693		} else if (strcmp(archive_entry_pathname(ae), "lock/dir1/f1") == 0) {
1694			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1695			assertEqualInt(archive_entry_size(ae), 10);
1696			assertEqualIntA(a, ARCHIVE_OK,
1697			    archive_read_data_block(a, &p, &size, &offset));
1698			assertEqualInt((int)size, 10);
1699			assertEqualInt((int)offset, 0);
1700			assertEqualMem(p, "0123456789", 10);
1701			assertEqualInt(ARCHIVE_EOF,
1702			    archive_read_data_block(a, &p, &size, &offset));
1703			assertEqualInt((int)size, 0);
1704			assertEqualInt((int)offset, 10);
1705			++match_count;
1706		}
1707		if (archive_read_disk_can_descend(a)) {
1708			/* Descend into the current object */
1709			assertEqualIntA(a, ARCHIVE_OK,
1710			    archive_read_disk_descend(a));
1711		}
1712	}
1713	failure("Did not match expected filenames");
1714	assertEqualInt(match_count, 2);
1715	/*
1716	 * There is no entry. This will however fail if the directory traverse
1717	 * tries to ascend past the initial directory, since it lacks permission
1718	 * to do so.
1719	 */
1720	failure("There should be no entry and no error");
1721	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
1722
1723	/* Close the disk object. */
1724	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
1725
1726	/*
1727	 * Test3: Traverse lock/dir1/.
1728	 */
1729	failure("Directory traversals should work as well");
1730	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "lock/dir1/."));
1731
1732	file_count = 2;
1733	match_count = 0;
1734	while (file_count--) {
1735		archive_entry_clear(ae);
1736		assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae));
1737		if (strcmp(archive_entry_pathname(ae), "lock/dir1/.") == 0) {
1738			assertEqualInt(archive_entry_filetype(ae), AE_IFDIR);
1739			++match_count;
1740		} else if (strcmp(archive_entry_pathname(ae), "lock/dir1/./f1") == 0) {
1741			assertEqualInt(archive_entry_filetype(ae), AE_IFREG);
1742			assertEqualInt(archive_entry_size(ae), 10);
1743			assertEqualIntA(a, ARCHIVE_OK,
1744			    archive_read_data_block(a, &p, &size, &offset));
1745			assertEqualInt((int)size, 10);
1746			assertEqualInt((int)offset, 0);
1747			assertEqualMem(p, "0123456789", 10);
1748			assertEqualInt(ARCHIVE_EOF,
1749			    archive_read_data_block(a, &p, &size, &offset));
1750			assertEqualInt((int)size, 0);
1751			assertEqualInt((int)offset, 10);
1752			++match_count;
1753		}
1754		if (archive_read_disk_can_descend(a)) {
1755			/* Descend into the current object */
1756			assertEqualIntA(a, ARCHIVE_OK,
1757			    archive_read_disk_descend(a));
1758		}
1759	}
1760	failure("Did not match expected filenames");
1761	assertEqualInt(match_count, 2);
1762	/*
1763	 * There is no entry. This will however fail if the directory traverse
1764	 * tries to ascend past the initial directory, since it lacks permission
1765	 * to do so.
1766	 */
1767	failure("There should be no entry and no error");
1768	assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header2(a, ae));
1769
1770	/* Close the disk object. */
1771	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
1772
1773	/*
1774	 * Test4: Traverse lock/lock2/dir1 from inside lock.
1775	 *
1776	 * This test is expected to fail on platforms with no O_EXEC or
1777	 * equivalent (e.g. O_PATH on Linux or O_SEARCH on SunOS), because
1778	 * the current traversal code can't handle the case where it can't
1779	 * obtain an open fd for the initial current directory. We need to
1780	 * check that condition here, because if O_EXEC _does_ exist, we don't
1781	 * want to overlook any failure.
1782	 */
1783	assertChdir("lock");
1784
1785	failure("Directory traversals should work as well");
1786	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "lock2/dir1"));
1787
1788	archive_entry_clear(ae);
1789	r = archive_read_next_header2(a, ae);
1790	if (r == ARCHIVE_FAILED) {
1791#ifdef IGNORE_TRAVERSALS_TEST4
1792		if (ignore_traversals_test4 == NULL)
1793			assertEqualIntA(a, ARCHIVE_OK, r);
1794#endif
1795		/* Close the disk object. */
1796		archive_read_close(a);
1797	} else {
1798		file_count = 2;
1799		match_count = 0;
1800		while (file_count--) {
1801			if (file_count == 0)
1802				assertEqualIntA(a, ARCHIVE_OK,
1803				    archive_read_next_header2(a, ae));
1804			if (strcmp(archive_entry_pathname(ae),
1805				"lock2/dir1") == 0) {
1806				assertEqualInt(archive_entry_filetype(ae),
1807				    AE_IFDIR);
1808				++match_count;
1809			} else if (strcmp(archive_entry_pathname(ae),
1810				"lock2/dir1/f1") == 0) {
1811				assertEqualInt(archive_entry_filetype(ae),
1812				    AE_IFREG);
1813				assertEqualInt(archive_entry_size(ae), 10);
1814				assertEqualIntA(a, ARCHIVE_OK,
1815				    archive_read_data_block(a, &p, &size,
1816					&offset));
1817				assertEqualInt((int)size, 10);
1818				assertEqualInt((int)offset, 0);
1819				assertEqualMem(p, "0123456789", 10);
1820				assertEqualInt(ARCHIVE_EOF,
1821				    archive_read_data_block(a, &p, &size,
1822					&offset));
1823				assertEqualInt((int)size, 0);
1824				assertEqualInt((int)offset, 10);
1825				++match_count;
1826			}
1827			if (archive_read_disk_can_descend(a)) {
1828				/* Descend into the current object */
1829				assertEqualIntA(a, ARCHIVE_OK,
1830				    archive_read_disk_descend(a));
1831			}
1832		}
1833		failure("Did not match expected filenames");
1834		assertEqualInt(match_count, 2);
1835		/*
1836		 * There is no entry. This will however fail if the directory
1837		 * traverse tries to ascend past the initial directory, since
1838		 * it lacks permission to do so.
1839		 */
1840		failure("There should be no entry and no error");
1841		assertEqualIntA(a, ARCHIVE_EOF,
1842		    archive_read_next_header2(a, ae));
1843
1844		/* Close the disk object. */
1845		assertEqualInt(ARCHIVE_OK, archive_read_close(a));
1846	}
1847
1848	assertChdir("..");
1849	assertChmod("lock", 0755);
1850	assertChmod("lock/lock2", 0755);
1851
1852	/* Destroy the disk object. */
1853	assertEqualInt(ARCHIVE_OK, archive_read_free(a));
1854	archive_entry_free(ae);
1855}
1856
1857DEFINE_TEST(test_read_disk_directory_traversals)
1858{
1859	/* Basic test. */
1860	test_basic();
1861	/* Test hybrid mode; follow symlink initially, then not. */
1862	test_symlink_hybrid();
1863	/* Test logical mode; follow all symlinks. */
1864	test_symlink_logical();
1865	/* Test logical mode; prevent loop in symlinks. */
1866	test_symlink_logical_loop();
1867	/* Test to restore atime. */
1868	test_restore_atime();
1869	/* Test callbacks. */
1870	test_callbacks();
1871	/* Test nodump. */
1872	test_nodump();
1873	/* Test parent overshoot. */
1874	test_parent();
1875}
1876