]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/libarchive/test_utils/test_main.c
MFH r324148:
[FreeBSD/stable/10.git] / contrib / libarchive / test_utils / test_main.c
1 /*
2  * Copyright (c) 2003-2009 Tim Kientzle
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "test.h"
27 #include "test_utils.h"
28 #ifdef HAVE_SYS_IOCTL_H
29 #include <sys/ioctl.h>
30 #endif
31 #ifdef HAVE_SYS_TIME_H
32 #include <sys/time.h>
33 #endif
34 #include <errno.h>
35 #ifdef HAVE_ICONV_H
36 #include <iconv.h>
37 #endif
38 /*
39  * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h.
40  * As the include guards don't agree, the order of include is important.
41  */
42 #ifdef HAVE_LINUX_EXT2_FS_H
43 #include <linux/ext2_fs.h>      /* for Linux file flags */
44 #endif
45 #if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__)
46 #include <ext2fs/ext2_fs.h>     /* Linux file flags, broken on Cygwin */
47 #endif
48 #ifdef HAVE_LINUX_FS_H
49 #include <linux/fs.h>
50 #endif
51 #include <limits.h>
52 #include <locale.h>
53 #ifdef HAVE_SIGNAL_H
54 #include <signal.h>
55 #endif
56 #include <stdarg.h>
57 #include <time.h>
58
59 #ifdef HAVE_SIGNAL_H
60 #endif
61 #ifdef HAVE_ACL_LIBACL_H
62 #include <acl/libacl.h>
63 #endif
64 #ifdef HAVE_SYS_TYPES_H
65 #include <sys/types.h>
66 #endif
67 #ifdef HAVE_SYS_ACL_H
68 #include <sys/acl.h>
69 #endif
70 #ifdef HAVE_SYS_EA_H
71 #include <sys/ea.h>
72 #endif
73 #ifdef HAVE_SYS_EXTATTR_H
74 #include <sys/extattr.h>
75 #endif
76 #if HAVE_SYS_XATTR_H
77 #include <sys/xattr.h>
78 #elif HAVE_ATTR_XATTR_H
79 #include <attr/xattr.h>
80 #endif
81 #ifdef HAVE_SYS_RICHACL_H
82 #include <sys/richacl.h>
83 #endif
84 #if HAVE_MEMBERSHIP_H
85 #include <membership.h>
86 #endif
87
88 /*
89  *
90  * Windows support routines
91  *
92  * Note: Configuration is a tricky issue.  Using HAVE_* feature macros
93  * in the test harness is dangerous because they cover up
94  * configuration errors.  The classic example of this is omitting a
95  * configure check.  If libarchive and libarchive_test both look for
96  * the same feature macro, such errors are hard to detect.  Platform
97  * macros (e.g., _WIN32 or __GNUC__) are a little better, but can
98  * easily lead to very messy code.  It's best to limit yourself
99  * to only the most generic programming techniques in the test harness
100  * and thus avoid conditionals altogether.  Where that's not possible,
101  * try to minimize conditionals by grouping platform-specific tests in
102  * one place (e.g., test_acl_freebsd) or by adding new assert()
103  * functions (e.g., assertMakeHardlink()) to cover up platform
104  * differences.  Platform-specific coding in libarchive_test is often
105  * a symptom that some capability is missing from libarchive itself.
106  */
107 #if defined(_WIN32) && !defined(__CYGWIN__)
108 #include <io.h>
109 #include <direct.h>
110 #include <windows.h>
111 #ifndef F_OK
112 #define F_OK (0)
113 #endif
114 #ifndef S_ISDIR
115 #define S_ISDIR(m)  ((m) & _S_IFDIR)
116 #endif
117 #ifndef S_ISREG
118 #define S_ISREG(m)  ((m) & _S_IFREG)
119 #endif
120 #if !defined(__BORLANDC__)
121 #define access _access
122 #undef chdir
123 #define chdir _chdir
124 #endif
125 #ifndef fileno
126 #define fileno _fileno
127 #endif
128 /*#define fstat _fstat64*/
129 #if !defined(__BORLANDC__)
130 #define getcwd _getcwd
131 #endif
132 #define lstat stat
133 /*#define lstat _stat64*/
134 /*#define stat _stat64*/
135 #define rmdir _rmdir
136 #if !defined(__BORLANDC__)
137 #define strdup _strdup
138 #define umask _umask
139 #endif
140 #define int64_t __int64
141 #endif
142
143 #if defined(HAVE__CrtSetReportMode)
144 # include <crtdbg.h>
145 #endif
146
147 mode_t umasked(mode_t expected_mode)
148 {
149         mode_t mode = umask(0);
150         umask(mode);
151         return expected_mode & ~mode;
152 }
153
154 /* Path to working directory for current test */
155 const char *testworkdir;
156 #ifdef PROGRAM
157 /* Pathname of exe to be tested. */
158 const char *testprogfile;
159 /* Name of exe to use in printf-formatted command strings. */
160 /* On Windows, this includes leading/trailing quotes. */
161 const char *testprog;
162 #endif
163
164 #if defined(_WIN32) && !defined(__CYGWIN__)
165 static void     *GetFunctionKernel32(const char *);
166 static int       my_CreateSymbolicLinkA(const char *, const char *, int);
167 static int       my_CreateHardLinkA(const char *, const char *);
168 static int       my_GetFileInformationByName(const char *,
169                      BY_HANDLE_FILE_INFORMATION *);
170
171 static void *
172 GetFunctionKernel32(const char *name)
173 {
174         static HINSTANCE lib;
175         static int set;
176         if (!set) {
177                 set = 1;
178                 lib = LoadLibrary("kernel32.dll");
179         }
180         if (lib == NULL) {
181                 fprintf(stderr, "Can't load kernel32.dll?!\n");
182                 exit(1);
183         }
184         return (void *)GetProcAddress(lib, name);
185 }
186
187 static int
188 my_CreateSymbolicLinkA(const char *linkname, const char *target, int flags)
189 {
190         static BOOLEAN (WINAPI *f)(LPCSTR, LPCSTR, DWORD);
191         static int set;
192         if (!set) {
193                 set = 1;
194                 f = GetFunctionKernel32("CreateSymbolicLinkA");
195         }
196         return f == NULL ? 0 : (*f)(linkname, target, flags);
197 }
198
199 static int
200 my_CreateHardLinkA(const char *linkname, const char *target)
201 {
202         static BOOLEAN (WINAPI *f)(LPCSTR, LPCSTR, LPSECURITY_ATTRIBUTES);
203         static int set;
204         if (!set) {
205                 set = 1;
206                 f = GetFunctionKernel32("CreateHardLinkA");
207         }
208         return f == NULL ? 0 : (*f)(linkname, target, NULL);
209 }
210
211 static int
212 my_GetFileInformationByName(const char *path, BY_HANDLE_FILE_INFORMATION *bhfi)
213 {
214         HANDLE h;
215         int r;
216
217         memset(bhfi, 0, sizeof(*bhfi));
218         h = CreateFile(path, FILE_READ_ATTRIBUTES, 0, NULL,
219                 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
220         if (h == INVALID_HANDLE_VALUE)
221                 return (0);
222         r = GetFileInformationByHandle(h, bhfi);
223         CloseHandle(h);
224         return (r);
225 }
226 #endif
227
228 #if defined(HAVE__CrtSetReportMode) && !defined(__WATCOMC__)
229 static void
230 invalid_parameter_handler(const wchar_t * expression,
231     const wchar_t * function, const wchar_t * file,
232     unsigned int line, uintptr_t pReserved)
233 {
234         /* nop */
235         // Silence unused-parameter compiler warnings.
236         (void)expression;
237         (void)function;
238         (void)file;
239         (void)line;
240         (void)pReserved;
241 }
242 #endif
243
244 /*
245  *
246  * OPTIONS FLAGS
247  *
248  */
249
250 /* Enable core dump on failure. */
251 static int dump_on_failure = 0;
252 /* Default is to remove temp dirs and log data for successful tests. */
253 static int keep_temp_files = 0;
254 /* Default is to run the specified tests once and report errors. */
255 static int until_failure = 0;
256 /* Default is to just report pass/fail for each test. */
257 static int verbosity = 0;
258 #define VERBOSITY_SUMMARY_ONLY -1 /* -q */
259 #define VERBOSITY_PASSFAIL 0   /* Default */
260 #define VERBOSITY_LIGHT_REPORT 1 /* -v */
261 #define VERBOSITY_FULL 2 /* -vv */
262 /* A few places generate even more output for verbosity > VERBOSITY_FULL,
263  * mostly for debugging the test harness itself. */
264 /* Cumulative count of assertion failures. */
265 static int failures = 0;
266 /* Cumulative count of reported skips. */
267 static int skips = 0;
268 /* Cumulative count of assertions checked. */
269 static int assertions = 0;
270
271 /* Directory where uuencoded reference files can be found. */
272 static const char *refdir;
273
274 /*
275  * Report log information selectively to console and/or disk log.
276  */
277 static int log_console = 0;
278 static FILE *logfile;
279 static void
280 vlogprintf(const char *fmt, va_list ap)
281 {
282 #ifdef va_copy
283         va_list lfap;
284         va_copy(lfap, ap);
285 #endif
286         if (log_console)
287                 vfprintf(stdout, fmt, ap);
288         if (logfile != NULL)
289 #ifdef va_copy
290                 vfprintf(logfile, fmt, lfap);
291         va_end(lfap);
292 #else
293                 vfprintf(logfile, fmt, ap);
294 #endif
295 }
296
297 static void
298 logprintf(const char *fmt, ...)
299 {
300         va_list ap;
301         va_start(ap, fmt);
302         vlogprintf(fmt, ap);
303         va_end(ap);
304 }
305
306 /* Set up a message to display only if next assertion fails. */
307 static char msgbuff[4096];
308 static const char *msg, *nextmsg;
309 void
310 failure(const char *fmt, ...)
311 {
312         va_list ap;
313         if (fmt == NULL) {
314                 nextmsg = NULL;
315         } else {
316                 va_start(ap, fmt);
317                 vsprintf(msgbuff, fmt, ap);
318                 va_end(ap);
319                 nextmsg = msgbuff;
320         }
321 }
322
323 /*
324  * Copy arguments into file-local variables.
325  * This was added to permit vararg assert() functions without needing
326  * variadic wrapper macros.  Turns out that the vararg capability is almost
327  * never used, so almost all of the vararg assertions can be simplified
328  * by removing the vararg capability and reworking the wrapper macro to
329  * pass __FILE__, __LINE__ directly into the function instead of using
330  * this hook.  I suspect this machinery is used so rarely that we
331  * would be better off just removing it entirely.  That would simplify
332  * the code here noticeably.
333  */
334 static const char *skipping_filename;
335 static int skipping_line;
336 void skipping_setup(const char *filename, int line)
337 {
338         skipping_filename = filename;
339         skipping_line = line;
340 }
341
342 /* Called at the beginning of each assert() function. */
343 static void
344 assertion_count(const char *file, int line)
345 {
346         (void)file; /* UNUSED */
347         (void)line; /* UNUSED */
348         ++assertions;
349         /* Proper handling of "failure()" message. */
350         msg = nextmsg;
351         nextmsg = NULL;
352         /* Uncomment to print file:line after every assertion.
353          * Verbose, but occasionally useful in tracking down crashes. */
354         /* printf("Checked %s:%d\n", file, line); */
355 }
356
357 /*
358  * For each test source file, we remember how many times each
359  * assertion was reported.  Cleared before each new test,
360  * used by test_summarize().
361  */
362 static struct line {
363         int count;
364         int skip;
365 }  failed_lines[10000];
366 const char *failed_filename;
367
368 /* Count this failure, setup up log destination and handle initial report. */
369 static void
370 failure_start(const char *filename, int line, const char *fmt, ...)
371 {
372         va_list ap;
373
374         /* Record another failure for this line. */
375         ++failures;
376         failed_filename = filename;
377         failed_lines[line].count++;
378
379         /* Determine whether to log header to console. */
380         switch (verbosity) {
381         case VERBOSITY_LIGHT_REPORT:
382                 log_console = (failed_lines[line].count < 2);
383                 break;
384         default:
385                 log_console = (verbosity >= VERBOSITY_FULL);
386         }
387
388         /* Log file:line header for this failure */
389         va_start(ap, fmt);
390 #if _MSC_VER
391         logprintf("%s(%d): ", filename, line);
392 #else
393         logprintf("%s:%d: ", filename, line);
394 #endif
395         vlogprintf(fmt, ap);
396         va_end(ap);
397         logprintf("\n");
398
399         if (msg != NULL && msg[0] != '\0') {
400                 logprintf("   Description: %s\n", msg);
401                 msg = NULL;
402         }
403
404         /* Determine whether to log details to console. */
405         if (verbosity == VERBOSITY_LIGHT_REPORT)
406                 log_console = 0;
407 }
408
409 /* Complete reporting of failed tests. */
410 /*
411  * The 'extra' hook here is used by libarchive to include libarchive
412  * error messages with assertion failures.  It could also be used
413  * to add strerror() output, for example.  Just define the EXTRA_DUMP()
414  * macro appropriately.
415  */
416 static void
417 failure_finish(void *extra)
418 {
419         (void)extra; /* UNUSED (maybe) */
420 #ifdef EXTRA_DUMP
421         if (extra != NULL) {
422                 logprintf("    errno: %d\n", EXTRA_ERRNO(extra));
423                 logprintf("   detail: %s\n", EXTRA_DUMP(extra));
424         }
425 #endif
426
427         if (dump_on_failure) {
428                 fprintf(stderr,
429                     " *** forcing core dump so failure can be debugged ***\n");
430                 abort();
431         }
432 }
433
434 /* Inform user that we're skipping some checks. */
435 void
436 test_skipping(const char *fmt, ...)
437 {
438         char buff[1024];
439         va_list ap;
440
441         va_start(ap, fmt);
442         vsprintf(buff, fmt, ap);
443         va_end(ap);
444         /* Use failure() message if set. */
445         msg = nextmsg;
446         nextmsg = NULL;
447         /* failure_start() isn't quite right, but is awfully convenient. */
448         failure_start(skipping_filename, skipping_line, "SKIPPING: %s", buff);
449         --failures; /* Undo failures++ in failure_start() */
450         /* Don't failure_finish() here. */
451         /* Mark as skip, so doesn't count as failed test. */
452         failed_lines[skipping_line].skip = 1;
453         ++skips;
454 }
455
456 /*
457  *
458  * ASSERTIONS
459  *
460  */
461
462 /* Generic assert() just displays the failed condition. */
463 int
464 assertion_assert(const char *file, int line, int value,
465     const char *condition, void *extra)
466 {
467         assertion_count(file, line);
468         if (!value) {
469                 failure_start(file, line, "Assertion failed: %s", condition);
470                 failure_finish(extra);
471         }
472         return (value);
473 }
474
475 /* chdir() and report any errors */
476 int
477 assertion_chdir(const char *file, int line, const char *pathname)
478 {
479         assertion_count(file, line);
480         if (chdir(pathname) == 0)
481                 return (1);
482         failure_start(file, line, "chdir(\"%s\")", pathname);
483         failure_finish(NULL);
484         return (0);
485
486 }
487
488 /* Verify two integers are equal. */
489 int
490 assertion_equal_int(const char *file, int line,
491     long long v1, const char *e1, long long v2, const char *e2, void *extra)
492 {
493         assertion_count(file, line);
494         if (v1 == v2)
495                 return (1);
496         failure_start(file, line, "%s != %s", e1, e2);
497         logprintf("      %s=%lld (0x%llx, 0%llo)\n", e1, v1, v1, v1);
498         logprintf("      %s=%lld (0x%llx, 0%llo)\n", e2, v2, v2, v2);
499         failure_finish(extra);
500         return (0);
501 }
502
503 /*
504  * Utility to convert a single UTF-8 sequence.
505  */
506 static int
507 _utf8_to_unicode(uint32_t *pwc, const char *s, size_t n)
508 {
509         static const char utf8_count[256] = {
510                  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 00 - 0F */
511                  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 10 - 1F */
512                  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 20 - 2F */
513                  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 30 - 3F */
514                  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40 - 4F */
515                  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 50 - 5F */
516                  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 60 - 6F */
517                  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 70 - 7F */
518                  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 80 - 8F */
519                  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 90 - 9F */
520                  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* A0 - AF */
521                  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* B0 - BF */
522                  0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,/* C0 - CF */
523                  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,/* D0 - DF */
524                  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,/* E0 - EF */
525                  4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* F0 - FF */
526         };
527         int ch;
528         int cnt;
529         uint32_t wc;
530
531         *pwc = 0;
532
533         /* Sanity check. */
534         if (n == 0)
535                 return (0);
536         /*
537          * Decode 1-4 bytes depending on the value of the first byte.
538          */
539         ch = (unsigned char)*s;
540         if (ch == 0)
541                 return (0); /* Standard:  return 0 for end-of-string. */
542         cnt = utf8_count[ch];
543
544         /* Invalid sequence or there are not plenty bytes. */
545         if (n < (size_t)cnt)
546                 return (-1);
547
548         /* Make a Unicode code point from a single UTF-8 sequence. */
549         switch (cnt) {
550         case 1: /* 1 byte sequence. */
551                 *pwc = ch & 0x7f;
552                 return (cnt);
553         case 2: /* 2 bytes sequence. */
554                 if ((s[1] & 0xc0) != 0x80) return (-1);
555                 *pwc = ((ch & 0x1f) << 6) | (s[1] & 0x3f);
556                 return (cnt);
557         case 3: /* 3 bytes sequence. */
558                 if ((s[1] & 0xc0) != 0x80) return (-1);
559                 if ((s[2] & 0xc0) != 0x80) return (-1);
560                 wc = ((ch & 0x0f) << 12)
561                     | ((s[1] & 0x3f) << 6)
562                     | (s[2] & 0x3f);
563                 if (wc < 0x800)
564                         return (-1);/* Overlong sequence. */
565                 break;
566         case 4: /* 4 bytes sequence. */
567                 if (n < 4)
568                         return (-1);
569                 if ((s[1] & 0xc0) != 0x80) return (-1);
570                 if ((s[2] & 0xc0) != 0x80) return (-1);
571                 if ((s[3] & 0xc0) != 0x80) return (-1);
572                 wc = ((ch & 0x07) << 18)
573                     | ((s[1] & 0x3f) << 12)
574                     | ((s[2] & 0x3f) << 6)
575                     | (s[3] & 0x3f);
576                 if (wc < 0x10000)
577                         return (-1);/* Overlong sequence. */
578                 break;
579         default:
580                 return (-1);
581         }
582
583         /* The code point larger than 0x10FFFF is not legal
584          * Unicode values. */
585         if (wc > 0x10FFFF)
586                 return (-1);
587         /* Correctly gets a Unicode, returns used bytes. */
588         *pwc = wc;
589         return (cnt);
590 }
591
592 static void strdump(const char *e, const char *p, int ewidth, int utf8)
593 {
594         const char *q = p;
595
596         logprintf("      %*s = ", ewidth, e);
597         if (p == NULL) {
598                 logprintf("NULL\n");
599                 return;
600         }
601         logprintf("\"");
602         while (*p != '\0') {
603                 unsigned int c = 0xff & *p++;
604                 switch (c) {
605                 case '\a': logprintf("\\a"); break;
606                 case '\b': logprintf("\\b"); break;
607                 case '\n': logprintf("\\n"); break;
608                 case '\r': logprintf("\\r"); break;
609                 default:
610                         if (c >= 32 && c < 127)
611                                 logprintf("%c", c);
612                         else
613                                 logprintf("\\x%02X", c);
614                 }
615         }
616         logprintf("\"");
617         logprintf(" (length %d)", q == NULL ? -1 : (int)strlen(q));
618
619         /*
620          * If the current string is UTF-8, dump its code points.
621          */
622         if (utf8) {
623                 size_t len;
624                 uint32_t uc;
625                 int n;
626                 int cnt = 0;
627
628                 p = q;
629                 len = strlen(p);
630                 logprintf(" [");
631                 while ((n = _utf8_to_unicode(&uc, p, len)) > 0) {
632                         if (p != q)
633                                 logprintf(" ");
634                         logprintf("%04X", uc);
635                         p += n;
636                         len -= n;
637                         cnt++;
638                 }
639                 logprintf("]");
640                 logprintf(" (count %d", cnt);
641                 if (n < 0) {
642                         logprintf(",unknown %d bytes", len);
643                 }
644                 logprintf(")");
645
646         }
647         logprintf("\n");
648 }
649
650 /* Verify two strings are equal, dump them if not. */
651 int
652 assertion_equal_string(const char *file, int line,
653     const char *v1, const char *e1,
654     const char *v2, const char *e2,
655     void *extra, int utf8)
656 {
657         int l1, l2;
658
659         assertion_count(file, line);
660         if (v1 == v2 || (v1 != NULL && v2 != NULL && strcmp(v1, v2) == 0))
661                 return (1);
662         failure_start(file, line, "%s != %s", e1, e2);
663         l1 = (int)strlen(e1);
664         l2 = (int)strlen(e2);
665         if (l1 < l2)
666                 l1 = l2;
667         strdump(e1, v1, l1, utf8);
668         strdump(e2, v2, l1, utf8);
669         failure_finish(extra);
670         return (0);
671 }
672
673 static void
674 wcsdump(const char *e, const wchar_t *w)
675 {
676         logprintf("      %s = ", e);
677         if (w == NULL) {
678                 logprintf("(null)");
679                 return;
680         }
681         logprintf("\"");
682         while (*w != L'\0') {
683                 unsigned int c = *w++;
684                 if (c >= 32 && c < 127)
685                         logprintf("%c", c);
686                 else if (c < 256)
687                         logprintf("\\x%02X", c);
688                 else if (c < 0x10000)
689                         logprintf("\\u%04X", c);
690                 else
691                         logprintf("\\U%08X", c);
692         }
693         logprintf("\"\n");
694 }
695
696 #ifndef HAVE_WCSCMP
697 static int
698 wcscmp(const wchar_t *s1, const wchar_t *s2)
699 {
700
701         while (*s1 == *s2++) {
702                 if (*s1++ == L'\0')
703                         return 0;
704         }
705         if (*s1 > *--s2)
706                 return 1;
707         else
708                 return -1;
709 }
710 #endif
711
712 /* Verify that two wide strings are equal, dump them if not. */
713 int
714 assertion_equal_wstring(const char *file, int line,
715     const wchar_t *v1, const char *e1,
716     const wchar_t *v2, const char *e2,
717     void *extra)
718 {
719         assertion_count(file, line);
720         if (v1 == v2)
721                 return (1);
722         if (v1 != NULL && v2 != NULL && wcscmp(v1, v2) == 0)
723                 return (1);
724         failure_start(file, line, "%s != %s", e1, e2);
725         wcsdump(e1, v1);
726         wcsdump(e2, v2);
727         failure_finish(extra);
728         return (0);
729 }
730
731 /*
732  * Pretty standard hexdump routine.  As a bonus, if ref != NULL, then
733  * any bytes in p that differ from ref will be highlighted with '_'
734  * before and after the hex value.
735  */
736 static void
737 hexdump(const char *p, const char *ref, size_t l, size_t offset)
738 {
739         size_t i, j;
740         char sep;
741
742         if (p == NULL) {
743                 logprintf("(null)\n");
744                 return;
745         }
746         for(i=0; i < l; i+=16) {
747                 logprintf("%04x", (unsigned)(i + offset));
748                 sep = ' ';
749                 for (j = 0; j < 16 && i + j < l; j++) {
750                         if (ref != NULL && p[i + j] != ref[i + j])
751                                 sep = '_';
752                         logprintf("%c%02x", sep, 0xff & (int)p[i+j]);
753                         if (ref != NULL && p[i + j] == ref[i + j])
754                                 sep = ' ';
755                 }
756                 for (; j < 16; j++) {
757                         logprintf("%c  ", sep);
758                         sep = ' ';
759                 }
760                 logprintf("%c", sep);
761                 for (j=0; j < 16 && i + j < l; j++) {
762                         int c = p[i + j];
763                         if (c >= ' ' && c <= 126)
764                                 logprintf("%c", c);
765                         else
766                                 logprintf(".");
767                 }
768                 logprintf("\n");
769         }
770 }
771
772 /* Verify that two blocks of memory are the same, display the first
773  * block of differences if they're not. */
774 int
775 assertion_equal_mem(const char *file, int line,
776     const void *_v1, const char *e1,
777     const void *_v2, const char *e2,
778     size_t l, const char *ld, void *extra)
779 {
780         const char *v1 = (const char *)_v1;
781         const char *v2 = (const char *)_v2;
782         size_t offset;
783
784         assertion_count(file, line);
785         if (v1 == v2 || (v1 != NULL && v2 != NULL && memcmp(v1, v2, l) == 0))
786                 return (1);
787         if (v1 == NULL || v2 == NULL)
788                 return (0);
789
790         failure_start(file, line, "%s != %s", e1, e2);
791         logprintf("      size %s = %d\n", ld, (int)l);
792         /* Dump 48 bytes (3 lines) so that the first difference is
793          * in the second line. */
794         offset = 0;
795         while (l > 64 && memcmp(v1, v2, 32) == 0) {
796                 /* Two lines agree, so step forward one line. */
797                 v1 += 16;
798                 v2 += 16;
799                 l -= 16;
800                 offset += 16;
801         }
802         logprintf("      Dump of %s\n", e1);
803         hexdump(v1, v2, l < 128 ? l : 128, offset);
804         logprintf("      Dump of %s\n", e2);
805         hexdump(v2, v1, l < 128 ? l : 128, offset);
806         logprintf("\n");
807         failure_finish(extra);
808         return (0);
809 }
810
811 /* Verify that a block of memory is filled with the specified byte. */
812 int
813 assertion_memory_filled_with(const char *file, int line,
814     const void *_v1, const char *vd,
815     size_t l, const char *ld,
816     char b, const char *bd, void *extra)
817 {
818         const char *v1 = (const char *)_v1;
819         size_t c = 0;
820         size_t i;
821         (void)ld; /* UNUSED */
822
823         assertion_count(file, line);
824
825         for (i = 0; i < l; ++i) {
826                 if (v1[i] == b) {
827                         ++c;
828                 }
829         }
830         if (c == l)
831                 return (1);
832
833         failure_start(file, line, "%s (size %d) not filled with %s", vd, (int)l, bd);
834         logprintf("   Only %d bytes were correct\n", (int)c);
835         failure_finish(extra);
836         return (0);
837 }
838
839 /* Verify that the named file exists and is empty. */
840 int
841 assertion_empty_file(const char *filename, int line, const char *f1)
842 {
843         char buff[1024];
844         struct stat st;
845         ssize_t s;
846         FILE *f;
847
848         assertion_count(filename, line);
849
850         if (stat(f1, &st) != 0) {
851                 failure_start(filename, line, "Stat failed: %s", f1);
852                 failure_finish(NULL);
853                 return (0);
854         }
855         if (st.st_size == 0)
856                 return (1);
857
858         failure_start(filename, line, "File should be empty: %s", f1);
859         logprintf("    File size: %d\n", (int)st.st_size);
860         logprintf("    Contents:\n");
861         f = fopen(f1, "rb");
862         if (f == NULL) {
863                 logprintf("    Unable to open %s\n", f1);
864         } else {
865                 s = ((off_t)sizeof(buff) < st.st_size) ?
866                     (ssize_t)sizeof(buff) : (ssize_t)st.st_size;
867                 s = fread(buff, 1, s, f);
868                 hexdump(buff, NULL, s, 0);
869                 fclose(f);
870         }
871         failure_finish(NULL);
872         return (0);
873 }
874
875 /* Verify that the named file exists and is not empty. */
876 int
877 assertion_non_empty_file(const char *filename, int line, const char *f1)
878 {
879         struct stat st;
880
881         assertion_count(filename, line);
882
883         if (stat(f1, &st) != 0) {
884                 failure_start(filename, line, "Stat failed: %s", f1);
885                 failure_finish(NULL);
886                 return (0);
887         }
888         if (st.st_size == 0) {
889                 failure_start(filename, line, "File empty: %s", f1);
890                 failure_finish(NULL);
891                 return (0);
892         }
893         return (1);
894 }
895
896 /* Verify that two files have the same contents. */
897 /* TODO: hexdump the first bytes that actually differ. */
898 int
899 assertion_equal_file(const char *filename, int line, const char *fn1, const char *fn2)
900 {
901         char buff1[1024];
902         char buff2[1024];
903         FILE *f1, *f2;
904         int n1, n2;
905
906         assertion_count(filename, line);
907
908         f1 = fopen(fn1, "rb");
909         f2 = fopen(fn2, "rb");
910         if (f1 == NULL || f2 == NULL) {
911                 if (f1) fclose(f1);
912                 if (f2) fclose(f2);
913                 return (0);
914         }
915         for (;;) {
916                 n1 = (int)fread(buff1, 1, sizeof(buff1), f1);
917                 n2 = (int)fread(buff2, 1, sizeof(buff2), f2);
918                 if (n1 != n2)
919                         break;
920                 if (n1 == 0 && n2 == 0) {
921                         fclose(f1);
922                         fclose(f2);
923                         return (1);
924                 }
925                 if (memcmp(buff1, buff2, n1) != 0)
926                         break;
927         }
928         fclose(f1);
929         fclose(f2);
930         failure_start(filename, line, "Files not identical");
931         logprintf("  file1=\"%s\"\n", fn1);
932         logprintf("  file2=\"%s\"\n", fn2);
933         failure_finish(NULL);
934         return (0);
935 }
936
937 /* Verify that the named file does exist. */
938 int
939 assertion_file_exists(const char *filename, int line, const char *f)
940 {
941         assertion_count(filename, line);
942
943 #if defined(_WIN32) && !defined(__CYGWIN__)
944         if (!_access(f, 0))
945                 return (1);
946 #else
947         if (!access(f, F_OK))
948                 return (1);
949 #endif
950         failure_start(filename, line, "File should exist: %s", f);
951         failure_finish(NULL);
952         return (0);
953 }
954
955 /* Verify that the named file doesn't exist. */
956 int
957 assertion_file_not_exists(const char *filename, int line, const char *f)
958 {
959         assertion_count(filename, line);
960
961 #if defined(_WIN32) && !defined(__CYGWIN__)
962         if (_access(f, 0))
963                 return (1);
964 #else
965         if (access(f, F_OK))
966                 return (1);
967 #endif
968         failure_start(filename, line, "File should not exist: %s", f);
969         failure_finish(NULL);
970         return (0);
971 }
972
973 /* Compare the contents of a file to a block of memory. */
974 int
975 assertion_file_contents(const char *filename, int line, const void *buff, int s, const char *fn)
976 {
977         char *contents;
978         FILE *f;
979         int n;
980
981         assertion_count(filename, line);
982
983         f = fopen(fn, "rb");
984         if (f == NULL) {
985                 failure_start(filename, line,
986                     "File should exist: %s", fn);
987                 failure_finish(NULL);
988                 return (0);
989         }
990         contents = malloc(s * 2);
991         n = (int)fread(contents, 1, s * 2, f);
992         fclose(f);
993         if (n == s && memcmp(buff, contents, s) == 0) {
994                 free(contents);
995                 return (1);
996         }
997         failure_start(filename, line, "File contents don't match");
998         logprintf("  file=\"%s\"\n", fn);
999         if (n > 0)
1000                 hexdump(contents, buff, n > 512 ? 512 : n, 0);
1001         else {
1002                 logprintf("  File empty, contents should be:\n");
1003                 hexdump(buff, NULL, s > 512 ? 512 : s, 0);
1004         }
1005         failure_finish(NULL);
1006         free(contents);
1007         return (0);
1008 }
1009
1010 /* Check the contents of a text file, being tolerant of line endings. */
1011 int
1012 assertion_text_file_contents(const char *filename, int line, const char *buff, const char *fn)
1013 {
1014         char *contents;
1015         const char *btxt, *ftxt;
1016         FILE *f;
1017         int n, s;
1018
1019         assertion_count(filename, line);
1020         f = fopen(fn, "r");
1021         if (f == NULL) {
1022                 failure_start(filename, line,
1023                     "File doesn't exist: %s", fn);
1024                 failure_finish(NULL);
1025                 return (0);
1026         }
1027         s = (int)strlen(buff);
1028         contents = malloc(s * 2 + 128);
1029         n = (int)fread(contents, 1, s * 2 + 128 - 1, f);
1030         if (n >= 0)
1031                 contents[n] = '\0';
1032         fclose(f);
1033         /* Compare texts. */
1034         btxt = buff;
1035         ftxt = (const char *)contents;
1036         while (*btxt != '\0' && *ftxt != '\0') {
1037                 if (*btxt == *ftxt) {
1038                         ++btxt;
1039                         ++ftxt;
1040                         continue;
1041                 }
1042                 if (btxt[0] == '\n' && ftxt[0] == '\r' && ftxt[1] == '\n') {
1043                         /* Pass over different new line characters. */
1044                         ++btxt;
1045                         ftxt += 2;
1046                         continue;
1047                 }
1048                 break;
1049         }
1050         if (*btxt == '\0' && *ftxt == '\0') {
1051                 free(contents);
1052                 return (1);
1053         }
1054         failure_start(filename, line, "Contents don't match");
1055         logprintf("  file=\"%s\"\n", fn);
1056         if (n > 0) {
1057                 hexdump(contents, buff, n, 0);
1058                 logprintf("  expected\n", fn);
1059                 hexdump(buff, contents, s, 0);
1060         } else {
1061                 logprintf("  File empty, contents should be:\n");
1062                 hexdump(buff, NULL, s, 0);
1063         }
1064         failure_finish(NULL);
1065         free(contents);
1066         return (0);
1067 }
1068
1069 /* Verify that a text file contains the specified lines, regardless of order */
1070 /* This could be more efficient if we sorted both sets of lines, etc, but
1071  * since this is used only for testing and only ever deals with a dozen or so
1072  * lines at a time, this relatively crude approach is just fine. */
1073 int
1074 assertion_file_contains_lines_any_order(const char *file, int line,
1075     const char *pathname, const char *lines[])
1076 {
1077         char *buff;
1078         size_t buff_size;
1079         size_t expected_count, actual_count, i, j;
1080         char **expected = NULL;
1081         char *p, **actual = NULL;
1082         char c;
1083         int expected_failure = 0, actual_failure = 0;
1084
1085         assertion_count(file, line);
1086
1087         buff = slurpfile(&buff_size, "%s", pathname);
1088         if (buff == NULL) {
1089                 failure_start(pathname, line, "Can't read file: %s", pathname);
1090                 failure_finish(NULL);
1091                 return (0);
1092         }
1093
1094         /* Make a copy of the provided lines and count up the expected
1095          * file size. */
1096         for (i = 0; lines[i] != NULL; ++i) {
1097         }
1098         expected_count = i;
1099         if (expected_count) {
1100                 expected = malloc(sizeof(char *) * expected_count);
1101                 if (expected == NULL) {
1102                         failure_start(pathname, line, "Can't allocate memory");
1103                         failure_finish(NULL);
1104                         free(expected);
1105                         free(buff);
1106                         return (0);
1107                 }
1108                 for (i = 0; lines[i] != NULL; ++i) {
1109                         expected[i] = strdup(lines[i]);
1110                 }
1111         }
1112
1113         /* Break the file into lines */
1114         actual_count = 0;
1115         for (c = '\0', p = buff; p < buff + buff_size; ++p) {
1116                 if (*p == '\x0d' || *p == '\x0a')
1117                         *p = '\0';
1118                 if (c == '\0' && *p != '\0')
1119                         ++actual_count;
1120                 c = *p;
1121         }
1122         if (actual_count) {
1123                 actual = calloc(sizeof(char *), actual_count);
1124                 if (actual == NULL) {
1125                         failure_start(pathname, line, "Can't allocate memory");
1126                         failure_finish(NULL);
1127                         free(expected);
1128                         free(buff);
1129                         return (0);
1130                 }
1131                 for (j = 0, p = buff; p < buff + buff_size;
1132                     p += 1 + strlen(p)) {
1133                         if (*p != '\0') {
1134                                 actual[j] = p;
1135                                 ++j;
1136                         }
1137                 }
1138         }
1139
1140         /* Erase matching lines from both lists */
1141         for (i = 0; i < expected_count; ++i) {
1142                 if (expected[i] == NULL)
1143                         continue;
1144                 for (j = 0; j < actual_count; ++j) {
1145                         if (actual[j] == NULL)
1146                                 continue;
1147                         if (strcmp(expected[i], actual[j]) == 0) {
1148                                 free(expected[i]);
1149                                 expected[i] = NULL;
1150                                 actual[j] = NULL;
1151                                 break;
1152                         }
1153                 }
1154         }
1155
1156         /* If there's anything left, it's a failure */
1157         for (i = 0; i < expected_count; ++i) {
1158                 if (expected[i] != NULL)
1159                         ++expected_failure;
1160         }
1161         for (j = 0; j < actual_count; ++j) {
1162                 if (actual[j] != NULL)
1163                         ++actual_failure;
1164         }
1165         if (expected_failure == 0 && actual_failure == 0) {
1166                 free(buff);
1167                 free(expected);
1168                 free(actual);
1169                 return (1);
1170         }
1171         failure_start(file, line, "File doesn't match: %s", pathname);
1172         for (i = 0; i < expected_count; ++i) {
1173                 if (expected[i] != NULL) {
1174                         logprintf("  Expected but not present: %s\n", expected[i]);
1175                         free(expected[i]);
1176                 }
1177         }
1178         for (j = 0; j < actual_count; ++j) {
1179                 if (actual[j] != NULL)
1180                         logprintf("  Present but not expected: %s\n", actual[j]);
1181         }
1182         failure_finish(NULL);
1183         free(buff);
1184         free(expected);
1185         free(actual);
1186         return (0);
1187 }
1188
1189 /* Verify that a text file does not contains the specified strings */
1190 int
1191 assertion_file_contains_no_invalid_strings(const char *file, int line,
1192     const char *pathname, const char *strings[])
1193 {
1194         char *buff;
1195         int i;
1196
1197         buff = slurpfile(NULL, "%s", pathname);
1198         if (buff == NULL) {
1199                 failure_start(file, line, "Can't read file: %s", pathname);
1200                 failure_finish(NULL);
1201                 return (0);
1202         }
1203
1204         for (i = 0; strings[i] != NULL; ++i) {
1205                 if (strstr(buff, strings[i]) != NULL) {
1206                         failure_start(file, line, "Invalid string in %s: %s", pathname,
1207                             strings[i]);
1208                         failure_finish(NULL);
1209                         free(buff);
1210                         return(0);
1211                 }
1212         }
1213
1214         free(buff);
1215         return (0);
1216 }
1217
1218 /* Test that two paths point to the same file. */
1219 /* As a side-effect, asserts that both files exist. */
1220 static int
1221 is_hardlink(const char *file, int line,
1222     const char *path1, const char *path2)
1223 {
1224 #if defined(_WIN32) && !defined(__CYGWIN__)
1225         BY_HANDLE_FILE_INFORMATION bhfi1, bhfi2;
1226         int r;
1227
1228         assertion_count(file, line);
1229         r = my_GetFileInformationByName(path1, &bhfi1);
1230         if (r == 0) {
1231                 failure_start(file, line, "File %s can't be inspected?", path1);
1232                 failure_finish(NULL);
1233                 return (0);
1234         }
1235         r = my_GetFileInformationByName(path2, &bhfi2);
1236         if (r == 0) {
1237                 failure_start(file, line, "File %s can't be inspected?", path2);
1238                 failure_finish(NULL);
1239                 return (0);
1240         }
1241         return (bhfi1.dwVolumeSerialNumber == bhfi2.dwVolumeSerialNumber
1242                 && bhfi1.nFileIndexHigh == bhfi2.nFileIndexHigh
1243                 && bhfi1.nFileIndexLow == bhfi2.nFileIndexLow);
1244 #else
1245         struct stat st1, st2;
1246         int r;
1247
1248         assertion_count(file, line);
1249         r = lstat(path1, &st1);
1250         if (r != 0) {
1251                 failure_start(file, line, "File should exist: %s", path1);
1252                 failure_finish(NULL);
1253                 return (0);
1254         }
1255         r = lstat(path2, &st2);
1256         if (r != 0) {
1257                 failure_start(file, line, "File should exist: %s", path2);
1258                 failure_finish(NULL);
1259                 return (0);
1260         }
1261         return (st1.st_ino == st2.st_ino && st1.st_dev == st2.st_dev);
1262 #endif
1263 }
1264
1265 int
1266 assertion_is_hardlink(const char *file, int line,
1267     const char *path1, const char *path2)
1268 {
1269         if (is_hardlink(file, line, path1, path2))
1270                 return (1);
1271         failure_start(file, line,
1272             "Files %s and %s are not hardlinked", path1, path2);
1273         failure_finish(NULL);
1274         return (0);
1275 }
1276
1277 int
1278 assertion_is_not_hardlink(const char *file, int line,
1279     const char *path1, const char *path2)
1280 {
1281         if (!is_hardlink(file, line, path1, path2))
1282                 return (1);
1283         failure_start(file, line,
1284             "Files %s and %s should not be hardlinked", path1, path2);
1285         failure_finish(NULL);
1286         return (0);
1287 }
1288
1289 /* Verify a/b/mtime of 'pathname'. */
1290 /* If 'recent', verify that it's within last 10 seconds. */
1291 static int
1292 assertion_file_time(const char *file, int line,
1293     const char *pathname, long t, long nsec, char type, int recent)
1294 {
1295         long long filet, filet_nsec;
1296         int r;
1297
1298 #if defined(_WIN32) && !defined(__CYGWIN__)
1299 #define EPOC_TIME       (116444736000000000ULL)
1300         FILETIME fxtime, fbirthtime, fatime, fmtime;
1301         ULARGE_INTEGER wintm;
1302         HANDLE h;
1303         fxtime.dwLowDateTime = 0;
1304         fxtime.dwHighDateTime = 0;
1305
1306         assertion_count(file, line);
1307         /* Note: FILE_FLAG_BACKUP_SEMANTICS applies to open
1308          * a directory file. If not, CreateFile() will fail when
1309          * the pathname is a directory. */
1310         h = CreateFile(pathname, FILE_READ_ATTRIBUTES, 0, NULL,
1311             OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1312         if (h == INVALID_HANDLE_VALUE) {
1313                 failure_start(file, line, "Can't access %s\n", pathname);
1314                 failure_finish(NULL);
1315                 return (0);
1316         }
1317         r = GetFileTime(h, &fbirthtime, &fatime, &fmtime);
1318         switch (type) {
1319         case 'a': fxtime = fatime; break;
1320         case 'b': fxtime = fbirthtime; break;
1321         case 'm': fxtime = fmtime; break;
1322         }
1323         CloseHandle(h);
1324         if (r == 0) {
1325                 failure_start(file, line, "Can't GetFileTime %s\n", pathname);
1326                 failure_finish(NULL);
1327                 return (0);
1328         }
1329         wintm.LowPart = fxtime.dwLowDateTime;
1330         wintm.HighPart = fxtime.dwHighDateTime;
1331         filet = (wintm.QuadPart - EPOC_TIME) / 10000000;
1332         filet_nsec = ((wintm.QuadPart - EPOC_TIME) % 10000000) * 100;
1333         nsec = (nsec / 100) * 100; /* Round the request */
1334 #else
1335         struct stat st;
1336
1337         assertion_count(file, line);
1338         r = lstat(pathname, &st);
1339         if (r != 0) {
1340                 failure_start(file, line, "Can't stat %s\n", pathname);
1341                 failure_finish(NULL);
1342                 return (0);
1343         }
1344         switch (type) {
1345         case 'a': filet = st.st_atime; break;
1346         case 'm': filet = st.st_mtime; break;
1347         case 'b': filet = 0; break;
1348         default: fprintf(stderr, "INTERNAL: Bad type %c for file time", type);
1349                 exit(1);
1350         }
1351 #if defined(__FreeBSD__)
1352         switch (type) {
1353         case 'a': filet_nsec = st.st_atimespec.tv_nsec; break;
1354         case 'b': filet = st.st_birthtime;
1355                 /* FreeBSD filesystems that don't support birthtime
1356                  * (e.g., UFS1) always return -1 here. */
1357                 if (filet == -1) {
1358                         return (1);
1359                 }
1360                 filet_nsec = st.st_birthtimespec.tv_nsec; break;
1361         case 'm': filet_nsec = st.st_mtimespec.tv_nsec; break;
1362         default: fprintf(stderr, "INTERNAL: Bad type %c for file time", type);
1363                 exit(1);
1364         }
1365         /* FreeBSD generally only stores to microsecond res, so round. */
1366         filet_nsec = (filet_nsec / 1000) * 1000;
1367         nsec = (nsec / 1000) * 1000;
1368 #else
1369         filet_nsec = nsec = 0;  /* Generic POSIX only has whole seconds. */
1370         if (type == 'b') return (1); /* Generic POSIX doesn't have birthtime */
1371 #if defined(__HAIKU__)
1372         if (type == 'a') return (1); /* Haiku doesn't have atime. */
1373 #endif
1374 #endif
1375 #endif
1376         if (recent) {
1377                 /* Check that requested time is up-to-date. */
1378                 time_t now = time(NULL);
1379                 if (filet < now - 10 || filet > now + 1) {
1380                         failure_start(file, line,
1381                             "File %s has %ctime %lld, %lld seconds ago\n",
1382                             pathname, type, filet, now - filet);
1383                         failure_finish(NULL);
1384                         return (0);
1385                 }
1386         } else if (filet != t || filet_nsec != nsec) {
1387                 failure_start(file, line,
1388                     "File %s has %ctime %lld.%09lld, expected %lld.%09lld",
1389                     pathname, type, filet, filet_nsec, t, nsec);
1390                 failure_finish(NULL);
1391                 return (0);
1392         }
1393         return (1);
1394 }
1395
1396 /* Verify atime of 'pathname'. */
1397 int
1398 assertion_file_atime(const char *file, int line,
1399     const char *pathname, long t, long nsec)
1400 {
1401         return assertion_file_time(file, line, pathname, t, nsec, 'a', 0);
1402 }
1403
1404 /* Verify atime of 'pathname' is up-to-date. */
1405 int
1406 assertion_file_atime_recent(const char *file, int line, const char *pathname)
1407 {
1408         return assertion_file_time(file, line, pathname, 0, 0, 'a', 1);
1409 }
1410
1411 /* Verify birthtime of 'pathname'. */
1412 int
1413 assertion_file_birthtime(const char *file, int line,
1414     const char *pathname, long t, long nsec)
1415 {
1416         return assertion_file_time(file, line, pathname, t, nsec, 'b', 0);
1417 }
1418
1419 /* Verify birthtime of 'pathname' is up-to-date. */
1420 int
1421 assertion_file_birthtime_recent(const char *file, int line,
1422     const char *pathname)
1423 {
1424         return assertion_file_time(file, line, pathname, 0, 0, 'b', 1);
1425 }
1426
1427 /* Verify mode of 'pathname'. */
1428 int
1429 assertion_file_mode(const char *file, int line, const char *pathname, int expected_mode)
1430 {
1431         int mode;
1432         int r;
1433
1434         assertion_count(file, line);
1435 #if defined(_WIN32) && !defined(__CYGWIN__)
1436         failure_start(file, line, "assertFileMode not yet implemented for Windows");
1437         (void)mode; /* UNUSED */
1438         (void)r; /* UNUSED */
1439         (void)pathname; /* UNUSED */
1440         (void)expected_mode; /* UNUSED */
1441 #else
1442         {
1443                 struct stat st;
1444                 r = lstat(pathname, &st);
1445                 mode = (int)(st.st_mode & 0777);
1446         }
1447         if (r == 0 && mode == expected_mode)
1448                         return (1);
1449         failure_start(file, line, "File %s has mode %o, expected %o",
1450             pathname, mode, expected_mode);
1451 #endif
1452         failure_finish(NULL);
1453         return (0);
1454 }
1455
1456 /* Verify mtime of 'pathname'. */
1457 int
1458 assertion_file_mtime(const char *file, int line,
1459     const char *pathname, long t, long nsec)
1460 {
1461         return assertion_file_time(file, line, pathname, t, nsec, 'm', 0);
1462 }
1463
1464 /* Verify mtime of 'pathname' is up-to-date. */
1465 int
1466 assertion_file_mtime_recent(const char *file, int line, const char *pathname)
1467 {
1468         return assertion_file_time(file, line, pathname, 0, 0, 'm', 1);
1469 }
1470
1471 /* Verify number of links to 'pathname'. */
1472 int
1473 assertion_file_nlinks(const char *file, int line,
1474     const char *pathname, int nlinks)
1475 {
1476 #if defined(_WIN32) && !defined(__CYGWIN__)
1477         BY_HANDLE_FILE_INFORMATION bhfi;
1478         int r;
1479
1480         assertion_count(file, line);
1481         r = my_GetFileInformationByName(pathname, &bhfi);
1482         if (r != 0 && bhfi.nNumberOfLinks == (DWORD)nlinks)
1483                 return (1);
1484         failure_start(file, line, "File %s has %d links, expected %d",
1485             pathname, bhfi.nNumberOfLinks, nlinks);
1486         failure_finish(NULL);
1487         return (0);
1488 #else
1489         struct stat st;
1490         int r;
1491
1492         assertion_count(file, line);
1493         r = lstat(pathname, &st);
1494         if (r == 0 && (int)st.st_nlink == nlinks)
1495                 return (1);
1496         failure_start(file, line, "File %s has %d links, expected %d",
1497             pathname, st.st_nlink, nlinks);
1498         failure_finish(NULL);
1499         return (0);
1500 #endif
1501 }
1502
1503 /* Verify size of 'pathname'. */
1504 int
1505 assertion_file_size(const char *file, int line, const char *pathname, long size)
1506 {
1507         int64_t filesize;
1508         int r;
1509
1510         assertion_count(file, line);
1511 #if defined(_WIN32) && !defined(__CYGWIN__)
1512         {
1513                 BY_HANDLE_FILE_INFORMATION bhfi;
1514                 r = !my_GetFileInformationByName(pathname, &bhfi);
1515                 filesize = ((int64_t)bhfi.nFileSizeHigh << 32) + bhfi.nFileSizeLow;
1516         }
1517 #else
1518         {
1519                 struct stat st;
1520                 r = lstat(pathname, &st);
1521                 filesize = st.st_size;
1522         }
1523 #endif
1524         if (r == 0 && filesize == size)
1525                         return (1);
1526         failure_start(file, line, "File %s has size %ld, expected %ld",
1527             pathname, (long)filesize, (long)size);
1528         failure_finish(NULL);
1529         return (0);
1530 }
1531
1532 /* Assert that 'pathname' is a dir.  If mode >= 0, verify that too. */
1533 int
1534 assertion_is_dir(const char *file, int line, const char *pathname, int mode)
1535 {
1536         struct stat st;
1537         int r;
1538
1539 #if defined(_WIN32) && !defined(__CYGWIN__)
1540         (void)mode; /* UNUSED */
1541 #endif
1542         assertion_count(file, line);
1543         r = lstat(pathname, &st);
1544         if (r != 0) {
1545                 failure_start(file, line, "Dir should exist: %s", pathname);
1546                 failure_finish(NULL);
1547                 return (0);
1548         }
1549         if (!S_ISDIR(st.st_mode)) {
1550                 failure_start(file, line, "%s is not a dir", pathname);
1551                 failure_finish(NULL);
1552                 return (0);
1553         }
1554 #if !defined(_WIN32) || defined(__CYGWIN__)
1555         /* Windows doesn't handle permissions the same way as POSIX,
1556          * so just ignore the mode tests. */
1557         /* TODO: Can we do better here? */
1558         if (mode >= 0 && (mode_t)mode != (st.st_mode & 07777)) {
1559                 failure_start(file, line, "Dir %s has wrong mode", pathname);
1560                 logprintf("  Expected: 0%3o\n", mode);
1561                 logprintf("  Found: 0%3o\n", st.st_mode & 07777);
1562                 failure_finish(NULL);
1563                 return (0);
1564         }
1565 #endif
1566         return (1);
1567 }
1568
1569 /* Verify that 'pathname' is a regular file.  If 'mode' is >= 0,
1570  * verify that too. */
1571 int
1572 assertion_is_reg(const char *file, int line, const char *pathname, int mode)
1573 {
1574         struct stat st;
1575         int r;
1576
1577 #if defined(_WIN32) && !defined(__CYGWIN__)
1578         (void)mode; /* UNUSED */
1579 #endif
1580         assertion_count(file, line);
1581         r = lstat(pathname, &st);
1582         if (r != 0 || !S_ISREG(st.st_mode)) {
1583                 failure_start(file, line, "File should exist: %s", pathname);
1584                 failure_finish(NULL);
1585                 return (0);
1586         }
1587 #if !defined(_WIN32) || defined(__CYGWIN__)
1588         /* Windows doesn't handle permissions the same way as POSIX,
1589          * so just ignore the mode tests. */
1590         /* TODO: Can we do better here? */
1591         if (mode >= 0 && (mode_t)mode != (st.st_mode & 07777)) {
1592                 failure_start(file, line, "File %s has wrong mode", pathname);
1593                 logprintf("  Expected: 0%3o\n", mode);
1594                 logprintf("  Found: 0%3o\n", st.st_mode & 07777);
1595                 failure_finish(NULL);
1596                 return (0);
1597         }
1598 #endif
1599         return (1);
1600 }
1601
1602 /* Check whether 'pathname' is a symbolic link.  If 'contents' is
1603  * non-NULL, verify that the symlink has those contents. */
1604 static int
1605 is_symlink(const char *file, int line,
1606     const char *pathname, const char *contents)
1607 {
1608 #if defined(_WIN32) && !defined(__CYGWIN__)
1609         (void)pathname; /* UNUSED */
1610         (void)contents; /* UNUSED */
1611         assertion_count(file, line);
1612         /* Windows sort-of has real symlinks, but they're only usable
1613          * by privileged users and are crippled even then, so there's
1614          * really not much point in bothering with this. */
1615         return (0);
1616 #else
1617         char buff[300];
1618         struct stat st;
1619         ssize_t linklen;
1620         int r;
1621
1622         assertion_count(file, line);
1623         r = lstat(pathname, &st);
1624         if (r != 0) {
1625                 failure_start(file, line,
1626                     "Symlink should exist: %s", pathname);
1627                 failure_finish(NULL);
1628                 return (0);
1629         }
1630         if (!S_ISLNK(st.st_mode))
1631                 return (0);
1632         if (contents == NULL)
1633                 return (1);
1634         linklen = readlink(pathname, buff, sizeof(buff));
1635         if (linklen < 0) {
1636                 failure_start(file, line, "Can't read symlink %s", pathname);
1637                 failure_finish(NULL);
1638                 return (0);
1639         }
1640         buff[linklen] = '\0';
1641         if (strcmp(buff, contents) != 0)
1642                 return (0);
1643         return (1);
1644 #endif
1645 }
1646
1647 /* Assert that path is a symlink that (optionally) contains contents. */
1648 int
1649 assertion_is_symlink(const char *file, int line,
1650     const char *path, const char *contents)
1651 {
1652         if (is_symlink(file, line, path, contents))
1653                 return (1);
1654         if (contents)
1655                 failure_start(file, line, "File %s is not a symlink to %s",
1656                     path, contents);
1657         else
1658                 failure_start(file, line, "File %s is not a symlink", path);
1659         failure_finish(NULL);
1660         return (0);
1661 }
1662
1663
1664 /* Create a directory and report any errors. */
1665 int
1666 assertion_make_dir(const char *file, int line, const char *dirname, int mode)
1667 {
1668         assertion_count(file, line);
1669 #if defined(_WIN32) && !defined(__CYGWIN__)
1670         (void)mode; /* UNUSED */
1671         if (0 == _mkdir(dirname))
1672                 return (1);
1673 #else
1674         if (0 == mkdir(dirname, mode)) {
1675                 if (0 == chmod(dirname, mode)) {
1676                         assertion_file_mode(file, line, dirname, mode);
1677                         return (1);
1678                 }
1679         }
1680 #endif
1681         failure_start(file, line, "Could not create directory %s", dirname);
1682         failure_finish(NULL);
1683         return(0);
1684 }
1685
1686 /* Create a file with the specified contents and report any failures. */
1687 int
1688 assertion_make_file(const char *file, int line,
1689     const char *path, int mode, int csize, const void *contents)
1690 {
1691 #if defined(_WIN32) && !defined(__CYGWIN__)
1692         /* TODO: Rework this to set file mode as well. */
1693         FILE *f;
1694         (void)mode; /* UNUSED */
1695         assertion_count(file, line);
1696         f = fopen(path, "wb");
1697         if (f == NULL) {
1698                 failure_start(file, line, "Could not create file %s", path);
1699                 failure_finish(NULL);
1700                 return (0);
1701         }
1702         if (contents != NULL) {
1703                 size_t wsize;
1704
1705                 if (csize < 0)
1706                         wsize = strlen(contents);
1707                 else
1708                         wsize = (size_t)csize;
1709                 if (wsize != fwrite(contents, 1, wsize, f)) {
1710                         fclose(f);
1711                         failure_start(file, line,
1712                             "Could not write file %s", path);
1713                         failure_finish(NULL);
1714                         return (0);
1715                 }
1716         }
1717         fclose(f);
1718         return (1);
1719 #else
1720         int fd;
1721         assertion_count(file, line);
1722         fd = open(path, O_CREAT | O_WRONLY, mode >= 0 ? mode : 0644);
1723         if (fd < 0) {
1724                 failure_start(file, line, "Could not create %s", path);
1725                 failure_finish(NULL);
1726                 return (0);
1727         }
1728         if (0 != chmod(path, mode)) {
1729                 failure_start(file, line, "Could not chmod %s", path);
1730                 failure_finish(NULL);
1731                 close(fd);
1732                 return (0);
1733         }
1734         if (contents != NULL) {
1735                 ssize_t wsize;
1736
1737                 if (csize < 0)
1738                         wsize = (ssize_t)strlen(contents);
1739                 else
1740                         wsize = (ssize_t)csize;
1741                 if (wsize != write(fd, contents, wsize)) {
1742                         close(fd);
1743                         failure_start(file, line,
1744                             "Could not write to %s", path);
1745                         failure_finish(NULL);
1746                         close(fd);
1747                         return (0);
1748                 }
1749         }
1750         close(fd);
1751         assertion_file_mode(file, line, path, mode);
1752         return (1);
1753 #endif
1754 }
1755
1756 /* Create a hardlink and report any failures. */
1757 int
1758 assertion_make_hardlink(const char *file, int line,
1759     const char *newpath, const char *linkto)
1760 {
1761         int succeeded;
1762
1763         assertion_count(file, line);
1764 #if defined(_WIN32) && !defined(__CYGWIN__)
1765         succeeded = my_CreateHardLinkA(newpath, linkto);
1766 #elif HAVE_LINK
1767         succeeded = !link(linkto, newpath);
1768 #else
1769         succeeded = 0;
1770 #endif
1771         if (succeeded)
1772                 return (1);
1773         failure_start(file, line, "Could not create hardlink");
1774         logprintf("   New link: %s\n", newpath);
1775         logprintf("   Old name: %s\n", linkto);
1776         failure_finish(NULL);
1777         return(0);
1778 }
1779
1780 /* Create a symlink and report any failures. */
1781 int
1782 assertion_make_symlink(const char *file, int line,
1783     const char *newpath, const char *linkto)
1784 {
1785 #if defined(_WIN32) && !defined(__CYGWIN__)
1786         int targetIsDir = 0;  /* TODO: Fix this */
1787         assertion_count(file, line);
1788         if (my_CreateSymbolicLinkA(newpath, linkto, targetIsDir))
1789                 return (1);
1790 #elif HAVE_SYMLINK
1791         assertion_count(file, line);
1792         if (0 == symlink(linkto, newpath))
1793                 return (1);
1794 #endif
1795         failure_start(file, line, "Could not create symlink");
1796         logprintf("   New link: %s\n", newpath);
1797         logprintf("   Old name: %s\n", linkto);
1798         failure_finish(NULL);
1799         return(0);
1800 }
1801
1802 /* Set umask, report failures. */
1803 int
1804 assertion_umask(const char *file, int line, int mask)
1805 {
1806         assertion_count(file, line);
1807         (void)file; /* UNUSED */
1808         (void)line; /* UNUSED */
1809         umask(mask);
1810         return (1);
1811 }
1812
1813 /* Set times, report failures. */
1814 int
1815 assertion_utimes(const char *file, int line,
1816     const char *pathname, long at, long at_nsec, long mt, long mt_nsec)
1817 {
1818         int r;
1819
1820 #if defined(_WIN32) && !defined(__CYGWIN__)
1821 #define WINTIME(sec, nsec) ((Int32x32To64(sec, 10000000) + EPOC_TIME)\
1822          + (((nsec)/1000)*10))
1823         HANDLE h;
1824         ULARGE_INTEGER wintm;
1825         FILETIME fatime, fmtime;
1826         FILETIME *pat, *pmt;
1827
1828         assertion_count(file, line);
1829         h = CreateFileA(pathname,GENERIC_READ | GENERIC_WRITE,
1830                     FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
1831                     FILE_FLAG_BACKUP_SEMANTICS, NULL);
1832         if (h == INVALID_HANDLE_VALUE) {
1833                 failure_start(file, line, "Can't access %s\n", pathname);
1834                 failure_finish(NULL);
1835                 return (0);
1836         }
1837
1838         if (at > 0 || at_nsec > 0) {
1839                 wintm.QuadPart = WINTIME(at, at_nsec);
1840                 fatime.dwLowDateTime = wintm.LowPart;
1841                 fatime.dwHighDateTime = wintm.HighPart;
1842                 pat = &fatime;
1843         } else
1844                 pat = NULL;
1845         if (mt > 0 || mt_nsec > 0) {
1846                 wintm.QuadPart = WINTIME(mt, mt_nsec);
1847                 fmtime.dwLowDateTime = wintm.LowPart;
1848                 fmtime.dwHighDateTime = wintm.HighPart;
1849                 pmt = &fmtime;
1850         } else
1851                 pmt = NULL;
1852         if (pat != NULL || pmt != NULL)
1853                 r = SetFileTime(h, NULL, pat, pmt);
1854         else
1855                 r = 1;
1856         CloseHandle(h);
1857         if (r == 0) {
1858                 failure_start(file, line, "Can't SetFileTime %s\n", pathname);
1859                 failure_finish(NULL);
1860                 return (0);
1861         }
1862         return (1);
1863 #else /* defined(_WIN32) && !defined(__CYGWIN__) */
1864         struct stat st;
1865         struct timeval times[2];
1866
1867 #if !defined(__FreeBSD__)
1868         mt_nsec = at_nsec = 0;  /* Generic POSIX only has whole seconds. */
1869 #endif
1870         if (mt == 0 && mt_nsec == 0 && at == 0 && at_nsec == 0)
1871                 return (1);
1872
1873         r = lstat(pathname, &st);
1874         if (r < 0) {
1875                 failure_start(file, line, "Can't stat %s\n", pathname);
1876                 failure_finish(NULL);
1877                 return (0);
1878         }
1879
1880         if (mt == 0 && mt_nsec == 0) {
1881                 mt = st.st_mtime;
1882 #if defined(__FreeBSD__)
1883                 mt_nsec = st.st_mtimespec.tv_nsec;
1884                 /* FreeBSD generally only stores to microsecond res, so round. */
1885                 mt_nsec = (mt_nsec / 1000) * 1000;
1886 #endif
1887         }
1888         if (at == 0 && at_nsec == 0) {
1889                 at = st.st_atime;
1890 #if defined(__FreeBSD__)
1891                 at_nsec = st.st_atimespec.tv_nsec;
1892                 /* FreeBSD generally only stores to microsecond res, so round. */
1893                 at_nsec = (at_nsec / 1000) * 1000;
1894 #endif
1895         }
1896
1897         times[1].tv_sec = mt;
1898         times[1].tv_usec = mt_nsec / 1000;
1899
1900         times[0].tv_sec = at;
1901         times[0].tv_usec = at_nsec / 1000;
1902
1903 #ifdef HAVE_LUTIMES
1904         r = lutimes(pathname, times);
1905 #else
1906         r = utimes(pathname, times);
1907 #endif
1908         if (r < 0) {
1909                 failure_start(file, line, "Can't utimes %s\n", pathname);
1910                 failure_finish(NULL);
1911                 return (0);
1912         }
1913         return (1);
1914 #endif /* defined(_WIN32) && !defined(__CYGWIN__) */
1915 }
1916
1917 /* Compare file flags */
1918 int
1919 assertion_compare_fflags(const char *file, int line, const char *patha,
1920     const char *pathb, int nomatch)
1921 {
1922 #if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP)
1923         struct stat sa, sb;
1924
1925         assertion_count(file, line);
1926
1927         if (stat(patha, &sa) < 0)
1928                 return (0);
1929         if (stat(pathb, &sb) < 0)
1930                 return (0);
1931         if (!nomatch && sa.st_flags != sb.st_flags) {
1932                 failure_start(file, line, "File flags should be identical: "
1933                     "%s=%#010x %s=%#010x", patha, sa.st_flags, pathb,
1934                     sb.st_flags);
1935                 failure_finish(NULL);
1936                 return (0);
1937         }
1938         if (nomatch && sa.st_flags == sb.st_flags) {
1939                 failure_start(file, line, "File flags should be different: "
1940                     "%s=%#010x %s=%#010x", patha, sa.st_flags, pathb,
1941                     sb.st_flags);
1942                 failure_finish(NULL);
1943                 return (0);
1944         }
1945 #elif (defined(FS_IOC_GETFLAGS) && defined(HAVE_WORKING_FS_IOC_GETFLAGS) && \
1946        defined(FS_NODUMP_FL)) || \
1947       (defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS) \
1948          && defined(EXT2_NODUMP_FL))
1949         int fd, r, flagsa, flagsb;
1950
1951         assertion_count(file, line);
1952         fd = open(patha, O_RDONLY | O_NONBLOCK);
1953         if (fd < 0) {
1954                 failure_start(file, line, "Can't open %s\n", patha);
1955                 failure_finish(NULL);
1956                 return (0);
1957         }
1958         r = ioctl(fd,
1959 #ifdef FS_IOC_GETFLAGS
1960             FS_IOC_GETFLAGS,
1961 #else
1962             EXT2_IOC_GETFLAGS,
1963 #endif
1964             &flagsa);
1965         close(fd);
1966         if (r < 0) {
1967                 failure_start(file, line, "Can't get flags %s\n", patha);
1968                 failure_finish(NULL);
1969                 return (0);
1970         }
1971         fd = open(pathb, O_RDONLY | O_NONBLOCK);
1972         if (fd < 0) {
1973                 failure_start(file, line, "Can't open %s\n", pathb);
1974                 failure_finish(NULL);
1975                 return (0);
1976         }
1977         r = ioctl(fd,
1978 #ifdef FS_IOC_GETFLAGS
1979             FS_IOC_GETFLAGS,
1980 #else
1981             EXT2_IOC_GETFLAGS,
1982 #endif
1983             &flagsb);
1984         close(fd);
1985         if (r < 0) {
1986                 failure_start(file, line, "Can't get flags %s\n", pathb);
1987                 failure_finish(NULL);
1988                 return (0);
1989         }
1990         if (!nomatch && flagsa != flagsb) {
1991                 failure_start(file, line, "File flags should be identical: "
1992                     "%s=%#010x %s=%#010x", patha, flagsa, pathb, flagsb);
1993                 failure_finish(NULL);
1994                 return (0);
1995         }
1996         if (nomatch && flagsa == flagsb) {
1997                 failure_start(file, line, "File flags should be different: "
1998                     "%s=%#010x %s=%#010x", patha, flagsa, pathb, flagsb);
1999                 failure_finish(NULL);
2000                 return (0);
2001         }
2002 #else
2003         (void)patha; /* UNUSED */
2004         (void)pathb; /* UNUSED */
2005         (void)nomatch; /* UNUSED */
2006         assertion_count(file, line);
2007 #endif
2008         return (1);
2009 }
2010
2011 /* Set nodump, report failures. */
2012 int
2013 assertion_set_nodump(const char *file, int line, const char *pathname)
2014 {
2015 #if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP)
2016         int r;
2017
2018         assertion_count(file, line);
2019         r = chflags(pathname, UF_NODUMP);
2020         if (r < 0) {
2021                 failure_start(file, line, "Can't set nodump %s\n", pathname);
2022                 failure_finish(NULL);
2023                 return (0);
2024         }
2025 #elif (defined(FS_IOC_GETFLAGS) && defined(HAVE_WORKING_FS_IOC_GETFLAGS) && \
2026        defined(FS_NODUMP_FL)) || \
2027       (defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS) \
2028          && defined(EXT2_NODUMP_FL))
2029         int fd, r, flags;
2030
2031         assertion_count(file, line);
2032         fd = open(pathname, O_RDONLY | O_NONBLOCK);
2033         if (fd < 0) {
2034                 failure_start(file, line, "Can't open %s\n", pathname);
2035                 failure_finish(NULL);
2036                 return (0);
2037         }
2038         r = ioctl(fd,
2039 #ifdef FS_IOC_GETFLAGS
2040             FS_IOC_GETFLAGS,
2041 #else
2042             EXT2_IOC_GETFLAGS,
2043 #endif
2044             &flags);
2045         if (r < 0) {
2046                 failure_start(file, line, "Can't get flags %s\n", pathname);
2047                 failure_finish(NULL);
2048                 return (0);
2049         }
2050 #ifdef FS_NODUMP_FL
2051         flags |= FS_NODUMP_FL;
2052 #else
2053         flags |= EXT2_NODUMP_FL;
2054 #endif
2055
2056          r = ioctl(fd,
2057 #ifdef FS_IOC_SETFLAGS
2058             FS_IOC_SETFLAGS,
2059 #else
2060             EXT2_IOC_SETFLAGS,
2061 #endif
2062             &flags);
2063         if (r < 0) {
2064                 failure_start(file, line, "Can't set nodump %s\n", pathname);
2065                 failure_finish(NULL);
2066                 return (0);
2067         }
2068         close(fd);
2069 #else
2070         (void)pathname; /* UNUSED */
2071         assertion_count(file, line);
2072 #endif
2073         return (1);
2074 }
2075
2076 #ifdef PROGRAM
2077 static void assert_version_id(char **qq, size_t *ss)
2078 {
2079         char *q = *qq;
2080         size_t s = *ss;
2081
2082         /* Version number is a series of digits and periods. */
2083         while (s > 0 && (*q == '.' || (*q >= '0' && *q <= '9'))) {
2084                 ++q;
2085                 --s;
2086         }
2087
2088         if (q[0] == 'd' && q[1] == 'e' && q[2] == 'v') {
2089                 q += 3;
2090                 s -= 3;
2091         }
2092         
2093         /* Skip a single trailing a,b,c, or d. */
2094         if (*q == 'a' || *q == 'b' || *q == 'c' || *q == 'd')
2095                 ++q;
2096
2097         /* Version number terminated by space. */
2098         failure("No space after version: ``%s''", q);
2099         assert(s > 1);
2100         failure("No space after version: ``%s''", q);
2101         assert(*q == ' ');
2102
2103         ++q; --s;
2104
2105         *qq = q;
2106         *ss = s;
2107 }
2108
2109
2110 /*
2111  * Check program version
2112  */
2113 void assertVersion(const char *prog, const char *base)
2114 {
2115         int r;
2116         char *p, *q;
2117         size_t s;
2118         unsigned int prog_len = strlen(base);
2119
2120         r = systemf("%s --version >version.stdout 2>version.stderr", prog);
2121         if (r != 0)
2122                 r = systemf("%s -W version >version.stdout 2>version.stderr",
2123                     prog);
2124
2125         failure("Unable to run either %s --version or %s -W version",
2126                 prog, prog);
2127         if (!assert(r == 0))
2128                 return;
2129
2130         /* --version should generate nothing to stdout. */
2131         assertEmptyFile("version.stderr");
2132
2133         /* Verify format of version message. */
2134         q = p = slurpfile(&s, "version.stdout");
2135
2136         /* Version message should start with name of program, then space. */
2137         assert(s > prog_len + 1);
2138         
2139         failure("Version must start with '%s': ``%s''", base, p);
2140         if (!assertEqualMem(q, base, prog_len)) {
2141                 free(p);
2142                 return;
2143         }
2144
2145         q += prog_len; s -= prog_len;
2146
2147         assert(*q == ' ');
2148         q++; s--;
2149
2150         assert_version_id(&q, &s);
2151
2152         /* Separator. */
2153         failure("No `-' between program name and versions: ``%s''", p);
2154         assertEqualMem(q, "- ", 2);
2155         q += 2; s -= 2;
2156
2157         failure("Not long enough for libarchive version: ``%s''", p);
2158         assert(s > 11);
2159
2160         failure("Libarchive version must start with `libarchive': ``%s''", p);
2161         assertEqualMem(q, "libarchive ", 11);
2162
2163         q += 11; s -= 11;
2164
2165         assert_version_id(&q, &s);
2166
2167         /* Skip arbitrary third-party version numbers. */
2168         while (s > 0 && (*q == ' ' || *q == '-' || *q == '/' || *q == '.' ||
2169             isalnum(*q))) {
2170                 ++q;
2171                 --s;
2172         }
2173
2174         /* All terminated by end-of-line. */
2175         assert(s >= 1);
2176
2177         /* Skip an optional CR character (e.g., Windows) */
2178         failure("Version output must end with \\n or \\r\\n");
2179
2180         if (*q == '\r') { ++q; --s; }
2181         assertEqualMem(q, "\n", 1);
2182
2183         free(p);
2184 }
2185 #endif  /* PROGRAM */
2186
2187 /*
2188  *
2189  *  UTILITIES for use by tests.
2190  *
2191  */
2192
2193 /*
2194  * Check whether platform supports symlinks.  This is intended
2195  * for tests to use in deciding whether to bother testing symlink
2196  * support; if the platform doesn't support symlinks, there's no point
2197  * in checking whether the program being tested can create them.
2198  *
2199  * Note that the first time this test is called, we actually go out to
2200  * disk to create and verify a symlink.  This is necessary because
2201  * symlink support is actually a property of a particular filesystem
2202  * and can thus vary between directories on a single system.  After
2203  * the first call, this returns the cached result from memory, so it's
2204  * safe to call it as often as you wish.
2205  */
2206 int
2207 canSymlink(void)
2208 {
2209         /* Remember the test result */
2210         static int value = 0, tested = 0;
2211         if (tested)
2212                 return (value);
2213
2214         ++tested;
2215         assertion_make_file(__FILE__, __LINE__, "canSymlink.0", 0644, 1, "a");
2216         /* Note: Cygwin has its own symlink() emulation that does not
2217          * use the Win32 CreateSymbolicLink() function. */
2218 #if defined(_WIN32) && !defined(__CYGWIN__)
2219         value = my_CreateSymbolicLinkA("canSymlink.1", "canSymlink.0", 0)
2220             && is_symlink(__FILE__, __LINE__, "canSymlink.1", "canSymlink.0");
2221 #elif HAVE_SYMLINK
2222         value = (0 == symlink("canSymlink.0", "canSymlink.1"))
2223             && is_symlink(__FILE__, __LINE__, "canSymlink.1","canSymlink.0");
2224 #endif
2225         return (value);
2226 }
2227
2228 /* Platform-dependent options for hiding the output of a subcommand. */
2229 #if defined(_WIN32) && !defined(__CYGWIN__)
2230 static const char *redirectArgs = ">NUL 2>NUL"; /* Win32 cmd.exe */
2231 #else
2232 static const char *redirectArgs = ">/dev/null 2>/dev/null"; /* POSIX 'sh' */
2233 #endif
2234 /*
2235  * Can this platform run the bzip2 program?
2236  */
2237 int
2238 canBzip2(void)
2239 {
2240         static int tested = 0, value = 0;
2241         if (!tested) {
2242                 tested = 1;
2243                 if (systemf("bzip2 -d -V %s", redirectArgs) == 0)
2244                         value = 1;
2245         }
2246         return (value);
2247 }
2248
2249 /*
2250  * Can this platform run the grzip program?
2251  */
2252 int
2253 canGrzip(void)
2254 {
2255         static int tested = 0, value = 0;
2256         if (!tested) {
2257                 tested = 1;
2258                 if (systemf("grzip -V %s", redirectArgs) == 0)
2259                         value = 1;
2260         }
2261         return (value);
2262 }
2263
2264 /*
2265  * Can this platform run the gzip program?
2266  */
2267 int
2268 canGzip(void)
2269 {
2270         static int tested = 0, value = 0;
2271         if (!tested) {
2272                 tested = 1;
2273                 if (systemf("gzip -V %s", redirectArgs) == 0)
2274                         value = 1;
2275         }
2276         return (value);
2277 }
2278
2279 /*
2280  * Can this platform run the lrzip program?
2281  */
2282 int
2283 canRunCommand(const char *cmd)
2284 {
2285   static int tested = 0, value = 0;
2286   if (!tested) {
2287     tested = 1;
2288     if (systemf("%s %s", cmd, redirectArgs) == 0)
2289       value = 1;
2290   }
2291   return (value);
2292 }
2293
2294 int
2295 canLrzip(void)
2296 {
2297         static int tested = 0, value = 0;
2298         if (!tested) {
2299                 tested = 1;
2300                 if (systemf("lrzip -V %s", redirectArgs) == 0)
2301                         value = 1;
2302         }
2303         return (value);
2304 }
2305
2306 /*
2307  * Can this platform run the lz4 program?
2308  */
2309 int
2310 canLz4(void)
2311 {
2312         static int tested = 0, value = 0;
2313         if (!tested) {
2314                 tested = 1;
2315                 if (systemf("lz4 -V %s", redirectArgs) == 0)
2316                         value = 1;
2317         }
2318         return (value);
2319 }
2320
2321 /*
2322  * Can this platform run the zstd program?
2323  */
2324 int
2325 canZstd(void)
2326 {
2327         static int tested = 0, value = 0;
2328         if (!tested) {
2329                 tested = 1;
2330                 if (systemf("zstd -V %s", redirectArgs) == 0)
2331                         value = 1;
2332         }
2333         return (value);
2334 }
2335
2336 /*
2337  * Can this platform run the lzip program?
2338  */
2339 int
2340 canLzip(void)
2341 {
2342         static int tested = 0, value = 0;
2343         if (!tested) {
2344                 tested = 1;
2345                 if (systemf("lzip -V %s", redirectArgs) == 0)
2346                         value = 1;
2347         }
2348         return (value);
2349 }
2350
2351 /*
2352  * Can this platform run the lzma program?
2353  */
2354 int
2355 canLzma(void)
2356 {
2357         static int tested = 0, value = 0;
2358         if (!tested) {
2359                 tested = 1;
2360                 if (systemf("lzma -V %s", redirectArgs) == 0)
2361                         value = 1;
2362         }
2363         return (value);
2364 }
2365
2366 /*
2367  * Can this platform run the lzop program?
2368  */
2369 int
2370 canLzop(void)
2371 {
2372         static int tested = 0, value = 0;
2373         if (!tested) {
2374                 tested = 1;
2375                 if (systemf("lzop -V %s", redirectArgs) == 0)
2376                         value = 1;
2377         }
2378         return (value);
2379 }
2380
2381 /*
2382  * Can this platform run the xz program?
2383  */
2384 int
2385 canXz(void)
2386 {
2387         static int tested = 0, value = 0;
2388         if (!tested) {
2389                 tested = 1;
2390                 if (systemf("xz -V %s", redirectArgs) == 0)
2391                         value = 1;
2392         }
2393         return (value);
2394 }
2395
2396 /*
2397  * Can this filesystem handle nodump flags.
2398  */
2399 int
2400 canNodump(void)
2401 {
2402 #if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP)
2403         const char *path = "cannodumptest";
2404         struct stat sb;
2405
2406         assertion_make_file(__FILE__, __LINE__, path, 0644, 0, NULL);
2407         if (chflags(path, UF_NODUMP) < 0)
2408                 return (0);
2409         if (stat(path, &sb) < 0)
2410                 return (0);
2411         if (sb.st_flags & UF_NODUMP)
2412                 return (1);
2413 #elif (defined(FS_IOC_GETFLAGS) && defined(HAVE_WORKING_FS_IOC_GETFLAGS) \
2414          && defined(FS_NODUMP_FL)) || \
2415       (defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS) \
2416          && defined(EXT2_NODUMP_FL))
2417         const char *path = "cannodumptest";
2418         int fd, r, flags;
2419
2420         assertion_make_file(__FILE__, __LINE__, path, 0644, 0, NULL);
2421         fd = open(path, O_RDONLY | O_NONBLOCK);
2422         if (fd < 0)
2423                 return (0);
2424         r = ioctl(fd,
2425 #ifdef FS_IOC_GETFLAGS
2426             FS_IOC_GETFLAGS,
2427 #else
2428             EXT2_IOC_GETFLAGS,
2429 #endif
2430             &flags);
2431         if (r < 0)
2432                 return (0);
2433 #ifdef FS_NODUMP_FL
2434         flags |= FS_NODUMP_FL;
2435 #else
2436         flags |= EXT2_NODUMP_FL;
2437 #endif
2438         r = ioctl(fd,
2439 #ifdef FS_IOC_SETFLAGS
2440             FS_IOC_SETFLAGS,
2441 #else
2442             EXT2_IOC_SETFLAGS,
2443 #endif
2444            &flags);
2445         if (r < 0)
2446                 return (0);
2447         close(fd);
2448         fd = open(path, O_RDONLY | O_NONBLOCK);
2449         if (fd < 0)
2450                 return (0);
2451         r = ioctl(fd,
2452 #ifdef FS_IOC_GETFLAGS
2453             FS_IOC_GETFLAGS,
2454 #else
2455             EXT2_IOC_GETFLAGS,
2456 #endif
2457             &flags);
2458         if (r < 0)
2459                 return (0);
2460         close(fd);
2461 #ifdef FS_NODUMP_FL
2462         if (flags & FS_NODUMP_FL)
2463 #else
2464         if (flags & EXT2_NODUMP_FL)
2465 #endif
2466                 return (1);
2467 #endif
2468         return (0);
2469 }
2470
2471 /* Get extended attribute from a path */
2472 const void *
2473 getXattr(const char *path, const char *name, size_t *sizep)
2474
2475         void *value = NULL;
2476 #if ARCHIVE_XATTR_SUPPORT
2477         ssize_t size;
2478 #if ARCHIVE_XATTR_LINUX
2479         size = lgetxattr(path, name, NULL, 0);
2480 #elif ARCHIVE_XATTR_DARWIN
2481         size = getxattr(path, name, NULL, 0, 0, XATTR_NOFOLLOW);
2482 #elif ARCHIVE_XATTR_AIX
2483         size = lgetea(path, name, NULL, 0);
2484 #elif ARCHIVE_XATTR_FREEBSD
2485         size = extattr_get_link(path, EXTATTR_NAMESPACE_USER, name + 5,
2486             NULL, 0);
2487 #endif
2488
2489         if (size >= 0) {
2490                 value = malloc(size);
2491 #if ARCHIVE_XATTR_LINUX
2492                 size = lgetxattr(path, name, value, size);
2493 #elif ARCHIVE_XATTR_DARWIN
2494                 size = getxattr(path, name, value, size, 0, XATTR_NOFOLLOW);
2495 #elif ARCHIVE_XATTR_AIX
2496                 size = lgetea(path, name, value, size);
2497 #elif ARCHIVE_XATTR_FREEBSD
2498                 size = extattr_get_link(path, EXTATTR_NAMESPACE_USER, name + 5,
2499                     value, size);
2500 #endif
2501                 if (size < 0) {
2502                         free(value);
2503                         value = NULL;
2504                 }
2505         }
2506         if (size < 0)
2507                 *sizep = 0;
2508         else
2509                 *sizep = (size_t)size;
2510 #else   /* !ARCHIVE_XATTR_SUPPORT */
2511         (void)path;     /* UNUSED */
2512         (void)name;     /* UNUSED */
2513         *sizep = 0;
2514 #endif  /* !ARCHIVE_XATTR_SUPPORT */
2515         return (value);
2516 }
2517
2518 /*
2519  * Set extended attribute on a path
2520  * Returns 0 on error, 1 on success
2521  */
2522 int
2523 setXattr(const char *path, const char *name, const void *value, size_t size)
2524 {
2525 #if ARCHIVE_XATTR_SUPPORT
2526 #if ARCHIVE_XATTR_LINUX
2527         if (lsetxattr(path, name, value, size, 0) == 0)
2528 #elif ARCHIVE_XATTR_DARWIN
2529         if (setxattr(path, name, value, size, 0, XATTR_NOFOLLOW) == 0)
2530 #elif ARCHIVE_XATTR_AIX
2531         if (lsetea(path, name, value, size, 0) == 0)
2532 #elif ARCHIVE_XATTR_FREEBSD
2533         if (extattr_set_link(path, EXTATTR_NAMESPACE_USER, name + 5, value,
2534             size) > -1)
2535 #else
2536         if (0)
2537 #endif
2538                 return (1);
2539 #else   /* !ARCHIVE_XATTR_SUPPORT */
2540         (void)path;     /* UNUSED */
2541         (void)name;     /* UNUSED */
2542         (void)value;    /* UNUSED */
2543         (void)size;     /* UNUSED */
2544 #endif  /* !ARCHIVE_XATTR_SUPPORT */
2545         return (0);
2546 }
2547
2548 #if ARCHIVE_ACL_SUNOS
2549 /* Fetch ACLs on Solaris using acl() or facl() */
2550 void *
2551 sunacl_get(int cmd, int *aclcnt, int fd, const char *path)
2552 {
2553         int cnt, cntcmd;
2554         size_t size;
2555         void *aclp;
2556
2557         if (cmd == GETACL) {
2558                 cntcmd = GETACLCNT;
2559                 size = sizeof(aclent_t);
2560         }
2561 #if ARCHIVE_ACL_SUNOS_NFS4
2562         else if (cmd == ACE_GETACL) {
2563                 cntcmd = ACE_GETACLCNT;
2564                 size = sizeof(ace_t);
2565         }
2566 #endif
2567         else {
2568                 errno = EINVAL;
2569                 *aclcnt = -1;
2570                 return (NULL);
2571         }
2572
2573         aclp = NULL;
2574         cnt = -2;
2575         while (cnt == -2 || (cnt == -1 && errno == ENOSPC)) {
2576                 if (path != NULL)
2577                         cnt = acl(path, cntcmd, 0, NULL);
2578                 else
2579                         cnt = facl(fd, cntcmd, 0, NULL);
2580
2581                 if (cnt > 0) {
2582                         if (aclp == NULL)
2583                                 aclp = malloc(cnt * size);
2584                         else
2585                                 aclp = realloc(NULL, cnt * size);
2586                         if (aclp != NULL) {
2587                                 if (path != NULL)
2588                                         cnt = acl(path, cmd, cnt, aclp);
2589                                 else
2590                                         cnt = facl(fd, cmd, cnt, aclp);
2591                         }
2592                 } else {
2593                         if (aclp != NULL) {
2594                                 free(aclp);
2595                                 aclp = NULL;
2596                         }
2597                         break;
2598                 }
2599         }
2600
2601         *aclcnt = cnt;
2602         return (aclp);
2603 }
2604 #endif /* ARCHIVE_ACL_SUNOS */
2605
2606 /*
2607  * Set test ACLs on a path
2608  * Return values:
2609  * 0: error setting ACLs
2610  * ARCHIVE_TEST_ACL_TYPE_POSIX1E: POSIX.1E ACLs have been set
2611  * ARCHIVE_TEST_ACL_TYPE_NFS4: NFSv4 or extended ACLs have been set
2612  */
2613 int
2614 setTestAcl(const char *path)
2615 {
2616 #if ARCHIVE_ACL_SUPPORT
2617         int r = 1;
2618 #if ARCHIVE_ACL_LIBACL || ARCHIVE_ACL_FREEBSD || ARCHIVE_ACL_DARWIN
2619         acl_t acl;
2620 #endif
2621 #if ARCHIVE_ACL_LIBRICHACL
2622         struct richacl *richacl;
2623 #endif
2624 #if ARCHIVE_ACL_LIBACL || ARCHIVE_ACL_FREEBSD
2625         const char *acltext_posix1e = "user:1:rw-,"
2626             "group:15:r-x,"
2627             "user::rwx,"
2628             "group::rwx,"
2629             "other::r-x,"
2630             "mask::rwx";
2631 #elif ARCHIVE_ACL_SUNOS /* Solaris POSIX.1e */
2632         aclent_t aclp_posix1e[] = {
2633             { USER_OBJ, -1, 4 | 2 | 1 },
2634             { USER, 1, 4 | 2 },
2635             { GROUP_OBJ, -1, 4 | 2 | 1 },
2636             { GROUP, 15, 4 | 1 },
2637             { CLASS_OBJ, -1, 4 | 2 | 1 },
2638             { OTHER_OBJ, -1, 4 | 2 | 1 }
2639         };
2640 #endif
2641 #if ARCHIVE_ACL_FREEBSD /* FreeBSD NFS4 */
2642         const char *acltext_nfs4 = "user:1:rwpaRcs::allow:1,"
2643             "group:15:rxaRcs::allow:15,"
2644             "owner@:rwpxaARWcCos::allow,"
2645             "group@:rwpxaRcs::allow,"
2646             "everyone@:rxaRcs::allow";
2647 #elif ARCHIVE_ACL_LIBRICHACL
2648         const char *acltext_nfs4 = "owner:rwpxaARWcCoS::mask,"
2649             "group:rwpxaRcS::mask,"
2650             "other:rxaRcS::mask,"
2651             "user:1:rwpaRcS::allow,"
2652             "group:15:rxaRcS::allow,"
2653             "owner@:rwpxaARWcCoS::allow,"
2654             "group@:rwpxaRcS::allow,"
2655             "everyone@:rxaRcS::allow";
2656 #elif ARCHIVE_ACL_SUNOS_NFS4 /* Solaris NFS4 */
2657         ace_t aclp_nfs4[] = {
2658             { 1, ACE_READ_DATA | ACE_WRITE_DATA | ACE_APPEND_DATA |
2659               ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS | ACE_READ_ACL |
2660               ACE_SYNCHRONIZE, 0, ACE_ACCESS_ALLOWED_ACE_TYPE },
2661             { 15, ACE_READ_DATA | ACE_EXECUTE | ACE_READ_ATTRIBUTES |
2662               ACE_READ_NAMED_ATTRS | ACE_READ_ACL | ACE_SYNCHRONIZE,
2663               ACE_IDENTIFIER_GROUP, ACE_ACCESS_ALLOWED_ACE_TYPE },
2664             { -1, ACE_READ_DATA | ACE_WRITE_DATA | ACE_APPEND_DATA |
2665               ACE_EXECUTE | ACE_READ_ATTRIBUTES | ACE_WRITE_ATTRIBUTES |
2666               ACE_READ_NAMED_ATTRS | ACE_WRITE_NAMED_ATTRS |
2667               ACE_READ_ACL | ACE_WRITE_ACL | ACE_WRITE_OWNER | ACE_SYNCHRONIZE,
2668               ACE_OWNER, ACE_ACCESS_ALLOWED_ACE_TYPE },
2669             { -1, ACE_READ_DATA | ACE_WRITE_DATA | ACE_APPEND_DATA |
2670               ACE_EXECUTE | ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS |
2671               ACE_READ_ACL | ACE_SYNCHRONIZE, ACE_GROUP | ACE_IDENTIFIER_GROUP,
2672               ACE_ACCESS_ALLOWED_ACE_TYPE },
2673             { -1, ACE_READ_DATA | ACE_EXECUTE | ACE_READ_ATTRIBUTES |
2674               ACE_READ_NAMED_ATTRS | ACE_READ_ACL | ACE_SYNCHRONIZE,
2675               ACE_EVERYONE, ACE_ACCESS_ALLOWED_ACE_TYPE }
2676         };
2677 #elif ARCHIVE_ACL_DARWIN /* Mac OS X */
2678         acl_entry_t aclent;
2679         acl_permset_t permset;
2680         const uid_t uid = 1;
2681         uuid_t uuid;
2682         int i;
2683         const acl_perm_t acl_perms[] = {
2684                 ACL_READ_DATA,
2685                 ACL_WRITE_DATA,
2686                 ACL_APPEND_DATA,
2687                 ACL_EXECUTE,
2688                 ACL_READ_ATTRIBUTES,
2689                 ACL_READ_EXTATTRIBUTES,
2690                 ACL_READ_SECURITY,
2691 #if HAVE_DECL_ACL_SYNCHRONIZE
2692                 ACL_SYNCHRONIZE
2693 #endif
2694         };
2695 #endif /* ARCHIVE_ACL_DARWIN */
2696
2697 #if ARCHIVE_ACL_FREEBSD
2698         acl = acl_from_text(acltext_nfs4);
2699         failure("acl_from_text() error: %s", strerror(errno));
2700         if (assert(acl != NULL) == 0)
2701                 return (0);
2702 #elif ARCHIVE_ACL_LIBRICHACL
2703         richacl = richacl_from_text(acltext_nfs4, NULL, NULL);
2704         failure("richacl_from_text() error: %s", strerror(errno));
2705         if (assert(richacl != NULL) == 0)
2706                 return (0);
2707 #elif ARCHIVE_ACL_DARWIN
2708         acl = acl_init(1);
2709         failure("acl_init() error: %s", strerror(errno));
2710         if (assert(acl != NULL) == 0)
2711                 return (0);
2712         r = acl_create_entry(&acl, &aclent);
2713         failure("acl_create_entry() error: %s", strerror(errno));
2714         if (assertEqualInt(r, 0) == 0)
2715                 goto testacl_free;
2716         r = acl_set_tag_type(aclent, ACL_EXTENDED_ALLOW);
2717         failure("acl_set_tag_type() error: %s", strerror(errno));
2718         if (assertEqualInt(r, 0) == 0)
2719                 goto testacl_free;
2720         r = acl_get_permset(aclent, &permset);
2721         failure("acl_get_permset() error: %s", strerror(errno));
2722         if (assertEqualInt(r, 0) == 0)
2723                 goto testacl_free;
2724         for (i = 0; i < (int)(sizeof(acl_perms) / sizeof(acl_perms[0])); i++) {
2725                 r = acl_add_perm(permset, acl_perms[i]);
2726                 failure("acl_add_perm() error: %s", strerror(errno));
2727                 if (assertEqualInt(r, 0) == 0)
2728                         goto testacl_free;
2729         }
2730         r = acl_set_permset(aclent, permset);
2731         failure("acl_set_permset() error: %s", strerror(errno));
2732         if (assertEqualInt(r, 0) == 0)
2733                 goto testacl_free;
2734         r = mbr_uid_to_uuid(uid, uuid);
2735         failure("mbr_uid_to_uuid() error: %s", strerror(errno));
2736         if (assertEqualInt(r, 0) == 0)
2737                 goto testacl_free;
2738         r = acl_set_qualifier(aclent, uuid);
2739         failure("acl_set_qualifier() error: %s", strerror(errno));
2740         if (assertEqualInt(r, 0) == 0)
2741                 goto testacl_free;
2742 #endif /* ARCHIVE_ACL_DARWIN */
2743
2744 #if ARCHIVE_ACL_NFS4
2745 #if ARCHIVE_ACL_FREEBSD
2746         r = acl_set_file(path, ACL_TYPE_NFS4, acl);
2747         acl_free(acl);
2748 #elif ARCHIVE_ACL_LIBRICHACL
2749         r = richacl_set_file(path, richacl);
2750         richacl_free(richacl);
2751 #elif ARCHIVE_ACL_SUNOS_NFS4
2752         r = acl(path, ACE_SETACL,
2753             (int)(sizeof(aclp_nfs4)/sizeof(aclp_nfs4[0])), aclp_nfs4);
2754 #elif ARCHIVE_ACL_DARWIN
2755         r = acl_set_file(path, ACL_TYPE_EXTENDED, acl);
2756         acl_free(acl);
2757 #endif
2758         if (r == 0)
2759                 return (ARCHIVE_TEST_ACL_TYPE_NFS4);
2760 #endif  /* ARCHIVE_ACL_NFS4 */
2761
2762 #if ARCHIVE_ACL_POSIX1E
2763 #if ARCHIVE_ACL_FREEBSD || ARCHIVE_ACL_LIBACL
2764         acl = acl_from_text(acltext_posix1e);
2765         failure("acl_from_text() error: %s", strerror(errno));
2766         if (assert(acl != NULL) == 0)
2767                 return (0);
2768
2769         r = acl_set_file(path, ACL_TYPE_ACCESS, acl);
2770         acl_free(acl);
2771 #elif ARCHIVE_ACL_SUNOS
2772         r = acl(path, SETACL,
2773             (int)(sizeof(aclp_posix1e)/sizeof(aclp_posix1e[0])), aclp_posix1e);
2774 #endif
2775         if (r == 0)
2776                 return (ARCHIVE_TEST_ACL_TYPE_POSIX1E);
2777         else
2778                 return (0);
2779 #endif /* ARCHIVE_ACL_POSIX1E */
2780 #if ARCHIVE_ACL_DARWIN
2781 testacl_free:
2782         acl_free(acl);
2783 #endif
2784 #endif /* ARCHIVE_ACL_SUPPORT */
2785         (void)path;     /* UNUSED */
2786         return (0);
2787 }
2788
2789 /*
2790  * Sleep as needed; useful for verifying disk timestamp changes by
2791  * ensuring that the wall-clock time has actually changed before we
2792  * go back to re-read something from disk.
2793  */
2794 void
2795 sleepUntilAfter(time_t t)
2796 {
2797         while (t >= time(NULL))
2798 #if defined(_WIN32) && !defined(__CYGWIN__)
2799                 Sleep(500);
2800 #else
2801                 sleep(1);
2802 #endif
2803 }
2804
2805 /*
2806  * Call standard system() call, but build up the command line using
2807  * sprintf() conventions.
2808  */
2809 int
2810 systemf(const char *fmt, ...)
2811 {
2812         char buff[8192];
2813         va_list ap;
2814         int r;
2815
2816         va_start(ap, fmt);
2817         vsprintf(buff, fmt, ap);
2818         if (verbosity > VERBOSITY_FULL)
2819                 logprintf("Cmd: %s\n", buff);
2820         r = system(buff);
2821         va_end(ap);
2822         return (r);
2823 }
2824
2825 /*
2826  * Slurp a file into memory for ease of comparison and testing.
2827  * Returns size of file in 'sizep' if non-NULL, null-terminates
2828  * data in memory for ease of use.
2829  */
2830 char *
2831 slurpfile(size_t * sizep, const char *fmt, ...)
2832 {
2833         char filename[8192];
2834         struct stat st;
2835         va_list ap;
2836         char *p;
2837         ssize_t bytes_read;
2838         FILE *f;
2839         int r;
2840
2841         va_start(ap, fmt);
2842         vsprintf(filename, fmt, ap);
2843         va_end(ap);
2844
2845         f = fopen(filename, "rb");
2846         if (f == NULL) {
2847                 /* Note: No error; non-existent file is okay here. */
2848                 return (NULL);
2849         }
2850         r = fstat(fileno(f), &st);
2851         if (r != 0) {
2852                 logprintf("Can't stat file %s\n", filename);
2853                 fclose(f);
2854                 return (NULL);
2855         }
2856         p = malloc((size_t)st.st_size + 1);
2857         if (p == NULL) {
2858                 logprintf("Can't allocate %ld bytes of memory to read file %s\n",
2859                     (long int)st.st_size, filename);
2860                 fclose(f);
2861                 return (NULL);
2862         }
2863         bytes_read = fread(p, 1, (size_t)st.st_size, f);
2864         if (bytes_read < st.st_size) {
2865                 logprintf("Can't read file %s\n", filename);
2866                 fclose(f);
2867                 free(p);
2868                 return (NULL);
2869         }
2870         p[st.st_size] = '\0';
2871         if (sizep != NULL)
2872                 *sizep = (size_t)st.st_size;
2873         fclose(f);
2874         return (p);
2875 }
2876
2877 /*
2878  * Slurp a file into memory for ease of comparison and testing.
2879  * Returns size of file in 'sizep' if non-NULL, null-terminates
2880  * data in memory for ease of use.
2881  */
2882 void
2883 dumpfile(const char *filename, void *data, size_t len)
2884 {
2885         ssize_t bytes_written;
2886         FILE *f;
2887
2888         f = fopen(filename, "wb");
2889         if (f == NULL) {
2890                 logprintf("Can't open file %s for writing\n", filename);
2891                 return;
2892         }
2893         bytes_written = fwrite(data, 1, len, f);
2894         if (bytes_written < (ssize_t)len)
2895                 logprintf("Can't write file %s\n", filename);
2896         fclose(f);
2897 }
2898
2899 /* Read a uuencoded file from the reference directory, decode, and
2900  * write the result into the current directory. */
2901 #define VALID_UUDECODE(c) (c >= 32 && c <= 96)
2902 #define UUDECODE(c) (((c) - 0x20) & 0x3f)
2903 void
2904 extract_reference_file(const char *name)
2905 {
2906         char buff[1024];
2907         FILE *in, *out;
2908
2909         sprintf(buff, "%s/%s.uu", refdir, name);
2910         in = fopen(buff, "r");
2911         failure("Couldn't open reference file %s", buff);
2912         assert(in != NULL);
2913         if (in == NULL)
2914                 return;
2915         /* Read up to and including the 'begin' line. */
2916         for (;;) {
2917                 if (fgets(buff, sizeof(buff), in) == NULL) {
2918                         /* TODO: This is a failure. */
2919                         return;
2920                 }
2921                 if (memcmp(buff, "begin ", 6) == 0)
2922                         break;
2923         }
2924         /* Now, decode the rest and write it. */
2925         out = fopen(name, "wb");
2926         while (fgets(buff, sizeof(buff), in) != NULL) {
2927                 char *p = buff;
2928                 int bytes;
2929
2930                 if (memcmp(buff, "end", 3) == 0)
2931                         break;
2932
2933                 bytes = UUDECODE(*p++);
2934                 while (bytes > 0) {
2935                         int n = 0;
2936                         /* Write out 1-3 bytes from that. */
2937                         if (bytes > 0) {
2938                                 assert(VALID_UUDECODE(p[0]));
2939                                 assert(VALID_UUDECODE(p[1]));
2940                                 n = UUDECODE(*p++) << 18;
2941                                 n |= UUDECODE(*p++) << 12;
2942                                 fputc(n >> 16, out);
2943                                 --bytes;
2944                         }
2945                         if (bytes > 0) {
2946                                 assert(VALID_UUDECODE(p[0]));
2947                                 n |= UUDECODE(*p++) << 6;
2948                                 fputc((n >> 8) & 0xFF, out);
2949                                 --bytes;
2950                         }
2951                         if (bytes > 0) {
2952                                 assert(VALID_UUDECODE(p[0]));
2953                                 n |= UUDECODE(*p++);
2954                                 fputc(n & 0xFF, out);
2955                                 --bytes;
2956                         }
2957                 }
2958         }
2959         fclose(out);
2960         fclose(in);
2961 }
2962
2963 void
2964 copy_reference_file(const char *name)
2965 {
2966         char buff[1024];
2967         FILE *in, *out;
2968         size_t rbytes;
2969
2970         sprintf(buff, "%s/%s", refdir, name);
2971         in = fopen(buff, "rb");
2972         failure("Couldn't open reference file %s", buff);
2973         assert(in != NULL);
2974         if (in == NULL)
2975                 return;
2976         /* Now, decode the rest and write it. */
2977         /* Not a lot of error checking here; the input better be right. */
2978         out = fopen(name, "wb");
2979         while ((rbytes = fread(buff, 1, sizeof(buff), in)) > 0) {
2980                 if (fwrite(buff, 1, rbytes, out) != rbytes) {
2981                         logprintf("Error: fwrite\n");
2982                         break;
2983                 }
2984         }
2985         fclose(out);
2986         fclose(in);
2987 }
2988
2989 int
2990 is_LargeInode(const char *file)
2991 {
2992 #if defined(_WIN32) && !defined(__CYGWIN__)
2993         BY_HANDLE_FILE_INFORMATION bhfi;
2994         int r;
2995
2996         r = my_GetFileInformationByName(file, &bhfi);
2997         if (r != 0)
2998                 return (0);
2999         return (bhfi.nFileIndexHigh & 0x0000FFFFUL);
3000 #else
3001         struct stat st;
3002         int64_t ino;
3003
3004         if (stat(file, &st) < 0)
3005                 return (0);
3006         ino = (int64_t)st.st_ino;
3007         return (ino > 0xffffffff);
3008 #endif
3009 }
3010
3011 void
3012 extract_reference_files(const char **names)
3013 {
3014         while (names && *names)
3015                 extract_reference_file(*names++);
3016 }
3017
3018 #ifndef PROGRAM
3019 /* Set ACLs */
3020 int
3021 assertion_entry_set_acls(const char *file, int line, struct archive_entry *ae,
3022     struct archive_test_acl_t *acls, int n)
3023 {
3024         int i, r, ret;
3025
3026         assertion_count(file, line);
3027
3028         ret = 0;
3029         archive_entry_acl_clear(ae);
3030         for (i = 0; i < n; i++) {
3031                 r = archive_entry_acl_add_entry(ae,
3032                     acls[i].type, acls[i].permset, acls[i].tag,
3033                     acls[i].qual, acls[i].name);
3034                 if (r != 0) {
3035                         ret = 1;
3036                         failure_start(file, line, "type=%#010x, ",
3037                             "permset=%#010x, tag=%d, qual=%d name=%s",
3038                             acls[i].type, acls[i].permset, acls[i].tag,
3039                             acls[i].qual, acls[i].name);
3040                         failure_finish(NULL);
3041                 }
3042         }
3043
3044         return (ret);
3045 }
3046
3047 static int
3048 archive_test_acl_match(struct archive_test_acl_t *acl, int type, int permset,
3049     int tag, int qual, const char *name)
3050 {
3051         if (type != acl->type)
3052                 return (0);
3053         if (permset != acl->permset)
3054                 return (0);
3055         if (tag != acl->tag)
3056                 return (0);
3057         if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ)
3058                 return (1);
3059         if (tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ)
3060                 return (1);
3061         if (tag == ARCHIVE_ENTRY_ACL_EVERYONE)
3062                 return (1);
3063         if (tag == ARCHIVE_ENTRY_ACL_OTHER)
3064                 return (1);
3065         if (qual != acl->qual)
3066                 return (0);
3067         if (name == NULL) {
3068                 if (acl->name == NULL || acl->name[0] == '\0')
3069                         return (1);
3070                 return (0);
3071         }
3072         if (acl->name == NULL) {
3073                 if (name[0] == '\0')
3074                         return (1);
3075                 return (0);
3076         }
3077         return (0 == strcmp(name, acl->name));
3078 }
3079
3080 /* Compare ACLs */
3081 int
3082 assertion_entry_compare_acls(const char *file, int line,
3083     struct archive_entry *ae, struct archive_test_acl_t *acls, int cnt,
3084     int want_type, int mode)
3085 {
3086         int *marker;
3087         int i, r, n, ret;
3088         int type, permset, tag, qual;
3089         int matched;
3090         const char *name;
3091
3092         assertion_count(file, line);
3093
3094         ret = 0;
3095         n = 0;
3096         marker = malloc(sizeof(marker[0]) * cnt);
3097
3098         for (i = 0; i < cnt; i++) {
3099                 if ((acls[i].type & want_type) != 0) {
3100                         marker[n] = i;
3101                         n++;
3102                 }
3103         }
3104
3105         if (n == 0) {
3106                 failure_start(file, line, "No ACL's to compare, type mask: %d",
3107                     want_type);
3108                 return (1);
3109         }
3110
3111         while (0 == (r = archive_entry_acl_next(ae, want_type,
3112                          &type, &permset, &tag, &qual, &name))) {
3113                 for (i = 0, matched = 0; i < n && !matched; i++) {
3114                         if (archive_test_acl_match(&acls[marker[i]], type,
3115                             permset, tag, qual, name)) {
3116                                 /* We found a match; remove it. */
3117                                 marker[i] = marker[n - 1];
3118                                 n--;
3119                                 matched = 1;
3120                         }
3121                 }
3122                 if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS
3123                     && tag == ARCHIVE_ENTRY_ACL_USER_OBJ) {
3124                         if (!matched) {
3125                                 failure_start(file, line, "No match for "
3126                                     "user_obj perm");
3127                                 failure_finish(NULL);
3128                                 ret = 1;
3129                         }
3130                         if ((permset << 6) != (mode & 0700)) {
3131                                 failure_start(file, line, "USER_OBJ permset "
3132                                     "(%02o) != user mode (%02o)", permset,
3133                                     07 & (mode >> 6));
3134                                 failure_finish(NULL);
3135                                 ret = 1;
3136                         }
3137                 } else if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS
3138                     && tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ) {
3139                         if (!matched) {
3140                                 failure_start(file, line, "No match for "
3141                                     "group_obj perm");
3142                                 failure_finish(NULL);
3143                                 ret = 1;
3144                         }
3145                         if ((permset << 3) != (mode & 0070)) {
3146                                 failure_start(file, line, "GROUP_OBJ permset "
3147                                     "(%02o) != group mode (%02o)", permset,
3148                                     07 & (mode >> 3));
3149                                 failure_finish(NULL);
3150                                 ret = 1;
3151                         }
3152                 } else if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS
3153                     && tag == ARCHIVE_ENTRY_ACL_OTHER) {
3154                         if (!matched) {
3155                                 failure_start(file, line, "No match for "
3156                                     "other perm");
3157                                 failure_finish(NULL);
3158                                 ret = 1;
3159                         }
3160                         if ((permset << 0) != (mode & 0007)) {
3161                                 failure_start(file, line, "OTHER permset "
3162                                     "(%02o) != other mode (%02o)", permset,
3163                                     mode & 07);
3164                                 failure_finish(NULL);
3165                                 ret = 1;
3166                         }
3167                 } else if (matched != 1) {
3168                         failure_start(file, line, "Could not find match for "
3169                             "ACL (type=%#010x,permset=%#010x,tag=%d,qual=%d,"
3170                             "name=``%s'')", type, permset, tag, qual, name);
3171                         failure_finish(NULL);
3172                         ret = 1;
3173                 }
3174         }
3175         if (r != ARCHIVE_EOF) {
3176                 failure_start(file, line, "Should not exit before EOF");
3177                 failure_finish(NULL);
3178                 ret = 1;
3179         }
3180         if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0 &&
3181             (mode_t)(mode & 0777) != (archive_entry_mode(ae) & 0777)) {
3182                 failure_start(file, line, "Mode (%02o) and entry mode (%02o) "
3183                     "mismatch", mode, archive_entry_mode(ae));
3184                 failure_finish(NULL);
3185                 ret = 1;
3186         }
3187         if (n != 0) {
3188                 failure_start(file, line, "Could not find match for ACL "
3189                     "(type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s'')",
3190                     acls[marker[0]].type, acls[marker[0]].permset,
3191                     acls[marker[0]].tag, acls[marker[0]].qual,
3192                     acls[marker[0]].name);
3193                 failure_finish(NULL);
3194                 ret = 1;
3195                 /* Number of ACLs not matched should == 0 */
3196         }
3197         free(marker);
3198         return (ret);
3199 }
3200 #endif  /* !defined(PROGRAM) */
3201
3202 /*
3203  *
3204  * TEST management
3205  *
3206  */
3207
3208 /*
3209  * "list.h" is simply created by "grep DEFINE_TEST test_*.c"; it has
3210  * a line like
3211  *      DEFINE_TEST(test_function)
3212  * for each test.
3213  */
3214
3215 /* Use "list.h" to declare all of the test functions. */
3216 #undef DEFINE_TEST
3217 #define DEFINE_TEST(name) void name(void);
3218 #include "list.h"
3219
3220 /* Use "list.h" to create a list of all tests (functions and names). */
3221 #undef DEFINE_TEST
3222 #define DEFINE_TEST(n) { n, #n, 0 },
3223 struct test_list_t tests[] = {
3224         #include "list.h"
3225 };
3226
3227 /*
3228  * Summarize repeated failures in the just-completed test.
3229  */
3230 static void
3231 test_summarize(int failed, int skips_num)
3232 {
3233         unsigned int i;
3234
3235         switch (verbosity) {
3236         case VERBOSITY_SUMMARY_ONLY:
3237                 printf(failed ? "E" : ".");
3238                 fflush(stdout);
3239                 break;
3240         case VERBOSITY_PASSFAIL:
3241                 printf(failed ? "FAIL\n" : skips_num ? "ok (S)\n" : "ok\n");
3242                 break;
3243         }
3244
3245         log_console = (verbosity == VERBOSITY_LIGHT_REPORT);
3246
3247         for (i = 0; i < sizeof(failed_lines)/sizeof(failed_lines[0]); i++) {
3248                 if (failed_lines[i].count > 1 && !failed_lines[i].skip)
3249                         logprintf("%s:%d: Summary: Failed %d times\n",
3250                             failed_filename, i, failed_lines[i].count);
3251         }
3252         /* Clear the failure history for the next file. */
3253         failed_filename = NULL;
3254         memset(failed_lines, 0, sizeof(failed_lines));
3255 }
3256
3257 /*
3258  * Actually run a single test, with appropriate setup and cleanup.
3259  */
3260 static int
3261 test_run(int i, const char *tmpdir)
3262 {
3263         char workdir[1024];
3264         char logfilename[64];
3265         int failures_before = failures;
3266         int skips_before = skips;
3267         int oldumask;
3268
3269         switch (verbosity) {
3270         case VERBOSITY_SUMMARY_ONLY: /* No per-test reports at all */
3271                 break;
3272         case VERBOSITY_PASSFAIL: /* rest of line will include ok/FAIL marker */
3273                 printf("%3d: %-64s", i, tests[i].name);
3274                 fflush(stdout);
3275                 break;
3276         default: /* Title of test, details will follow */
3277                 printf("%3d: %s\n", i, tests[i].name);
3278         }
3279
3280         /* Chdir to the top-level work directory. */
3281         if (!assertChdir(tmpdir)) {
3282                 fprintf(stderr,
3283                     "ERROR: Can't chdir to top work dir %s\n", tmpdir);
3284                 exit(1);
3285         }
3286         /* Create a log file for this test. */
3287         sprintf(logfilename, "%s.log", tests[i].name);
3288         logfile = fopen(logfilename, "w");
3289         fprintf(logfile, "%s\n\n", tests[i].name);
3290         /* Chdir() to a work dir for this specific test. */
3291         snprintf(workdir, sizeof(workdir), "%s/%s", tmpdir, tests[i].name);
3292         testworkdir = workdir;
3293         if (!assertMakeDir(testworkdir, 0755)
3294             || !assertChdir(testworkdir)) {
3295                 fprintf(stderr,
3296                     "ERROR: Can't chdir to work dir %s\n", testworkdir);
3297                 exit(1);
3298         }
3299         /* Explicitly reset the locale before each test. */
3300         setlocale(LC_ALL, "C");
3301         /* Record the umask before we run the test. */
3302         umask(oldumask = umask(0));
3303         /*
3304          * Run the actual test.
3305          */
3306         (*tests[i].func)();
3307         /*
3308          * Clean up and report afterwards.
3309          */
3310         testworkdir = NULL;
3311         /* Restore umask */
3312         umask(oldumask);
3313         /* Reset locale. */
3314         setlocale(LC_ALL, "C");
3315         /* Reset directory. */
3316         if (!assertChdir(tmpdir)) {
3317                 fprintf(stderr, "ERROR: Couldn't chdir to temp dir %s\n",
3318                     tmpdir);
3319                 exit(1);
3320         }
3321         /* Report per-test summaries. */
3322         tests[i].failures = failures - failures_before;
3323         test_summarize(tests[i].failures, skips - skips_before);
3324         /* Close the per-test log file. */
3325         fclose(logfile);
3326         logfile = NULL;
3327         /* If there were no failures, we can remove the work dir and logfile. */
3328         if (tests[i].failures == 0) {
3329                 if (!keep_temp_files && assertChdir(tmpdir)) {
3330 #if defined(_WIN32) && !defined(__CYGWIN__)
3331                         /* Make sure not to leave empty directories.
3332                          * Sometimes a processing of closing files used by tests
3333                          * is not done, then rmdir will be failed and it will
3334                          * leave a empty test directory. So we should wait a few
3335                          * seconds and retry rmdir. */
3336                         int r, t;
3337                         for (t = 0; t < 10; t++) {
3338                                 if (t > 0)
3339                                         Sleep(1000);
3340                                 r = systemf("rmdir /S /Q %s", tests[i].name);
3341                                 if (r == 0)
3342                                         break;
3343                         }
3344                         systemf("del %s", logfilename);
3345 #else
3346                         systemf("rm -rf %s", tests[i].name);
3347                         systemf("rm %s", logfilename);
3348 #endif
3349                 }
3350         }
3351         /* Return appropriate status. */
3352         return (tests[i].failures);
3353 }
3354
3355 /*
3356  *
3357  *
3358  * MAIN and support routines.
3359  *
3360  *
3361  */
3362
3363 static void
3364 usage(const char *program)
3365 {
3366         static const int limit = sizeof(tests) / sizeof(tests[0]);
3367         int i;
3368
3369         printf("Usage: %s [options] <test> <test> ...\n", program);
3370         printf("Default is to run all tests.\n");
3371         printf("Otherwise, specify the numbers of the tests you wish to run.\n");
3372         printf("Options:\n");
3373         printf("  -d  Dump core after any failure, for debugging.\n");
3374         printf("  -k  Keep all temp files.\n");
3375         printf("      Default: temp files for successful tests deleted.\n");
3376 #ifdef PROGRAM
3377         printf("  -p <path>  Path to executable to be tested.\n");
3378         printf("      Default: path taken from " ENVBASE " environment variable.\n");
3379 #endif
3380         printf("  -q  Quiet.\n");
3381         printf("  -r <dir>   Path to dir containing reference files.\n");
3382         printf("      Default: Current directory.\n");
3383         printf("  -u  Keep running specifies tests until one fails.\n");
3384         printf("  -v  Verbose.\n");
3385         printf("Available tests:\n");
3386         for (i = 0; i < limit; i++)
3387                 printf("  %d: %s\n", i, tests[i].name);
3388         exit(1);
3389 }
3390
3391 static char *
3392 get_refdir(const char *d)
3393 {
3394         size_t tried_size, buff_size;
3395         char *buff, *tried, *pwd = NULL, *p = NULL;
3396
3397 #ifdef PATH_MAX
3398         buff_size = PATH_MAX;
3399 #else
3400         buff_size = 8192;
3401 #endif
3402         buff = calloc(buff_size, 1);
3403         if (buff == NULL) {
3404                 fprintf(stderr, "Unable to allocate memory\n");
3405                 exit(1);
3406         }
3407
3408         /* Allocate a buffer to hold the various directories we checked. */
3409         tried_size = buff_size * 2;
3410         tried = calloc(tried_size, 1);
3411         if (tried == NULL) {
3412                 fprintf(stderr, "Unable to allocate memory\n");
3413                 exit(1);
3414         }
3415
3416         /* If a dir was specified, try that */
3417         if (d != NULL) {
3418                 pwd = NULL;
3419                 snprintf(buff, buff_size, "%s", d);
3420                 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
3421                 if (p != NULL) goto success;
3422                 strncat(tried, buff, tried_size - strlen(tried) - 1);
3423                 strncat(tried, "\n", tried_size - strlen(tried) - 1);
3424                 goto failure;
3425         }
3426
3427         /* Get the current dir. */
3428 #ifdef PATH_MAX
3429         pwd = getcwd(NULL, PATH_MAX);/* Solaris getcwd needs the size. */
3430 #else
3431         pwd = getcwd(NULL, 0);
3432 #endif
3433         while (pwd[strlen(pwd) - 1] == '\n')
3434                 pwd[strlen(pwd) - 1] = '\0';
3435
3436         /* Look for a known file. */
3437         snprintf(buff, buff_size, "%s", pwd);
3438         p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
3439         if (p != NULL) goto success;
3440         strncat(tried, buff, tried_size - strlen(tried) - 1);
3441         strncat(tried, "\n", tried_size - strlen(tried) - 1);
3442
3443         snprintf(buff, buff_size, "%s/test", pwd);
3444         p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
3445         if (p != NULL) goto success;
3446         strncat(tried, buff, tried_size - strlen(tried) - 1);
3447         strncat(tried, "\n", tried_size - strlen(tried) - 1);
3448
3449 #if defined(LIBRARY)
3450         snprintf(buff, buff_size, "%s/%s/test", pwd, LIBRARY);
3451 #else
3452         snprintf(buff, buff_size, "%s/%s/test", pwd, PROGRAM);
3453 #endif
3454         p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
3455         if (p != NULL) goto success;
3456         strncat(tried, buff, tried_size - strlen(tried) - 1);
3457         strncat(tried, "\n", tried_size - strlen(tried) - 1);
3458
3459 #if defined(PROGRAM_ALIAS)
3460         snprintf(buff, buff_size, "%s/%s/test", pwd, PROGRAM_ALIAS);
3461         p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
3462         if (p != NULL) goto success;
3463         strncat(tried, buff, tried_size - strlen(tried) - 1);
3464         strncat(tried, "\n", tried_size - strlen(tried) - 1);
3465 #endif
3466
3467         if (memcmp(pwd, "/usr/obj", 8) == 0) {
3468                 snprintf(buff, buff_size, "%s", pwd + 8);
3469                 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
3470                 if (p != NULL) goto success;
3471                 strncat(tried, buff, tried_size - strlen(tried) - 1);
3472                 strncat(tried, "\n", tried_size - strlen(tried) - 1);
3473
3474                 snprintf(buff, buff_size, "%s/test", pwd + 8);
3475                 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
3476                 if (p != NULL) goto success;
3477                 strncat(tried, buff, tried_size - strlen(tried) - 1);
3478                 strncat(tried, "\n", tried_size - strlen(tried) - 1);
3479         }
3480
3481 failure:
3482         printf("Unable to locate known reference file %s\n", KNOWNREF);
3483         printf("  Checked following directories:\n%s\n", tried);
3484         printf("Use -r option to specify full path to reference directory\n");
3485 #if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG)
3486         DebugBreak();
3487 #endif
3488         exit(1);
3489
3490 success:
3491         free(p);
3492         free(pwd);
3493         free(tried);
3494
3495         /* Copy result into a fresh buffer to reduce memory usage. */
3496         p = strdup(buff);
3497         free(buff);
3498         return p;
3499 }
3500
3501 int
3502 main(int argc, char **argv)
3503 {
3504         static const int limit = sizeof(tests) / sizeof(tests[0]);
3505         int test_set[sizeof(tests) / sizeof(tests[0])];
3506         int i = 0, j = 0, tests_run = 0, tests_failed = 0, option;
3507         time_t now;
3508         char *refdir_alloc = NULL;
3509         const char *progname;
3510         char **saved_argv;
3511         const char *tmp, *option_arg, *p;
3512         char tmpdir[256], *pwd, *testprogdir, *tmp2 = NULL, *vlevel = NULL;
3513         char tmpdir_timestamp[256];
3514
3515         (void)argc; /* UNUSED */
3516
3517         /* Get the current dir. */
3518 #ifdef PATH_MAX
3519         pwd = getcwd(NULL, PATH_MAX);/* Solaris getcwd needs the size. */
3520 #else
3521         pwd = getcwd(NULL, 0);
3522 #endif
3523         while (pwd[strlen(pwd) - 1] == '\n')
3524                 pwd[strlen(pwd) - 1] = '\0';
3525
3526 #if defined(HAVE__CrtSetReportMode) && !defined(__WATCOMC__)
3527         /* To stop to run the default invalid parameter handler. */
3528         _set_invalid_parameter_handler(invalid_parameter_handler);
3529         /* Disable annoying assertion message box. */
3530         _CrtSetReportMode(_CRT_ASSERT, 0);
3531 #endif
3532
3533         /*
3534          * Name of this program, used to build root of our temp directory
3535          * tree.
3536          */
3537         progname = p = argv[0];
3538         if ((testprogdir = (char *)malloc(strlen(progname) + 1)) == NULL)
3539         {
3540                 fprintf(stderr, "ERROR: Out of memory.");
3541                 exit(1);
3542         }
3543         strcpy(testprogdir, progname);
3544         while (*p != '\0') {
3545                 /* Support \ or / dir separators for Windows compat. */
3546                 if (*p == '/' || *p == '\\')
3547                 {
3548                         progname = p + 1;
3549                         i = j;
3550                 }
3551                 ++p;
3552                 j++;
3553         }
3554         testprogdir[i] = '\0';
3555 #if defined(_WIN32) && !defined(__CYGWIN__)
3556         if (testprogdir[0] != '/' && testprogdir[0] != '\\' &&
3557             !(((testprogdir[0] >= 'a' && testprogdir[0] <= 'z') ||
3558                (testprogdir[0] >= 'A' && testprogdir[0] <= 'Z')) &&
3559                 testprogdir[1] == ':' &&
3560                 (testprogdir[2] == '/' || testprogdir[2] == '\\')))
3561 #else
3562         if (testprogdir[0] != '/')
3563 #endif
3564         {
3565                 /* Fixup path for relative directories. */
3566                 if ((testprogdir = (char *)realloc(testprogdir,
3567                         strlen(pwd) + 1 + strlen(testprogdir) + 1)) == NULL)
3568                 {
3569                         fprintf(stderr, "ERROR: Out of memory.");
3570                         exit(1);
3571                 }
3572                 memmove(testprogdir + strlen(pwd) + 1, testprogdir,
3573                     strlen(testprogdir) + 1);
3574                 memcpy(testprogdir, pwd, strlen(pwd));
3575                 testprogdir[strlen(pwd)] = '/';
3576         }
3577
3578 #ifdef PROGRAM
3579         /* Get the target program from environment, if available. */
3580         testprogfile = getenv(ENVBASE);
3581 #endif
3582
3583         if (getenv("TMPDIR") != NULL)
3584                 tmp = getenv("TMPDIR");
3585         else if (getenv("TMP") != NULL)
3586                 tmp = getenv("TMP");
3587         else if (getenv("TEMP") != NULL)
3588                 tmp = getenv("TEMP");
3589         else if (getenv("TEMPDIR") != NULL)
3590                 tmp = getenv("TEMPDIR");
3591         else
3592                 tmp = "/tmp";
3593
3594         /* Allow -d to be controlled through the environment. */
3595         if (getenv(ENVBASE "_DEBUG") != NULL)
3596                 dump_on_failure = 1;
3597
3598         /* Allow -v to be controlled through the environment. */
3599         if (getenv("_VERBOSITY_LEVEL") != NULL)
3600         {
3601                 vlevel = getenv("_VERBOSITY_LEVEL");
3602                 verbosity = atoi(vlevel);
3603                 if (verbosity < VERBOSITY_SUMMARY_ONLY || verbosity > VERBOSITY_FULL)
3604                 {
3605                         /* Unsupported verbosity levels are silently ignored */
3606                         vlevel = NULL;
3607                         verbosity = VERBOSITY_PASSFAIL;
3608                 }
3609         }
3610
3611         /* Get the directory holding test files from environment. */
3612         refdir = getenv(ENVBASE "_TEST_FILES");
3613
3614         /*
3615          * Parse options, without using getopt(), which isn't available
3616          * on all platforms.
3617          */
3618         ++argv; /* Skip program name */
3619         while (*argv != NULL) {
3620                 if (**argv != '-')
3621                         break;
3622                 p = *argv++;
3623                 ++p; /* Skip '-' */
3624                 while (*p != '\0') {
3625                         option = *p++;
3626                         option_arg = NULL;
3627                         /* If 'opt' takes an argument, parse that. */
3628                         if (option == 'p' || option == 'r') {
3629                                 if (*p != '\0')
3630                                         option_arg = p;
3631                                 else if (*argv == NULL) {
3632                                         fprintf(stderr,
3633                                             "Option -%c requires argument.\n",
3634                                             option);
3635                                         usage(progname);
3636                                 } else
3637                                         option_arg = *argv++;
3638                                 p = ""; /* End of this option word. */
3639                         }
3640
3641                         /* Now, handle the option. */
3642                         switch (option) {
3643                         case 'd':
3644                                 dump_on_failure = 1;
3645                                 break;
3646                         case 'k':
3647                                 keep_temp_files = 1;
3648                                 break;
3649                         case 'p':
3650 #ifdef PROGRAM
3651                                 testprogfile = option_arg;
3652 #else
3653                                 fprintf(stderr, "-p option not permitted\n");
3654                                 usage(progname);
3655 #endif
3656                                 break;
3657                         case 'q':
3658                                 if (!vlevel)
3659                                         verbosity--;
3660                                 break;
3661                         case 'r':
3662                                 refdir = option_arg;
3663                                 break;
3664                         case 'u':
3665                                 until_failure++;
3666                                 break;
3667                         case 'v':
3668                                 if (!vlevel)
3669                                         verbosity++;
3670                                 break;
3671                         default:
3672                                 fprintf(stderr, "Unrecognized option '%c'\n",
3673                                     option);
3674                                 usage(progname);
3675                         }
3676                 }
3677         }
3678
3679         /*
3680          * Sanity-check that our options make sense.
3681          */
3682 #ifdef PROGRAM
3683         if (testprogfile == NULL)
3684         {
3685                 if ((tmp2 = (char *)malloc(strlen(testprogdir) + 1 +
3686                         strlen(PROGRAM) + 1)) == NULL)
3687                 {
3688                         fprintf(stderr, "ERROR: Out of memory.");
3689                         exit(1);
3690                 }
3691                 strcpy(tmp2, testprogdir);
3692                 strcat(tmp2, "/");
3693                 strcat(tmp2, PROGRAM);
3694                 testprogfile = tmp2;
3695         }
3696
3697         {
3698                 char *testprg;
3699 #if defined(_WIN32) && !defined(__CYGWIN__)
3700                 /* Command.com sometimes rejects '/' separators. */
3701                 testprg = strdup(testprogfile);
3702                 for (i = 0; testprg[i] != '\0'; i++) {
3703                         if (testprg[i] == '/')
3704                                 testprg[i] = '\\';
3705                 }
3706                 testprogfile = testprg;
3707 #endif
3708                 /* Quote the name that gets put into shell command lines. */
3709                 testprg = malloc(strlen(testprogfile) + 3);
3710                 strcpy(testprg, "\"");
3711                 strcat(testprg, testprogfile);
3712                 strcat(testprg, "\"");
3713                 testprog = testprg;
3714         }
3715 #endif
3716
3717 #if !defined(_WIN32) && defined(SIGPIPE)
3718         {   /* Ignore SIGPIPE signals */
3719                 struct sigaction sa;
3720                 sa.sa_handler = SIG_IGN;
3721                 sigemptyset(&sa.sa_mask);
3722                 sa.sa_flags = 0;
3723                 sigaction(SIGPIPE, &sa, NULL);
3724         }
3725 #endif
3726
3727         /*
3728          * Create a temp directory for the following tests.
3729          * Include the time the tests started as part of the name,
3730          * to make it easier to track the results of multiple tests.
3731          */
3732         now = time(NULL);
3733         for (i = 0; ; i++) {
3734                 strftime(tmpdir_timestamp, sizeof(tmpdir_timestamp),
3735                     "%Y-%m-%dT%H.%M.%S",
3736                     localtime(&now));
3737                 sprintf(tmpdir, "%s/%s.%s-%03d", tmp, progname,
3738                     tmpdir_timestamp, i);
3739                 if (assertMakeDir(tmpdir,0755))
3740                         break;
3741                 if (i >= 999) {
3742                         fprintf(stderr,
3743                             "ERROR: Unable to create temp directory %s\n",
3744                             tmpdir);
3745                         exit(1);
3746                 }
3747         }
3748
3749         /*
3750          * If the user didn't specify a directory for locating
3751          * reference files, try to find the reference files in
3752          * the "usual places."
3753          */
3754         refdir = refdir_alloc = get_refdir(refdir);
3755
3756         /*
3757          * Banner with basic information.
3758          */
3759         printf("\n");
3760         printf("If tests fail or crash, details will be in:\n");
3761         printf("   %s\n", tmpdir);
3762         printf("\n");
3763         if (verbosity > VERBOSITY_SUMMARY_ONLY) {
3764                 printf("Reference files will be read from: %s\n", refdir);
3765 #ifdef PROGRAM
3766                 printf("Running tests on: %s\n", testprog);
3767 #endif
3768                 printf("Exercising: ");
3769                 fflush(stdout);
3770                 printf("%s\n", EXTRA_VERSION);
3771         } else {
3772                 printf("Running ");
3773                 fflush(stdout);
3774         }
3775
3776         /*
3777          * Run some or all of the individual tests.
3778          */
3779         saved_argv = argv;
3780         do {
3781                 argv = saved_argv;
3782                 do {
3783                         int test_num;
3784
3785                         test_num = get_test_set(test_set, limit, *argv, tests);
3786                         if (test_num < 0) {
3787                                 printf("*** INVALID Test %s\n", *argv);
3788                                 free(refdir_alloc);
3789                                 free(testprogdir);
3790                                 usage(progname);
3791                                 return (1);
3792                         }
3793                         for (i = 0; i < test_num; i++) {
3794                                 tests_run++;
3795                                 if (test_run(test_set[i], tmpdir)) {
3796                                         tests_failed++;
3797                                         if (until_failure)
3798                                                 goto finish;
3799                                 }
3800                         }
3801                         if (*argv != NULL)
3802                                 argv++;
3803                 } while (*argv != NULL);
3804         } while (until_failure);
3805
3806 finish:
3807         /* Must be freed after all tests run */
3808         free(tmp2);
3809         free(testprogdir);
3810         free(pwd);
3811
3812         /*
3813          * Report summary statistics.
3814          */
3815         if (verbosity > VERBOSITY_SUMMARY_ONLY) {
3816                 printf("\n");
3817                 printf("Totals:\n");
3818                 printf("  Tests run:         %8d\n", tests_run);
3819                 printf("  Tests failed:      %8d\n", tests_failed);
3820                 printf("  Assertions checked:%8d\n", assertions);
3821                 printf("  Assertions failed: %8d\n", failures);
3822                 printf("  Skips reported:    %8d\n", skips);
3823         }
3824         if (failures) {
3825                 printf("\n");
3826                 printf("Failing tests:\n");
3827                 for (i = 0; i < limit; ++i) {
3828                         if (tests[i].failures)
3829                                 printf("  %d: %s (%d failures)\n", i,
3830                                     tests[i].name, tests[i].failures);
3831                 }
3832                 printf("\n");
3833                 printf("Details for failing tests: %s\n", tmpdir);
3834                 printf("\n");
3835         } else {
3836                 if (verbosity == VERBOSITY_SUMMARY_ONLY)
3837                         printf("\n");
3838                 printf("%d tests passed, no failures\n", tests_run);
3839         }
3840
3841         free(refdir_alloc);
3842
3843         /* If the final tmpdir is empty, we can remove it. */
3844         /* This should be the usual case when all tests succeed. */
3845         assertChdir("..");
3846         rmdir(tmpdir);
3847
3848         return (tests_failed ? 1 : 0);
3849 }