]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/libarchive/test_utils/test_main.c
MFC r315636,315876,316095:
[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                         return (0);
1106                 }
1107                 for (i = 0; lines[i] != NULL; ++i) {
1108                         expected[i] = strdup(lines[i]);
1109                 }
1110         }
1111
1112         /* Break the file into lines */
1113         actual_count = 0;
1114         for (c = '\0', p = buff; p < buff + buff_size; ++p) {
1115                 if (*p == '\x0d' || *p == '\x0a')
1116                         *p = '\0';
1117                 if (c == '\0' && *p != '\0')
1118                         ++actual_count;
1119                 c = *p;
1120         }
1121         if (actual_count) {
1122                 actual = calloc(sizeof(char *), actual_count);
1123                 if (actual == NULL) {
1124                         failure_start(pathname, line, "Can't allocate memory");
1125                         failure_finish(NULL);
1126                         free(expected);
1127                         return (0);
1128                 }
1129                 for (j = 0, p = buff; p < buff + buff_size;
1130                     p += 1 + strlen(p)) {
1131                         if (*p != '\0') {
1132                                 actual[j] = p;
1133                                 ++j;
1134                         }
1135                 }
1136         }
1137
1138         /* Erase matching lines from both lists */
1139         for (i = 0; i < expected_count; ++i) {
1140                 if (expected[i] == NULL)
1141                         continue;
1142                 for (j = 0; j < actual_count; ++j) {
1143                         if (actual[j] == NULL)
1144                                 continue;
1145                         if (strcmp(expected[i], actual[j]) == 0) {
1146                                 free(expected[i]);
1147                                 expected[i] = NULL;
1148                                 actual[j] = NULL;
1149                                 break;
1150                         }
1151                 }
1152         }
1153
1154         /* If there's anything left, it's a failure */
1155         for (i = 0; i < expected_count; ++i) {
1156                 if (expected[i] != NULL)
1157                         ++expected_failure;
1158         }
1159         for (j = 0; j < actual_count; ++j) {
1160                 if (actual[j] != NULL)
1161                         ++actual_failure;
1162         }
1163         if (expected_failure == 0 && actual_failure == 0) {
1164                 free(buff);
1165                 free(expected);
1166                 free(actual);
1167                 return (1);
1168         }
1169         failure_start(file, line, "File doesn't match: %s", pathname);
1170         for (i = 0; i < expected_count; ++i) {
1171                 if (expected[i] != NULL) {
1172                         logprintf("  Expected but not present: %s\n", expected[i]);
1173                         free(expected[i]);
1174                 }
1175         }
1176         for (j = 0; j < actual_count; ++j) {
1177                 if (actual[j] != NULL)
1178                         logprintf("  Present but not expected: %s\n", actual[j]);
1179         }
1180         failure_finish(NULL);
1181         free(buff);
1182         free(expected);
1183         free(actual);
1184         return (0);
1185 }
1186
1187 /* Verify that a text file does not contains the specified strings */
1188 int
1189 assertion_file_contains_no_invalid_strings(const char *file, int line,
1190     const char *pathname, const char *strings[])
1191 {
1192         char *buff;
1193         int i;
1194
1195         buff = slurpfile(NULL, "%s", pathname);
1196         if (buff == NULL) {
1197                 failure_start(file, line, "Can't read file: %s", pathname);
1198                 failure_finish(NULL);
1199                 return (0);
1200         }
1201
1202         for (i = 0; strings[i] != NULL; ++i) {
1203                 if (strstr(buff, strings[i]) != NULL) {
1204                         failure_start(file, line, "Invalid string in %s: %s", pathname,
1205                             strings[i]);
1206                         failure_finish(NULL);
1207                         free(buff);
1208                         return(0);
1209                 }
1210         }
1211
1212         free(buff);
1213         return (0);
1214 }
1215
1216 /* Test that two paths point to the same file. */
1217 /* As a side-effect, asserts that both files exist. */
1218 static int
1219 is_hardlink(const char *file, int line,
1220     const char *path1, const char *path2)
1221 {
1222 #if defined(_WIN32) && !defined(__CYGWIN__)
1223         BY_HANDLE_FILE_INFORMATION bhfi1, bhfi2;
1224         int r;
1225
1226         assertion_count(file, line);
1227         r = my_GetFileInformationByName(path1, &bhfi1);
1228         if (r == 0) {
1229                 failure_start(file, line, "File %s can't be inspected?", path1);
1230                 failure_finish(NULL);
1231                 return (0);
1232         }
1233         r = my_GetFileInformationByName(path2, &bhfi2);
1234         if (r == 0) {
1235                 failure_start(file, line, "File %s can't be inspected?", path2);
1236                 failure_finish(NULL);
1237                 return (0);
1238         }
1239         return (bhfi1.dwVolumeSerialNumber == bhfi2.dwVolumeSerialNumber
1240                 && bhfi1.nFileIndexHigh == bhfi2.nFileIndexHigh
1241                 && bhfi1.nFileIndexLow == bhfi2.nFileIndexLow);
1242 #else
1243         struct stat st1, st2;
1244         int r;
1245
1246         assertion_count(file, line);
1247         r = lstat(path1, &st1);
1248         if (r != 0) {
1249                 failure_start(file, line, "File should exist: %s", path1);
1250                 failure_finish(NULL);
1251                 return (0);
1252         }
1253         r = lstat(path2, &st2);
1254         if (r != 0) {
1255                 failure_start(file, line, "File should exist: %s", path2);
1256                 failure_finish(NULL);
1257                 return (0);
1258         }
1259         return (st1.st_ino == st2.st_ino && st1.st_dev == st2.st_dev);
1260 #endif
1261 }
1262
1263 int
1264 assertion_is_hardlink(const char *file, int line,
1265     const char *path1, const char *path2)
1266 {
1267         if (is_hardlink(file, line, path1, path2))
1268                 return (1);
1269         failure_start(file, line,
1270             "Files %s and %s are not hardlinked", path1, path2);
1271         failure_finish(NULL);
1272         return (0);
1273 }
1274
1275 int
1276 assertion_is_not_hardlink(const char *file, int line,
1277     const char *path1, const char *path2)
1278 {
1279         if (!is_hardlink(file, line, path1, path2))
1280                 return (1);
1281         failure_start(file, line,
1282             "Files %s and %s should not be hardlinked", path1, path2);
1283         failure_finish(NULL);
1284         return (0);
1285 }
1286
1287 /* Verify a/b/mtime of 'pathname'. */
1288 /* If 'recent', verify that it's within last 10 seconds. */
1289 static int
1290 assertion_file_time(const char *file, int line,
1291     const char *pathname, long t, long nsec, char type, int recent)
1292 {
1293         long long filet, filet_nsec;
1294         int r;
1295
1296 #if defined(_WIN32) && !defined(__CYGWIN__)
1297 #define EPOC_TIME       (116444736000000000ULL)
1298         FILETIME fxtime, fbirthtime, fatime, fmtime;
1299         ULARGE_INTEGER wintm;
1300         HANDLE h;
1301         fxtime.dwLowDateTime = 0;
1302         fxtime.dwHighDateTime = 0;
1303
1304         assertion_count(file, line);
1305         /* Note: FILE_FLAG_BACKUP_SEMANTICS applies to open
1306          * a directory file. If not, CreateFile() will fail when
1307          * the pathname is a directory. */
1308         h = CreateFile(pathname, FILE_READ_ATTRIBUTES, 0, NULL,
1309             OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
1310         if (h == INVALID_HANDLE_VALUE) {
1311                 failure_start(file, line, "Can't access %s\n", pathname);
1312                 failure_finish(NULL);
1313                 return (0);
1314         }
1315         r = GetFileTime(h, &fbirthtime, &fatime, &fmtime);
1316         switch (type) {
1317         case 'a': fxtime = fatime; break;
1318         case 'b': fxtime = fbirthtime; break;
1319         case 'm': fxtime = fmtime; break;
1320         }
1321         CloseHandle(h);
1322         if (r == 0) {
1323                 failure_start(file, line, "Can't GetFileTime %s\n", pathname);
1324                 failure_finish(NULL);
1325                 return (0);
1326         }
1327         wintm.LowPart = fxtime.dwLowDateTime;
1328         wintm.HighPart = fxtime.dwHighDateTime;
1329         filet = (wintm.QuadPart - EPOC_TIME) / 10000000;
1330         filet_nsec = ((wintm.QuadPart - EPOC_TIME) % 10000000) * 100;
1331         nsec = (nsec / 100) * 100; /* Round the request */
1332 #else
1333         struct stat st;
1334
1335         assertion_count(file, line);
1336         r = lstat(pathname, &st);
1337         if (r != 0) {
1338                 failure_start(file, line, "Can't stat %s\n", pathname);
1339                 failure_finish(NULL);
1340                 return (0);
1341         }
1342         switch (type) {
1343         case 'a': filet = st.st_atime; break;
1344         case 'm': filet = st.st_mtime; break;
1345         case 'b': filet = 0; break;
1346         default: fprintf(stderr, "INTERNAL: Bad type %c for file time", type);
1347                 exit(1);
1348         }
1349 #if defined(__FreeBSD__)
1350         switch (type) {
1351         case 'a': filet_nsec = st.st_atimespec.tv_nsec; break;
1352         case 'b': filet = st.st_birthtime;
1353                 /* FreeBSD filesystems that don't support birthtime
1354                  * (e.g., UFS1) always return -1 here. */
1355                 if (filet == -1) {
1356                         return (1);
1357                 }
1358                 filet_nsec = st.st_birthtimespec.tv_nsec; break;
1359         case 'm': filet_nsec = st.st_mtimespec.tv_nsec; break;
1360         default: fprintf(stderr, "INTERNAL: Bad type %c for file time", type);
1361                 exit(1);
1362         }
1363         /* FreeBSD generally only stores to microsecond res, so round. */
1364         filet_nsec = (filet_nsec / 1000) * 1000;
1365         nsec = (nsec / 1000) * 1000;
1366 #else
1367         filet_nsec = nsec = 0;  /* Generic POSIX only has whole seconds. */
1368         if (type == 'b') return (1); /* Generic POSIX doesn't have birthtime */
1369 #if defined(__HAIKU__)
1370         if (type == 'a') return (1); /* Haiku doesn't have atime. */
1371 #endif
1372 #endif
1373 #endif
1374         if (recent) {
1375                 /* Check that requested time is up-to-date. */
1376                 time_t now = time(NULL);
1377                 if (filet < now - 10 || filet > now + 1) {
1378                         failure_start(file, line,
1379                             "File %s has %ctime %lld, %lld seconds ago\n",
1380                             pathname, type, filet, now - filet);
1381                         failure_finish(NULL);
1382                         return (0);
1383                 }
1384         } else if (filet != t || filet_nsec != nsec) {
1385                 failure_start(file, line,
1386                     "File %s has %ctime %lld.%09lld, expected %lld.%09lld",
1387                     pathname, type, filet, filet_nsec, t, nsec);
1388                 failure_finish(NULL);
1389                 return (0);
1390         }
1391         return (1);
1392 }
1393
1394 /* Verify atime of 'pathname'. */
1395 int
1396 assertion_file_atime(const char *file, int line,
1397     const char *pathname, long t, long nsec)
1398 {
1399         return assertion_file_time(file, line, pathname, t, nsec, 'a', 0);
1400 }
1401
1402 /* Verify atime of 'pathname' is up-to-date. */
1403 int
1404 assertion_file_atime_recent(const char *file, int line, const char *pathname)
1405 {
1406         return assertion_file_time(file, line, pathname, 0, 0, 'a', 1);
1407 }
1408
1409 /* Verify birthtime of 'pathname'. */
1410 int
1411 assertion_file_birthtime(const char *file, int line,
1412     const char *pathname, long t, long nsec)
1413 {
1414         return assertion_file_time(file, line, pathname, t, nsec, 'b', 0);
1415 }
1416
1417 /* Verify birthtime of 'pathname' is up-to-date. */
1418 int
1419 assertion_file_birthtime_recent(const char *file, int line,
1420     const char *pathname)
1421 {
1422         return assertion_file_time(file, line, pathname, 0, 0, 'b', 1);
1423 }
1424
1425 /* Verify mode of 'pathname'. */
1426 int
1427 assertion_file_mode(const char *file, int line, const char *pathname, int expected_mode)
1428 {
1429         int mode;
1430         int r;
1431
1432         assertion_count(file, line);
1433 #if defined(_WIN32) && !defined(__CYGWIN__)
1434         failure_start(file, line, "assertFileMode not yet implemented for Windows");
1435         (void)mode; /* UNUSED */
1436         (void)r; /* UNUSED */
1437         (void)pathname; /* UNUSED */
1438         (void)expected_mode; /* UNUSED */
1439 #else
1440         {
1441                 struct stat st;
1442                 r = lstat(pathname, &st);
1443                 mode = (int)(st.st_mode & 0777);
1444         }
1445         if (r == 0 && mode == expected_mode)
1446                         return (1);
1447         failure_start(file, line, "File %s has mode %o, expected %o",
1448             pathname, mode, expected_mode);
1449 #endif
1450         failure_finish(NULL);
1451         return (0);
1452 }
1453
1454 /* Verify mtime of 'pathname'. */
1455 int
1456 assertion_file_mtime(const char *file, int line,
1457     const char *pathname, long t, long nsec)
1458 {
1459         return assertion_file_time(file, line, pathname, t, nsec, 'm', 0);
1460 }
1461
1462 /* Verify mtime of 'pathname' is up-to-date. */
1463 int
1464 assertion_file_mtime_recent(const char *file, int line, const char *pathname)
1465 {
1466         return assertion_file_time(file, line, pathname, 0, 0, 'm', 1);
1467 }
1468
1469 /* Verify number of links to 'pathname'. */
1470 int
1471 assertion_file_nlinks(const char *file, int line,
1472     const char *pathname, int nlinks)
1473 {
1474 #if defined(_WIN32) && !defined(__CYGWIN__)
1475         BY_HANDLE_FILE_INFORMATION bhfi;
1476         int r;
1477
1478         assertion_count(file, line);
1479         r = my_GetFileInformationByName(pathname, &bhfi);
1480         if (r != 0 && bhfi.nNumberOfLinks == (DWORD)nlinks)
1481                 return (1);
1482         failure_start(file, line, "File %s has %d links, expected %d",
1483             pathname, bhfi.nNumberOfLinks, nlinks);
1484         failure_finish(NULL);
1485         return (0);
1486 #else
1487         struct stat st;
1488         int r;
1489
1490         assertion_count(file, line);
1491         r = lstat(pathname, &st);
1492         if (r == 0 && (int)st.st_nlink == nlinks)
1493                 return (1);
1494         failure_start(file, line, "File %s has %d links, expected %d",
1495             pathname, st.st_nlink, nlinks);
1496         failure_finish(NULL);
1497         return (0);
1498 #endif
1499 }
1500
1501 /* Verify size of 'pathname'. */
1502 int
1503 assertion_file_size(const char *file, int line, const char *pathname, long size)
1504 {
1505         int64_t filesize;
1506         int r;
1507
1508         assertion_count(file, line);
1509 #if defined(_WIN32) && !defined(__CYGWIN__)
1510         {
1511                 BY_HANDLE_FILE_INFORMATION bhfi;
1512                 r = !my_GetFileInformationByName(pathname, &bhfi);
1513                 filesize = ((int64_t)bhfi.nFileSizeHigh << 32) + bhfi.nFileSizeLow;
1514         }
1515 #else
1516         {
1517                 struct stat st;
1518                 r = lstat(pathname, &st);
1519                 filesize = st.st_size;
1520         }
1521 #endif
1522         if (r == 0 && filesize == size)
1523                         return (1);
1524         failure_start(file, line, "File %s has size %ld, expected %ld",
1525             pathname, (long)filesize, (long)size);
1526         failure_finish(NULL);
1527         return (0);
1528 }
1529
1530 /* Assert that 'pathname' is a dir.  If mode >= 0, verify that too. */
1531 int
1532 assertion_is_dir(const char *file, int line, const char *pathname, int mode)
1533 {
1534         struct stat st;
1535         int r;
1536
1537 #if defined(_WIN32) && !defined(__CYGWIN__)
1538         (void)mode; /* UNUSED */
1539 #endif
1540         assertion_count(file, line);
1541         r = lstat(pathname, &st);
1542         if (r != 0) {
1543                 failure_start(file, line, "Dir should exist: %s", pathname);
1544                 failure_finish(NULL);
1545                 return (0);
1546         }
1547         if (!S_ISDIR(st.st_mode)) {
1548                 failure_start(file, line, "%s is not a dir", pathname);
1549                 failure_finish(NULL);
1550                 return (0);
1551         }
1552 #if !defined(_WIN32) || defined(__CYGWIN__)
1553         /* Windows doesn't handle permissions the same way as POSIX,
1554          * so just ignore the mode tests. */
1555         /* TODO: Can we do better here? */
1556         if (mode >= 0 && (mode_t)mode != (st.st_mode & 07777)) {
1557                 failure_start(file, line, "Dir %s has wrong mode", pathname);
1558                 logprintf("  Expected: 0%3o\n", mode);
1559                 logprintf("  Found: 0%3o\n", st.st_mode & 07777);
1560                 failure_finish(NULL);
1561                 return (0);
1562         }
1563 #endif
1564         return (1);
1565 }
1566
1567 /* Verify that 'pathname' is a regular file.  If 'mode' is >= 0,
1568  * verify that too. */
1569 int
1570 assertion_is_reg(const char *file, int line, const char *pathname, int mode)
1571 {
1572         struct stat st;
1573         int r;
1574
1575 #if defined(_WIN32) && !defined(__CYGWIN__)
1576         (void)mode; /* UNUSED */
1577 #endif
1578         assertion_count(file, line);
1579         r = lstat(pathname, &st);
1580         if (r != 0 || !S_ISREG(st.st_mode)) {
1581                 failure_start(file, line, "File should exist: %s", pathname);
1582                 failure_finish(NULL);
1583                 return (0);
1584         }
1585 #if !defined(_WIN32) || defined(__CYGWIN__)
1586         /* Windows doesn't handle permissions the same way as POSIX,
1587          * so just ignore the mode tests. */
1588         /* TODO: Can we do better here? */
1589         if (mode >= 0 && (mode_t)mode != (st.st_mode & 07777)) {
1590                 failure_start(file, line, "File %s has wrong mode", pathname);
1591                 logprintf("  Expected: 0%3o\n", mode);
1592                 logprintf("  Found: 0%3o\n", st.st_mode & 07777);
1593                 failure_finish(NULL);
1594                 return (0);
1595         }
1596 #endif
1597         return (1);
1598 }
1599
1600 /* Check whether 'pathname' is a symbolic link.  If 'contents' is
1601  * non-NULL, verify that the symlink has those contents. */
1602 static int
1603 is_symlink(const char *file, int line,
1604     const char *pathname, const char *contents)
1605 {
1606 #if defined(_WIN32) && !defined(__CYGWIN__)
1607         (void)pathname; /* UNUSED */
1608         (void)contents; /* UNUSED */
1609         assertion_count(file, line);
1610         /* Windows sort-of has real symlinks, but they're only usable
1611          * by privileged users and are crippled even then, so there's
1612          * really not much point in bothering with this. */
1613         return (0);
1614 #else
1615         char buff[300];
1616         struct stat st;
1617         ssize_t linklen;
1618         int r;
1619
1620         assertion_count(file, line);
1621         r = lstat(pathname, &st);
1622         if (r != 0) {
1623                 failure_start(file, line,
1624                     "Symlink should exist: %s", pathname);
1625                 failure_finish(NULL);
1626                 return (0);
1627         }
1628         if (!S_ISLNK(st.st_mode))
1629                 return (0);
1630         if (contents == NULL)
1631                 return (1);
1632         linklen = readlink(pathname, buff, sizeof(buff));
1633         if (linklen < 0) {
1634                 failure_start(file, line, "Can't read symlink %s", pathname);
1635                 failure_finish(NULL);
1636                 return (0);
1637         }
1638         buff[linklen] = '\0';
1639         if (strcmp(buff, contents) != 0)
1640                 return (0);
1641         return (1);
1642 #endif
1643 }
1644
1645 /* Assert that path is a symlink that (optionally) contains contents. */
1646 int
1647 assertion_is_symlink(const char *file, int line,
1648     const char *path, const char *contents)
1649 {
1650         if (is_symlink(file, line, path, contents))
1651                 return (1);
1652         if (contents)
1653                 failure_start(file, line, "File %s is not a symlink to %s",
1654                     path, contents);
1655         else
1656                 failure_start(file, line, "File %s is not a symlink", path);
1657         failure_finish(NULL);
1658         return (0);
1659 }
1660
1661
1662 /* Create a directory and report any errors. */
1663 int
1664 assertion_make_dir(const char *file, int line, const char *dirname, int mode)
1665 {
1666         assertion_count(file, line);
1667 #if defined(_WIN32) && !defined(__CYGWIN__)
1668         (void)mode; /* UNUSED */
1669         if (0 == _mkdir(dirname))
1670                 return (1);
1671 #else
1672         if (0 == mkdir(dirname, mode)) {
1673                 if (0 == chmod(dirname, mode)) {
1674                         assertion_file_mode(file, line, dirname, mode);
1675                         return (1);
1676                 }
1677         }
1678 #endif
1679         failure_start(file, line, "Could not create directory %s", dirname);
1680         failure_finish(NULL);
1681         return(0);
1682 }
1683
1684 /* Create a file with the specified contents and report any failures. */
1685 int
1686 assertion_make_file(const char *file, int line,
1687     const char *path, int mode, int csize, const void *contents)
1688 {
1689 #if defined(_WIN32) && !defined(__CYGWIN__)
1690         /* TODO: Rework this to set file mode as well. */
1691         FILE *f;
1692         (void)mode; /* UNUSED */
1693         assertion_count(file, line);
1694         f = fopen(path, "wb");
1695         if (f == NULL) {
1696                 failure_start(file, line, "Could not create file %s", path);
1697                 failure_finish(NULL);
1698                 return (0);
1699         }
1700         if (contents != NULL) {
1701                 size_t wsize;
1702
1703                 if (csize < 0)
1704                         wsize = strlen(contents);
1705                 else
1706                         wsize = (size_t)csize;
1707                 if (wsize != fwrite(contents, 1, wsize, f)) {
1708                         fclose(f);
1709                         failure_start(file, line,
1710                             "Could not write file %s", path);
1711                         failure_finish(NULL);
1712                         return (0);
1713                 }
1714         }
1715         fclose(f);
1716         return (1);
1717 #else
1718         int fd;
1719         assertion_count(file, line);
1720         fd = open(path, O_CREAT | O_WRONLY, mode >= 0 ? mode : 0644);
1721         if (fd < 0) {
1722                 failure_start(file, line, "Could not create %s", path);
1723                 failure_finish(NULL);
1724                 return (0);
1725         }
1726         if (0 != chmod(path, mode)) {
1727                 failure_start(file, line, "Could not chmod %s", path);
1728                 failure_finish(NULL);
1729                 close(fd);
1730                 return (0);
1731         }
1732         if (contents != NULL) {
1733                 ssize_t wsize;
1734
1735                 if (csize < 0)
1736                         wsize = (ssize_t)strlen(contents);
1737                 else
1738                         wsize = (ssize_t)csize;
1739                 if (wsize != write(fd, contents, wsize)) {
1740                         close(fd);
1741                         failure_start(file, line,
1742                             "Could not write to %s", path);
1743                         failure_finish(NULL);
1744                         close(fd);
1745                         return (0);
1746                 }
1747         }
1748         close(fd);
1749         assertion_file_mode(file, line, path, mode);
1750         return (1);
1751 #endif
1752 }
1753
1754 /* Create a hardlink and report any failures. */
1755 int
1756 assertion_make_hardlink(const char *file, int line,
1757     const char *newpath, const char *linkto)
1758 {
1759         int succeeded;
1760
1761         assertion_count(file, line);
1762 #if defined(_WIN32) && !defined(__CYGWIN__)
1763         succeeded = my_CreateHardLinkA(newpath, linkto);
1764 #elif HAVE_LINK
1765         succeeded = !link(linkto, newpath);
1766 #else
1767         succeeded = 0;
1768 #endif
1769         if (succeeded)
1770                 return (1);
1771         failure_start(file, line, "Could not create hardlink");
1772         logprintf("   New link: %s\n", newpath);
1773         logprintf("   Old name: %s\n", linkto);
1774         failure_finish(NULL);
1775         return(0);
1776 }
1777
1778 /* Create a symlink and report any failures. */
1779 int
1780 assertion_make_symlink(const char *file, int line,
1781     const char *newpath, const char *linkto)
1782 {
1783 #if defined(_WIN32) && !defined(__CYGWIN__)
1784         int targetIsDir = 0;  /* TODO: Fix this */
1785         assertion_count(file, line);
1786         if (my_CreateSymbolicLinkA(newpath, linkto, targetIsDir))
1787                 return (1);
1788 #elif HAVE_SYMLINK
1789         assertion_count(file, line);
1790         if (0 == symlink(linkto, newpath))
1791                 return (1);
1792 #endif
1793         failure_start(file, line, "Could not create symlink");
1794         logprintf("   New link: %s\n", newpath);
1795         logprintf("   Old name: %s\n", linkto);
1796         failure_finish(NULL);
1797         return(0);
1798 }
1799
1800 /* Set umask, report failures. */
1801 int
1802 assertion_umask(const char *file, int line, int mask)
1803 {
1804         assertion_count(file, line);
1805         (void)file; /* UNUSED */
1806         (void)line; /* UNUSED */
1807         umask(mask);
1808         return (1);
1809 }
1810
1811 /* Set times, report failures. */
1812 int
1813 assertion_utimes(const char *file, int line,
1814     const char *pathname, long at, long at_nsec, long mt, long mt_nsec)
1815 {
1816         int r;
1817
1818 #if defined(_WIN32) && !defined(__CYGWIN__)
1819 #define WINTIME(sec, nsec) ((Int32x32To64(sec, 10000000) + EPOC_TIME)\
1820          + (((nsec)/1000)*10))
1821         HANDLE h;
1822         ULARGE_INTEGER wintm;
1823         FILETIME fatime, fmtime;
1824         FILETIME *pat, *pmt;
1825
1826         assertion_count(file, line);
1827         h = CreateFileA(pathname,GENERIC_READ | GENERIC_WRITE,
1828                     FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
1829                     FILE_FLAG_BACKUP_SEMANTICS, NULL);
1830         if (h == INVALID_HANDLE_VALUE) {
1831                 failure_start(file, line, "Can't access %s\n", pathname);
1832                 failure_finish(NULL);
1833                 return (0);
1834         }
1835
1836         if (at > 0 || at_nsec > 0) {
1837                 wintm.QuadPart = WINTIME(at, at_nsec);
1838                 fatime.dwLowDateTime = wintm.LowPart;
1839                 fatime.dwHighDateTime = wintm.HighPart;
1840                 pat = &fatime;
1841         } else
1842                 pat = NULL;
1843         if (mt > 0 || mt_nsec > 0) {
1844                 wintm.QuadPart = WINTIME(mt, mt_nsec);
1845                 fmtime.dwLowDateTime = wintm.LowPart;
1846                 fmtime.dwHighDateTime = wintm.HighPart;
1847                 pmt = &fmtime;
1848         } else
1849                 pmt = NULL;
1850         if (pat != NULL || pmt != NULL)
1851                 r = SetFileTime(h, NULL, pat, pmt);
1852         else
1853                 r = 1;
1854         CloseHandle(h);
1855         if (r == 0) {
1856                 failure_start(file, line, "Can't SetFileTime %s\n", pathname);
1857                 failure_finish(NULL);
1858                 return (0);
1859         }
1860         return (1);
1861 #else /* defined(_WIN32) && !defined(__CYGWIN__) */
1862         struct stat st;
1863         struct timeval times[2];
1864
1865 #if !defined(__FreeBSD__)
1866         mt_nsec = at_nsec = 0;  /* Generic POSIX only has whole seconds. */
1867 #endif
1868         if (mt == 0 && mt_nsec == 0 && at == 0 && at_nsec == 0)
1869                 return (1);
1870
1871         r = lstat(pathname, &st);
1872         if (r < 0) {
1873                 failure_start(file, line, "Can't stat %s\n", pathname);
1874                 failure_finish(NULL);
1875                 return (0);
1876         }
1877
1878         if (mt == 0 && mt_nsec == 0) {
1879                 mt = st.st_mtime;
1880 #if defined(__FreeBSD__)
1881                 mt_nsec = st.st_mtimespec.tv_nsec;
1882                 /* FreeBSD generally only stores to microsecond res, so round. */
1883                 mt_nsec = (mt_nsec / 1000) * 1000;
1884 #endif
1885         }
1886         if (at == 0 && at_nsec == 0) {
1887                 at = st.st_atime;
1888 #if defined(__FreeBSD__)
1889                 at_nsec = st.st_atimespec.tv_nsec;
1890                 /* FreeBSD generally only stores to microsecond res, so round. */
1891                 at_nsec = (at_nsec / 1000) * 1000;
1892 #endif
1893         }
1894
1895         times[1].tv_sec = mt;
1896         times[1].tv_usec = mt_nsec / 1000;
1897
1898         times[0].tv_sec = at;
1899         times[0].tv_usec = at_nsec / 1000;
1900
1901 #ifdef HAVE_LUTIMES
1902         r = lutimes(pathname, times);
1903 #else
1904         r = utimes(pathname, times);
1905 #endif
1906         if (r < 0) {
1907                 failure_start(file, line, "Can't utimes %s\n", pathname);
1908                 failure_finish(NULL);
1909                 return (0);
1910         }
1911         return (1);
1912 #endif /* defined(_WIN32) && !defined(__CYGWIN__) */
1913 }
1914
1915 /* Compare file flags */
1916 int
1917 assertion_compare_fflags(const char *file, int line, const char *patha,
1918     const char *pathb, int nomatch)
1919 {
1920 #if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP)
1921         struct stat sa, sb;
1922
1923         assertion_count(file, line);
1924
1925         if (stat(patha, &sa) < 0)
1926                 return (0);
1927         if (stat(pathb, &sb) < 0)
1928                 return (0);
1929         if (!nomatch && sa.st_flags != sb.st_flags) {
1930                 failure_start(file, line, "File flags should be identical: "
1931                     "%s=%#010x %s=%#010x", patha, sa.st_flags, pathb,
1932                     sb.st_flags);
1933                 failure_finish(NULL);
1934                 return (0);
1935         }
1936         if (nomatch && sa.st_flags == sb.st_flags) {
1937                 failure_start(file, line, "File flags should be different: "
1938                     "%s=%#010x %s=%#010x", patha, sa.st_flags, pathb,
1939                     sb.st_flags);
1940                 failure_finish(NULL);
1941                 return (0);
1942         }
1943 #elif (defined(FS_IOC_GETFLAGS) && defined(HAVE_WORKING_FS_IOC_GETFLAGS) && \
1944        defined(FS_NODUMP_FL)) || \
1945       (defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS) \
1946          && defined(EXT2_NODUMP_FL))
1947         int fd, r, flagsa, flagsb;
1948
1949         assertion_count(file, line);
1950         fd = open(patha, O_RDONLY | O_NONBLOCK);
1951         if (fd < 0) {
1952                 failure_start(file, line, "Can't open %s\n", patha);
1953                 failure_finish(NULL);
1954                 return (0);
1955         }
1956         r = ioctl(fd,
1957 #ifdef FS_IOC_GETFLAGS
1958             FS_IOC_GETFLAGS,
1959 #else
1960             EXT2_IOC_GETFLAGS,
1961 #endif
1962             &flagsa);
1963         close(fd);
1964         if (r < 0) {
1965                 failure_start(file, line, "Can't get flags %s\n", patha);
1966                 failure_finish(NULL);
1967                 return (0);
1968         }
1969         fd = open(pathb, O_RDONLY | O_NONBLOCK);
1970         if (fd < 0) {
1971                 failure_start(file, line, "Can't open %s\n", pathb);
1972                 failure_finish(NULL);
1973                 return (0);
1974         }
1975         r = ioctl(fd,
1976 #ifdef FS_IOC_GETFLAGS
1977             FS_IOC_GETFLAGS,
1978 #else
1979             EXT2_IOC_GETFLAGS,
1980 #endif
1981             &flagsb);
1982         close(fd);
1983         if (r < 0) {
1984                 failure_start(file, line, "Can't get flags %s\n", pathb);
1985                 failure_finish(NULL);
1986                 return (0);
1987         }
1988         if (!nomatch && flagsa != flagsb) {
1989                 failure_start(file, line, "File flags should be identical: "
1990                     "%s=%#010x %s=%#010x", patha, flagsa, pathb, flagsb);
1991                 failure_finish(NULL);
1992                 return (0);
1993         }
1994         if (nomatch && flagsa == flagsb) {
1995                 failure_start(file, line, "File flags should be different: "
1996                     "%s=%#010x %s=%#010x", patha, flagsa, pathb, flagsb);
1997                 failure_finish(NULL);
1998                 return (0);
1999         }
2000 #else
2001         (void)patha; /* UNUSED */
2002         (void)pathb; /* UNUSED */
2003         (void)nomatch; /* UNUSED */
2004         assertion_count(file, line);
2005 #endif
2006         return (1);
2007 }
2008
2009 /* Set nodump, report failures. */
2010 int
2011 assertion_set_nodump(const char *file, int line, const char *pathname)
2012 {
2013 #if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP)
2014         int r;
2015
2016         assertion_count(file, line);
2017         r = chflags(pathname, UF_NODUMP);
2018         if (r < 0) {
2019                 failure_start(file, line, "Can't set nodump %s\n", pathname);
2020                 failure_finish(NULL);
2021                 return (0);
2022         }
2023 #elif (defined(FS_IOC_GETFLAGS) && defined(HAVE_WORKING_FS_IOC_GETFLAGS) && \
2024        defined(FS_NODUMP_FL)) || \
2025       (defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS) \
2026          && defined(EXT2_NODUMP_FL))
2027         int fd, r, flags;
2028
2029         assertion_count(file, line);
2030         fd = open(pathname, O_RDONLY | O_NONBLOCK);
2031         if (fd < 0) {
2032                 failure_start(file, line, "Can't open %s\n", pathname);
2033                 failure_finish(NULL);
2034                 return (0);
2035         }
2036         r = ioctl(fd,
2037 #ifdef FS_IOC_GETFLAGS
2038             FS_IOC_GETFLAGS,
2039 #else
2040             EXT2_IOC_GETFLAGS,
2041 #endif
2042             &flags);
2043         if (r < 0) {
2044                 failure_start(file, line, "Can't get flags %s\n", pathname);
2045                 failure_finish(NULL);
2046                 return (0);
2047         }
2048 #ifdef FS_NODUMP_FL
2049         flags |= FS_NODUMP_FL;
2050 #else
2051         flags |= EXT2_NODUMP_FL;
2052 #endif
2053
2054          r = ioctl(fd,
2055 #ifdef FS_IOC_SETFLAGS
2056             FS_IOC_SETFLAGS,
2057 #else
2058             EXT2_IOC_SETFLAGS,
2059 #endif
2060             &flags);
2061         if (r < 0) {
2062                 failure_start(file, line, "Can't set nodump %s\n", pathname);
2063                 failure_finish(NULL);
2064                 return (0);
2065         }
2066         close(fd);
2067 #else
2068         (void)pathname; /* UNUSED */
2069         assertion_count(file, line);
2070 #endif
2071         return (1);
2072 }
2073
2074 #ifdef PROGRAM
2075 static void assert_version_id(char **qq, size_t *ss)
2076 {
2077         char *q = *qq;
2078         size_t s = *ss;
2079
2080         /* Version number is a series of digits and periods. */
2081         while (s > 0 && (*q == '.' || (*q >= '0' && *q <= '9'))) {
2082                 ++q;
2083                 --s;
2084         }
2085
2086         if (q[0] == 'd' && q[1] == 'e' && q[2] == 'v') {
2087                 q += 3;
2088                 s -= 3;
2089         }
2090         
2091         /* Skip a single trailing a,b,c, or d. */
2092         if (*q == 'a' || *q == 'b' || *q == 'c' || *q == 'd')
2093                 ++q;
2094
2095         /* Version number terminated by space. */
2096         failure("No space after version: ``%s''", q);
2097         assert(s > 1);
2098         failure("No space after version: ``%s''", q);
2099         assert(*q == ' ');
2100
2101         ++q; --s;
2102
2103         *qq = q;
2104         *ss = s;
2105 }
2106
2107
2108 /*
2109  * Check program version
2110  */
2111 void assertVersion(const char *prog, const char *base)
2112 {
2113         int r;
2114         char *p, *q;
2115         size_t s;
2116         unsigned int prog_len = strlen(base);
2117
2118         r = systemf("%s --version >version.stdout 2>version.stderr", prog);
2119         if (r != 0)
2120                 r = systemf("%s -W version >version.stdout 2>version.stderr",
2121                     prog);
2122
2123         failure("Unable to run either %s --version or %s -W version",
2124                 prog, prog);
2125         if (!assert(r == 0))
2126                 return;
2127
2128         /* --version should generate nothing to stdout. */
2129         assertEmptyFile("version.stderr");
2130
2131         /* Verify format of version message. */
2132         q = p = slurpfile(&s, "version.stdout");
2133
2134         /* Version message should start with name of program, then space. */
2135         assert(s > prog_len + 1);
2136         
2137         failure("Version must start with '%s': ``%s''", base, p);
2138         if (!assertEqualMem(q, base, prog_len)) {
2139                 free(p);
2140                 return;
2141         }
2142
2143         q += prog_len; s -= prog_len;
2144
2145         assert(*q == ' ');
2146         q++; s--;
2147
2148         assert_version_id(&q, &s);
2149
2150         /* Separator. */
2151         failure("No `-' between program name and versions: ``%s''", p);
2152         assertEqualMem(q, "- ", 2);
2153         q += 2; s -= 2;
2154
2155         failure("Not long enough for libarchive version: ``%s''", p);
2156         assert(s > 11);
2157
2158         failure("Libarchive version must start with `libarchive': ``%s''", p);
2159         assertEqualMem(q, "libarchive ", 11);
2160
2161         q += 11; s -= 11;
2162
2163         assert_version_id(&q, &s);
2164
2165         /* Skip arbitrary third-party version numbers. */
2166         while (s > 0 && (*q == ' ' || *q == '-' || *q == '/' || *q == '.' ||
2167             isalnum(*q))) {
2168                 ++q;
2169                 --s;
2170         }
2171
2172         /* All terminated by end-of-line. */
2173         assert(s >= 1);
2174
2175         /* Skip an optional CR character (e.g., Windows) */
2176         failure("Version output must end with \\n or \\r\\n");
2177
2178         if (*q == '\r') { ++q; --s; }
2179         assertEqualMem(q, "\n", 1);
2180
2181         free(p);
2182 }
2183 #endif  /* PROGRAM */
2184
2185 /*
2186  *
2187  *  UTILITIES for use by tests.
2188  *
2189  */
2190
2191 /*
2192  * Check whether platform supports symlinks.  This is intended
2193  * for tests to use in deciding whether to bother testing symlink
2194  * support; if the platform doesn't support symlinks, there's no point
2195  * in checking whether the program being tested can create them.
2196  *
2197  * Note that the first time this test is called, we actually go out to
2198  * disk to create and verify a symlink.  This is necessary because
2199  * symlink support is actually a property of a particular filesystem
2200  * and can thus vary between directories on a single system.  After
2201  * the first call, this returns the cached result from memory, so it's
2202  * safe to call it as often as you wish.
2203  */
2204 int
2205 canSymlink(void)
2206 {
2207         /* Remember the test result */
2208         static int value = 0, tested = 0;
2209         if (tested)
2210                 return (value);
2211
2212         ++tested;
2213         assertion_make_file(__FILE__, __LINE__, "canSymlink.0", 0644, 1, "a");
2214         /* Note: Cygwin has its own symlink() emulation that does not
2215          * use the Win32 CreateSymbolicLink() function. */
2216 #if defined(_WIN32) && !defined(__CYGWIN__)
2217         value = my_CreateSymbolicLinkA("canSymlink.1", "canSymlink.0", 0)
2218             && is_symlink(__FILE__, __LINE__, "canSymlink.1", "canSymlink.0");
2219 #elif HAVE_SYMLINK
2220         value = (0 == symlink("canSymlink.0", "canSymlink.1"))
2221             && is_symlink(__FILE__, __LINE__, "canSymlink.1","canSymlink.0");
2222 #endif
2223         return (value);
2224 }
2225
2226 /* Platform-dependent options for hiding the output of a subcommand. */
2227 #if defined(_WIN32) && !defined(__CYGWIN__)
2228 static const char *redirectArgs = ">NUL 2>NUL"; /* Win32 cmd.exe */
2229 #else
2230 static const char *redirectArgs = ">/dev/null 2>/dev/null"; /* POSIX 'sh' */
2231 #endif
2232 /*
2233  * Can this platform run the bzip2 program?
2234  */
2235 int
2236 canBzip2(void)
2237 {
2238         static int tested = 0, value = 0;
2239         if (!tested) {
2240                 tested = 1;
2241                 if (systemf("bzip2 -d -V %s", redirectArgs) == 0)
2242                         value = 1;
2243         }
2244         return (value);
2245 }
2246
2247 /*
2248  * Can this platform run the grzip program?
2249  */
2250 int
2251 canGrzip(void)
2252 {
2253         static int tested = 0, value = 0;
2254         if (!tested) {
2255                 tested = 1;
2256                 if (systemf("grzip -V %s", redirectArgs) == 0)
2257                         value = 1;
2258         }
2259         return (value);
2260 }
2261
2262 /*
2263  * Can this platform run the gzip program?
2264  */
2265 int
2266 canGzip(void)
2267 {
2268         static int tested = 0, value = 0;
2269         if (!tested) {
2270                 tested = 1;
2271                 if (systemf("gzip -V %s", redirectArgs) == 0)
2272                         value = 1;
2273         }
2274         return (value);
2275 }
2276
2277 /*
2278  * Can this platform run the lrzip program?
2279  */
2280 int
2281 canRunCommand(const char *cmd)
2282 {
2283   static int tested = 0, value = 0;
2284   if (!tested) {
2285     tested = 1;
2286     if (systemf("%s %s", cmd, redirectArgs) == 0)
2287       value = 1;
2288   }
2289   return (value);
2290 }
2291
2292 int
2293 canLrzip(void)
2294 {
2295         static int tested = 0, value = 0;
2296         if (!tested) {
2297                 tested = 1;
2298                 if (systemf("lrzip -V %s", redirectArgs) == 0)
2299                         value = 1;
2300         }
2301         return (value);
2302 }
2303
2304 /*
2305  * Can this platform run the lz4 program?
2306  */
2307 int
2308 canLz4(void)
2309 {
2310         static int tested = 0, value = 0;
2311         if (!tested) {
2312                 tested = 1;
2313                 if (systemf("lz4 -V %s", redirectArgs) == 0)
2314                         value = 1;
2315         }
2316         return (value);
2317 }
2318
2319 /*
2320  * Can this platform run the lzip program?
2321  */
2322 int
2323 canLzip(void)
2324 {
2325         static int tested = 0, value = 0;
2326         if (!tested) {
2327                 tested = 1;
2328                 if (systemf("lzip -V %s", redirectArgs) == 0)
2329                         value = 1;
2330         }
2331         return (value);
2332 }
2333
2334 /*
2335  * Can this platform run the lzma program?
2336  */
2337 int
2338 canLzma(void)
2339 {
2340         static int tested = 0, value = 0;
2341         if (!tested) {
2342                 tested = 1;
2343                 if (systemf("lzma -V %s", redirectArgs) == 0)
2344                         value = 1;
2345         }
2346         return (value);
2347 }
2348
2349 /*
2350  * Can this platform run the lzop program?
2351  */
2352 int
2353 canLzop(void)
2354 {
2355         static int tested = 0, value = 0;
2356         if (!tested) {
2357                 tested = 1;
2358                 if (systemf("lzop -V %s", redirectArgs) == 0)
2359                         value = 1;
2360         }
2361         return (value);
2362 }
2363
2364 /*
2365  * Can this platform run the xz program?
2366  */
2367 int
2368 canXz(void)
2369 {
2370         static int tested = 0, value = 0;
2371         if (!tested) {
2372                 tested = 1;
2373                 if (systemf("xz -V %s", redirectArgs) == 0)
2374                         value = 1;
2375         }
2376         return (value);
2377 }
2378
2379 /*
2380  * Can this filesystem handle nodump flags.
2381  */
2382 int
2383 canNodump(void)
2384 {
2385 #if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP)
2386         const char *path = "cannodumptest";
2387         struct stat sb;
2388
2389         assertion_make_file(__FILE__, __LINE__, path, 0644, 0, NULL);
2390         if (chflags(path, UF_NODUMP) < 0)
2391                 return (0);
2392         if (stat(path, &sb) < 0)
2393                 return (0);
2394         if (sb.st_flags & UF_NODUMP)
2395                 return (1);
2396 #elif (defined(FS_IOC_GETFLAGS) && defined(HAVE_WORKING_FS_IOC_GETFLAGS) \
2397          && defined(FS_NODUMP_FL)) || \
2398       (defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS) \
2399          && defined(EXT2_NODUMP_FL))
2400         const char *path = "cannodumptest";
2401         int fd, r, flags;
2402
2403         assertion_make_file(__FILE__, __LINE__, path, 0644, 0, NULL);
2404         fd = open(path, O_RDONLY | O_NONBLOCK);
2405         if (fd < 0)
2406                 return (0);
2407         r = ioctl(fd,
2408 #ifdef FS_IOC_GETFLAGS
2409             FS_IOC_GETFLAGS,
2410 #else
2411             EXT2_IOC_GETFLAGS,
2412 #endif
2413             &flags);
2414         if (r < 0)
2415                 return (0);
2416 #ifdef FS_NODUMP_FL
2417         flags |= FS_NODUMP_FL;
2418 #else
2419         flags |= EXT2_NODUMP_FL;
2420 #endif
2421         r = ioctl(fd,
2422 #ifdef FS_IOC_SETFLAGS
2423             FS_IOC_SETFLAGS,
2424 #else
2425             EXT2_IOC_SETFLAGS,
2426 #endif
2427            &flags);
2428         if (r < 0)
2429                 return (0);
2430         close(fd);
2431         fd = open(path, O_RDONLY | O_NONBLOCK);
2432         if (fd < 0)
2433                 return (0);
2434         r = ioctl(fd,
2435 #ifdef FS_IOC_GETFLAGS
2436             FS_IOC_GETFLAGS,
2437 #else
2438             EXT2_IOC_GETFLAGS,
2439 #endif
2440             &flags);
2441         if (r < 0)
2442                 return (0);
2443         close(fd);
2444 #ifdef FS_NODUMP_FL
2445         if (flags & FS_NODUMP_FL)
2446 #else
2447         if (flags & EXT2_NODUMP_FL)
2448 #endif
2449                 return (1);
2450 #endif
2451         return (0);
2452 }
2453
2454 /* Get extended attribute from a path */
2455 const void *
2456 getXattr(const char *path, const char *name, size_t *sizep)
2457
2458         void *value = NULL;
2459 #if ARCHIVE_XATTR_SUPPORT
2460         ssize_t size;
2461 #if ARCHIVE_XATTR_LINUX
2462         size = lgetxattr(path, name, NULL, 0);
2463 #elif ARCHIVE_XATTR_DARWIN
2464         size = getxattr(path, name, NULL, 0, 0, XATTR_NOFOLLOW);
2465 #elif ARCHIVE_XATTR_AIX
2466         size = lgetea(path, name, NULL, 0);
2467 #elif ARCHIVE_XATTR_FREEBSD
2468         size = extattr_get_link(path, EXTATTR_NAMESPACE_USER, name + 5,
2469             NULL, 0);
2470 #endif
2471
2472         if (size >= 0) {
2473                 value = malloc(size);
2474 #if ARCHIVE_XATTR_LINUX
2475                 size = lgetxattr(path, name, value, size);
2476 #elif ARCHIVE_XATTR_DARWIN
2477                 size = getxattr(path, name, value, size, 0, XATTR_NOFOLLOW);
2478 #elif ARCHIVE_XATTR_AIX
2479                 size = lgetea(path, name, value, size);
2480 #elif ARCHIVE_XATTR_FREEBSD
2481                 size = extattr_get_link(path, EXTATTR_NAMESPACE_USER, name + 5,
2482                     value, size);
2483 #endif
2484                 if (size < 0) {
2485                         free(value);
2486                         value = NULL;
2487                 }
2488         }
2489         if (size < 0)
2490                 *sizep = 0;
2491         else
2492                 *sizep = (size_t)size;
2493 #else   /* !ARCHIVE_XATTR_SUPPORT */
2494         (void)path;     /* UNUSED */
2495         (void)name;     /* UNUSED */
2496         *sizep = 0;
2497 #endif  /* !ARCHIVE_XATTR_SUPPORT */
2498         return (value);
2499 }
2500
2501 /*
2502  * Set extended attribute on a path
2503  * Returns 0 on error, 1 on success
2504  */
2505 int
2506 setXattr(const char *path, const char *name, const void *value, size_t size)
2507 {
2508 #if ARCHIVE_XATTR_SUPPORT
2509 #if ARCHIVE_XATTR_LINUX
2510         if (lsetxattr(path, name, value, size, 0) == 0)
2511 #elif ARCHIVE_XATTR_DARWIN
2512         if (setxattr(path, name, value, size, 0, XATTR_NOFOLLOW) == 0)
2513 #elif ARCHIVE_XATTR_AIX
2514         if (lsetea(path, name, value, size, 0) == 0)
2515 #elif ARCHIVE_XATTR_FREEBSD
2516         if (extattr_set_link(path, EXTATTR_NAMESPACE_USER, name + 5, value,
2517             size) > -1)
2518 #else
2519         if (0)
2520 #endif
2521                 return (1);
2522 #else   /* !ARCHIVE_XATTR_SUPPORT */
2523         (void)path;     /* UNUSED */
2524         (void)name;     /* UNUSED */
2525         (void)value;    /* UNUSED */
2526         (void)size;     /* UNUSED */
2527 #endif  /* !ARCHIVE_XATTR_SUPPORT */
2528         return (0);
2529 }
2530
2531 #if ARCHIVE_ACL_SUNOS
2532 /* Fetch ACLs on Solaris using acl() or facl() */
2533 void *
2534 sunacl_get(int cmd, int *aclcnt, int fd, const char *path)
2535 {
2536         int cnt, cntcmd;
2537         size_t size;
2538         void *aclp;
2539
2540         if (cmd == GETACL) {
2541                 cntcmd = GETACLCNT;
2542                 size = sizeof(aclent_t);
2543         }
2544 #if ARCHIVE_ACL_SUNOS_NFS4
2545         else if (cmd == ACE_GETACL) {
2546                 cntcmd = ACE_GETACLCNT;
2547                 size = sizeof(ace_t);
2548         }
2549 #endif
2550         else {
2551                 errno = EINVAL;
2552                 *aclcnt = -1;
2553                 return (NULL);
2554         }
2555
2556         aclp = NULL;
2557         cnt = -2;
2558         while (cnt == -2 || (cnt == -1 && errno == ENOSPC)) {
2559                 if (path != NULL)
2560                         cnt = acl(path, cntcmd, 0, NULL);
2561                 else
2562                         cnt = facl(fd, cntcmd, 0, NULL);
2563
2564                 if (cnt > 0) {
2565                         if (aclp == NULL)
2566                                 aclp = malloc(cnt * size);
2567                         else
2568                                 aclp = realloc(NULL, cnt * size);
2569                         if (aclp != NULL) {
2570                                 if (path != NULL)
2571                                         cnt = acl(path, cmd, cnt, aclp);
2572                                 else
2573                                         cnt = facl(fd, cmd, cnt, aclp);
2574                         }
2575                 } else {
2576                         if (aclp != NULL) {
2577                                 free(aclp);
2578                                 aclp = NULL;
2579                         }
2580                         break;
2581                 }
2582         }
2583
2584         *aclcnt = cnt;
2585         return (aclp);
2586 }
2587 #endif /* ARCHIVE_ACL_SUNOS */
2588
2589 /*
2590  * Set test ACLs on a path
2591  * Return values:
2592  * 0: error setting ACLs
2593  * ARCHIVE_TEST_ACL_TYPE_POSIX1E: POSIX.1E ACLs have been set
2594  * ARCHIVE_TEST_ACL_TYPE_NFS4: NFSv4 or extended ACLs have been set
2595  */
2596 int
2597 setTestAcl(const char *path)
2598 {
2599 #if ARCHIVE_ACL_SUPPORT
2600         int r = 1;
2601 #if ARCHIVE_ACL_LIBACL || ARCHIVE_ACL_FREEBSD || ARCHIVE_ACL_DARWIN
2602         acl_t acl;
2603 #endif
2604 #if ARCHIVE_ACL_LIBRICHACL
2605         struct richacl *richacl;
2606 #endif
2607 #if ARCHIVE_ACL_LIBACL || ARCHIVE_ACL_FREEBSD
2608         const char *acltext_posix1e = "user:1:rw-,"
2609             "group:15:r-x,"
2610             "user::rwx,"
2611             "group::rwx,"
2612             "other::r-x,"
2613             "mask::rwx";
2614 #elif ARCHIVE_ACL_SUNOS /* Solaris POSIX.1e */
2615         aclent_t aclp_posix1e[] = {
2616             { USER_OBJ, -1, 4 | 2 | 1 },
2617             { USER, 1, 4 | 2 },
2618             { GROUP_OBJ, -1, 4 | 2 | 1 },
2619             { GROUP, 15, 4 | 1 },
2620             { CLASS_OBJ, -1, 4 | 2 | 1 },
2621             { OTHER_OBJ, -1, 4 | 2 | 1 }
2622         };
2623 #endif
2624 #if ARCHIVE_ACL_FREEBSD /* FreeBSD NFS4 */
2625         const char *acltext_nfs4 = "user:1:rwpaRcs::allow:1,"
2626             "group:15:rxaRcs::allow:15,"
2627             "owner@:rwpxaARWcCos::allow,"
2628             "group@:rwpxaRcs::allow,"
2629             "everyone@:rxaRcs::allow";
2630 #elif ARCHIVE_ACL_LIBRICHACL
2631         const char *acltext_nfs4 = "owner:rwpxaARWcCoS::mask,"
2632             "group:rwpxaRcS::mask,"
2633             "other:rxaRcS::mask,"
2634             "user:1:rwpaRcS::allow,"
2635             "group:15:rxaRcS::allow,"
2636             "owner@:rwpxaARWcCoS::allow,"
2637             "group@:rwpxaRcS::allow,"
2638             "everyone@:rxaRcS::allow";
2639 #elif ARCHIVE_ACL_SUNOS_NFS4 /* Solaris NFS4 */
2640         ace_t aclp_nfs4[] = {
2641             { 1, ACE_READ_DATA | ACE_WRITE_DATA | ACE_APPEND_DATA |
2642               ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS | ACE_READ_ACL |
2643               ACE_SYNCHRONIZE, 0, ACE_ACCESS_ALLOWED_ACE_TYPE },
2644             { 15, ACE_READ_DATA | ACE_EXECUTE | ACE_READ_ATTRIBUTES |
2645               ACE_READ_NAMED_ATTRS | ACE_READ_ACL | ACE_SYNCHRONIZE,
2646               ACE_IDENTIFIER_GROUP, ACE_ACCESS_ALLOWED_ACE_TYPE },
2647             { -1, ACE_READ_DATA | ACE_WRITE_DATA | ACE_APPEND_DATA |
2648               ACE_EXECUTE | ACE_READ_ATTRIBUTES | ACE_WRITE_ATTRIBUTES |
2649               ACE_READ_NAMED_ATTRS | ACE_WRITE_NAMED_ATTRS |
2650               ACE_READ_ACL | ACE_WRITE_ACL | ACE_WRITE_OWNER | ACE_SYNCHRONIZE,
2651               ACE_OWNER, ACE_ACCESS_ALLOWED_ACE_TYPE },
2652             { -1, ACE_READ_DATA | ACE_WRITE_DATA | ACE_APPEND_DATA |
2653               ACE_EXECUTE | ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS |
2654               ACE_READ_ACL | ACE_SYNCHRONIZE, ACE_GROUP | ACE_IDENTIFIER_GROUP,
2655               ACE_ACCESS_ALLOWED_ACE_TYPE },
2656             { -1, ACE_READ_DATA | ACE_EXECUTE | ACE_READ_ATTRIBUTES |
2657               ACE_READ_NAMED_ATTRS | ACE_READ_ACL | ACE_SYNCHRONIZE,
2658               ACE_EVERYONE, ACE_ACCESS_ALLOWED_ACE_TYPE }
2659         };
2660 #elif ARCHIVE_ACL_DARWIN /* Mac OS X */
2661         acl_entry_t aclent;
2662         acl_permset_t permset;
2663         const uid_t uid = 1;
2664         uuid_t uuid;
2665         int i;
2666         const acl_perm_t acl_perms[] = {
2667                 ACL_READ_DATA,
2668                 ACL_WRITE_DATA,
2669                 ACL_APPEND_DATA,
2670                 ACL_EXECUTE,
2671                 ACL_READ_ATTRIBUTES,
2672                 ACL_READ_EXTATTRIBUTES,
2673                 ACL_READ_SECURITY,
2674 #if HAVE_DECL_ACL_SYNCHRONIZE
2675                 ACL_SYNCHRONIZE
2676 #endif
2677         };
2678 #endif /* ARCHIVE_ACL_DARWIN */
2679
2680 #if ARCHIVE_ACL_FREEBSD
2681         acl = acl_from_text(acltext_nfs4);
2682         failure("acl_from_text() error: %s", strerror(errno));
2683         if (assert(acl != NULL) == 0)
2684                 return (0);
2685 #elif ARCHIVE_ACL_LIBRICHACL
2686         richacl = richacl_from_text(acltext_nfs4, NULL, NULL);
2687         failure("richacl_from_text() error: %s", strerror(errno));
2688         if (assert(richacl != NULL) == 0)
2689                 return (0);
2690 #elif ARCHIVE_ACL_DARWIN
2691         acl = acl_init(1);
2692         failure("acl_init() error: %s", strerror(errno));
2693         if (assert(acl != NULL) == 0)
2694                 return (0);
2695         r = acl_create_entry(&acl, &aclent);
2696         failure("acl_create_entry() error: %s", strerror(errno));
2697         if (assertEqualInt(r, 0) == 0)
2698                 goto testacl_free;
2699         r = acl_set_tag_type(aclent, ACL_EXTENDED_ALLOW);
2700         failure("acl_set_tag_type() error: %s", strerror(errno));
2701         if (assertEqualInt(r, 0) == 0)
2702                 goto testacl_free;
2703         r = acl_get_permset(aclent, &permset);
2704         failure("acl_get_permset() error: %s", strerror(errno));
2705         if (assertEqualInt(r, 0) == 0)
2706                 goto testacl_free;
2707         for (i = 0; i < (int)(sizeof(acl_perms) / sizeof(acl_perms[0])); i++) {
2708                 r = acl_add_perm(permset, acl_perms[i]);
2709                 failure("acl_add_perm() error: %s", strerror(errno));
2710                 if (assertEqualInt(r, 0) == 0)
2711                         goto testacl_free;
2712         }
2713         r = acl_set_permset(aclent, permset);
2714         failure("acl_set_permset() error: %s", strerror(errno));
2715         if (assertEqualInt(r, 0) == 0)
2716                 goto testacl_free;
2717         r = mbr_uid_to_uuid(uid, uuid);
2718         failure("mbr_uid_to_uuid() error: %s", strerror(errno));
2719         if (assertEqualInt(r, 0) == 0)
2720                 goto testacl_free;
2721         r = acl_set_qualifier(aclent, uuid);
2722         failure("acl_set_qualifier() error: %s", strerror(errno));
2723         if (assertEqualInt(r, 0) == 0)
2724                 goto testacl_free;
2725 #endif /* ARCHIVE_ACL_DARWIN */
2726
2727 #if ARCHIVE_ACL_NFS4
2728 #if ARCHIVE_ACL_FREEBSD
2729         r = acl_set_file(path, ACL_TYPE_NFS4, acl);
2730         acl_free(acl);
2731 #elif ARCHIVE_ACL_LIBRICHACL
2732         r = richacl_set_file(path, richacl);
2733         richacl_free(richacl);
2734 #elif ARCHIVE_ACL_SUNOS_NFS4
2735         r = acl(path, ACE_SETACL,
2736             (int)(sizeof(aclp_nfs4)/sizeof(aclp_nfs4[0])), aclp_nfs4);
2737 #elif ARCHIVE_ACL_DARWIN
2738         r = acl_set_file(path, ACL_TYPE_EXTENDED, acl);
2739         acl_free(acl);
2740 #endif
2741         if (r == 0)
2742                 return (ARCHIVE_TEST_ACL_TYPE_NFS4);
2743 #endif  /* ARCHIVE_ACL_NFS4 */
2744
2745 #if ARCHIVE_ACL_POSIX1E
2746 #if ARCHIVE_ACL_FREEBSD || ARCHIVE_ACL_LIBACL
2747         acl = acl_from_text(acltext_posix1e);
2748         failure("acl_from_text() error: %s", strerror(errno));
2749         if (assert(acl != NULL) == 0)
2750                 return (0);
2751
2752         r = acl_set_file(path, ACL_TYPE_ACCESS, acl);
2753         acl_free(acl);
2754 #elif ARCHIVE_ACL_SUNOS
2755         r = acl(path, SETACL,
2756             (int)(sizeof(aclp_posix1e)/sizeof(aclp_posix1e[0])), aclp_posix1e);
2757 #endif
2758         if (r == 0)
2759                 return (ARCHIVE_TEST_ACL_TYPE_POSIX1E);
2760         else
2761                 return (0);
2762 #endif /* ARCHIVE_ACL_POSIX1E */
2763 #if ARCHIVE_ACL_DARWIN
2764 testacl_free:
2765         acl_free(acl);
2766 #endif
2767 #endif /* ARCHIVE_ACL_SUPPORT */
2768         (void)path;     /* UNUSED */
2769         return (0);
2770 }
2771
2772 /*
2773  * Sleep as needed; useful for verifying disk timestamp changes by
2774  * ensuring that the wall-clock time has actually changed before we
2775  * go back to re-read something from disk.
2776  */
2777 void
2778 sleepUntilAfter(time_t t)
2779 {
2780         while (t >= time(NULL))
2781 #if defined(_WIN32) && !defined(__CYGWIN__)
2782                 Sleep(500);
2783 #else
2784                 sleep(1);
2785 #endif
2786 }
2787
2788 /*
2789  * Call standard system() call, but build up the command line using
2790  * sprintf() conventions.
2791  */
2792 int
2793 systemf(const char *fmt, ...)
2794 {
2795         char buff[8192];
2796         va_list ap;
2797         int r;
2798
2799         va_start(ap, fmt);
2800         vsprintf(buff, fmt, ap);
2801         if (verbosity > VERBOSITY_FULL)
2802                 logprintf("Cmd: %s\n", buff);
2803         r = system(buff);
2804         va_end(ap);
2805         return (r);
2806 }
2807
2808 /*
2809  * Slurp a file into memory for ease of comparison and testing.
2810  * Returns size of file in 'sizep' if non-NULL, null-terminates
2811  * data in memory for ease of use.
2812  */
2813 char *
2814 slurpfile(size_t * sizep, const char *fmt, ...)
2815 {
2816         char filename[8192];
2817         struct stat st;
2818         va_list ap;
2819         char *p;
2820         ssize_t bytes_read;
2821         FILE *f;
2822         int r;
2823
2824         va_start(ap, fmt);
2825         vsprintf(filename, fmt, ap);
2826         va_end(ap);
2827
2828         f = fopen(filename, "rb");
2829         if (f == NULL) {
2830                 /* Note: No error; non-existent file is okay here. */
2831                 return (NULL);
2832         }
2833         r = fstat(fileno(f), &st);
2834         if (r != 0) {
2835                 logprintf("Can't stat file %s\n", filename);
2836                 fclose(f);
2837                 return (NULL);
2838         }
2839         p = malloc((size_t)st.st_size + 1);
2840         if (p == NULL) {
2841                 logprintf("Can't allocate %ld bytes of memory to read file %s\n",
2842                     (long int)st.st_size, filename);
2843                 fclose(f);
2844                 return (NULL);
2845         }
2846         bytes_read = fread(p, 1, (size_t)st.st_size, f);
2847         if (bytes_read < st.st_size) {
2848                 logprintf("Can't read file %s\n", filename);
2849                 fclose(f);
2850                 free(p);
2851                 return (NULL);
2852         }
2853         p[st.st_size] = '\0';
2854         if (sizep != NULL)
2855                 *sizep = (size_t)st.st_size;
2856         fclose(f);
2857         return (p);
2858 }
2859
2860 /*
2861  * Slurp a file into memory for ease of comparison and testing.
2862  * Returns size of file in 'sizep' if non-NULL, null-terminates
2863  * data in memory for ease of use.
2864  */
2865 void
2866 dumpfile(const char *filename, void *data, size_t len)
2867 {
2868         ssize_t bytes_written;
2869         FILE *f;
2870
2871         f = fopen(filename, "wb");
2872         if (f == NULL) {
2873                 logprintf("Can't open file %s for writing\n", filename);
2874                 return;
2875         }
2876         bytes_written = fwrite(data, 1, len, f);
2877         if (bytes_written < (ssize_t)len)
2878                 logprintf("Can't write file %s\n", filename);
2879         fclose(f);
2880 }
2881
2882 /* Read a uuencoded file from the reference directory, decode, and
2883  * write the result into the current directory. */
2884 #define VALID_UUDECODE(c) (c >= 32 && c <= 96)
2885 #define UUDECODE(c) (((c) - 0x20) & 0x3f)
2886 void
2887 extract_reference_file(const char *name)
2888 {
2889         char buff[1024];
2890         FILE *in, *out;
2891
2892         sprintf(buff, "%s/%s.uu", refdir, name);
2893         in = fopen(buff, "r");
2894         failure("Couldn't open reference file %s", buff);
2895         assert(in != NULL);
2896         if (in == NULL)
2897                 return;
2898         /* Read up to and including the 'begin' line. */
2899         for (;;) {
2900                 if (fgets(buff, sizeof(buff), in) == NULL) {
2901                         /* TODO: This is a failure. */
2902                         return;
2903                 }
2904                 if (memcmp(buff, "begin ", 6) == 0)
2905                         break;
2906         }
2907         /* Now, decode the rest and write it. */
2908         out = fopen(name, "wb");
2909         while (fgets(buff, sizeof(buff), in) != NULL) {
2910                 char *p = buff;
2911                 int bytes;
2912
2913                 if (memcmp(buff, "end", 3) == 0)
2914                         break;
2915
2916                 bytes = UUDECODE(*p++);
2917                 while (bytes > 0) {
2918                         int n = 0;
2919                         /* Write out 1-3 bytes from that. */
2920                         if (bytes > 0) {
2921                                 assert(VALID_UUDECODE(p[0]));
2922                                 assert(VALID_UUDECODE(p[1]));
2923                                 n = UUDECODE(*p++) << 18;
2924                                 n |= UUDECODE(*p++) << 12;
2925                                 fputc(n >> 16, out);
2926                                 --bytes;
2927                         }
2928                         if (bytes > 0) {
2929                                 assert(VALID_UUDECODE(p[0]));
2930                                 n |= UUDECODE(*p++) << 6;
2931                                 fputc((n >> 8) & 0xFF, out);
2932                                 --bytes;
2933                         }
2934                         if (bytes > 0) {
2935                                 assert(VALID_UUDECODE(p[0]));
2936                                 n |= UUDECODE(*p++);
2937                                 fputc(n & 0xFF, out);
2938                                 --bytes;
2939                         }
2940                 }
2941         }
2942         fclose(out);
2943         fclose(in);
2944 }
2945
2946 void
2947 copy_reference_file(const char *name)
2948 {
2949         char buff[1024];
2950         FILE *in, *out;
2951         size_t rbytes;
2952
2953         sprintf(buff, "%s/%s", refdir, name);
2954         in = fopen(buff, "rb");
2955         failure("Couldn't open reference file %s", buff);
2956         assert(in != NULL);
2957         if (in == NULL)
2958                 return;
2959         /* Now, decode the rest and write it. */
2960         /* Not a lot of error checking here; the input better be right. */
2961         out = fopen(name, "wb");
2962         while ((rbytes = fread(buff, 1, sizeof(buff), in)) > 0) {
2963                 if (fwrite(buff, 1, rbytes, out) != rbytes) {
2964                         logprintf("Error: fwrite\n");
2965                         break;
2966                 }
2967         }
2968         fclose(out);
2969         fclose(in);
2970 }
2971
2972 int
2973 is_LargeInode(const char *file)
2974 {
2975 #if defined(_WIN32) && !defined(__CYGWIN__)
2976         BY_HANDLE_FILE_INFORMATION bhfi;
2977         int r;
2978
2979         r = my_GetFileInformationByName(file, &bhfi);
2980         if (r != 0)
2981                 return (0);
2982         return (bhfi.nFileIndexHigh & 0x0000FFFFUL);
2983 #else
2984         struct stat st;
2985         int64_t ino;
2986
2987         if (stat(file, &st) < 0)
2988                 return (0);
2989         ino = (int64_t)st.st_ino;
2990         return (ino > 0xffffffff);
2991 #endif
2992 }
2993
2994 void
2995 extract_reference_files(const char **names)
2996 {
2997         while (names && *names)
2998                 extract_reference_file(*names++);
2999 }
3000
3001 #ifndef PROGRAM
3002 /* Set ACLs */
3003 int
3004 assertion_entry_set_acls(const char *file, int line, struct archive_entry *ae,
3005     struct archive_test_acl_t *acls, int n)
3006 {
3007         int i, r, ret;
3008
3009         assertion_count(file, line);
3010
3011         ret = 0;
3012         archive_entry_acl_clear(ae);
3013         for (i = 0; i < n; i++) {
3014                 r = archive_entry_acl_add_entry(ae,
3015                     acls[i].type, acls[i].permset, acls[i].tag,
3016                     acls[i].qual, acls[i].name);
3017                 if (r != 0) {
3018                         ret = 1;
3019                         failure_start(file, line, "type=%#010x, ",
3020                             "permset=%#010x, tag=%d, qual=%d name=%s",
3021                             acls[i].type, acls[i].permset, acls[i].tag,
3022                             acls[i].qual, acls[i].name);
3023                         failure_finish(NULL);
3024                 }
3025         }
3026
3027         return (ret);
3028 }
3029
3030 static int
3031 archive_test_acl_match(struct archive_test_acl_t *acl, int type, int permset,
3032     int tag, int qual, const char *name)
3033 {
3034         if (type != acl->type)
3035                 return (0);
3036         if (permset != acl->permset)
3037                 return (0);
3038         if (tag != acl->tag)
3039                 return (0);
3040         if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ)
3041                 return (1);
3042         if (tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ)
3043                 return (1);
3044         if (tag == ARCHIVE_ENTRY_ACL_EVERYONE)
3045                 return (1);
3046         if (tag == ARCHIVE_ENTRY_ACL_OTHER)
3047                 return (1);
3048         if (qual != acl->qual)
3049                 return (0);
3050         if (name == NULL) {
3051                 if (acl->name == NULL || acl->name[0] == '\0')
3052                         return (1);
3053                 return (0);
3054         }
3055         if (acl->name == NULL) {
3056                 if (name[0] == '\0')
3057                         return (1);
3058                 return (0);
3059         }
3060         return (0 == strcmp(name, acl->name));
3061 }
3062
3063 /* Compare ACLs */
3064 int
3065 assertion_entry_compare_acls(const char *file, int line,
3066     struct archive_entry *ae, struct archive_test_acl_t *acls, int cnt,
3067     int want_type, int mode)
3068 {
3069         int *marker;
3070         int i, r, n, ret;
3071         int type, permset, tag, qual;
3072         int matched;
3073         const char *name;
3074
3075         assertion_count(file, line);
3076
3077         ret = 0;
3078         n = 0;
3079         marker = malloc(sizeof(marker[0]) * cnt);
3080
3081         for (i = 0; i < cnt; i++) {
3082                 if ((acls[i].type & want_type) != 0) {
3083                         marker[n] = i;
3084                         n++;
3085                 }
3086         }
3087
3088         if (n == 0) {
3089                 failure_start(file, line, "No ACL's to compare, type mask: %d",
3090                     want_type);
3091                 return (1);
3092         }
3093
3094         while (0 == (r = archive_entry_acl_next(ae, want_type,
3095                          &type, &permset, &tag, &qual, &name))) {
3096                 for (i = 0, matched = 0; i < n && !matched; i++) {
3097                         if (archive_test_acl_match(&acls[marker[i]], type,
3098                             permset, tag, qual, name)) {
3099                                 /* We found a match; remove it. */
3100                                 marker[i] = marker[n - 1];
3101                                 n--;
3102                                 matched = 1;
3103                         }
3104                 }
3105                 if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS
3106                     && tag == ARCHIVE_ENTRY_ACL_USER_OBJ) {
3107                         if (!matched) {
3108                                 failure_start(file, line, "No match for "
3109                                     "user_obj perm");
3110                                 failure_finish(NULL);
3111                                 ret = 1;
3112                         }
3113                         if ((permset << 6) != (mode & 0700)) {
3114                                 failure_start(file, line, "USER_OBJ permset "
3115                                     "(%02o) != user mode (%02o)", permset,
3116                                     07 & (mode >> 6));
3117                                 failure_finish(NULL);
3118                                 ret = 1;
3119                         }
3120                 } else if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS
3121                     && tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ) {
3122                         if (!matched) {
3123                                 failure_start(file, line, "No match for "
3124                                     "group_obj perm");
3125                                 failure_finish(NULL);
3126                                 ret = 1;
3127                         }
3128                         if ((permset << 3) != (mode & 0070)) {
3129                                 failure_start(file, line, "GROUP_OBJ permset "
3130                                     "(%02o) != group mode (%02o)", permset,
3131                                     07 & (mode >> 3));
3132                                 failure_finish(NULL);
3133                                 ret = 1;
3134                         }
3135                 } else if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS
3136                     && tag == ARCHIVE_ENTRY_ACL_OTHER) {
3137                         if (!matched) {
3138                                 failure_start(file, line, "No match for "
3139                                     "other perm");
3140                                 failure_finish(NULL);
3141                                 ret = 1;
3142                         }
3143                         if ((permset << 0) != (mode & 0007)) {
3144                                 failure_start(file, line, "OTHER permset "
3145                                     "(%02o) != other mode (%02o)", permset,
3146                                     mode & 07);
3147                                 failure_finish(NULL);
3148                                 ret = 1;
3149                         }
3150                 } else if (matched != 1) {
3151                         failure_start(file, line, "Could not find match for "
3152                             "ACL (type=%#010x,permset=%#010x,tag=%d,qual=%d,"
3153                             "name=``%s'')", type, permset, tag, qual, name);
3154                         failure_finish(NULL);
3155                         ret = 1;
3156                 }
3157         }
3158         if (r != ARCHIVE_EOF) {
3159                 failure_start(file, line, "Should not exit before EOF");
3160                 failure_finish(NULL);
3161                 ret = 1;
3162         }
3163         if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0 &&
3164             (mode_t)(mode & 0777) != (archive_entry_mode(ae) & 0777)) {
3165                 failure_start(file, line, "Mode (%02o) and entry mode (%02o) "
3166                     "mismatch", mode, archive_entry_mode(ae));
3167                 failure_finish(NULL);
3168                 ret = 1;
3169         }
3170         if (n != 0) {
3171                 failure_start(file, line, "Could not find match for ACL "
3172                     "(type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s'')",
3173                     acls[marker[0]].type, acls[marker[0]].permset,
3174                     acls[marker[0]].tag, acls[marker[0]].qual,
3175                     acls[marker[0]].name);
3176                 failure_finish(NULL);
3177                 ret = 1;
3178                 /* Number of ACLs not matched should == 0 */
3179         }
3180         free(marker);
3181         return (ret);
3182 }
3183 #endif  /* !defined(PROGRAM) */
3184
3185 /*
3186  *
3187  * TEST management
3188  *
3189  */
3190
3191 /*
3192  * "list.h" is simply created by "grep DEFINE_TEST test_*.c"; it has
3193  * a line like
3194  *      DEFINE_TEST(test_function)
3195  * for each test.
3196  */
3197
3198 /* Use "list.h" to declare all of the test functions. */
3199 #undef DEFINE_TEST
3200 #define DEFINE_TEST(name) void name(void);
3201 #include "list.h"
3202
3203 /* Use "list.h" to create a list of all tests (functions and names). */
3204 #undef DEFINE_TEST
3205 #define DEFINE_TEST(n) { n, #n, 0 },
3206 struct test_list_t tests[] = {
3207         #include "list.h"
3208 };
3209
3210 /*
3211  * Summarize repeated failures in the just-completed test.
3212  */
3213 static void
3214 test_summarize(int failed, int skips_num)
3215 {
3216         unsigned int i;
3217
3218         switch (verbosity) {
3219         case VERBOSITY_SUMMARY_ONLY:
3220                 printf(failed ? "E" : ".");
3221                 fflush(stdout);
3222                 break;
3223         case VERBOSITY_PASSFAIL:
3224                 printf(failed ? "FAIL\n" : skips_num ? "ok (S)\n" : "ok\n");
3225                 break;
3226         }
3227
3228         log_console = (verbosity == VERBOSITY_LIGHT_REPORT);
3229
3230         for (i = 0; i < sizeof(failed_lines)/sizeof(failed_lines[0]); i++) {
3231                 if (failed_lines[i].count > 1 && !failed_lines[i].skip)
3232                         logprintf("%s:%d: Summary: Failed %d times\n",
3233                             failed_filename, i, failed_lines[i].count);
3234         }
3235         /* Clear the failure history for the next file. */
3236         failed_filename = NULL;
3237         memset(failed_lines, 0, sizeof(failed_lines));
3238 }
3239
3240 /*
3241  * Actually run a single test, with appropriate setup and cleanup.
3242  */
3243 static int
3244 test_run(int i, const char *tmpdir)
3245 {
3246         char workdir[1024];
3247         char logfilename[64];
3248         int failures_before = failures;
3249         int skips_before = skips;
3250         int oldumask;
3251
3252         switch (verbosity) {
3253         case VERBOSITY_SUMMARY_ONLY: /* No per-test reports at all */
3254                 break;
3255         case VERBOSITY_PASSFAIL: /* rest of line will include ok/FAIL marker */
3256                 printf("%3d: %-64s", i, tests[i].name);
3257                 fflush(stdout);
3258                 break;
3259         default: /* Title of test, details will follow */
3260                 printf("%3d: %s\n", i, tests[i].name);
3261         }
3262
3263         /* Chdir to the top-level work directory. */
3264         if (!assertChdir(tmpdir)) {
3265                 fprintf(stderr,
3266                     "ERROR: Can't chdir to top work dir %s\n", tmpdir);
3267                 exit(1);
3268         }
3269         /* Create a log file for this test. */
3270         sprintf(logfilename, "%s.log", tests[i].name);
3271         logfile = fopen(logfilename, "w");
3272         fprintf(logfile, "%s\n\n", tests[i].name);
3273         /* Chdir() to a work dir for this specific test. */
3274         snprintf(workdir, sizeof(workdir), "%s/%s", tmpdir, tests[i].name);
3275         testworkdir = workdir;
3276         if (!assertMakeDir(testworkdir, 0755)
3277             || !assertChdir(testworkdir)) {
3278                 fprintf(stderr,
3279                     "ERROR: Can't chdir to work dir %s\n", testworkdir);
3280                 exit(1);
3281         }
3282         /* Explicitly reset the locale before each test. */
3283         setlocale(LC_ALL, "C");
3284         /* Record the umask before we run the test. */
3285         umask(oldumask = umask(0));
3286         /*
3287          * Run the actual test.
3288          */
3289         (*tests[i].func)();
3290         /*
3291          * Clean up and report afterwards.
3292          */
3293         testworkdir = NULL;
3294         /* Restore umask */
3295         umask(oldumask);
3296         /* Reset locale. */
3297         setlocale(LC_ALL, "C");
3298         /* Reset directory. */
3299         if (!assertChdir(tmpdir)) {
3300                 fprintf(stderr, "ERROR: Couldn't chdir to temp dir %s\n",
3301                     tmpdir);
3302                 exit(1);
3303         }
3304         /* Report per-test summaries. */
3305         tests[i].failures = failures - failures_before;
3306         test_summarize(tests[i].failures, skips - skips_before);
3307         /* Close the per-test log file. */
3308         fclose(logfile);
3309         logfile = NULL;
3310         /* If there were no failures, we can remove the work dir and logfile. */
3311         if (tests[i].failures == 0) {
3312                 if (!keep_temp_files && assertChdir(tmpdir)) {
3313 #if defined(_WIN32) && !defined(__CYGWIN__)
3314                         /* Make sure not to leave empty directories.
3315                          * Sometimes a processing of closing files used by tests
3316                          * is not done, then rmdir will be failed and it will
3317                          * leave a empty test directory. So we should wait a few
3318                          * seconds and retry rmdir. */
3319                         int r, t;
3320                         for (t = 0; t < 10; t++) {
3321                                 if (t > 0)
3322                                         Sleep(1000);
3323                                 r = systemf("rmdir /S /Q %s", tests[i].name);
3324                                 if (r == 0)
3325                                         break;
3326                         }
3327                         systemf("del %s", logfilename);
3328 #else
3329                         systemf("rm -rf %s", tests[i].name);
3330                         systemf("rm %s", logfilename);
3331 #endif
3332                 }
3333         }
3334         /* Return appropriate status. */
3335         return (tests[i].failures);
3336 }
3337
3338 /*
3339  *
3340  *
3341  * MAIN and support routines.
3342  *
3343  *
3344  */
3345
3346 static void
3347 usage(const char *program)
3348 {
3349         static const int limit = sizeof(tests) / sizeof(tests[0]);
3350         int i;
3351
3352         printf("Usage: %s [options] <test> <test> ...\n", program);
3353         printf("Default is to run all tests.\n");
3354         printf("Otherwise, specify the numbers of the tests you wish to run.\n");
3355         printf("Options:\n");
3356         printf("  -d  Dump core after any failure, for debugging.\n");
3357         printf("  -k  Keep all temp files.\n");
3358         printf("      Default: temp files for successful tests deleted.\n");
3359 #ifdef PROGRAM
3360         printf("  -p <path>  Path to executable to be tested.\n");
3361         printf("      Default: path taken from " ENVBASE " environment variable.\n");
3362 #endif
3363         printf("  -q  Quiet.\n");
3364         printf("  -r <dir>   Path to dir containing reference files.\n");
3365         printf("      Default: Current directory.\n");
3366         printf("  -u  Keep running specifies tests until one fails.\n");
3367         printf("  -v  Verbose.\n");
3368         printf("Available tests:\n");
3369         for (i = 0; i < limit; i++)
3370                 printf("  %d: %s\n", i, tests[i].name);
3371         exit(1);
3372 }
3373
3374 static char *
3375 get_refdir(const char *d)
3376 {
3377         size_t tried_size, buff_size;
3378         char *buff, *tried, *pwd = NULL, *p = NULL;
3379
3380 #ifdef PATH_MAX
3381         buff_size = PATH_MAX;
3382 #else
3383         buff_size = 8192;
3384 #endif
3385         buff = calloc(buff_size, 1);
3386         if (buff == NULL) {
3387                 fprintf(stderr, "Unable to allocate memory\n");
3388                 exit(1);
3389         }
3390
3391         /* Allocate a buffer to hold the various directories we checked. */
3392         tried_size = buff_size * 2;
3393         tried = calloc(tried_size, 1);
3394         if (tried == NULL) {
3395                 fprintf(stderr, "Unable to allocate memory\n");
3396                 exit(1);
3397         }
3398
3399         /* If a dir was specified, try that */
3400         if (d != NULL) {
3401                 pwd = NULL;
3402                 snprintf(buff, buff_size, "%s", d);
3403                 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
3404                 if (p != NULL) goto success;
3405                 strncat(tried, buff, tried_size - strlen(tried) - 1);
3406                 strncat(tried, "\n", tried_size - strlen(tried) - 1);
3407                 goto failure;
3408         }
3409
3410         /* Get the current dir. */
3411 #ifdef PATH_MAX
3412         pwd = getcwd(NULL, PATH_MAX);/* Solaris getcwd needs the size. */
3413 #else
3414         pwd = getcwd(NULL, 0);
3415 #endif
3416         while (pwd[strlen(pwd) - 1] == '\n')
3417                 pwd[strlen(pwd) - 1] = '\0';
3418
3419         /* Look for a known file. */
3420         snprintf(buff, buff_size, "%s", pwd);
3421         p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
3422         if (p != NULL) goto success;
3423         strncat(tried, buff, tried_size - strlen(tried) - 1);
3424         strncat(tried, "\n", tried_size - strlen(tried) - 1);
3425
3426         snprintf(buff, buff_size, "%s/test", pwd);
3427         p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
3428         if (p != NULL) goto success;
3429         strncat(tried, buff, tried_size - strlen(tried) - 1);
3430         strncat(tried, "\n", tried_size - strlen(tried) - 1);
3431
3432 #if defined(LIBRARY)
3433         snprintf(buff, buff_size, "%s/%s/test", pwd, LIBRARY);
3434 #else
3435         snprintf(buff, buff_size, "%s/%s/test", pwd, PROGRAM);
3436 #endif
3437         p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
3438         if (p != NULL) goto success;
3439         strncat(tried, buff, tried_size - strlen(tried) - 1);
3440         strncat(tried, "\n", tried_size - strlen(tried) - 1);
3441
3442 #if defined(PROGRAM_ALIAS)
3443         snprintf(buff, buff_size, "%s/%s/test", pwd, PROGRAM_ALIAS);
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 #endif
3449
3450         if (memcmp(pwd, "/usr/obj", 8) == 0) {
3451                 snprintf(buff, buff_size, "%s", pwd + 8);
3452                 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
3453                 if (p != NULL) goto success;
3454                 strncat(tried, buff, tried_size - strlen(tried) - 1);
3455                 strncat(tried, "\n", tried_size - strlen(tried) - 1);
3456
3457                 snprintf(buff, buff_size, "%s/test", pwd + 8);
3458                 p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
3459                 if (p != NULL) goto success;
3460                 strncat(tried, buff, tried_size - strlen(tried) - 1);
3461                 strncat(tried, "\n", tried_size - strlen(tried) - 1);
3462         }
3463
3464 failure:
3465         printf("Unable to locate known reference file %s\n", KNOWNREF);
3466         printf("  Checked following directories:\n%s\n", tried);
3467         printf("Use -r option to specify full path to reference directory\n");
3468 #if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG)
3469         DebugBreak();
3470 #endif
3471         exit(1);
3472
3473 success:
3474         free(p);
3475         free(pwd);
3476         free(tried);
3477
3478         /* Copy result into a fresh buffer to reduce memory usage. */
3479         p = strdup(buff);
3480         free(buff);
3481         return p;
3482 }
3483
3484 int
3485 main(int argc, char **argv)
3486 {
3487         static const int limit = sizeof(tests) / sizeof(tests[0]);
3488         int test_set[sizeof(tests) / sizeof(tests[0])];
3489         int i = 0, j = 0, tests_run = 0, tests_failed = 0, option;
3490         time_t now;
3491         char *refdir_alloc = NULL;
3492         const char *progname;
3493         char **saved_argv;
3494         const char *tmp, *option_arg, *p;
3495         char tmpdir[256], *pwd, *testprogdir, *tmp2 = NULL, *vlevel = NULL;
3496         char tmpdir_timestamp[256];
3497
3498         (void)argc; /* UNUSED */
3499
3500         /* Get the current dir. */
3501 #ifdef PATH_MAX
3502         pwd = getcwd(NULL, PATH_MAX);/* Solaris getcwd needs the size. */
3503 #else
3504         pwd = getcwd(NULL, 0);
3505 #endif
3506         while (pwd[strlen(pwd) - 1] == '\n')
3507                 pwd[strlen(pwd) - 1] = '\0';
3508
3509 #if defined(HAVE__CrtSetReportMode) && !defined(__WATCOMC__)
3510         /* To stop to run the default invalid parameter handler. */
3511         _set_invalid_parameter_handler(invalid_parameter_handler);
3512         /* Disable annoying assertion message box. */
3513         _CrtSetReportMode(_CRT_ASSERT, 0);
3514 #endif
3515
3516         /*
3517          * Name of this program, used to build root of our temp directory
3518          * tree.
3519          */
3520         progname = p = argv[0];
3521         if ((testprogdir = (char *)malloc(strlen(progname) + 1)) == NULL)
3522         {
3523                 fprintf(stderr, "ERROR: Out of memory.");
3524                 exit(1);
3525         }
3526         strcpy(testprogdir, progname);
3527         while (*p != '\0') {
3528                 /* Support \ or / dir separators for Windows compat. */
3529                 if (*p == '/' || *p == '\\')
3530                 {
3531                         progname = p + 1;
3532                         i = j;
3533                 }
3534                 ++p;
3535                 j++;
3536         }
3537         testprogdir[i] = '\0';
3538 #if defined(_WIN32) && !defined(__CYGWIN__)
3539         if (testprogdir[0] != '/' && testprogdir[0] != '\\' &&
3540             !(((testprogdir[0] >= 'a' && testprogdir[0] <= 'z') ||
3541                (testprogdir[0] >= 'A' && testprogdir[0] <= 'Z')) &&
3542                 testprogdir[1] == ':' &&
3543                 (testprogdir[2] == '/' || testprogdir[2] == '\\')))
3544 #else
3545         if (testprogdir[0] != '/')
3546 #endif
3547         {
3548                 /* Fixup path for relative directories. */
3549                 if ((testprogdir = (char *)realloc(testprogdir,
3550                         strlen(pwd) + 1 + strlen(testprogdir) + 1)) == NULL)
3551                 {
3552                         fprintf(stderr, "ERROR: Out of memory.");
3553                         exit(1);
3554                 }
3555                 memmove(testprogdir + strlen(pwd) + 1, testprogdir,
3556                     strlen(testprogdir) + 1);
3557                 memcpy(testprogdir, pwd, strlen(pwd));
3558                 testprogdir[strlen(pwd)] = '/';
3559         }
3560
3561 #ifdef PROGRAM
3562         /* Get the target program from environment, if available. */
3563         testprogfile = getenv(ENVBASE);
3564 #endif
3565
3566         if (getenv("TMPDIR") != NULL)
3567                 tmp = getenv("TMPDIR");
3568         else if (getenv("TMP") != NULL)
3569                 tmp = getenv("TMP");
3570         else if (getenv("TEMP") != NULL)
3571                 tmp = getenv("TEMP");
3572         else if (getenv("TEMPDIR") != NULL)
3573                 tmp = getenv("TEMPDIR");
3574         else
3575                 tmp = "/tmp";
3576
3577         /* Allow -d to be controlled through the environment. */
3578         if (getenv(ENVBASE "_DEBUG") != NULL)
3579                 dump_on_failure = 1;
3580
3581         /* Allow -v to be controlled through the environment. */
3582         if (getenv("_VERBOSITY_LEVEL") != NULL)
3583         {
3584                 vlevel = getenv("_VERBOSITY_LEVEL");
3585                 verbosity = atoi(vlevel);
3586                 if (verbosity < VERBOSITY_SUMMARY_ONLY || verbosity > VERBOSITY_FULL)
3587                 {
3588                         /* Unsupported verbosity levels are silently ignored */
3589                         vlevel = NULL;
3590                         verbosity = VERBOSITY_PASSFAIL;
3591                 }
3592         }
3593
3594         /* Get the directory holding test files from environment. */
3595         refdir = getenv(ENVBASE "_TEST_FILES");
3596
3597         /*
3598          * Parse options, without using getopt(), which isn't available
3599          * on all platforms.
3600          */
3601         ++argv; /* Skip program name */
3602         while (*argv != NULL) {
3603                 if (**argv != '-')
3604                         break;
3605                 p = *argv++;
3606                 ++p; /* Skip '-' */
3607                 while (*p != '\0') {
3608                         option = *p++;
3609                         option_arg = NULL;
3610                         /* If 'opt' takes an argument, parse that. */
3611                         if (option == 'p' || option == 'r') {
3612                                 if (*p != '\0')
3613                                         option_arg = p;
3614                                 else if (*argv == NULL) {
3615                                         fprintf(stderr,
3616                                             "Option -%c requires argument.\n",
3617                                             option);
3618                                         usage(progname);
3619                                 } else
3620                                         option_arg = *argv++;
3621                                 p = ""; /* End of this option word. */
3622                         }
3623
3624                         /* Now, handle the option. */
3625                         switch (option) {
3626                         case 'd':
3627                                 dump_on_failure = 1;
3628                                 break;
3629                         case 'k':
3630                                 keep_temp_files = 1;
3631                                 break;
3632                         case 'p':
3633 #ifdef PROGRAM
3634                                 testprogfile = option_arg;
3635 #else
3636                                 fprintf(stderr, "-p option not permitted\n");
3637                                 usage(progname);
3638 #endif
3639                                 break;
3640                         case 'q':
3641                                 if (!vlevel)
3642                                         verbosity--;
3643                                 break;
3644                         case 'r':
3645                                 refdir = option_arg;
3646                                 break;
3647                         case 'u':
3648                                 until_failure++;
3649                                 break;
3650                         case 'v':
3651                                 if (!vlevel)
3652                                         verbosity++;
3653                                 break;
3654                         default:
3655                                 fprintf(stderr, "Unrecognized option '%c'\n",
3656                                     option);
3657                                 usage(progname);
3658                         }
3659                 }
3660         }
3661
3662         /*
3663          * Sanity-check that our options make sense.
3664          */
3665 #ifdef PROGRAM
3666         if (testprogfile == NULL)
3667         {
3668                 if ((tmp2 = (char *)malloc(strlen(testprogdir) + 1 +
3669                         strlen(PROGRAM) + 1)) == NULL)
3670                 {
3671                         fprintf(stderr, "ERROR: Out of memory.");
3672                         exit(1);
3673                 }
3674                 strcpy(tmp2, testprogdir);
3675                 strcat(tmp2, "/");
3676                 strcat(tmp2, PROGRAM);
3677                 testprogfile = tmp2;
3678         }
3679
3680         {
3681                 char *testprg;
3682 #if defined(_WIN32) && !defined(__CYGWIN__)
3683                 /* Command.com sometimes rejects '/' separators. */
3684                 testprg = strdup(testprogfile);
3685                 for (i = 0; testprg[i] != '\0'; i++) {
3686                         if (testprg[i] == '/')
3687                                 testprg[i] = '\\';
3688                 }
3689                 testprogfile = testprg;
3690 #endif
3691                 /* Quote the name that gets put into shell command lines. */
3692                 testprg = malloc(strlen(testprogfile) + 3);
3693                 strcpy(testprg, "\"");
3694                 strcat(testprg, testprogfile);
3695                 strcat(testprg, "\"");
3696                 testprog = testprg;
3697         }
3698 #endif
3699
3700 #if !defined(_WIN32) && defined(SIGPIPE)
3701         {   /* Ignore SIGPIPE signals */
3702                 struct sigaction sa;
3703                 sa.sa_handler = SIG_IGN;
3704                 sigemptyset(&sa.sa_mask);
3705                 sa.sa_flags = 0;
3706                 sigaction(SIGPIPE, &sa, NULL);
3707         }
3708 #endif
3709
3710         /*
3711          * Create a temp directory for the following tests.
3712          * Include the time the tests started as part of the name,
3713          * to make it easier to track the results of multiple tests.
3714          */
3715         now = time(NULL);
3716         for (i = 0; ; i++) {
3717                 strftime(tmpdir_timestamp, sizeof(tmpdir_timestamp),
3718                     "%Y-%m-%dT%H.%M.%S",
3719                     localtime(&now));
3720                 sprintf(tmpdir, "%s/%s.%s-%03d", tmp, progname,
3721                     tmpdir_timestamp, i);
3722                 if (assertMakeDir(tmpdir,0755))
3723                         break;
3724                 if (i >= 999) {
3725                         fprintf(stderr,
3726                             "ERROR: Unable to create temp directory %s\n",
3727                             tmpdir);
3728                         exit(1);
3729                 }
3730         }
3731
3732         /*
3733          * If the user didn't specify a directory for locating
3734          * reference files, try to find the reference files in
3735          * the "usual places."
3736          */
3737         refdir = refdir_alloc = get_refdir(refdir);
3738
3739         /*
3740          * Banner with basic information.
3741          */
3742         printf("\n");
3743         printf("If tests fail or crash, details will be in:\n");
3744         printf("   %s\n", tmpdir);
3745         printf("\n");
3746         if (verbosity > VERBOSITY_SUMMARY_ONLY) {
3747                 printf("Reference files will be read from: %s\n", refdir);
3748 #ifdef PROGRAM
3749                 printf("Running tests on: %s\n", testprog);
3750 #endif
3751                 printf("Exercising: ");
3752                 fflush(stdout);
3753                 printf("%s\n", EXTRA_VERSION);
3754         } else {
3755                 printf("Running ");
3756                 fflush(stdout);
3757         }
3758
3759         /*
3760          * Run some or all of the individual tests.
3761          */
3762         saved_argv = argv;
3763         do {
3764                 argv = saved_argv;
3765                 do {
3766                         int test_num;
3767
3768                         test_num = get_test_set(test_set, limit, *argv, tests);
3769                         if (test_num < 0) {
3770                                 printf("*** INVALID Test %s\n", *argv);
3771                                 free(refdir_alloc);
3772                                 free(testprogdir);
3773                                 usage(progname);
3774                                 return (1);
3775                         }
3776                         for (i = 0; i < test_num; i++) {
3777                                 tests_run++;
3778                                 if (test_run(test_set[i], tmpdir)) {
3779                                         tests_failed++;
3780                                         if (until_failure)
3781                                                 goto finish;
3782                                 }
3783                         }
3784                         if (*argv != NULL)
3785                                 argv++;
3786                 } while (*argv != NULL);
3787         } while (until_failure);
3788
3789 finish:
3790         /* Must be freed after all tests run */
3791         free(tmp2);
3792         free(testprogdir);
3793         free(pwd);
3794
3795         /*
3796          * Report summary statistics.
3797          */
3798         if (verbosity > VERBOSITY_SUMMARY_ONLY) {
3799                 printf("\n");
3800                 printf("Totals:\n");
3801                 printf("  Tests run:         %8d\n", tests_run);
3802                 printf("  Tests failed:      %8d\n", tests_failed);
3803                 printf("  Assertions checked:%8d\n", assertions);
3804                 printf("  Assertions failed: %8d\n", failures);
3805                 printf("  Skips reported:    %8d\n", skips);
3806         }
3807         if (failures) {
3808                 printf("\n");
3809                 printf("Failing tests:\n");
3810                 for (i = 0; i < limit; ++i) {
3811                         if (tests[i].failures)
3812                                 printf("  %d: %s (%d failures)\n", i,
3813                                     tests[i].name, tests[i].failures);
3814                 }
3815                 printf("\n");
3816                 printf("Details for failing tests: %s\n", tmpdir);
3817                 printf("\n");
3818         } else {
3819                 if (verbosity == VERBOSITY_SUMMARY_ONLY)
3820                         printf("\n");
3821                 printf("%d tests passed, no failures\n", tests_run);
3822         }
3823
3824         free(refdir_alloc);
3825
3826         /* If the final tmpdir is empty, we can remove it. */
3827         /* This should be the usual case when all tests succeed. */
3828         assertChdir("..");
3829         rmdir(tmpdir);
3830
3831         return (tests_failed ? 1 : 0);
3832 }