]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/libarchive/libarchive/test/test_read_disk_directory_traversals.c
MFC r368207,368607:
[FreeBSD/stable/10.git] / contrib / libarchive / libarchive / test / test_read_disk_directory_traversals.c
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  */
38 static int
39 atimeIsUpdated(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
82 static void
83 test_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
575 static void
576 test_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
732 static void
733 test_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
962 static void
963 test_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
1041 static void
1042 test_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
1301 static int
1302 metadata_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
1325 static void
1326 test_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
1457 static void
1458 test_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
1593 static void
1594 test_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         assertChmod("lock", 0755);
1837         assertChmod("lock/lock2", 0755);
1838
1839         /* Destroy the disk object. */
1840         assertEqualInt(ARCHIVE_OK, archive_read_free(a));
1841         archive_entry_free(ae);
1842 }
1843
1844 DEFINE_TEST(test_read_disk_directory_traversals)
1845 {
1846         /* Basic test. */
1847         test_basic();
1848         /* Test hybrid mode; follow symlink initially, then not. */
1849         test_symlink_hybrid();
1850         /* Test logical mode; follow all symlinks. */
1851         test_symlink_logical();
1852         /* Test logical mode; prevent loop in symlinks. */
1853         test_symlink_logical_loop();
1854         /* Test to restore atime. */
1855         test_restore_atime();
1856         /* Test callbacks. */
1857         test_callbacks();
1858         /* Test nodump. */
1859         test_nodump();
1860         /* Test parent overshoot. */
1861         test_parent();
1862 }