Merge pull request #876 from bradking/bcrypt-vs2010

Define bcrypt macro not available in Win 7 SDK
diff --git a/CMakeLists.txt b/CMakeLists.txt
index eb36b5b..baedfcc 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -44,13 +44,13 @@
 #
 FILE(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/build/version _version)
 STRING(REGEX REPLACE
- "^([0-9])[0-9][0-9][0-9][0-9][0-9][0-9][a-z]?$" "\\1" _major ${_version})
+ "^([0-9])[0-9][0-9][0-9][0-9][0-9][0-9][a-z]*$" "\\1" _major ${_version})
 STRING(REGEX REPLACE
- "^[0-9]([0-9][0-9][0-9])[0-9][0-9][0-9][a-z]?$" "\\1" _minor ${_version})
+ "^[0-9]([0-9][0-9][0-9])[0-9][0-9][0-9][a-z]*$" "\\1" _minor ${_version})
 STRING(REGEX REPLACE
- "^[0-9][0-9][0-9][0-9]([0-9][0-9][0-9])[a-z]?$" "\\1" _revision ${_version})
+ "^[0-9][0-9][0-9][0-9]([0-9][0-9][0-9])[a-z]*$" "\\1" _revision ${_version})
 STRING(REGEX REPLACE
- "^[0-9][0-9][0-9][0-9][0-9][0-9][0-9]([a-z]?)$" "\\1" _quality ${_version})
+ "^[0-9][0-9][0-9][0-9][0-9][0-9][0-9]([a-z]*)$" "\\1" _quality ${_version})
 SET(_version_number ${_major}${_minor}${_revision})
 STRING(REGEX REPLACE "[0]*([^0]*[0-9])$" "\\1" _trimmed_minor ${_minor})
 STRING(REGEX REPLACE "[0]*([^0]*[0-9])$" "\\1" _trimmed_revision ${_revision})
@@ -570,6 +570,11 @@
 LA_CHECK_INCLUDE_FILE("linux/types.h" HAVE_LINUX_TYPES_H)
 LA_CHECK_INCLUDE_FILE("linux/fiemap.h" HAVE_LINUX_FIEMAP_H)
 LA_CHECK_INCLUDE_FILE("linux/fs.h" HAVE_LINUX_FS_H)
+
+CHECK_C_SOURCE_COMPILES("#include <sys/ioctl.h>
+#include <linux/fs.h>
+int main(void) { return FS_IOC_GETFLAGS; }" HAVE_WORKING_FS_IOC_GETFLAGS)
+
 LA_CHECK_INCLUDE_FILE("linux/magic.h" HAVE_LINUX_MAGIC_H)
 LA_CHECK_INCLUDE_FILE("locale.h" HAVE_LOCALE_H)
 LA_CHECK_INCLUDE_FILE("memory.h" HAVE_MEMORY_H)
diff --git a/Makefile.am b/Makefile.am
index dd1fc81..a699dc5 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -310,7 +310,9 @@
 # Sources needed by all test programs
 test_utils_SOURCES= \
 	test_utils/test_utils.c \
-	test_utils/test_utils.h
+	test_utils/test_utils.h \
+	test_utils/test_main.c \
+	test_utils/test_common.h
 
 #
 #
@@ -320,7 +322,6 @@
 libarchive_test_SOURCES= \
 	$(libarchive_la_SOURCES) \
 	$(test_utils_SOURCES) \
-	libarchive/test/main.c \
 	libarchive/test/read_open_memory.c \
 	libarchive/test/test.h \
 	libarchive/test/test_acl_nfs4.c \
@@ -586,7 +587,13 @@
 	libarchive/test/test_write_read_format_zip.c \
 	libarchive/test/test_zip_filename_encoding.c
 
-libarchive_test_CPPFLAGS= -I$(top_srcdir)/libarchive -I$(top_srcdir)/test_utils -I$(top_builddir)/libarchive/test -DLIBARCHIVE_STATIC $(PLATFORMCPPFLAGS)
+libarchive_test_CPPFLAGS= \
+	-I$(top_srcdir)/libarchive \
+	-I$(top_srcdir)/libarchive/test \
+	-I$(top_srcdir)/test_utils \
+	-I$(top_builddir)/libarchive/test \
+	-DLIBARCHIVE_STATIC $(PLATFORMCPPFLAGS)
+
 libarchive_test_LDADD= $(LTLIBICONV)
 
 # The "list.h" file just lists all of the tests defined in all of the sources.
@@ -918,7 +925,6 @@
 
 bsdtar_test_SOURCES= \
 	$(test_utils_SOURCES) \
-	tar/test/main.c \
 	tar/test/test.h \
 	tar/test/test_0.c \
 	tar/test/test_basic.c \
@@ -981,7 +987,8 @@
 bsdtar_test_CPPFLAGS=\
 	-I$(top_srcdir)/libarchive -I$(top_srcdir)/libarchive_fe \
 	-I$(top_srcdir)/test_utils \
-	-I$(top_srcdir)/tar -I$(top_builddir)/tar/test \
+	-I$(top_srcdir)/tar -I$(top_srcdir)/tar/test \
+	-I$(top_builddir)/tar/test \
 	$(PLATFORMCPPFLAGS)
 
 tar/test/list.h: Makefile
@@ -1076,7 +1083,6 @@
 bsdcpio_test_SOURCES= \
 	$(test_utils_SOURCES) \
 	cpio/cmdline.c \
-	cpio/test/main.c \
 	cpio/test/test.h \
 	cpio/test/test_0.c \
 	cpio/test/test_basic.c \
@@ -1128,7 +1134,8 @@
 bsdcpio_test_CPPFLAGS= \
 	-I$(top_srcdir)/libarchive -I$(top_srcdir)/libarchive_fe \
 	-I$(top_srcdir)/test_utils \
-	-I$(top_srcdir)/cpio -I$(top_builddir)/cpio/test \
+	-I$(top_srcdir)/cpio -I$(top_srcdir)/cpio/test \
+	-I$(top_builddir)/cpio/test \
 	$(PLATFORMCPPFLAGS)
 bsdcpio_test_LDADD=libarchive_fe.la
 
@@ -1223,7 +1230,6 @@
 
 bsdcat_test_SOURCES= \
 	$(test_utils_SOURCES) \
-	cat/test/main.c \
 	cat/test/test.h \
 	cat/test/test_0.c \
 	cat/test/test_empty_gz.c \
@@ -1244,7 +1250,8 @@
 bsdcat_test_CPPFLAGS= \
 	-I$(top_srcdir)/libarchive -I$(top_srcdir)/libarchive_fe \
 	-I$(top_srcdir)/test_utils \
-	-I$(top_srcdir)/cat -I$(top_builddir)/cat/test \
+	-I$(top_srcdir)/cat -I$(top_srcdir)/cat/test \
+	-I$(top_builddir)/cat/test \
 	$(PLATFORMCPPFLAGS)
 bsdcat_test_LDADD=libarchive_fe.la
 
diff --git a/NEWS b/NEWS
index 7b5c31f..907ab67 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,6 @@
+Feb 19, 2017: libarchive 3.3.0 released
+    Security & Feature release
+
 Jan 29, 2017: Limited NFSv4 ACL support for Mac OS (Darwin)
 
 Jan 10, 2017: POSIX.1e and NFSv4 ACL support for Solaris and derivates
@@ -5,6 +8,8 @@
 Dec 27, 2016: NFSv4 ACL read and write support for pax
     Deprecated functions: archive_entry_acl_text(), archive_entry_acl_text_w()
 
+Nov, 2016: libarchive is now being tested by the OSS-Fuzz project
+
 Oct 26, 2016: Remove liblzmadec support
 
 Oct 23, 2016: libarchive 3.2.2 released
diff --git a/build/cmake/config.h.in b/build/cmake/config.h.in
index ec64d99..923a78e 100644
--- a/build/cmake/config.h.in
+++ b/build/cmake/config.h.in
@@ -1099,6 +1099,9 @@
 /* Define to 1 if you have a working EXT2_IOC_GETFLAGS */
 #cmakedefine HAVE_WORKING_EXT2_IOC_GETFLAGS 1
 
+/* Define to 1 if you have a working FS_IOC_GETFLAGS */
+#cmakedefine HAVE_WORKING_FS_IOC_GETFLAGS 1
+
 /* Define to 1 if you have the <zlib.h> header file. */
 #cmakedefine HAVE_ZLIB_H 1
 
diff --git a/build/version b/build/version
index f54ddaa..3cddc6c 100644
--- a/build/version
+++ b/build/version
@@ -1 +1 @@
-3002002
+3003001dev
diff --git a/cat/test/CMakeLists.txt b/cat/test/CMakeLists.txt
index c4642ae..7f1ce5e 100644
--- a/cat/test/CMakeLists.txt
+++ b/cat/test/CMakeLists.txt
@@ -6,7 +6,7 @@
 IF(ENABLE_CAT AND ENABLE_TEST)
   SET(bsdcat_test_SOURCES
     ../../test_utils/test_utils.c
-    main.c
+    ../../test_utils/test_main.c
     test.h
     test_0.c
     test_empty_gz.c
@@ -54,6 +54,7 @@
   INCLUDE(${CMAKE_CURRENT_BINARY_DIR}/list.h)
   INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
   INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/test_utils)
+  INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/cat/test)
 
   # Experimental new test handling
   ADD_CUSTOM_TARGET(run_bsdcat_test
diff --git a/cat/test/main.c b/cat/test/main.c
deleted file mode 100644
index cdfdd9b..0000000
--- a/cat/test/main.c
+++ /dev/null
@@ -1,3072 +0,0 @@
-/*
- * Copyright (c) 2003-2009 Tim Kientzle
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "test.h"
-#include "test_utils.h"
-#ifdef HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#include <errno.h>
-#ifdef HAVE_ICONV_H
-#include <iconv.h>
-#endif
-/*
- * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h.
- * As the include guards don't agree, the order of include is important.
- */
-#ifdef HAVE_LINUX_EXT2_FS_H
-#include <linux/ext2_fs.h>      /* for Linux file flags */
-#endif
-#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__)
-#include <ext2fs/ext2_fs.h>     /* Linux file flags, broken on Cygwin */
-#endif
-#include <limits.h>
-#include <locale.h>
-#ifdef HAVE_SIGNAL_H
-#include <signal.h>
-#endif
-#include <stdarg.h>
-#include <time.h>
-
-/*
- * This same file is used pretty much verbatim for all test harnesses.
- *
- * The next few lines are the only differences.
- * TODO: Move this into a separate configuration header, have all test
- * suites share one copy of this file.
- */
-#define KNOWNREF       "test_expand.Z.uu"
-#define ENVBASE "BSDCAT"  /* Prefix for environment variables. */
-#define	PROGRAM "bsdcat"  /* Name of program being tested. */
-#define PROGRAM_ALIAS "cat" /* Generic alias for program */
-#undef	LIBRARY		  /* Not testing a library. */
-#undef	EXTRA_DUMP	  /* How to dump extra data */
-#undef	EXTRA_ERRNO	  /* How to dump errno */
-/* How to generate extra version info. */
-#define	EXTRA_VERSION    (systemf("%s --version", testprog) ? "" : "")
-
-/*
- *
- * Windows support routines
- *
- * Note: Configuration is a tricky issue.  Using HAVE_* feature macros
- * in the test harness is dangerous because they cover up
- * configuration errors.  The classic example of this is omitting a
- * configure check.  If libarchive and libarchive_test both look for
- * the same feature macro, such errors are hard to detect.  Platform
- * macros (e.g., _WIN32 or __GNUC__) are a little better, but can
- * easily lead to very messy code.  It's best to limit yourself
- * to only the most generic programming techniques in the test harness
- * and thus avoid conditionals altogether.  Where that's not possible,
- * try to minimize conditionals by grouping platform-specific tests in
- * one place (e.g., test_acl_freebsd) or by adding new assert()
- * functions (e.g., assertMakeHardlink()) to cover up platform
- * differences.  Platform-specific coding in libarchive_test is often
- * a symptom that some capability is missing from libarchive itself.
- */
-#if defined(_WIN32) && !defined(__CYGWIN__)
-#include <io.h>
-#include <direct.h>
-#include <windows.h>
-#ifndef F_OK
-#define F_OK (0)
-#endif
-#ifndef S_ISDIR
-#define S_ISDIR(m)  ((m) & _S_IFDIR)
-#endif
-#ifndef S_ISREG
-#define S_ISREG(m)  ((m) & _S_IFREG)
-#endif
-#if !defined(__BORLANDC__)
-#define access _access
-#undef chdir
-#define chdir _chdir
-#endif
-#ifndef fileno
-#define fileno _fileno
-#endif
-/*#define fstat _fstat64*/
-#if !defined(__BORLANDC__)
-#define getcwd _getcwd
-#endif
-#define lstat stat
-/*#define lstat _stat64*/
-/*#define stat _stat64*/
-#define rmdir _rmdir
-#if !defined(__BORLANDC__)
-#define strdup _strdup
-#define umask _umask
-#endif
-#define int64_t __int64
-#endif
-
-#if defined(HAVE__CrtSetReportMode)
-# include <crtdbg.h>
-#endif
-
-mode_t umasked(mode_t expected_mode)
-{
-	mode_t mode = umask(0);
-	umask(mode);
-	return expected_mode & ~mode;
-}
-
-/* Path to working directory for current test */
-const char *testworkdir;
-#ifdef PROGRAM
-/* Pathname of exe to be tested. */
-const char *testprogfile;
-/* Name of exe to use in printf-formatted command strings. */
-/* On Windows, this includes leading/trailing quotes. */
-const char *testprog;
-#endif
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-static void	*GetFunctionKernel32(const char *);
-static int	 my_CreateSymbolicLinkA(const char *, const char *, int);
-static int	 my_CreateHardLinkA(const char *, const char *);
-static int	 my_GetFileInformationByName(const char *,
-		     BY_HANDLE_FILE_INFORMATION *);
-
-static void *
-GetFunctionKernel32(const char *name)
-{
-	static HINSTANCE lib;
-	static int set;
-	if (!set) {
-		set = 1;
-		lib = LoadLibrary("kernel32.dll");
-	}
-	if (lib == NULL) {
-		fprintf(stderr, "Can't load kernel32.dll?!\n");
-		exit(1);
-	}
-	return (void *)GetProcAddress(lib, name);
-}
-
-static int
-my_CreateSymbolicLinkA(const char *linkname, const char *target, int flags)
-{
-	static BOOLEAN (WINAPI *f)(LPCSTR, LPCSTR, DWORD);
-	static int set;
-	if (!set) {
-		set = 1;
-		f = GetFunctionKernel32("CreateSymbolicLinkA");
-	}
-	return f == NULL ? 0 : (*f)(linkname, target, flags);
-}
-
-static int
-my_CreateHardLinkA(const char *linkname, const char *target)
-{
-	static BOOLEAN (WINAPI *f)(LPCSTR, LPCSTR, LPSECURITY_ATTRIBUTES);
-	static int set;
-	if (!set) {
-		set = 1;
-		f = GetFunctionKernel32("CreateHardLinkA");
-	}
-	return f == NULL ? 0 : (*f)(linkname, target, NULL);
-}
-
-static int
-my_GetFileInformationByName(const char *path, BY_HANDLE_FILE_INFORMATION *bhfi)
-{
-	HANDLE h;
-	int r;
-
-	memset(bhfi, 0, sizeof(*bhfi));
-	h = CreateFile(path, FILE_READ_ATTRIBUTES, 0, NULL,
-		OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
-	if (h == INVALID_HANDLE_VALUE)
-		return (0);
-	r = GetFileInformationByHandle(h, bhfi);
-	CloseHandle(h);
-	return (r);
-}
-#endif
-
-#if defined(HAVE__CrtSetReportMode) && !defined(__WATCOMC__)
-static void
-invalid_parameter_handler(const wchar_t * expression,
-    const wchar_t * function, const wchar_t * file,
-    unsigned int line, uintptr_t pReserved)
-{
-	/* nop */
-}
-#endif
-
-/*
- *
- * OPTIONS FLAGS
- *
- */
-
-/* Enable core dump on failure. */
-static int dump_on_failure = 0;
-/* Default is to remove temp dirs and log data for successful tests. */
-static int keep_temp_files = 0;
-/* Default is to run the specified tests once and report errors. */
-static int until_failure = 0;
-/* Default is to just report pass/fail for each test. */
-static int verbosity = 0;
-#define	VERBOSITY_SUMMARY_ONLY -1 /* -q */
-#define VERBOSITY_PASSFAIL 0   /* Default */
-#define VERBOSITY_LIGHT_REPORT 1 /* -v */
-#define VERBOSITY_FULL 2 /* -vv */
-/* A few places generate even more output for verbosity > VERBOSITY_FULL,
- * mostly for debugging the test harness itself. */
-/* Cumulative count of assertion failures. */
-static int failures = 0;
-/* Cumulative count of reported skips. */
-static int skips = 0;
-/* Cumulative count of assertions checked. */
-static int assertions = 0;
-
-/* Directory where uuencoded reference files can be found. */
-static const char *refdir;
-
-/*
- * Report log information selectively to console and/or disk log.
- */
-static int log_console = 0;
-static FILE *logfile;
-static void
-vlogprintf(const char *fmt, va_list ap)
-{
-#ifdef va_copy
-	va_list lfap;
-	va_copy(lfap, ap);
-#endif
-	if (log_console)
-		vfprintf(stdout, fmt, ap);
-	if (logfile != NULL)
-#ifdef va_copy
-		vfprintf(logfile, fmt, lfap);
-	va_end(lfap);
-#else
-		vfprintf(logfile, fmt, ap);
-#endif
-}
-
-static void
-logprintf(const char *fmt, ...)
-{
-	va_list ap;
-	va_start(ap, fmt);
-	vlogprintf(fmt, ap);
-	va_end(ap);
-}
-
-/* Set up a message to display only if next assertion fails. */
-static char msgbuff[4096];
-static const char *msg, *nextmsg;
-void
-failure(const char *fmt, ...)
-{
-	va_list ap;
-	if (fmt == NULL) {
-		nextmsg = NULL;
-	} else {
-		va_start(ap, fmt);
-		vsprintf(msgbuff, fmt, ap);
-		va_end(ap);
-		nextmsg = msgbuff;
-	}
-}
-
-/*
- * Copy arguments into file-local variables.
- * This was added to permit vararg assert() functions without needing
- * variadic wrapper macros.  Turns out that the vararg capability is almost
- * never used, so almost all of the vararg assertions can be simplified
- * by removing the vararg capability and reworking the wrapper macro to
- * pass __FILE__, __LINE__ directly into the function instead of using
- * this hook.  I suspect this machinery is used so rarely that we
- * would be better off just removing it entirely.  That would simplify
- * the code here noticeably.
- */
-static const char *skipping_filename;
-static int skipping_line;
-void skipping_setup(const char *filename, int line)
-{
-	skipping_filename = filename;
-	skipping_line = line;
-}
-
-/* Called at the beginning of each assert() function. */
-static void
-assertion_count(const char *file, int line)
-{
-	(void)file; /* UNUSED */
-	(void)line; /* UNUSED */
-	++assertions;
-	/* Proper handling of "failure()" message. */
-	msg = nextmsg;
-	nextmsg = NULL;
-	/* Uncomment to print file:line after every assertion.
-	 * Verbose, but occasionally useful in tracking down crashes. */
-	/* printf("Checked %s:%d\n", file, line); */
-}
-
-/*
- * For each test source file, we remember how many times each
- * assertion was reported.  Cleared before each new test,
- * used by test_summarize().
- */
-static struct line {
-	int count;
-	int skip;
-}  failed_lines[10000];
-const char *failed_filename;
-
-/* Count this failure, setup up log destination and handle initial report. */
-static void
-failure_start(const char *filename, int line, const char *fmt, ...)
-{
-	va_list ap;
-
-	/* Record another failure for this line. */
-	++failures;
-	failed_filename = filename;
-	failed_lines[line].count++;
-
-	/* Determine whether to log header to console. */
-	switch (verbosity) {
-	case VERBOSITY_LIGHT_REPORT:
-		log_console = (failed_lines[line].count < 2);
-		break;
-	default:
-		log_console = (verbosity >= VERBOSITY_FULL);
-	}
-
-	/* Log file:line header for this failure */
-	va_start(ap, fmt);
-#if _MSC_VER
-	logprintf("%s(%d): ", filename, line);
-#else
-	logprintf("%s:%d: ", filename, line);
-#endif
-	vlogprintf(fmt, ap);
-	va_end(ap);
-	logprintf("\n");
-
-	if (msg != NULL && msg[0] != '\0') {
-		logprintf("   Description: %s\n", msg);
-		msg = NULL;
-	}
-
-	/* Determine whether to log details to console. */
-	if (verbosity == VERBOSITY_LIGHT_REPORT)
-		log_console = 0;
-}
-
-/* Complete reporting of failed tests. */
-/*
- * The 'extra' hook here is used by libarchive to include libarchive
- * error messages with assertion failures.  It could also be used
- * to add strerror() output, for example.  Just define the EXTRA_DUMP()
- * macro appropriately.
- */
-static void
-failure_finish(void *extra)
-{
-	(void)extra; /* UNUSED (maybe) */
-#ifdef EXTRA_DUMP
-	if (extra != NULL) {
-		logprintf("    errno: %d\n", EXTRA_ERRNO(extra));
-		logprintf("   detail: %s\n", EXTRA_DUMP(extra));
-	}
-#endif
-
-	if (dump_on_failure) {
-		fprintf(stderr,
-		    " *** forcing core dump so failure can be debugged ***\n");
-		abort();
-	}
-}
-
-/* Inform user that we're skipping some checks. */
-void
-test_skipping(const char *fmt, ...)
-{
-	char buff[1024];
-	va_list ap;
-
-	va_start(ap, fmt);
-	vsprintf(buff, fmt, ap);
-	va_end(ap);
-	/* Use failure() message if set. */
-	msg = nextmsg;
-	nextmsg = NULL;
-	/* failure_start() isn't quite right, but is awfully convenient. */
-	failure_start(skipping_filename, skipping_line, "SKIPPING: %s", buff);
-	--failures; /* Undo failures++ in failure_start() */
-	/* Don't failure_finish() here. */
-	/* Mark as skip, so doesn't count as failed test. */
-	failed_lines[skipping_line].skip = 1;
-	++skips;
-}
-
-/*
- *
- * ASSERTIONS
- *
- */
-
-/* Generic assert() just displays the failed condition. */
-int
-assertion_assert(const char *file, int line, int value,
-    const char *condition, void *extra)
-{
-	assertion_count(file, line);
-	if (!value) {
-		failure_start(file, line, "Assertion failed: %s", condition);
-		failure_finish(extra);
-	}
-	return (value);
-}
-
-/* chdir() and report any errors */
-int
-assertion_chdir(const char *file, int line, const char *pathname)
-{
-	assertion_count(file, line);
-	if (chdir(pathname) == 0)
-		return (1);
-	failure_start(file, line, "chdir(\"%s\")", pathname);
-	failure_finish(NULL);
-	return (0);
-
-}
-
-/* Verify two integers are equal. */
-int
-assertion_equal_int(const char *file, int line,
-    long long v1, const char *e1, long long v2, const char *e2, void *extra)
-{
-	assertion_count(file, line);
-	if (v1 == v2)
-		return (1);
-	failure_start(file, line, "%s != %s", e1, e2);
-	logprintf("      %s=%lld (0x%llx, 0%llo)\n", e1, v1, v1, v1);
-	logprintf("      %s=%lld (0x%llx, 0%llo)\n", e2, v2, v2, v2);
-	failure_finish(extra);
-	return (0);
-}
-
-/*
- * Utility to convert a single UTF-8 sequence.
- */
-static int
-_utf8_to_unicode(uint32_t *pwc, const char *s, size_t n)
-{
-	static const char utf8_count[256] = {
-		 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 00 - 0F */
-		 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 10 - 1F */
-		 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 20 - 2F */
-		 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 30 - 3F */
-		 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40 - 4F */
-		 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 50 - 5F */
-		 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 60 - 6F */
-		 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 70 - 7F */
-		 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 80 - 8F */
-		 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 90 - 9F */
-		 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* A0 - AF */
-		 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* B0 - BF */
-		 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,/* C0 - CF */
-		 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,/* D0 - DF */
-		 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,/* E0 - EF */
-		 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* F0 - FF */
-	};
-	int ch;
-	int cnt;
-	uint32_t wc;
-
-	*pwc = 0;
-
-	/* Sanity check. */
-	if (n == 0)
-		return (0);
-	/*
-	 * Decode 1-4 bytes depending on the value of the first byte.
-	 */
-	ch = (unsigned char)*s;
-	if (ch == 0)
-		return (0); /* Standard:  return 0 for end-of-string. */
-	cnt = utf8_count[ch];
-
-	/* Invalid sequence or there are not plenty bytes. */
-	if (n < (size_t)cnt)
-		return (-1);
-
-	/* Make a Unicode code point from a single UTF-8 sequence. */
-	switch (cnt) {
-	case 1:	/* 1 byte sequence. */
-		*pwc = ch & 0x7f;
-		return (cnt);
-	case 2:	/* 2 bytes sequence. */
-		if ((s[1] & 0xc0) != 0x80) return (-1);
-		*pwc = ((ch & 0x1f) << 6) | (s[1] & 0x3f);
-		return (cnt);
-	case 3:	/* 3 bytes sequence. */
-		if ((s[1] & 0xc0) != 0x80) return (-1);
-		if ((s[2] & 0xc0) != 0x80) return (-1);
-		wc = ((ch & 0x0f) << 12)
-		    | ((s[1] & 0x3f) << 6)
-		    | (s[2] & 0x3f);
-		if (wc < 0x800)
-			return (-1);/* Overlong sequence. */
-		break;
-	case 4:	/* 4 bytes sequence. */
-		if (n < 4)
-			return (-1);
-		if ((s[1] & 0xc0) != 0x80) return (-1);
-		if ((s[2] & 0xc0) != 0x80) return (-1);
-		if ((s[3] & 0xc0) != 0x80) return (-1);
-		wc = ((ch & 0x07) << 18)
-		    | ((s[1] & 0x3f) << 12)
-		    | ((s[2] & 0x3f) << 6)
-		    | (s[3] & 0x3f);
-		if (wc < 0x10000)
-			return (-1);/* Overlong sequence. */
-		break;
-	default:
-		return (-1);
-	}
-
-	/* The code point larger than 0x10FFFF is not legal
-	 * Unicode values. */
-	if (wc > 0x10FFFF)
-		return (-1);
-	/* Correctly gets a Unicode, returns used bytes. */
-	*pwc = wc;
-	return (cnt);
-}
-
-static void strdump(const char *e, const char *p, int ewidth, int utf8)
-{
-	const char *q = p;
-
-	logprintf("      %*s = ", ewidth, e);
-	if (p == NULL) {
-		logprintf("NULL\n");
-		return;
-	}
-	logprintf("\"");
-	while (*p != '\0') {
-		unsigned int c = 0xff & *p++;
-		switch (c) {
-		case '\a': logprintf("\\a"); break;
-		case '\b': logprintf("\\b"); break;
-		case '\n': logprintf("\\n"); break;
-		case '\r': logprintf("\\r"); break;
-		default:
-			if (c >= 32 && c < 127)
-				logprintf("%c", c);
-			else
-				logprintf("\\x%02X", c);
-		}
-	}
-	logprintf("\"");
-	logprintf(" (length %d)", q == NULL ? -1 : (int)strlen(q));
-
-	/*
-	 * If the current string is UTF-8, dump its code points.
-	 */
-	if (utf8) {
-		size_t len;
-		uint32_t uc;
-		int n;
-		int cnt = 0;
-
-		p = q;
-		len = strlen(p);
-		logprintf(" [");
-		while ((n = _utf8_to_unicode(&uc, p, len)) > 0) {
-			if (p != q)
-				logprintf(" ");
-			logprintf("%04X", uc);
-			p += n;
-			len -= n;
-			cnt++;
-		}
-		logprintf("]");
-		logprintf(" (count %d", cnt);
-		if (n < 0) {
-			logprintf(",unknown %d bytes", len);
-		}
-		logprintf(")");
-
-	}
-	logprintf("\n");
-}
-
-/* Verify two strings are equal, dump them if not. */
-int
-assertion_equal_string(const char *file, int line,
-    const char *v1, const char *e1,
-    const char *v2, const char *e2,
-    void *extra, int utf8)
-{
-	int l1, l2;
-
-	assertion_count(file, line);
-	if (v1 == v2 || (v1 != NULL && v2 != NULL && strcmp(v1, v2) == 0))
-		return (1);
-	failure_start(file, line, "%s != %s", e1, e2);
-	l1 = (int)strlen(e1);
-	l2 = (int)strlen(e2);
-	if (l1 < l2)
-		l1 = l2;
-	strdump(e1, v1, l1, utf8);
-	strdump(e2, v2, l1, utf8);
-	failure_finish(extra);
-	return (0);
-}
-
-static void
-wcsdump(const char *e, const wchar_t *w)
-{
-	logprintf("      %s = ", e);
-	if (w == NULL) {
-		logprintf("(null)");
-		return;
-	}
-	logprintf("\"");
-	while (*w != L'\0') {
-		unsigned int c = *w++;
-		if (c >= 32 && c < 127)
-			logprintf("%c", c);
-		else if (c < 256)
-			logprintf("\\x%02X", c);
-		else if (c < 0x10000)
-			logprintf("\\u%04X", c);
-		else
-			logprintf("\\U%08X", c);
-	}
-	logprintf("\"\n");
-}
-
-#ifndef HAVE_WCSCMP
-static int
-wcscmp(const wchar_t *s1, const wchar_t *s2)
-{
-
-	while (*s1 == *s2++) {
-		if (*s1++ == L'\0')
-			return 0;
-	}
-	if (*s1 > *--s2)
-		return 1;
-	else
-		return -1;
-}
-#endif
-
-/* Verify that two wide strings are equal, dump them if not. */
-int
-assertion_equal_wstring(const char *file, int line,
-    const wchar_t *v1, const char *e1,
-    const wchar_t *v2, const char *e2,
-    void *extra)
-{
-	assertion_count(file, line);
-	if (v1 == v2)
-		return (1);
-	if (v1 != NULL && v2 != NULL && wcscmp(v1, v2) == 0)
-		return (1);
-	failure_start(file, line, "%s != %s", e1, e2);
-	wcsdump(e1, v1);
-	wcsdump(e2, v2);
-	failure_finish(extra);
-	return (0);
-}
-
-/*
- * Pretty standard hexdump routine.  As a bonus, if ref != NULL, then
- * any bytes in p that differ from ref will be highlighted with '_'
- * before and after the hex value.
- */
-static void
-hexdump(const char *p, const char *ref, size_t l, size_t offset)
-{
-	size_t i, j;
-	char sep;
-
-	if (p == NULL) {
-		logprintf("(null)\n");
-		return;
-	}
-	for(i=0; i < l; i+=16) {
-		logprintf("%04x", (unsigned)(i + offset));
-		sep = ' ';
-		for (j = 0; j < 16 && i + j < l; j++) {
-			if (ref != NULL && p[i + j] != ref[i + j])
-				sep = '_';
-			logprintf("%c%02x", sep, 0xff & (int)p[i+j]);
-			if (ref != NULL && p[i + j] == ref[i + j])
-				sep = ' ';
-		}
-		for (; j < 16; j++) {
-			logprintf("%c  ", sep);
-			sep = ' ';
-		}
-		logprintf("%c", sep);
-		for (j=0; j < 16 && i + j < l; j++) {
-			int c = p[i + j];
-			if (c >= ' ' && c <= 126)
-				logprintf("%c", c);
-			else
-				logprintf(".");
-		}
-		logprintf("\n");
-	}
-}
-
-/* Verify that two blocks of memory are the same, display the first
- * block of differences if they're not. */
-int
-assertion_equal_mem(const char *file, int line,
-    const void *_v1, const char *e1,
-    const void *_v2, const char *e2,
-    size_t l, const char *ld, void *extra)
-{
-	const char *v1 = (const char *)_v1;
-	const char *v2 = (const char *)_v2;
-	size_t offset;
-
-	assertion_count(file, line);
-	if (v1 == v2 || (v1 != NULL && v2 != NULL && memcmp(v1, v2, l) == 0))
-		return (1);
-	if (v1 == NULL || v2 == NULL)
-		return (0);
-
-	failure_start(file, line, "%s != %s", e1, e2);
-	logprintf("      size %s = %d\n", ld, (int)l);
-	/* Dump 48 bytes (3 lines) so that the first difference is
-	 * in the second line. */
-	offset = 0;
-	while (l > 64 && memcmp(v1, v2, 32) == 0) {
-		/* Two lines agree, so step forward one line. */
-		v1 += 16;
-		v2 += 16;
-		l -= 16;
-		offset += 16;
-	}
-	logprintf("      Dump of %s\n", e1);
-	hexdump(v1, v2, l < 128 ? l : 128, offset);
-	logprintf("      Dump of %s\n", e2);
-	hexdump(v2, v1, l < 128 ? l : 128, offset);
-	logprintf("\n");
-	failure_finish(extra);
-	return (0);
-}
-
-/* Verify that a block of memory is filled with the specified byte. */
-int
-assertion_memory_filled_with(const char *file, int line,
-    const void *_v1, const char *vd,
-    size_t l, const char *ld,
-    char b, const char *bd, void *extra)
-{
-	const char *v1 = (const char *)_v1;
-	size_t c = 0;
-	size_t i;
-	(void)ld; /* UNUSED */
-
-	assertion_count(file, line);
-
-	for (i = 0; i < l; ++i) {
-		if (v1[i] == b) {
-			++c;
-		}
-	}
-	if (c == l)
-		return (1);
-
-	failure_start(file, line, "%s (size %d) not filled with %s", vd, (int)l, bd);
-	logprintf("   Only %d bytes were correct\n", (int)c);
-	failure_finish(extra);
-	return (0);
-}
-
-/* Verify that the named file exists and is empty. */
-int
-assertion_empty_file(const char *filename, int line, const char *f1)
-{
-	char buff[1024];
-	struct stat st;
-	ssize_t s;
-	FILE *f;
-
-	assertion_count(filename, line);
-
-	if (stat(f1, &st) != 0) {
-		failure_start(filename, line, "Stat failed: %s", f1);
-		failure_finish(NULL);
-		return (0);
-	}
-	if (st.st_size == 0)
-		return (1);
-
-	failure_start(filename, line, "File should be empty: %s", f1);
-	logprintf("    File size: %d\n", (int)st.st_size);
-	logprintf("    Contents:\n");
-	f = fopen(f1, "rb");
-	if (f == NULL) {
-		logprintf("    Unable to open %s\n", f1);
-	} else {
-		s = ((off_t)sizeof(buff) < st.st_size) ?
-		    (ssize_t)sizeof(buff) : (ssize_t)st.st_size;
-		s = fread(buff, 1, s, f);
-		hexdump(buff, NULL, s, 0);
-		fclose(f);
-	}
-	failure_finish(NULL);
-	return (0);
-}
-
-/* Verify that the named file exists and is not empty. */
-int
-assertion_non_empty_file(const char *filename, int line, const char *f1)
-{
-	struct stat st;
-
-	assertion_count(filename, line);
-
-	if (stat(f1, &st) != 0) {
-		failure_start(filename, line, "Stat failed: %s", f1);
-		failure_finish(NULL);
-		return (0);
-	}
-	if (st.st_size == 0) {
-		failure_start(filename, line, "File empty: %s", f1);
-		failure_finish(NULL);
-		return (0);
-	}
-	return (1);
-}
-
-/* Verify that two files have the same contents. */
-/* TODO: hexdump the first bytes that actually differ. */
-int
-assertion_equal_file(const char *filename, int line, const char *fn1, const char *fn2)
-{
-	char buff1[1024];
-	char buff2[1024];
-	FILE *f1, *f2;
-	int n1, n2;
-
-	assertion_count(filename, line);
-
-	f1 = fopen(fn1, "rb");
-	f2 = fopen(fn2, "rb");
-	if (f1 == NULL || f2 == NULL) {
-		if (f1) fclose(f1);
-		if (f2) fclose(f2);
-		return (0);
-	}
-	for (;;) {
-		n1 = (int)fread(buff1, 1, sizeof(buff1), f1);
-		n2 = (int)fread(buff2, 1, sizeof(buff2), f2);
-		if (n1 != n2)
-			break;
-		if (n1 == 0 && n2 == 0) {
-			fclose(f1);
-			fclose(f2);
-			return (1);
-		}
-		if (memcmp(buff1, buff2, n1) != 0)
-			break;
-	}
-	fclose(f1);
-	fclose(f2);
-	failure_start(filename, line, "Files not identical");
-	logprintf("  file1=\"%s\"\n", fn1);
-	logprintf("  file2=\"%s\"\n", fn2);
-	failure_finish(NULL);
-	return (0);
-}
-
-/* Verify that the named file does exist. */
-int
-assertion_file_exists(const char *filename, int line, const char *f)
-{
-	assertion_count(filename, line);
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	if (!_access(f, 0))
-		return (1);
-#else
-	if (!access(f, F_OK))
-		return (1);
-#endif
-	failure_start(filename, line, "File should exist: %s", f);
-	failure_finish(NULL);
-	return (0);
-}
-
-/* Verify that the named file doesn't exist. */
-int
-assertion_file_not_exists(const char *filename, int line, const char *f)
-{
-	assertion_count(filename, line);
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	if (_access(f, 0))
-		return (1);
-#else
-	if (access(f, F_OK))
-		return (1);
-#endif
-	failure_start(filename, line, "File should not exist: %s", f);
-	failure_finish(NULL);
-	return (0);
-}
-
-/* Compare the contents of a file to a block of memory. */
-int
-assertion_file_contents(const char *filename, int line, const void *buff, int s, const char *fn)
-{
-	char *contents;
-	FILE *f;
-	int n;
-
-	assertion_count(filename, line);
-
-	f = fopen(fn, "rb");
-	if (f == NULL) {
-		failure_start(filename, line,
-		    "File should exist: %s", fn);
-		failure_finish(NULL);
-		return (0);
-	}
-	contents = malloc(s * 2);
-	n = (int)fread(contents, 1, s * 2, f);
-	fclose(f);
-	if (n == s && memcmp(buff, contents, s) == 0) {
-		free(contents);
-		return (1);
-	}
-	failure_start(filename, line, "File contents don't match");
-	logprintf("  file=\"%s\"\n", fn);
-	if (n > 0)
-		hexdump(contents, buff, n > 512 ? 512 : n, 0);
-	else {
-		logprintf("  File empty, contents should be:\n");
-		hexdump(buff, NULL, s > 512 ? 512 : s, 0);
-	}
-	failure_finish(NULL);
-	free(contents);
-	return (0);
-}
-
-/* Check the contents of a text file, being tolerant of line endings. */
-int
-assertion_text_file_contents(const char *filename, int line, const char *buff, const char *fn)
-{
-	char *contents;
-	const char *btxt, *ftxt;
-	FILE *f;
-	int n, s;
-
-	assertion_count(filename, line);
-	f = fopen(fn, "r");
-	if (f == NULL) {
-		failure_start(filename, line,
-		    "File doesn't exist: %s", fn);
-		failure_finish(NULL);
-		return (0);
-	}
-	s = (int)strlen(buff);
-	contents = malloc(s * 2 + 128);
-	n = (int)fread(contents, 1, s * 2 + 128 - 1, f);
-	if (n >= 0)
-		contents[n] = '\0';
-	fclose(f);
-	/* Compare texts. */
-	btxt = buff;
-	ftxt = (const char *)contents;
-	while (*btxt != '\0' && *ftxt != '\0') {
-		if (*btxt == *ftxt) {
-			++btxt;
-			++ftxt;
-			continue;
-		}
-		if (btxt[0] == '\n' && ftxt[0] == '\r' && ftxt[1] == '\n') {
-			/* Pass over different new line characters. */
-			++btxt;
-			ftxt += 2;
-			continue;
-		}
-		break;
-	}
-	if (*btxt == '\0' && *ftxt == '\0') {
-		free(contents);
-		return (1);
-	}
-	failure_start(filename, line, "Contents don't match");
-	logprintf("  file=\"%s\"\n", fn);
-	if (n > 0) {
-		hexdump(contents, buff, n, 0);
-		logprintf("  expected\n", fn);
-		hexdump(buff, contents, s, 0);
-	} else {
-		logprintf("  File empty, contents should be:\n");
-		hexdump(buff, NULL, s, 0);
-	}
-	failure_finish(NULL);
-	free(contents);
-	return (0);
-}
-
-/* Verify that a text file contains the specified lines, regardless of order */
-/* This could be more efficient if we sorted both sets of lines, etc, but
- * since this is used only for testing and only ever deals with a dozen or so
- * lines at a time, this relatively crude approach is just fine. */
-int
-assertion_file_contains_lines_any_order(const char *file, int line,
-    const char *pathname, const char *lines[])
-{
-	char *buff;
-	size_t buff_size;
-	size_t expected_count, actual_count, i, j;
-	char **expected = NULL;
-	char *p, **actual = NULL;
-	char c;
-	int expected_failure = 0, actual_failure = 0;
-
-	assertion_count(file, line);
-
-	buff = slurpfile(&buff_size, "%s", pathname);
-	if (buff == NULL) {
-		failure_start(pathname, line, "Can't read file: %s", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-
-	/* Make a copy of the provided lines and count up the expected
-	 * file size. */
-	for (i = 0; lines[i] != NULL; ++i) {
-	}
-	expected_count = i;
-	if (expected_count) {
-		expected = malloc(sizeof(char *) * expected_count);
-		if (expected == NULL) {
-			failure_start(pathname, line, "Can't allocate memory");
-			failure_finish(NULL);
-			free(expected);
-			return (0);
-		}
-		for (i = 0; lines[i] != NULL; ++i) {
-			expected[i] = strdup(lines[i]);
-		}
-	}
-
-	/* Break the file into lines */
-	actual_count = 0;
-	for (c = '\0', p = buff; p < buff + buff_size; ++p) {
-		if (*p == '\x0d' || *p == '\x0a')
-			*p = '\0';
-		if (c == '\0' && *p != '\0')
-			++actual_count;
-		c = *p;
-	}
-	if (actual_count) {
-		actual = calloc(sizeof(char *), actual_count);
-		if (actual == NULL) {
-			failure_start(pathname, line, "Can't allocate memory");
-			failure_finish(NULL);
-			free(expected);
-			return (0);
-		}
-		for (j = 0, p = buff; p < buff + buff_size;
-		    p += 1 + strlen(p)) {
-			if (*p != '\0') {
-				actual[j] = p;
-				++j;
-			}
-		}
-	}
-
-	/* Erase matching lines from both lists */
-	for (i = 0; i < expected_count; ++i) {
-		if (expected[i] == NULL)
-			continue;
-		for (j = 0; j < actual_count; ++j) {
-			if (actual[j] == NULL)
-				continue;
-			if (strcmp(expected[i], actual[j]) == 0) {
-				free(expected[i]);
-				expected[i] = NULL;
-				actual[j] = NULL;
-				break;
-			}
-		}
-	}
-
-	/* If there's anything left, it's a failure */
-	for (i = 0; i < expected_count; ++i) {
-		if (expected[i] != NULL)
-			++expected_failure;
-	}
-	for (j = 0; j < actual_count; ++j) {
-		if (actual[j] != NULL)
-			++actual_failure;
-	}
-	if (expected_failure == 0 && actual_failure == 0) {
-		free(buff);
-		free(expected);
-		free(actual);
-		return (1);
-	}
-	failure_start(file, line, "File doesn't match: %s", pathname);
-	for (i = 0; i < expected_count; ++i) {
-		if (expected[i] != NULL) {
-			logprintf("  Expected but not present: %s\n", expected[i]);
-			free(expected[i]);
-		}
-	}
-	for (j = 0; j < actual_count; ++j) {
-		if (actual[j] != NULL)
-			logprintf("  Present but not expected: %s\n", actual[j]);
-	}
-	failure_finish(NULL);
-	free(buff);
-	free(expected);
-	free(actual);
-	return (0);
-}
-
-/* Verify that a text file does not contains the specified strings */
-int
-assertion_file_contains_no_invalid_strings(const char *file, int line,
-    const char *pathname, const char *strings[])
-{
-	char *buff;
-	int i;
-
-	buff = slurpfile(NULL, "%s", pathname);
-	if (buff == NULL) {
-		failure_start(file, line, "Can't read file: %s", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-
-	for (i = 0; strings[i] != NULL; ++i) {
-		if (strstr(buff, strings[i]) != NULL) {
-			failure_start(file, line, "Invalid string in %s: %s", pathname,
-			    strings[i]);
-			failure_finish(NULL);
-			free(buff);
-			return(0);
-		}
-	}
-
-	free(buff);
-	return (0);
-}
-
-/* Test that two paths point to the same file. */
-/* As a side-effect, asserts that both files exist. */
-static int
-is_hardlink(const char *file, int line,
-    const char *path1, const char *path2)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	BY_HANDLE_FILE_INFORMATION bhfi1, bhfi2;
-	int r;
-
-	assertion_count(file, line);
-	r = my_GetFileInformationByName(path1, &bhfi1);
-	if (r == 0) {
-		failure_start(file, line, "File %s can't be inspected?", path1);
-		failure_finish(NULL);
-		return (0);
-	}
-	r = my_GetFileInformationByName(path2, &bhfi2);
-	if (r == 0) {
-		failure_start(file, line, "File %s can't be inspected?", path2);
-		failure_finish(NULL);
-		return (0);
-	}
-	return (bhfi1.dwVolumeSerialNumber == bhfi2.dwVolumeSerialNumber
-		&& bhfi1.nFileIndexHigh == bhfi2.nFileIndexHigh
-		&& bhfi1.nFileIndexLow == bhfi2.nFileIndexLow);
-#else
-	struct stat st1, st2;
-	int r;
-
-	assertion_count(file, line);
-	r = lstat(path1, &st1);
-	if (r != 0) {
-		failure_start(file, line, "File should exist: %s", path1);
-		failure_finish(NULL);
-		return (0);
-	}
-	r = lstat(path2, &st2);
-	if (r != 0) {
-		failure_start(file, line, "File should exist: %s", path2);
-		failure_finish(NULL);
-		return (0);
-	}
-	return (st1.st_ino == st2.st_ino && st1.st_dev == st2.st_dev);
-#endif
-}
-
-int
-assertion_is_hardlink(const char *file, int line,
-    const char *path1, const char *path2)
-{
-	if (is_hardlink(file, line, path1, path2))
-		return (1);
-	failure_start(file, line,
-	    "Files %s and %s are not hardlinked", path1, path2);
-	failure_finish(NULL);
-	return (0);
-}
-
-int
-assertion_is_not_hardlink(const char *file, int line,
-    const char *path1, const char *path2)
-{
-	if (!is_hardlink(file, line, path1, path2))
-		return (1);
-	failure_start(file, line,
-	    "Files %s and %s should not be hardlinked", path1, path2);
-	failure_finish(NULL);
-	return (0);
-}
-
-/* Verify a/b/mtime of 'pathname'. */
-/* If 'recent', verify that it's within last 10 seconds. */
-static int
-assertion_file_time(const char *file, int line,
-    const char *pathname, long t, long nsec, char type, int recent)
-{
-	long long filet, filet_nsec;
-	int r;
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-#define EPOC_TIME	(116444736000000000ULL)
-	FILETIME fxtime, fbirthtime, fatime, fmtime;
-	ULARGE_INTEGER wintm;
-	HANDLE h;
-	fxtime.dwLowDateTime = 0;
-	fxtime.dwHighDateTime = 0;
-
-	assertion_count(file, line);
-	/* Note: FILE_FLAG_BACKUP_SEMANTICS applies to open
-	 * a directory file. If not, CreateFile() will fail when
-	 * the pathname is a directory. */
-	h = CreateFile(pathname, FILE_READ_ATTRIBUTES, 0, NULL,
-	    OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
-	if (h == INVALID_HANDLE_VALUE) {
-		failure_start(file, line, "Can't access %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	r = GetFileTime(h, &fbirthtime, &fatime, &fmtime);
-	switch (type) {
-	case 'a': fxtime = fatime; break;
-	case 'b': fxtime = fbirthtime; break;
-	case 'm': fxtime = fmtime; break;
-	}
-	CloseHandle(h);
-	if (r == 0) {
-		failure_start(file, line, "Can't GetFileTime %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	wintm.LowPart = fxtime.dwLowDateTime;
-	wintm.HighPart = fxtime.dwHighDateTime;
-	filet = (wintm.QuadPart - EPOC_TIME) / 10000000;
-	filet_nsec = ((wintm.QuadPart - EPOC_TIME) % 10000000) * 100;
-	nsec = (nsec / 100) * 100; /* Round the request */
-#else
-	struct stat st;
-
-	assertion_count(file, line);
-	r = lstat(pathname, &st);
-	if (r != 0) {
-		failure_start(file, line, "Can't stat %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	switch (type) {
-	case 'a': filet = st.st_atime; break;
-	case 'm': filet = st.st_mtime; break;
-	case 'b': filet = 0; break;
-	default: fprintf(stderr, "INTERNAL: Bad type %c for file time", type);
-		exit(1);
-	}
-#if defined(__FreeBSD__)
-	switch (type) {
-	case 'a': filet_nsec = st.st_atimespec.tv_nsec; break;
-	case 'b': filet = st.st_birthtime;
-		/* FreeBSD filesystems that don't support birthtime
-		 * (e.g., UFS1) always return -1 here. */
-		if (filet == -1) {
-			return (1);
-		}
-		filet_nsec = st.st_birthtimespec.tv_nsec; break;
-	case 'm': filet_nsec = st.st_mtimespec.tv_nsec; break;
-	default: fprintf(stderr, "INTERNAL: Bad type %c for file time", type);
-		exit(1);
-	}
-	/* FreeBSD generally only stores to microsecond res, so round. */
-	filet_nsec = (filet_nsec / 1000) * 1000;
-	nsec = (nsec / 1000) * 1000;
-#else
-	filet_nsec = nsec = 0;	/* Generic POSIX only has whole seconds. */
-	if (type == 'b') return (1); /* Generic POSIX doesn't have birthtime */
-#if defined(__HAIKU__)
-	if (type == 'a') return (1); /* Haiku doesn't have atime. */
-#endif
-#endif
-#endif
-	if (recent) {
-		/* Check that requested time is up-to-date. */
-		time_t now = time(NULL);
-		if (filet < now - 10 || filet > now + 1) {
-			failure_start(file, line,
-			    "File %s has %ctime %lld, %lld seconds ago\n",
-			    pathname, type, filet, now - filet);
-			failure_finish(NULL);
-			return (0);
-		}
-	} else if (filet != t || filet_nsec != nsec) {
-		failure_start(file, line,
-		    "File %s has %ctime %lld.%09lld, expected %lld.%09lld",
-		    pathname, type, filet, filet_nsec, t, nsec);
-		failure_finish(NULL);
-		return (0);
-	}
-	return (1);
-}
-
-/* Verify atime of 'pathname'. */
-int
-assertion_file_atime(const char *file, int line,
-    const char *pathname, long t, long nsec)
-{
-	return assertion_file_time(file, line, pathname, t, nsec, 'a', 0);
-}
-
-/* Verify atime of 'pathname' is up-to-date. */
-int
-assertion_file_atime_recent(const char *file, int line, const char *pathname)
-{
-	return assertion_file_time(file, line, pathname, 0, 0, 'a', 1);
-}
-
-/* Verify birthtime of 'pathname'. */
-int
-assertion_file_birthtime(const char *file, int line,
-    const char *pathname, long t, long nsec)
-{
-	return assertion_file_time(file, line, pathname, t, nsec, 'b', 0);
-}
-
-/* Verify birthtime of 'pathname' is up-to-date. */
-int
-assertion_file_birthtime_recent(const char *file, int line,
-    const char *pathname)
-{
-	return assertion_file_time(file, line, pathname, 0, 0, 'b', 1);
-}
-
-/* Verify mode of 'pathname'. */
-int
-assertion_file_mode(const char *file, int line, const char *pathname, int expected_mode)
-{
-	int mode;
-	int r;
-
-	assertion_count(file, line);
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	failure_start(file, line, "assertFileMode not yet implemented for Windows");
-	(void)mode; /* UNUSED */
-	(void)r; /* UNUSED */
-#else
-	{
-		struct stat st;
-		r = lstat(pathname, &st);
-		mode = (int)(st.st_mode & 0777);
-	}
-	if (r == 0 && mode == expected_mode)
-			return (1);
-	failure_start(file, line, "File %s has mode %o, expected %o",
-	    pathname, mode, expected_mode);
-#endif
-	failure_finish(NULL);
-	return (0);
-}
-
-/* Verify mtime of 'pathname'. */
-int
-assertion_file_mtime(const char *file, int line,
-    const char *pathname, long t, long nsec)
-{
-	return assertion_file_time(file, line, pathname, t, nsec, 'm', 0);
-}
-
-/* Verify mtime of 'pathname' is up-to-date. */
-int
-assertion_file_mtime_recent(const char *file, int line, const char *pathname)
-{
-	return assertion_file_time(file, line, pathname, 0, 0, 'm', 1);
-}
-
-/* Verify number of links to 'pathname'. */
-int
-assertion_file_nlinks(const char *file, int line,
-    const char *pathname, int nlinks)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	BY_HANDLE_FILE_INFORMATION bhfi;
-	int r;
-
-	assertion_count(file, line);
-	r = my_GetFileInformationByName(pathname, &bhfi);
-	if (r != 0 && bhfi.nNumberOfLinks == (DWORD)nlinks)
-		return (1);
-	failure_start(file, line, "File %s has %d links, expected %d",
-	    pathname, bhfi.nNumberOfLinks, nlinks);
-	failure_finish(NULL);
-	return (0);
-#else
-	struct stat st;
-	int r;
-
-	assertion_count(file, line);
-	r = lstat(pathname, &st);
-	if (r == 0 && (int)st.st_nlink == nlinks)
-		return (1);
-	failure_start(file, line, "File %s has %d links, expected %d",
-	    pathname, st.st_nlink, nlinks);
-	failure_finish(NULL);
-	return (0);
-#endif
-}
-
-/* Verify size of 'pathname'. */
-int
-assertion_file_size(const char *file, int line, const char *pathname, long size)
-{
-	int64_t filesize;
-	int r;
-
-	assertion_count(file, line);
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	{
-		BY_HANDLE_FILE_INFORMATION bhfi;
-		r = !my_GetFileInformationByName(pathname, &bhfi);
-		filesize = ((int64_t)bhfi.nFileSizeHigh << 32) + bhfi.nFileSizeLow;
-	}
-#else
-	{
-		struct stat st;
-		r = lstat(pathname, &st);
-		filesize = st.st_size;
-	}
-#endif
-	if (r == 0 && filesize == size)
-			return (1);
-	failure_start(file, line, "File %s has size %ld, expected %ld",
-	    pathname, (long)filesize, (long)size);
-	failure_finish(NULL);
-	return (0);
-}
-
-/* Assert that 'pathname' is a dir.  If mode >= 0, verify that too. */
-int
-assertion_is_dir(const char *file, int line, const char *pathname, int mode)
-{
-	struct stat st;
-	int r;
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	(void)mode; /* UNUSED */
-#endif
-	assertion_count(file, line);
-	r = lstat(pathname, &st);
-	if (r != 0) {
-		failure_start(file, line, "Dir should exist: %s", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	if (!S_ISDIR(st.st_mode)) {
-		failure_start(file, line, "%s is not a dir", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-#if !defined(_WIN32) || defined(__CYGWIN__)
-	/* Windows doesn't handle permissions the same way as POSIX,
-	 * so just ignore the mode tests. */
-	/* TODO: Can we do better here? */
-	if (mode >= 0 && (mode_t)mode != (st.st_mode & 07777)) {
-		failure_start(file, line, "Dir %s has wrong mode", pathname);
-		logprintf("  Expected: 0%3o\n", mode);
-		logprintf("  Found: 0%3o\n", st.st_mode & 07777);
-		failure_finish(NULL);
-		return (0);
-	}
-#endif
-	return (1);
-}
-
-/* Verify that 'pathname' is a regular file.  If 'mode' is >= 0,
- * verify that too. */
-int
-assertion_is_reg(const char *file, int line, const char *pathname, int mode)
-{
-	struct stat st;
-	int r;
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	(void)mode; /* UNUSED */
-#endif
-	assertion_count(file, line);
-	r = lstat(pathname, &st);
-	if (r != 0 || !S_ISREG(st.st_mode)) {
-		failure_start(file, line, "File should exist: %s", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-#if !defined(_WIN32) || defined(__CYGWIN__)
-	/* Windows doesn't handle permissions the same way as POSIX,
-	 * so just ignore the mode tests. */
-	/* TODO: Can we do better here? */
-	if (mode >= 0 && (mode_t)mode != (st.st_mode & 07777)) {
-		failure_start(file, line, "File %s has wrong mode", pathname);
-		logprintf("  Expected: 0%3o\n", mode);
-		logprintf("  Found: 0%3o\n", st.st_mode & 07777);
-		failure_finish(NULL);
-		return (0);
-	}
-#endif
-	return (1);
-}
-
-/* Check whether 'pathname' is a symbolic link.  If 'contents' is
- * non-NULL, verify that the symlink has those contents. */
-static int
-is_symlink(const char *file, int line,
-    const char *pathname, const char *contents)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	(void)pathname; /* UNUSED */
-	(void)contents; /* UNUSED */
-	assertion_count(file, line);
-	/* Windows sort-of has real symlinks, but they're only usable
-	 * by privileged users and are crippled even then, so there's
-	 * really not much point in bothering with this. */
-	return (0);
-#else
-	char buff[300];
-	struct stat st;
-	ssize_t linklen;
-	int r;
-
-	assertion_count(file, line);
-	r = lstat(pathname, &st);
-	if (r != 0) {
-		failure_start(file, line,
-		    "Symlink should exist: %s", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	if (!S_ISLNK(st.st_mode))
-		return (0);
-	if (contents == NULL)
-		return (1);
-	linklen = readlink(pathname, buff, sizeof(buff));
-	if (linklen < 0) {
-		failure_start(file, line, "Can't read symlink %s", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	buff[linklen] = '\0';
-	if (strcmp(buff, contents) != 0)
-		return (0);
-	return (1);
-#endif
-}
-
-/* Assert that path is a symlink that (optionally) contains contents. */
-int
-assertion_is_symlink(const char *file, int line,
-    const char *path, const char *contents)
-{
-	if (is_symlink(file, line, path, contents))
-		return (1);
-	if (contents)
-		failure_start(file, line, "File %s is not a symlink to %s",
-		    path, contents);
-	else
-		failure_start(file, line, "File %s is not a symlink", path);
-	failure_finish(NULL);
-	return (0);
-}
-
-
-/* Create a directory and report any errors. */
-int
-assertion_make_dir(const char *file, int line, const char *dirname, int mode)
-{
-	assertion_count(file, line);
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	(void)mode; /* UNUSED */
-	if (0 == _mkdir(dirname))
-		return (1);
-#else
-	if (0 == mkdir(dirname, mode)) {
-		if (0 == chmod(dirname, mode)) {
-			assertion_file_mode(file, line, dirname, mode);
-			return (1);
-		}
-	}
-#endif
-	failure_start(file, line, "Could not create directory %s", dirname);
-	failure_finish(NULL);
-	return(0);
-}
-
-/* Create a file with the specified contents and report any failures. */
-int
-assertion_make_file(const char *file, int line,
-    const char *path, int mode, int csize, const void *contents)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	/* TODO: Rework this to set file mode as well. */
-	FILE *f;
-	(void)mode; /* UNUSED */
-	assertion_count(file, line);
-	f = fopen(path, "wb");
-	if (f == NULL) {
-		failure_start(file, line, "Could not create file %s", path);
-		failure_finish(NULL);
-		return (0);
-	}
-	if (contents != NULL) {
-		size_t wsize;
-
-		if (csize < 0)
-			wsize = strlen(contents);
-		else
-			wsize = (size_t)csize;
-		if (wsize != fwrite(contents, 1, wsize, f)) {
-			fclose(f);
-			failure_start(file, line,
-			    "Could not write file %s", path);
-			failure_finish(NULL);
-			return (0);
-		}
-	}
-	fclose(f);
-	return (1);
-#else
-	int fd;
-	assertion_count(file, line);
-	fd = open(path, O_CREAT | O_WRONLY, mode >= 0 ? mode : 0644);
-	if (fd < 0) {
-		failure_start(file, line, "Could not create %s", path);
-		failure_finish(NULL);
-		return (0);
-	}
-	if (0 != chmod(path, mode)) {
-		failure_start(file, line, "Could not chmod %s", path);
-		failure_finish(NULL);
-		close(fd);
-		return (0);
-	}
-	if (contents != NULL) {
-		ssize_t wsize;
-
-		if (csize < 0)
-			wsize = (ssize_t)strlen(contents);
-		else
-			wsize = (ssize_t)csize;
-		if (wsize != write(fd, contents, wsize)) {
-			close(fd);
-			failure_start(file, line,
-			    "Could not write to %s", path);
-			failure_finish(NULL);
-			close(fd);
-			return (0);
-		}
-	}
-	close(fd);
-	assertion_file_mode(file, line, path, mode);
-	return (1);
-#endif
-}
-
-/* Create a hardlink and report any failures. */
-int
-assertion_make_hardlink(const char *file, int line,
-    const char *newpath, const char *linkto)
-{
-	int succeeded;
-
-	assertion_count(file, line);
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	succeeded = my_CreateHardLinkA(newpath, linkto);
-#elif HAVE_LINK
-	succeeded = !link(linkto, newpath);
-#else
-	succeeded = 0;
-#endif
-	if (succeeded)
-		return (1);
-	failure_start(file, line, "Could not create hardlink");
-	logprintf("   New link: %s\n", newpath);
-	logprintf("   Old name: %s\n", linkto);
-	failure_finish(NULL);
-	return(0);
-}
-
-/* Create a symlink and report any failures. */
-int
-assertion_make_symlink(const char *file, int line,
-    const char *newpath, const char *linkto)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	int targetIsDir = 0;  /* TODO: Fix this */
-	assertion_count(file, line);
-	if (my_CreateSymbolicLinkA(newpath, linkto, targetIsDir))
-		return (1);
-#elif HAVE_SYMLINK
-	assertion_count(file, line);
-	if (0 == symlink(linkto, newpath))
-		return (1);
-#endif
-	failure_start(file, line, "Could not create symlink");
-	logprintf("   New link: %s\n", newpath);
-	logprintf("   Old name: %s\n", linkto);
-	failure_finish(NULL);
-	return(0);
-}
-
-/* Set umask, report failures. */
-int
-assertion_umask(const char *file, int line, int mask)
-{
-	assertion_count(file, line);
-	(void)file; /* UNUSED */
-	(void)line; /* UNUSED */
-	umask(mask);
-	return (1);
-}
-
-/* Set times, report failures. */
-int
-assertion_utimes(const char *file, int line,
-    const char *pathname, long at, long at_nsec, long mt, long mt_nsec)
-{
-	int r;
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-#define WINTIME(sec, nsec) ((Int32x32To64(sec, 10000000) + EPOC_TIME)\
-	 + (((nsec)/1000)*10))
-	HANDLE h;
-	ULARGE_INTEGER wintm;
-	FILETIME fatime, fmtime;
-	FILETIME *pat, *pmt;
-
-	assertion_count(file, line);
-	h = CreateFileA(pathname,GENERIC_READ | GENERIC_WRITE,
-		    FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
-		    FILE_FLAG_BACKUP_SEMANTICS, NULL);
-	if (h == INVALID_HANDLE_VALUE) {
-		failure_start(file, line, "Can't access %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-
-	if (at > 0 || at_nsec > 0) {
-		wintm.QuadPart = WINTIME(at, at_nsec);
-		fatime.dwLowDateTime = wintm.LowPart;
-		fatime.dwHighDateTime = wintm.HighPart;
-		pat = &fatime;
-	} else
-		pat = NULL;
-	if (mt > 0 || mt_nsec > 0) {
-		wintm.QuadPart = WINTIME(mt, mt_nsec);
-		fmtime.dwLowDateTime = wintm.LowPart;
-		fmtime.dwHighDateTime = wintm.HighPart;
-		pmt = &fmtime;
-	} else
-		pmt = NULL;
-	if (pat != NULL || pmt != NULL)
-		r = SetFileTime(h, NULL, pat, pmt);
-	else
-		r = 1;
-	CloseHandle(h);
-	if (r == 0) {
-		failure_start(file, line, "Can't SetFileTime %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	return (1);
-#else /* defined(_WIN32) && !defined(__CYGWIN__) */
-	struct stat st;
-	struct timeval times[2];
-
-#if !defined(__FreeBSD__)
-	mt_nsec = at_nsec = 0;	/* Generic POSIX only has whole seconds. */
-#endif
-	if (mt == 0 && mt_nsec == 0 && at == 0 && at_nsec == 0)
-		return (1);
-
-	r = lstat(pathname, &st);
-	if (r < 0) {
-		failure_start(file, line, "Can't stat %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-
-	if (mt == 0 && mt_nsec == 0) {
-		mt = st.st_mtime;
-#if defined(__FreeBSD__)
-		mt_nsec = st.st_mtimespec.tv_nsec;
-		/* FreeBSD generally only stores to microsecond res, so round. */
-		mt_nsec = (mt_nsec / 1000) * 1000;
-#endif
-	}
-	if (at == 0 && at_nsec == 0) {
-		at = st.st_atime;
-#if defined(__FreeBSD__)
-		at_nsec = st.st_atimespec.tv_nsec;
-		/* FreeBSD generally only stores to microsecond res, so round. */
-		at_nsec = (at_nsec / 1000) * 1000;
-#endif
-	}
-
-	times[1].tv_sec = mt;
-	times[1].tv_usec = mt_nsec / 1000;
-
-	times[0].tv_sec = at;
-	times[0].tv_usec = at_nsec / 1000;
-
-#ifdef HAVE_LUTIMES
-	r = lutimes(pathname, times);
-#else
-	r = utimes(pathname, times);
-#endif
-	if (r < 0) {
-		failure_start(file, line, "Can't utimes %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	return (1);
-#endif /* defined(_WIN32) && !defined(__CYGWIN__) */
-}
-
-/* Set nodump, report failures. */
-int
-assertion_nodump(const char *file, int line, const char *pathname)
-{
-#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP)
-	int r;
-
-	assertion_count(file, line);
-	r = chflags(pathname, UF_NODUMP);
-	if (r < 0) {
-		failure_start(file, line, "Can't set nodump %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-#elif defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)\
-	 && defined(EXT2_NODUMP_FL)
-	int fd, r, flags;
-
-	assertion_count(file, line);
-	fd = open(pathname, O_RDONLY | O_NONBLOCK);
-	if (fd < 0) {
-		failure_start(file, line, "Can't open %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags);
-	if (r < 0) {
-		failure_start(file, line, "Can't get flags %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	flags |= EXT2_NODUMP_FL;
-	r = ioctl(fd, EXT2_IOC_SETFLAGS, &flags);
-	if (r < 0) {
-		failure_start(file, line, "Can't set nodump %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	close(fd);
-#else
-	(void)pathname; /* UNUSED */
-	assertion_count(file, line);
-#endif
-	return (1);
-}
-
-/*
- *
- *  UTILITIES for use by tests.
- *
- */
-
-/*
- * Check whether platform supports symlinks.  This is intended
- * for tests to use in deciding whether to bother testing symlink
- * support; if the platform doesn't support symlinks, there's no point
- * in checking whether the program being tested can create them.
- *
- * Note that the first time this test is called, we actually go out to
- * disk to create and verify a symlink.  This is necessary because
- * symlink support is actually a property of a particular filesystem
- * and can thus vary between directories on a single system.  After
- * the first call, this returns the cached result from memory, so it's
- * safe to call it as often as you wish.
- */
-int
-canSymlink(void)
-{
-	/* Remember the test result */
-	static int value = 0, tested = 0;
-	if (tested)
-		return (value);
-
-	++tested;
-	assertion_make_file(__FILE__, __LINE__, "canSymlink.0", 0644, 1, "a");
-	/* Note: Cygwin has its own symlink() emulation that does not
-	 * use the Win32 CreateSymbolicLink() function. */
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	value = my_CreateSymbolicLinkA("canSymlink.1", "canSymlink.0", 0)
-	    && is_symlink(__FILE__, __LINE__, "canSymlink.1", "canSymlink.0");
-#elif HAVE_SYMLINK
-	value = (0 == symlink("canSymlink.0", "canSymlink.1"))
-	    && is_symlink(__FILE__, __LINE__, "canSymlink.1","canSymlink.0");
-#endif
-	return (value);
-}
-
-/* Platform-dependent options for hiding the output of a subcommand. */
-#if defined(_WIN32) && !defined(__CYGWIN__)
-static const char *redirectArgs = ">NUL 2>NUL"; /* Win32 cmd.exe */
-#else
-static const char *redirectArgs = ">/dev/null 2>/dev/null"; /* POSIX 'sh' */
-#endif
-/*
- * Can this platform run the bzip2 program?
- */
-int
-canBzip2(void)
-{
-	static int tested = 0, value = 0;
-	if (!tested) {
-		tested = 1;
-		if (systemf("bzip2 -d -V %s", redirectArgs) == 0)
-			value = 1;
-	}
-	return (value);
-}
-
-/*
- * Can this platform run the grzip program?
- */
-int
-canGrzip(void)
-{
-	static int tested = 0, value = 0;
-	if (!tested) {
-		tested = 1;
-		if (systemf("grzip -V %s", redirectArgs) == 0)
-			value = 1;
-	}
-	return (value);
-}
-
-/*
- * Can this platform run the gzip program?
- */
-int
-canGzip(void)
-{
-	static int tested = 0, value = 0;
-	if (!tested) {
-		tested = 1;
-		if (systemf("gzip -V %s", redirectArgs) == 0)
-			value = 1;
-	}
-	return (value);
-}
-
-/*
- * Can this platform run the lrzip program?
- */
-int
-canRunCommand(const char *cmd)
-{
-  static int tested = 0, value = 0;
-  if (!tested) {
-    tested = 1;
-    if (systemf("%s %s", cmd, redirectArgs) == 0)
-      value = 1;
-  }
-  return (value);
-}
-
-int
-canLrzip(void)
-{
-	static int tested = 0, value = 0;
-	if (!tested) {
-		tested = 1;
-		if (systemf("lrzip -V %s", redirectArgs) == 0)
-			value = 1;
-	}
-	return (value);
-}
-
-/*
- * Can this platform run the lz4 program?
- */
-int
-canLz4(void)
-{
-	static int tested = 0, value = 0;
-	if (!tested) {
-		tested = 1;
-		if (systemf("lz4 -V %s", redirectArgs) == 0)
-			value = 1;
-	}
-	return (value);
-}
-
-/*
- * Can this platform run the lzip program?
- */
-int
-canLzip(void)
-{
-	static int tested = 0, value = 0;
-	if (!tested) {
-		tested = 1;
-		if (systemf("lzip -V %s", redirectArgs) == 0)
-			value = 1;
-	}
-	return (value);
-}
-
-/*
- * Can this platform run the lzma program?
- */
-int
-canLzma(void)
-{
-	static int tested = 0, value = 0;
-	if (!tested) {
-		tested = 1;
-		if (systemf("lzma -V %s", redirectArgs) == 0)
-			value = 1;
-	}
-	return (value);
-}
-
-/*
- * Can this platform run the lzop program?
- */
-int
-canLzop(void)
-{
-	static int tested = 0, value = 0;
-	if (!tested) {
-		tested = 1;
-		if (systemf("lzop -V %s", redirectArgs) == 0)
-			value = 1;
-	}
-	return (value);
-}
-
-/*
- * Can this platform run the xz program?
- */
-int
-canXz(void)
-{
-	static int tested = 0, value = 0;
-	if (!tested) {
-		tested = 1;
-		if (systemf("xz -V %s", redirectArgs) == 0)
-			value = 1;
-	}
-	return (value);
-}
-
-/*
- * Can this filesystem handle nodump flags.
- */
-#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP)
-
-int
-canNodump(void)
-{
-	const char *path = "cannodumptest";
-	struct stat sb;
-
-	assertion_make_file(__FILE__, __LINE__, path, 0644, 0, NULL);
-	if (chflags(path, UF_NODUMP) < 0)
-		return (0);
-	if (stat(path, &sb) < 0)
-		return (0);
-	if (sb.st_flags & UF_NODUMP)
-		return (1);
-	return (0);
-}
-
-#elif defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)\
-	 && defined(EXT2_NODUMP_FL)
-
-int
-canNodump(void)
-{
-	const char *path = "cannodumptest";
-	int fd, r, flags;
-
-	assertion_make_file(__FILE__, __LINE__, path, 0644, 0, NULL);
-	fd = open(path, O_RDONLY | O_NONBLOCK);
-	if (fd < 0)
-		return (0);
-	r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags);
-	if (r < 0)
-		return (0);
-	flags |= EXT2_NODUMP_FL;
-	r = ioctl(fd, EXT2_IOC_SETFLAGS, &flags);
-	if (r < 0)
-		return (0);
-	close(fd);
-	fd = open(path, O_RDONLY | O_NONBLOCK);
-	if (fd < 0)
-		return (0);
-	r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags);
-	if (r < 0)
-		return (0);
-	close(fd);
-	if (flags & EXT2_NODUMP_FL)
-		return (1);
-	return (0);
-}
-
-#else
-
-int
-canNodump()
-{
-	return (0);
-}
-
-#endif
-
-/*
- * Sleep as needed; useful for verifying disk timestamp changes by
- * ensuring that the wall-clock time has actually changed before we
- * go back to re-read something from disk.
- */
-void
-sleepUntilAfter(time_t t)
-{
-	while (t >= time(NULL))
-#if defined(_WIN32) && !defined(__CYGWIN__)
-		Sleep(500);
-#else
-		sleep(1);
-#endif
-}
-
-/*
- * Call standard system() call, but build up the command line using
- * sprintf() conventions.
- */
-int
-systemf(const char *fmt, ...)
-{
-	char buff[8192];
-	va_list ap;
-	int r;
-
-	va_start(ap, fmt);
-	vsprintf(buff, fmt, ap);
-	if (verbosity > VERBOSITY_FULL)
-		logprintf("Cmd: %s\n", buff);
-	r = system(buff);
-	va_end(ap);
-	return (r);
-}
-
-/*
- * Slurp a file into memory for ease of comparison and testing.
- * Returns size of file in 'sizep' if non-NULL, null-terminates
- * data in memory for ease of use.
- */
-char *
-slurpfile(size_t * sizep, const char *fmt, ...)
-{
-	char filename[8192];
-	struct stat st;
-	va_list ap;
-	char *p;
-	ssize_t bytes_read;
-	FILE *f;
-	int r;
-
-	va_start(ap, fmt);
-	vsprintf(filename, fmt, ap);
-	va_end(ap);
-
-	f = fopen(filename, "rb");
-	if (f == NULL) {
-		/* Note: No error; non-existent file is okay here. */
-		return (NULL);
-	}
-	r = fstat(fileno(f), &st);
-	if (r != 0) {
-		logprintf("Can't stat file %s\n", filename);
-		fclose(f);
-		return (NULL);
-	}
-	p = malloc((size_t)st.st_size + 1);
-	if (p == NULL) {
-		logprintf("Can't allocate %ld bytes of memory to read file %s\n",
-		    (long int)st.st_size, filename);
-		fclose(f);
-		return (NULL);
-	}
-	bytes_read = fread(p, 1, (size_t)st.st_size, f);
-	if (bytes_read < st.st_size) {
-		logprintf("Can't read file %s\n", filename);
-		fclose(f);
-		free(p);
-		return (NULL);
-	}
-	p[st.st_size] = '\0';
-	if (sizep != NULL)
-		*sizep = (size_t)st.st_size;
-	fclose(f);
-	return (p);
-}
-
-/*
- * Slurp a file into memory for ease of comparison and testing.
- * Returns size of file in 'sizep' if non-NULL, null-terminates
- * data in memory for ease of use.
- */
-void
-dumpfile(const char *filename, void *data, size_t len)
-{
-	ssize_t bytes_written;
-	FILE *f;
-
-	f = fopen(filename, "wb");
-	if (f == NULL) {
-		logprintf("Can't open file %s for writing\n", filename);
-		return;
-	}
-	bytes_written = fwrite(data, 1, len, f);
-	if (bytes_written < (ssize_t)len)
-		logprintf("Can't write file %s\n", filename);
-	fclose(f);
-}
-
-/* Read a uuencoded file from the reference directory, decode, and
- * write the result into the current directory. */
-#define VALID_UUDECODE(c) (c >= 32 && c <= 96)
-#define	UUDECODE(c) (((c) - 0x20) & 0x3f)
-void
-extract_reference_file(const char *name)
-{
-	char buff[1024];
-	FILE *in, *out;
-
-	sprintf(buff, "%s/%s.uu", refdir, name);
-	in = fopen(buff, "r");
-	failure("Couldn't open reference file %s", buff);
-	assert(in != NULL);
-	if (in == NULL)
-		return;
-	/* Read up to and including the 'begin' line. */
-	for (;;) {
-		if (fgets(buff, sizeof(buff), in) == NULL) {
-			/* TODO: This is a failure. */
-			return;
-		}
-		if (memcmp(buff, "begin ", 6) == 0)
-			break;
-	}
-	/* Now, decode the rest and write it. */
-	out = fopen(name, "wb");
-	while (fgets(buff, sizeof(buff), in) != NULL) {
-		char *p = buff;
-		int bytes;
-
-		if (memcmp(buff, "end", 3) == 0)
-			break;
-
-		bytes = UUDECODE(*p++);
-		while (bytes > 0) {
-			int n = 0;
-			/* Write out 1-3 bytes from that. */
-			if (bytes > 0) {
-				assert(VALID_UUDECODE(p[0]));
-				assert(VALID_UUDECODE(p[1]));
-				n = UUDECODE(*p++) << 18;
-				n |= UUDECODE(*p++) << 12;
-				fputc(n >> 16, out);
-				--bytes;
-			}
-			if (bytes > 0) {
-				assert(VALID_UUDECODE(p[0]));
-				n |= UUDECODE(*p++) << 6;
-				fputc((n >> 8) & 0xFF, out);
-				--bytes;
-			}
-			if (bytes > 0) {
-				assert(VALID_UUDECODE(p[0]));
-				n |= UUDECODE(*p++);
-				fputc(n & 0xFF, out);
-				--bytes;
-			}
-		}
-	}
-	fclose(out);
-	fclose(in);
-}
-
-void
-copy_reference_file(const char *name)
-{
-	char buff[1024];
-	FILE *in, *out;
-	size_t rbytes;
-
-	sprintf(buff, "%s/%s", refdir, name);
-	in = fopen(buff, "rb");
-	failure("Couldn't open reference file %s", buff);
-	assert(in != NULL);
-	if (in == NULL)
-		return;
-	/* Now, decode the rest and write it. */
-	/* Not a lot of error checking here; the input better be right. */
-	out = fopen(name, "wb");
-	while ((rbytes = fread(buff, 1, sizeof(buff), in)) > 0) {
-		if (fwrite(buff, 1, rbytes, out) != rbytes) {
-			logprintf("Error: fwrite\n");
-			break;
-		}
-	}
-	fclose(out);
-	fclose(in);
-}
-
-int
-is_LargeInode(const char *file)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	BY_HANDLE_FILE_INFORMATION bhfi;
-	int r;
-
-	r = my_GetFileInformationByName(file, &bhfi);
-	if (r != 0)
-		return (0);
-	return (bhfi.nFileIndexHigh & 0x0000FFFFUL);
-#else
-	struct stat st;
-	int64_t ino;
-
-	if (stat(file, &st) < 0)
-		return (0);
-	ino = (int64_t)st.st_ino;
-	return (ino > 0xffffffff);
-#endif
-}
-
-void
-extract_reference_files(const char **names)
-{
-	while (names && *names)
-		extract_reference_file(*names++);
-}
-
-/*
- *
- * TEST management
- *
- */
-
-/*
- * "list.h" is simply created by "grep DEFINE_TEST test_*.c"; it has
- * a line like
- *      DEFINE_TEST(test_function)
- * for each test.
- */
-
-/* Use "list.h" to declare all of the test functions. */
-#undef DEFINE_TEST
-#define	DEFINE_TEST(name) void name(void);
-#include "list.h"
-
-/* Use "list.h" to create a list of all tests (functions and names). */
-#undef DEFINE_TEST
-#define	DEFINE_TEST(n) { n, #n, 0 },
-struct test_list_t tests[] = {
-	#include "list.h"
-};
-
-/*
- * Summarize repeated failures in the just-completed test.
- */
-static void
-test_summarize(int failed, int skips_num)
-{
-	unsigned int i;
-
-	switch (verbosity) {
-	case VERBOSITY_SUMMARY_ONLY:
-		printf(failed ? "E" : ".");
-		fflush(stdout);
-		break;
-	case VERBOSITY_PASSFAIL:
-		printf(failed ? "FAIL\n" : skips_num ? "ok (S)\n" : "ok\n");
-		break;
-	}
-
-	log_console = (verbosity == VERBOSITY_LIGHT_REPORT);
-
-	for (i = 0; i < sizeof(failed_lines)/sizeof(failed_lines[0]); i++) {
-		if (failed_lines[i].count > 1 && !failed_lines[i].skip)
-			logprintf("%s:%d: Summary: Failed %d times\n",
-			    failed_filename, i, failed_lines[i].count);
-	}
-	/* Clear the failure history for the next file. */
-	failed_filename = NULL;
-	memset(failed_lines, 0, sizeof(failed_lines));
-}
-
-/*
- * Actually run a single test, with appropriate setup and cleanup.
- */
-static int
-test_run(int i, const char *tmpdir)
-{
-	char workdir[1024];
-	char logfilename[64];
-	int failures_before = failures;
-	int skips_before = skips;
-	int oldumask;
-
-	switch (verbosity) {
-	case VERBOSITY_SUMMARY_ONLY: /* No per-test reports at all */
-		break;
-	case VERBOSITY_PASSFAIL: /* rest of line will include ok/FAIL marker */
-		printf("%3d: %-64s", i, tests[i].name);
-		fflush(stdout);
-		break;
-	default: /* Title of test, details will follow */
-		printf("%3d: %s\n", i, tests[i].name);
-	}
-
-	/* Chdir to the top-level work directory. */
-	if (!assertChdir(tmpdir)) {
-		fprintf(stderr,
-		    "ERROR: Can't chdir to top work dir %s\n", tmpdir);
-		exit(1);
-	}
-	/* Create a log file for this test. */
-	sprintf(logfilename, "%s.log", tests[i].name);
-	logfile = fopen(logfilename, "w");
-	fprintf(logfile, "%s\n\n", tests[i].name);
-	/* Chdir() to a work dir for this specific test. */
-	snprintf(workdir, sizeof(workdir), "%s/%s", tmpdir, tests[i].name);
-	testworkdir = workdir;
-	if (!assertMakeDir(testworkdir, 0755)
-	    || !assertChdir(testworkdir)) {
-		fprintf(stderr,
-		    "ERROR: Can't chdir to work dir %s\n", testworkdir);
-		exit(1);
-	}
-	/* Explicitly reset the locale before each test. */
-	setlocale(LC_ALL, "C");
-	/* Record the umask before we run the test. */
-	umask(oldumask = umask(0));
-	/*
-	 * Run the actual test.
-	 */
-	(*tests[i].func)();
-	/*
-	 * Clean up and report afterwards.
-	 */
-	testworkdir = NULL;
-	/* Restore umask */
-	umask(oldumask);
-	/* Reset locale. */
-	setlocale(LC_ALL, "C");
-	/* Reset directory. */
-	if (!assertChdir(tmpdir)) {
-		fprintf(stderr, "ERROR: Couldn't chdir to temp dir %s\n",
-		    tmpdir);
-		exit(1);
-	}
-	/* Report per-test summaries. */
-	tests[i].failures = failures - failures_before;
-	test_summarize(tests[i].failures, skips - skips_before);
-	/* Close the per-test log file. */
-	fclose(logfile);
-	logfile = NULL;
-	/* If there were no failures, we can remove the work dir and logfile. */
-	if (tests[i].failures == 0) {
-		if (!keep_temp_files && assertChdir(tmpdir)) {
-#if defined(_WIN32) && !defined(__CYGWIN__)
-			/* Make sure not to leave empty directories.
-			 * Sometimes a processing of closing files used by tests
-			 * is not done, then rmdir will be failed and it will
-			 * leave a empty test directory. So we should wait a few
-			 * seconds and retry rmdir. */
-			int r, t;
-			for (t = 0; t < 10; t++) {
-				if (t > 0)
-					Sleep(1000);
-				r = systemf("rmdir /S /Q %s", tests[i].name);
-				if (r == 0)
-					break;
-			}
-			systemf("del %s", logfilename);
-#else
-			systemf("rm -rf %s", tests[i].name);
-			systemf("rm %s", logfilename);
-#endif
-		}
-	}
-	/* Return appropriate status. */
-	return (tests[i].failures);
-}
-
-/*
- *
- *
- * MAIN and support routines.
- *
- *
- */
-
-static void
-usage(const char *program)
-{
-	static const int limit = sizeof(tests) / sizeof(tests[0]);
-	int i;
-
-	printf("Usage: %s [options] <test> <test> ...\n", program);
-	printf("Default is to run all tests.\n");
-	printf("Otherwise, specify the numbers of the tests you wish to run.\n");
-	printf("Options:\n");
-	printf("  -d  Dump core after any failure, for debugging.\n");
-	printf("  -k  Keep all temp files.\n");
-	printf("      Default: temp files for successful tests deleted.\n");
-#ifdef PROGRAM
-	printf("  -p <path>  Path to executable to be tested.\n");
-	printf("      Default: path taken from " ENVBASE " environment variable.\n");
-#endif
-	printf("  -q  Quiet.\n");
-	printf("  -r <dir>   Path to dir containing reference files.\n");
-	printf("      Default: Current directory.\n");
-	printf("  -u  Keep running specifies tests until one fails.\n");
-	printf("  -v  Verbose.\n");
-	printf("Available tests:\n");
-	for (i = 0; i < limit; i++)
-		printf("  %d: %s\n", i, tests[i].name);
-	exit(1);
-}
-
-static char *
-get_refdir(const char *d)
-{
-	size_t tried_size, buff_size;
-	char *buff, *tried, *pwd = NULL, *p = NULL;
-
-#ifdef PATH_MAX
-	buff_size = PATH_MAX;
-#else
-	buff_size = 8192;
-#endif
-	buff = calloc(buff_size, 1);
-	if (buff == NULL) {
-		fprintf(stderr, "Unable to allocate memory\n");
-		exit(1);
-	}
-
-	/* Allocate a buffer to hold the various directories we checked. */
-	tried_size = buff_size * 2;
-	tried = calloc(tried_size, 1);
-	if (tried == NULL) {
-		fprintf(stderr, "Unable to allocate memory\n");
-		exit(1);
-	}
-
-	/* If a dir was specified, try that */
-	if (d != NULL) {
-		pwd = NULL;
-		snprintf(buff, buff_size, "%s", d);
-		p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
-		if (p != NULL) goto success;
-		strncat(tried, buff, tried_size - strlen(tried) - 1);
-		strncat(tried, "\n", tried_size - strlen(tried) - 1);
-		goto failure;
-	}
-
-	/* Get the current dir. */
-#ifdef PATH_MAX
-	pwd = getcwd(NULL, PATH_MAX);/* Solaris getcwd needs the size. */
-#else
-	pwd = getcwd(NULL, 0);
-#endif
-	while (pwd[strlen(pwd) - 1] == '\n')
-		pwd[strlen(pwd) - 1] = '\0';
-
-	/* Look for a known file. */
-	snprintf(buff, buff_size, "%s", pwd);
-	p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
-	if (p != NULL) goto success;
-	strncat(tried, buff, tried_size - strlen(tried) - 1);
-	strncat(tried, "\n", tried_size - strlen(tried) - 1);
-
-	snprintf(buff, buff_size, "%s/test", pwd);
-	p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
-	if (p != NULL) goto success;
-	strncat(tried, buff, tried_size - strlen(tried) - 1);
-	strncat(tried, "\n", tried_size - strlen(tried) - 1);
-
-#if defined(LIBRARY)
-	snprintf(buff, buff_size, "%s/%s/test", pwd, LIBRARY);
-#else
-	snprintf(buff, buff_size, "%s/%s/test", pwd, PROGRAM);
-#endif
-	p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
-	if (p != NULL) goto success;
-	strncat(tried, buff, tried_size - strlen(tried) - 1);
-	strncat(tried, "\n", tried_size - strlen(tried) - 1);
-
-#if defined(PROGRAM_ALIAS)
-	snprintf(buff, buff_size, "%s/%s/test", pwd, PROGRAM_ALIAS);
-	p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
-	if (p != NULL) goto success;
-	strncat(tried, buff, tried_size - strlen(tried) - 1);
-	strncat(tried, "\n", tried_size - strlen(tried) - 1);
-#endif
-
-	if (memcmp(pwd, "/usr/obj", 8) == 0) {
-		snprintf(buff, buff_size, "%s", pwd + 8);
-		p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
-		if (p != NULL) goto success;
-		strncat(tried, buff, tried_size - strlen(tried) - 1);
-		strncat(tried, "\n", tried_size - strlen(tried) - 1);
-
-		snprintf(buff, buff_size, "%s/test", pwd + 8);
-		p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
-		if (p != NULL) goto success;
-		strncat(tried, buff, tried_size - strlen(tried) - 1);
-		strncat(tried, "\n", tried_size - strlen(tried) - 1);
-	}
-
-failure:
-	printf("Unable to locate known reference file %s\n", KNOWNREF);
-	printf("  Checked following directories:\n%s\n", tried);
-	printf("Use -r option to specify full path to reference directory\n");
-#if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG)
-	DebugBreak();
-#endif
-	exit(1);
-
-success:
-	free(p);
-	free(pwd);
-	free(tried);
-
-	/* Copy result into a fresh buffer to reduce memory usage. */
-	p = strdup(buff);
-	free(buff);
-	return p;
-}
-
-int
-main(int argc, char **argv)
-{
-	static const int limit = sizeof(tests) / sizeof(tests[0]);
-	int test_set[sizeof(tests) / sizeof(tests[0])];
-	int i = 0, j = 0, tests_run = 0, tests_failed = 0, option;
-	time_t now;
-	char *refdir_alloc = NULL;
-	const char *progname;
-	char **saved_argv;
-	const char *tmp, *option_arg, *p;
-	char tmpdir[256], *pwd, *testprogdir, *tmp2 = NULL, *vlevel = NULL;
-	char tmpdir_timestamp[256];
-
-	(void)argc; /* UNUSED */
-
-	/* Get the current dir. */
-#ifdef PATH_MAX
-	pwd = getcwd(NULL, PATH_MAX);/* Solaris getcwd needs the size. */
-#else
-	pwd = getcwd(NULL, 0);
-#endif
-	while (pwd[strlen(pwd) - 1] == '\n')
-		pwd[strlen(pwd) - 1] = '\0';
-
-#if defined(HAVE__CrtSetReportMode) && !defined(__WATCOMC__)
-	/* To stop to run the default invalid parameter handler. */
-	_set_invalid_parameter_handler(invalid_parameter_handler);
-	/* Disable annoying assertion message box. */
-	_CrtSetReportMode(_CRT_ASSERT, 0);
-#endif
-
-	/*
-	 * Name of this program, used to build root of our temp directory
-	 * tree.
-	 */
-	progname = p = argv[0];
-	if ((testprogdir = (char *)malloc(strlen(progname) + 1)) == NULL)
-	{
-		fprintf(stderr, "ERROR: Out of memory.");
-		exit(1);
-	}
-	strcpy(testprogdir, progname);
-	while (*p != '\0') {
-		/* Support \ or / dir separators for Windows compat. */
-		if (*p == '/' || *p == '\\')
-		{
-			progname = p + 1;
-			i = j;
-		}
-		++p;
-		j++;
-	}
-	testprogdir[i] = '\0';
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	if (testprogdir[0] != '/' && testprogdir[0] != '\\' &&
-	    !(((testprogdir[0] >= 'a' && testprogdir[0] <= 'z') ||
-	       (testprogdir[0] >= 'A' && testprogdir[0] <= 'Z')) &&
-		testprogdir[1] == ':' &&
-		(testprogdir[2] == '/' || testprogdir[2] == '\\')))
-#else
-	if (testprogdir[0] != '/')
-#endif
-	{
-		/* Fixup path for relative directories. */
-		if ((testprogdir = (char *)realloc(testprogdir,
-			strlen(pwd) + 1 + strlen(testprogdir) + 1)) == NULL)
-		{
-			fprintf(stderr, "ERROR: Out of memory.");
-			exit(1);
-		}
-		memmove(testprogdir + strlen(pwd) + 1, testprogdir,
-		    strlen(testprogdir) + 1);
-		memcpy(testprogdir, pwd, strlen(pwd));
-		testprogdir[strlen(pwd)] = '/';
-	}
-
-#ifdef PROGRAM
-	/* Get the target program from environment, if available. */
-	testprogfile = getenv(ENVBASE);
-#endif
-
-	if (getenv("TMPDIR") != NULL)
-		tmp = getenv("TMPDIR");
-	else if (getenv("TMP") != NULL)
-		tmp = getenv("TMP");
-	else if (getenv("TEMP") != NULL)
-		tmp = getenv("TEMP");
-	else if (getenv("TEMPDIR") != NULL)
-		tmp = getenv("TEMPDIR");
-	else
-		tmp = "/tmp";
-
-	/* Allow -d to be controlled through the environment. */
-	if (getenv(ENVBASE "_DEBUG") != NULL)
-		dump_on_failure = 1;
-
-	/* Allow -v to be controlled through the environment. */
-	if (getenv("_VERBOSITY_LEVEL") != NULL)
-	{
-		vlevel = getenv("_VERBOSITY_LEVEL");
-		verbosity = atoi(vlevel);
-		if (verbosity < VERBOSITY_SUMMARY_ONLY || verbosity > VERBOSITY_FULL)
-		{
-			/* Unsupported verbosity levels are silently ignored */
-			vlevel = NULL;
-			verbosity = VERBOSITY_PASSFAIL;
-		}
-	}
-
-	/* Get the directory holding test files from environment. */
-	refdir = getenv(ENVBASE "_TEST_FILES");
-
-	/*
-	 * Parse options, without using getopt(), which isn't available
-	 * on all platforms.
-	 */
-	++argv; /* Skip program name */
-	while (*argv != NULL) {
-		if (**argv != '-')
-			break;
-		p = *argv++;
-		++p; /* Skip '-' */
-		while (*p != '\0') {
-			option = *p++;
-			option_arg = NULL;
-			/* If 'opt' takes an argument, parse that. */
-			if (option == 'p' || option == 'r') {
-				if (*p != '\0')
-					option_arg = p;
-				else if (*argv == NULL) {
-					fprintf(stderr,
-					    "Option -%c requires argument.\n",
-					    option);
-					usage(progname);
-				} else
-					option_arg = *argv++;
-				p = ""; /* End of this option word. */
-			}
-
-			/* Now, handle the option. */
-			switch (option) {
-			case 'd':
-				dump_on_failure = 1;
-				break;
-			case 'k':
-				keep_temp_files = 1;
-				break;
-			case 'p':
-#ifdef PROGRAM
-				testprogfile = option_arg;
-#else
-				fprintf(stderr, "-p option not permitted\n");
-				usage(progname);
-#endif
-				break;
-			case 'q':
-				if (!vlevel)
-					verbosity--;
-				break;
-			case 'r':
-				refdir = option_arg;
-				break;
-			case 'u':
-				until_failure++;
-				break;
-			case 'v':
-				if (!vlevel)
-					verbosity++;
-				break;
-			default:
-				fprintf(stderr, "Unrecognized option '%c'\n",
-				    option);
-				usage(progname);
-			}
-		}
-	}
-
-	/*
-	 * Sanity-check that our options make sense.
-	 */
-#ifdef PROGRAM
-	if (testprogfile == NULL)
-	{
-		if ((tmp2 = (char *)malloc(strlen(testprogdir) + 1 +
-			strlen(PROGRAM) + 1)) == NULL)
-		{
-			fprintf(stderr, "ERROR: Out of memory.");
-			exit(1);
-		}
-		strcpy(tmp2, testprogdir);
-		strcat(tmp2, "/");
-		strcat(tmp2, PROGRAM);
-		testprogfile = tmp2;
-	}
-
-	{
-		char *testprg;
-#if defined(_WIN32) && !defined(__CYGWIN__)
-		/* Command.com sometimes rejects '/' separators. */
-		testprg = strdup(testprogfile);
-		for (i = 0; testprg[i] != '\0'; i++) {
-			if (testprg[i] == '/')
-				testprg[i] = '\\';
-		}
-		testprogfile = testprg;
-#endif
-		/* Quote the name that gets put into shell command lines. */
-		testprg = malloc(strlen(testprogfile) + 3);
-		strcpy(testprg, "\"");
-		strcat(testprg, testprogfile);
-		strcat(testprg, "\"");
-		testprog = testprg;
-	}
-#endif
-
-#if !defined(_WIN32) && defined(SIGPIPE)
-	{   /* Ignore SIGPIPE signals */
-		struct sigaction sa;
-		sa.sa_handler = SIG_IGN;
-		sigemptyset(&sa.sa_mask);
-		sa.sa_flags = 0;
-		sigaction(SIGPIPE, &sa, NULL);
-	}
-#endif
-
-	/*
-	 * Create a temp directory for the following tests.
-	 * Include the time the tests started as part of the name,
-	 * to make it easier to track the results of multiple tests.
-	 */
-	now = time(NULL);
-	for (i = 0; ; i++) {
-		strftime(tmpdir_timestamp, sizeof(tmpdir_timestamp),
-		    "%Y-%m-%dT%H.%M.%S",
-		    localtime(&now));
-		sprintf(tmpdir, "%s/%s.%s-%03d", tmp, progname,
-		    tmpdir_timestamp, i);
-		if (assertMakeDir(tmpdir,0755))
-			break;
-		if (i >= 999) {
-			fprintf(stderr,
-			    "ERROR: Unable to create temp directory %s\n",
-			    tmpdir);
-			exit(1);
-		}
-	}
-
-	/*
-	 * If the user didn't specify a directory for locating
-	 * reference files, try to find the reference files in
-	 * the "usual places."
-	 */
-	refdir = refdir_alloc = get_refdir(refdir);
-
-	/*
-	 * Banner with basic information.
-	 */
-	printf("\n");
-	printf("If tests fail or crash, details will be in:\n");
-	printf("   %s\n", tmpdir);
-	printf("\n");
-	if (verbosity > VERBOSITY_SUMMARY_ONLY) {
-		printf("Reference files will be read from: %s\n", refdir);
-#ifdef PROGRAM
-		printf("Running tests on: %s\n", testprog);
-#endif
-		printf("Exercising: ");
-		fflush(stdout);
-		printf("%s\n", EXTRA_VERSION);
-	} else {
-		printf("Running ");
-		fflush(stdout);
-	}
-
-	/*
-	 * Run some or all of the individual tests.
-	 */
-	saved_argv = argv;
-	do {
-		argv = saved_argv;
-		do {
-			int test_num;
-
-			test_num = get_test_set(test_set, limit, *argv, tests);
-			if (test_num < 0) {
-				printf("*** INVALID Test %s\n", *argv);
-				free(refdir_alloc);
-				free(testprogdir);
-				usage(progname);
-				return (1);
-			}
-			for (i = 0; i < test_num; i++) {
-				tests_run++;
-				if (test_run(test_set[i], tmpdir)) {
-					tests_failed++;
-					if (until_failure)
-						goto finish;
-				}
-			}
-			if (*argv != NULL)
-				argv++;
-		} while (*argv != NULL);
-	} while (until_failure);
-
-finish:
-	/* Must be freed after all tests run */
-	free(tmp2);
-	free(testprogdir);
-	free(pwd);
-
-	/*
-	 * Report summary statistics.
-	 */
-	if (verbosity > VERBOSITY_SUMMARY_ONLY) {
-		printf("\n");
-		printf("Totals:\n");
-		printf("  Tests run:         %8d\n", tests_run);
-		printf("  Tests failed:      %8d\n", tests_failed);
-		printf("  Assertions checked:%8d\n", assertions);
-		printf("  Assertions failed: %8d\n", failures);
-		printf("  Skips reported:    %8d\n", skips);
-	}
-	if (failures) {
-		printf("\n");
-		printf("Failing tests:\n");
-		for (i = 0; i < limit; ++i) {
-			if (tests[i].failures)
-				printf("  %d: %s (%d failures)\n", i,
-				    tests[i].name, tests[i].failures);
-		}
-		printf("\n");
-		printf("Details for failing tests: %s\n", tmpdir);
-		printf("\n");
-	} else {
-		if (verbosity == VERBOSITY_SUMMARY_ONLY)
-			printf("\n");
-		printf("%d tests passed, no failures\n", tests_run);
-	}
-
-	free(refdir_alloc);
-
-	/* If the final tmpdir is empty, we can remove it. */
-	/* This should be the usual case when all tests succeed. */
-	assertChdir("..");
-	rmdir(tmpdir);
-
-	return (tests_failed ? 1 : 0);
-}
diff --git a/cat/test/test.h b/cat/test/test.h
index 3a23a05..350bcad 100644
--- a/cat/test/test.h
+++ b/cat/test/test.h
@@ -22,333 +22,19 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/usr.bin/tar/test/test.h,v 1.4 2008/08/21 07:04:57 kientzle Exp $
+ * $FreeBSD$
  */
 
 /* Every test program should #include "test.h" as the first thing. */
 
-/*
- * The goal of this file (and the matching test.c) is to
- * simplify the very repetitive test-*.c test programs.
- */
-#if defined(HAVE_CONFIG_H)
-/* Most POSIX platforms use the 'configure' script to build config.h */
-#include "config.h"
-#elif defined(__FreeBSD__)
-/* Building as part of FreeBSD system requires a pre-built config.h. */
-#include "config_freebsd.h"
-#elif defined(_WIN32) && !defined(__CYGWIN__)
-/* Win32 can't run the 'configure' script. */
-#include "config_windows.h"
-#else
-/* Warn if the library hasn't been (automatically or manually) configured. */
-#error Oops: No config.h and no pre-built configuration in test.h.
-#endif
+#define KNOWNREF       "test_expand.Z.uu"
+#define ENVBASE "BSDCAT"  /* Prefix for environment variables. */
+#define	PROGRAM "bsdcat"  /* Name of program being tested. */
+#define PROGRAM_ALIAS "cat" /* Generic alias for program */
+#undef	LIBRARY		  /* Not testing a library. */
+#undef	EXTRA_DUMP	  /* How to dump extra data */
+#undef	EXTRA_ERRNO	  /* How to dump errno */
+/* How to generate extra version info. */
+#define	EXTRA_VERSION    (systemf("%s --version", testprog) ? "" : "")
 
-#include <sys/types.h>  /* Windows requires this before sys/stat.h */
-#include <sys/stat.h>
-
-#if HAVE_DIRENT_H
-#include <dirent.h>
-#endif
-#ifdef HAVE_DIRECT_H
-#include <direct.h>
-#define dirent direct
-#endif
-#include <errno.h>
-#include <fcntl.h>
-#ifdef HAVE_IO_H
-#include <io.h>
-#endif
-#ifdef HAVE_STDINT_H
-#include <stdint.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <time.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <wchar.h>
-#ifdef HAVE_WINDOWS_H
-#include <windows.h>
-#endif
-
-/*
- * System-specific tweaks.  We really want to minimize these
- * as much as possible, since they make it harder to understand
- * the mainline code.
- */
-
-/* Windows (including Visual Studio and MinGW but not Cygwin) */
-#if defined(_WIN32) && !defined(__CYGWIN__)
-#if !defined(__BORLANDC__)
-#undef chdir
-#define chdir _chdir
-#define strdup _strdup
-#endif
-#endif
-
-/* Visual Studio */
-#if defined(_MSC_VER) && _MSC_VER < 1900
-#define snprintf	sprintf_s
-#endif
-
-#if defined(__BORLANDC__)
-#pragma warn -8068	/* Constant out of range in comparison. */
-#endif
-
-/* Haiku OS and QNX */
-#if defined(__HAIKU__) || defined(__QNXNTO__)
-/* Haiku and QNX have typedefs in stdint.h (needed for int64_t) */
-#include <stdint.h>
-#endif
-
-/* Get a real definition for __FBSDID if we can */
-#if HAVE_SYS_CDEFS_H
-#include <sys/cdefs.h>
-#endif
-
-/* If not, define it so as to avoid dangling semicolons. */
-#ifndef __FBSDID
-#define	__FBSDID(a)     struct _undefined_hack
-#endif
-
-#ifndef O_BINARY
-#define	O_BINARY 0
-#endif
-
-/*
- * Redefine DEFINE_TEST for use in defining the test functions.
- */
-#undef DEFINE_TEST
-#define DEFINE_TEST(name) void name(void); void name(void)
-
-/* An implementation of the standard assert() macro */
-#define assert(e)   assertion_assert(__FILE__, __LINE__, (e), #e, NULL)
-/* chdir() and error if it fails */
-#define assertChdir(path)  \
-  assertion_chdir(__FILE__, __LINE__, path)
-/* Assert two integers are the same.  Reports value of each one if not. */
-#define assertEqualInt(v1,v2) \
-  assertion_equal_int(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL)
-/* Assert two strings are the same.  Reports value of each one if not. */
-#define assertEqualString(v1,v2)   \
-  assertion_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL, 0)
-#define assertEqualUTF8String(v1,v2)   \
-  assertion_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL, 1)
-/* As above, but v1 and v2 are wchar_t * */
-#define assertEqualWString(v1,v2)   \
-  assertion_equal_wstring(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL)
-/* As above, but raw blocks of bytes. */
-#define assertEqualMem(v1, v2, l)	\
-  assertion_equal_mem(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (l), #l, NULL)
-/* Assert that memory is full of a specified byte */
-#define assertMemoryFilledWith(v1, l, b)					\
-  assertion_memory_filled_with(__FILE__, __LINE__, (v1), #v1, (l), #l, (b), #b, NULL)
-/* Assert two files are the same. */
-#define assertEqualFile(f1, f2)	\
-  assertion_equal_file(__FILE__, __LINE__, (f1), (f2))
-/* Assert that a file is empty. */
-#define assertEmptyFile(pathname)	\
-  assertion_empty_file(__FILE__, __LINE__, (pathname))
-/* Assert that a file is not empty. */
-#define assertNonEmptyFile(pathname)		\
-  assertion_non_empty_file(__FILE__, __LINE__, (pathname))
-#define assertFileAtime(pathname, sec, nsec)	\
-  assertion_file_atime(__FILE__, __LINE__, pathname, sec, nsec)
-#define assertFileAtimeRecent(pathname)	\
-  assertion_file_atime_recent(__FILE__, __LINE__, pathname)
-#define assertFileBirthtime(pathname, sec, nsec)	\
-  assertion_file_birthtime(__FILE__, __LINE__, pathname, sec, nsec)
-#define assertFileBirthtimeRecent(pathname) \
-  assertion_file_birthtime_recent(__FILE__, __LINE__, pathname)
-/* Assert that a file exists; supports printf-style arguments. */
-#define assertFileExists(pathname) \
-  assertion_file_exists(__FILE__, __LINE__, pathname)
-/* Assert that a file exists. */
-#define assertFileNotExists(pathname) \
-  assertion_file_not_exists(__FILE__, __LINE__, pathname)
-/* Assert that file contents match a string. */
-#define assertFileContents(data, data_size, pathname) \
-  assertion_file_contents(__FILE__, __LINE__, data, data_size, pathname)
-/* Verify that a file does not contain invalid strings */
-#define assertFileContainsNoInvalidStrings(pathname, strings) \
-  assertion_file_contains_no_invalid_strings(__FILE__, __LINE__, pathname, strings)
-#define assertFileMtime(pathname, sec, nsec)	\
-  assertion_file_mtime(__FILE__, __LINE__, pathname, sec, nsec)
-#define assertFileMtimeRecent(pathname) \
-  assertion_file_mtime_recent(__FILE__, __LINE__, pathname)
-#define assertFileNLinks(pathname, nlinks)  \
-  assertion_file_nlinks(__FILE__, __LINE__, pathname, nlinks)
-#define assertFileSize(pathname, size)  \
-  assertion_file_size(__FILE__, __LINE__, pathname, size)
-#define assertFileMode(pathname, mode)  \
-  assertion_file_mode(__FILE__, __LINE__, pathname, mode)
-#define assertTextFileContents(text, pathname) \
-  assertion_text_file_contents(__FILE__, __LINE__, text, pathname)
-#define assertFileContainsLinesAnyOrder(pathname, lines)	\
-  assertion_file_contains_lines_any_order(__FILE__, __LINE__, pathname, lines)
-#define assertIsDir(pathname, mode)		\
-  assertion_is_dir(__FILE__, __LINE__, pathname, mode)
-#define assertIsHardlink(path1, path2)	\
-  assertion_is_hardlink(__FILE__, __LINE__, path1, path2)
-#define assertIsNotHardlink(path1, path2)	\
-  assertion_is_not_hardlink(__FILE__, __LINE__, path1, path2)
-#define assertIsReg(pathname, mode)		\
-  assertion_is_reg(__FILE__, __LINE__, pathname, mode)
-#define assertIsSymlink(pathname, contents)	\
-  assertion_is_symlink(__FILE__, __LINE__, pathname, contents)
-/* Create a directory, report error if it fails. */
-#define assertMakeDir(dirname, mode)	\
-  assertion_make_dir(__FILE__, __LINE__, dirname, mode)
-#define assertMakeFile(path, mode, contents) \
-  assertion_make_file(__FILE__, __LINE__, path, mode, -1, contents)
-#define assertMakeBinFile(path, mode, csize, contents) \
-  assertion_make_file(__FILE__, __LINE__, path, mode, csize, contents)
-#define assertMakeHardlink(newfile, oldfile)	\
-  assertion_make_hardlink(__FILE__, __LINE__, newfile, oldfile)
-#define assertMakeSymlink(newfile, linkto)	\
-  assertion_make_symlink(__FILE__, __LINE__, newfile, linkto)
-#define assertNodump(path)      \
-  assertion_nodump(__FILE__, __LINE__, path)
-#define assertUmask(mask)	\
-  assertion_umask(__FILE__, __LINE__, mask)
-#define assertUtimes(pathname, atime, atime_nsec, mtime, mtime_nsec)	\
-  assertion_utimes(__FILE__, __LINE__, pathname, atime, atime_nsec, mtime, mtime_nsec)
-
-/*
- * This would be simple with C99 variadic macros, but I don't want to
- * require that.  Instead, I insert a function call before each
- * skipping() call to pass the file and line information down.  Crude,
- * but effective.
- */
-#define skipping	\
-  skipping_setup(__FILE__, __LINE__);test_skipping
-
-/* Function declarations.  These are defined in test_utility.c. */
-void failure(const char *fmt, ...);
-int assertion_assert(const char *, int, int, const char *, void *);
-int assertion_chdir(const char *, int, const char *);
-int assertion_empty_file(const char *, int, const char *);
-int assertion_equal_file(const char *, int, const char *, const char *);
-int assertion_equal_int(const char *, int, long long, const char *, long long, const char *, void *);
-int assertion_equal_mem(const char *, int, const void *, const char *, const void *, const char *, size_t, const char *, void *);
-int assertion_memory_filled_with(const char *, int, const void *, const char *, size_t, const char *, char, const char *, void *);
-int assertion_equal_string(const char *, int, const char *v1, const char *, const char *v2, const char *, void *, int);
-int assertion_equal_wstring(const char *, int, const wchar_t *v1, const char *, const wchar_t *v2, const char *, void *);
-int assertion_file_atime(const char *, int, const char *, long, long);
-int assertion_file_atime_recent(const char *, int, const char *);
-int assertion_file_birthtime(const char *, int, const char *, long, long);
-int assertion_file_birthtime_recent(const char *, int, const char *);
-int assertion_file_contains_lines_any_order(const char *, int, const char *, const char **);
-int assertion_file_contains_no_invalid_strings(const char *, int, const char *, const char **);
-int assertion_file_contents(const char *, int, const void *, int, const char *);
-int assertion_file_exists(const char *, int, const char *);
-int assertion_file_mode(const char *, int, const char *, int);
-int assertion_file_mtime(const char *, int, const char *, long, long);
-int assertion_file_mtime_recent(const char *, int, const char *);
-int assertion_file_nlinks(const char *, int, const char *, int);
-int assertion_file_not_exists(const char *, int, const char *);
-int assertion_file_size(const char *, int, const char *, long);
-int assertion_is_dir(const char *, int, const char *, int);
-int assertion_is_hardlink(const char *, int, const char *, const char *);
-int assertion_is_not_hardlink(const char *, int, const char *, const char *);
-int assertion_is_reg(const char *, int, const char *, int);
-int assertion_is_symlink(const char *, int, const char *, const char *);
-int assertion_make_dir(const char *, int, const char *, int);
-int assertion_make_file(const char *, int, const char *, int, int, const void *);
-int assertion_make_hardlink(const char *, int, const char *newpath, const char *);
-int assertion_make_symlink(const char *, int, const char *newpath, const char *);
-int assertion_nodump(const char *, int, const char *);
-int assertion_non_empty_file(const char *, int, const char *);
-int assertion_text_file_contents(const char *, int, const char *buff, const char *f);
-int assertion_umask(const char *, int, int);
-int assertion_utimes(const char *, int, const char *, long, long, long, long );
-
-void skipping_setup(const char *, int);
-void test_skipping(const char *fmt, ...);
-
-/* Like sprintf, then system() */
-int systemf(const char * fmt, ...);
-
-/* Delay until time() returns a value after this. */
-void sleepUntilAfter(time_t);
-
-/* Return true if this platform can create symlinks. */
-int canSymlink(void);
-
-/* Return true if this platform can run the "bzip2" program. */
-int canBzip2(void);
-
-/* Return true if this platform can run the "grzip" program. */
-int canGrzip(void);
-
-/* Return true if this platform can run the "gzip" program. */
-int canGzip(void);
-
-/* Return true if this platform can run the specified command. */
-int canRunCommand(const char *);
-
-/* Return true if this platform can run the "lrzip" program. */
-int canLrzip(void);
-
-/* Return true if this platform can run the "lz4" program. */
-int canLz4(void);
-
-/* Return true if this platform can run the "lzip" program. */
-int canLzip(void);
-
-/* Return true if this platform can run the "lzma" program. */
-int canLzma(void);
-
-/* Return true if this platform can run the "lzop" program. */
-int canLzop(void);
-
-/* Return true if this platform can run the "xz" program. */
-int canXz(void);
-
-/* Return true if this filesystem can handle nodump flags. */
-int canNodump(void);
-
-/* Return true if the file has large i-node number(>0xffffffff). */
-int is_LargeInode(const char *);
-
-/* Suck file into string allocated via malloc(). Call free() when done. */
-/* Supports printf-style args: slurpfile(NULL, "%s/myfile", refdir); */
-char *slurpfile(size_t *, const char *fmt, ...);
-
-/* Dump block of bytes to a file. */
-void dumpfile(const char *filename, void *, size_t);
-
-/* Extracts named reference file to the current directory. */
-void extract_reference_file(const char *);
-/* Copies named reference file to the current directory. */
-void copy_reference_file(const char *);
-
-/* Extracts a list of files to the current directory.
- * List must be NULL terminated.
- */
-void extract_reference_files(const char **);
-
-/* Subtract umask from mode */
-mode_t umasked(mode_t expected_mode);
-
-/* Path to working directory for current test */
-extern const char *testworkdir;
-
-/*
- * Special interfaces for program test harness.
- */
-
-/* Pathname of exe to be tested. */
-extern const char *testprogfile;
-/* Name of exe to use in printf-formatted command strings. */
-/* On Windows, this includes leading/trailing quotes. */
-extern const char *testprog;
-
-#ifdef USE_DMALLOC
-#include <dmalloc.h>
-#endif
+#include "test_common.h"
diff --git a/cat/test/test_version.c b/cat/test/test_version.c
index e587b34..51a4fd4 100644
--- a/cat/test/test_version.c
+++ b/cat/test/test_version.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2003-2017 Tim Kientzle
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -30,68 +30,5 @@
 
 DEFINE_TEST(test_version)
 {
-	int r;
-	char *p, *q;
-	size_t s;
-
-
-	r = systemf("%s --version >version.stdout 2>version.stderr", testprog);
-	failure("Unable to run %s --version", testprog);
-	if (!assert(r == 0))
-		return;
-
-	/* --version should generate nothing to stdout. */
-	assertEmptyFile("version.stderr");
-	/* Verify format of version message. */
-	q = p = slurpfile(&s, "version.stdout");
-	/* Version message should start with name of program, then space. */
-	assert(s > 6);
-	failure("Version must start with 'bsdcat': ``%s''", p);
-	if (!assertEqualMem(q, "bsdcat ", 7))
-		return;
-	q += 7; s -= 7;
-	/* Version number is a series of digits and periods. */
-	while (s > 0 && (*q == '.' || (*q >= '0' && *q <= '9'))) {
-		++q;
-		--s;
-	}
-	/* Version number terminated by space. */
-	failure("No space after bsdcat version: ``%s''", p);
-	assert(s > 1);
-	/* Skip a single trailing a,b,c, or d. */
-	if (*q == 'a' || *q == 'b' || *q == 'c' || *q == 'd')
-		++q;
-	failure("No space after bsdcat version: ``%s''", p);
-	assert(*q == ' ');
-	++q; --s;
-	/* Separator. */
-	failure("No `-' between bsdcat and libarchive versions: ``%s''", p);
-	assertEqualMem(q, "- ", 2);
-	q += 2; s -= 2;
-	/* libarchive name and version number */
-	failure("Not long enough for libarchive version: ``%s''", p);
-	assert(s > 11);
-	failure("Libarchive version must start with `libarchive': ``%s''", p);
-	assertEqualMem(q, "libarchive ", 11);
-	q += 11; s -= 11;
-	/* Version number is a series of digits and periods. */
-	while (s > 0 && (*q == '.' || (*q >= '0' && *q <= '9'))) {
-		++q;
-		--s;
-	}
-	/* Skip a single trailing a,b,c, or d. */
-	if (*q == 'a' || *q == 'b' || *q == 'c' || *q == 'd')
-		++q;
-	/* Skip arbitrary third-party version numbers. */
-	while (s > 0 && (*q == ' ' || *q == '-' || *q == '/' || *q == '.' || isalnum(*q))) {
-		++q;
-		--s;
-	}
-	/* All terminated by end-of-line. */
-	assert(s >= 1);
-	/* Skip an optional CR character (e.g., Windows) */
-	failure("Version output must end with \\n or \\r\\n");
-	if (*q == '\r') { ++q; --s; }
-	assertEqualMem(q, "\n", 1);
-	free(p);
+	assertVersion(testprog, "bsdcat");
 }
diff --git a/configure.ac b/configure.ac
index f3b8fda..b29917e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -4,8 +4,8 @@
 dnl In particular, this allows the version macro to be used in AC_INIT
 
 dnl These first two version numbers are updated automatically on each release.
-m4_define([LIBARCHIVE_VERSION_S],[3.2.2])
-m4_define([LIBARCHIVE_VERSION_N],[3002002])
+m4_define([LIBARCHIVE_VERSION_S],[3.3.1dev])
+m4_define([LIBARCHIVE_VERSION_N],[3003001])
 
 dnl bsdtar and bsdcpio versioning tracks libarchive
 m4_define([BSDTAR_VERSION_S],LIBARCHIVE_VERSION_S())
@@ -270,6 +270,19 @@
 
 AC_CHECK_HEADERS([inttypes.h io.h langinfo.h limits.h])
 AC_CHECK_HEADERS([linux/fiemap.h linux/fs.h linux/magic.h linux/types.h])
+
+AC_CACHE_CHECK([whether FS_IOC_GETFLAGS is usable],
+    [ac_cv_have_decl_FS_IOC_GETFLAGS],
+    [AC_COMPILE_IFELSE([AC_LANG_PROGRAM([@%:@include <sys/ioctl.h>
+@%:@include <linux/fs.h>],
+                                   [int x = FS_IOC_GETFLAGS])],
+                  [AS_VAR_SET([ac_cv_have_decl_FS_IOC_GETFLAGS], [yes])],
+                  [AS_VAR_SET([ac_cv_have_decl_FS_IOC_GETFLAGS], [no])])])
+
+AS_VAR_IF([ac_cv_have_decl_FS_IOC_GETFLAGS], [yes],
+    [AC_DEFINE_UNQUOTED([HAVE_WORKING_FS_IOC_GETFLAGS], [1],
+                    [Define to 1 if you have a working FS_IOC_GETFLAGS])])
+
 AC_CHECK_HEADERS([locale.h paths.h poll.h pthread.h pwd.h])
 AC_CHECK_HEADERS([readpassphrase.h signal.h spawn.h])
 AC_CHECK_HEADERS([stdarg.h stdint.h stdlib.h string.h])
@@ -381,7 +394,7 @@
 AC_ARG_WITH([lzo2],
   AS_HELP_STRING([--with-lzo2], [Build with LZO support from liblzo2]))
 
-if test "x$with_lzo2" == "xyes"; then
+if test "x$with_lzo2" = "xyes"; then
   AC_CHECK_HEADERS([lzo/lzoconf.h lzo/lzo1x.h])
   AC_CHECK_LIB(lzo2,lzo1x_decompress_safe)
 fi
diff --git a/cpio/test/CMakeLists.txt b/cpio/test/CMakeLists.txt
index 8ffb542..ec9509b 100644
--- a/cpio/test/CMakeLists.txt
+++ b/cpio/test/CMakeLists.txt
@@ -8,7 +8,7 @@
     ../cmdline.c
     ../../libarchive_fe/err.c
     ../../test_utils/test_utils.c
-    main.c
+    ../../test_utils/test_main.c
     test.h
     test_0.c
     test_basic.c
@@ -87,6 +87,7 @@
   INCLUDE(${CMAKE_CURRENT_BINARY_DIR}/list.h)
   INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
   INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/test_utils)
+  INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/cpio/test)
 
   # Experimental new test handling
   ADD_CUSTOM_TARGET(run_bsdcpio_test
diff --git a/cpio/test/main.c b/cpio/test/main.c
deleted file mode 100644
index 34282f3..0000000
--- a/cpio/test/main.c
+++ /dev/null
@@ -1,3073 +0,0 @@
-/*
- * Copyright (c) 2003-2009 Tim Kientzle
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "test.h"
-#include "test_utils.h"
-#ifdef HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#include <errno.h>
-#ifdef HAVE_ICONV_H
-#include <iconv.h>
-#endif
-/*
- * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h.
- * As the include guards don't agree, the order of include is important.
- */
-#ifdef HAVE_LINUX_EXT2_FS_H
-#include <linux/ext2_fs.h>      /* for Linux file flags */
-#endif
-#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__)
-#include <ext2fs/ext2_fs.h>     /* Linux file flags, broken on Cygwin */
-#endif
-#include <limits.h>
-#include <locale.h>
-#ifdef HAVE_SIGNAL_H
-#include <signal.h>
-#endif
-#include <stdarg.h>
-#include <time.h>
-
-/*
- * This same file is used pretty much verbatim for all test harnesses.
- *
- * The next few lines are the only differences.
- * TODO: Move this into a separate configuration header, have all test
- * suites share one copy of this file.
- */
-__FBSDID("$FreeBSD: src/usr.bin/cpio/test/main.c,v 1.3 2008/08/24 04:58:22 kientzle Exp $");
-#define KNOWNREF	"test_option_f.cpio.uu"
-#define ENVBASE "BSDCPIO" /* Prefix for environment variables. */
-#define	PROGRAM "bsdcpio" /* Name of program being tested. */
-#define PROGRAM_ALIAS "cpio" /* Generic alias for program */
-#undef	LIBRARY		  /* Not testing a library. */
-#undef	EXTRA_DUMP	  /* How to dump extra data */
-#undef	EXTRA_ERRNO	  /* How to dump errno */
-/* How to generate extra version info. */
-#define	EXTRA_VERSION    (systemf("%s --version", testprog) ? "" : "")
-
-/*
- *
- * Windows support routines
- *
- * Note: Configuration is a tricky issue.  Using HAVE_* feature macros
- * in the test harness is dangerous because they cover up
- * configuration errors.  The classic example of this is omitting a
- * configure check.  If libarchive and libarchive_test both look for
- * the same feature macro, such errors are hard to detect.  Platform
- * macros (e.g., _WIN32 or __GNUC__) are a little better, but can
- * easily lead to very messy code.  It's best to limit yourself
- * to only the most generic programming techniques in the test harness
- * and thus avoid conditionals altogether.  Where that's not possible,
- * try to minimize conditionals by grouping platform-specific tests in
- * one place (e.g., test_acl_freebsd) or by adding new assert()
- * functions (e.g., assertMakeHardlink()) to cover up platform
- * differences.  Platform-specific coding in libarchive_test is often
- * a symptom that some capability is missing from libarchive itself.
- */
-#if defined(_WIN32) && !defined(__CYGWIN__)
-#include <io.h>
-#include <direct.h>
-#include <windows.h>
-#ifndef F_OK
-#define F_OK (0)
-#endif
-#ifndef S_ISDIR
-#define S_ISDIR(m)  ((m) & _S_IFDIR)
-#endif
-#ifndef S_ISREG
-#define S_ISREG(m)  ((m) & _S_IFREG)
-#endif
-#if !defined(__BORLANDC__)
-#define access _access
-#undef chdir
-#define chdir _chdir
-#endif
-#ifndef fileno
-#define fileno _fileno
-#endif
-/*#define fstat _fstat64*/
-#if !defined(__BORLANDC__)
-#define getcwd _getcwd
-#endif
-#define lstat stat
-/*#define lstat _stat64*/
-/*#define stat _stat64*/
-#define rmdir _rmdir
-#if !defined(__BORLANDC__)
-#define strdup _strdup
-#define umask _umask
-#endif
-#define int64_t __int64
-#endif
-
-#if defined(HAVE__CrtSetReportMode)
-# include <crtdbg.h>
-#endif
-
-mode_t umasked(mode_t expected_mode)
-{
-	mode_t mode = umask(0);
-	umask(mode);
-	return expected_mode & ~mode;
-}
-
-/* Path to working directory for current test */
-const char *testworkdir;
-#ifdef PROGRAM
-/* Pathname of exe to be tested. */
-const char *testprogfile;
-/* Name of exe to use in printf-formatted command strings. */
-/* On Windows, this includes leading/trailing quotes. */
-const char *testprog;
-#endif
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-static void	*GetFunctionKernel32(const char *);
-static int	 my_CreateSymbolicLinkA(const char *, const char *, int);
-static int	 my_CreateHardLinkA(const char *, const char *);
-static int	 my_GetFileInformationByName(const char *,
-		     BY_HANDLE_FILE_INFORMATION *);
-
-static void *
-GetFunctionKernel32(const char *name)
-{
-	static HINSTANCE lib;
-	static int set;
-	if (!set) {
-		set = 1;
-		lib = LoadLibrary("kernel32.dll");
-	}
-	if (lib == NULL) {
-		fprintf(stderr, "Can't load kernel32.dll?!\n");
-		exit(1);
-	}
-	return (void *)GetProcAddress(lib, name);
-}
-
-static int
-my_CreateSymbolicLinkA(const char *linkname, const char *target, int flags)
-{
-	static BOOLEAN (WINAPI *f)(LPCSTR, LPCSTR, DWORD);
-	static int set;
-	if (!set) {
-		set = 1;
-		f = GetFunctionKernel32("CreateSymbolicLinkA");
-	}
-	return f == NULL ? 0 : (*f)(linkname, target, flags);
-}
-
-static int
-my_CreateHardLinkA(const char *linkname, const char *target)
-{
-	static BOOLEAN (WINAPI *f)(LPCSTR, LPCSTR, LPSECURITY_ATTRIBUTES);
-	static int set;
-	if (!set) {
-		set = 1;
-		f = GetFunctionKernel32("CreateHardLinkA");
-	}
-	return f == NULL ? 0 : (*f)(linkname, target, NULL);
-}
-
-static int
-my_GetFileInformationByName(const char *path, BY_HANDLE_FILE_INFORMATION *bhfi)
-{
-	HANDLE h;
-	int r;
-
-	memset(bhfi, 0, sizeof(*bhfi));
-	h = CreateFile(path, FILE_READ_ATTRIBUTES, 0, NULL,
-		OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
-	if (h == INVALID_HANDLE_VALUE)
-		return (0);
-	r = GetFileInformationByHandle(h, bhfi);
-	CloseHandle(h);
-	return (r);
-}
-#endif
-
-#if defined(HAVE__CrtSetReportMode) && !defined(__WATCOMC__)
-static void
-invalid_parameter_handler(const wchar_t * expression,
-    const wchar_t * function, const wchar_t * file,
-    unsigned int line, uintptr_t pReserved)
-{
-	/* nop */
-}
-#endif
-
-/*
- *
- * OPTIONS FLAGS
- *
- */
-
-/* Enable core dump on failure. */
-static int dump_on_failure = 0;
-/* Default is to remove temp dirs and log data for successful tests. */
-static int keep_temp_files = 0;
-/* Default is to run the specified tests once and report errors. */
-static int until_failure = 0;
-/* Default is to just report pass/fail for each test. */
-static int verbosity = 0;
-#define	VERBOSITY_SUMMARY_ONLY -1 /* -q */
-#define VERBOSITY_PASSFAIL 0   /* Default */
-#define VERBOSITY_LIGHT_REPORT 1 /* -v */
-#define VERBOSITY_FULL 2 /* -vv */
-/* A few places generate even more output for verbosity > VERBOSITY_FULL,
- * mostly for debugging the test harness itself. */
-/* Cumulative count of assertion failures. */
-static int failures = 0;
-/* Cumulative count of reported skips. */
-static int skips = 0;
-/* Cumulative count of assertions checked. */
-static int assertions = 0;
-
-/* Directory where uuencoded reference files can be found. */
-static const char *refdir;
-
-/*
- * Report log information selectively to console and/or disk log.
- */
-static int log_console = 0;
-static FILE *logfile;
-static void
-vlogprintf(const char *fmt, va_list ap)
-{
-#ifdef va_copy
-	va_list lfap;
-	va_copy(lfap, ap);
-#endif
-	if (log_console)
-		vfprintf(stdout, fmt, ap);
-	if (logfile != NULL)
-#ifdef va_copy
-		vfprintf(logfile, fmt, lfap);
-	va_end(lfap);
-#else
-		vfprintf(logfile, fmt, ap);
-#endif
-}
-
-static void
-logprintf(const char *fmt, ...)
-{
-	va_list ap;
-	va_start(ap, fmt);
-	vlogprintf(fmt, ap);
-	va_end(ap);
-}
-
-/* Set up a message to display only if next assertion fails. */
-static char msgbuff[4096];
-static const char *msg, *nextmsg;
-void
-failure(const char *fmt, ...)
-{
-	va_list ap;
-	if (fmt == NULL) {
-		nextmsg = NULL;
-	} else {
-		va_start(ap, fmt);
-		vsprintf(msgbuff, fmt, ap);
-		va_end(ap);
-		nextmsg = msgbuff;
-	}
-}
-
-/*
- * Copy arguments into file-local variables.
- * This was added to permit vararg assert() functions without needing
- * variadic wrapper macros.  Turns out that the vararg capability is almost
- * never used, so almost all of the vararg assertions can be simplified
- * by removing the vararg capability and reworking the wrapper macro to
- * pass __FILE__, __LINE__ directly into the function instead of using
- * this hook.  I suspect this machinery is used so rarely that we
- * would be better off just removing it entirely.  That would simplify
- * the code here noticeably.
- */
-static const char *skipping_filename;
-static int skipping_line;
-void skipping_setup(const char *filename, int line)
-{
-	skipping_filename = filename;
-	skipping_line = line;
-}
-
-/* Called at the beginning of each assert() function. */
-static void
-assertion_count(const char *file, int line)
-{
-	(void)file; /* UNUSED */
-	(void)line; /* UNUSED */
-	++assertions;
-	/* Proper handling of "failure()" message. */
-	msg = nextmsg;
-	nextmsg = NULL;
-	/* Uncomment to print file:line after every assertion.
-	 * Verbose, but occasionally useful in tracking down crashes. */
-	/* printf("Checked %s:%d\n", file, line); */
-}
-
-/*
- * For each test source file, we remember how many times each
- * assertion was reported.  Cleared before each new test,
- * used by test_summarize().
- */
-static struct line {
-	int count;
-	int skip;
-}  failed_lines[10000];
-const char *failed_filename;
-
-/* Count this failure, setup up log destination and handle initial report. */
-static void
-failure_start(const char *filename, int line, const char *fmt, ...)
-{
-	va_list ap;
-
-	/* Record another failure for this line. */
-	++failures;
-	failed_filename = filename;
-	failed_lines[line].count++;
-
-	/* Determine whether to log header to console. */
-	switch (verbosity) {
-	case VERBOSITY_LIGHT_REPORT:
-		log_console = (failed_lines[line].count < 2);
-		break;
-	default:
-		log_console = (verbosity >= VERBOSITY_FULL);
-	}
-
-	/* Log file:line header for this failure */
-	va_start(ap, fmt);
-#if _MSC_VER
-	logprintf("%s(%d): ", filename, line);
-#else
-	logprintf("%s:%d: ", filename, line);
-#endif
-	vlogprintf(fmt, ap);
-	va_end(ap);
-	logprintf("\n");
-
-	if (msg != NULL && msg[0] != '\0') {
-		logprintf("   Description: %s\n", msg);
-		msg = NULL;
-	}
-
-	/* Determine whether to log details to console. */
-	if (verbosity == VERBOSITY_LIGHT_REPORT)
-		log_console = 0;
-}
-
-/* Complete reporting of failed tests. */
-/*
- * The 'extra' hook here is used by libarchive to include libarchive
- * error messages with assertion failures.  It could also be used
- * to add strerror() output, for example.  Just define the EXTRA_DUMP()
- * macro appropriately.
- */
-static void
-failure_finish(void *extra)
-{
-	(void)extra; /* UNUSED (maybe) */
-#ifdef EXTRA_DUMP
-	if (extra != NULL) {
-		logprintf("    errno: %d\n", EXTRA_ERRNO(extra));
-		logprintf("   detail: %s\n", EXTRA_DUMP(extra));
-	}
-#endif
-
-	if (dump_on_failure) {
-		fprintf(stderr,
-		    " *** forcing core dump so failure can be debugged ***\n");
-		abort();
-	}
-}
-
-/* Inform user that we're skipping some checks. */
-void
-test_skipping(const char *fmt, ...)
-{
-	char buff[1024];
-	va_list ap;
-
-	va_start(ap, fmt);
-	vsprintf(buff, fmt, ap);
-	va_end(ap);
-	/* Use failure() message if set. */
-	msg = nextmsg;
-	nextmsg = NULL;
-	/* failure_start() isn't quite right, but is awfully convenient. */
-	failure_start(skipping_filename, skipping_line, "SKIPPING: %s", buff);
-	--failures; /* Undo failures++ in failure_start() */
-	/* Don't failure_finish() here. */
-	/* Mark as skip, so doesn't count as failed test. */
-	failed_lines[skipping_line].skip = 1;
-	++skips;
-}
-
-/*
- *
- * ASSERTIONS
- *
- */
-
-/* Generic assert() just displays the failed condition. */
-int
-assertion_assert(const char *file, int line, int value,
-    const char *condition, void *extra)
-{
-	assertion_count(file, line);
-	if (!value) {
-		failure_start(file, line, "Assertion failed: %s", condition);
-		failure_finish(extra);
-	}
-	return (value);
-}
-
-/* chdir() and report any errors */
-int
-assertion_chdir(const char *file, int line, const char *pathname)
-{
-	assertion_count(file, line);
-	if (chdir(pathname) == 0)
-		return (1);
-	failure_start(file, line, "chdir(\"%s\")", pathname);
-	failure_finish(NULL);
-	return (0);
-
-}
-
-/* Verify two integers are equal. */
-int
-assertion_equal_int(const char *file, int line,
-    long long v1, const char *e1, long long v2, const char *e2, void *extra)
-{
-	assertion_count(file, line);
-	if (v1 == v2)
-		return (1);
-	failure_start(file, line, "%s != %s", e1, e2);
-	logprintf("      %s=%lld (0x%llx, 0%llo)\n", e1, v1, v1, v1);
-	logprintf("      %s=%lld (0x%llx, 0%llo)\n", e2, v2, v2, v2);
-	failure_finish(extra);
-	return (0);
-}
-
-/*
- * Utility to convert a single UTF-8 sequence.
- */
-static int
-_utf8_to_unicode(uint32_t *pwc, const char *s, size_t n)
-{
-	static const char utf8_count[256] = {
-		 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 00 - 0F */
-		 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 10 - 1F */
-		 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 20 - 2F */
-		 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 30 - 3F */
-		 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40 - 4F */
-		 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 50 - 5F */
-		 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 60 - 6F */
-		 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 70 - 7F */
-		 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 80 - 8F */
-		 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 90 - 9F */
-		 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* A0 - AF */
-		 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* B0 - BF */
-		 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,/* C0 - CF */
-		 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,/* D0 - DF */
-		 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,/* E0 - EF */
-		 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* F0 - FF */
-	};
-	int ch;
-	int cnt;
-	uint32_t wc;
-
-	*pwc = 0;
-
-	/* Sanity check. */
-	if (n == 0)
-		return (0);
-	/*
-	 * Decode 1-4 bytes depending on the value of the first byte.
-	 */
-	ch = (unsigned char)*s;
-	if (ch == 0)
-		return (0); /* Standard:  return 0 for end-of-string. */
-	cnt = utf8_count[ch];
-
-	/* Invalid sequence or there are not plenty bytes. */
-	if (n < (size_t)cnt)
-		return (-1);
-
-	/* Make a Unicode code point from a single UTF-8 sequence. */
-	switch (cnt) {
-	case 1:	/* 1 byte sequence. */
-		*pwc = ch & 0x7f;
-		return (cnt);
-	case 2:	/* 2 bytes sequence. */
-		if ((s[1] & 0xc0) != 0x80) return (-1);
-		*pwc = ((ch & 0x1f) << 6) | (s[1] & 0x3f);
-		return (cnt);
-	case 3:	/* 3 bytes sequence. */
-		if ((s[1] & 0xc0) != 0x80) return (-1);
-		if ((s[2] & 0xc0) != 0x80) return (-1);
-		wc = ((ch & 0x0f) << 12)
-		    | ((s[1] & 0x3f) << 6)
-		    | (s[2] & 0x3f);
-		if (wc < 0x800)
-			return (-1);/* Overlong sequence. */
-		break;
-	case 4:	/* 4 bytes sequence. */
-		if (n < 4)
-			return (-1);
-		if ((s[1] & 0xc0) != 0x80) return (-1);
-		if ((s[2] & 0xc0) != 0x80) return (-1);
-		if ((s[3] & 0xc0) != 0x80) return (-1);
-		wc = ((ch & 0x07) << 18)
-		    | ((s[1] & 0x3f) << 12)
-		    | ((s[2] & 0x3f) << 6)
-		    | (s[3] & 0x3f);
-		if (wc < 0x10000)
-			return (-1);/* Overlong sequence. */
-		break;
-	default:
-		return (-1);
-	}
-
-	/* The code point larger than 0x10FFFF is not legal
-	 * Unicode values. */
-	if (wc > 0x10FFFF)
-		return (-1);
-	/* Correctly gets a Unicode, returns used bytes. */
-	*pwc = wc;
-	return (cnt);
-}
-
-static void strdump(const char *e, const char *p, int ewidth, int utf8)
-{
-	const char *q = p;
-
-	logprintf("      %*s = ", ewidth, e);
-	if (p == NULL) {
-		logprintf("NULL\n");
-		return;
-	}
-	logprintf("\"");
-	while (*p != '\0') {
-		unsigned int c = 0xff & *p++;
-		switch (c) {
-		case '\a': logprintf("\\a"); break;
-		case '\b': logprintf("\\b"); break;
-		case '\n': logprintf("\\n"); break;
-		case '\r': logprintf("\\r"); break;
-		default:
-			if (c >= 32 && c < 127)
-				logprintf("%c", c);
-			else
-				logprintf("\\x%02X", c);
-		}
-	}
-	logprintf("\"");
-	logprintf(" (length %d)", q == NULL ? -1 : (int)strlen(q));
-
-	/*
-	 * If the current string is UTF-8, dump its code points.
-	 */
-	if (utf8) {
-		size_t len;
-		uint32_t uc;
-		int n;
-		int cnt = 0;
-
-		p = q;
-		len = strlen(p);
-		logprintf(" [");
-		while ((n = _utf8_to_unicode(&uc, p, len)) > 0) {
-			if (p != q)
-				logprintf(" ");
-			logprintf("%04X", uc);
-			p += n;
-			len -= n;
-			cnt++;
-		}
-		logprintf("]");
-		logprintf(" (count %d", cnt);
-		if (n < 0) {
-			logprintf(",unknown %d bytes", len);
-		}
-		logprintf(")");
-
-	}
-	logprintf("\n");
-}
-
-/* Verify two strings are equal, dump them if not. */
-int
-assertion_equal_string(const char *file, int line,
-    const char *v1, const char *e1,
-    const char *v2, const char *e2,
-    void *extra, int utf8)
-{
-	int l1, l2;
-
-	assertion_count(file, line);
-	if (v1 == v2 || (v1 != NULL && v2 != NULL && strcmp(v1, v2) == 0))
-		return (1);
-	failure_start(file, line, "%s != %s", e1, e2);
-	l1 = (int)strlen(e1);
-	l2 = (int)strlen(e2);
-	if (l1 < l2)
-		l1 = l2;
-	strdump(e1, v1, l1, utf8);
-	strdump(e2, v2, l1, utf8);
-	failure_finish(extra);
-	return (0);
-}
-
-static void
-wcsdump(const char *e, const wchar_t *w)
-{
-	logprintf("      %s = ", e);
-	if (w == NULL) {
-		logprintf("(null)");
-		return;
-	}
-	logprintf("\"");
-	while (*w != L'\0') {
-		unsigned int c = *w++;
-		if (c >= 32 && c < 127)
-			logprintf("%c", c);
-		else if (c < 256)
-			logprintf("\\x%02X", c);
-		else if (c < 0x10000)
-			logprintf("\\u%04X", c);
-		else
-			logprintf("\\U%08X", c);
-	}
-	logprintf("\"\n");
-}
-
-#ifndef HAVE_WCSCMP
-static int
-wcscmp(const wchar_t *s1, const wchar_t *s2)
-{
-
-	while (*s1 == *s2++) {
-		if (*s1++ == L'\0')
-			return 0;
-	}
-	if (*s1 > *--s2)
-		return 1;
-	else
-		return -1;
-}
-#endif
-
-/* Verify that two wide strings are equal, dump them if not. */
-int
-assertion_equal_wstring(const char *file, int line,
-    const wchar_t *v1, const char *e1,
-    const wchar_t *v2, const char *e2,
-    void *extra)
-{
-	assertion_count(file, line);
-	if (v1 == v2)
-		return (1);
-	if (v1 != NULL && v2 != NULL && wcscmp(v1, v2) == 0)
-		return (1);
-	failure_start(file, line, "%s != %s", e1, e2);
-	wcsdump(e1, v1);
-	wcsdump(e2, v2);
-	failure_finish(extra);
-	return (0);
-}
-
-/*
- * Pretty standard hexdump routine.  As a bonus, if ref != NULL, then
- * any bytes in p that differ from ref will be highlighted with '_'
- * before and after the hex value.
- */
-static void
-hexdump(const char *p, const char *ref, size_t l, size_t offset)
-{
-	size_t i, j;
-	char sep;
-
-	if (p == NULL) {
-		logprintf("(null)\n");
-		return;
-	}
-	for(i=0; i < l; i+=16) {
-		logprintf("%04x", (unsigned)(i + offset));
-		sep = ' ';
-		for (j = 0; j < 16 && i + j < l; j++) {
-			if (ref != NULL && p[i + j] != ref[i + j])
-				sep = '_';
-			logprintf("%c%02x", sep, 0xff & (int)p[i+j]);
-			if (ref != NULL && p[i + j] == ref[i + j])
-				sep = ' ';
-		}
-		for (; j < 16; j++) {
-			logprintf("%c  ", sep);
-			sep = ' ';
-		}
-		logprintf("%c", sep);
-		for (j=0; j < 16 && i + j < l; j++) {
-			int c = p[i + j];
-			if (c >= ' ' && c <= 126)
-				logprintf("%c", c);
-			else
-				logprintf(".");
-		}
-		logprintf("\n");
-	}
-}
-
-/* Verify that two blocks of memory are the same, display the first
- * block of differences if they're not. */
-int
-assertion_equal_mem(const char *file, int line,
-    const void *_v1, const char *e1,
-    const void *_v2, const char *e2,
-    size_t l, const char *ld, void *extra)
-{
-	const char *v1 = (const char *)_v1;
-	const char *v2 = (const char *)_v2;
-	size_t offset;
-
-	assertion_count(file, line);
-	if (v1 == v2 || (v1 != NULL && v2 != NULL && memcmp(v1, v2, l) == 0))
-		return (1);
-	if (v1 == NULL || v2 == NULL)
-		return (0);
-
-	failure_start(file, line, "%s != %s", e1, e2);
-	logprintf("      size %s = %d\n", ld, (int)l);
-	/* Dump 48 bytes (3 lines) so that the first difference is
-	 * in the second line. */
-	offset = 0;
-	while (l > 64 && memcmp(v1, v2, 32) == 0) {
-		/* Two lines agree, so step forward one line. */
-		v1 += 16;
-		v2 += 16;
-		l -= 16;
-		offset += 16;
-	}
-	logprintf("      Dump of %s\n", e1);
-	hexdump(v1, v2, l < 128 ? l : 128, offset);
-	logprintf("      Dump of %s\n", e2);
-	hexdump(v2, v1, l < 128 ? l : 128, offset);
-	logprintf("\n");
-	failure_finish(extra);
-	return (0);
-}
-
-/* Verify that a block of memory is filled with the specified byte. */
-int
-assertion_memory_filled_with(const char *file, int line,
-    const void *_v1, const char *vd,
-    size_t l, const char *ld,
-    char b, const char *bd, void *extra)
-{
-	const char *v1 = (const char *)_v1;
-	size_t c = 0;
-	size_t i;
-	(void)ld; /* UNUSED */
-
-	assertion_count(file, line);
-
-	for (i = 0; i < l; ++i) {
-		if (v1[i] == b) {
-			++c;
-		}
-	}
-	if (c == l)
-		return (1);
-
-	failure_start(file, line, "%s (size %d) not filled with %s", vd, (int)l, bd);
-	logprintf("   Only %d bytes were correct\n", (int)c);
-	failure_finish(extra);
-	return (0);
-}
-
-/* Verify that the named file exists and is empty. */
-int
-assertion_empty_file(const char *filename, int line, const char *f1)
-{
-	char buff[1024];
-	struct stat st;
-	ssize_t s;
-	FILE *f;
-
-	assertion_count(filename, line);
-
-	if (stat(f1, &st) != 0) {
-		failure_start(filename, line, "Stat failed: %s", f1);
-		failure_finish(NULL);
-		return (0);
-	}
-	if (st.st_size == 0)
-		return (1);
-
-	failure_start(filename, line, "File should be empty: %s", f1);
-	logprintf("    File size: %d\n", (int)st.st_size);
-	logprintf("    Contents:\n");
-	f = fopen(f1, "rb");
-	if (f == NULL) {
-		logprintf("    Unable to open %s\n", f1);
-	} else {
-		s = ((off_t)sizeof(buff) < st.st_size) ?
-		    (ssize_t)sizeof(buff) : (ssize_t)st.st_size;
-		s = fread(buff, 1, s, f);
-		hexdump(buff, NULL, s, 0);
-		fclose(f);
-	}
-	failure_finish(NULL);
-	return (0);
-}
-
-/* Verify that the named file exists and is not empty. */
-int
-assertion_non_empty_file(const char *filename, int line, const char *f1)
-{
-	struct stat st;
-
-	assertion_count(filename, line);
-
-	if (stat(f1, &st) != 0) {
-		failure_start(filename, line, "Stat failed: %s", f1);
-		failure_finish(NULL);
-		return (0);
-	}
-	if (st.st_size == 0) {
-		failure_start(filename, line, "File empty: %s", f1);
-		failure_finish(NULL);
-		return (0);
-	}
-	return (1);
-}
-
-/* Verify that two files have the same contents. */
-/* TODO: hexdump the first bytes that actually differ. */
-int
-assertion_equal_file(const char *filename, int line, const char *fn1, const char *fn2)
-{
-	char buff1[1024];
-	char buff2[1024];
-	FILE *f1, *f2;
-	int n1, n2;
-
-	assertion_count(filename, line);
-
-	f1 = fopen(fn1, "rb");
-	f2 = fopen(fn2, "rb");
-	if (f1 == NULL || f2 == NULL) {
-		if (f1) fclose(f1);
-		if (f2) fclose(f2);
-		return (0);
-	}
-	for (;;) {
-		n1 = (int)fread(buff1, 1, sizeof(buff1), f1);
-		n2 = (int)fread(buff2, 1, sizeof(buff2), f2);
-		if (n1 != n2)
-			break;
-		if (n1 == 0 && n2 == 0) {
-			fclose(f1);
-			fclose(f2);
-			return (1);
-		}
-		if (memcmp(buff1, buff2, n1) != 0)
-			break;
-	}
-	fclose(f1);
-	fclose(f2);
-	failure_start(filename, line, "Files not identical");
-	logprintf("  file1=\"%s\"\n", fn1);
-	logprintf("  file2=\"%s\"\n", fn2);
-	failure_finish(NULL);
-	return (0);
-}
-
-/* Verify that the named file does exist. */
-int
-assertion_file_exists(const char *filename, int line, const char *f)
-{
-	assertion_count(filename, line);
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	if (!_access(f, 0))
-		return (1);
-#else
-	if (!access(f, F_OK))
-		return (1);
-#endif
-	failure_start(filename, line, "File should exist: %s", f);
-	failure_finish(NULL);
-	return (0);
-}
-
-/* Verify that the named file doesn't exist. */
-int
-assertion_file_not_exists(const char *filename, int line, const char *f)
-{
-	assertion_count(filename, line);
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	if (_access(f, 0))
-		return (1);
-#else
-	if (access(f, F_OK))
-		return (1);
-#endif
-	failure_start(filename, line, "File should not exist: %s", f);
-	failure_finish(NULL);
-	return (0);
-}
-
-/* Compare the contents of a file to a block of memory. */
-int
-assertion_file_contents(const char *filename, int line, const void *buff, int s, const char *fn)
-{
-	char *contents;
-	FILE *f;
-	int n;
-
-	assertion_count(filename, line);
-
-	f = fopen(fn, "rb");
-	if (f == NULL) {
-		failure_start(filename, line,
-		    "File should exist: %s", fn);
-		failure_finish(NULL);
-		return (0);
-	}
-	contents = malloc(s * 2);
-	n = (int)fread(contents, 1, s * 2, f);
-	fclose(f);
-	if (n == s && memcmp(buff, contents, s) == 0) {
-		free(contents);
-		return (1);
-	}
-	failure_start(filename, line, "File contents don't match");
-	logprintf("  file=\"%s\"\n", fn);
-	if (n > 0)
-		hexdump(contents, buff, n > 512 ? 512 : n, 0);
-	else {
-		logprintf("  File empty, contents should be:\n");
-		hexdump(buff, NULL, s > 512 ? 512 : s, 0);
-	}
-	failure_finish(NULL);
-	free(contents);
-	return (0);
-}
-
-/* Check the contents of a text file, being tolerant of line endings. */
-int
-assertion_text_file_contents(const char *filename, int line, const char *buff, const char *fn)
-{
-	char *contents;
-	const char *btxt, *ftxt;
-	FILE *f;
-	int n, s;
-
-	assertion_count(filename, line);
-	f = fopen(fn, "r");
-	if (f == NULL) {
-		failure_start(filename, line,
-		    "File doesn't exist: %s", fn);
-		failure_finish(NULL);
-		return (0);
-	}
-	s = (int)strlen(buff);
-	contents = malloc(s * 2 + 128);
-	n = (int)fread(contents, 1, s * 2 + 128 - 1, f);
-	if (n >= 0)
-		contents[n] = '\0';
-	fclose(f);
-	/* Compare texts. */
-	btxt = buff;
-	ftxt = (const char *)contents;
-	while (*btxt != '\0' && *ftxt != '\0') {
-		if (*btxt == *ftxt) {
-			++btxt;
-			++ftxt;
-			continue;
-		}
-		if (btxt[0] == '\n' && ftxt[0] == '\r' && ftxt[1] == '\n') {
-			/* Pass over different new line characters. */
-			++btxt;
-			ftxt += 2;
-			continue;
-		}
-		break;
-	}
-	if (*btxt == '\0' && *ftxt == '\0') {
-		free(contents);
-		return (1);
-	}
-	failure_start(filename, line, "Contents don't match");
-	logprintf("  file=\"%s\"\n", fn);
-	if (n > 0) {
-		hexdump(contents, buff, n, 0);
-		logprintf("  expected\n", fn);
-		hexdump(buff, contents, s, 0);
-	} else {
-		logprintf("  File empty, contents should be:\n");
-		hexdump(buff, NULL, s, 0);
-	}
-	failure_finish(NULL);
-	free(contents);
-	return (0);
-}
-
-/* Verify that a text file contains the specified lines, regardless of order */
-/* This could be more efficient if we sorted both sets of lines, etc, but
- * since this is used only for testing and only ever deals with a dozen or so
- * lines at a time, this relatively crude approach is just fine. */
-int
-assertion_file_contains_lines_any_order(const char *file, int line,
-    const char *pathname, const char *lines[])
-{
-	char *buff;
-	size_t buff_size;
-	size_t expected_count, actual_count, i, j;
-	char **expected = NULL;
-	char *p, **actual = NULL;
-	char c;
-	int expected_failure = 0, actual_failure = 0;
-
-	assertion_count(file, line);
-
-	buff = slurpfile(&buff_size, "%s", pathname);
-	if (buff == NULL) {
-		failure_start(pathname, line, "Can't read file: %s", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-
-	/* Make a copy of the provided lines and count up the expected
-	 * file size. */
-	for (i = 0; lines[i] != NULL; ++i) {
-	}
-	expected_count = i;
-	if (expected_count) {
-		expected = malloc(sizeof(char *) * expected_count);
-		if (expected == NULL) {
-			failure_start(pathname, line, "Can't allocate memory");
-			failure_finish(NULL);
-			free(expected);
-			return (0);
-		}
-		for (i = 0; lines[i] != NULL; ++i) {
-			expected[i] = strdup(lines[i]);
-		}
-	}
-
-	/* Break the file into lines */
-	actual_count = 0;
-	for (c = '\0', p = buff; p < buff + buff_size; ++p) {
-		if (*p == '\x0d' || *p == '\x0a')
-			*p = '\0';
-		if (c == '\0' && *p != '\0')
-			++actual_count;
-		c = *p;
-	}
-	if (actual_count) {
-		actual = calloc(sizeof(char *), actual_count);
-		if (actual == NULL) {
-			failure_start(pathname, line, "Can't allocate memory");
-			failure_finish(NULL);
-			free(expected);
-			return (0);
-		}
-		for (j = 0, p = buff; p < buff + buff_size;
-		    p += 1 + strlen(p)) {
-			if (*p != '\0') {
-				actual[j] = p;
-				++j;
-			}
-		}
-	}
-
-	/* Erase matching lines from both lists */
-	for (i = 0; i < expected_count; ++i) {
-		if (expected[i] == NULL)
-			continue;
-		for (j = 0; j < actual_count; ++j) {
-			if (actual[j] == NULL)
-				continue;
-			if (strcmp(expected[i], actual[j]) == 0) {
-				free(expected[i]);
-				expected[i] = NULL;
-				actual[j] = NULL;
-				break;
-			}
-		}
-	}
-
-	/* If there's anything left, it's a failure */
-	for (i = 0; i < expected_count; ++i) {
-		if (expected[i] != NULL)
-			++expected_failure;
-	}
-	for (j = 0; j < actual_count; ++j) {
-		if (actual[j] != NULL)
-			++actual_failure;
-	}
-	if (expected_failure == 0 && actual_failure == 0) {
-		free(buff);
-		free(expected);
-		free(actual);
-		return (1);
-	}
-	failure_start(file, line, "File doesn't match: %s", pathname);
-	for (i = 0; i < expected_count; ++i) {
-		if (expected[i] != NULL) {
-			logprintf("  Expected but not present: %s\n", expected[i]);
-			free(expected[i]);
-		}
-	}
-	for (j = 0; j < actual_count; ++j) {
-		if (actual[j] != NULL)
-			logprintf("  Present but not expected: %s\n", actual[j]);
-	}
-	failure_finish(NULL);
-	free(buff);
-	free(expected);
-	free(actual);
-	return (0);
-}
-
-/* Verify that a text file does not contains the specified strings */
-int
-assertion_file_contains_no_invalid_strings(const char *file, int line,
-    const char *pathname, const char *strings[])
-{
-	char *buff;
-	int i;
-
-	buff = slurpfile(NULL, "%s", pathname);
-	if (buff == NULL) {
-		failure_start(file, line, "Can't read file: %s", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-
-	for (i = 0; strings[i] != NULL; ++i) {
-		if (strstr(buff, strings[i]) != NULL) {
-			failure_start(file, line, "Invalid string in %s: %s", pathname,
-			    strings[i]);
-			failure_finish(NULL);
-			free(buff);
-			return(0);
-		}
-	}
-
-	free(buff);
-	return (0);
-}
-
-/* Test that two paths point to the same file. */
-/* As a side-effect, asserts that both files exist. */
-static int
-is_hardlink(const char *file, int line,
-    const char *path1, const char *path2)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	BY_HANDLE_FILE_INFORMATION bhfi1, bhfi2;
-	int r;
-
-	assertion_count(file, line);
-	r = my_GetFileInformationByName(path1, &bhfi1);
-	if (r == 0) {
-		failure_start(file, line, "File %s can't be inspected?", path1);
-		failure_finish(NULL);
-		return (0);
-	}
-	r = my_GetFileInformationByName(path2, &bhfi2);
-	if (r == 0) {
-		failure_start(file, line, "File %s can't be inspected?", path2);
-		failure_finish(NULL);
-		return (0);
-	}
-	return (bhfi1.dwVolumeSerialNumber == bhfi2.dwVolumeSerialNumber
-		&& bhfi1.nFileIndexHigh == bhfi2.nFileIndexHigh
-		&& bhfi1.nFileIndexLow == bhfi2.nFileIndexLow);
-#else
-	struct stat st1, st2;
-	int r;
-
-	assertion_count(file, line);
-	r = lstat(path1, &st1);
-	if (r != 0) {
-		failure_start(file, line, "File should exist: %s", path1);
-		failure_finish(NULL);
-		return (0);
-	}
-	r = lstat(path2, &st2);
-	if (r != 0) {
-		failure_start(file, line, "File should exist: %s", path2);
-		failure_finish(NULL);
-		return (0);
-	}
-	return (st1.st_ino == st2.st_ino && st1.st_dev == st2.st_dev);
-#endif
-}
-
-int
-assertion_is_hardlink(const char *file, int line,
-    const char *path1, const char *path2)
-{
-	if (is_hardlink(file, line, path1, path2))
-		return (1);
-	failure_start(file, line,
-	    "Files %s and %s are not hardlinked", path1, path2);
-	failure_finish(NULL);
-	return (0);
-}
-
-int
-assertion_is_not_hardlink(const char *file, int line,
-    const char *path1, const char *path2)
-{
-	if (!is_hardlink(file, line, path1, path2))
-		return (1);
-	failure_start(file, line,
-	    "Files %s and %s should not be hardlinked", path1, path2);
-	failure_finish(NULL);
-	return (0);
-}
-
-/* Verify a/b/mtime of 'pathname'. */
-/* If 'recent', verify that it's within last 10 seconds. */
-static int
-assertion_file_time(const char *file, int line,
-    const char *pathname, long t, long nsec, char type, int recent)
-{
-	long long filet, filet_nsec;
-	int r;
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-#define EPOC_TIME	(116444736000000000ULL)
-	FILETIME fxtime, fbirthtime, fatime, fmtime;
-	ULARGE_INTEGER wintm;
-	HANDLE h;
-	fxtime.dwLowDateTime = 0;
-	fxtime.dwHighDateTime = 0;
-
-	assertion_count(file, line);
-	/* Note: FILE_FLAG_BACKUP_SEMANTICS applies to open
-	 * a directory file. If not, CreateFile() will fail when
-	 * the pathname is a directory. */
-	h = CreateFile(pathname, FILE_READ_ATTRIBUTES, 0, NULL,
-	    OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
-	if (h == INVALID_HANDLE_VALUE) {
-		failure_start(file, line, "Can't access %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	r = GetFileTime(h, &fbirthtime, &fatime, &fmtime);
-	switch (type) {
-	case 'a': fxtime = fatime; break;
-	case 'b': fxtime = fbirthtime; break;
-	case 'm': fxtime = fmtime; break;
-	}
-	CloseHandle(h);
-	if (r == 0) {
-		failure_start(file, line, "Can't GetFileTime %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	wintm.LowPart = fxtime.dwLowDateTime;
-	wintm.HighPart = fxtime.dwHighDateTime;
-	filet = (wintm.QuadPart - EPOC_TIME) / 10000000;
-	filet_nsec = ((wintm.QuadPart - EPOC_TIME) % 10000000) * 100;
-	nsec = (nsec / 100) * 100; /* Round the request */
-#else
-	struct stat st;
-
-	assertion_count(file, line);
-	r = lstat(pathname, &st);
-	if (r != 0) {
-		failure_start(file, line, "Can't stat %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	switch (type) {
-	case 'a': filet = st.st_atime; break;
-	case 'm': filet = st.st_mtime; break;
-	case 'b': filet = 0; break;
-	default: fprintf(stderr, "INTERNAL: Bad type %c for file time", type);
-		exit(1);
-	}
-#if defined(__FreeBSD__)
-	switch (type) {
-	case 'a': filet_nsec = st.st_atimespec.tv_nsec; break;
-	case 'b': filet = st.st_birthtime;
-		/* FreeBSD filesystems that don't support birthtime
-		 * (e.g., UFS1) always return -1 here. */
-		if (filet == -1) {
-			return (1);
-		}
-		filet_nsec = st.st_birthtimespec.tv_nsec; break;
-	case 'm': filet_nsec = st.st_mtimespec.tv_nsec; break;
-	default: fprintf(stderr, "INTERNAL: Bad type %c for file time", type);
-		exit(1);
-	}
-	/* FreeBSD generally only stores to microsecond res, so round. */
-	filet_nsec = (filet_nsec / 1000) * 1000;
-	nsec = (nsec / 1000) * 1000;
-#else
-	filet_nsec = nsec = 0;	/* Generic POSIX only has whole seconds. */
-	if (type == 'b') return (1); /* Generic POSIX doesn't have birthtime */
-#if defined(__HAIKU__)
-	if (type == 'a') return (1); /* Haiku doesn't have atime. */
-#endif
-#endif
-#endif
-	if (recent) {
-		/* Check that requested time is up-to-date. */
-		time_t now = time(NULL);
-		if (filet < now - 10 || filet > now + 1) {
-			failure_start(file, line,
-			    "File %s has %ctime %lld, %lld seconds ago\n",
-			    pathname, type, filet, now - filet);
-			failure_finish(NULL);
-			return (0);
-		}
-	} else if (filet != t || filet_nsec != nsec) {
-		failure_start(file, line,
-		    "File %s has %ctime %lld.%09lld, expected %lld.%09lld",
-		    pathname, type, filet, filet_nsec, t, nsec);
-		failure_finish(NULL);
-		return (0);
-	}
-	return (1);
-}
-
-/* Verify atime of 'pathname'. */
-int
-assertion_file_atime(const char *file, int line,
-    const char *pathname, long t, long nsec)
-{
-	return assertion_file_time(file, line, pathname, t, nsec, 'a', 0);
-}
-
-/* Verify atime of 'pathname' is up-to-date. */
-int
-assertion_file_atime_recent(const char *file, int line, const char *pathname)
-{
-	return assertion_file_time(file, line, pathname, 0, 0, 'a', 1);
-}
-
-/* Verify birthtime of 'pathname'. */
-int
-assertion_file_birthtime(const char *file, int line,
-    const char *pathname, long t, long nsec)
-{
-	return assertion_file_time(file, line, pathname, t, nsec, 'b', 0);
-}
-
-/* Verify birthtime of 'pathname' is up-to-date. */
-int
-assertion_file_birthtime_recent(const char *file, int line,
-    const char *pathname)
-{
-	return assertion_file_time(file, line, pathname, 0, 0, 'b', 1);
-}
-
-/* Verify mode of 'pathname'. */
-int
-assertion_file_mode(const char *file, int line, const char *pathname, int expected_mode)
-{
-	int mode;
-	int r;
-
-	assertion_count(file, line);
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	failure_start(file, line, "assertFileMode not yet implemented for Windows");
-	(void)mode; /* UNUSED */
-	(void)r; /* UNUSED */
-#else
-	{
-		struct stat st;
-		r = lstat(pathname, &st);
-		mode = (int)(st.st_mode & 0777);
-	}
-	if (r == 0 && mode == expected_mode)
-			return (1);
-	failure_start(file, line, "File %s has mode %o, expected %o",
-	    pathname, mode, expected_mode);
-#endif
-	failure_finish(NULL);
-	return (0);
-}
-
-/* Verify mtime of 'pathname'. */
-int
-assertion_file_mtime(const char *file, int line,
-    const char *pathname, long t, long nsec)
-{
-	return assertion_file_time(file, line, pathname, t, nsec, 'm', 0);
-}
-
-/* Verify mtime of 'pathname' is up-to-date. */
-int
-assertion_file_mtime_recent(const char *file, int line, const char *pathname)
-{
-	return assertion_file_time(file, line, pathname, 0, 0, 'm', 1);
-}
-
-/* Verify number of links to 'pathname'. */
-int
-assertion_file_nlinks(const char *file, int line,
-    const char *pathname, int nlinks)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	BY_HANDLE_FILE_INFORMATION bhfi;
-	int r;
-
-	assertion_count(file, line);
-	r = my_GetFileInformationByName(pathname, &bhfi);
-	if (r != 0 && bhfi.nNumberOfLinks == (DWORD)nlinks)
-		return (1);
-	failure_start(file, line, "File %s has %d links, expected %d",
-	    pathname, bhfi.nNumberOfLinks, nlinks);
-	failure_finish(NULL);
-	return (0);
-#else
-	struct stat st;
-	int r;
-
-	assertion_count(file, line);
-	r = lstat(pathname, &st);
-	if (r == 0 && (int)st.st_nlink == nlinks)
-		return (1);
-	failure_start(file, line, "File %s has %d links, expected %d",
-	    pathname, st.st_nlink, nlinks);
-	failure_finish(NULL);
-	return (0);
-#endif
-}
-
-/* Verify size of 'pathname'. */
-int
-assertion_file_size(const char *file, int line, const char *pathname, long size)
-{
-	int64_t filesize;
-	int r;
-
-	assertion_count(file, line);
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	{
-		BY_HANDLE_FILE_INFORMATION bhfi;
-		r = !my_GetFileInformationByName(pathname, &bhfi);
-		filesize = ((int64_t)bhfi.nFileSizeHigh << 32) + bhfi.nFileSizeLow;
-	}
-#else
-	{
-		struct stat st;
-		r = lstat(pathname, &st);
-		filesize = st.st_size;
-	}
-#endif
-	if (r == 0 && filesize == size)
-			return (1);
-	failure_start(file, line, "File %s has size %ld, expected %ld",
-	    pathname, (long)filesize, (long)size);
-	failure_finish(NULL);
-	return (0);
-}
-
-/* Assert that 'pathname' is a dir.  If mode >= 0, verify that too. */
-int
-assertion_is_dir(const char *file, int line, const char *pathname, int mode)
-{
-	struct stat st;
-	int r;
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	(void)mode; /* UNUSED */
-#endif
-	assertion_count(file, line);
-	r = lstat(pathname, &st);
-	if (r != 0) {
-		failure_start(file, line, "Dir should exist: %s", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	if (!S_ISDIR(st.st_mode)) {
-		failure_start(file, line, "%s is not a dir", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-#if !defined(_WIN32) || defined(__CYGWIN__)
-	/* Windows doesn't handle permissions the same way as POSIX,
-	 * so just ignore the mode tests. */
-	/* TODO: Can we do better here? */
-	if (mode >= 0 && (mode_t)mode != (st.st_mode & 07777)) {
-		failure_start(file, line, "Dir %s has wrong mode", pathname);
-		logprintf("  Expected: 0%3o\n", mode);
-		logprintf("  Found: 0%3o\n", st.st_mode & 07777);
-		failure_finish(NULL);
-		return (0);
-	}
-#endif
-	return (1);
-}
-
-/* Verify that 'pathname' is a regular file.  If 'mode' is >= 0,
- * verify that too. */
-int
-assertion_is_reg(const char *file, int line, const char *pathname, int mode)
-{
-	struct stat st;
-	int r;
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	(void)mode; /* UNUSED */
-#endif
-	assertion_count(file, line);
-	r = lstat(pathname, &st);
-	if (r != 0 || !S_ISREG(st.st_mode)) {
-		failure_start(file, line, "File should exist: %s", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-#if !defined(_WIN32) || defined(__CYGWIN__)
-	/* Windows doesn't handle permissions the same way as POSIX,
-	 * so just ignore the mode tests. */
-	/* TODO: Can we do better here? */
-	if (mode >= 0 && (mode_t)mode != (st.st_mode & 07777)) {
-		failure_start(file, line, "File %s has wrong mode", pathname);
-		logprintf("  Expected: 0%3o\n", mode);
-		logprintf("  Found: 0%3o\n", st.st_mode & 07777);
-		failure_finish(NULL);
-		return (0);
-	}
-#endif
-	return (1);
-}
-
-/* Check whether 'pathname' is a symbolic link.  If 'contents' is
- * non-NULL, verify that the symlink has those contents. */
-static int
-is_symlink(const char *file, int line,
-    const char *pathname, const char *contents)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	(void)pathname; /* UNUSED */
-	(void)contents; /* UNUSED */
-	assertion_count(file, line);
-	/* Windows sort-of has real symlinks, but they're only usable
-	 * by privileged users and are crippled even then, so there's
-	 * really not much point in bothering with this. */
-	return (0);
-#else
-	char buff[300];
-	struct stat st;
-	ssize_t linklen;
-	int r;
-
-	assertion_count(file, line);
-	r = lstat(pathname, &st);
-	if (r != 0) {
-		failure_start(file, line,
-		    "Symlink should exist: %s", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	if (!S_ISLNK(st.st_mode))
-		return (0);
-	if (contents == NULL)
-		return (1);
-	linklen = readlink(pathname, buff, sizeof(buff));
-	if (linklen < 0) {
-		failure_start(file, line, "Can't read symlink %s", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	buff[linklen] = '\0';
-	if (strcmp(buff, contents) != 0)
-		return (0);
-	return (1);
-#endif
-}
-
-/* Assert that path is a symlink that (optionally) contains contents. */
-int
-assertion_is_symlink(const char *file, int line,
-    const char *path, const char *contents)
-{
-	if (is_symlink(file, line, path, contents))
-		return (1);
-	if (contents)
-		failure_start(file, line, "File %s is not a symlink to %s",
-		    path, contents);
-	else
-		failure_start(file, line, "File %s is not a symlink", path);
-	failure_finish(NULL);
-	return (0);
-}
-
-
-/* Create a directory and report any errors. */
-int
-assertion_make_dir(const char *file, int line, const char *dirname, int mode)
-{
-	assertion_count(file, line);
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	(void)mode; /* UNUSED */
-	if (0 == _mkdir(dirname))
-		return (1);
-#else
-	if (0 == mkdir(dirname, mode)) {
-		if (0 == chmod(dirname, mode)) {
-			assertion_file_mode(file, line, dirname, mode);
-			return (1);
-		}
-	}
-#endif
-	failure_start(file, line, "Could not create directory %s", dirname);
-	failure_finish(NULL);
-	return(0);
-}
-
-/* Create a file with the specified contents and report any failures. */
-int
-assertion_make_file(const char *file, int line,
-    const char *path, int mode, int csize, const void *contents)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	/* TODO: Rework this to set file mode as well. */
-	FILE *f;
-	(void)mode; /* UNUSED */
-	assertion_count(file, line);
-	f = fopen(path, "wb");
-	if (f == NULL) {
-		failure_start(file, line, "Could not create file %s", path);
-		failure_finish(NULL);
-		return (0);
-	}
-	if (contents != NULL) {
-		size_t wsize;
-
-		if (csize < 0)
-			wsize = strlen(contents);
-		else
-			wsize = (size_t)csize;
-		if (wsize != fwrite(contents, 1, wsize, f)) {
-			fclose(f);
-			failure_start(file, line,
-			    "Could not write file %s", path);
-			failure_finish(NULL);
-			return (0);
-		}
-	}
-	fclose(f);
-	return (1);
-#else
-	int fd;
-	assertion_count(file, line);
-	fd = open(path, O_CREAT | O_WRONLY, mode >= 0 ? mode : 0644);
-	if (fd < 0) {
-		failure_start(file, line, "Could not create %s", path);
-		failure_finish(NULL);
-		return (0);
-	}
-	if (0 != chmod(path, mode)) {
-		failure_start(file, line, "Could not chmod %s", path);
-		failure_finish(NULL);
-		close(fd);
-		return (0);
-	}
-	if (contents != NULL) {
-		ssize_t wsize;
-
-		if (csize < 0)
-			wsize = (ssize_t)strlen(contents);
-		else
-			wsize = (ssize_t)csize;
-		if (wsize != write(fd, contents, wsize)) {
-			close(fd);
-			failure_start(file, line,
-			    "Could not write to %s", path);
-			failure_finish(NULL);
-			close(fd);
-			return (0);
-		}
-	}
-	close(fd);
-	assertion_file_mode(file, line, path, mode);
-	return (1);
-#endif
-}
-
-/* Create a hardlink and report any failures. */
-int
-assertion_make_hardlink(const char *file, int line,
-    const char *newpath, const char *linkto)
-{
-	int succeeded;
-
-	assertion_count(file, line);
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	succeeded = my_CreateHardLinkA(newpath, linkto);
-#elif HAVE_LINK
-	succeeded = !link(linkto, newpath);
-#else
-	succeeded = 0;
-#endif
-	if (succeeded)
-		return (1);
-	failure_start(file, line, "Could not create hardlink");
-	logprintf("   New link: %s\n", newpath);
-	logprintf("   Old name: %s\n", linkto);
-	failure_finish(NULL);
-	return(0);
-}
-
-/* Create a symlink and report any failures. */
-int
-assertion_make_symlink(const char *file, int line,
-    const char *newpath, const char *linkto)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	int targetIsDir = 0;  /* TODO: Fix this */
-	assertion_count(file, line);
-	if (my_CreateSymbolicLinkA(newpath, linkto, targetIsDir))
-		return (1);
-#elif HAVE_SYMLINK
-	assertion_count(file, line);
-	if (0 == symlink(linkto, newpath))
-		return (1);
-#endif
-	failure_start(file, line, "Could not create symlink");
-	logprintf("   New link: %s\n", newpath);
-	logprintf("   Old name: %s\n", linkto);
-	failure_finish(NULL);
-	return(0);
-}
-
-/* Set umask, report failures. */
-int
-assertion_umask(const char *file, int line, int mask)
-{
-	assertion_count(file, line);
-	(void)file; /* UNUSED */
-	(void)line; /* UNUSED */
-	umask(mask);
-	return (1);
-}
-
-/* Set times, report failures. */
-int
-assertion_utimes(const char *file, int line,
-    const char *pathname, long at, long at_nsec, long mt, long mt_nsec)
-{
-	int r;
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-#define WINTIME(sec, nsec) ((Int32x32To64(sec, 10000000) + EPOC_TIME)\
-	 + (((nsec)/1000)*10))
-	HANDLE h;
-	ULARGE_INTEGER wintm;
-	FILETIME fatime, fmtime;
-	FILETIME *pat, *pmt;
-
-	assertion_count(file, line);
-	h = CreateFileA(pathname,GENERIC_READ | GENERIC_WRITE,
-		    FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
-		    FILE_FLAG_BACKUP_SEMANTICS, NULL);
-	if (h == INVALID_HANDLE_VALUE) {
-		failure_start(file, line, "Can't access %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-
-	if (at > 0 || at_nsec > 0) {
-		wintm.QuadPart = WINTIME(at, at_nsec);
-		fatime.dwLowDateTime = wintm.LowPart;
-		fatime.dwHighDateTime = wintm.HighPart;
-		pat = &fatime;
-	} else
-		pat = NULL;
-	if (mt > 0 || mt_nsec > 0) {
-		wintm.QuadPart = WINTIME(mt, mt_nsec);
-		fmtime.dwLowDateTime = wintm.LowPart;
-		fmtime.dwHighDateTime = wintm.HighPart;
-		pmt = &fmtime;
-	} else
-		pmt = NULL;
-	if (pat != NULL || pmt != NULL)
-		r = SetFileTime(h, NULL, pat, pmt);
-	else
-		r = 1;
-	CloseHandle(h);
-	if (r == 0) {
-		failure_start(file, line, "Can't SetFileTime %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	return (1);
-#else /* defined(_WIN32) && !defined(__CYGWIN__) */
-	struct stat st;
-	struct timeval times[2];
-
-#if !defined(__FreeBSD__)
-	mt_nsec = at_nsec = 0;	/* Generic POSIX only has whole seconds. */
-#endif
-	if (mt == 0 && mt_nsec == 0 && at == 0 && at_nsec == 0)
-		return (1);
-
-	r = lstat(pathname, &st);
-	if (r < 0) {
-		failure_start(file, line, "Can't stat %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-
-	if (mt == 0 && mt_nsec == 0) {
-		mt = st.st_mtime;
-#if defined(__FreeBSD__)
-		mt_nsec = st.st_mtimespec.tv_nsec;
-		/* FreeBSD generally only stores to microsecond res, so round. */
-		mt_nsec = (mt_nsec / 1000) * 1000;
-#endif
-	}
-	if (at == 0 && at_nsec == 0) {
-		at = st.st_atime;
-#if defined(__FreeBSD__)
-		at_nsec = st.st_atimespec.tv_nsec;
-		/* FreeBSD generally only stores to microsecond res, so round. */
-		at_nsec = (at_nsec / 1000) * 1000;
-#endif
-	}
-
-	times[1].tv_sec = mt;
-	times[1].tv_usec = mt_nsec / 1000;
-
-	times[0].tv_sec = at;
-	times[0].tv_usec = at_nsec / 1000;
-
-#ifdef HAVE_LUTIMES
-	r = lutimes(pathname, times);
-#else
-	r = utimes(pathname, times);
-#endif
-	if (r < 0) {
-		failure_start(file, line, "Can't utimes %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	return (1);
-#endif /* defined(_WIN32) && !defined(__CYGWIN__) */
-}
-
-/* Set nodump, report failures. */
-int
-assertion_nodump(const char *file, int line, const char *pathname)
-{
-#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP)
-	int r;
-
-	assertion_count(file, line);
-	r = chflags(pathname, UF_NODUMP);
-	if (r < 0) {
-		failure_start(file, line, "Can't set nodump %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-#elif defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)\
-	 && defined(EXT2_NODUMP_FL)
-	int fd, r, flags;
-
-	assertion_count(file, line);
-	fd = open(pathname, O_RDONLY | O_NONBLOCK);
-	if (fd < 0) {
-		failure_start(file, line, "Can't open %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags);
-	if (r < 0) {
-		failure_start(file, line, "Can't get flags %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	flags |= EXT2_NODUMP_FL;
-	r = ioctl(fd, EXT2_IOC_SETFLAGS, &flags);
-	if (r < 0) {
-		failure_start(file, line, "Can't set nodump %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	close(fd);
-#else
-	(void)pathname; /* UNUSED */
-	assertion_count(file, line);
-#endif
-	return (1);
-}
-
-/*
- *
- *  UTILITIES for use by tests.
- *
- */
-
-/*
- * Check whether platform supports symlinks.  This is intended
- * for tests to use in deciding whether to bother testing symlink
- * support; if the platform doesn't support symlinks, there's no point
- * in checking whether the program being tested can create them.
- *
- * Note that the first time this test is called, we actually go out to
- * disk to create and verify a symlink.  This is necessary because
- * symlink support is actually a property of a particular filesystem
- * and can thus vary between directories on a single system.  After
- * the first call, this returns the cached result from memory, so it's
- * safe to call it as often as you wish.
- */
-int
-canSymlink(void)
-{
-	/* Remember the test result */
-	static int value = 0, tested = 0;
-	if (tested)
-		return (value);
-
-	++tested;
-	assertion_make_file(__FILE__, __LINE__, "canSymlink.0", 0644, 1, "a");
-	/* Note: Cygwin has its own symlink() emulation that does not
-	 * use the Win32 CreateSymbolicLink() function. */
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	value = my_CreateSymbolicLinkA("canSymlink.1", "canSymlink.0", 0)
-	    && is_symlink(__FILE__, __LINE__, "canSymlink.1", "canSymlink.0");
-#elif HAVE_SYMLINK
-	value = (0 == symlink("canSymlink.0", "canSymlink.1"))
-	    && is_symlink(__FILE__, __LINE__, "canSymlink.1","canSymlink.0");
-#endif
-	return (value);
-}
-
-/* Platform-dependent options for hiding the output of a subcommand. */
-#if defined(_WIN32) && !defined(__CYGWIN__)
-static const char *redirectArgs = ">NUL 2>NUL"; /* Win32 cmd.exe */
-#else
-static const char *redirectArgs = ">/dev/null 2>/dev/null"; /* POSIX 'sh' */
-#endif
-/*
- * Can this platform run the bzip2 program?
- */
-int
-canBzip2(void)
-{
-	static int tested = 0, value = 0;
-	if (!tested) {
-		tested = 1;
-		if (systemf("bzip2 -d -V %s", redirectArgs) == 0)
-			value = 1;
-	}
-	return (value);
-}
-
-/*
- * Can this platform run the grzip program?
- */
-int
-canGrzip(void)
-{
-	static int tested = 0, value = 0;
-	if (!tested) {
-		tested = 1;
-		if (systemf("grzip -V %s", redirectArgs) == 0)
-			value = 1;
-	}
-	return (value);
-}
-
-/*
- * Can this platform run the gzip program?
- */
-int
-canGzip(void)
-{
-	static int tested = 0, value = 0;
-	if (!tested) {
-		tested = 1;
-		if (systemf("gzip -V %s", redirectArgs) == 0)
-			value = 1;
-	}
-	return (value);
-}
-
-/*
- * Can this platform run the lrzip program?
- */
-int
-canRunCommand(const char *cmd)
-{
-  static int tested = 0, value = 0;
-  if (!tested) {
-    tested = 1;
-    if (systemf("%s %s", cmd, redirectArgs) == 0)
-      value = 1;
-  }
-  return (value);
-}
-
-int
-canLrzip(void)
-{
-	static int tested = 0, value = 0;
-	if (!tested) {
-		tested = 1;
-		if (systemf("lrzip -V %s", redirectArgs) == 0)
-			value = 1;
-	}
-	return (value);
-}
-
-/*
- * Can this platform run the lz4 program?
- */
-int
-canLz4(void)
-{
-	static int tested = 0, value = 0;
-	if (!tested) {
-		tested = 1;
-		if (systemf("lz4 -V %s", redirectArgs) == 0)
-			value = 1;
-	}
-	return (value);
-}
-
-/*
- * Can this platform run the lzip program?
- */
-int
-canLzip(void)
-{
-	static int tested = 0, value = 0;
-	if (!tested) {
-		tested = 1;
-		if (systemf("lzip -V %s", redirectArgs) == 0)
-			value = 1;
-	}
-	return (value);
-}
-
-/*
- * Can this platform run the lzma program?
- */
-int
-canLzma(void)
-{
-	static int tested = 0, value = 0;
-	if (!tested) {
-		tested = 1;
-		if (systemf("lzma -V %s", redirectArgs) == 0)
-			value = 1;
-	}
-	return (value);
-}
-
-/*
- * Can this platform run the lzop program?
- */
-int
-canLzop(void)
-{
-	static int tested = 0, value = 0;
-	if (!tested) {
-		tested = 1;
-		if (systemf("lzop -V %s", redirectArgs) == 0)
-			value = 1;
-	}
-	return (value);
-}
-
-/*
- * Can this platform run the xz program?
- */
-int
-canXz(void)
-{
-	static int tested = 0, value = 0;
-	if (!tested) {
-		tested = 1;
-		if (systemf("xz -V %s", redirectArgs) == 0)
-			value = 1;
-	}
-	return (value);
-}
-
-/*
- * Can this filesystem handle nodump flags.
- */
-#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP)
-
-int
-canNodump(void)
-{
-	const char *path = "cannodumptest";
-	struct stat sb;
-
-	assertion_make_file(__FILE__, __LINE__, path, 0644, 0, NULL);
-	if (chflags(path, UF_NODUMP) < 0)
-		return (0);
-	if (stat(path, &sb) < 0)
-		return (0);
-	if (sb.st_flags & UF_NODUMP)
-		return (1);
-	return (0);
-}
-
-#elif defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)\
-	 && defined(EXT2_NODUMP_FL)
-
-int
-canNodump(void)
-{
-	const char *path = "cannodumptest";
-	int fd, r, flags;
-
-	assertion_make_file(__FILE__, __LINE__, path, 0644, 0, NULL);
-	fd = open(path, O_RDONLY | O_NONBLOCK);
-	if (fd < 0)
-		return (0);
-	r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags);
-	if (r < 0)
-		return (0);
-	flags |= EXT2_NODUMP_FL;
-	r = ioctl(fd, EXT2_IOC_SETFLAGS, &flags);
-	if (r < 0)
-		return (0);
-	close(fd);
-	fd = open(path, O_RDONLY | O_NONBLOCK);
-	if (fd < 0)
-		return (0);
-	r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags);
-	if (r < 0)
-		return (0);
-	close(fd);
-	if (flags & EXT2_NODUMP_FL)
-		return (1);
-	return (0);
-}
-
-#else
-
-int
-canNodump()
-{
-	return (0);
-}
-
-#endif
-
-/*
- * Sleep as needed; useful for verifying disk timestamp changes by
- * ensuring that the wall-clock time has actually changed before we
- * go back to re-read something from disk.
- */
-void
-sleepUntilAfter(time_t t)
-{
-	while (t >= time(NULL))
-#if defined(_WIN32) && !defined(__CYGWIN__)
-		Sleep(500);
-#else
-		sleep(1);
-#endif
-}
-
-/*
- * Call standard system() call, but build up the command line using
- * sprintf() conventions.
- */
-int
-systemf(const char *fmt, ...)
-{
-	char buff[8192];
-	va_list ap;
-	int r;
-
-	va_start(ap, fmt);
-	vsprintf(buff, fmt, ap);
-	if (verbosity > VERBOSITY_FULL)
-		logprintf("Cmd: %s\n", buff);
-	r = system(buff);
-	va_end(ap);
-	return (r);
-}
-
-/*
- * Slurp a file into memory for ease of comparison and testing.
- * Returns size of file in 'sizep' if non-NULL, null-terminates
- * data in memory for ease of use.
- */
-char *
-slurpfile(size_t * sizep, const char *fmt, ...)
-{
-	char filename[8192];
-	struct stat st;
-	va_list ap;
-	char *p;
-	ssize_t bytes_read;
-	FILE *f;
-	int r;
-
-	va_start(ap, fmt);
-	vsprintf(filename, fmt, ap);
-	va_end(ap);
-
-	f = fopen(filename, "rb");
-	if (f == NULL) {
-		/* Note: No error; non-existent file is okay here. */
-		return (NULL);
-	}
-	r = fstat(fileno(f), &st);
-	if (r != 0) {
-		logprintf("Can't stat file %s\n", filename);
-		fclose(f);
-		return (NULL);
-	}
-	p = malloc((size_t)st.st_size + 1);
-	if (p == NULL) {
-		logprintf("Can't allocate %ld bytes of memory to read file %s\n",
-		    (long int)st.st_size, filename);
-		fclose(f);
-		return (NULL);
-	}
-	bytes_read = fread(p, 1, (size_t)st.st_size, f);
-	if (bytes_read < st.st_size) {
-		logprintf("Can't read file %s\n", filename);
-		fclose(f);
-		free(p);
-		return (NULL);
-	}
-	p[st.st_size] = '\0';
-	if (sizep != NULL)
-		*sizep = (size_t)st.st_size;
-	fclose(f);
-	return (p);
-}
-
-/*
- * Slurp a file into memory for ease of comparison and testing.
- * Returns size of file in 'sizep' if non-NULL, null-terminates
- * data in memory for ease of use.
- */
-void
-dumpfile(const char *filename, void *data, size_t len)
-{
-	ssize_t bytes_written;
-	FILE *f;
-
-	f = fopen(filename, "wb");
-	if (f == NULL) {
-		logprintf("Can't open file %s for writing\n", filename);
-		return;
-	}
-	bytes_written = fwrite(data, 1, len, f);
-	if (bytes_written < (ssize_t)len)
-		logprintf("Can't write file %s\n", filename);
-	fclose(f);
-}
-
-/* Read a uuencoded file from the reference directory, decode, and
- * write the result into the current directory. */
-#define VALID_UUDECODE(c) (c >= 32 && c <= 96)
-#define	UUDECODE(c) (((c) - 0x20) & 0x3f)
-void
-extract_reference_file(const char *name)
-{
-	char buff[1024];
-	FILE *in, *out;
-
-	sprintf(buff, "%s/%s.uu", refdir, name);
-	in = fopen(buff, "r");
-	failure("Couldn't open reference file %s", buff);
-	assert(in != NULL);
-	if (in == NULL)
-		return;
-	/* Read up to and including the 'begin' line. */
-	for (;;) {
-		if (fgets(buff, sizeof(buff), in) == NULL) {
-			/* TODO: This is a failure. */
-			return;
-		}
-		if (memcmp(buff, "begin ", 6) == 0)
-			break;
-	}
-	/* Now, decode the rest and write it. */
-	out = fopen(name, "wb");
-	while (fgets(buff, sizeof(buff), in) != NULL) {
-		char *p = buff;
-		int bytes;
-
-		if (memcmp(buff, "end", 3) == 0)
-			break;
-
-		bytes = UUDECODE(*p++);
-		while (bytes > 0) {
-			int n = 0;
-			/* Write out 1-3 bytes from that. */
-			if (bytes > 0) {
-				assert(VALID_UUDECODE(p[0]));
-				assert(VALID_UUDECODE(p[1]));
-				n = UUDECODE(*p++) << 18;
-				n |= UUDECODE(*p++) << 12;
-				fputc(n >> 16, out);
-				--bytes;
-			}
-			if (bytes > 0) {
-				assert(VALID_UUDECODE(p[0]));
-				n |= UUDECODE(*p++) << 6;
-				fputc((n >> 8) & 0xFF, out);
-				--bytes;
-			}
-			if (bytes > 0) {
-				assert(VALID_UUDECODE(p[0]));
-				n |= UUDECODE(*p++);
-				fputc(n & 0xFF, out);
-				--bytes;
-			}
-		}
-	}
-	fclose(out);
-	fclose(in);
-}
-
-void
-copy_reference_file(const char *name)
-{
-	char buff[1024];
-	FILE *in, *out;
-	size_t rbytes;
-
-	sprintf(buff, "%s/%s", refdir, name);
-	in = fopen(buff, "rb");
-	failure("Couldn't open reference file %s", buff);
-	assert(in != NULL);
-	if (in == NULL)
-		return;
-	/* Now, decode the rest and write it. */
-	/* Not a lot of error checking here; the input better be right. */
-	out = fopen(name, "wb");
-	while ((rbytes = fread(buff, 1, sizeof(buff), in)) > 0) {
-		if (fwrite(buff, 1, rbytes, out) != rbytes) {
-			logprintf("Error: fwrite\n");
-			break;
-		}
-	}
-	fclose(out);
-	fclose(in);
-}
-
-int
-is_LargeInode(const char *file)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	BY_HANDLE_FILE_INFORMATION bhfi;
-	int r;
-
-	r = my_GetFileInformationByName(file, &bhfi);
-	if (r != 0)
-		return (0);
-	return (bhfi.nFileIndexHigh & 0x0000FFFFUL);
-#else
-	struct stat st;
-	int64_t ino;
-
-	if (stat(file, &st) < 0)
-		return (0);
-	ino = (int64_t)st.st_ino;
-	return (ino > 0xffffffff);
-#endif
-}
-
-void
-extract_reference_files(const char **names)
-{
-	while (names && *names)
-		extract_reference_file(*names++);
-}
-
-/*
- *
- * TEST management
- *
- */
-
-/*
- * "list.h" is simply created by "grep DEFINE_TEST test_*.c"; it has
- * a line like
- *      DEFINE_TEST(test_function)
- * for each test.
- */
-
-/* Use "list.h" to declare all of the test functions. */
-#undef DEFINE_TEST
-#define	DEFINE_TEST(name) void name(void);
-#include "list.h"
-
-/* Use "list.h" to create a list of all tests (functions and names). */
-#undef DEFINE_TEST
-#define	DEFINE_TEST(n) { n, #n, 0 },
-struct test_list_t tests[] = {
-	#include "list.h"
-};
-
-/*
- * Summarize repeated failures in the just-completed test.
- */
-static void
-test_summarize(int failed, int skips_num)
-{
-	unsigned int i;
-
-	switch (verbosity) {
-	case VERBOSITY_SUMMARY_ONLY:
-		printf(failed ? "E" : ".");
-		fflush(stdout);
-		break;
-	case VERBOSITY_PASSFAIL:
-		printf(failed ? "FAIL\n" : skips_num ? "ok (S)\n" : "ok\n");
-		break;
-	}
-
-	log_console = (verbosity == VERBOSITY_LIGHT_REPORT);
-
-	for (i = 0; i < sizeof(failed_lines)/sizeof(failed_lines[0]); i++) {
-		if (failed_lines[i].count > 1 && !failed_lines[i].skip)
-			logprintf("%s:%d: Summary: Failed %d times\n",
-			    failed_filename, i, failed_lines[i].count);
-	}
-	/* Clear the failure history for the next file. */
-	failed_filename = NULL;
-	memset(failed_lines, 0, sizeof(failed_lines));
-}
-
-/*
- * Actually run a single test, with appropriate setup and cleanup.
- */
-static int
-test_run(int i, const char *tmpdir)
-{
-	char workdir[1024];
-	char logfilename[64];
-	int failures_before = failures;
-	int skips_before = skips;
-	int oldumask;
-
-	switch (verbosity) {
-	case VERBOSITY_SUMMARY_ONLY: /* No per-test reports at all */
-		break;
-	case VERBOSITY_PASSFAIL: /* rest of line will include ok/FAIL marker */
-		printf("%3d: %-64s", i, tests[i].name);
-		fflush(stdout);
-		break;
-	default: /* Title of test, details will follow */
-		printf("%3d: %s\n", i, tests[i].name);
-	}
-
-	/* Chdir to the top-level work directory. */
-	if (!assertChdir(tmpdir)) {
-		fprintf(stderr,
-		    "ERROR: Can't chdir to top work dir %s\n", tmpdir);
-		exit(1);
-	}
-	/* Create a log file for this test. */
-	sprintf(logfilename, "%s.log", tests[i].name);
-	logfile = fopen(logfilename, "w");
-	fprintf(logfile, "%s\n\n", tests[i].name);
-	/* Chdir() to a work dir for this specific test. */
-	snprintf(workdir, sizeof(workdir), "%s/%s", tmpdir, tests[i].name);
-	testworkdir = workdir;
-	if (!assertMakeDir(testworkdir, 0755)
-	    || !assertChdir(testworkdir)) {
-		fprintf(stderr,
-		    "ERROR: Can't chdir to work dir %s\n", testworkdir);
-		exit(1);
-	}
-	/* Explicitly reset the locale before each test. */
-	setlocale(LC_ALL, "C");
-	/* Record the umask before we run the test. */
-	umask(oldumask = umask(0));
-	/*
-	 * Run the actual test.
-	 */
-	(*tests[i].func)();
-	/*
-	 * Clean up and report afterwards.
-	 */
-	testworkdir = NULL;
-	/* Restore umask */
-	umask(oldumask);
-	/* Reset locale. */
-	setlocale(LC_ALL, "C");
-	/* Reset directory. */
-	if (!assertChdir(tmpdir)) {
-		fprintf(stderr, "ERROR: Couldn't chdir to temp dir %s\n",
-		    tmpdir);
-		exit(1);
-	}
-	/* Report per-test summaries. */
-	tests[i].failures = failures - failures_before;
-	test_summarize(tests[i].failures, skips - skips_before);
-	/* Close the per-test log file. */
-	fclose(logfile);
-	logfile = NULL;
-	/* If there were no failures, we can remove the work dir and logfile. */
-	if (tests[i].failures == 0) {
-		if (!keep_temp_files && assertChdir(tmpdir)) {
-#if defined(_WIN32) && !defined(__CYGWIN__)
-			/* Make sure not to leave empty directories.
-			 * Sometimes a processing of closing files used by tests
-			 * is not done, then rmdir will be failed and it will
-			 * leave a empty test directory. So we should wait a few
-			 * seconds and retry rmdir. */
-			int r, t;
-			for (t = 0; t < 10; t++) {
-				if (t > 0)
-					Sleep(1000);
-				r = systemf("rmdir /S /Q %s", tests[i].name);
-				if (r == 0)
-					break;
-			}
-			systemf("del %s", logfilename);
-#else
-			systemf("rm -rf %s", tests[i].name);
-			systemf("rm %s", logfilename);
-#endif
-		}
-	}
-	/* Return appropriate status. */
-	return (tests[i].failures);
-}
-
-/*
- *
- *
- * MAIN and support routines.
- *
- *
- */
-
-static void
-usage(const char *program)
-{
-	static const int limit = sizeof(tests) / sizeof(tests[0]);
-	int i;
-
-	printf("Usage: %s [options] <test> <test> ...\n", program);
-	printf("Default is to run all tests.\n");
-	printf("Otherwise, specify the numbers of the tests you wish to run.\n");
-	printf("Options:\n");
-	printf("  -d  Dump core after any failure, for debugging.\n");
-	printf("  -k  Keep all temp files.\n");
-	printf("      Default: temp files for successful tests deleted.\n");
-#ifdef PROGRAM
-	printf("  -p <path>  Path to executable to be tested.\n");
-	printf("      Default: path taken from " ENVBASE " environment variable.\n");
-#endif
-	printf("  -q  Quiet.\n");
-	printf("  -r <dir>   Path to dir containing reference files.\n");
-	printf("      Default: Current directory.\n");
-	printf("  -u  Keep running specifies tests until one fails.\n");
-	printf("  -v  Verbose.\n");
-	printf("Available tests:\n");
-	for (i = 0; i < limit; i++)
-		printf("  %d: %s\n", i, tests[i].name);
-	exit(1);
-}
-
-static char *
-get_refdir(const char *d)
-{
-	size_t tried_size, buff_size;
-	char *buff, *tried, *pwd = NULL, *p = NULL;
-
-#ifdef PATH_MAX
-	buff_size = PATH_MAX;
-#else
-	buff_size = 8192;
-#endif
-	buff = calloc(buff_size, 1);
-	if (buff == NULL) {
-		fprintf(stderr, "Unable to allocate memory\n");
-		exit(1);
-	}
-
-	/* Allocate a buffer to hold the various directories we checked. */
-	tried_size = buff_size * 2;
-	tried = calloc(tried_size, 1);
-	if (tried == NULL) {
-		fprintf(stderr, "Unable to allocate memory\n");
-		exit(1);
-	}
-
-	/* If a dir was specified, try that */
-	if (d != NULL) {
-		pwd = NULL;
-		snprintf(buff, buff_size, "%s", d);
-		p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
-		if (p != NULL) goto success;
-		strncat(tried, buff, tried_size - strlen(tried) - 1);
-		strncat(tried, "\n", tried_size - strlen(tried) - 1);
-		goto failure;
-	}
-
-	/* Get the current dir. */
-#ifdef PATH_MAX
-	pwd = getcwd(NULL, PATH_MAX);/* Solaris getcwd needs the size. */
-#else
-	pwd = getcwd(NULL, 0);
-#endif
-	while (pwd[strlen(pwd) - 1] == '\n')
-		pwd[strlen(pwd) - 1] = '\0';
-
-	/* Look for a known file. */
-	snprintf(buff, buff_size, "%s", pwd);
-	p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
-	if (p != NULL) goto success;
-	strncat(tried, buff, tried_size - strlen(tried) - 1);
-	strncat(tried, "\n", tried_size - strlen(tried) - 1);
-
-	snprintf(buff, buff_size, "%s/test", pwd);
-	p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
-	if (p != NULL) goto success;
-	strncat(tried, buff, tried_size - strlen(tried) - 1);
-	strncat(tried, "\n", tried_size - strlen(tried) - 1);
-
-#if defined(LIBRARY)
-	snprintf(buff, buff_size, "%s/%s/test", pwd, LIBRARY);
-#else
-	snprintf(buff, buff_size, "%s/%s/test", pwd, PROGRAM);
-#endif
-	p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
-	if (p != NULL) goto success;
-	strncat(tried, buff, tried_size - strlen(tried) - 1);
-	strncat(tried, "\n", tried_size - strlen(tried) - 1);
-
-#if defined(PROGRAM_ALIAS)
-	snprintf(buff, buff_size, "%s/%s/test", pwd, PROGRAM_ALIAS);
-	p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
-	if (p != NULL) goto success;
-	strncat(tried, buff, tried_size - strlen(tried) - 1);
-	strncat(tried, "\n", tried_size - strlen(tried) - 1);
-#endif
-
-	if (memcmp(pwd, "/usr/obj", 8) == 0) {
-		snprintf(buff, buff_size, "%s", pwd + 8);
-		p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
-		if (p != NULL) goto success;
-		strncat(tried, buff, tried_size - strlen(tried) - 1);
-		strncat(tried, "\n", tried_size - strlen(tried) - 1);
-
-		snprintf(buff, buff_size, "%s/test", pwd + 8);
-		p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
-		if (p != NULL) goto success;
-		strncat(tried, buff, tried_size - strlen(tried) - 1);
-		strncat(tried, "\n", tried_size - strlen(tried) - 1);
-	}
-
-failure:
-	printf("Unable to locate known reference file %s\n", KNOWNREF);
-	printf("  Checked following directories:\n%s\n", tried);
-	printf("Use -r option to specify full path to reference directory\n");
-#if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG)
-	DebugBreak();
-#endif
-	exit(1);
-
-success:
-	free(p);
-	free(pwd);
-	free(tried);
-
-	/* Copy result into a fresh buffer to reduce memory usage. */
-	p = strdup(buff);
-	free(buff);
-	return p;
-}
-
-int
-main(int argc, char **argv)
-{
-	static const int limit = sizeof(tests) / sizeof(tests[0]);
-	int test_set[sizeof(tests) / sizeof(tests[0])];
-	int i = 0, j = 0, tests_run = 0, tests_failed = 0, option;
-	time_t now;
-	char *refdir_alloc = NULL;
-	const char *progname;
-	char **saved_argv;
-	const char *tmp, *option_arg, *p;
-	char tmpdir[256], *pwd, *testprogdir, *tmp2 = NULL, *vlevel = NULL;
-	char tmpdir_timestamp[256];
-
-	(void)argc; /* UNUSED */
-
-	/* Get the current dir. */
-#ifdef PATH_MAX
-	pwd = getcwd(NULL, PATH_MAX);/* Solaris getcwd needs the size. */
-#else
-	pwd = getcwd(NULL, 0);
-#endif
-	while (pwd[strlen(pwd) - 1] == '\n')
-		pwd[strlen(pwd) - 1] = '\0';
-
-#if defined(HAVE__CrtSetReportMode) && !defined(__WATCOMC__)
-	/* To stop to run the default invalid parameter handler. */
-	_set_invalid_parameter_handler(invalid_parameter_handler);
-	/* Disable annoying assertion message box. */
-	_CrtSetReportMode(_CRT_ASSERT, 0);
-#endif
-
-	/*
-	 * Name of this program, used to build root of our temp directory
-	 * tree.
-	 */
-	progname = p = argv[0];
-	if ((testprogdir = (char *)malloc(strlen(progname) + 1)) == NULL)
-	{
-		fprintf(stderr, "ERROR: Out of memory.");
-		exit(1);
-	}
-	strcpy(testprogdir, progname);
-	while (*p != '\0') {
-		/* Support \ or / dir separators for Windows compat. */
-		if (*p == '/' || *p == '\\')
-		{
-			progname = p + 1;
-			i = j;
-		}
-		++p;
-		j++;
-	}
-	testprogdir[i] = '\0';
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	if (testprogdir[0] != '/' && testprogdir[0] != '\\' &&
-	    !(((testprogdir[0] >= 'a' && testprogdir[0] <= 'z') ||
-	       (testprogdir[0] >= 'A' && testprogdir[0] <= 'Z')) &&
-		testprogdir[1] == ':' &&
-		(testprogdir[2] == '/' || testprogdir[2] == '\\')))
-#else
-	if (testprogdir[0] != '/')
-#endif
-	{
-		/* Fixup path for relative directories. */
-		if ((testprogdir = (char *)realloc(testprogdir,
-			strlen(pwd) + 1 + strlen(testprogdir) + 1)) == NULL)
-		{
-			fprintf(stderr, "ERROR: Out of memory.");
-			exit(1);
-		}
-		memmove(testprogdir + strlen(pwd) + 1, testprogdir,
-		    strlen(testprogdir) + 1);
-		memcpy(testprogdir, pwd, strlen(pwd));
-		testprogdir[strlen(pwd)] = '/';
-	}
-
-#ifdef PROGRAM
-	/* Get the target program from environment, if available. */
-	testprogfile = getenv(ENVBASE);
-#endif
-
-	if (getenv("TMPDIR") != NULL)
-		tmp = getenv("TMPDIR");
-	else if (getenv("TMP") != NULL)
-		tmp = getenv("TMP");
-	else if (getenv("TEMP") != NULL)
-		tmp = getenv("TEMP");
-	else if (getenv("TEMPDIR") != NULL)
-		tmp = getenv("TEMPDIR");
-	else
-		tmp = "/tmp";
-
-	/* Allow -d to be controlled through the environment. */
-	if (getenv(ENVBASE "_DEBUG") != NULL)
-		dump_on_failure = 1;
-
-	/* Allow -v to be controlled through the environment. */
-	if (getenv("_VERBOSITY_LEVEL") != NULL)
-	{
-		vlevel = getenv("_VERBOSITY_LEVEL");
-		verbosity = atoi(vlevel);
-		if (verbosity < VERBOSITY_SUMMARY_ONLY || verbosity > VERBOSITY_FULL)
-		{
-			/* Unsupported verbosity levels are silently ignored */
-			vlevel = NULL;
-			verbosity = VERBOSITY_PASSFAIL;
-		}
-	}
-
-	/* Get the directory holding test files from environment. */
-	refdir = getenv(ENVBASE "_TEST_FILES");
-
-	/*
-	 * Parse options, without using getopt(), which isn't available
-	 * on all platforms.
-	 */
-	++argv; /* Skip program name */
-	while (*argv != NULL) {
-		if (**argv != '-')
-			break;
-		p = *argv++;
-		++p; /* Skip '-' */
-		while (*p != '\0') {
-			option = *p++;
-			option_arg = NULL;
-			/* If 'opt' takes an argument, parse that. */
-			if (option == 'p' || option == 'r') {
-				if (*p != '\0')
-					option_arg = p;
-				else if (*argv == NULL) {
-					fprintf(stderr,
-					    "Option -%c requires argument.\n",
-					    option);
-					usage(progname);
-				} else
-					option_arg = *argv++;
-				p = ""; /* End of this option word. */
-			}
-
-			/* Now, handle the option. */
-			switch (option) {
-			case 'd':
-				dump_on_failure = 1;
-				break;
-			case 'k':
-				keep_temp_files = 1;
-				break;
-			case 'p':
-#ifdef PROGRAM
-				testprogfile = option_arg;
-#else
-				fprintf(stderr, "-p option not permitted\n");
-				usage(progname);
-#endif
-				break;
-			case 'q':
-				if (!vlevel)
-					verbosity--;
-				break;
-			case 'r':
-				refdir = option_arg;
-				break;
-			case 'u':
-				until_failure++;
-				break;
-			case 'v':
-				if (!vlevel)
-					verbosity++;
-				break;
-			default:
-				fprintf(stderr, "Unrecognized option '%c'\n",
-				    option);
-				usage(progname);
-			}
-		}
-	}
-
-	/*
-	 * Sanity-check that our options make sense.
-	 */
-#ifdef PROGRAM
-	if (testprogfile == NULL)
-	{
-		if ((tmp2 = (char *)malloc(strlen(testprogdir) + 1 +
-			strlen(PROGRAM) + 1)) == NULL)
-		{
-			fprintf(stderr, "ERROR: Out of memory.");
-			exit(1);
-		}
-		strcpy(tmp2, testprogdir);
-		strcat(tmp2, "/");
-		strcat(tmp2, PROGRAM);
-		testprogfile = tmp2;
-	}
-
-	{
-		char *testprg;
-#if defined(_WIN32) && !defined(__CYGWIN__)
-		/* Command.com sometimes rejects '/' separators. */
-		testprg = strdup(testprogfile);
-		for (i = 0; testprg[i] != '\0'; i++) {
-			if (testprg[i] == '/')
-				testprg[i] = '\\';
-		}
-		testprogfile = testprg;
-#endif
-		/* Quote the name that gets put into shell command lines. */
-		testprg = malloc(strlen(testprogfile) + 3);
-		strcpy(testprg, "\"");
-		strcat(testprg, testprogfile);
-		strcat(testprg, "\"");
-		testprog = testprg;
-	}
-#endif
-
-#if !defined(_WIN32) && defined(SIGPIPE)
-	{   /* Ignore SIGPIPE signals */
-		struct sigaction sa;
-		sa.sa_handler = SIG_IGN;
-		sigemptyset(&sa.sa_mask);
-		sa.sa_flags = 0;
-		sigaction(SIGPIPE, &sa, NULL);
-	}
-#endif
-
-	/*
-	 * Create a temp directory for the following tests.
-	 * Include the time the tests started as part of the name,
-	 * to make it easier to track the results of multiple tests.
-	 */
-	now = time(NULL);
-	for (i = 0; ; i++) {
-		strftime(tmpdir_timestamp, sizeof(tmpdir_timestamp),
-		    "%Y-%m-%dT%H.%M.%S",
-		    localtime(&now));
-		sprintf(tmpdir, "%s/%s.%s-%03d", tmp, progname,
-		    tmpdir_timestamp, i);
-		if (assertMakeDir(tmpdir,0755))
-			break;
-		if (i >= 999) {
-			fprintf(stderr,
-			    "ERROR: Unable to create temp directory %s\n",
-			    tmpdir);
-			exit(1);
-		}
-	}
-
-	/*
-	 * If the user didn't specify a directory for locating
-	 * reference files, try to find the reference files in
-	 * the "usual places."
-	 */
-	refdir = refdir_alloc = get_refdir(refdir);
-
-	/*
-	 * Banner with basic information.
-	 */
-	printf("\n");
-	printf("If tests fail or crash, details will be in:\n");
-	printf("   %s\n", tmpdir);
-	printf("\n");
-	if (verbosity > VERBOSITY_SUMMARY_ONLY) {
-		printf("Reference files will be read from: %s\n", refdir);
-#ifdef PROGRAM
-		printf("Running tests on: %s\n", testprog);
-#endif
-		printf("Exercising: ");
-		fflush(stdout);
-		printf("%s\n", EXTRA_VERSION);
-	} else {
-		printf("Running ");
-		fflush(stdout);
-	}
-
-	/*
-	 * Run some or all of the individual tests.
-	 */
-	saved_argv = argv;
-	do {
-		argv = saved_argv;
-		do {
-			int test_num;
-
-			test_num = get_test_set(test_set, limit, *argv, tests);
-			if (test_num < 0) {
-				printf("*** INVALID Test %s\n", *argv);
-				free(refdir_alloc);
-				free(testprogdir);
-				usage(progname);
-				return (1);
-			}
-			for (i = 0; i < test_num; i++) {
-				tests_run++;
-				if (test_run(test_set[i], tmpdir)) {
-					tests_failed++;
-					if (until_failure)
-						goto finish;
-				}
-			}
-			if (*argv != NULL)
-				argv++;
-		} while (*argv != NULL);
-	} while (until_failure);
-
-finish:
-	/* Must be freed after all tests run */
-	free(tmp2);
-	free(testprogdir);
-	free(pwd);
-
-	/*
-	 * Report summary statistics.
-	 */
-	if (verbosity > VERBOSITY_SUMMARY_ONLY) {
-		printf("\n");
-		printf("Totals:\n");
-		printf("  Tests run:         %8d\n", tests_run);
-		printf("  Tests failed:      %8d\n", tests_failed);
-		printf("  Assertions checked:%8d\n", assertions);
-		printf("  Assertions failed: %8d\n", failures);
-		printf("  Skips reported:    %8d\n", skips);
-	}
-	if (failures) {
-		printf("\n");
-		printf("Failing tests:\n");
-		for (i = 0; i < limit; ++i) {
-			if (tests[i].failures)
-				printf("  %d: %s (%d failures)\n", i,
-				    tests[i].name, tests[i].failures);
-		}
-		printf("\n");
-		printf("Details for failing tests: %s\n", tmpdir);
-		printf("\n");
-	} else {
-		if (verbosity == VERBOSITY_SUMMARY_ONLY)
-			printf("\n");
-		printf("%d tests passed, no failures\n", tests_run);
-	}
-
-	free(refdir_alloc);
-
-	/* If the final tmpdir is empty, we can remove it. */
-	/* This should be the usual case when all tests succeed. */
-	assertChdir("..");
-	rmdir(tmpdir);
-
-	return (tests_failed ? 1 : 0);
-}
diff --git a/cpio/test/test.h b/cpio/test/test.h
index 49fa32c..1dadf68 100644
--- a/cpio/test/test.h
+++ b/cpio/test/test.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2006 Tim Kientzle
+ * Copyright (c) 2003-2017 Tim Kientzle
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -22,333 +22,19 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/usr.bin/cpio/test/test.h,v 1.2 2008/06/21 02:17:18 kientzle Exp $
+ * $FreeBSD$
  */
 
 /* Every test program should #include "test.h" as the first thing. */
 
-/*
- * The goal of this file (and the matching test.c) is to
- * simplify the very repetitive test-*.c test programs.
- */
-#if defined(HAVE_CONFIG_H)
-/* Most POSIX platforms use the 'configure' script to build config.h */
-#include "config.h"
-#elif defined(__FreeBSD__)
-/* Building as part of FreeBSD system requires a pre-built config.h. */
-#include "config_freebsd.h"
-#elif defined(_WIN32) && !defined(__CYGWIN__)
-/* Win32 can't run the 'configure' script. */
-#include "config_windows.h"
-#else
-/* Warn if the library hasn't been (automatically or manually) configured. */
-#error Oops: No config.h and no pre-built configuration in test.h.
-#endif
+#define KNOWNREF	"test_option_f.cpio.uu"
+#define ENVBASE "BSDCPIO" /* Prefix for environment variables. */
+#define	PROGRAM "bsdcpio" /* Name of program being tested. */
+#define PROGRAM_ALIAS "cpio" /* Generic alias for program */
+#undef	LIBRARY		  /* Not testing a library. */
+#undef	EXTRA_DUMP	  /* How to dump extra data */
+#undef	EXTRA_ERRNO	  /* How to dump errno */
+/* How to generate extra version info. */
+#define	EXTRA_VERSION    (systemf("%s --version", testprog) ? "" : "")
 
-#include <sys/types.h>  /* Windows requires this before sys/stat.h */
-#include <sys/stat.h>
-
-#if HAVE_DIRENT_H
-#include <dirent.h>
-#endif
-#ifdef HAVE_DIRECT_H
-#include <direct.h>
-#define dirent direct
-#endif
-#include <errno.h>
-#include <fcntl.h>
-#ifdef HAVE_IO_H
-#include <io.h>
-#endif
-#ifdef HAVE_STDINT_H
-#include <stdint.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <time.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <wchar.h>
-#ifdef HAVE_WINDOWS_H
-#include <windows.h>
-#endif
-
-/*
- * System-specific tweaks.  We really want to minimize these
- * as much as possible, since they make it harder to understand
- * the mainline code.
- */
-
-/* Windows (including Visual Studio and MinGW but not Cygwin) */
-#if defined(_WIN32) && !defined(__CYGWIN__)
-#if !defined(__BORLANDC__)
-#undef chdir
-#define chdir _chdir
-#define strdup _strdup
-#endif
-#endif
-
-/* Visual Studio */
-#if defined(_MSC_VER) && _MSC_VER < 1900
-#define snprintf	sprintf_s
-#endif
-
-#if defined(__BORLANDC__)
-#pragma warn -8068	/* Constant out of range in comparison. */
-#endif
-
-/* Haiku OS and QNX */
-#if defined(__HAIKU__) || defined(__QNXNTO__)
-/* Haiku and QNX have typedefs in stdint.h (needed for int64_t) */
-#include <stdint.h>
-#endif
-
-/* Get a real definition for __FBSDID if we can */
-#if HAVE_SYS_CDEFS_H
-#include <sys/cdefs.h>
-#endif
-
-/* If not, define it so as to avoid dangling semicolons. */
-#ifndef __FBSDID
-#define	__FBSDID(a)     struct _undefined_hack
-#endif
-
-#ifndef O_BINARY
-#define	O_BINARY 0
-#endif
-
-/*
- * Redefine DEFINE_TEST for use in defining the test functions.
- */
-#undef DEFINE_TEST
-#define DEFINE_TEST(name) void name(void); void name(void)
-
-/* An implementation of the standard assert() macro */
-#define assert(e)   assertion_assert(__FILE__, __LINE__, (e), #e, NULL)
-/* chdir() and error if it fails */
-#define assertChdir(path)  \
-  assertion_chdir(__FILE__, __LINE__, path)
-/* Assert two integers are the same.  Reports value of each one if not. */
-#define assertEqualInt(v1,v2) \
-  assertion_equal_int(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL)
-/* Assert two strings are the same.  Reports value of each one if not. */
-#define assertEqualString(v1,v2)   \
-  assertion_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL, 0)
-#define assertEqualUTF8String(v1,v2)   \
-  assertion_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL, 1)
-/* As above, but v1 and v2 are wchar_t * */
-#define assertEqualWString(v1,v2)   \
-  assertion_equal_wstring(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL)
-/* As above, but raw blocks of bytes. */
-#define assertEqualMem(v1, v2, l)	\
-  assertion_equal_mem(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (l), #l, NULL)
-/* Assert that memory is full of a specified byte */
-#define assertMemoryFilledWith(v1, l, b)					\
-  assertion_memory_filled_with(__FILE__, __LINE__, (v1), #v1, (l), #l, (b), #b, NULL)
-/* Assert two files are the same. */
-#define assertEqualFile(f1, f2)	\
-  assertion_equal_file(__FILE__, __LINE__, (f1), (f2))
-/* Assert that a file is empty. */
-#define assertEmptyFile(pathname)	\
-  assertion_empty_file(__FILE__, __LINE__, (pathname))
-/* Assert that a file is not empty. */
-#define assertNonEmptyFile(pathname)		\
-  assertion_non_empty_file(__FILE__, __LINE__, (pathname))
-#define assertFileAtime(pathname, sec, nsec)	\
-  assertion_file_atime(__FILE__, __LINE__, pathname, sec, nsec)
-#define assertFileAtimeRecent(pathname)	\
-  assertion_file_atime_recent(__FILE__, __LINE__, pathname)
-#define assertFileBirthtime(pathname, sec, nsec)	\
-  assertion_file_birthtime(__FILE__, __LINE__, pathname, sec, nsec)
-#define assertFileBirthtimeRecent(pathname) \
-  assertion_file_birthtime_recent(__FILE__, __LINE__, pathname)
-/* Assert that a file exists; supports printf-style arguments. */
-#define assertFileExists(pathname) \
-  assertion_file_exists(__FILE__, __LINE__, pathname)
-/* Assert that a file exists. */
-#define assertFileNotExists(pathname) \
-  assertion_file_not_exists(__FILE__, __LINE__, pathname)
-/* Assert that file contents match a string. */
-#define assertFileContents(data, data_size, pathname) \
-  assertion_file_contents(__FILE__, __LINE__, data, data_size, pathname)
-/* Verify that a file does not contain invalid strings */
-#define assertFileContainsNoInvalidStrings(pathname, strings) \
-  assertion_file_contains_no_invalid_strings(__FILE__, __LINE__, pathname, strings)
-#define assertFileMtime(pathname, sec, nsec)	\
-  assertion_file_mtime(__FILE__, __LINE__, pathname, sec, nsec)
-#define assertFileMtimeRecent(pathname) \
-  assertion_file_mtime_recent(__FILE__, __LINE__, pathname)
-#define assertFileNLinks(pathname, nlinks)  \
-  assertion_file_nlinks(__FILE__, __LINE__, pathname, nlinks)
-#define assertFileSize(pathname, size)  \
-  assertion_file_size(__FILE__, __LINE__, pathname, size)
-#define assertFileMode(pathname, mode)  \
-  assertion_file_mode(__FILE__, __LINE__, pathname, mode)
-#define assertTextFileContents(text, pathname) \
-  assertion_text_file_contents(__FILE__, __LINE__, text, pathname)
-#define assertFileContainsLinesAnyOrder(pathname, lines)	\
-  assertion_file_contains_lines_any_order(__FILE__, __LINE__, pathname, lines)
-#define assertIsDir(pathname, mode)		\
-  assertion_is_dir(__FILE__, __LINE__, pathname, mode)
-#define assertIsHardlink(path1, path2)	\
-  assertion_is_hardlink(__FILE__, __LINE__, path1, path2)
-#define assertIsNotHardlink(path1, path2)	\
-  assertion_is_not_hardlink(__FILE__, __LINE__, path1, path2)
-#define assertIsReg(pathname, mode)		\
-  assertion_is_reg(__FILE__, __LINE__, pathname, mode)
-#define assertIsSymlink(pathname, contents)	\
-  assertion_is_symlink(__FILE__, __LINE__, pathname, contents)
-/* Create a directory, report error if it fails. */
-#define assertMakeDir(dirname, mode)	\
-  assertion_make_dir(__FILE__, __LINE__, dirname, mode)
-#define assertMakeFile(path, mode, contents) \
-  assertion_make_file(__FILE__, __LINE__, path, mode, -1, contents)
-#define assertMakeBinFile(path, mode, csize, contents) \
-  assertion_make_file(__FILE__, __LINE__, path, mode, csize, contents)
-#define assertMakeHardlink(newfile, oldfile)	\
-  assertion_make_hardlink(__FILE__, __LINE__, newfile, oldfile)
-#define assertMakeSymlink(newfile, linkto)	\
-  assertion_make_symlink(__FILE__, __LINE__, newfile, linkto)
-#define assertNodump(path)      \
-  assertion_nodump(__FILE__, __LINE__, path)
-#define assertUmask(mask)	\
-  assertion_umask(__FILE__, __LINE__, mask)
-#define assertUtimes(pathname, atime, atime_nsec, mtime, mtime_nsec)	\
-  assertion_utimes(__FILE__, __LINE__, pathname, atime, atime_nsec, mtime, mtime_nsec)
-
-/*
- * This would be simple with C99 variadic macros, but I don't want to
- * require that.  Instead, I insert a function call before each
- * skipping() call to pass the file and line information down.  Crude,
- * but effective.
- */
-#define skipping	\
-  skipping_setup(__FILE__, __LINE__);test_skipping
-
-/* Function declarations.  These are defined in test_utility.c. */
-void failure(const char *fmt, ...);
-int assertion_assert(const char *, int, int, const char *, void *);
-int assertion_chdir(const char *, int, const char *);
-int assertion_empty_file(const char *, int, const char *);
-int assertion_equal_file(const char *, int, const char *, const char *);
-int assertion_equal_int(const char *, int, long long, const char *, long long, const char *, void *);
-int assertion_equal_mem(const char *, int, const void *, const char *, const void *, const char *, size_t, const char *, void *);
-int assertion_memory_filled_with(const char *, int, const void *, const char *, size_t, const char *, char, const char *, void *);
-int assertion_equal_string(const char *, int, const char *v1, const char *, const char *v2, const char *, void *, int);
-int assertion_equal_wstring(const char *, int, const wchar_t *v1, const char *, const wchar_t *v2, const char *, void *);
-int assertion_file_atime(const char *, int, const char *, long, long);
-int assertion_file_atime_recent(const char *, int, const char *);
-int assertion_file_birthtime(const char *, int, const char *, long, long);
-int assertion_file_birthtime_recent(const char *, int, const char *);
-int assertion_file_contains_lines_any_order(const char *, int, const char *, const char **);
-int assertion_file_contains_no_invalid_strings(const char *, int, const char *, const char **);
-int assertion_file_contents(const char *, int, const void *, int, const char *);
-int assertion_file_exists(const char *, int, const char *);
-int assertion_file_mode(const char *, int, const char *, int);
-int assertion_file_mtime(const char *, int, const char *, long, long);
-int assertion_file_mtime_recent(const char *, int, const char *);
-int assertion_file_nlinks(const char *, int, const char *, int);
-int assertion_file_not_exists(const char *, int, const char *);
-int assertion_file_size(const char *, int, const char *, long);
-int assertion_is_dir(const char *, int, const char *, int);
-int assertion_is_hardlink(const char *, int, const char *, const char *);
-int assertion_is_not_hardlink(const char *, int, const char *, const char *);
-int assertion_is_reg(const char *, int, const char *, int);
-int assertion_is_symlink(const char *, int, const char *, const char *);
-int assertion_make_dir(const char *, int, const char *, int);
-int assertion_make_file(const char *, int, const char *, int, int, const void *);
-int assertion_make_hardlink(const char *, int, const char *newpath, const char *);
-int assertion_make_symlink(const char *, int, const char *newpath, const char *);
-int assertion_nodump(const char *, int, const char *);
-int assertion_non_empty_file(const char *, int, const char *);
-int assertion_text_file_contents(const char *, int, const char *buff, const char *f);
-int assertion_umask(const char *, int, int);
-int assertion_utimes(const char *, int, const char *, long, long, long, long );
-
-void skipping_setup(const char *, int);
-void test_skipping(const char *fmt, ...);
-
-/* Like sprintf, then system() */
-int systemf(const char * fmt, ...);
-
-/* Delay until time() returns a value after this. */
-void sleepUntilAfter(time_t);
-
-/* Return true if this platform can create symlinks. */
-int canSymlink(void);
-
-/* Return true if this platform can run the "bzip2" program. */
-int canBzip2(void);
-
-/* Return true if this platform can run the "grzip" program. */
-int canGrzip(void);
-
-/* Return true if this platform can run the "gzip" program. */
-int canGzip(void);
-
-/* Return true if this platform can run the specified command. */
-int canRunCommand(const char *);
-
-/* Return true if this platform can run the "lrzip" program. */
-int canLrzip(void);
-
-/* Return true if this platform can run the "lz4" program. */
-int canLz4(void);
-
-/* Return true if this platform can run the "lzip" program. */
-int canLzip(void);
-
-/* Return true if this platform can run the "lzma" program. */
-int canLzma(void);
-
-/* Return true if this platform can run the "lzop" program. */
-int canLzop(void);
-
-/* Return true if this platform can run the "xz" program. */
-int canXz(void);
-
-/* Return true if this filesystem can handle nodump flags. */
-int canNodump(void);
-
-/* Return true if the file has large i-node number(>0xffffffff). */
-int is_LargeInode(const char *);
-
-/* Suck file into string allocated via malloc(). Call free() when done. */
-/* Supports printf-style args: slurpfile(NULL, "%s/myfile", refdir); */
-char *slurpfile(size_t *, const char *fmt, ...);
-
-/* Dump block of bytes to a file. */
-void dumpfile(const char *filename, void *, size_t);
-
-/* Extracts named reference file to the current directory. */
-void extract_reference_file(const char *);
-/* Copies named reference file to the current directory. */
-void copy_reference_file(const char *);
-
-/* Extracts a list of files to the current directory.
- * List must be NULL terminated.
- */
-void extract_reference_files(const char **);
-
-/* Subtract umask from mode */
-mode_t umasked(mode_t expected_mode);
-
-/* Path to working directory for current test */
-extern const char *testworkdir;
-
-/*
- * Special interfaces for program test harness.
- */
-
-/* Pathname of exe to be tested. */
-extern const char *testprogfile;
-/* Name of exe to use in printf-formatted command strings. */
-/* On Windows, this includes leading/trailing quotes. */
-extern const char *testprog;
-
-#ifdef USE_DMALLOC
-#include <dmalloc.h>
-#endif
+#include "test_common.h"
diff --git a/cpio/test/test_option_version.c b/cpio/test/test_option_version.c
index ac58cef..505db27 100644
--- a/cpio/test/test_option_version.c
+++ b/cpio/test/test_option_version.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2003-2017 Tim Kientzle
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -23,92 +23,8 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include "test.h"
-__FBSDID("$FreeBSD$");
-
-/*
- * Test that --version option works and generates reasonable output.
- */
-
-static void
-verify(const char *p, size_t s)
-{
-	const char *q = p;
-
-	/* Version message should start with name of program, then space. */
-	failure("version message too short:", p);
-	if (!assert(s > 6))
-		return;
-	failure("Version message should begin with 'bsdcpio': %s", p);
-	if (!assertEqualMem(q, "bsdcpio ", 8))
-		/* If we're not testing bsdcpio, don't keep going. */
-		return;
-	q += 8; s -= 8;
-	/* Version number is a series of digits and periods. */
-	while (s > 0 && (*q == '.' || (*q >= '0' && *q <= '9'))) {
-		++q;
-		--s;
-	}
-	/* Version number terminated by space. */
-	failure("Version: %s", p);
-	assert(s > 1);
-	/* Skip a single trailing a,b,c, or d. */
-	if (*q == 'a' || *q == 'b' || *q == 'c' || *q == 'd')
-		++q;
-	failure("Version: %s", p);
-	assert(*q == ' ');
-	++q; --s;
-	/* Separator. */
-	failure("Version: %s", p);
-	assertEqualMem(q, "- ", 2);
-	q += 2; s -= 2;
-	/* libarchive name and version number */
-	assert(s > 11);
-	failure("Version: %s", p);
-	assertEqualMem(q, "libarchive ", 11);
-	q += 11; s -= 11;
-	/* Version number is a series of digits and periods. */
-	while (s > 0 && (*q == '.' || (*q >= '0' && *q <= '9'))) {
-		++q;
-		--s;
-	}
-	/* Skip a single trailing a,b,c, or d. */
-	if (*q == 'a' || *q == 'b' || *q == 'c' || *q == 'd')
-		++q;
-	/* Skip arbitrary third-party version numbers. */
-	while (s > 0 && (*q == ' ' || *q == '-' || *q == '/' || *q == '.' || isalnum(*q))) {
-		++q;
-		--s;
-	}
-	/* All terminated by end-of-line: \r, \r\n, or \n */
-	assert(s >= 1);
-	failure("Version: %s", p);
-	if (*q == '\x0d') {
-		if (q[1] != '\0')
-			assertEqualMem(q, "\x0d\x0a", 2);
-	} else
-		assertEqualMem(q, "\x0a", 1);
-}
-
 
 DEFINE_TEST(test_option_version)
 {
-	int r;
-	char *p;
-	size_t s;
-
-	r = systemf("%s --version >version.stdout 2>version.stderr", testprog);
-	if (r != 0)
-		r = systemf("%s -W version >version.stdout 2>version.stderr",
-		    testprog);
-	failure("Unable to run either %s --version or %s -W version",
-	    testprog, testprog);
-	if (!assert(r == 0))
-		return;
-
-	/* --version should generate nothing to stderr. */
-	assertEmptyFile("version.stderr");
-	/* Verify format of version message. */
-	p = slurpfile(&s, "version.stdout");
-	verify(p, s);
-	free(p);
+	assertVersion(testprog, "bsdcpio");
 }
diff --git a/libarchive/archive.h b/libarchive/archive.h
index c676858..e74be4d 100644
--- a/libarchive/archive.h
+++ b/libarchive/archive.h
@@ -36,7 +36,7 @@
  * assert that ARCHIVE_VERSION_NUMBER >= 2012108.
  */
 /* Note: Compiler will complain if this does not match archive_entry.h! */
-#define	ARCHIVE_VERSION_NUMBER 3002002
+#define	ARCHIVE_VERSION_NUMBER 3003001
 
 #include <sys/stat.h>
 #include <stddef.h>  /* for wchar_t */
@@ -155,7 +155,7 @@
 /*
  * Textual name/version of the library, useful for version displays.
  */
-#define	ARCHIVE_VERSION_ONLY_STRING "3.2.2"
+#define	ARCHIVE_VERSION_ONLY_STRING "3.3.1dev"
 #define	ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
 __LA_DECL const char *	archive_version_string(void);
 
@@ -1001,6 +1001,10 @@
 #define	ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS	(0x0008)
 /* Default: Xattrs are read from disk. */
 #define	ARCHIVE_READDISK_NO_XATTR		(0x0010)
+/* Default: ACLs are read from disk. */
+#define	ARCHIVE_READDISK_NO_ACL			(0x0020)
+/* Default: File flags are read from disk. */
+#define	ARCHIVE_READDISK_NO_FFLAGS		(0x0040)
 
 __LA_DECL int  archive_read_disk_set_behavior(struct archive *,
 		    int flags);
diff --git a/libarchive/archive_entry.c b/libarchive/archive_entry.c
index d4f061b..10eff11 100644
--- a/libarchive/archive_entry.c
+++ b/libarchive/archive_entry.c
@@ -1649,7 +1649,10 @@
 	{ "nosappnd",	L"nosappnd",		SF_APPEND,	0 },
 	{ "nosappend",	L"nosappend",		SF_APPEND,	0 },
 #endif
-#ifdef  EXT2_APPEND_FL				/* 'a' */
+#if defined(FS_APPEND_FL)			/* 'a' */
+	{ "nosappnd",	L"nosappnd",		FS_APPEND_FL,	0 },
+	{ "nosappend",	L"nosappend",		FS_APPEND_FL,	0 },
+#elif defined(EXT2_APPEND_FL)			/* 'a' */
 	{ "nosappnd",	L"nosappnd",		EXT2_APPEND_FL,	0 },
 	{ "nosappend",	L"nosappend",		EXT2_APPEND_FL,	0 },
 #endif
@@ -1662,7 +1665,11 @@
 	{ "noschange",	L"noschange",		SF_IMMUTABLE,	0 },
 	{ "nosimmutable",	L"nosimmutable",	SF_IMMUTABLE,	0 },
 #endif
-#ifdef EXT2_IMMUTABLE_FL			/* 'i' */
+#if defined(FS_IMMUTABLE_FL)			/* 'i' */
+	{ "noschg",	L"noschg",		FS_IMMUTABLE_FL,	0 },
+	{ "noschange",	L"noschange",		FS_IMMUTABLE_FL,	0 },
+	{ "nosimmutable",	L"nosimmutable",	FS_IMMUTABLE_FL,	0 },
+#elif defined(EXT2_IMMUTABLE_FL)		/* 'i' */
 	{ "noschg",	L"noschg",		EXT2_IMMUTABLE_FL,	0 },
 	{ "noschange",	L"noschange",		EXT2_IMMUTABLE_FL,	0 },
 	{ "nosimmutable",	L"nosimmutable",	EXT2_IMMUTABLE_FL,	0 },
@@ -1686,7 +1693,9 @@
 #ifdef UF_NODUMP
 	{ "nodump",	L"nodump",		0,		UF_NODUMP},
 #endif
-#ifdef EXT2_NODUMP_FL				/* 'd' */
+#if defined(FS_NODUMP_FL)	/* 'd' */
+	{ "nodump",	L"nodump",		0,		FS_NODUMP_FL},
+#elif defined(EXT2_NODUMP_FL) 	/* 'd' */
 	{ "nodump",	L"nodump",		0,		EXT2_NODUMP_FL},
 #endif
 #ifdef UF_OPAQUE
@@ -1699,65 +1708,124 @@
 #ifdef UF_COMPRESSED
 	{ "nocompressed",L"nocompressed",	UF_COMPRESSED,	0 },
 #endif
-#ifdef EXT2_UNRM_FL
+#if defined(FS_UNRM_FL)
+        { "nouunlink",	L"nouunlink",		FS_UNRM_FL,	0},
+#elif defined(EXT2_UNRM_FL)
         { "nouunlink",	L"nouunlink",		EXT2_UNRM_FL,	0},
 #endif
 
-#ifdef EXT2_BTREE_FL
+#if defined(FS_BTREE_FL)
+        { "nobtree",	L"nobtree",       	FS_BTREE_FL,	0 },
+#elif defined(EXT2_BTREE_FL)
         { "nobtree",	L"nobtree",       	EXT2_BTREE_FL,	0 },
 #endif
 
-#ifdef EXT2_ECOMPR_FL
+#if defined(FS_ECOMPR_FL)
+        { "nocomperr",	L"nocomperr",       	FS_ECOMPR_FL,	0 },
+#elif defined(EXT2_ECOMPR_FL)
         { "nocomperr",	L"nocomperr",       	EXT2_ECOMPR_FL,	0 },
 #endif
 
-#ifdef EXT2_COMPR_FL				/* 'c' */
+#if defined(FS_COMPR_FL)			/* 'c' */
+        { "nocompress",	L"nocompress",       	FS_COMPR_FL,	0 },
+#elif defined(EXT2_COMPR_FL)			/* 'c' */
         { "nocompress",	L"nocompress",       	EXT2_COMPR_FL,	0 },
 #endif
 
-#ifdef EXT2_NOATIME_FL				/* 'A' */
+#if defined(FS_NOATIME_FL)			/* 'A' */
+        { "noatime",	L"noatime",		0,		FS_NOATIME_FL},
+#elif defined(EXT2_NOATIME_FL)			/* 'A' */
         { "noatime",	L"noatime",		0,		EXT2_NOATIME_FL},
 #endif
 
-#ifdef EXT2_DIRTY_FL
+#if defined(FS_DIRTY_FL)
+        { "nocompdirty",L"nocompdirty",		FS_DIRTY_FL,		0},
+#elif defined(EXT2_DIRTY_FL)
         { "nocompdirty",L"nocompdirty",		EXT2_DIRTY_FL,		0},
 #endif
 
-#ifdef EXT2_COMPRBLK_FL
-#ifdef EXT2_NOCOMPR_FL
+#if defined(FS_COMPRBLK_FL)
+#if defined(FS_NOCOMPR_FL)
+        { "nocomprblk",	L"nocomprblk",		FS_COMPRBLK_FL, FS_NOCOMPR_FL},
+#else
+        { "nocomprblk",	L"nocomprblk",		FS_COMPRBLK_FL,	0},
+#endif
+#elif defined(EXT2_COMPRBLK_FL)
+#if defined(EXT2_NOCOMPR_FL)
         { "nocomprblk",	L"nocomprblk",		EXT2_COMPRBLK_FL, EXT2_NOCOMPR_FL},
 #else
         { "nocomprblk",	L"nocomprblk",		EXT2_COMPRBLK_FL,	0},
 #endif
 #endif
-#ifdef EXT2_DIRSYNC_FL
+#if defined(FS_DIRSYNC_FL)
+        { "nodirsync",	L"nodirsync",		FS_DIRSYNC_FL,	0},
+#elif defined(EXT2_DIRSYNC_FL)
         { "nodirsync",	L"nodirsync",		EXT2_DIRSYNC_FL,	0},
 #endif
-#ifdef EXT2_INDEX_FL
+#if defined(FS_INDEX_FL)
+        { "nohashidx",	L"nohashidx",		FS_INDEX_FL,		0},
+#elif defined(EXT2_INDEX_FL)
         { "nohashidx",	L"nohashidx",		EXT2_INDEX_FL,		0},
 #endif
-#ifdef EXT2_IMAGIC_FL
+#if defined(FS_IMAGIC_FL)
+        { "noimagic",	L"noimagic",		FS_IMAGIC_FL,		0},
+#elif defined(EXT2_IMAGIC_FL)
         { "noimagic",	L"noimagic",		EXT2_IMAGIC_FL,		0},
 #endif
-#ifdef EXT3_JOURNAL_DATA_FL
+#if defined(FS_JOURNAL_DATA_FL)
+        { "nojournal",	L"nojournal",		FS_JOURNAL_DATA_FL,	0},
+#elif defined(EXT3_JOURNAL_DATA_FL)
         { "nojournal",	L"nojournal",		EXT3_JOURNAL_DATA_FL,	0},
 #endif
-#ifdef EXT2_SECRM_FL
+#if defined(FS_SECRM_FL)
+        { "nosecuredeletion",L"nosecuredeletion",FS_SECRM_FL,		0},
+#elif defined(EXT2_SECRM_FL)
         { "nosecuredeletion",L"nosecuredeletion",EXT2_SECRM_FL,		0},
 #endif
-#ifdef EXT2_SYNC_FL
+#if defined(FS_SYNC_FL)
+        { "nosync",	L"nosync",		FS_SYNC_FL,		0},
+#elif defined(EXT2_SYNC_FL)
         { "nosync",	L"nosync",		EXT2_SYNC_FL,		0},
 #endif
-#ifdef EXT2_NOTAIL_FL
+#if defined(FS_NOTAIL_FL)
+        { "notail",	L"notail",		0,		FS_NOTAIL_FL},
+#elif defined(EXT2_NOTAIL_FL)
         { "notail",	L"notail",		0,		EXT2_NOTAIL_FL},
 #endif
-#ifdef EXT2_TOPDIR_FL
+#if defined(FS_TOPDIR_FL)
+        { "notopdir",	L"notopdir",		FS_TOPDIR_FL,		0},
+#elif defined(EXT2_TOPDIR_FL)
         { "notopdir",	L"notopdir",		EXT2_TOPDIR_FL,		0},
 #endif
-#ifdef EXT2_RESERVED_FL
+#ifdef FS_ENCRYPT_FL
+        { "noencrypt",	L"noencrypt",		FS_ENCRYPT_FL,	0},
+#endif
+#ifdef FS_HUGE_FILE_FL
+        { "nohugefile",	L"nohugefile",		FS_HUGE_FILE_FL,	0},
+#endif
+#ifdef FS_EXTENT_FL
+        { "noextent",	L"noextent",		FS_EXTENT_FL,	0},
+#endif
+#ifdef FS_EA_INODE_FL
+        { "noeainode",	L"noeainode",		FS_EA_INODE_FL,	0},
+#endif
+#ifdef FS_EOFBLOCKS_FL
+        { "noeofblocks",L"noeofblocks",		FS_EOFBLOCKS_FL,	0},
+#endif
+#ifdef FS_NOCOW_FL
+        { "nocow",	L"nocow",		FS_NOCOW_FL,	0},
+#endif
+#ifdef FS_INLINE_DATA_FL
+        { "noinlinedata",L"noinlinedata",	FS_INLINE_DATA_FL,	0},
+#endif
+#ifdef FS_PROJINHERIT_FL
+        { "noprojinherit",L"noprojinherit",	FS_PROJINHERIT_FL,	0},
+#endif
+#if defined(FS_RESERVED_FL)
+        { "noreserved",	L"noreserved",		FS_RESERVED_FL,	0},
+#elif defined(EXT2_RESERVED_FL)
         { "noreserved",	L"noreserved",		EXT2_RESERVED_FL,	0},
 #endif
-
 	{ NULL,		NULL,			0,		0 }
 };
 
diff --git a/libarchive/archive_entry.h b/libarchive/archive_entry.h
index ca77b37..7645f0c 100644
--- a/libarchive/archive_entry.h
+++ b/libarchive/archive_entry.h
@@ -30,7 +30,7 @@
 #define	ARCHIVE_ENTRY_H_INCLUDED
 
 /* Note: Compiler will complain if this does not match archive.h! */
-#define	ARCHIVE_VERSION_NUMBER 3002002
+#define	ARCHIVE_VERSION_NUMBER 3003001
 
 /*
  * Note: archive_entry.h is for use outside of libarchive; the
@@ -66,6 +66,27 @@
 # endif
 #endif
 
+/* The la_ssize_t should match the type used in 'struct stat' */
+#if !defined(__LA_SSIZE_T_DEFINED)
+/* Older code relied on the __LA_SSIZE_T macro; after 4.0 we'll switch to the typedef exclusively. */
+# if ARCHIVE_VERSION_NUMBER < 4000000
+#define __LA_SSIZE_T la_ssize_t
+# endif
+#define __LA_SSIZE_T_DEFINED
+# if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__)
+#  if defined(_SSIZE_T_DEFINED) || defined(_SSIZE_T_)
+typedef ssize_t la_ssize_t;
+#  elif defined(_WIN64)
+typedef __int64 la_ssize_t;
+#  else
+typedef long la_ssize_t;
+#  endif
+# else
+# include <unistd.h>  /* ssize_t */
+typedef ssize_t la_ssize_t;
+# endif
+#endif
+
 /* Get a suitable definition for mode_t */
 #if ARCHIVE_VERSION_NUMBER >= 3999000
 /* Switch to plain 'int' for libarchive 4.0.  It's less broken than 'mode_t' */
@@ -526,9 +547,9 @@
 #define	ARCHIVE_ENTRY_ACL_STYLE_COMPACT		0x00000010
 
 __LA_DECL wchar_t *archive_entry_acl_to_text_w(struct archive_entry *,
-	    ssize_t * /* len */, int /* flags */);
+	    la_ssize_t * /* len */, int /* flags */);
 __LA_DECL char *archive_entry_acl_to_text(struct archive_entry *,
-	    ssize_t * /* len */, int /* flags */);
+	    la_ssize_t * /* len */, int /* flags */);
 __LA_DECL int archive_entry_acl_from_text_w(struct archive_entry *,
 	    const wchar_t * /* wtext */, int /* type */);
 __LA_DECL int archive_entry_acl_from_text(struct archive_entry *,
diff --git a/libarchive/archive_read_disk_entry_from_file.c b/libarchive/archive_read_disk_entry_from_file.c
index 591a212..b2f1d17 100644
--- a/libarchive/archive_read_disk_entry_from_file.c
+++ b/libarchive/archive_read_disk_entry_from_file.c
@@ -203,15 +203,17 @@
 #ifdef HAVE_STRUCT_STAT_ST_FLAGS
 	/* On FreeBSD, we get flags for free with the stat. */
 	/* TODO: Does this belong in copy_stat()? */
-	if (st->st_flags != 0)
+	if ((a->flags & ARCHIVE_READDISK_NO_FFLAGS) == 0 && st->st_flags != 0)
 		archive_entry_set_fflags(entry, st->st_flags, 0);
 #endif
 
-#if defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)
+#if (defined(FS_IOC_GETFLAGS) && defined(HAVE_WORKING_FS_IOC_GETFLAGS)) || \
+    (defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS))
 	/* Linux requires an extra ioctl to pull the flags.  Although
 	 * this is an extra step, it has a nice side-effect: We get an
 	 * open file descriptor which we can use in the subsequent lookups. */
-	if ((S_ISREG(st->st_mode) || S_ISDIR(st->st_mode))) {
+	if ((a->flags & ARCHIVE_READDISK_NO_FFLAGS) == 0 &&
+	    (S_ISREG(st->st_mode) || S_ISDIR(st->st_mode))) {
 		if (fd < 0) {
 			if (a->tree != NULL)
 				fd = a->open_on_current_dir(a->tree, path,
@@ -223,7 +225,13 @@
 		}
 		if (fd >= 0) {
 			int stflags;
-			r = ioctl(fd, EXT2_IOC_GETFLAGS, &stflags);
+			r = ioctl(fd,
+#if defined(FS_IOC_GETFLAGS)
+			    FS_IOC_GETFLAGS,
+#else
+			    EXT2_IOC_GETFLAGS,
+#endif
+			    &stflags);
 			if (r == 0 && stflags != 0)
 				archive_entry_set_fflags(entry, stflags, 0);
 		}
@@ -269,13 +277,15 @@
 	}
 #endif /* HAVE_READLINK || HAVE_READLINKAT */
 
-	r = setup_acls(a, entry, &fd);
-	if (!a->suppress_xattr) {
+	r = 0;
+	if ((a->flags & ARCHIVE_READDISK_NO_ACL) == 0)
+		r = setup_acls(a, entry, &fd);
+	if ((a->flags & ARCHIVE_READDISK_NO_XATTR) == 0) {
 		r1 = setup_xattrs(a, entry, &fd);
 		if (r1 < r)
 			r = r1;
 	}
-	if (a->enable_copyfile) {
+	if (a->flags & ARCHIVE_READDISK_MAC_COPYFILE) {
 		r1 = setup_mac_metadata(a, entry, &fd);
 		if (r1 < r)
 			r = r1;
diff --git a/libarchive/archive_read_disk_posix.c b/libarchive/archive_read_disk_posix.c
index b893704..6961ae6 100644
--- a/libarchive/archive_read_disk_posix.c
+++ b/libarchive/archive_read_disk_posix.c
@@ -465,8 +465,7 @@
 	a->entry = archive_entry_new2(&a->archive);
 	a->lookup_uname = trivial_lookup_uname;
 	a->lookup_gname = trivial_lookup_gname;
-	a->enable_copyfile = 1;
-	a->traverse_mount_points = 1;
+	a->flags = ARCHIVE_READDISK_MAC_COPYFILE;
 	a->open_on_current_dir = open_on_current_dir;
 	a->tree_current_dir_fd = tree_current_dir_fd;
 	a->tree_enter_working_dir = tree_enter_working_dir;
@@ -563,25 +562,19 @@
 int
 archive_read_disk_set_atime_restored(struct archive *_a)
 {
-#ifndef HAVE_UTIMES
-	static int warning_done = 0;
-#endif
 	struct archive_read_disk *a = (struct archive_read_disk *)_a;
 	archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
 	    ARCHIVE_STATE_ANY, "archive_read_disk_restore_atime");
 #ifdef HAVE_UTIMES
-	a->restore_time = 1;
+	a->flags |= ARCHIVE_READDISK_RESTORE_ATIME;
 	if (a->tree != NULL)
 		a->tree->flags |= needsRestoreTimes;
 	return (ARCHIVE_OK);
 #else
-	if (warning_done)
-		/* Warning was already emitted; suppress further warnings. */
-		return (ARCHIVE_OK);
-
+	/* Display warning and unset flag */
 	archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 	    "Cannot restore access time on this system");
-	warning_done = 1;
+	a->flags &= ~ARCHIVE_READDISK_RESTORE_ATIME;
 	return (ARCHIVE_WARN);
 #endif
 }
@@ -595,29 +588,14 @@
 	archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
 	    ARCHIVE_STATE_ANY, "archive_read_disk_honor_nodump");
 
+	a->flags = flags;
+
 	if (flags & ARCHIVE_READDISK_RESTORE_ATIME)
 		r = archive_read_disk_set_atime_restored(_a);
 	else {
-		a->restore_time = 0;
 		if (a->tree != NULL)
 			a->tree->flags &= ~needsRestoreTimes;
 	}
-	if (flags & ARCHIVE_READDISK_HONOR_NODUMP)
-		a->honor_nodump = 1;
-	else
-		a->honor_nodump = 0;
-	if (flags & ARCHIVE_READDISK_MAC_COPYFILE)
-		a->enable_copyfile = 1;
-	else
-		a->enable_copyfile = 0;
-	if (flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS)
-		a->traverse_mount_points = 0;
-	else
-		a->traverse_mount_points = 1;
-	if (flags & ARCHIVE_READDISK_NO_XATTR)
-		a->suppress_xattr = 1;
-	else
-		a->suppress_xattr = 0;
 	return (r);
 }
 
@@ -918,7 +896,7 @@
 	} while (lst == NULL);
 
 #ifdef __APPLE__
-	if (a->enable_copyfile) {
+	if (a->flags & ARCHIVE_READDISK_MAC_COPYFILE) {
 		/* If we're using copyfile(), ignore "._XXX" files. */
 		const char *bname = strrchr(tree_current_path(t), '/');
 		if (bname == NULL)
@@ -989,7 +967,7 @@
 	}
 	if (t->initial_filesystem_id == -1)
 		t->initial_filesystem_id = t->current_filesystem_id;
-	if (!a->traverse_mount_points) {
+	if (a->flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS) {
 		if (t->initial_filesystem_id != t->current_filesystem_id)
 			descend = 0;
 	}
@@ -999,12 +977,14 @@
 	 * Honor nodump flag.
 	 * If the file is marked with nodump flag, do not return this entry.
 	 */
-	if (a->honor_nodump) {
+	if (a->flags & ARCHIVE_READDISK_HONOR_NODUMP) {
 #if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP)
 		if (st->st_flags & UF_NODUMP)
 			return (ARCHIVE_RETRY);
-#elif defined(EXT2_IOC_GETFLAGS) && defined(EXT2_NODUMP_FL) &&\
-      defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)
+#elif (defined(FS_IOC_GETFLAGS) && defined(FS_NODUMP_FL) && \
+       defined(HAVE_WORKING_FS_IOC_GETFLAGS)) || \
+      (defined(EXT2_IOC_GETFLAGS) && defined(EXT2_NODUMP_FL) && \
+       defined(HAVE_WORKING_EXT2_IOC_GETFLAGS))
 		if (S_ISREG(st->st_mode) || S_ISDIR(st->st_mode)) {
 			int stflags;
 
@@ -1013,9 +993,18 @@
 			    O_RDONLY | O_NONBLOCK | O_CLOEXEC);
 			__archive_ensure_cloexec_flag(t->entry_fd);
 			if (t->entry_fd >= 0) {
-				r = ioctl(t->entry_fd, EXT2_IOC_GETFLAGS,
+				r = ioctl(t->entry_fd,
+#ifdef FS_IOC_GETFLAGS
+				FS_IOC_GETFLAGS,
+#else
+				EXT2_IOC_GETFLAGS,
+#endif
 					&stflags);
+#ifdef FS_NODUMP_FL
+				if (r == 0 && (stflags & FS_NODUMP_FL) != 0)
+#else
 				if (r == 0 && (stflags & EXT2_NODUMP_FL) != 0)
+#endif
 					return (ARCHIVE_RETRY);
 			}
 		}
@@ -1340,10 +1329,11 @@
 	struct archive_read_disk *a = (struct archive_read_disk *)_a;
 
 	if (a->tree != NULL)
-		a->tree = tree_reopen(a->tree, pathname, a->restore_time);
+		a->tree = tree_reopen(a->tree, pathname,
+		    a->flags & ARCHIVE_READDISK_RESTORE_ATIME);
 	else
 		a->tree = tree_open(pathname, a->symlink_mode,
-		    a->restore_time);
+		    a->flags & ARCHIVE_READDISK_RESTORE_ATIME);
 	if (a->tree == NULL) {
 		archive_set_error(&a->archive, ENOMEM,
 		    "Can't allocate tar data");
@@ -2132,7 +2122,7 @@
 static struct tree *
 tree_reopen(struct tree *t, const char *path, int restore_time)
 {
-	t->flags = (restore_time)?needsRestoreTimes:0;
+	t->flags = (restore_time != 0)?needsRestoreTimes:0;
 	t->flags |= onInitialDir;
 	t->visit_type = 0;
 	t->tree_errno = 0;
diff --git a/libarchive/archive_read_disk_private.h b/libarchive/archive_read_disk_private.h
index 2569321..b5a8328 100644
--- a/libarchive/archive_read_disk_private.h
+++ b/libarchive/archive_read_disk_private.h
@@ -63,16 +63,8 @@
 	int	(*tree_current_dir_fd)(struct tree*);
 	int	(*tree_enter_working_dir)(struct tree*);
 
-	/* Set 1 if users request to restore atime . */
-	int		 restore_time;
-	/* Set 1 if users request to honor nodump flag . */
-	int		 honor_nodump;
-	/* Set 1 if users request to enable mac copyfile. */
-	int		 enable_copyfile;
-	/* Set 1 if users request to traverse mount points. */
-	int		 traverse_mount_points;
-	/* Set 1 if users want to suppress xattr information. */
-	int		 suppress_xattr;
+	/* Bitfield with ARCHIVE_READDISK_* tunables */
+	int	flags;
 
 	const char * (*lookup_gname)(void *private, int64_t gid);
 	void	(*cleanup_gname)(void *private);
diff --git a/libarchive/archive_read_disk_windows.c b/libarchive/archive_read_disk_windows.c
index 27b75e3..3b90330 100644
--- a/libarchive/archive_read_disk_windows.c
+++ b/libarchive/archive_read_disk_windows.c
@@ -398,8 +398,7 @@
 	a->entry = archive_entry_new2(&a->archive);
 	a->lookup_uname = trivial_lookup_uname;
 	a->lookup_gname = trivial_lookup_gname;
-	a->enable_copyfile = 1;
-	a->traverse_mount_points = 1;
+	a->flags = ARCHIVE_READDISK_MAC_COPYFILE;
 	return (&a->archive);
 }
 
@@ -495,7 +494,7 @@
 	struct archive_read_disk *a = (struct archive_read_disk *)_a;
 	archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
 	    ARCHIVE_STATE_ANY, "archive_read_disk_restore_atime");
-	a->restore_time = 1;
+	a->flags |= ARCHIVE_READDISK_RESTORE_ATIME;
 	if (a->tree != NULL)
 		a->tree->flags |= needsRestoreTimes;
 	return (ARCHIVE_OK);
@@ -510,25 +509,14 @@
 	archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
 	    ARCHIVE_STATE_ANY, "archive_read_disk_honor_nodump");
 
+	a->flags = flags;
+
 	if (flags & ARCHIVE_READDISK_RESTORE_ATIME)
 		r = archive_read_disk_set_atime_restored(_a);
 	else {
-		a->restore_time = 0;
 		if (a->tree != NULL)
 			a->tree->flags &= ~needsRestoreTimes;
 	}
-	if (flags & ARCHIVE_READDISK_HONOR_NODUMP)
-		a->honor_nodump = 1;
-	else
-		a->honor_nodump = 0;
-	if (flags & ARCHIVE_READDISK_MAC_COPYFILE)
-		a->enable_copyfile = 1;
-	else
-		a->enable_copyfile = 0;
-	if (flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS)
-		a->traverse_mount_points = 0;
-	else
-		a->traverse_mount_points = 1;
 	return (r);
 }
 
@@ -852,7 +840,7 @@
 	}
 	if (t->initial_filesystem_id == -1)
 		t->initial_filesystem_id = t->current_filesystem_id;
-	if (!a->traverse_mount_points) {
+	if (a->flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS) {
 		if (t->initial_filesystem_id != t->current_filesystem_id)
 			return (ARCHIVE_RETRY);
 	}
@@ -1219,9 +1207,11 @@
 	struct archive_read_disk *a = (struct archive_read_disk *)_a;
 
 	if (a->tree != NULL)
-		a->tree = tree_reopen(a->tree, pathname, a->restore_time);
+		a->tree = tree_reopen(a->tree, pathname,
+		    a->flags & ARCHIVE_READDISK_RESTORE_ATIME);
 	else
-		a->tree = tree_open(pathname, a->symlink_mode, a->restore_time);
+		a->tree = tree_open(pathname, a->symlink_mode,
+		    a->flags & ARCHIVE_READDISK_RESTORE_ATIME);
 	if (a->tree == NULL) {
 		archive_set_error(&a->archive, ENOMEM,
 		    "Can't allocate directory traversal data");
@@ -1519,7 +1509,7 @@
 	struct archive_wstring ws;
 	wchar_t *pathname, *p, *base;
 
-	t->flags = (restore_time)?needsRestoreTimes:0;
+	t->flags = (restore_time != 0)?needsRestoreTimes:0;
 	t->visit_type = 0;
 	t->tree_errno = 0;
 	t->full_path_dir_length = 0;
diff --git a/libarchive/archive_write_disk_posix.c b/libarchive/archive_write_disk_posix.c
index 20450ba..5a01e84 100644
--- a/libarchive/archive_write_disk_posix.c
+++ b/libarchive/archive_write_disk_posix.c
@@ -1712,7 +1712,8 @@
 		const void *metadata;
 		size_t metadata_size;
 		metadata = archive_entry_mac_metadata(a->entry, &metadata_size);
-		if (metadata == NULL || metadata_size == 0) {
+		if ((a->todo & TODO_MAC_METADATA) == 0 ||
+		    metadata == NULL || metadata_size == 0) {
 #endif
 		r2 = archive_write_disk_set_acls(&a->archive, a->fd,
 		    archive_entry_pathname(a->entry),
@@ -2293,7 +2294,8 @@
 			chmod(p->name, p->mode);
 		if (p->fixup & TODO_ACLS)
 #ifdef HAVE_DARWIN_ACL
-			if (p->mac_metadata == NULL ||
+			if ((p->fixup & TODO_MAC_METADATA) == 0 ||
+			    p->mac_metadata == NULL ||
 			    p->mac_metadata_size == 0)
 #endif
 				archive_write_disk_set_acls(&a->archive,
@@ -3465,12 +3467,19 @@
 #ifdef UF_APPEND
 	critical_flags |= UF_APPEND;
 #endif
-#ifdef EXT2_APPEND_FL
+#if defined(FS_APPEND_FL)
+	critical_flags |= FS_APPEND_FL;
+#elif defined(EXT2_APPEND_FL)
 	critical_flags |= EXT2_APPEND_FL;
 #endif
-#ifdef EXT2_IMMUTABLE_FL
+#if defined(FS_IMMUTABLE_FL)
+	critical_flags |= FS_IMMUTABLE_FL;
+#elif defined(EXT2_IMMUTABLE_FL)
 	critical_flags |= EXT2_IMMUTABLE_FL;
 #endif
+#ifdef FS_JOURNAL_DATA_FL
+	critical_flags |= FS_JOURNAL_DATA_FL;
+#endif
 
 	if (a->todo & TODO_FFLAGS) {
 		archive_entry_fflags(a->entry, &set, &clear);
@@ -3582,7 +3591,10 @@
 	return (ARCHIVE_WARN);
 }
 
-#elif defined(EXT2_IOC_GETFLAGS) && defined(EXT2_IOC_SETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)
+#elif (defined(FS_IOC_GETFLAGS) && defined(FS_IOC_SETFLAGS) && \
+       defined(HAVE_WORKING_FS_IOC_GETFLAGS)) || \
+      (defined(EXT2_IOC_GETFLAGS) && defined(EXT2_IOC_SETFLAGS) && \
+       defined(HAVE_WORKING_EXT2_IOC_GETFLAGS))
 /*
  * Linux uses ioctl() to read and write file flags.
  */
@@ -3595,7 +3607,7 @@
 	int newflags, oldflags;
 	int sf_mask = 0;
 
-	if (set == 0  && clear == 0)
+	if (set == 0 && clear == 0)
 		return (ARCHIVE_OK);
 	/* Only regular files and dirs can have flags. */
 	if (!S_ISREG(mode) && !S_ISDIR(mode))
@@ -3616,12 +3628,19 @@
 	 * defines. (?)  The code below degrades reasonably gracefully
 	 * if sf_mask is incomplete.
 	 */
-#ifdef EXT2_IMMUTABLE_FL
+#if defined(FS_IMMUTABLE_FL)
+	sf_mask |= FS_IMMUTABLE_FL;
+#elif defined(EXT2_IMMUTABLE_FL)
 	sf_mask |= EXT2_IMMUTABLE_FL;
 #endif
-#ifdef EXT2_APPEND_FL
+#if defined(FS_APPEND_FL)
+	sf_mask |= FS_APPEND_FL;
+#elif defined(EXT2_APPEND_FL)
 	sf_mask |= EXT2_APPEND_FL;
 #endif
+#if defined(FS_JOURNAL_DATA_FL)
+	sf_mask |= FS_JOURNAL_DATA_FL;
+#endif
 	/*
 	 * XXX As above, this would be way simpler if we didn't have
 	 * to read the current flags from disk. XXX
@@ -3629,12 +3648,24 @@
 	ret = ARCHIVE_OK;
 
 	/* Read the current file flags. */
-	if (ioctl(myfd, EXT2_IOC_GETFLAGS, &oldflags) < 0)
+	if (ioctl(myfd,
+#ifdef FS_IOC_GETFLAGS
+	    FS_IOC_GETFLAGS,
+#else
+	    EXT2_IOC_GETFLAGS,
+#endif
+	    &oldflags) < 0)
 		goto fail;
 
 	/* Try setting the flags as given. */
 	newflags = (oldflags & ~clear) | set;
-	if (ioctl(myfd, EXT2_IOC_SETFLAGS, &newflags) >= 0)
+	if (ioctl(myfd,
+#ifdef FS_IOC_SETFLAGS
+	    FS_IOC_SETFLAGS,
+#else
+	    EXT2_IOC_SETFLAGS,
+#endif
+	    &newflags) >= 0)
 		goto cleanup;
 	if (errno != EPERM)
 		goto fail;
@@ -3643,7 +3674,13 @@
 	newflags &= ~sf_mask;
 	oldflags &= sf_mask;
 	newflags |= oldflags;
-	if (ioctl(myfd, EXT2_IOC_SETFLAGS, &newflags) >= 0)
+	if (ioctl(myfd,
+#ifdef FS_IOC_SETFLAGS
+	    FS_IOC_SETFLAGS,
+#else
+	    EXT2_IOC_SETFLAGS,
+#endif
+	    &newflags) >= 0)
 		goto cleanup;
 
 	/* We couldn't set the flags, so report the failure. */
diff --git a/libarchive/archive_write_set_format_iso9660.c b/libarchive/archive_write_set_format_iso9660.c
index 4e91097..c0ca435 100644
--- a/libarchive/archive_write_set_format_iso9660.c
+++ b/libarchive/archive_write_set_format_iso9660.c
@@ -4074,8 +4074,10 @@
 	memset(info.s, 0, info_size);
 	opt = 0;
 #if defined(HAVE__CTIME64_S)
-	__time64_t iso9660_birth_time_tmp = (__time64_t) iso9660->birth_time; //time_t may be shorter than 64 bits
-	_ctime64_s(buf, sizeof(buf), &(iso9660_birth_time_tmp));
+	{
+		__time64_t iso9660_birth_time_tmp = (__time64_t) iso9660->birth_time; //time_t may be shorter than 64 bits
+		_ctime64_s(buf, sizeof(buf), &(iso9660_birth_time_tmp));
+	}
 #elif defined(HAVE_CTIME_R)
 	ctime_r(&(iso9660->birth_time), buf);
 #else
diff --git a/libarchive/test/CMakeLists.txt b/libarchive/test/CMakeLists.txt
index 6c4ac23..5016eed 100644
--- a/libarchive/test/CMakeLists.txt
+++ b/libarchive/test/CMakeLists.txt
@@ -6,7 +6,7 @@
 IF(ENABLE_TEST)
   SET(libarchive_test_SOURCES
     ../../test_utils/test_utils.c
-    main.c
+    ../../test_utils/test_main.c
     read_open_memory.c
     test.h
     test_acl_nfs4.c
@@ -303,6 +303,7 @@
   INCLUDE(${CMAKE_CURRENT_BINARY_DIR}/list.h)
   INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
   INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/test_utils)
+  INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/libarchive/test)
 
   # Experimental new test handling
   ADD_CUSTOM_TARGET(run_libarchive_test
diff --git a/libarchive/test/test.h b/libarchive/test/test.h
index 58df1cb..fd679f5 100644
--- a/libarchive/test/test.h
+++ b/libarchive/test/test.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2006 Tim Kientzle
+ * Copyright (c) 2003-2017 Tim Kientzle
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -21,388 +21,16 @@
  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * $FreeBSD: head/lib/libarchive/test/test.h 201247 2009-12-30 05:59:21Z kientzle $
  */
 
 /* Every test program should #include "test.h" as the first thing. */
 
-/*
- * The goal of this file (and the matching test.c) is to
- * simplify the very repetitive test-*.c test programs.
- */
-#if defined(HAVE_CONFIG_H)
-/* Most POSIX platforms use the 'configure' script to build config.h */
-#include "config.h"
-#elif defined(__FreeBSD__)
-/* Building as part of FreeBSD system requires a pre-built config.h. */
-#include "config_freebsd.h"
-#elif defined(_WIN32) && !defined(__CYGWIN__)
-/* Win32 can't run the 'configure' script. */
-#include "config_windows.h"
-#else
-/* Warn if the library hasn't been (automatically or manually) configured. */
-#error Oops: No config.h and no pre-built configuration in test.h.
-#endif
+#define KNOWNREF	"test_compat_gtar_1.tar.uu"
+#define	ENVBASE "LIBARCHIVE" /* Prefix for environment variables. */
+#undef	PROGRAM              /* Testing a library, not a program. */
+#define	LIBRARY	"libarchive"
+#define	EXTRA_DUMP(x)	archive_error_string((struct archive *)(x))
+#define	EXTRA_ERRNO(x)	archive_errno((struct archive *)(x))
+#define	EXTRA_VERSION	archive_version_details()
 
-#include <sys/types.h>  /* Windows requires this before sys/stat.h */
-#include <sys/stat.h>
-
-#if HAVE_DIRENT_H
-#include <dirent.h>
-#endif
-#ifdef HAVE_DIRECT_H
-#include <direct.h>
-#define dirent direct
-#endif
-#include <errno.h>
-#include <fcntl.h>
-#ifdef HAVE_IO_H
-#include <io.h>
-#endif
-#ifdef HAVE_STDINT_H
-#include <stdint.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <time.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <wchar.h>
-#ifdef HAVE_WINDOWS_H
-#include <windows.h>
-#endif
-
-/*
- * System-specific tweaks.  We really want to minimize these
- * as much as possible, since they make it harder to understand
- * the mainline code.
- */
-
-/* Windows (including Visual Studio and MinGW but not Cygwin) */
-#if defined(_WIN32) && !defined(__CYGWIN__)
-#if !defined(__BORLANDC__)
-#undef chdir
-#define chdir _chdir
-#define strdup _strdup
-#endif
-#endif
-
-/* Visual Studio */
-#if defined(_MSC_VER) && _MSC_VER < 1900
-#define snprintf	sprintf_s
-#endif
-
-#if defined(__BORLANDC__)
-#pragma warn -8068	/* Constant out of range in comparison. */
-#endif
-
-/* Haiku OS and QNX */
-#if defined(__HAIKU__) || defined(__QNXNTO__)
-/* Haiku and QNX have typedefs in stdint.h (needed for int64_t) */
-#include <stdint.h>
-#endif
-
-/* Get a real definition for __FBSDID if we can */
-#if HAVE_SYS_CDEFS_H
-#include <sys/cdefs.h>
-#endif
-
-/* If not, define it so as to avoid dangling semicolons. */
-#ifndef __FBSDID
-#define	__FBSDID(a)     struct _undefined_hack
-#endif
-
-#ifndef O_BINARY
-#define	O_BINARY 0
-#endif
-
-/*
- * If this platform has <sys/acl.h>, acl_create(), acl_init(),
- * acl_set_file(), and ACL_USER, we assume it has the rest of the
- * POSIX.1e draft functions used in archive_read_extract.c.
- */
-#if HAVE_SYS_ACL_H && HAVE_ACL_CREATE_ENTRY && HAVE_ACL_INIT && HAVE_ACL_SET_FILE
-#if HAVE_ACL_USER
-#define	HAVE_POSIX_ACL	1
-#elif HAVE_ACL_TYPE_EXTENDED
-#define	HAVE_DARWIN_ACL	1
-#endif
-#endif
-
-/*
- * If this platform has <sys/acl.h>, acl_get(), facl_get(), acl_set(),
- * facl_set() and types aclent_t and ace_t it uses Solaris-style ACL functions
- */
-#if HAVE_SYS_ACL_H && HAVE_ACL_GET && HAVE_FACL_GET && HAVE_ACL_SET && HAVE_FACL_SET && HAVE_ACLENT_T && HAVE_ACE_T
-#define	HAVE_SUN_ACL	1
-#endif
-
-/* Define if platform supports NFSv4 ACLs */
-#if (HAVE_POSIX_ACL && HAVE_ACL_TYPE_NFS4) || HAVE_SUN_ACL || HAVE_DARWIN_ACL
-#define	HAVE_NFS4_ACL	1
-#endif
-
-/*
- * Redefine DEFINE_TEST for use in defining the test functions.
- */
-#undef DEFINE_TEST
-#define DEFINE_TEST(name) void name(void); void name(void)
-
-/* An implementation of the standard assert() macro */
-#define assert(e)   assertion_assert(__FILE__, __LINE__, (e), #e, NULL)
-/* chdir() and error if it fails */
-#define assertChdir(path)  \
-  assertion_chdir(__FILE__, __LINE__, path)
-/* Assert two integers are the same.  Reports value of each one if not. */
-#define assertEqualInt(v1,v2) \
-  assertion_equal_int(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL)
-/* Assert two strings are the same.  Reports value of each one if not. */
-#define assertEqualString(v1,v2)   \
-  assertion_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL, 0)
-#define assertEqualUTF8String(v1,v2)   \
-  assertion_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL, 1)
-/* As above, but v1 and v2 are wchar_t * */
-#define assertEqualWString(v1,v2)   \
-  assertion_equal_wstring(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL)
-/* As above, but raw blocks of bytes. */
-#define assertEqualMem(v1, v2, l)	\
-  assertion_equal_mem(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (l), #l, NULL)
-/* Assert that memory is full of a specified byte */
-#define assertMemoryFilledWith(v1, l, b)					\
-  assertion_memory_filled_with(__FILE__, __LINE__, (v1), #v1, (l), #l, (b), #b, NULL)
-/* Assert two files are the same. */
-#define assertEqualFile(f1, f2)	\
-  assertion_equal_file(__FILE__, __LINE__, (f1), (f2))
-/* Assert that a file is empty. */
-#define assertEmptyFile(pathname)	\
-  assertion_empty_file(__FILE__, __LINE__, (pathname))
-/* Assert that a file is not empty. */
-#define assertNonEmptyFile(pathname)		\
-  assertion_non_empty_file(__FILE__, __LINE__, (pathname))
-#define assertFileAtime(pathname, sec, nsec)	\
-  assertion_file_atime(__FILE__, __LINE__, pathname, sec, nsec)
-#define assertFileAtimeRecent(pathname)	\
-  assertion_file_atime_recent(__FILE__, __LINE__, pathname)
-#define assertFileBirthtime(pathname, sec, nsec)	\
-  assertion_file_birthtime(__FILE__, __LINE__, pathname, sec, nsec)
-#define assertFileBirthtimeRecent(pathname) \
-  assertion_file_birthtime_recent(__FILE__, __LINE__, pathname)
-/* Assert that a file exists; supports printf-style arguments. */
-#define assertFileExists(pathname) \
-  assertion_file_exists(__FILE__, __LINE__, pathname)
-/* Assert that a file exists. */
-#define assertFileNotExists(pathname) \
-  assertion_file_not_exists(__FILE__, __LINE__, pathname)
-/* Assert that file contents match a string. */
-#define assertFileContents(data, data_size, pathname) \
-  assertion_file_contents(__FILE__, __LINE__, data, data_size, pathname)
-/* Verify that a file does not contain invalid strings */
-#define assertFileContainsNoInvalidStrings(pathname, strings) \
-  assertion_file_contains_no_invalid_strings(__FILE__, __LINE__, pathname, strings)
-#define assertFileMtime(pathname, sec, nsec)	\
-  assertion_file_mtime(__FILE__, __LINE__, pathname, sec, nsec)
-#define assertFileMtimeRecent(pathname) \
-  assertion_file_mtime_recent(__FILE__, __LINE__, pathname)
-#define assertFileNLinks(pathname, nlinks)  \
-  assertion_file_nlinks(__FILE__, __LINE__, pathname, nlinks)
-#define assertFileSize(pathname, size)  \
-  assertion_file_size(__FILE__, __LINE__, pathname, size)
-#define assertFileMode(pathname, mode)  \
-  assertion_file_mode(__FILE__, __LINE__, pathname, mode)
-#define assertTextFileContents(text, pathname) \
-  assertion_text_file_contents(__FILE__, __LINE__, text, pathname)
-#define assertFileContainsLinesAnyOrder(pathname, lines)	\
-  assertion_file_contains_lines_any_order(__FILE__, __LINE__, pathname, lines)
-#define assertIsDir(pathname, mode)		\
-  assertion_is_dir(__FILE__, __LINE__, pathname, mode)
-#define assertIsHardlink(path1, path2)	\
-  assertion_is_hardlink(__FILE__, __LINE__, path1, path2)
-#define assertIsNotHardlink(path1, path2)	\
-  assertion_is_not_hardlink(__FILE__, __LINE__, path1, path2)
-#define assertIsReg(pathname, mode)		\
-  assertion_is_reg(__FILE__, __LINE__, pathname, mode)
-#define assertIsSymlink(pathname, contents)	\
-  assertion_is_symlink(__FILE__, __LINE__, pathname, contents)
-/* Create a directory, report error if it fails. */
-#define assertMakeDir(dirname, mode)	\
-  assertion_make_dir(__FILE__, __LINE__, dirname, mode)
-#define assertMakeFile(path, mode, contents) \
-  assertion_make_file(__FILE__, __LINE__, path, mode, -1, contents)
-#define assertMakeBinFile(path, mode, csize, contents) \
-  assertion_make_file(__FILE__, __LINE__, path, mode, csize, contents)
-#define assertMakeHardlink(newfile, oldfile)	\
-  assertion_make_hardlink(__FILE__, __LINE__, newfile, oldfile)
-#define assertMakeSymlink(newfile, linkto)	\
-  assertion_make_symlink(__FILE__, __LINE__, newfile, linkto)
-#define assertNodump(path)      \
-  assertion_nodump(__FILE__, __LINE__, path)
-#define assertUmask(mask)	\
-  assertion_umask(__FILE__, __LINE__, mask)
-#define assertUtimes(pathname, atime, atime_nsec, mtime, mtime_nsec)	\
-  assertion_utimes(__FILE__, __LINE__, pathname, atime, atime_nsec, mtime, mtime_nsec)
-
-/*
- * This would be simple with C99 variadic macros, but I don't want to
- * require that.  Instead, I insert a function call before each
- * skipping() call to pass the file and line information down.  Crude,
- * but effective.
- */
-#define skipping	\
-  skipping_setup(__FILE__, __LINE__);test_skipping
-
-/* Function declarations.  These are defined in test_utility.c. */
-void failure(const char *fmt, ...);
-int assertion_assert(const char *, int, int, const char *, void *);
-int assertion_chdir(const char *, int, const char *);
-int assertion_empty_file(const char *, int, const char *);
-int assertion_equal_file(const char *, int, const char *, const char *);
-int assertion_equal_int(const char *, int, long long, const char *, long long, const char *, void *);
-int assertion_equal_mem(const char *, int, const void *, const char *, const void *, const char *, size_t, const char *, void *);
-int assertion_memory_filled_with(const char *, int, const void *, const char *, size_t, const char *, char, const char *, void *);
-int assertion_equal_string(const char *, int, const char *v1, const char *, const char *v2, const char *, void *, int);
-int assertion_equal_wstring(const char *, int, const wchar_t *v1, const char *, const wchar_t *v2, const char *, void *);
-int assertion_file_atime(const char *, int, const char *, long, long);
-int assertion_file_atime_recent(const char *, int, const char *);
-int assertion_file_birthtime(const char *, int, const char *, long, long);
-int assertion_file_birthtime_recent(const char *, int, const char *);
-int assertion_file_contains_lines_any_order(const char *, int, const char *, const char **);
-int assertion_file_contains_no_invalid_strings(const char *, int, const char *, const char **);
-int assertion_file_contents(const char *, int, const void *, int, const char *);
-int assertion_file_exists(const char *, int, const char *);
-int assertion_file_mode(const char *, int, const char *, int);
-int assertion_file_mtime(const char *, int, const char *, long, long);
-int assertion_file_mtime_recent(const char *, int, const char *);
-int assertion_file_nlinks(const char *, int, const char *, int);
-int assertion_file_not_exists(const char *, int, const char *);
-int assertion_file_size(const char *, int, const char *, long);
-int assertion_is_dir(const char *, int, const char *, int);
-int assertion_is_hardlink(const char *, int, const char *, const char *);
-int assertion_is_not_hardlink(const char *, int, const char *, const char *);
-int assertion_is_reg(const char *, int, const char *, int);
-int assertion_is_symlink(const char *, int, const char *, const char *);
-int assertion_make_dir(const char *, int, const char *, int);
-int assertion_make_file(const char *, int, const char *, int, int, const void *);
-int assertion_make_hardlink(const char *, int, const char *newpath, const char *);
-int assertion_make_symlink(const char *, int, const char *newpath, const char *);
-int assertion_nodump(const char *, int, const char *);
-int assertion_non_empty_file(const char *, int, const char *);
-int assertion_text_file_contents(const char *, int, const char *buff, const char *f);
-int assertion_umask(const char *, int, int);
-int assertion_utimes(const char *, int, const char *, long, long, long, long );
-
-void skipping_setup(const char *, int);
-void test_skipping(const char *fmt, ...);
-
-/* Like sprintf, then system() */
-int systemf(const char * fmt, ...);
-
-/* Delay until time() returns a value after this. */
-void sleepUntilAfter(time_t);
-
-/* Return true if this platform can create symlinks. */
-int canSymlink(void);
-
-/* Return true if this platform can run the "bzip2" program. */
-int canBzip2(void);
-
-/* Return true if this platform can run the "grzip" program. */
-int canGrzip(void);
-
-/* Return true if this platform can run the "gzip" program. */
-int canGzip(void);
-
-/* Return true if this platform can run the specified command. */
-int canRunCommand(const char *);
-
-/* Return true if this platform can run the "lrzip" program. */
-int canLrzip(void);
-
-/* Return true if this platform can run the "lz4" program. */
-int canLz4(void);
-
-/* Return true if this platform can run the "lzip" program. */
-int canLzip(void);
-
-/* Return true if this platform can run the "lzma" program. */
-int canLzma(void);
-
-/* Return true if this platform can run the "lzop" program. */
-int canLzop(void);
-
-/* Return true if this platform can run the "xz" program. */
-int canXz(void);
-
-/* Return true if this filesystem can handle nodump flags. */
-int canNodump(void);
-
-/* Return true if the file has large i-node number(>0xffffffff). */
-int is_LargeInode(const char *);
-
-/* Suck file into string allocated via malloc(). Call free() when done. */
-/* Supports printf-style args: slurpfile(NULL, "%s/myfile", refdir); */
-char *slurpfile(size_t *, const char *fmt, ...);
-
-/* Dump block of bytes to a file. */
-void dumpfile(const char *filename, void *, size_t);
-
-/* Extracts named reference file to the current directory. */
-void extract_reference_file(const char *);
-/* Copies named reference file to the current directory. */
-void copy_reference_file(const char *);
-
-/* Extracts a list of files to the current directory.
- * List must be NULL terminated.
- */
-void extract_reference_files(const char **);
-
-/* Subtract umask from mode */
-mode_t umasked(mode_t expected_mode);
-
-/* Path to working directory for current test */
-extern const char *testworkdir;
-
-/*
- * Special interfaces for libarchive test harness.
- */
-
-#include "archive.h"
-#include "archive_entry.h"
-
-/* ACL structure */
-struct archive_test_acl_t {
-	int type;  /* Type of ACL */
-	int permset; /* Permissions for this class of users. */
-	int tag; /* Owner, User, Owning group, group, other, etc. */
-	int qual; /* GID or UID of user/group, depending on tag. */
-	const char *name; /* Name of user/group, depending on tag. */
-};
-
-/* Set ACLs */
-void archive_test_set_acls(struct archive_entry *, struct archive_test_acl_t *,
-    int);
-
-/* Compare ACLs */
-void archive_test_compare_acls(struct archive_entry *,
-    struct archive_test_acl_t *, int, int, int);
-
-/* Special customized read-from-memory interface. */
-int read_open_memory(struct archive *, const void *, size_t, size_t);
-/* _minimal version exercises a slightly different set of libarchive APIs. */
-int read_open_memory_minimal(struct archive *, const void *, size_t, size_t);
-/* _seek version produces a seekable file. */
-int read_open_memory_seek(struct archive *, const void *, size_t, size_t);
-
-/* Versions of above that accept an archive argument for additional info. */
-#define assertA(e)   assertion_assert(__FILE__, __LINE__, (e), #e, (a))
-#define assertEqualIntA(a,v1,v2)   \
-  assertion_equal_int(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (a))
-#define assertEqualStringA(a,v1,v2)   \
-  assertion_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (a), 0)
-
-#ifdef USE_DMALLOC
-#include <dmalloc.h>
-#endif
+#include "test_common.h"
diff --git a/libarchive/test/test_acl_nfs4.c b/libarchive/test/test_acl_nfs4.c
index f4e66f5..fdc0191 100644
--- a/libarchive/test/test_acl_nfs4.c
+++ b/libarchive/test/test_acl_nfs4.c
@@ -159,7 +159,7 @@
         archive_entry_set_mode(ae, S_IFREG | 0777);
 
 	/* Store and read back some basic ACL entries. */
-	archive_test_set_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]));
+	assertEntrySetAcls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]));
 
 	/* Check that entry contains only NFSv4 types */
 	assert((archive_entry_acl_types(ae) &
@@ -169,21 +169,21 @@
 
 	assertEqualInt(4,
 	    archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4));
-	archive_test_compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]),
+	assertEntryCompareAcls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_NFS4, 0);
 
 	/* A more extensive set of ACLs. */
-	archive_test_set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]));
+	assertEntrySetAcls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]));
 	assertEqualInt(32,
 	    archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4));
-	archive_test_compare_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]),
+	assertEntryCompareAcls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_NFS4, 0);
 
 	/*
 	 * Check that clearing ACLs gets rid of them all by repeating
 	 * the first test.
 	 */
-	archive_test_set_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]));
+	assertEntrySetAcls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]));
 	failure("Basic ACLs shouldn't be stored as extended ACLs");
 	assertEqualInt(4,
 	    archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4));
@@ -192,7 +192,7 @@
 	 * Different types of malformed ACL entries that should
 	 * fail when added to existing NFS4 ACLs.
 	 */
-	archive_test_set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]));
+	assertEntrySetAcls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]));
 	for (i = 0; i < (int)(sizeof(acls_bad)/sizeof(acls_bad[0])); ++i) {
 		struct archive_test_acl_t *p = &acls_bad[i];
 		failure("Malformed ACL test #%d", i);
diff --git a/libarchive/test/test_acl_pax.c b/libarchive/test/test_acl_pax.c
index 8dfa0e0..8566f55 100644
--- a/libarchive/test/test_acl_pax.c
+++ b/libarchive/test/test_acl_pax.c
@@ -238,23 +238,22 @@
         archive_entry_set_mode(ae, S_IFREG | 0777);
 
 	/* Basic owner/owning group should just update mode bits. */
-	archive_test_set_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]));
+	assertEntrySetAcls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]));
 	assertA(0 == archive_write_header(a, ae));
 
 	/* With any extended ACL entry, we should read back a full set. */
-	archive_test_set_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]));
+	assertEntrySetAcls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]));
 	assertA(0 == archive_write_header(a, ae));
 
-
 	/* A more extensive set of ACLs. */
-	archive_test_set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]));
+	assertEntrySetAcls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]));
 	assertA(0 == archive_write_header(a, ae));
 
 	/*
 	 * Check that clearing ACLs gets rid of them all by repeating
 	 * the first test.
 	 */
-	archive_test_set_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]));
+	assertEntrySetAcls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]));
 	assertA(0 == archive_write_header(a, ae));
 	archive_entry_free(ae);
 
@@ -296,7 +295,7 @@
 	assertA(0 == archive_read_next_header(a, &ae));
 	failure("One extended ACL should flag all ACLs to be returned.");
 	assert(4 == archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
-	archive_test_compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]),
+	assertEntryCompareAcls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0142);
 	failure("Basic ACLs should set mode to 0142, not %04o",
 	    archive_entry_mode(ae)&0777);
@@ -306,7 +305,7 @@
 	assertA(0 == archive_read_next_header(a, &ae));
 	assertEqualInt(6, archive_entry_acl_reset(ae,
 	    ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
-	archive_test_compare_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]),
+	assertEntryCompareAcls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0543);
 	failure("Basic ACLs should set mode to 0543, not %04o",
 	    archive_entry_mode(ae)&0777);
@@ -350,15 +349,15 @@
         archive_entry_set_mode(ae, S_IFREG | 0777);
 
 	/* NFS4 ACLs mirroring 0754 file mode */
-	archive_test_set_acls(ae, acls3, sizeof(acls3)/sizeof(acls3[0]));
+	assertEntrySetAcls(ae, acls3, sizeof(acls3)/sizeof(acls3[0]));
 	assertA(0 == archive_write_header(a, ae));
 
 	/* A more extensive set of NFS4 ACLs. */
-	archive_test_set_acls(ae, acls4, sizeof(acls4)/sizeof(acls4[0]));
+	assertEntrySetAcls(ae, acls4, sizeof(acls4)/sizeof(acls4[0]));
 	assertA(0 == archive_write_header(a, ae));
 
 	/* Set with special (audit, alarm) NFS4 ACLs. */
-	archive_test_set_acls(ae, acls5, sizeof(acls5)/sizeof(acls5[0]));
+	assertEntrySetAcls(ae, acls5, sizeof(acls5)/sizeof(acls5[0]));
 	assertA(0 == archive_write_header(a, ae));
 
 	archive_entry_free(ae);
@@ -393,21 +392,21 @@
 	assertA(0 == archive_read_next_header(a, &ae));
 	assertEqualInt(3, archive_entry_acl_reset(ae,
 	    ARCHIVE_ENTRY_ACL_TYPE_ALLOW));
-	archive_test_compare_acls(ae, acls3, sizeof(acls3)/sizeof(acls3[0]),
+	assertEntryCompareAcls(ae, acls3, sizeof(acls3)/sizeof(acls3[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_ALLOW, 0);
 
 	/* Second item has has more fine-grained NFS4 ACLs */
 	assertA(0 == archive_read_next_header(a, &ae));
 	assertEqualInt(6, archive_entry_acl_reset(ae,
 	    ARCHIVE_ENTRY_ACL_TYPE_NFS4));
-	archive_test_compare_acls(ae, acls4, sizeof(acls4)/sizeof(acls4[0]),
+	assertEntryCompareAcls(ae, acls4, sizeof(acls4)/sizeof(acls4[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_NFS4, 0);
 
 	/* Third item has has audit and alarm NFS4 ACLs */
 	assertA(0 == archive_read_next_header(a, &ae));
 	assertEqualInt(6, archive_entry_acl_reset(ae,
 	    ARCHIVE_ENTRY_ACL_TYPE_NFS4));
-	archive_test_compare_acls(ae, acls5, sizeof(acls5)/sizeof(acls5[0]),
+	assertEntryCompareAcls(ae, acls5, sizeof(acls5)/sizeof(acls5[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_NFS4, 0);
 
 	/* Close the archive. */
diff --git a/libarchive/test/test_acl_platform_posix1e.c b/libarchive/test/test_acl_platform_posix1e.c
index 5d1732a..b46f658 100644
--- a/libarchive/test/test_acl_platform_posix1e.c
+++ b/libarchive/test/test_acl_platform_posix1e.c
@@ -393,7 +393,7 @@
 	archive_entry_set_pathname(ae, "test0");
 	archive_entry_set_mtime(ae, 123456, 7890);
 	archive_entry_set_size(ae, 0);
-	archive_test_set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]));
+	assertEntrySetAcls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]));
 	assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
 	archive_entry_free(ae);
 
diff --git a/libarchive/test/test_acl_posix1e.c b/libarchive/test/test_acl_posix1e.c
index 01167da..fa2628d 100644
--- a/libarchive/test/test_acl_posix1e.c
+++ b/libarchive/test/test_acl_posix1e.c
@@ -116,16 +116,15 @@
 	 * triggering unnecessary extensions.  It's better to identify
 	 * trivial ACLs at the point they are being read from disk.
 	 */
-	archive_test_set_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]));
+	assertEntrySetAcls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]));
 	failure("Basic ACLs shouldn't be stored as extended ACLs");
 	assert(0 == archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
 	failure("Basic ACLs should set mode to 0142, not %04o",
 	    archive_entry_mode(ae)&0777);
 	assert((archive_entry_mode(ae) & 0777) == 0142);
 
-
 	/* With any extended ACL entry, we should read back a full set. */
-	archive_test_set_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]));
+	assertEntrySetAcls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]));
 	failure("One extended ACL should flag all ACLs to be returned.");
 
 	/* Check that entry contains only POSIX.1e types */
@@ -135,7 +134,7 @@
 	    ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0);
 
 	assert(4 == archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
-	archive_test_compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]),
+	assertEntryCompareAcls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0142);
 	failure("Basic ACLs should set mode to 0142, not %04o",
 	    archive_entry_mode(ae)&0777);
@@ -143,9 +142,9 @@
 
 
 	/* A more extensive set of ACLs. */
-	archive_test_set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]));
+	assertEntrySetAcls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]));
 	assertEqualInt(6, archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
-	archive_test_compare_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]),
+	assertEntryCompareAcls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0543);
 	failure("Basic ACLs should set mode to 0543, not %04o",
 	    archive_entry_mode(ae)&0777);
@@ -155,7 +154,7 @@
 	 * Check that clearing ACLs gets rid of them all by repeating
 	 * the first test.
 	 */
-	archive_test_set_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]));
+	assertEntrySetAcls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]));
 	failure("Basic ACLs shouldn't be stored as extended ACLs");
 	assert(0 == archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
 	failure("Basic ACLs should set mode to 0142, not %04o",
@@ -166,7 +165,7 @@
 	 * Different types of malformed ACL entries that should
 	 * fail when added to existing POSIX.1e ACLs.
 	 */
-	archive_test_set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]));
+	assertEntrySetAcls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]));
 	for (i = 0; i < (int)(sizeof(acls_nfs4)/sizeof(acls_nfs4[0])); ++i) {
 		struct archive_test_acl_t *p = &acls_nfs4[i];
 		failure("Malformed ACL test #%d", i);
diff --git a/libarchive/test/test_acl_text.c b/libarchive/test/test_acl_text.c
index f3d2b10..8072893 100644
--- a/libarchive/test/test_acl_text.c
+++ b/libarchive/test/test_acl_text.c
@@ -282,7 +282,7 @@
 	assertEqualInt(ARCHIVE_OK,
 	    archive_entry_acl_from_text(ae, acltext[5],
 	    ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
-	archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
+	assertEntryCompareAcls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0755);
 	assertEqualInt(6, archive_entry_acl_reset(ae,
 	    ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
@@ -291,7 +291,7 @@
 	assertEqualInt(ARCHIVE_OK,
 	    archive_entry_acl_from_text(ae, acltext[7],
 	    ARCHIVE_ENTRY_ACL_TYPE_DEFAULT));
-	archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
+	assertEntryCompareAcls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, 0755);
 	assertEqualInt(11, archive_entry_acl_reset(ae,
 	    ARCHIVE_ENTRY_ACL_TYPE_POSIX1E));
@@ -303,7 +303,7 @@
 	assertEqualInt(ARCHIVE_OK,
 	    archive_entry_acl_from_text_w(ae, ws,
 	    ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
-	archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
+	assertEntryCompareAcls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0755);
 	assertEqualInt(6, archive_entry_acl_reset(ae,
 	    ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
@@ -314,7 +314,7 @@
 	assertEqualInt(ARCHIVE_OK,
 	    archive_entry_acl_from_text_w(ae, ws,
 	    ARCHIVE_ENTRY_ACL_TYPE_DEFAULT));
-	archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
+	assertEntryCompareAcls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, 0755);
 	assertEqualInt(11, archive_entry_acl_reset(ae,
 	    ARCHIVE_ENTRY_ACL_TYPE_POSIX1E));
@@ -324,7 +324,7 @@
 	assertEqualInt(ARCHIVE_OK,
 	    archive_entry_acl_from_text(ae, acltext[7],
 	    ARCHIVE_ENTRY_ACL_TYPE_DEFAULT));
-	archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
+	assertEntryCompareAcls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, 0);
 	assertEqualInt(5, archive_entry_acl_reset(ae,
 	    ARCHIVE_ENTRY_ACL_TYPE_DEFAULT));
@@ -334,7 +334,7 @@
 	assertEqualInt(ARCHIVE_OK,
 	    archive_entry_acl_from_text_w(ae, ws,
 	    ARCHIVE_ENTRY_ACL_TYPE_DEFAULT));
-	archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
+	assertEntryCompareAcls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, 0);
 	assertEqualInt(5, archive_entry_acl_reset(ae,
 	    ARCHIVE_ENTRY_ACL_TYPE_DEFAULT));
@@ -344,7 +344,7 @@
 	assertEqualInt(ARCHIVE_OK,
 	    archive_entry_acl_from_text(ae, acltext[1],
 	    ARCHIVE_ENTRY_ACL_TYPE_POSIX1E));
-	archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
+	assertEntryCompareAcls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, 0755);
 	assertEqualInt(11, archive_entry_acl_reset(ae,
 	    ARCHIVE_ENTRY_ACL_TYPE_POSIX1E));
@@ -355,7 +355,7 @@
 	assertEqualInt(ARCHIVE_OK,
 	    archive_entry_acl_from_text_w(ae, ws,
 	    ARCHIVE_ENTRY_ACL_TYPE_POSIX1E));
-	archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
+	assertEntryCompareAcls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, 0755);
 	assertEqualInt(11, archive_entry_acl_reset(ae,
 	    ARCHIVE_ENTRY_ACL_TYPE_POSIX1E));
@@ -365,7 +365,7 @@
 	assertEqualInt(ARCHIVE_OK,
 	    archive_entry_acl_from_text(ae, acltext[2],
 	    ARCHIVE_ENTRY_ACL_TYPE_POSIX1E));
-	archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
+	assertEntryCompareAcls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, 0755);
 	assertEqualInt(11, archive_entry_acl_reset(ae,
 	    ARCHIVE_ENTRY_ACL_TYPE_POSIX1E));
@@ -376,7 +376,7 @@
 	assertEqualInt(ARCHIVE_OK,
 	    archive_entry_acl_from_text_w(ae, ws,
 	    ARCHIVE_ENTRY_ACL_TYPE_POSIX1E));
-	archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
+	assertEntryCompareAcls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, 0755);
 	assertEqualInt(11, archive_entry_acl_reset(ae,
 	    ARCHIVE_ENTRY_ACL_TYPE_POSIX1E));
@@ -386,7 +386,7 @@
 	assertEqualInt(ARCHIVE_OK,
 	    archive_entry_acl_from_text(ae, acltext[10],
 	    ARCHIVE_ENTRY_ACL_TYPE_NFS4));
-	archive_test_compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]),
+	assertEntryCompareAcls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_NFS4, 0);
 	assertEqualInt(6, archive_entry_acl_reset(ae,
 	    ARCHIVE_ENTRY_ACL_TYPE_NFS4));
@@ -398,7 +398,7 @@
 	assertEqualInt(ARCHIVE_OK,
 	    archive_entry_acl_from_text_w(ae, ws,
 	    ARCHIVE_ENTRY_ACL_TYPE_NFS4));
-	archive_test_compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]),
+	assertEntryCompareAcls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_NFS4, 0);
 	assertEqualInt(6, archive_entry_acl_reset(ae,
 	    ARCHIVE_ENTRY_ACL_TYPE_NFS4));
@@ -416,7 +416,7 @@
 	assert((ae = archive_entry_new()) != NULL);
 
 	/* Write POSIX.1e ACLs  */
-	archive_test_set_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]));
+	assertEntrySetAcls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]));
 
 	/* No flags should give output like getfacl(1) on linux */
 	compare_acl_text(ae, 0, acltext[0]);
@@ -457,7 +457,7 @@
 	    ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT, acltext[8]);
 
 	/* Write NFSv4 ACLs */
-	archive_test_set_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]));
+	assertEntrySetAcls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]));
 
 	/* NFSv4 ACLs like getfacl(1) on FreeBSD */
 	compare_acl_text(ae, 0, acltext[9]);
diff --git a/libarchive/test/test_archive_api_feature.c b/libarchive/test/test_archive_api_feature.c
index d551e6a..60773ad 100644
--- a/libarchive/test/test_archive_api_feature.c
+++ b/libarchive/test/test_archive_api_feature.c
@@ -42,8 +42,12 @@
 	if (strlen(buff) < strlen(archive_version_string())) {
 		p = archive_version_string() + strlen(buff);
 		failure("Version string is: %s", archive_version_string());
-		assert(*p == 'a' || *p == 'b' || *p == 'c' || *p == 'd');
-		++p;
+		if (p[0] == 'd'&& p[1] == 'e' && p[2] == 'v')
+			p += 3;
+		else {
+			assert(*p == 'a' || *p == 'b' || *p == 'c' || *p == 'd');
+			++p;
+		}
 		failure("Version string is: %s", archive_version_string());
 		assert(*p == '\0');
 	}
diff --git a/libarchive/test/test_compat_solaris_tar_acl.c b/libarchive/test/test_compat_solaris_tar_acl.c
index 3d063c1..8159772 100644
--- a/libarchive/test/test_compat_solaris_tar_acl.c
+++ b/libarchive/test/test_compat_solaris_tar_acl.c
@@ -227,7 +227,7 @@
 	failure("One extended ACL should flag all ACLs to be returned.");
 	assertEqualInt(7, archive_entry_acl_reset(ae,
 	    ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
-	archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
+	assertEntryCompareAcls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0644);
 	failure("Basic ACLs should set mode to 0644, not %04o",
 	    archive_entry_mode(ae)&0777);
@@ -237,28 +237,28 @@
 	assertA(0 == archive_read_next_header(a, &ae));
 	assertEqualInt(6, archive_entry_acl_reset(ae,
 	    ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
-	archive_test_compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]),
+	assertEntryCompareAcls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0750);
 	failure("Basic ACLs should set mode to 0750, not %04o",
 	    archive_entry_mode(ae)&0777);
 	assert((archive_entry_mode(ae) & 0777) == 0750);
 	assertEqualInt(6, archive_entry_acl_reset(ae,
 	    ARCHIVE_ENTRY_ACL_TYPE_DEFAULT));
-	archive_test_compare_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]),
+	assertEntryCompareAcls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, 0750);
 
 	/* Third item has NFS4 ACLs */
 	assertA(0 == archive_read_next_header(a, &ae));
 	assertEqualInt(6, archive_entry_acl_reset(ae,
 	    ARCHIVE_ENTRY_ACL_TYPE_NFS4));
-	archive_test_compare_acls(ae, acls3, sizeof(acls3)/sizeof(acls3[0]),
+	assertEntryCompareAcls(ae, acls3, sizeof(acls3)/sizeof(acls3[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_NFS4, 0);
 
 	/* Fourth item has NFS4 ACLs and inheritance flags */
 	assertA(0 == archive_read_next_header(a, &ae));
 	assertEqualInt(5, archive_entry_acl_reset(ae,
 	    ARCHIVE_ENTRY_ACL_TYPE_NFS4));
-	archive_test_compare_acls(ae, acls4, sizeof(acls4)/sizeof(acls0[4]),
+	assertEntryCompareAcls(ae, acls4, sizeof(acls4)/sizeof(acls0[4]),
 	    ARCHIVE_ENTRY_ACL_TYPE_NFS4, 0);
 
 	/* Close the archive. */
diff --git a/libarchive/test/test_compat_star_acl.c b/libarchive/test/test_compat_star_acl.c
index f2a78b2..8247101 100644
--- a/libarchive/test/test_compat_star_acl.c
+++ b/libarchive/test/test_compat_star_acl.c
@@ -249,7 +249,7 @@
 	failure("One extended ACL should flag all ACLs to be returned.");
 	assertEqualInt(5, archive_entry_acl_reset(ae,
 	    ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
-	archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
+	assertEntryCompareAcls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0142);
 	failure("Basic ACLs should set mode to 0142, not %04o",
 	    archive_entry_mode(ae)&0777);
@@ -259,7 +259,7 @@
 	assertA(0 == archive_read_next_header(a, &ae));
 	assertEqualInt(7, archive_entry_acl_reset(ae,
 	    ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
-	archive_test_compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]),
+	assertEntryCompareAcls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0543);
 	failure("Basic ACLs should set mode to 0543, not %04o",
 	    archive_entry_mode(ae)&0777);
@@ -269,7 +269,7 @@
 	assertA(0 == archive_read_next_header(a, &ae));
 	assertEqualInt(6, archive_entry_acl_reset(ae,
 	    ARCHIVE_ENTRY_ACL_TYPE_DEFAULT));
-	archive_test_compare_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]),
+	assertEntryCompareAcls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, 0142);
 	failure("Basic ACLs should set mode to 0142, not %04o",
 	    archive_entry_mode(ae)&0777);
@@ -298,21 +298,21 @@
 	assertA(0 == archive_read_next_header(a, &ae));
 	assertEqualInt(3, archive_entry_acl_reset(ae,
 	    ARCHIVE_ENTRY_ACL_TYPE_ALLOW));
-	archive_test_compare_acls(ae, acls3, sizeof(acls3)/sizeof(acls3[0]),
+	assertEntryCompareAcls(ae, acls3, sizeof(acls3)/sizeof(acls3[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_ALLOW, 0);
 
 	/* Second item has has fine-grained NFS4 ACLs */
 	assertA(0 == archive_read_next_header(a, &ae));
 	assertEqualInt(6, archive_entry_acl_reset(ae,
 	    ARCHIVE_ENTRY_ACL_TYPE_NFS4));
-	archive_test_compare_acls(ae, acls4, sizeof(acls4)/sizeof(acls0[4]),
+	assertEntryCompareAcls(ae, acls4, sizeof(acls4)/sizeof(acls0[4]),
 	    ARCHIVE_ENTRY_ACL_TYPE_NFS4, 0);
 
 	/* Third item has file and directory inheritance NFS4 ACLs */
 	assertA(0 == archive_read_next_header(a, &ae));
 	assertEqualInt(5, archive_entry_acl_reset(ae,
 	    ARCHIVE_ENTRY_ACL_TYPE_NFS4));
-	archive_test_compare_acls(ae, acls5, sizeof(acls5)/sizeof(acls5[0]),
+	assertEntryCompareAcls(ae, acls5, sizeof(acls5)/sizeof(acls5[0]),
 	    ARCHIVE_ENTRY_ACL_TYPE_NFS4, 0);
 
 	/* Close the archive. */
diff --git a/libarchive/test/test_fuzz.c b/libarchive/test/test_fuzz.c
index 71bf3ff..ce7b866 100644
--- a/libarchive/test/test_fuzz.c
+++ b/libarchive/test/test_fuzz.c
@@ -110,8 +110,9 @@
 		} else {
 			for (i = 0; filesets[n].names[i] != NULL; ++i)
 			{
+				char *newraw;
 				tmp = slurpfile(&size, filesets[n].names[i]);
-				char *newraw = realloc(rawimage, oldsize + size);
+				newraw = realloc(rawimage, oldsize + size);
 				if (!assert(newraw != NULL))
 				{
 					free(rawimage);
diff --git a/libarchive/test/test_read_disk_directory_traversals.c b/libarchive/test/test_read_disk_directory_traversals.c
index c9aca8f..fdbfbec 100644
--- a/libarchive/test/test_read_disk_directory_traversals.c
+++ b/libarchive/test/test_read_disk_directory_traversals.c
@@ -1228,8 +1228,8 @@
 	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
 
 	/*
-	 * Test4: Traversals with archive_read_disk_set_atime_restored() and
-	 * archive_read_disk_honor_nodump().
+	 * Test4: Traversals with ARCHIVE_READDISK_RESTORE_ATIME and
+	 * ARCHIVE_READDISK_HONOR_NODUMP
 	 */
 	assertNodump("at/f1");
 	assertNodump("at/f2");
@@ -1460,7 +1460,7 @@
 	assert((a = archive_read_disk_new()) != NULL);
 
 	/*
-	 * Test1: Traversals without archive_read_disk_honor_nodump().
+	 * Test1: Traversals without ARCHIVE_READDISK_HONOR_NODUMP
 	 */
 	failure("Directory traversals should work as well");
 	assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "nd"));
@@ -1513,7 +1513,7 @@
 	assertEqualInt(ARCHIVE_OK, archive_read_close(a));
 
 	/*
-	 * Test2: Traversals with archive_read_disk_honor_nodump().
+	 * Test2: Traversals with ARCHIVE_READDISK_HONOR_NODUMP
 	 */
 	assertUtimes("nd/f1", 886600, 0, 886600, 0);
 	assertUtimes("nd/f2", 886611, 0, 886611, 0);
diff --git a/tar/bsdtar.1 b/tar/bsdtar.1
index 9eadaaf..b60f09c 100644
--- a/tar/bsdtar.1
+++ b/tar/bsdtar.1
@@ -1,4 +1,5 @@
 .\" Copyright (c) 2003-2007 Tim Kientzle
+.\" Copyright (c) 2017 Martin Matuska
 .\" All rights reserved.
 .\"
 .\" Redistribution and use in source and binary forms, with or without
@@ -24,7 +25,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd September 16, 2014
+.Dd February 24, 2017
 .Dt TAR 1
 .Os
 .Sh NAME
@@ -124,7 +125,7 @@
 all operating modes.
 .Bl -tag -width indent
 .It Cm @ Ns Pa archive
-(c and r mode only)
+(c and r modes only)
 The specified archive is opened and the entries
 in it will be appended to the current archive.
 As a simple example,
@@ -164,6 +165,16 @@
 .Dl Nm Fl a Fl jcf Pa archive.xxx source.c source.h
 if it is unknown suffix or no suffix, creates a new archive with
 restricted pax format and bzip2 compression.
+.It Fl Fl acls
+(c, r, u, x modes only)
+Archive or extract POSIX.1e or NFSv4 ACLs. This is the reverse of
+.Fl Fl no-acls
+and the default behavior in c, r, and u modes (except Mac OS X) or if
+.Nm
+is run in x mode as root. On Mac OS X this option translates extended ACLs
+to NFSv4 ACLs. To store extended ACLs the
+.Fl Fl mac-metadata
+option is preferred.
 .It Fl B , Fl Fl read-full-blocks
 Ignored for compatibility with other
 .Xr tar 1
@@ -188,15 +199,18 @@
 (x mode only)
 Before removing file system objects to replace them, clear platform-specific
 file flags that might prevent removal.
-.It Fl Fl disable-copyfile
-Mac OS X specific.
-Disable the use of
-.Xr copyfile 3 .
 .It Fl Fl exclude Ar pattern
 Do not process files or directories that match the
 specified pattern.
 Note that exclusions take precedence over patterns or filenames
 specified on the command line.
+.It Fl Fl fflags
+(c, r, u, x modes only)
+Archive or extract file flags. This is the reverse of
+.Fl Fl no-fflags
+and the default behavior in c, r, and u modes or if
+.Nm
+is run in x mode as root.
 .It Fl Fl format Ar format
 (c, r, u mode only)
 Use the specified format for the created archive.
@@ -245,11 +259,11 @@
 in the archive;
 the name will not be verified against the system group database.
 .It Fl H
-(c and r mode only)
+(c and r modes only)
 Symbolic links named on the command line will be followed; the
 target of the link will be archived, not the link itself.
 .It Fl h
-(c and r mode only)
+(c and r modes only)
 Synonym for
 .Fl L .
 .It Fl I
@@ -259,7 +273,8 @@
 Show usage.
 .It Fl Fl hfsCompression
 (x mode only)
-Mac OS X specific(v10.6 or later). Compress extracted regular files with HFS+ compression.
+Mac OS X specific (v10.6 or later). Compress extracted regular files with HFS+
+compression.
 .It Fl Fl ignore-zeros
 An alias of
 .Fl Fl options Cm read_concatenated_archives
@@ -310,7 +325,7 @@
 Do not overwrite existing files that are newer than the
 versions appearing in the archive being extracted.
 .It Fl L , Fl Fl dereference
-(c and r mode only)
+(c and r modes only)
 All symbolic links will be followed.
 Normally, symbolic links are archived as such.
 With this option, the target of the link will be archived instead.
@@ -345,6 +360,16 @@
 (x mode only)
 Do not extract modification time.
 By default, the modification time is set to the time stored in the archive.
+.It Fl Fl mac-metadata
+(c, r, u and x mode only)
+Mac OS X specific. Archive or extract extended ACLs and extended attributes
+using
+.Xr copyfile 3
+in AppleDouble format. This is the reverse of
+.Fl Fl no-mac-metadata .
+and the default behavior in c, r, and u modes or if
+.Nm
+is run in x mode as root.
 .It Fl n , Fl Fl norecurse , Fl Fl no-recursion
 (c, r, u modes only)
 Do not recursively archive the contents of directories.
@@ -385,6 +410,30 @@
 .Fl print0
 option to
 .Xr find 1 .
+.It Fl Fl no-acls
+(c, r, u, x modes only)
+Do not archive or extract POSIX.1e or NFSv4 ACLs. This is the reverse of
+.Fl Fl acls
+and the default behavior if
+.Nm
+is run as non-root in x mode (on Mac OS X also in c, r and u modes).
+.It Fl Fl no-fflags
+(c, r, u, x modes only)
+Do not archive or extract file flags. This is the reverse of
+.Fl Fl fflags
+and the default behavior if
+.Nm
+is run as non-root in x mode.
+.It Fl Fl no-mac-metadata
+(x mode only)
+Mac OS X specific. Do not archive or extract ACLs and extended attributes using
+.Xr copyfile 3
+in AppleDouble format. This is the reverse of
+.Fl Fl mac-metadata .
+and the default behavior if
+.Nm
+is run as non-root in x mode.
+.It Fl n , Fl Fl norecurse , Fl Fl no-recursion
 .It Fl Fl no-same-owner
 (x mode only)
 Do not extract owner and group IDs.
@@ -401,7 +450,21 @@
 .Fl p
 and the default behavior if
 .Nm
-is run as non-root.
+is run as non-root and can be overridden by also specifying
+.Fl Fl acls ,
+.Fl Fl fflags ,
+.Fl Fl mac-metadata,
+.Fl Fl same-owner ,
+.Fl Fl same-permissions
+and
+.Fl Fl xattrs .
+.It Fl Fl no-xattrs
+(c, r, u, x modes only)
+Do not archive or extract extended attributes. This is the reverse of
+.Fl Fl xattrs
+and the default behavior if
+.Nm
+is run as non-root in x mode.
 .It Fl Fl numeric-owner
 This is equivalent to
 .Fl Fl uname
@@ -583,14 +646,18 @@
 .It Fl p , Fl Fl insecure , Fl Fl preserve-permissions
 (x mode only)
 Preserve file permissions.
-Attempt to restore the full permissions, including owner, file modes, file
-flags and ACLs, if available, for each item extracted from the archive.
-This is the default, if
+Attempt to restore the full permissions, including owner, file modes, ACLs,
+extended atributes and extended file flags, if available, for each item
+extracted from the archive. This is the default, if
 .Nm
 is being run by root and can be overridden by also specifying
-.Fl Fl no-same-owner
+.Fl Fl no-acls ,
+.Fl Fl no-fflags ,
+.Fl Fl no-mac-metadata,
+.Fl Fl no-same-owner ,
+.Fl Fl no-same-permissions
 and
-.Fl Fl no-same-permissions .
+.Fl Fl no-xattrs .
 .It Fl Fl passphrase Ar passphrase
 The
 .Pa passphrase
@@ -692,7 +759,7 @@
 .Fl n
 as well.
 .It Fl Fl totals
-(c, r, u mode only)
+(c, r, u modes only)
 After archiving all files, print a summary to stderr.
 .It Fl U , Fl Fl unlink , Fl Fl unlink-first
 (x mode only)
@@ -754,6 +821,13 @@
 See
 .Fl Fl exclude
 for more information about the handling of exclusions.
+.It Fl Fl xattrs
+(c, r, u, x modes only)
+Archive or extract extended attributes. This is the reverse of
+.Fl Fl no-xattrs
+and the default behavior in c, r, and u modes or if
+.Nm
+is run in x mode as root.
 .It Fl y
 (c mode only)
 Compress the resulting archive with
diff --git a/tar/bsdtar.c b/tar/bsdtar.c
index 93bf60a..a9252a5 100644
--- a/tar/bsdtar.c
+++ b/tar/bsdtar.c
@@ -137,7 +137,6 @@
 	char			 compression, compression2;
 	const char		*compression_name, *compression2_name;
 	const char		*compress_program;
-	char			 option_a, option_o;
 	char			 possible_help_request;
 	char			 buff[16];
 
@@ -150,7 +149,7 @@
 	bsdtar->fd = -1; /* Mark as "unused" */
 	bsdtar->gid = -1;
 	bsdtar->uid = -1;
-	option_a = option_o = 0;
+	bsdtar->flags = 0;
 	compression = compression2 = '\0';
 	compression_name = compression2_name = NULL;
 	compress_program = NULL;
@@ -233,6 +232,14 @@
 	if (getenv(COPYFILE_DISABLE_VAR))
 		bsdtar->readdisk_flags &= ~ARCHIVE_READDISK_MAC_COPYFILE;
 #endif
+#if defined(__APPLE__)
+	/*
+	 * On Mac OS ACLs are archived with copyfile() (--mac-metadata)
+	 * Translation to NFSv4 ACLs has to be requested explicitly with --acls
+	 */
+	bsdtar->readdisk_flags |= ARCHIVE_READDISK_NO_ACL;
+#endif
+
 	bsdtar->matching = archive_match_new();
 	if (bsdtar->matching == NULL)
 		lafe_errc(1, errno, "Out of memory");
@@ -252,7 +259,12 @@
 	while ((opt = bsdtar_getopt(bsdtar)) != -1) {
 		switch (opt) {
 		case 'a': /* GNU tar */
-			option_a = 1; /* Record it and resolve it later. */
+			bsdtar->flags |= OPTFLAG_AUTO_COMPRESS;
+			break;
+		case OPTION_ACLS: /* GNU tar */
+			bsdtar->extract_flags |= ARCHIVE_EXTRACT_ACL;
+			bsdtar->readdisk_flags &= ~ARCHIVE_READDISK_NO_ACL;
+			bsdtar->flags |= OPTFLAG_ACLS;
 			break;
 		case 'B': /* GNU tar */
 			/* libarchive doesn't need this; just ignore it. */
@@ -285,24 +297,26 @@
 			set_mode(bsdtar, opt);
 			break;
 		case OPTION_CHECK_LINKS: /* GNU tar */
-			bsdtar->option_warn_links = 1;
+			bsdtar->flags |= OPTFLAG_WARN_LINKS;
 			break;
 		case OPTION_CHROOT: /* NetBSD */
-			bsdtar->option_chroot = 1;
+			bsdtar->flags |= OPTFLAG_CHROOT;
 			break;
 		case OPTION_CLEAR_NOCHANGE_FFLAGS:
 			bsdtar->extract_flags |=
 			    ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS;
 			break;
-		case OPTION_DISABLE_COPYFILE: /* Mac OS X */
-			bsdtar->readdisk_flags &= ~ARCHIVE_READDISK_MAC_COPYFILE;
-			break;
 		case OPTION_EXCLUDE: /* GNU tar */
 			if (archive_match_exclude_pattern(
 			    bsdtar->matching, bsdtar->argument) != ARCHIVE_OK)
 				lafe_errc(1, 0,
 				    "Couldn't exclude %s\n", bsdtar->argument);
 			break;
+		case OPTION_FFLAGS:
+			bsdtar->extract_flags |= ARCHIVE_EXTRACT_FFLAGS;
+			bsdtar->readdisk_flags &= ~ARCHIVE_READDISK_NO_FFLAGS;
+			bsdtar->flags |= OPTFLAG_FFLAGS;
+			break;
 		case OPTION_FORMAT: /* GNU tar, others */
 			cset_set_format(bsdtar->cset, bsdtar->argument);
 			break;
@@ -344,7 +358,7 @@
 			    ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED;
 			break;
 		case OPTION_IGNORE_ZEROS:
-			bsdtar->option_ignore_zeros = 1;
+			bsdtar->flags |= OPTFLAG_IGNORE_ZEROS;
 			break;
 		case 'I': /* GNU tar */
 			/*
@@ -398,7 +412,7 @@
 			break;
 	        case 'l': /* SUSv2 and GNU tar beginning with 1.16 */
 			/* GNU tar 1.13  used -l for --one-file-system */
-			bsdtar->option_warn_links = 1;
+			bsdtar->flags |= OPTFLAG_WARN_LINKS;
 			break;
 		case OPTION_LRZIP:
 		case OPTION_LZ4:
@@ -421,8 +435,13 @@
 		case 'm': /* SUSv2 */
 			bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_TIME;
 			break;
+		case OPTION_MAC_METADATA: /* Mac OS X */
+			bsdtar->readdisk_flags |= ARCHIVE_READDISK_MAC_COPYFILE;
+			bsdtar->extract_flags |= ARCHIVE_EXTRACT_MAC_METADATA;
+			bsdtar->flags |= OPTFLAG_MAC_METADATA;
+			break;
 		case 'n': /* GNU tar */
-			bsdtar->option_no_subdirs = 1;
+			bsdtar->flags |= OPTFLAG_NO_SUBDIRS;
 			break;
 	        /*
 		 * Selecting files by time:
@@ -466,6 +485,21 @@
 			bsdtar->extract_flags |=
 			    ARCHIVE_EXTRACT_NO_HFS_COMPRESSION;
 			break;
+		case OPTION_NO_ACLS: /* GNU tar */
+			bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_ACL;
+			bsdtar->readdisk_flags |= ARCHIVE_READDISK_NO_ACL;
+			bsdtar->flags |= OPTFLAG_NO_ACLS;
+			break;
+		case OPTION_NO_FFLAGS:
+			bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_FFLAGS;
+			bsdtar->readdisk_flags |= ARCHIVE_READDISK_NO_FFLAGS;
+			bsdtar->flags |= OPTFLAG_NO_FFLAGS;
+			break;
+		case OPTION_NO_MAC_METADATA: /* Mac OS X */
+			bsdtar->readdisk_flags &= ~ARCHIVE_READDISK_MAC_COPYFILE;
+			bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_MAC_METADATA;
+			bsdtar->flags |= OPTFLAG_NO_MAC_METADATA;
+			break;
 		case OPTION_NO_SAME_OWNER: /* GNU tar */
 			bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_OWNER;
 			break;
@@ -476,23 +510,24 @@
 			bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_FFLAGS;
 			bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_MAC_METADATA;
 			break;
-		case OPTION_NO_XATTR: /* Issue #131 */
+		case OPTION_NO_XATTRS: /* GNU tar */
 			bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_XATTR;
 			bsdtar->readdisk_flags |= ARCHIVE_READDISK_NO_XATTR;
+			bsdtar->flags |= OPTFLAG_NO_XATTRS;
 			break;
 		case OPTION_NULL: /* GNU tar */
-			bsdtar->option_null++;
+			bsdtar->flags |= OPTFLAG_NULL;
 			break;
 		case OPTION_NUMERIC_OWNER: /* GNU tar */
 			bsdtar->uname = "";
 			bsdtar->gname = "";
-			bsdtar->option_numeric_owner++;
+			bsdtar->flags |= OPTFLAG_NUMERIC_OWNER;
 			break;
 		case 'O': /* GNU tar */
-			bsdtar->option_stdout = 1;
+			bsdtar->flags |= OPTFLAG_STDOUT;
 			break;
 		case 'o': /* SUSv2 and GNU conflict here, but not fatally */
-			option_o = 1; /* Record it and resolve it later. */
+			bsdtar->flags |= OPTFLAG_O;
 			break;
 	        /*
 		 * Selecting files by time:
@@ -548,7 +583,7 @@
 #endif
 		case 'P': /* GNU tar */
 			bsdtar->extract_flags &= ~SECURITY;
-			bsdtar->option_absolute_paths = 1;
+			bsdtar->flags |= OPTFLAG_ABSOLUTE_PATHS;
 			break;
 		case 'p': /* GNU tar, star */
 			bsdtar->extract_flags |= ARCHIVE_EXTRACT_PERM;
@@ -564,7 +599,7 @@
 			cset_set_format(bsdtar->cset, "pax");
 			break;
 		case 'q': /* FreeBSD GNU tar --fast-read, NetBSD -q */
-			bsdtar->option_fast_read = 1;
+			bsdtar->flags |= OPTFLAG_FAST_READ;
 			break;
 		case 'r': /* SUSv2 */
 			set_mode(bsdtar, opt);
@@ -601,11 +636,11 @@
 			bsdtar->verbose++;
 			break;
 		case OPTION_TOTALS: /* GNU tar */
-			bsdtar->option_totals++;
+			bsdtar->flags |= OPTFLAG_TOTALS;
 			break;
 		case 'U': /* GNU tar */
 			bsdtar->extract_flags |= ARCHIVE_EXTRACT_UNLINK;
-			bsdtar->option_unlink_first = 1;
+			bsdtar->flags |= OPTFLAG_UNLINK_FIRST;
 			break;
 		case 'u': /* SUSv2 */
 			set_mode(bsdtar, opt);
@@ -643,7 +678,7 @@
 			break;
 #endif
 		case 'w': /* SUSv2 */
-			bsdtar->option_interactive = 1;
+			bsdtar->flags |= OPTFLAG_INTERACTIVE;
 			break;
 		case 'X': /* GNU tar */
 			if (archive_match_exclude_pattern_from_file(
@@ -655,6 +690,11 @@
 		case 'x': /* SUSv2 */
 			set_mode(bsdtar, opt);
 			break;
+		case OPTION_XATTRS: /* GNU tar */
+			bsdtar->extract_flags |= ARCHIVE_EXTRACT_XATTR;
+			bsdtar->readdisk_flags &= ~ARCHIVE_READDISK_NO_XATTR;
+			bsdtar->flags |= OPTFLAG_XATTRS;
+			break;
 		case 'y': /* FreeBSD version of GNU tar */
 			if (compression != '\0')
 				lafe_errc(1, 0,
@@ -703,11 +743,11 @@
 		    "Must specify one of -c, -r, -t, -u, -x");
 
 	/* Check boolean options only permitted in certain modes. */
-	if (option_a)
+	if (bsdtar->flags & OPTFLAG_AUTO_COMPRESS)
 		only_mode(bsdtar, "-a", "c");
 	if (bsdtar->readdisk_flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS)
 		only_mode(bsdtar, "--one-file-system", "cru");
-	if (bsdtar->option_fast_read)
+	if (bsdtar->flags & OPTFLAG_FAST_READ)
 		only_mode(bsdtar, "--fast-read", "xt");
 	if (bsdtar->extract_flags & ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED)
 		only_mode(bsdtar, "--hfsCompression", "x");
@@ -715,9 +755,23 @@
 		only_mode(bsdtar, "--nopreserveHFSCompression", "x");
 	if (bsdtar->readdisk_flags & ARCHIVE_READDISK_HONOR_NODUMP)
 		only_mode(bsdtar, "--nodump", "cru");
-	if (bsdtar->readdisk_flags & ARCHIVE_READDISK_NO_XATTR)
-		only_mode(bsdtar, "--no-xattr", "crux");
-	if (option_o > 0) {
+	if (bsdtar->flags & OPTFLAG_ACLS)
+		only_mode(bsdtar, "--acls", "crux");
+	if (bsdtar->flags & OPTFLAG_NO_ACLS)
+		only_mode(bsdtar, "--no-acls", "crux");
+	if (bsdtar->flags & OPTFLAG_XATTRS)
+		only_mode(bsdtar, "--xattrs", "crux");
+	if (bsdtar->flags & OPTFLAG_NO_XATTRS)
+		only_mode(bsdtar, "--no-xattrs", "crux");
+	if (bsdtar->flags & OPTFLAG_FFLAGS)
+		only_mode(bsdtar, "--fflags", "crux");
+	if (bsdtar->flags & OPTFLAG_NO_FFLAGS)
+		only_mode(bsdtar, "--no-fflags", "crux");
+	if (bsdtar->flags & OPTFLAG_MAC_METADATA)
+		only_mode(bsdtar, "--mac-metadata", "crux");
+	if (bsdtar->flags & OPTFLAG_NO_MAC_METADATA)
+		only_mode(bsdtar, "--no-mac-metadata", "crux");
+	if (bsdtar->flags & OPTFLAG_O) {
 		switch (bsdtar->mode) {
 		case 'c':
 			/*
@@ -730,7 +784,7 @@
 			break;
 		case 'x':
 			/* POSIX-compatible behavior. */
-			bsdtar->option_no_owner = 1;
+			bsdtar->flags |= OPTFLAG_NO_OWNER;
 			bsdtar->extract_flags &= ~ARCHIVE_EXTRACT_OWNER;
 			break;
 		default:
@@ -738,16 +792,17 @@
 			break;
 		}
 	}
-	if (bsdtar->option_no_subdirs)
+	if (bsdtar->flags & OPTFLAG_NO_SUBDIRS)
 		only_mode(bsdtar, "-n", "cru");
-	if (bsdtar->option_stdout)
+	if (bsdtar->flags & OPTFLAG_STDOUT)
 		only_mode(bsdtar, "-O", "xt");
-	if (bsdtar->option_unlink_first)
+	if (bsdtar->flags & OPTFLAG_UNLINK_FIRST)
 		only_mode(bsdtar, "-U", "x");
-	if (bsdtar->option_warn_links)
+	if (bsdtar->flags & OPTFLAG_WARN_LINKS)
 		only_mode(bsdtar, "--check-links", "cr");
 
-	if (option_a && cset_auto_compress(bsdtar->cset, bsdtar->filename)) {
+	if ((bsdtar->flags & OPTFLAG_AUTO_COMPRESS) &&
+	    cset_auto_compress(bsdtar->cset, bsdtar->filename)) {
 		/* Ignore specified compressions if auto-compress works. */
 		compression = '\0';
 		compression2 = '\0';
diff --git a/tar/bsdtar.h b/tar/bsdtar.h
index 4b84ba1..ee9c648 100644
--- a/tar/bsdtar.h
+++ b/tar/bsdtar.h
@@ -50,6 +50,7 @@
 	int		  bytes_per_block; /* -b block_size */
 	int		  bytes_in_last_block; /* See -b handling. */
 	int		  verbose;   /* -v */
+	unsigned int	  flags; /* Bitfield of boolean options */
 	int		  extract_flags; /* Flags for extract operation */
 	int		  readdisk_flags; /* Flags for read disk operation */
 	int		  strip_components; /* Remove this many leading dirs */
@@ -60,20 +61,7 @@
 	const char	 *passphrase; /* --passphrase */
 	char		  mode; /* Program mode: 'c', 't', 'r', 'u', 'x' */
 	char		  symlink_mode; /* H or L, per BSD conventions */
-	char		  option_absolute_paths; /* -P */
-	char		  option_chroot; /* --chroot */
-	char		  option_fast_read; /* --fast-read */
 	const char	 *option_options; /* --options */
-	char		  option_ignore_zeros; /* --ignore-zeros */
-	char		  option_interactive; /* -w */
-	char		  option_no_owner; /* -o */
-	char		  option_no_subdirs; /* -n */
-	char		  option_numeric_owner; /* --numeric-owner */
-	char		  option_null; /* --null */
-	char		  option_stdout; /* -O */
-	char		  option_totals; /* --totals */
-	char		  option_unlink_first; /* -U */
-	char		  option_warn_links; /* --check-links */
 	char		  day_first; /* show day before month in -tv output */
 	struct creation_set *cset;
 
@@ -114,14 +102,40 @@
 	char			*ppbuff;	/* for util.c */
 };
 
+/* Options for flags bitfield */
+#define	OPTFLAG_AUTO_COMPRESS	(0x00000001)	/* -a */
+#define	OPTFLAG_ABSOLUTE_PATHS	(0x00000002)	/* -P */
+#define	OPTFLAG_CHROOT		(0x00000004)	/* --chroot */
+#define	OPTFLAG_FAST_READ	(0x00000008)	/* --fast-read */
+#define	OPTFLAG_IGNORE_ZEROS	(0x00000010)	/* --ignore-zeros */
+#define	OPTFLAG_INTERACTIVE	(0x00000020)	/* -w */
+#define	OPTFLAG_NO_OWNER	(0x00000040)	/* -o */
+#define	OPTFLAG_NO_SUBDIRS	(0x00000080)	/* -n */
+#define	OPTFLAG_NULL		(0x00000100)	/* --null */
+#define	OPTFLAG_NUMERIC_OWNER	(0x00000200)	/* --numeric-owner */
+#define	OPTFLAG_O		(0x00000400)	/* -o */
+#define	OPTFLAG_STDOUT		(0x00000800)	/* -O */
+#define	OPTFLAG_TOTALS		(0x00001000)	/* --totals */
+#define	OPTFLAG_UNLINK_FIRST	(0x00002000)	/* -U */
+#define	OPTFLAG_WARN_LINKS	(0x00004000)	/* --check-links */
+#define	OPTFLAG_NO_XATTRS	(0x00008000)	/* --no-xattrs */
+#define	OPTFLAG_XATTRS		(0x00010000)	/* --xattrs */
+#define	OPTFLAG_NO_ACLS		(0x00020000)	/* --no-acls */
+#define	OPTFLAG_ACLS		(0x00040000)	/* --acls */
+#define	OPTFLAG_NO_FFLAGS	(0x00080000)	/* --no-fflags */
+#define	OPTFLAG_FFLAGS		(0x00100000)	/* --fflags */
+#define	OPTFLAG_NO_MAC_METADATA	(0x00200000)	/* --no-mac-metadata */
+#define	OPTFLAG_MAC_METADATA	(0x00400000)	/* --mac-metadata */
+
 /* Fake short equivalents for long options that otherwise lack them. */
 enum {
-	OPTION_B64ENCODE = 1,
+	OPTION_ACLS = 1,
+	OPTION_B64ENCODE,
 	OPTION_CHECK_LINKS,
 	OPTION_CHROOT,
 	OPTION_CLEAR_NOCHANGE_FFLAGS,
-	OPTION_DISABLE_COPYFILE,
 	OPTION_EXCLUDE,
+	OPTION_FFLAGS,
 	OPTION_FORMAT,
 	OPTION_GID,
 	OPTION_GNAME,
@@ -136,15 +150,19 @@
 	OPTION_LZIP,
 	OPTION_LZMA,
 	OPTION_LZOP,
+	OPTION_MAC_METADATA,
 	OPTION_NEWER_CTIME,
 	OPTION_NEWER_CTIME_THAN,
 	OPTION_NEWER_MTIME,
 	OPTION_NEWER_MTIME_THAN,
 	OPTION_NODUMP,
 	OPTION_NOPRESERVE_HFS_COMPRESSION,
+	OPTION_NO_ACLS,
+	OPTION_NO_FFLAGS,
+	OPTION_NO_MAC_METADATA,
 	OPTION_NO_SAME_OWNER,
 	OPTION_NO_SAME_PERMISSIONS,
-	OPTION_NO_XATTR,
+	OPTION_NO_XATTRS,
 	OPTION_NULL,
 	OPTION_NUMERIC_OWNER,
 	OPTION_OLDER_CTIME,
@@ -162,7 +180,8 @@
 	OPTION_UNAME,
 	OPTION_USE_COMPRESS_PROGRAM,
 	OPTION_UUENCODE,
-	OPTION_VERSION
+	OPTION_VERSION,
+	OPTION_XATTRS
 };
 
 int	bsdtar_getopt(struct bsdtar *);
diff --git a/tar/cmdline.c b/tar/cmdline.c
index c87741c..e36c545 100644
--- a/tar/cmdline.c
+++ b/tar/cmdline.c
@@ -65,6 +65,7 @@
 } tar_longopts[] = {
 	{ "absolute-paths",       0, 'P' },
 	{ "append",               0, 'r' },
+	{ "acls",                 0, OPTION_ACLS },
 	{ "auto-compress",        0, 'a' },
 	{ "b64encode",            0, OPTION_B64ENCODE },
 	{ "block-size",           1, 'b' },
@@ -81,11 +82,12 @@
 	{ "create",               0, 'c' },
 	{ "dereference",	  0, 'L' },
 	{ "directory",            1, 'C' },
-	{ "disable-copyfile",	  0, OPTION_DISABLE_COPYFILE },
+	{ "disable-copyfile",	  0, OPTION_NO_MAC_METADATA },
 	{ "exclude",              1, OPTION_EXCLUDE },
 	{ "exclude-from",         1, 'X' },
 	{ "extract",              0, 'x' },
 	{ "fast-read",            0, 'q' },
+	{ "fflags",               0, OPTION_FFLAGS },
 	{ "file",                 1, 'f' },
 	{ "files-from",           1, 'T' },
 	{ "format",               1, OPTION_FORMAT },
@@ -108,6 +110,7 @@
 	{ "lzip",                 0, OPTION_LZIP },
 	{ "lzma",                 0, OPTION_LZMA },
 	{ "lzop",                 0, OPTION_LZOP },
+	{ "mac-metadata",         0, OPTION_MAC_METADATA },
 	{ "modification-time",    0, 'm' },
 	{ "newer",		  1, OPTION_NEWER_CTIME },
 	{ "newer-ctime",	  1, OPTION_NEWER_CTIME },
@@ -115,10 +118,14 @@
 	{ "newer-mtime",	  1, OPTION_NEWER_MTIME },
 	{ "newer-mtime-than",	  1, OPTION_NEWER_MTIME_THAN },
 	{ "newer-than",		  1, OPTION_NEWER_CTIME_THAN },
+	{ "no-acls",              0, OPTION_NO_ACLS },
+	{ "no-fflags",            0, OPTION_NO_FFLAGS },
+	{ "no-mac-metadata",      0, OPTION_NO_MAC_METADATA },
 	{ "no-recursion",         0, 'n' },
 	{ "no-same-owner",	  0, OPTION_NO_SAME_OWNER },
 	{ "no-same-permissions",  0, OPTION_NO_SAME_PERMISSIONS },
-	{ "no-xattr",             0, OPTION_NO_XATTR },
+	{ "no-xattr",             0, OPTION_NO_XATTRS },
+	{ "no-xattrs",            0, OPTION_NO_XATTRS },
 	{ "nodump",               0, OPTION_NODUMP },
 	{ "nopreserveHFSCompression",0, OPTION_NOPRESERVE_HFS_COMPRESSION },
 	{ "norecurse",            0, 'n' },
@@ -151,6 +158,7 @@
 	{ "uuencode",             0, OPTION_UUENCODE },
 	{ "verbose",              0, 'v' },
 	{ "version",              0, OPTION_VERSION },
+	{ "xattrs",               0, OPTION_XATTRS },
 	{ "xz",                   0, 'J' },
 	{ NULL, 0, 0 }
 };
diff --git a/tar/read.c b/tar/read.c
index 3c6cb0c..658c810 100644
--- a/tar/read.c
+++ b/tar/read.c
@@ -105,7 +105,7 @@
 	writer = archive_write_disk_new();
 	if (writer == NULL)
 		lafe_errc(1, ENOMEM, "Cannot allocate disk writer object");
-	if (!bsdtar->option_numeric_owner)
+	if ((bsdtar->flags & OPTFLAG_NUMERIC_OWNER) == 0)
 		archive_write_disk_set_standard_lookup(writer);
 	archive_write_disk_set_options(writer, bsdtar->extract_flags);
 
@@ -177,7 +177,7 @@
 	if (bsdtar->names_from_file != NULL)
 		if (archive_match_include_pattern_from_file(
 		    bsdtar->matching, bsdtar->names_from_file,
-		    bsdtar->option_null) != ARCHIVE_OK)
+		    (bsdtar->flags & OPTFLAG_NULL)) != ARCHIVE_OK)
 			lafe_errc(1, 0, "Error inclusion pattern: %s",
 			    archive_error_string(bsdtar->matching));
 
@@ -208,7 +208,7 @@
 	}
 	if (ARCHIVE_OK != archive_read_set_options(a, bsdtar->option_options))
 		lafe_errc(1, 0, "%s", archive_error_string(a));
-	if (bsdtar->option_ignore_zeros)
+	if (bsdtar->flags & OPTFLAG_IGNORE_ZEROS)
 		if (archive_read_set_options(a,
 		    "read_concatenated_archives") != ARCHIVE_OK)
 			lafe_errc(1, 0, "%s", archive_error_string(a));
@@ -234,7 +234,7 @@
 		    &progress_data);
 	}
 
-	if (mode == 'x' && bsdtar->option_chroot) {
+	if (mode == 'x' && (bsdtar->flags & OPTFLAG_CHROOT)) {
 #if HAVE_CHROOT
 		if (chroot(".") != 0)
 			lafe_errc(1, errno, "Can't chroot to \".\"");
@@ -245,7 +245,7 @@
 	}
 
 #if defined(_WIN32) && !defined(__CYGWIN__)
-	if (mode == 'x' && bsdtar->option_stdout) {
+	if (mode == 'x' && (bsdtar->flags & OPTFLAG_STDOUT)) {
 		_setmode(1, _O_BINARY);
 	}
 #endif
@@ -253,7 +253,7 @@
 	for (;;) {
 		/* Support --fast-read option */
 		const char *p;
-		if (bsdtar->option_fast_read &&
+		if ((bsdtar->flags & OPTFLAG_FAST_READ) &&
 		    archive_match_path_unmatched_inclusions(bsdtar->matching) == 0)
 			break;
 
@@ -307,7 +307,8 @@
 		if (mode == 't') {
 			/* Perversely, gtar uses -O to mean "send to stderr"
 			 * when used with -t. */
-			out = bsdtar->option_stdout ? stderr : stdout;
+			out = (bsdtar->flags & OPTFLAG_STDOUT) ?
+			    stderr : stdout;
 
 			/*
 			 * TODO: Provide some reasonable way to
@@ -345,7 +346,7 @@
 			if (edit_pathname(bsdtar, entry))
 				continue; /* Excluded by a rewrite failure. */
 
-			if (bsdtar->option_interactive &&
+			if ((bsdtar->flags & OPTFLAG_INTERACTIVE) &&
 			    !yes("extract '%s'", archive_entry_pathname(entry)))
 				continue;
 
@@ -364,7 +365,7 @@
 
 			/* TODO siginfo_printinfo(bsdtar, 0); */
 
-			if (bsdtar->option_stdout)
+			if (bsdtar->flags & OPTFLAG_STDOUT)
 				r = archive_read_data_into_fd(a, 1);
 			else
 				r = archive_read_extract2(a, entry, writer);
diff --git a/tar/test/CMakeLists.txt b/tar/test/CMakeLists.txt
index 0d2da36..3dd3601 100644
--- a/tar/test/CMakeLists.txt
+++ b/tar/test/CMakeLists.txt
@@ -6,7 +6,7 @@
 IF(ENABLE_TAR AND ENABLE_TEST)
   SET(bsdtar_test_SOURCES
     ../../test_utils/test_utils.c
-    main.c
+    ../../test_utils/test_main.c
     test.h
     test_0.c
     test_basic.c
@@ -96,6 +96,7 @@
   INCLUDE(${CMAKE_CURRENT_BINARY_DIR}/list.h)
   INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
   INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/test_utils)
+  INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/tar/test)
 
   # Experimental new test handling
   ADD_CUSTOM_TARGET(run_bsdtar_test
diff --git a/tar/test/main.c b/tar/test/main.c
deleted file mode 100644
index 8d31706..0000000
--- a/tar/test/main.c
+++ /dev/null
@@ -1,3072 +0,0 @@
-/*
- * Copyright (c) 2003-2009 Tim Kientzle
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "test.h"
-#include "test_utils.h"
-#ifdef HAVE_SYS_IOCTL_H
-#include <sys/ioctl.h>
-#endif
-#ifdef HAVE_SYS_TIME_H
-#include <sys/time.h>
-#endif
-#include <errno.h>
-#ifdef HAVE_ICONV_H
-#include <iconv.h>
-#endif
-/*
- * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h.
- * As the include guards don't agree, the order of include is important.
- */
-#ifdef HAVE_LINUX_EXT2_FS_H
-#include <linux/ext2_fs.h>      /* for Linux file flags */
-#endif
-#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__)
-#include <ext2fs/ext2_fs.h>     /* Linux file flags, broken on Cygwin */
-#endif
-#include <limits.h>
-#include <locale.h>
-#ifdef HAVE_SIGNAL_H
-#include <signal.h>
-#endif
-#include <stdarg.h>
-#include <time.h>
-
-/*
- * This same file is used pretty much verbatim for all test harnesses.
- *
- * The next few lines are the only differences.
- * TODO: Move this into a separate configuration header, have all test
- * suites share one copy of this file.
- */
-__FBSDID("$FreeBSD: src/usr.bin/tar/test/main.c,v 1.6 2008/11/05 06:40:53 kientzle Exp $");
-#define KNOWNREF	"test_patterns_2.tar.uu"
-#define ENVBASE "BSDTAR"  /* Prefix for environment variables. */
-#define	PROGRAM "bsdtar"  /* Name of program being tested. */
-#define PROGRAM_ALIAS "tar" /* Generic alias for program */
-#undef	LIBRARY		  /* Not testing a library. */
-#undef	EXTRA_DUMP	  /* How to dump extra data */
-#undef	EXTRA_ERRNO	  /* How to dump errno */
-/* How to generate extra version info. */
-#define	EXTRA_VERSION    (systemf("%s --version", testprog) ? "" : "")
-
-/*
- *
- * Windows support routines
- *
- * Note: Configuration is a tricky issue.  Using HAVE_* feature macros
- * in the test harness is dangerous because they cover up
- * configuration errors.  The classic example of this is omitting a
- * configure check.  If libarchive and libarchive_test both look for
- * the same feature macro, such errors are hard to detect.  Platform
- * macros (e.g., _WIN32 or __GNUC__) are a little better, but can
- * easily lead to very messy code.  It's best to limit yourself
- * to only the most generic programming techniques in the test harness
- * and thus avoid conditionals altogether.  Where that's not possible,
- * try to minimize conditionals by grouping platform-specific tests in
- * one place (e.g., test_acl_freebsd) or by adding new assert()
- * functions (e.g., assertMakeHardlink()) to cover up platform
- * differences.  Platform-specific coding in libarchive_test is often
- * a symptom that some capability is missing from libarchive itself.
- */
-#if defined(_WIN32) && !defined(__CYGWIN__)
-#include <io.h>
-#include <direct.h>
-#include <windows.h>
-#ifndef F_OK
-#define F_OK (0)
-#endif
-#ifndef S_ISDIR
-#define S_ISDIR(m)  ((m) & _S_IFDIR)
-#endif
-#ifndef S_ISREG
-#define S_ISREG(m)  ((m) & _S_IFREG)
-#endif
-#if !defined(__BORLANDC__)
-#define access _access
-#undef chdir
-#define chdir _chdir
-#endif
-#ifndef fileno
-#define fileno _fileno
-#endif
-/*#define fstat _fstat64*/
-#if !defined(__BORLANDC__)
-#define getcwd _getcwd
-#endif
-#define lstat stat
-/*#define lstat _stat64*/
-/*#define stat _stat64*/
-#define rmdir _rmdir
-#if !defined(__BORLANDC__)
-#define strdup _strdup
-#define umask _umask
-#endif
-#define int64_t __int64
-#endif
-
-#if defined(HAVE__CrtSetReportMode)
-# include <crtdbg.h>
-#endif
-
-mode_t umasked(mode_t expected_mode)
-{
-	mode_t mode = umask(0);
-	umask(mode);
-	return expected_mode & ~mode;
-}
-
-/* Path to working directory for current test */
-const char *testworkdir;
-#ifdef PROGRAM
-/* Pathname of exe to be tested. */
-const char *testprogfile;
-/* Name of exe to use in printf-formatted command strings. */
-/* On Windows, this includes leading/trailing quotes. */
-const char *testprog;
-#endif
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-static void	*GetFunctionKernel32(const char *);
-static int	 my_CreateSymbolicLinkA(const char *, const char *, int);
-static int	 my_CreateHardLinkA(const char *, const char *);
-static int	 my_GetFileInformationByName(const char *,
-		     BY_HANDLE_FILE_INFORMATION *);
-
-static void *
-GetFunctionKernel32(const char *name)
-{
-	static HINSTANCE lib;
-	static int set;
-	if (!set) {
-		set = 1;
-		lib = LoadLibrary("kernel32.dll");
-	}
-	if (lib == NULL) {
-		fprintf(stderr, "Can't load kernel32.dll?!\n");
-		exit(1);
-	}
-	return (void *)GetProcAddress(lib, name);
-}
-
-static int
-my_CreateSymbolicLinkA(const char *linkname, const char *target, int flags)
-{
-	static BOOLEAN (WINAPI *f)(LPCSTR, LPCSTR, DWORD);
-	static int set;
-	if (!set) {
-		set = 1;
-		f = GetFunctionKernel32("CreateSymbolicLinkA");
-	}
-	return f == NULL ? 0 : (*f)(linkname, target, flags);
-}
-
-static int
-my_CreateHardLinkA(const char *linkname, const char *target)
-{
-	static BOOLEAN (WINAPI *f)(LPCSTR, LPCSTR, LPSECURITY_ATTRIBUTES);
-	static int set;
-	if (!set) {
-		set = 1;
-		f = GetFunctionKernel32("CreateHardLinkA");
-	}
-	return f == NULL ? 0 : (*f)(linkname, target, NULL);
-}
-
-static int
-my_GetFileInformationByName(const char *path, BY_HANDLE_FILE_INFORMATION *bhfi)
-{
-	HANDLE h;
-	int r;
-
-	memset(bhfi, 0, sizeof(*bhfi));
-	h = CreateFile(path, FILE_READ_ATTRIBUTES, 0, NULL,
-		OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
-	if (h == INVALID_HANDLE_VALUE)
-		return (0);
-	r = GetFileInformationByHandle(h, bhfi);
-	CloseHandle(h);
-	return (r);
-}
-#endif
-
-#if defined(HAVE__CrtSetReportMode) && !defined(__WATCOMC__)
-static void
-invalid_parameter_handler(const wchar_t * expression,
-    const wchar_t * function, const wchar_t * file,
-    unsigned int line, uintptr_t pReserved)
-{
-	/* nop */
-}
-#endif
-
-/*
- *
- * OPTIONS FLAGS
- *
- */
-
-/* Enable core dump on failure. */
-static int dump_on_failure = 0;
-/* Default is to remove temp dirs and log data for successful tests. */
-static int keep_temp_files = 0;
-/* Default is to run the specified tests once and report errors. */
-static int until_failure = 0;
-/* Default is to just report pass/fail for each test. */
-static int verbosity = 0;
-#define	VERBOSITY_SUMMARY_ONLY -1 /* -q */
-#define VERBOSITY_PASSFAIL 0   /* Default */
-#define VERBOSITY_LIGHT_REPORT 1 /* -v */
-#define VERBOSITY_FULL 2 /* -vv */
-/* A few places generate even more output for verbosity > VERBOSITY_FULL,
- * mostly for debugging the test harness itself. */
-/* Cumulative count of assertion failures. */
-static int failures = 0;
-/* Cumulative count of reported skips. */
-static int skips = 0;
-/* Cumulative count of assertions checked. */
-static int assertions = 0;
-
-/* Directory where uuencoded reference files can be found. */
-static const char *refdir;
-
-/*
- * Report log information selectively to console and/or disk log.
- */
-static int log_console = 0;
-static FILE *logfile;
-static void
-vlogprintf(const char *fmt, va_list ap)
-{
-#ifdef va_copy
-	va_list lfap;
-	va_copy(lfap, ap);
-#endif
-	if (log_console)
-		vfprintf(stdout, fmt, ap);
-	if (logfile != NULL)
-#ifdef va_copy
-		vfprintf(logfile, fmt, lfap);
-	va_end(lfap);
-#else
-		vfprintf(logfile, fmt, ap);
-#endif
-}
-
-static void
-logprintf(const char *fmt, ...)
-{
-	va_list ap;
-	va_start(ap, fmt);
-	vlogprintf(fmt, ap);
-	va_end(ap);
-}
-
-/* Set up a message to display only if next assertion fails. */
-static char msgbuff[4096];
-static const char *msg, *nextmsg;
-void
-failure(const char *fmt, ...)
-{
-	va_list ap;
-	if (fmt == NULL) {
-		nextmsg = NULL;
-	} else {
-		va_start(ap, fmt);
-		vsprintf(msgbuff, fmt, ap);
-		va_end(ap);
-		nextmsg = msgbuff;
-	}
-}
-
-/*
- * Copy arguments into file-local variables.
- * This was added to permit vararg assert() functions without needing
- * variadic wrapper macros.  Turns out that the vararg capability is almost
- * never used, so almost all of the vararg assertions can be simplified
- * by removing the vararg capability and reworking the wrapper macro to
- * pass __FILE__, __LINE__ directly into the function instead of using
- * this hook.  I suspect this machinery is used so rarely that we
- * would be better off just removing it entirely.  That would simplify
- * the code here noticeably.
- */
-static const char *skipping_filename;
-static int skipping_line;
-void skipping_setup(const char *filename, int line)
-{
-	skipping_filename = filename;
-	skipping_line = line;
-}
-
-/* Called at the beginning of each assert() function. */
-static void
-assertion_count(const char *file, int line)
-{
-	(void)file; /* UNUSED */
-	(void)line; /* UNUSED */
-	++assertions;
-	/* Proper handling of "failure()" message. */
-	msg = nextmsg;
-	nextmsg = NULL;
-	/* Uncomment to print file:line after every assertion.
-	 * Verbose, but occasionally useful in tracking down crashes. */
-	/* printf("Checked %s:%d\n", file, line); */
-}
-
-/*
- * For each test source file, we remember how many times each
- * assertion was reported.  Cleared before each new test,
- * used by test_summarize().
- */
-static struct line {
-	int count;
-	int skip;
-}  failed_lines[10000];
-const char *failed_filename;
-
-/* Count this failure, setup up log destination and handle initial report. */
-static void
-failure_start(const char *filename, int line, const char *fmt, ...)
-{
-	va_list ap;
-
-	/* Record another failure for this line. */
-	++failures;
-	failed_filename = filename;
-	failed_lines[line].count++;
-
-	/* Determine whether to log header to console. */
-	switch (verbosity) {
-	case VERBOSITY_LIGHT_REPORT:
-		log_console = (failed_lines[line].count < 2);
-		break;
-	default:
-		log_console = (verbosity >= VERBOSITY_FULL);
-	}
-
-	/* Log file:line header for this failure */
-	va_start(ap, fmt);
-#if _MSC_VER
-	logprintf("%s(%d): ", filename, line);
-#else
-	logprintf("%s:%d: ", filename, line);
-#endif
-	vlogprintf(fmt, ap);
-	va_end(ap);
-	logprintf("\n");
-
-	if (msg != NULL && msg[0] != '\0') {
-		logprintf("   Description: %s\n", msg);
-		msg = NULL;
-	}
-
-	/* Determine whether to log details to console. */
-	if (verbosity == VERBOSITY_LIGHT_REPORT)
-		log_console = 0;
-}
-
-/* Complete reporting of failed tests. */
-/*
- * The 'extra' hook here is used by libarchive to include libarchive
- * error messages with assertion failures.  It could also be used
- * to add strerror() output, for example.  Just define the EXTRA_DUMP()
- * macro appropriately.
- */
-static void
-failure_finish(void *extra)
-{
-	(void)extra; /* UNUSED (maybe) */
-#ifdef EXTRA_DUMP
-	if (extra != NULL) {
-		logprintf("    errno: %d\n", EXTRA_ERRNO(extra));
-		logprintf("   detail: %s\n", EXTRA_DUMP(extra));
-	}
-#endif
-
-	if (dump_on_failure) {
-		fprintf(stderr,
-		    " *** forcing core dump so failure can be debugged ***\n");
-		abort();
-	}
-}
-
-/* Inform user that we're skipping some checks. */
-void
-test_skipping(const char *fmt, ...)
-{
-	char buff[1024];
-	va_list ap;
-
-	va_start(ap, fmt);
-	vsprintf(buff, fmt, ap);
-	va_end(ap);
-	/* Use failure() message if set. */
-	msg = nextmsg;
-	nextmsg = NULL;
-	/* failure_start() isn't quite right, but is awfully convenient. */
-	failure_start(skipping_filename, skipping_line, "SKIPPING: %s", buff);
-	--failures; /* Undo failures++ in failure_start() */
-	/* Don't failure_finish() here. */
-	/* Mark as skip, so doesn't count as failed test. */
-	failed_lines[skipping_line].skip = 1;
-	++skips;
-}
-
-/*
- *
- * ASSERTIONS
- *
- */
-
-/* Generic assert() just displays the failed condition. */
-int
-assertion_assert(const char *file, int line, int value,
-    const char *condition, void *extra)
-{
-	assertion_count(file, line);
-	if (!value) {
-		failure_start(file, line, "Assertion failed: %s", condition);
-		failure_finish(extra);
-	}
-	return (value);
-}
-
-/* chdir() and report any errors */
-int
-assertion_chdir(const char *file, int line, const char *pathname)
-{
-	assertion_count(file, line);
-	if (chdir(pathname) == 0)
-		return (1);
-	failure_start(file, line, "chdir(\"%s\")", pathname);
-	failure_finish(NULL);
-	return (0);
-
-}
-
-/* Verify two integers are equal. */
-int
-assertion_equal_int(const char *file, int line,
-    long long v1, const char *e1, long long v2, const char *e2, void *extra)
-{
-	assertion_count(file, line);
-	if (v1 == v2)
-		return (1);
-	failure_start(file, line, "%s != %s", e1, e2);
-	logprintf("      %s=%lld (0x%llx, 0%llo)\n", e1, v1, v1, v1);
-	logprintf("      %s=%lld (0x%llx, 0%llo)\n", e2, v2, v2, v2);
-	failure_finish(extra);
-	return (0);
-}
-
-/*
- * Utility to convert a single UTF-8 sequence.
- */
-static int
-_utf8_to_unicode(uint32_t *pwc, const char *s, size_t n)
-{
-	static const char utf8_count[256] = {
-		 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 00 - 0F */
-		 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 10 - 1F */
-		 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 20 - 2F */
-		 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 30 - 3F */
-		 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 40 - 4F */
-		 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 50 - 5F */
-		 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 60 - 6F */
-		 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,/* 70 - 7F */
-		 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 80 - 8F */
-		 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* 90 - 9F */
-		 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* A0 - AF */
-		 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,/* B0 - BF */
-		 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,/* C0 - CF */
-		 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,/* D0 - DF */
-		 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,/* E0 - EF */
-		 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 /* F0 - FF */
-	};
-	int ch;
-	int cnt;
-	uint32_t wc;
-
-	*pwc = 0;
-
-	/* Sanity check. */
-	if (n == 0)
-		return (0);
-	/*
-	 * Decode 1-4 bytes depending on the value of the first byte.
-	 */
-	ch = (unsigned char)*s;
-	if (ch == 0)
-		return (0); /* Standard:  return 0 for end-of-string. */
-	cnt = utf8_count[ch];
-
-	/* Invalid sequence or there are not plenty bytes. */
-	if (n < (size_t)cnt)
-		return (-1);
-
-	/* Make a Unicode code point from a single UTF-8 sequence. */
-	switch (cnt) {
-	case 1:	/* 1 byte sequence. */
-		*pwc = ch & 0x7f;
-		return (cnt);
-	case 2:	/* 2 bytes sequence. */
-		if ((s[1] & 0xc0) != 0x80) return (-1);
-		*pwc = ((ch & 0x1f) << 6) | (s[1] & 0x3f);
-		return (cnt);
-	case 3:	/* 3 bytes sequence. */
-		if ((s[1] & 0xc0) != 0x80) return (-1);
-		if ((s[2] & 0xc0) != 0x80) return (-1);
-		wc = ((ch & 0x0f) << 12)
-		    | ((s[1] & 0x3f) << 6)
-		    | (s[2] & 0x3f);
-		if (wc < 0x800)
-			return (-1);/* Overlong sequence. */
-		break;
-	case 4:	/* 4 bytes sequence. */
-		if (n < 4)
-			return (-1);
-		if ((s[1] & 0xc0) != 0x80) return (-1);
-		if ((s[2] & 0xc0) != 0x80) return (-1);
-		if ((s[3] & 0xc0) != 0x80) return (-1);
-		wc = ((ch & 0x07) << 18)
-		    | ((s[1] & 0x3f) << 12)
-		    | ((s[2] & 0x3f) << 6)
-		    | (s[3] & 0x3f);
-		if (wc < 0x10000)
-			return (-1);/* Overlong sequence. */
-		break;
-	default:
-		return (-1);
-	}
-
-	/* The code point larger than 0x10FFFF is not legal
-	 * Unicode values. */
-	if (wc > 0x10FFFF)
-		return (-1);
-	/* Correctly gets a Unicode, returns used bytes. */
-	*pwc = wc;
-	return (cnt);
-}
-
-static void strdump(const char *e, const char *p, int ewidth, int utf8)
-{
-	const char *q = p;
-
-	logprintf("      %*s = ", ewidth, e);
-	if (p == NULL) {
-		logprintf("NULL\n");
-		return;
-	}
-	logprintf("\"");
-	while (*p != '\0') {
-		unsigned int c = 0xff & *p++;
-		switch (c) {
-		case '\a': logprintf("\\a"); break;
-		case '\b': logprintf("\\b"); break;
-		case '\n': logprintf("\\n"); break;
-		case '\r': logprintf("\\r"); break;
-		default:
-			if (c >= 32 && c < 127)
-				logprintf("%c", c);
-			else
-				logprintf("\\x%02X", c);
-		}
-	}
-	logprintf("\"");
-	logprintf(" (length %d)", q == NULL ? -1 : (int)strlen(q));
-
-	/*
-	 * If the current string is UTF-8, dump its code points.
-	 */
-	if (utf8) {
-		size_t len;
-		uint32_t uc;
-		int n;
-		int cnt = 0;
-
-		p = q;
-		len = strlen(p);
-		logprintf(" [");
-		while ((n = _utf8_to_unicode(&uc, p, len)) > 0) {
-			if (p != q)
-				logprintf(" ");
-			logprintf("%04X", uc);
-			p += n;
-			len -= n;
-			cnt++;
-		}
-		logprintf("]");
-		logprintf(" (count %d", cnt);
-		if (n < 0) {
-			logprintf(",unknown %d bytes", len);
-		}
-		logprintf(")");
-
-	}
-	logprintf("\n");
-}
-
-/* Verify two strings are equal, dump them if not. */
-int
-assertion_equal_string(const char *file, int line,
-    const char *v1, const char *e1,
-    const char *v2, const char *e2,
-    void *extra, int utf8)
-{
-	int l1, l2;
-
-	assertion_count(file, line);
-	if (v1 == v2 || (v1 != NULL && v2 != NULL && strcmp(v1, v2) == 0))
-		return (1);
-	failure_start(file, line, "%s != %s", e1, e2);
-	l1 = (int)strlen(e1);
-	l2 = (int)strlen(e2);
-	if (l1 < l2)
-		l1 = l2;
-	strdump(e1, v1, l1, utf8);
-	strdump(e2, v2, l1, utf8);
-	failure_finish(extra);
-	return (0);
-}
-
-static void
-wcsdump(const char *e, const wchar_t *w)
-{
-	logprintf("      %s = ", e);
-	if (w == NULL) {
-		logprintf("(null)");
-		return;
-	}
-	logprintf("\"");
-	while (*w != L'\0') {
-		unsigned int c = *w++;
-		if (c >= 32 && c < 127)
-			logprintf("%c", c);
-		else if (c < 256)
-			logprintf("\\x%02X", c);
-		else if (c < 0x10000)
-			logprintf("\\u%04X", c);
-		else
-			logprintf("\\U%08X", c);
-	}
-	logprintf("\"\n");
-}
-
-#ifndef HAVE_WCSCMP
-static int
-wcscmp(const wchar_t *s1, const wchar_t *s2)
-{
-
-	while (*s1 == *s2++) {
-		if (*s1++ == L'\0')
-			return 0;
-	}
-	if (*s1 > *--s2)
-		return 1;
-	else
-		return -1;
-}
-#endif
-
-/* Verify that two wide strings are equal, dump them if not. */
-int
-assertion_equal_wstring(const char *file, int line,
-    const wchar_t *v1, const char *e1,
-    const wchar_t *v2, const char *e2,
-    void *extra)
-{
-	assertion_count(file, line);
-	if (v1 == v2)
-		return (1);
-	if (v1 != NULL && v2 != NULL && wcscmp(v1, v2) == 0)
-		return (1);
-	failure_start(file, line, "%s != %s", e1, e2);
-	wcsdump(e1, v1);
-	wcsdump(e2, v2);
-	failure_finish(extra);
-	return (0);
-}
-
-/*
- * Pretty standard hexdump routine.  As a bonus, if ref != NULL, then
- * any bytes in p that differ from ref will be highlighted with '_'
- * before and after the hex value.
- */
-static void
-hexdump(const char *p, const char *ref, size_t l, size_t offset)
-{
-	size_t i, j;
-	char sep;
-
-	if (p == NULL) {
-		logprintf("(null)\n");
-		return;
-	}
-	for(i=0; i < l; i+=16) {
-		logprintf("%04x", (unsigned)(i + offset));
-		sep = ' ';
-		for (j = 0; j < 16 && i + j < l; j++) {
-			if (ref != NULL && p[i + j] != ref[i + j])
-				sep = '_';
-			logprintf("%c%02x", sep, 0xff & (int)p[i+j]);
-			if (ref != NULL && p[i + j] == ref[i + j])
-				sep = ' ';
-		}
-		for (; j < 16; j++) {
-			logprintf("%c  ", sep);
-			sep = ' ';
-		}
-		logprintf("%c", sep);
-		for (j=0; j < 16 && i + j < l; j++) {
-			int c = p[i + j];
-			if (c >= ' ' && c <= 126)
-				logprintf("%c", c);
-			else
-				logprintf(".");
-		}
-		logprintf("\n");
-	}
-}
-
-/* Verify that two blocks of memory are the same, display the first
- * block of differences if they're not. */
-int
-assertion_equal_mem(const char *file, int line,
-    const void *_v1, const char *e1,
-    const void *_v2, const char *e2,
-    size_t l, const char *ld, void *extra)
-{
-	const char *v1 = (const char *)_v1;
-	const char *v2 = (const char *)_v2;
-	size_t offset;
-
-	assertion_count(file, line);
-	if (v1 == v2 || (v1 != NULL && v2 != NULL && memcmp(v1, v2, l) == 0))
-		return (1);
-	if (v1 == NULL || v2 == NULL)
-		return (0);
-
-	failure_start(file, line, "%s != %s", e1, e2);
-	logprintf("      size %s = %d\n", ld, (int)l);
-	/* Dump 48 bytes (3 lines) so that the first difference is
-	 * in the second line. */
-	offset = 0;
-	while (l > 64 && memcmp(v1, v2, 32) == 0) {
-		/* Two lines agree, so step forward one line. */
-		v1 += 16;
-		v2 += 16;
-		l -= 16;
-		offset += 16;
-	}
-	logprintf("      Dump of %s\n", e1);
-	hexdump(v1, v2, l < 128 ? l : 128, offset);
-	logprintf("      Dump of %s\n", e2);
-	hexdump(v2, v1, l < 128 ? l : 128, offset);
-	logprintf("\n");
-	failure_finish(extra);
-	return (0);
-}
-
-/* Verify that a block of memory is filled with the specified byte. */
-int
-assertion_memory_filled_with(const char *file, int line,
-    const void *_v1, const char *vd,
-    size_t l, const char *ld,
-    char b, const char *bd, void *extra)
-{
-	const char *v1 = (const char *)_v1;
-	size_t c = 0;
-	size_t i;
-	(void)ld; /* UNUSED */
-
-	assertion_count(file, line);
-
-	for (i = 0; i < l; ++i) {
-		if (v1[i] == b) {
-			++c;
-		}
-	}
-	if (c == l)
-		return (1);
-
-	failure_start(file, line, "%s (size %d) not filled with %s", vd, (int)l, bd);
-	logprintf("   Only %d bytes were correct\n", (int)c);
-	failure_finish(extra);
-	return (0);
-}
-
-/* Verify that the named file exists and is empty. */
-int
-assertion_empty_file(const char *filename, int line, const char *f1)
-{
-	char buff[1024];
-	struct stat st;
-	ssize_t s;
-	FILE *f;
-
-	assertion_count(filename, line);
-
-	if (stat(f1, &st) != 0) {
-		failure_start(filename, line, "Stat failed: %s", f1);
-		failure_finish(NULL);
-		return (0);
-	}
-	if (st.st_size == 0)
-		return (1);
-
-	failure_start(filename, line, "File should be empty: %s", f1);
-	logprintf("    File size: %d\n", (int)st.st_size);
-	logprintf("    Contents:\n");
-	f = fopen(f1, "rb");
-	if (f == NULL) {
-		logprintf("    Unable to open %s\n", f1);
-	} else {
-		s = ((off_t)sizeof(buff) < st.st_size) ?
-		    (ssize_t)sizeof(buff) : (ssize_t)st.st_size;
-		s = fread(buff, 1, s, f);
-		hexdump(buff, NULL, s, 0);
-		fclose(f);
-	}
-	failure_finish(NULL);
-	return (0);
-}
-
-/* Verify that the named file exists and is not empty. */
-int
-assertion_non_empty_file(const char *filename, int line, const char *f1)
-{
-	struct stat st;
-
-	assertion_count(filename, line);
-
-	if (stat(f1, &st) != 0) {
-		failure_start(filename, line, "Stat failed: %s", f1);
-		failure_finish(NULL);
-		return (0);
-	}
-	if (st.st_size == 0) {
-		failure_start(filename, line, "File empty: %s", f1);
-		failure_finish(NULL);
-		return (0);
-	}
-	return (1);
-}
-
-/* Verify that two files have the same contents. */
-/* TODO: hexdump the first bytes that actually differ. */
-int
-assertion_equal_file(const char *filename, int line, const char *fn1, const char *fn2)
-{
-	char buff1[1024];
-	char buff2[1024];
-	FILE *f1, *f2;
-	int n1, n2;
-
-	assertion_count(filename, line);
-
-	f1 = fopen(fn1, "rb");
-	f2 = fopen(fn2, "rb");
-	if (f1 == NULL || f2 == NULL) {
-		if (f1) fclose(f1);
-		if (f2) fclose(f2);
-		return (0);
-	}
-	for (;;) {
-		n1 = (int)fread(buff1, 1, sizeof(buff1), f1);
-		n2 = (int)fread(buff2, 1, sizeof(buff2), f2);
-		if (n1 != n2)
-			break;
-		if (n1 == 0 && n2 == 0) {
-			fclose(f1);
-			fclose(f2);
-			return (1);
-		}
-		if (memcmp(buff1, buff2, n1) != 0)
-			break;
-	}
-	fclose(f1);
-	fclose(f2);
-	failure_start(filename, line, "Files not identical");
-	logprintf("  file1=\"%s\"\n", fn1);
-	logprintf("  file2=\"%s\"\n", fn2);
-	failure_finish(NULL);
-	return (0);
-}
-
-/* Verify that the named file does exist. */
-int
-assertion_file_exists(const char *filename, int line, const char *f)
-{
-	assertion_count(filename, line);
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	if (!_access(f, 0))
-		return (1);
-#else
-	if (!access(f, F_OK))
-		return (1);
-#endif
-	failure_start(filename, line, "File should exist: %s", f);
-	failure_finish(NULL);
-	return (0);
-}
-
-/* Verify that the named file doesn't exist. */
-int
-assertion_file_not_exists(const char *filename, int line, const char *f)
-{
-	assertion_count(filename, line);
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	if (_access(f, 0))
-		return (1);
-#else
-	if (access(f, F_OK))
-		return (1);
-#endif
-	failure_start(filename, line, "File should not exist: %s", f);
-	failure_finish(NULL);
-	return (0);
-}
-
-/* Compare the contents of a file to a block of memory. */
-int
-assertion_file_contents(const char *filename, int line, const void *buff, int s, const char *fn)
-{
-	char *contents;
-	FILE *f;
-	int n;
-
-	assertion_count(filename, line);
-
-	f = fopen(fn, "rb");
-	if (f == NULL) {
-		failure_start(filename, line,
-		    "File should exist: %s", fn);
-		failure_finish(NULL);
-		return (0);
-	}
-	contents = malloc(s * 2);
-	n = (int)fread(contents, 1, s * 2, f);
-	fclose(f);
-	if (n == s && memcmp(buff, contents, s) == 0) {
-		free(contents);
-		return (1);
-	}
-	failure_start(filename, line, "File contents don't match");
-	logprintf("  file=\"%s\"\n", fn);
-	if (n > 0)
-		hexdump(contents, buff, n > 512 ? 512 : n, 0);
-	else {
-		logprintf("  File empty, contents should be:\n");
-		hexdump(buff, NULL, s > 512 ? 512 : s, 0);
-	}
-	failure_finish(NULL);
-	free(contents);
-	return (0);
-}
-
-/* Check the contents of a text file, being tolerant of line endings. */
-int
-assertion_text_file_contents(const char *filename, int line, const char *buff, const char *fn)
-{
-	char *contents;
-	const char *btxt, *ftxt;
-	FILE *f;
-	int n, s;
-
-	assertion_count(filename, line);
-	f = fopen(fn, "r");
-	if (f == NULL) {
-		failure_start(filename, line,
-		    "File doesn't exist: %s", fn);
-		failure_finish(NULL);
-		return (0);
-	}
-	s = (int)strlen(buff);
-	contents = malloc(s * 2 + 128);
-	n = (int)fread(contents, 1, s * 2 + 128 - 1, f);
-	if (n >= 0)
-		contents[n] = '\0';
-	fclose(f);
-	/* Compare texts. */
-	btxt = buff;
-	ftxt = (const char *)contents;
-	while (*btxt != '\0' && *ftxt != '\0') {
-		if (*btxt == *ftxt) {
-			++btxt;
-			++ftxt;
-			continue;
-		}
-		if (btxt[0] == '\n' && ftxt[0] == '\r' && ftxt[1] == '\n') {
-			/* Pass over different new line characters. */
-			++btxt;
-			ftxt += 2;
-			continue;
-		}
-		break;
-	}
-	if (*btxt == '\0' && *ftxt == '\0') {
-		free(contents);
-		return (1);
-	}
-	failure_start(filename, line, "Contents don't match");
-	logprintf("  file=\"%s\"\n", fn);
-	if (n > 0) {
-		hexdump(contents, buff, n, 0);
-		logprintf("  expected\n", fn);
-		hexdump(buff, contents, s, 0);
-	} else {
-		logprintf("  File empty, contents should be:\n");
-		hexdump(buff, NULL, s, 0);
-	}
-	failure_finish(NULL);
-	free(contents);
-	return (0);
-}
-
-/* Verify that a text file contains the specified lines, regardless of order */
-/* This could be more efficient if we sorted both sets of lines, etc, but
- * since this is used only for testing and only ever deals with a dozen or so
- * lines at a time, this relatively crude approach is just fine. */
-int
-assertion_file_contains_lines_any_order(const char *file, int line,
-    const char *pathname, const char *lines[])
-{
-	char *buff;
-	size_t buff_size;
-	size_t expected_count, actual_count, i, j;
-	char **expected = NULL;
-	char *p, **actual = NULL;
-	char c;
-	int expected_failure = 0, actual_failure = 0, retval = 0;
-
-	assertion_count(file, line);
-
-	buff = slurpfile(&buff_size, "%s", pathname);
-	if (buff == NULL) {
-		failure_start(pathname, line, "Can't read file: %s", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-
-	/* Make a copy of the provided lines and count up the expected
-	 * file size. */
-	for (i = 0; lines[i] != NULL; ++i) {
-	}
-	expected_count = i;
-	if (expected_count) {
-		expected = malloc(sizeof(char *) * expected_count);
-		if (expected == NULL) {
-			failure_start(pathname, line, "Can't allocate memory");
-			failure_finish(NULL);
-			goto done;
-		}
-		for (i = 0; lines[i] != NULL; ++i) {
-			expected[i] = strdup(lines[i]);
-		}
-	}
-
-	/* Break the file into lines */
-	actual_count = 0;
-	for (c = '\0', p = buff; p < buff + buff_size; ++p) {
-		if (*p == '\x0d' || *p == '\x0a')
-			*p = '\0';
-		if (c == '\0' && *p != '\0')
-			++actual_count;
-		c = *p;
-	}
-	if (actual_count) {
-		actual = calloc(sizeof(char *), actual_count);
-		if (actual == NULL) {
-			failure_start(pathname, line, "Can't allocate memory");
-			failure_finish(NULL);
-			goto done;
-		}
-		for (j = 0, p = buff; p < buff + buff_size;
-		    p += 1 + strlen(p)) {
-			if (*p != '\0') {
-				actual[j] = p;
-				++j;
-			}
-		}
-	}
-
-	/* Erase matching lines from both lists */
-	for (i = 0; i < expected_count; ++i) {
-		if (expected[i] == NULL)
-			continue;
-		for (j = 0; j < actual_count; ++j) {
-			if (actual[j] == NULL)
-				continue;
-			if (strcmp(expected[i], actual[j]) == 0) {
-				free(expected[i]);
-				expected[i] = NULL;
-				actual[j] = NULL;
-				break;
-			}
-		}
-	}
-
-	/* If there's anything left, it's a failure */
-	for (i = 0; i < expected_count; ++i) {
-		if (expected[i] != NULL)
-			++expected_failure;
-	}
-	for (j = 0; j < actual_count; ++j) {
-		if (actual[j] != NULL)
-			++actual_failure;
-	}
-	if (expected_failure == 0 && actual_failure == 0) {
-		retval = 1;
-		goto done;
-	}
-	failure_start(file, line, "File doesn't match: %s", pathname);
-	for (i = 0; i < expected_count; ++i) {
-		if (expected[i] != NULL)
-			logprintf("  Expected but not present: %s\n", expected[i]);
-	}
-	for (j = 0; j < actual_count; ++j) {
-		if (actual[j] != NULL)
-			logprintf("  Present but not expected: %s\n", actual[j]);
-	}
-	failure_finish(NULL);
-done:
-	free(actual);
-	free(buff);
-	for (i = 0; i < expected_count; ++i)
-		free(expected[i]);
-	free(expected);
-
-	return (retval);
-}
-
-/* Verify that a text file does not contains the specified strings */
-int
-assertion_file_contains_no_invalid_strings(const char *file, int line,
-    const char *pathname, const char *strings[])
-{
-	char *buff;
-	int i;
-
-	buff = slurpfile(NULL, "%s", pathname);
-	if (buff == NULL) {
-		failure_start(file, line, "Can't read file: %s", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-
-	for (i = 0; strings[i] != NULL; ++i) {
-		if (strstr(buff, strings[i]) != NULL) {
-			failure_start(file, line, "Invalid string in %s: %s", pathname,
-			    strings[i]);
-			failure_finish(NULL);
-			free(buff);
-			return(0);
-		}
-	}
-
-	free(buff);
-	return (0);
-}
-
-/* Test that two paths point to the same file. */
-/* As a side-effect, asserts that both files exist. */
-static int
-is_hardlink(const char *file, int line,
-    const char *path1, const char *path2)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	BY_HANDLE_FILE_INFORMATION bhfi1, bhfi2;
-	int r;
-
-	assertion_count(file, line);
-	r = my_GetFileInformationByName(path1, &bhfi1);
-	if (r == 0) {
-		failure_start(file, line, "File %s can't be inspected?", path1);
-		failure_finish(NULL);
-		return (0);
-	}
-	r = my_GetFileInformationByName(path2, &bhfi2);
-	if (r == 0) {
-		failure_start(file, line, "File %s can't be inspected?", path2);
-		failure_finish(NULL);
-		return (0);
-	}
-	return (bhfi1.dwVolumeSerialNumber == bhfi2.dwVolumeSerialNumber
-		&& bhfi1.nFileIndexHigh == bhfi2.nFileIndexHigh
-		&& bhfi1.nFileIndexLow == bhfi2.nFileIndexLow);
-#else
-	struct stat st1, st2;
-	int r;
-
-	assertion_count(file, line);
-	r = lstat(path1, &st1);
-	if (r != 0) {
-		failure_start(file, line, "File should exist: %s", path1);
-		failure_finish(NULL);
-		return (0);
-	}
-	r = lstat(path2, &st2);
-	if (r != 0) {
-		failure_start(file, line, "File should exist: %s", path2);
-		failure_finish(NULL);
-		return (0);
-	}
-	return (st1.st_ino == st2.st_ino && st1.st_dev == st2.st_dev);
-#endif
-}
-
-int
-assertion_is_hardlink(const char *file, int line,
-    const char *path1, const char *path2)
-{
-	if (is_hardlink(file, line, path1, path2))
-		return (1);
-	failure_start(file, line,
-	    "Files %s and %s are not hardlinked", path1, path2);
-	failure_finish(NULL);
-	return (0);
-}
-
-int
-assertion_is_not_hardlink(const char *file, int line,
-    const char *path1, const char *path2)
-{
-	if (!is_hardlink(file, line, path1, path2))
-		return (1);
-	failure_start(file, line,
-	    "Files %s and %s should not be hardlinked", path1, path2);
-	failure_finish(NULL);
-	return (0);
-}
-
-/* Verify a/b/mtime of 'pathname'. */
-/* If 'recent', verify that it's within last 10 seconds. */
-static int
-assertion_file_time(const char *file, int line,
-    const char *pathname, long t, long nsec, char type, int recent)
-{
-	long long filet, filet_nsec;
-	int r;
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-#define EPOC_TIME	(116444736000000000ULL)
-	FILETIME fxtime, fbirthtime, fatime, fmtime;
-	ULARGE_INTEGER wintm;
-	HANDLE h;
-	fxtime.dwLowDateTime = 0;
-	fxtime.dwHighDateTime = 0;
-
-	assertion_count(file, line);
-	/* Note: FILE_FLAG_BACKUP_SEMANTICS applies to open
-	 * a directory file. If not, CreateFile() will fail when
-	 * the pathname is a directory. */
-	h = CreateFile(pathname, FILE_READ_ATTRIBUTES, 0, NULL,
-	    OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
-	if (h == INVALID_HANDLE_VALUE) {
-		failure_start(file, line, "Can't access %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	r = GetFileTime(h, &fbirthtime, &fatime, &fmtime);
-	switch (type) {
-	case 'a': fxtime = fatime; break;
-	case 'b': fxtime = fbirthtime; break;
-	case 'm': fxtime = fmtime; break;
-	}
-	CloseHandle(h);
-	if (r == 0) {
-		failure_start(file, line, "Can't GetFileTime %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	wintm.LowPart = fxtime.dwLowDateTime;
-	wintm.HighPart = fxtime.dwHighDateTime;
-	filet = (wintm.QuadPart - EPOC_TIME) / 10000000;
-	filet_nsec = ((wintm.QuadPart - EPOC_TIME) % 10000000) * 100;
-	nsec = (nsec / 100) * 100; /* Round the request */
-#else
-	struct stat st;
-
-	assertion_count(file, line);
-	r = lstat(pathname, &st);
-	if (r != 0) {
-		failure_start(file, line, "Can't stat %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	switch (type) {
-	case 'a': filet = st.st_atime; break;
-	case 'm': filet = st.st_mtime; break;
-	case 'b': filet = 0; break;
-	default: fprintf(stderr, "INTERNAL: Bad type %c for file time", type);
-		exit(1);
-	}
-#if defined(__FreeBSD__)
-	switch (type) {
-	case 'a': filet_nsec = st.st_atimespec.tv_nsec; break;
-	case 'b': filet = st.st_birthtime;
-		/* FreeBSD filesystems that don't support birthtime
-		 * (e.g., UFS1) always return -1 here. */
-		if (filet == -1) {
-			return (1);
-		}
-		filet_nsec = st.st_birthtimespec.tv_nsec; break;
-	case 'm': filet_nsec = st.st_mtimespec.tv_nsec; break;
-	default: fprintf(stderr, "INTERNAL: Bad type %c for file time", type);
-		exit(1);
-	}
-	/* FreeBSD generally only stores to microsecond res, so round. */
-	filet_nsec = (filet_nsec / 1000) * 1000;
-	nsec = (nsec / 1000) * 1000;
-#else
-	filet_nsec = nsec = 0;	/* Generic POSIX only has whole seconds. */
-	if (type == 'b') return (1); /* Generic POSIX doesn't have birthtime */
-#if defined(__HAIKU__)
-	if (type == 'a') return (1); /* Haiku doesn't have atime. */
-#endif
-#endif
-#endif
-	if (recent) {
-		/* Check that requested time is up-to-date. */
-		time_t now = time(NULL);
-		if (filet < now - 10 || filet > now + 1) {
-			failure_start(file, line,
-			    "File %s has %ctime %lld, %lld seconds ago\n",
-			    pathname, type, filet, now - filet);
-			failure_finish(NULL);
-			return (0);
-		}
-	} else if (filet != t || filet_nsec != nsec) {
-		failure_start(file, line,
-		    "File %s has %ctime %lld.%09lld, expected %lld.%09lld",
-		    pathname, type, filet, filet_nsec, t, nsec);
-		failure_finish(NULL);
-		return (0);
-	}
-	return (1);
-}
-
-/* Verify atime of 'pathname'. */
-int
-assertion_file_atime(const char *file, int line,
-    const char *pathname, long t, long nsec)
-{
-	return assertion_file_time(file, line, pathname, t, nsec, 'a', 0);
-}
-
-/* Verify atime of 'pathname' is up-to-date. */
-int
-assertion_file_atime_recent(const char *file, int line, const char *pathname)
-{
-	return assertion_file_time(file, line, pathname, 0, 0, 'a', 1);
-}
-
-/* Verify birthtime of 'pathname'. */
-int
-assertion_file_birthtime(const char *file, int line,
-    const char *pathname, long t, long nsec)
-{
-	return assertion_file_time(file, line, pathname, t, nsec, 'b', 0);
-}
-
-/* Verify birthtime of 'pathname' is up-to-date. */
-int
-assertion_file_birthtime_recent(const char *file, int line,
-    const char *pathname)
-{
-	return assertion_file_time(file, line, pathname, 0, 0, 'b', 1);
-}
-
-/* Verify mode of 'pathname'. */
-int
-assertion_file_mode(const char *file, int line, const char *pathname, int expected_mode)
-{
-	int mode;
-	int r;
-
-	assertion_count(file, line);
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	failure_start(file, line, "assertFileMode not yet implemented for Windows");
-	(void)mode; /* UNUSED */
-	(void)r; /* UNUSED */
-#else
-	{
-		struct stat st;
-		r = lstat(pathname, &st);
-		mode = (int)(st.st_mode & 0777);
-	}
-	if (r == 0 && mode == expected_mode)
-			return (1);
-	failure_start(file, line, "File %s has mode %o, expected %o",
-	    pathname, mode, expected_mode);
-#endif
-	failure_finish(NULL);
-	return (0);
-}
-
-/* Verify mtime of 'pathname'. */
-int
-assertion_file_mtime(const char *file, int line,
-    const char *pathname, long t, long nsec)
-{
-	return assertion_file_time(file, line, pathname, t, nsec, 'm', 0);
-}
-
-/* Verify mtime of 'pathname' is up-to-date. */
-int
-assertion_file_mtime_recent(const char *file, int line, const char *pathname)
-{
-	return assertion_file_time(file, line, pathname, 0, 0, 'm', 1);
-}
-
-/* Verify number of links to 'pathname'. */
-int
-assertion_file_nlinks(const char *file, int line,
-    const char *pathname, int nlinks)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	BY_HANDLE_FILE_INFORMATION bhfi;
-	int r;
-
-	assertion_count(file, line);
-	r = my_GetFileInformationByName(pathname, &bhfi);
-	if (r != 0 && bhfi.nNumberOfLinks == (DWORD)nlinks)
-		return (1);
-	failure_start(file, line, "File %s has %d links, expected %d",
-	    pathname, bhfi.nNumberOfLinks, nlinks);
-	failure_finish(NULL);
-	return (0);
-#else
-	struct stat st;
-	int r;
-
-	assertion_count(file, line);
-	r = lstat(pathname, &st);
-	if (r == 0 && (int)st.st_nlink == nlinks)
-		return (1);
-	failure_start(file, line, "File %s has %d links, expected %d",
-	    pathname, st.st_nlink, nlinks);
-	failure_finish(NULL);
-	return (0);
-#endif
-}
-
-/* Verify size of 'pathname'. */
-int
-assertion_file_size(const char *file, int line, const char *pathname, long size)
-{
-	int64_t filesize;
-	int r;
-
-	assertion_count(file, line);
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	{
-		BY_HANDLE_FILE_INFORMATION bhfi;
-		r = !my_GetFileInformationByName(pathname, &bhfi);
-		filesize = ((int64_t)bhfi.nFileSizeHigh << 32) + bhfi.nFileSizeLow;
-	}
-#else
-	{
-		struct stat st;
-		r = lstat(pathname, &st);
-		filesize = st.st_size;
-	}
-#endif
-	if (r == 0 && filesize == size)
-			return (1);
-	failure_start(file, line, "File %s has size %ld, expected %ld",
-	    pathname, (long)filesize, (long)size);
-	failure_finish(NULL);
-	return (0);
-}
-
-/* Assert that 'pathname' is a dir.  If mode >= 0, verify that too. */
-int
-assertion_is_dir(const char *file, int line, const char *pathname, int mode)
-{
-	struct stat st;
-	int r;
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	(void)mode; /* UNUSED */
-#endif
-	assertion_count(file, line);
-	r = lstat(pathname, &st);
-	if (r != 0) {
-		failure_start(file, line, "Dir should exist: %s", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	if (!S_ISDIR(st.st_mode)) {
-		failure_start(file, line, "%s is not a dir", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-#if !defined(_WIN32) || defined(__CYGWIN__)
-	/* Windows doesn't handle permissions the same way as POSIX,
-	 * so just ignore the mode tests. */
-	/* TODO: Can we do better here? */
-	if (mode >= 0 && (mode_t)mode != (st.st_mode & 07777)) {
-		failure_start(file, line, "Dir %s has wrong mode", pathname);
-		logprintf("  Expected: 0%3o\n", mode);
-		logprintf("  Found: 0%3o\n", st.st_mode & 07777);
-		failure_finish(NULL);
-		return (0);
-	}
-#endif
-	return (1);
-}
-
-/* Verify that 'pathname' is a regular file.  If 'mode' is >= 0,
- * verify that too. */
-int
-assertion_is_reg(const char *file, int line, const char *pathname, int mode)
-{
-	struct stat st;
-	int r;
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	(void)mode; /* UNUSED */
-#endif
-	assertion_count(file, line);
-	r = lstat(pathname, &st);
-	if (r != 0 || !S_ISREG(st.st_mode)) {
-		failure_start(file, line, "File should exist: %s", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-#if !defined(_WIN32) || defined(__CYGWIN__)
-	/* Windows doesn't handle permissions the same way as POSIX,
-	 * so just ignore the mode tests. */
-	/* TODO: Can we do better here? */
-	if (mode >= 0 && (mode_t)mode != (st.st_mode & 07777)) {
-		failure_start(file, line, "File %s has wrong mode", pathname);
-		logprintf("  Expected: 0%3o\n", mode);
-		logprintf("  Found: 0%3o\n", st.st_mode & 07777);
-		failure_finish(NULL);
-		return (0);
-	}
-#endif
-	return (1);
-}
-
-/* Check whether 'pathname' is a symbolic link.  If 'contents' is
- * non-NULL, verify that the symlink has those contents. */
-static int
-is_symlink(const char *file, int line,
-    const char *pathname, const char *contents)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	(void)pathname; /* UNUSED */
-	(void)contents; /* UNUSED */
-	assertion_count(file, line);
-	/* Windows sort-of has real symlinks, but they're only usable
-	 * by privileged users and are crippled even then, so there's
-	 * really not much point in bothering with this. */
-	return (0);
-#else
-	char buff[301];
-	struct stat st;
-	ssize_t linklen;
-	int r;
-
-	assertion_count(file, line);
-	r = lstat(pathname, &st);
-	if (r != 0) {
-		failure_start(file, line,
-		    "Symlink should exist: %s", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	if (!S_ISLNK(st.st_mode))
-		return (0);
-	if (contents == NULL)
-		return (1);
-	linklen = readlink(pathname, buff, sizeof(buff) - 1);
-	if (linklen < 0) {
-		failure_start(file, line, "Can't read symlink %s", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	buff[linklen] = '\0';
-	if (strcmp(buff, contents) != 0)
-		return (0);
-	return (1);
-#endif
-}
-
-/* Assert that path is a symlink that (optionally) contains contents. */
-int
-assertion_is_symlink(const char *file, int line,
-    const char *path, const char *contents)
-{
-	if (is_symlink(file, line, path, contents))
-		return (1);
-	if (contents)
-		failure_start(file, line, "File %s is not a symlink to %s",
-		    path, contents);
-	else
-		failure_start(file, line, "File %s is not a symlink", path);
-	failure_finish(NULL);
-	return (0);
-}
-
-
-/* Create a directory and report any errors. */
-int
-assertion_make_dir(const char *file, int line, const char *dirname, int mode)
-{
-	assertion_count(file, line);
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	(void)mode; /* UNUSED */
-	if (0 == _mkdir(dirname))
-		return (1);
-#else
-	if (0 == mkdir(dirname, mode)) {
-		if (0 == chmod(dirname, mode)) {
-			assertion_file_mode(file, line, dirname, mode);
-			return (1);
-		}
-	}
-#endif
-	failure_start(file, line, "Could not create directory %s", dirname);
-	failure_finish(NULL);
-	return(0);
-}
-
-/* Create a file with the specified contents and report any failures. */
-int
-assertion_make_file(const char *file, int line,
-    const char *path, int mode, int csize, const void *contents)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	/* TODO: Rework this to set file mode as well. */
-	FILE *f;
-	(void)mode; /* UNUSED */
-	assertion_count(file, line);
-	f = fopen(path, "wb");
-	if (f == NULL) {
-		failure_start(file, line, "Could not create file %s", path);
-		failure_finish(NULL);
-		return (0);
-	}
-	if (contents != NULL) {
-		size_t wsize;
-
-		if (csize < 0)
-			wsize = strlen(contents);
-		else
-			wsize = (size_t)csize;
-		if (wsize != fwrite(contents, 1, wsize, f)) {
-			fclose(f);
-			failure_start(file, line,
-			    "Could not write file %s", path);
-			failure_finish(NULL);
-			return (0);
-		}
-	}
-	fclose(f);
-	return (1);
-#else
-	int fd;
-	assertion_count(file, line);
-	fd = open(path, O_CREAT | O_WRONLY, mode >= 0 ? mode : 0644);
-	if (fd < 0) {
-		failure_start(file, line, "Could not create %s", path);
-		failure_finish(NULL);
-		return (0);
-	}
-	if (0 != chmod(path, mode)) {
-		failure_start(file, line, "Could not chmod %s", path);
-		failure_finish(NULL);
-		close(fd);
-		return (0);
-	}
-	if (contents != NULL) {
-		ssize_t wsize;
-
-		if (csize < 0)
-			wsize = (ssize_t)strlen(contents);
-		else
-			wsize = (ssize_t)csize;
-		if (wsize != write(fd, contents, wsize)) {
-			close(fd);
-			failure_start(file, line,
-			    "Could not write to %s", path);
-			failure_finish(NULL);
-			close(fd);
-			return (0);
-		}
-	}
-	close(fd);
-	assertion_file_mode(file, line, path, mode);
-	return (1);
-#endif
-}
-
-/* Create a hardlink and report any failures. */
-int
-assertion_make_hardlink(const char *file, int line,
-    const char *newpath, const char *linkto)
-{
-	int succeeded;
-
-	assertion_count(file, line);
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	succeeded = my_CreateHardLinkA(newpath, linkto);
-#elif HAVE_LINK
-	succeeded = !link(linkto, newpath);
-#else
-	succeeded = 0;
-#endif
-	if (succeeded)
-		return (1);
-	failure_start(file, line, "Could not create hardlink");
-	logprintf("   New link: %s\n", newpath);
-	logprintf("   Old name: %s\n", linkto);
-	failure_finish(NULL);
-	return(0);
-}
-
-/* Create a symlink and report any failures. */
-int
-assertion_make_symlink(const char *file, int line,
-    const char *newpath, const char *linkto)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	int targetIsDir = 0;  /* TODO: Fix this */
-	assertion_count(file, line);
-	if (my_CreateSymbolicLinkA(newpath, linkto, targetIsDir))
-		return (1);
-#elif HAVE_SYMLINK
-	assertion_count(file, line);
-	if (0 == symlink(linkto, newpath))
-		return (1);
-#endif
-	failure_start(file, line, "Could not create symlink");
-	logprintf("   New link: %s\n", newpath);
-	logprintf("   Old name: %s\n", linkto);
-	failure_finish(NULL);
-	return(0);
-}
-
-/* Set umask, report failures. */
-int
-assertion_umask(const char *file, int line, int mask)
-{
-	assertion_count(file, line);
-	(void)file; /* UNUSED */
-	(void)line; /* UNUSED */
-	umask(mask);
-	return (1);
-}
-
-/* Set times, report failures. */
-int
-assertion_utimes(const char *file, int line,
-    const char *pathname, long at, long at_nsec, long mt, long mt_nsec)
-{
-	int r;
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-#define WINTIME(sec, nsec) ((Int32x32To64(sec, 10000000) + EPOC_TIME)\
-	 + (((nsec)/1000)*10))
-	HANDLE h;
-	ULARGE_INTEGER wintm;
-	FILETIME fatime, fmtime;
-	FILETIME *pat, *pmt;
-
-	assertion_count(file, line);
-	h = CreateFileA(pathname,GENERIC_READ | GENERIC_WRITE,
-		    FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
-		    FILE_FLAG_BACKUP_SEMANTICS, NULL);
-	if (h == INVALID_HANDLE_VALUE) {
-		failure_start(file, line, "Can't access %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-
-	if (at > 0 || at_nsec > 0) {
-		wintm.QuadPart = WINTIME(at, at_nsec);
-		fatime.dwLowDateTime = wintm.LowPart;
-		fatime.dwHighDateTime = wintm.HighPart;
-		pat = &fatime;
-	} else
-		pat = NULL;
-	if (mt > 0 || mt_nsec > 0) {
-		wintm.QuadPart = WINTIME(mt, mt_nsec);
-		fmtime.dwLowDateTime = wintm.LowPart;
-		fmtime.dwHighDateTime = wintm.HighPart;
-		pmt = &fmtime;
-	} else
-		pmt = NULL;
-	if (pat != NULL || pmt != NULL)
-		r = SetFileTime(h, NULL, pat, pmt);
-	else
-		r = 1;
-	CloseHandle(h);
-	if (r == 0) {
-		failure_start(file, line, "Can't SetFileTime %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	return (1);
-#else /* defined(_WIN32) && !defined(__CYGWIN__) */
-	struct stat st;
-	struct timeval times[2];
-
-#if !defined(__FreeBSD__)
-	mt_nsec = at_nsec = 0;	/* Generic POSIX only has whole seconds. */
-#endif
-	if (mt == 0 && mt_nsec == 0 && at == 0 && at_nsec == 0)
-		return (1);
-
-	r = lstat(pathname, &st);
-	if (r < 0) {
-		failure_start(file, line, "Can't stat %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-
-	if (mt == 0 && mt_nsec == 0) {
-		mt = st.st_mtime;
-#if defined(__FreeBSD__)
-		mt_nsec = st.st_mtimespec.tv_nsec;
-		/* FreeBSD generally only stores to microsecond res, so round. */
-		mt_nsec = (mt_nsec / 1000) * 1000;
-#endif
-	}
-	if (at == 0 && at_nsec == 0) {
-		at = st.st_atime;
-#if defined(__FreeBSD__)
-		at_nsec = st.st_atimespec.tv_nsec;
-		/* FreeBSD generally only stores to microsecond res, so round. */
-		at_nsec = (at_nsec / 1000) * 1000;
-#endif
-	}
-
-	times[1].tv_sec = mt;
-	times[1].tv_usec = mt_nsec / 1000;
-
-	times[0].tv_sec = at;
-	times[0].tv_usec = at_nsec / 1000;
-
-#ifdef HAVE_LUTIMES
-	r = lutimes(pathname, times);
-#else
-	r = utimes(pathname, times);
-#endif
-	if (r < 0) {
-		failure_start(file, line, "Can't utimes %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	return (1);
-#endif /* defined(_WIN32) && !defined(__CYGWIN__) */
-}
-
-/* Set nodump, report failures. */
-int
-assertion_nodump(const char *file, int line, const char *pathname)
-{
-#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP)
-	int r;
-
-	assertion_count(file, line);
-	r = chflags(pathname, UF_NODUMP);
-	if (r < 0) {
-		failure_start(file, line, "Can't set nodump %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-#elif defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)\
-	 && defined(EXT2_NODUMP_FL)
-	int fd, r, flags;
-
-	assertion_count(file, line);
-	fd = open(pathname, O_RDONLY | O_NONBLOCK);
-	if (fd < 0) {
-		failure_start(file, line, "Can't open %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags);
-	if (r < 0) {
-		failure_start(file, line, "Can't get flags %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	flags |= EXT2_NODUMP_FL;
-	r = ioctl(fd, EXT2_IOC_SETFLAGS, &flags);
-	if (r < 0) {
-		failure_start(file, line, "Can't set nodump %s\n", pathname);
-		failure_finish(NULL);
-		return (0);
-	}
-	close(fd);
-#else
-	(void)pathname; /* UNUSED */
-	assertion_count(file, line);
-#endif
-	return (1);
-}
-
-/*
- *
- *  UTILITIES for use by tests.
- *
- */
-
-/*
- * Check whether platform supports symlinks.  This is intended
- * for tests to use in deciding whether to bother testing symlink
- * support; if the platform doesn't support symlinks, there's no point
- * in checking whether the program being tested can create them.
- *
- * Note that the first time this test is called, we actually go out to
- * disk to create and verify a symlink.  This is necessary because
- * symlink support is actually a property of a particular filesystem
- * and can thus vary between directories on a single system.  After
- * the first call, this returns the cached result from memory, so it's
- * safe to call it as often as you wish.
- */
-int
-canSymlink(void)
-{
-	/* Remember the test result */
-	static int value = 0, tested = 0;
-	if (tested)
-		return (value);
-
-	++tested;
-	assertion_make_file(__FILE__, __LINE__, "canSymlink.0", 0644, 1, "a");
-	/* Note: Cygwin has its own symlink() emulation that does not
-	 * use the Win32 CreateSymbolicLink() function. */
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	value = my_CreateSymbolicLinkA("canSymlink.1", "canSymlink.0", 0)
-	    && is_symlink(__FILE__, __LINE__, "canSymlink.1", "canSymlink.0");
-#elif HAVE_SYMLINK
-	value = (0 == symlink("canSymlink.0", "canSymlink.1"))
-	    && is_symlink(__FILE__, __LINE__, "canSymlink.1","canSymlink.0");
-#endif
-	return (value);
-}
-
-/* Platform-dependent options for hiding the output of a subcommand. */
-#if defined(_WIN32) && !defined(__CYGWIN__)
-static const char *redirectArgs = ">NUL 2>NUL"; /* Win32 cmd.exe */
-#else
-static const char *redirectArgs = ">/dev/null 2>/dev/null"; /* POSIX 'sh' */
-#endif
-/*
- * Can this platform run the bzip2 program?
- */
-int
-canBzip2(void)
-{
-	static int tested = 0, value = 0;
-	if (!tested) {
-		tested = 1;
-		if (systemf("bzip2 -d -V %s", redirectArgs) == 0)
-			value = 1;
-	}
-	return (value);
-}
-
-/*
- * Can this platform run the grzip program?
- */
-int
-canGrzip(void)
-{
-	static int tested = 0, value = 0;
-	if (!tested) {
-		tested = 1;
-		if (systemf("grzip -V %s", redirectArgs) == 0)
-			value = 1;
-	}
-	return (value);
-}
-
-/*
- * Can this platform run the gzip program?
- */
-int
-canGzip(void)
-{
-	static int tested = 0, value = 0;
-	if (!tested) {
-		tested = 1;
-		if (systemf("gzip -V %s", redirectArgs) == 0)
-			value = 1;
-	}
-	return (value);
-}
-
-/*
- * Can this platform run the lrzip program?
- */
-int
-canRunCommand(const char *cmd)
-{
-  static int tested = 0, value = 0;
-  if (!tested) {
-    tested = 1;
-    if (systemf("%s %s", cmd, redirectArgs) == 0)
-      value = 1;
-  }
-  return (value);
-}
-
-int
-canLrzip(void)
-{
-	static int tested = 0, value = 0;
-	if (!tested) {
-		tested = 1;
-		if (systemf("lrzip -V %s", redirectArgs) == 0)
-			value = 1;
-	}
-	return (value);
-}
-
-/*
- * Can this platform run the lz4 program?
- */
-int
-canLz4(void)
-{
-	static int tested = 0, value = 0;
-	if (!tested) {
-		tested = 1;
-		if (systemf("lz4 -V %s", redirectArgs) == 0)
-			value = 1;
-	}
-	return (value);
-}
-
-/*
- * Can this platform run the lzip program?
- */
-int
-canLzip(void)
-{
-	static int tested = 0, value = 0;
-	if (!tested) {
-		tested = 1;
-		if (systemf("lzip -V %s", redirectArgs) == 0)
-			value = 1;
-	}
-	return (value);
-}
-
-/*
- * Can this platform run the lzma program?
- */
-int
-canLzma(void)
-{
-	static int tested = 0, value = 0;
-	if (!tested) {
-		tested = 1;
-		if (systemf("lzma -V %s", redirectArgs) == 0)
-			value = 1;
-	}
-	return (value);
-}
-
-/*
- * Can this platform run the lzop program?
- */
-int
-canLzop(void)
-{
-	static int tested = 0, value = 0;
-	if (!tested) {
-		tested = 1;
-		if (systemf("lzop -V %s", redirectArgs) == 0)
-			value = 1;
-	}
-	return (value);
-}
-
-/*
- * Can this platform run the xz program?
- */
-int
-canXz(void)
-{
-	static int tested = 0, value = 0;
-	if (!tested) {
-		tested = 1;
-		if (systemf("xz -V %s", redirectArgs) == 0)
-			value = 1;
-	}
-	return (value);
-}
-
-/*
- * Can this filesystem handle nodump flags.
- */
-#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP)
-
-int
-canNodump(void)
-{
-	const char *path = "cannodumptest";
-	struct stat sb;
-
-	assertion_make_file(__FILE__, __LINE__, path, 0644, 0, NULL);
-	if (chflags(path, UF_NODUMP) < 0)
-		return (0);
-	if (stat(path, &sb) < 0)
-		return (0);
-	if (sb.st_flags & UF_NODUMP)
-		return (1);
-	return (0);
-}
-
-#elif defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)\
-	 && defined(EXT2_NODUMP_FL)
-
-int
-canNodump(void)
-{
-	const char *path = "cannodumptest";
-	int fd, r, flags;
-
-	assertion_make_file(__FILE__, __LINE__, path, 0644, 0, NULL);
-	fd = open(path, O_RDONLY | O_NONBLOCK);
-	if (fd < 0)
-		return (0);
-	r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags);
-	if (r < 0)
-		return (0);
-	flags |= EXT2_NODUMP_FL;
-	r = ioctl(fd, EXT2_IOC_SETFLAGS, &flags);
-	if (r < 0)
-		return (0);
-	close(fd);
-	fd = open(path, O_RDONLY | O_NONBLOCK);
-	if (fd < 0)
-		return (0);
-	r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags);
-	if (r < 0)
-		return (0);
-	close(fd);
-	if (flags & EXT2_NODUMP_FL)
-		return (1);
-	return (0);
-}
-
-#else
-
-int
-canNodump()
-{
-	return (0);
-}
-
-#endif
-
-/*
- * Sleep as needed; useful for verifying disk timestamp changes by
- * ensuring that the wall-clock time has actually changed before we
- * go back to re-read something from disk.
- */
-void
-sleepUntilAfter(time_t t)
-{
-	while (t >= time(NULL))
-#if defined(_WIN32) && !defined(__CYGWIN__)
-		Sleep(500);
-#else
-		sleep(1);
-#endif
-}
-
-/*
- * Call standard system() call, but build up the command line using
- * sprintf() conventions.
- */
-int
-systemf(const char *fmt, ...)
-{
-	char buff[8192];
-	va_list ap;
-	int r;
-
-	va_start(ap, fmt);
-	vsprintf(buff, fmt, ap);
-	if (verbosity > VERBOSITY_FULL)
-		logprintf("Cmd: %s\n", buff);
-	r = system(buff);
-	va_end(ap);
-	return (r);
-}
-
-/*
- * Slurp a file into memory for ease of comparison and testing.
- * Returns size of file in 'sizep' if non-NULL, null-terminates
- * data in memory for ease of use.
- */
-char *
-slurpfile(size_t * sizep, const char *fmt, ...)
-{
-	char filename[8192];
-	struct stat st;
-	va_list ap;
-	char *p;
-	ssize_t bytes_read;
-	FILE *f;
-	int r;
-
-	va_start(ap, fmt);
-	vsprintf(filename, fmt, ap);
-	va_end(ap);
-
-	f = fopen(filename, "rb");
-	if (f == NULL) {
-		/* Note: No error; non-existent file is okay here. */
-		return (NULL);
-	}
-	r = fstat(fileno(f), &st);
-	if (r != 0) {
-		logprintf("Can't stat file %s\n", filename);
-		fclose(f);
-		return (NULL);
-	}
-	p = malloc((size_t)st.st_size + 1);
-	if (p == NULL) {
-		logprintf("Can't allocate %ld bytes of memory to read file %s\n",
-		    (long int)st.st_size, filename);
-		fclose(f);
-		return (NULL);
-	}
-	bytes_read = fread(p, 1, (size_t)st.st_size, f);
-	if (bytes_read < st.st_size) {
-		logprintf("Can't read file %s\n", filename);
-		fclose(f);
-		free(p);
-		return (NULL);
-	}
-	p[st.st_size] = '\0';
-	if (sizep != NULL)
-		*sizep = (size_t)st.st_size;
-	fclose(f);
-	return (p);
-}
-
-/*
- * Slurp a file into memory for ease of comparison and testing.
- * Returns size of file in 'sizep' if non-NULL, null-terminates
- * data in memory for ease of use.
- */
-void
-dumpfile(const char *filename, void *data, size_t len)
-{
-	ssize_t bytes_written;
-	FILE *f;
-
-	f = fopen(filename, "wb");
-	if (f == NULL) {
-		logprintf("Can't open file %s for writing\n", filename);
-		return;
-	}
-	bytes_written = fwrite(data, 1, len, f);
-	if (bytes_written < (ssize_t)len)
-		logprintf("Can't write file %s\n", filename);
-	fclose(f);
-}
-
-/* Read a uuencoded file from the reference directory, decode, and
- * write the result into the current directory. */
-#define VALID_UUDECODE(c) (c >= 32 && c <= 96)
-#define	UUDECODE(c) (((c) - 0x20) & 0x3f)
-void
-extract_reference_file(const char *name)
-{
-	char buff[1024];
-	FILE *in, *out;
-
-	sprintf(buff, "%s/%s.uu", refdir, name);
-	in = fopen(buff, "r");
-	failure("Couldn't open reference file %s", buff);
-	assert(in != NULL);
-	if (in == NULL)
-		return;
-	/* Read up to and including the 'begin' line. */
-	for (;;) {
-		if (fgets(buff, sizeof(buff), in) == NULL) {
-			/* TODO: This is a failure. */
-			goto done;
-		}
-		if (memcmp(buff, "begin ", 6) == 0)
-			break;
-	}
-	/* Now, decode the rest and write it. */
-	out = fopen(name, "wb");
-	while (fgets(buff, sizeof(buff), in) != NULL) {
-		char *p = buff;
-		int bytes;
-
-		if (memcmp(buff, "end", 3) == 0)
-			break;
-
-		bytes = UUDECODE(*p++);
-		while (bytes > 0) {
-			int n = 0;
-			/* Write out 1-3 bytes from that. */
-			if (bytes > 0) {
-				assert(VALID_UUDECODE(p[0]));
-				assert(VALID_UUDECODE(p[1]));
-				n = UUDECODE(*p++) << 18;
-				n |= UUDECODE(*p++) << 12;
-				fputc(n >> 16, out);
-				--bytes;
-			}
-			if (bytes > 0) {
-				assert(VALID_UUDECODE(p[0]));
-				n |= UUDECODE(*p++) << 6;
-				fputc((n >> 8) & 0xFF, out);
-				--bytes;
-			}
-			if (bytes > 0) {
-				assert(VALID_UUDECODE(p[0]));
-				n |= UUDECODE(*p++);
-				fputc(n & 0xFF, out);
-				--bytes;
-			}
-		}
-	}
-	fclose(out);
-done:
-	fclose(in);
-}
-
-void
-copy_reference_file(const char *name)
-{
-	char buff[1024];
-	FILE *in, *out;
-	size_t rbytes;
-
-	sprintf(buff, "%s/%s", refdir, name);
-	in = fopen(buff, "rb");
-	failure("Couldn't open reference file %s", buff);
-	assert(in != NULL);
-	if (in == NULL)
-		return;
-	/* Now, decode the rest and write it. */
-	/* Not a lot of error checking here; the input better be right. */
-	out = fopen(name, "wb");
-	while ((rbytes = fread(buff, 1, sizeof(buff), in)) > 0) {
-		if (fwrite(buff, 1, rbytes, out) != rbytes) {
-			logprintf("Error: fwrite\n");
-			break;
-		}
-	}
-	fclose(out);
-	fclose(in);
-}
-
-int
-is_LargeInode(const char *file)
-{
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	BY_HANDLE_FILE_INFORMATION bhfi;
-	int r;
-
-	r = my_GetFileInformationByName(file, &bhfi);
-	if (r != 0)
-		return (0);
-	return (bhfi.nFileIndexHigh & 0x0000FFFFUL);
-#else
-	struct stat st;
-	int64_t ino;
-
-	if (stat(file, &st) < 0)
-		return (0);
-	ino = (int64_t)st.st_ino;
-	return (ino > 0xffffffff);
-#endif
-}
-
-void
-extract_reference_files(const char **names)
-{
-	while (names && *names)
-		extract_reference_file(*names++);
-}
-
-/*
- *
- * TEST management
- *
- */
-
-/*
- * "list.h" is simply created by "grep DEFINE_TEST test_*.c"; it has
- * a line like
- *      DEFINE_TEST(test_function)
- * for each test.
- */
-
-/* Use "list.h" to declare all of the test functions. */
-#undef DEFINE_TEST
-#define	DEFINE_TEST(name) void name(void);
-#include "list.h"
-
-/* Use "list.h" to create a list of all tests (functions and names). */
-#undef DEFINE_TEST
-#define	DEFINE_TEST(n) { n, #n, 0 },
-struct test_list_t tests[] = {
-	#include "list.h"
-};
-
-/*
- * Summarize repeated failures in the just-completed test.
- */
-static void
-test_summarize(int failed, int skips_num)
-{
-	unsigned int i;
-
-	switch (verbosity) {
-	case VERBOSITY_SUMMARY_ONLY:
-		printf(failed ? "E" : ".");
-		fflush(stdout);
-		break;
-	case VERBOSITY_PASSFAIL:
-		printf(failed ? "FAIL\n" : skips_num ? "ok (S)\n" : "ok\n");
-		break;
-	}
-
-	log_console = (verbosity == VERBOSITY_LIGHT_REPORT);
-
-	for (i = 0; i < sizeof(failed_lines)/sizeof(failed_lines[0]); i++) {
-		if (failed_lines[i].count > 1 && !failed_lines[i].skip)
-			logprintf("%s:%d: Summary: Failed %d times\n",
-			    failed_filename, i, failed_lines[i].count);
-	}
-	/* Clear the failure history for the next file. */
-	failed_filename = NULL;
-	memset(failed_lines, 0, sizeof(failed_lines));
-}
-
-/*
- * Actually run a single test, with appropriate setup and cleanup.
- */
-static int
-test_run(int i, const char *tmpdir)
-{
-	char workdir[1024];
-	char logfilename[64];
-	int failures_before = failures;
-	int skips_before = skips;
-	int oldumask;
-
-	switch (verbosity) {
-	case VERBOSITY_SUMMARY_ONLY: /* No per-test reports at all */
-		break;
-	case VERBOSITY_PASSFAIL: /* rest of line will include ok/FAIL marker */
-		printf("%3d: %-64s", i, tests[i].name);
-		fflush(stdout);
-		break;
-	default: /* Title of test, details will follow */
-		printf("%3d: %s\n", i, tests[i].name);
-	}
-
-	/* Chdir to the top-level work directory. */
-	if (!assertChdir(tmpdir)) {
-		fprintf(stderr,
-		    "ERROR: Can't chdir to top work dir %s\n", tmpdir);
-		exit(1);
-	}
-	/* Create a log file for this test. */
-	sprintf(logfilename, "%s.log", tests[i].name);
-	logfile = fopen(logfilename, "w");
-	fprintf(logfile, "%s\n\n", tests[i].name);
-	/* Chdir() to a work dir for this specific test. */
-	snprintf(workdir, sizeof(workdir), "%s/%s", tmpdir, tests[i].name);
-	testworkdir = workdir;
-	if (!assertMakeDir(testworkdir, 0755)
-	    || !assertChdir(testworkdir)) {
-		fprintf(stderr,
-		    "ERROR: Can't chdir to work dir %s\n", testworkdir);
-		exit(1);
-	}
-	/* Explicitly reset the locale before each test. */
-	setlocale(LC_ALL, "C");
-	/* Record the umask before we run the test. */
-	umask(oldumask = umask(0));
-	/*
-	 * Run the actual test.
-	 */
-	(*tests[i].func)();
-	/*
-	 * Clean up and report afterwards.
-	 */
-	testworkdir = NULL;
-	/* Restore umask */
-	umask(oldumask);
-	/* Reset locale. */
-	setlocale(LC_ALL, "C");
-	/* Reset directory. */
-	if (!assertChdir(tmpdir)) {
-		fprintf(stderr, "ERROR: Couldn't chdir to temp dir %s\n",
-		    tmpdir);
-		exit(1);
-	}
-	/* Report per-test summaries. */
-	tests[i].failures = failures - failures_before;
-	test_summarize(tests[i].failures, skips - skips_before);
-	/* Close the per-test log file. */
-	fclose(logfile);
-	logfile = NULL;
-	/* If there were no failures, we can remove the work dir and logfile. */
-	if (tests[i].failures == 0) {
-		if (!keep_temp_files && assertChdir(tmpdir)) {
-#if defined(_WIN32) && !defined(__CYGWIN__)
-			/* Make sure not to leave empty directories.
-			 * Sometimes a processing of closing files used by tests
-			 * is not done, then rmdir will be failed and it will
-			 * leave a empty test directory. So we should wait a few
-			 * seconds and retry rmdir. */
-			int r, t;
-			for (t = 0; t < 10; t++) {
-				if (t > 0)
-					Sleep(1000);
-				r = systemf("rmdir /S /Q %s", tests[i].name);
-				if (r == 0)
-					break;
-			}
-			systemf("del %s", logfilename);
-#else
-			systemf("rm -rf %s", tests[i].name);
-			systemf("rm %s", logfilename);
-#endif
-		}
-	}
-	/* Return appropriate status. */
-	return (tests[i].failures);
-}
-
-/*
- *
- *
- * MAIN and support routines.
- *
- *
- */
-
-static void
-usage(const char *program)
-{
-	static const int limit = sizeof(tests) / sizeof(tests[0]);
-	int i;
-
-	printf("Usage: %s [options] <test> <test> ...\n", program);
-	printf("Default is to run all tests.\n");
-	printf("Otherwise, specify the numbers of the tests you wish to run.\n");
-	printf("Options:\n");
-	printf("  -d  Dump core after any failure, for debugging.\n");
-	printf("  -k  Keep all temp files.\n");
-	printf("      Default: temp files for successful tests deleted.\n");
-#ifdef PROGRAM
-	printf("  -p <path>  Path to executable to be tested.\n");
-	printf("      Default: path taken from " ENVBASE " environment variable.\n");
-#endif
-	printf("  -q  Quiet.\n");
-	printf("  -r <dir>   Path to dir containing reference files.\n");
-	printf("      Default: Current directory.\n");
-	printf("  -u  Keep running specifies tests until one fails.\n");
-	printf("  -v  Verbose.\n");
-	printf("Available tests:\n");
-	for (i = 0; i < limit; i++)
-		printf("  %d: %s\n", i, tests[i].name);
-	exit(1);
-}
-
-static char *
-get_refdir(const char *d)
-{
-	size_t tried_size, buff_size;
-	char *buff, *tried, *pwd = NULL, *p = NULL;
-
-#ifdef PATH_MAX
-	buff_size = PATH_MAX;
-#else
-	buff_size = 8192;
-#endif
-	buff = calloc(buff_size, 1);
-	if (buff == NULL) {
-		fprintf(stderr, "Unable to allocate memory\n");
-		exit(1);
-	}
-
-	/* Allocate a buffer to hold the various directories we checked. */
-	tried_size = buff_size * 2;
-	tried = calloc(tried_size, 1);
-	if (tried == NULL) {
-		fprintf(stderr, "Unable to allocate memory\n");
-		exit(1);
-	}
-
-	/* If a dir was specified, try that */
-	if (d != NULL) {
-		pwd = NULL;
-		snprintf(buff, buff_size, "%s", d);
-		p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
-		if (p != NULL) goto success;
-		strncat(tried, buff, tried_size - strlen(tried) - 1);
-		strncat(tried, "\n", tried_size - strlen(tried) - 1);
-		goto failure;
-	}
-
-	/* Get the current dir. */
-#ifdef PATH_MAX
-	pwd = getcwd(NULL, PATH_MAX);/* Solaris getcwd needs the size. */
-#else
-	pwd = getcwd(NULL, 0);
-#endif
-	while (pwd[strlen(pwd) - 1] == '\n')
-		pwd[strlen(pwd) - 1] = '\0';
-
-	/* Look for a known file. */
-	snprintf(buff, buff_size, "%s", pwd);
-	p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
-	if (p != NULL) goto success;
-	strncat(tried, buff, tried_size - strlen(tried) - 1);
-	strncat(tried, "\n", tried_size - strlen(tried) - 1);
-
-	snprintf(buff, buff_size, "%s/test", pwd);
-	p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
-	if (p != NULL) goto success;
-	strncat(tried, buff, tried_size - strlen(tried) - 1);
-	strncat(tried, "\n", tried_size - strlen(tried) - 1);
-
-#if defined(LIBRARY)
-	snprintf(buff, buff_size, "%s/%s/test", pwd, LIBRARY);
-#else
-	snprintf(buff, buff_size, "%s/%s/test", pwd, PROGRAM);
-#endif
-	p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
-	if (p != NULL) goto success;
-	strncat(tried, buff, tried_size - strlen(tried) - 1);
-	strncat(tried, "\n", tried_size - strlen(tried) - 1);
-
-#if defined(PROGRAM_ALIAS)
-	snprintf(buff, buff_size, "%s/%s/test", pwd, PROGRAM_ALIAS);
-	p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
-	if (p != NULL) goto success;
-	strncat(tried, buff, tried_size - strlen(tried) - 1);
-	strncat(tried, "\n", tried_size - strlen(tried) - 1);
-#endif
-
-	if (memcmp(pwd, "/usr/obj", 8) == 0) {
-		snprintf(buff, buff_size, "%s", pwd + 8);
-		p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
-		if (p != NULL) goto success;
-		strncat(tried, buff, tried_size - strlen(tried) - 1);
-		strncat(tried, "\n", tried_size - strlen(tried) - 1);
-
-		snprintf(buff, buff_size, "%s/test", pwd + 8);
-		p = slurpfile(NULL, "%s/%s", buff, KNOWNREF);
-		if (p != NULL) goto success;
-		strncat(tried, buff, tried_size - strlen(tried) - 1);
-		strncat(tried, "\n", tried_size - strlen(tried) - 1);
-	}
-
-failure:
-	printf("Unable to locate known reference file %s\n", KNOWNREF);
-	printf("  Checked following directories:\n%s\n", tried);
-	printf("Use -r option to specify full path to reference directory\n");
-#if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG)
-	DebugBreak();
-#endif
-	exit(1);
-
-success:
-	free(p);
-	free(pwd);
-	free(tried);
-
-	/* Copy result into a fresh buffer to reduce memory usage. */
-	p = strdup(buff);
-	free(buff);
-	return p;
-}
-
-int
-main(int argc, char **argv)
-{
-	static const int limit = sizeof(tests) / sizeof(tests[0]);
-	int test_set[sizeof(tests) / sizeof(tests[0])];
-	int i = 0, j = 0, tests_run = 0, tests_failed = 0, option;
-	time_t now;
-	char *refdir_alloc = NULL;
-	const char *progname;
-	char **saved_argv;
-	const char *tmp, *option_arg, *p;
-	char tmpdir[256], *pwd, *testprogdir, *tmp2 = NULL, *vlevel = NULL;
-	char tmpdir_timestamp[256];
-
-	(void)argc; /* UNUSED */
-
-	/* Get the current dir. */
-#ifdef PATH_MAX
-	pwd = getcwd(NULL, PATH_MAX);/* Solaris getcwd needs the size. */
-#else
-	pwd = getcwd(NULL, 0);
-#endif
-	while (pwd[strlen(pwd) - 1] == '\n')
-		pwd[strlen(pwd) - 1] = '\0';
-
-#if defined(HAVE__CrtSetReportMode) && !defined(__WATCOMC__)
-	/* To stop to run the default invalid parameter handler. */
-	_set_invalid_parameter_handler(invalid_parameter_handler);
-	/* Disable annoying assertion message box. */
-	_CrtSetReportMode(_CRT_ASSERT, 0);
-#endif
-
-	/*
-	 * Name of this program, used to build root of our temp directory
-	 * tree.
-	 */
-	progname = p = argv[0];
-	if ((testprogdir = (char *)malloc(strlen(progname) + 1)) == NULL)
-	{
-		fprintf(stderr, "ERROR: Out of memory.");
-		exit(1);
-	}
-	strcpy(testprogdir, progname);
-	while (*p != '\0') {
-		/* Support \ or / dir separators for Windows compat. */
-		if (*p == '/' || *p == '\\')
-		{
-			progname = p + 1;
-			i = j;
-		}
-		++p;
-		j++;
-	}
-	testprogdir[i] = '\0';
-#if defined(_WIN32) && !defined(__CYGWIN__)
-	if (testprogdir[0] != '/' && testprogdir[0] != '\\' &&
-	    !(((testprogdir[0] >= 'a' && testprogdir[0] <= 'z') ||
-	       (testprogdir[0] >= 'A' && testprogdir[0] <= 'Z')) &&
-		testprogdir[1] == ':' &&
-		(testprogdir[2] == '/' || testprogdir[2] == '\\')))
-#else
-	if (testprogdir[0] != '/')
-#endif
-	{
-		/* Fixup path for relative directories. */
-		if ((testprogdir = (char *)realloc(testprogdir,
-			strlen(pwd) + 1 + strlen(testprogdir) + 1)) == NULL)
-		{
-			fprintf(stderr, "ERROR: Out of memory.");
-			exit(1);
-		}
-		memmove(testprogdir + strlen(pwd) + 1, testprogdir,
-		    strlen(testprogdir) + 1);
-		memcpy(testprogdir, pwd, strlen(pwd));
-		testprogdir[strlen(pwd)] = '/';
-	}
-
-#ifdef PROGRAM
-	/* Get the target program from environment, if available. */
-	testprogfile = getenv(ENVBASE);
-#endif
-
-	if (getenv("TMPDIR") != NULL)
-		tmp = getenv("TMPDIR");
-	else if (getenv("TMP") != NULL)
-		tmp = getenv("TMP");
-	else if (getenv("TEMP") != NULL)
-		tmp = getenv("TEMP");
-	else if (getenv("TEMPDIR") != NULL)
-		tmp = getenv("TEMPDIR");
-	else
-		tmp = "/tmp";
-
-	/* Allow -d to be controlled through the environment. */
-	if (getenv(ENVBASE "_DEBUG") != NULL)
-		dump_on_failure = 1;
-
-	/* Allow -v to be controlled through the environment. */
-	if (getenv("_VERBOSITY_LEVEL") != NULL)
-	{
-		vlevel = getenv("_VERBOSITY_LEVEL");
-		verbosity = atoi(vlevel);
-		if (verbosity < VERBOSITY_SUMMARY_ONLY || verbosity > VERBOSITY_FULL)
-		{
-			/* Unsupported verbosity levels are silently ignored */
-			vlevel = NULL;
-			verbosity = VERBOSITY_PASSFAIL;
-		}
-	}
-
-	/* Get the directory holding test files from environment. */
-	refdir = getenv(ENVBASE "_TEST_FILES");
-
-	/*
-	 * Parse options, without using getopt(), which isn't available
-	 * on all platforms.
-	 */
-	++argv; /* Skip program name */
-	while (*argv != NULL) {
-		if (**argv != '-')
-			break;
-		p = *argv++;
-		++p; /* Skip '-' */
-		while (*p != '\0') {
-			option = *p++;
-			option_arg = NULL;
-			/* If 'opt' takes an argument, parse that. */
-			if (option == 'p' || option == 'r') {
-				if (*p != '\0')
-					option_arg = p;
-				else if (*argv == NULL) {
-					fprintf(stderr,
-					    "Option -%c requires argument.\n",
-					    option);
-					usage(progname);
-				} else
-					option_arg = *argv++;
-				p = ""; /* End of this option word. */
-			}
-
-			/* Now, handle the option. */
-			switch (option) {
-			case 'd':
-				dump_on_failure = 1;
-				break;
-			case 'k':
-				keep_temp_files = 1;
-				break;
-			case 'p':
-#ifdef PROGRAM
-				testprogfile = option_arg;
-#else
-				fprintf(stderr, "-p option not permitted\n");
-				usage(progname);
-#endif
-				break;
-			case 'q':
-				if (!vlevel)
-					verbosity--;
-				break;
-			case 'r':
-				refdir = option_arg;
-				break;
-			case 'u':
-				until_failure++;
-				break;
-			case 'v':
-				if (!vlevel)
-					verbosity++;
-				break;
-			default:
-				fprintf(stderr, "Unrecognized option '%c'\n",
-				    option);
-				usage(progname);
-			}
-		}
-	}
-
-	/*
-	 * Sanity-check that our options make sense.
-	 */
-#ifdef PROGRAM
-	if (testprogfile == NULL)
-	{
-		if ((tmp2 = (char *)malloc(strlen(testprogdir) + 1 +
-			strlen(PROGRAM) + 1)) == NULL)
-		{
-			fprintf(stderr, "ERROR: Out of memory.");
-			exit(1);
-		}
-		strcpy(tmp2, testprogdir);
-		strcat(tmp2, "/");
-		strcat(tmp2, PROGRAM);
-		testprogfile = tmp2;
-	}
-
-	{
-		char *testprg;
-#if defined(_WIN32) && !defined(__CYGWIN__)
-		/* Command.com sometimes rejects '/' separators. */
-		testprg = strdup(testprogfile);
-		for (i = 0; testprg[i] != '\0'; i++) {
-			if (testprg[i] == '/')
-				testprg[i] = '\\';
-		}
-		testprogfile = testprg;
-#endif
-		/* Quote the name that gets put into shell command lines. */
-		testprg = malloc(strlen(testprogfile) + 3);
-		strcpy(testprg, "\"");
-		strcat(testprg, testprogfile);
-		strcat(testprg, "\"");
-		testprog = testprg;
-	}
-#endif
-
-#if !defined(_WIN32) && defined(SIGPIPE)
-	{   /* Ignore SIGPIPE signals */
-		struct sigaction sa;
-		sa.sa_handler = SIG_IGN;
-		sigemptyset(&sa.sa_mask);
-		sa.sa_flags = 0;
-		sigaction(SIGPIPE, &sa, NULL);
-	}
-#endif
-
-	/*
-	 * Create a temp directory for the following tests.
-	 * Include the time the tests started as part of the name,
-	 * to make it easier to track the results of multiple tests.
-	 */
-	now = time(NULL);
-	for (i = 0; ; i++) {
-		strftime(tmpdir_timestamp, sizeof(tmpdir_timestamp),
-		    "%Y-%m-%dT%H.%M.%S",
-		    localtime(&now));
-		snprintf(tmpdir, sizeof(tmpdir), "%s/%s.%s-%03d", tmp,
-		    progname, tmpdir_timestamp, i);
-		if (assertMakeDir(tmpdir,0755))
-			break;
-		if (i >= 999) {
-			fprintf(stderr,
-			    "ERROR: Unable to create temp directory %s\n",
-			    tmpdir);
-			exit(1);
-		}
-	}
-
-	/*
-	 * If the user didn't specify a directory for locating
-	 * reference files, try to find the reference files in
-	 * the "usual places."
-	 */
-	refdir = refdir_alloc = get_refdir(refdir);
-
-	/*
-	 * Banner with basic information.
-	 */
-	printf("\n");
-	printf("If tests fail or crash, details will be in:\n");
-	printf("   %s\n", tmpdir);
-	printf("\n");
-	if (verbosity > VERBOSITY_SUMMARY_ONLY) {
-		printf("Reference files will be read from: %s\n", refdir);
-#ifdef PROGRAM
-		printf("Running tests on: %s\n", testprog);
-#endif
-		printf("Exercising: ");
-		fflush(stdout);
-		printf("%s\n", EXTRA_VERSION);
-	} else {
-		printf("Running ");
-		fflush(stdout);
-	}
-
-	/*
-	 * Run some or all of the individual tests.
-	 */
-	saved_argv = argv;
-	do {
-		argv = saved_argv;
-		do {
-			int test_num;
-
-			test_num = get_test_set(test_set, limit, *argv, tests);
-			if (test_num < 0) {
-				printf("*** INVALID Test %s\n", *argv);
-				free(refdir_alloc);
-				free(testprogdir);
-				usage(progname);
-				return (1);
-			}
-			for (i = 0; i < test_num; i++) {
-				tests_run++;
-				if (test_run(test_set[i], tmpdir)) {
-					tests_failed++;
-					if (until_failure)
-						goto finish;
-				}
-			}
-			if (*argv != NULL)
-				argv++;
-		} while (*argv != NULL);
-	} while (until_failure);
-
-finish:
-	/* Must be freed after all tests run */
-	free(tmp2);
-	free(testprogdir);
-	free(pwd);
-
-	/*
-	 * Report summary statistics.
-	 */
-	if (verbosity > VERBOSITY_SUMMARY_ONLY) {
-		printf("\n");
-		printf("Totals:\n");
-		printf("  Tests run:         %8d\n", tests_run);
-		printf("  Tests failed:      %8d\n", tests_failed);
-		printf("  Assertions checked:%8d\n", assertions);
-		printf("  Assertions failed: %8d\n", failures);
-		printf("  Skips reported:    %8d\n", skips);
-	}
-	if (failures) {
-		printf("\n");
-		printf("Failing tests:\n");
-		for (i = 0; i < limit; ++i) {
-			if (tests[i].failures)
-				printf("  %d: %s (%d failures)\n", i,
-				    tests[i].name, tests[i].failures);
-		}
-		printf("\n");
-		printf("Details for failing tests: %s\n", tmpdir);
-		printf("\n");
-	} else {
-		if (verbosity == VERBOSITY_SUMMARY_ONLY)
-			printf("\n");
-		printf("%d tests passed, no failures\n", tests_run);
-	}
-
-	free(refdir_alloc);
-
-	/* If the final tmpdir is empty, we can remove it. */
-	/* This should be the usual case when all tests succeed. */
-	assertChdir("..");
-	rmdir(tmpdir);
-
-	return (tests_failed ? 1 : 0);
-}
diff --git a/tar/test/test.h b/tar/test/test.h
index 3a23a05..1e1bee8 100644
--- a/tar/test/test.h
+++ b/tar/test/test.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003-2006 Tim Kientzle
+ * Copyright (c) 2003-2017 Tim Kientzle
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -22,333 +22,19 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/usr.bin/tar/test/test.h,v 1.4 2008/08/21 07:04:57 kientzle Exp $
+ * $FreeBSD$
  */
 
 /* Every test program should #include "test.h" as the first thing. */
 
-/*
- * The goal of this file (and the matching test.c) is to
- * simplify the very repetitive test-*.c test programs.
- */
-#if defined(HAVE_CONFIG_H)
-/* Most POSIX platforms use the 'configure' script to build config.h */
-#include "config.h"
-#elif defined(__FreeBSD__)
-/* Building as part of FreeBSD system requires a pre-built config.h. */
-#include "config_freebsd.h"
-#elif defined(_WIN32) && !defined(__CYGWIN__)
-/* Win32 can't run the 'configure' script. */
-#include "config_windows.h"
-#else
-/* Warn if the library hasn't been (automatically or manually) configured. */
-#error Oops: No config.h and no pre-built configuration in test.h.
-#endif
+#define KNOWNREF	"test_patterns_2.tar.uu"
+#define ENVBASE "BSDTAR"  /* Prefix for environment variables. */
+#define	PROGRAM "bsdtar"  /* Name of program being tested. */
+#define PROGRAM_ALIAS "tar" /* Generic alias for program */
+#undef	LIBRARY		  /* Not testing a library. */
+#undef	EXTRA_DUMP	  /* How to dump extra data */
+#undef	EXTRA_ERRNO	  /* How to dump errno */
+/* How to generate extra version info. */
+#define	EXTRA_VERSION    (systemf("%s --version", testprog) ? "" : "")
 
-#include <sys/types.h>  /* Windows requires this before sys/stat.h */
-#include <sys/stat.h>
-
-#if HAVE_DIRENT_H
-#include <dirent.h>
-#endif
-#ifdef HAVE_DIRECT_H
-#include <direct.h>
-#define dirent direct
-#endif
-#include <errno.h>
-#include <fcntl.h>
-#ifdef HAVE_IO_H
-#include <io.h>
-#endif
-#ifdef HAVE_STDINT_H
-#include <stdint.h>
-#endif
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <time.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-#include <wchar.h>
-#ifdef HAVE_WINDOWS_H
-#include <windows.h>
-#endif
-
-/*
- * System-specific tweaks.  We really want to minimize these
- * as much as possible, since they make it harder to understand
- * the mainline code.
- */
-
-/* Windows (including Visual Studio and MinGW but not Cygwin) */
-#if defined(_WIN32) && !defined(__CYGWIN__)
-#if !defined(__BORLANDC__)
-#undef chdir
-#define chdir _chdir
-#define strdup _strdup
-#endif
-#endif
-
-/* Visual Studio */
-#if defined(_MSC_VER) && _MSC_VER < 1900
-#define snprintf	sprintf_s
-#endif
-
-#if defined(__BORLANDC__)
-#pragma warn -8068	/* Constant out of range in comparison. */
-#endif
-
-/* Haiku OS and QNX */
-#if defined(__HAIKU__) || defined(__QNXNTO__)
-/* Haiku and QNX have typedefs in stdint.h (needed for int64_t) */
-#include <stdint.h>
-#endif
-
-/* Get a real definition for __FBSDID if we can */
-#if HAVE_SYS_CDEFS_H
-#include <sys/cdefs.h>
-#endif
-
-/* If not, define it so as to avoid dangling semicolons. */
-#ifndef __FBSDID
-#define	__FBSDID(a)     struct _undefined_hack
-#endif
-
-#ifndef O_BINARY
-#define	O_BINARY 0
-#endif
-
-/*
- * Redefine DEFINE_TEST for use in defining the test functions.
- */
-#undef DEFINE_TEST
-#define DEFINE_TEST(name) void name(void); void name(void)
-
-/* An implementation of the standard assert() macro */
-#define assert(e)   assertion_assert(__FILE__, __LINE__, (e), #e, NULL)
-/* chdir() and error if it fails */
-#define assertChdir(path)  \
-  assertion_chdir(__FILE__, __LINE__, path)
-/* Assert two integers are the same.  Reports value of each one if not. */
-#define assertEqualInt(v1,v2) \
-  assertion_equal_int(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL)
-/* Assert two strings are the same.  Reports value of each one if not. */
-#define assertEqualString(v1,v2)   \
-  assertion_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL, 0)
-#define assertEqualUTF8String(v1,v2)   \
-  assertion_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL, 1)
-/* As above, but v1 and v2 are wchar_t * */
-#define assertEqualWString(v1,v2)   \
-  assertion_equal_wstring(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL)
-/* As above, but raw blocks of bytes. */
-#define assertEqualMem(v1, v2, l)	\
-  assertion_equal_mem(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (l), #l, NULL)
-/* Assert that memory is full of a specified byte */
-#define assertMemoryFilledWith(v1, l, b)					\
-  assertion_memory_filled_with(__FILE__, __LINE__, (v1), #v1, (l), #l, (b), #b, NULL)
-/* Assert two files are the same. */
-#define assertEqualFile(f1, f2)	\
-  assertion_equal_file(__FILE__, __LINE__, (f1), (f2))
-/* Assert that a file is empty. */
-#define assertEmptyFile(pathname)	\
-  assertion_empty_file(__FILE__, __LINE__, (pathname))
-/* Assert that a file is not empty. */
-#define assertNonEmptyFile(pathname)		\
-  assertion_non_empty_file(__FILE__, __LINE__, (pathname))
-#define assertFileAtime(pathname, sec, nsec)	\
-  assertion_file_atime(__FILE__, __LINE__, pathname, sec, nsec)
-#define assertFileAtimeRecent(pathname)	\
-  assertion_file_atime_recent(__FILE__, __LINE__, pathname)
-#define assertFileBirthtime(pathname, sec, nsec)	\
-  assertion_file_birthtime(__FILE__, __LINE__, pathname, sec, nsec)
-#define assertFileBirthtimeRecent(pathname) \
-  assertion_file_birthtime_recent(__FILE__, __LINE__, pathname)
-/* Assert that a file exists; supports printf-style arguments. */
-#define assertFileExists(pathname) \
-  assertion_file_exists(__FILE__, __LINE__, pathname)
-/* Assert that a file exists. */
-#define assertFileNotExists(pathname) \
-  assertion_file_not_exists(__FILE__, __LINE__, pathname)
-/* Assert that file contents match a string. */
-#define assertFileContents(data, data_size, pathname) \
-  assertion_file_contents(__FILE__, __LINE__, data, data_size, pathname)
-/* Verify that a file does not contain invalid strings */
-#define assertFileContainsNoInvalidStrings(pathname, strings) \
-  assertion_file_contains_no_invalid_strings(__FILE__, __LINE__, pathname, strings)
-#define assertFileMtime(pathname, sec, nsec)	\
-  assertion_file_mtime(__FILE__, __LINE__, pathname, sec, nsec)
-#define assertFileMtimeRecent(pathname) \
-  assertion_file_mtime_recent(__FILE__, __LINE__, pathname)
-#define assertFileNLinks(pathname, nlinks)  \
-  assertion_file_nlinks(__FILE__, __LINE__, pathname, nlinks)
-#define assertFileSize(pathname, size)  \
-  assertion_file_size(__FILE__, __LINE__, pathname, size)
-#define assertFileMode(pathname, mode)  \
-  assertion_file_mode(__FILE__, __LINE__, pathname, mode)
-#define assertTextFileContents(text, pathname) \
-  assertion_text_file_contents(__FILE__, __LINE__, text, pathname)
-#define assertFileContainsLinesAnyOrder(pathname, lines)	\
-  assertion_file_contains_lines_any_order(__FILE__, __LINE__, pathname, lines)
-#define assertIsDir(pathname, mode)		\
-  assertion_is_dir(__FILE__, __LINE__, pathname, mode)
-#define assertIsHardlink(path1, path2)	\
-  assertion_is_hardlink(__FILE__, __LINE__, path1, path2)
-#define assertIsNotHardlink(path1, path2)	\
-  assertion_is_not_hardlink(__FILE__, __LINE__, path1, path2)
-#define assertIsReg(pathname, mode)		\
-  assertion_is_reg(__FILE__, __LINE__, pathname, mode)
-#define assertIsSymlink(pathname, contents)	\
-  assertion_is_symlink(__FILE__, __LINE__, pathname, contents)
-/* Create a directory, report error if it fails. */
-#define assertMakeDir(dirname, mode)	\
-  assertion_make_dir(__FILE__, __LINE__, dirname, mode)
-#define assertMakeFile(path, mode, contents) \
-  assertion_make_file(__FILE__, __LINE__, path, mode, -1, contents)
-#define assertMakeBinFile(path, mode, csize, contents) \
-  assertion_make_file(__FILE__, __LINE__, path, mode, csize, contents)
-#define assertMakeHardlink(newfile, oldfile)	\
-  assertion_make_hardlink(__FILE__, __LINE__, newfile, oldfile)
-#define assertMakeSymlink(newfile, linkto)	\
-  assertion_make_symlink(__FILE__, __LINE__, newfile, linkto)
-#define assertNodump(path)      \
-  assertion_nodump(__FILE__, __LINE__, path)
-#define assertUmask(mask)	\
-  assertion_umask(__FILE__, __LINE__, mask)
-#define assertUtimes(pathname, atime, atime_nsec, mtime, mtime_nsec)	\
-  assertion_utimes(__FILE__, __LINE__, pathname, atime, atime_nsec, mtime, mtime_nsec)
-
-/*
- * This would be simple with C99 variadic macros, but I don't want to
- * require that.  Instead, I insert a function call before each
- * skipping() call to pass the file and line information down.  Crude,
- * but effective.
- */
-#define skipping	\
-  skipping_setup(__FILE__, __LINE__);test_skipping
-
-/* Function declarations.  These are defined in test_utility.c. */
-void failure(const char *fmt, ...);
-int assertion_assert(const char *, int, int, const char *, void *);
-int assertion_chdir(const char *, int, const char *);
-int assertion_empty_file(const char *, int, const char *);
-int assertion_equal_file(const char *, int, const char *, const char *);
-int assertion_equal_int(const char *, int, long long, const char *, long long, const char *, void *);
-int assertion_equal_mem(const char *, int, const void *, const char *, const void *, const char *, size_t, const char *, void *);
-int assertion_memory_filled_with(const char *, int, const void *, const char *, size_t, const char *, char, const char *, void *);
-int assertion_equal_string(const char *, int, const char *v1, const char *, const char *v2, const char *, void *, int);
-int assertion_equal_wstring(const char *, int, const wchar_t *v1, const char *, const wchar_t *v2, const char *, void *);
-int assertion_file_atime(const char *, int, const char *, long, long);
-int assertion_file_atime_recent(const char *, int, const char *);
-int assertion_file_birthtime(const char *, int, const char *, long, long);
-int assertion_file_birthtime_recent(const char *, int, const char *);
-int assertion_file_contains_lines_any_order(const char *, int, const char *, const char **);
-int assertion_file_contains_no_invalid_strings(const char *, int, const char *, const char **);
-int assertion_file_contents(const char *, int, const void *, int, const char *);
-int assertion_file_exists(const char *, int, const char *);
-int assertion_file_mode(const char *, int, const char *, int);
-int assertion_file_mtime(const char *, int, const char *, long, long);
-int assertion_file_mtime_recent(const char *, int, const char *);
-int assertion_file_nlinks(const char *, int, const char *, int);
-int assertion_file_not_exists(const char *, int, const char *);
-int assertion_file_size(const char *, int, const char *, long);
-int assertion_is_dir(const char *, int, const char *, int);
-int assertion_is_hardlink(const char *, int, const char *, const char *);
-int assertion_is_not_hardlink(const char *, int, const char *, const char *);
-int assertion_is_reg(const char *, int, const char *, int);
-int assertion_is_symlink(const char *, int, const char *, const char *);
-int assertion_make_dir(const char *, int, const char *, int);
-int assertion_make_file(const char *, int, const char *, int, int, const void *);
-int assertion_make_hardlink(const char *, int, const char *newpath, const char *);
-int assertion_make_symlink(const char *, int, const char *newpath, const char *);
-int assertion_nodump(const char *, int, const char *);
-int assertion_non_empty_file(const char *, int, const char *);
-int assertion_text_file_contents(const char *, int, const char *buff, const char *f);
-int assertion_umask(const char *, int, int);
-int assertion_utimes(const char *, int, const char *, long, long, long, long );
-
-void skipping_setup(const char *, int);
-void test_skipping(const char *fmt, ...);
-
-/* Like sprintf, then system() */
-int systemf(const char * fmt, ...);
-
-/* Delay until time() returns a value after this. */
-void sleepUntilAfter(time_t);
-
-/* Return true if this platform can create symlinks. */
-int canSymlink(void);
-
-/* Return true if this platform can run the "bzip2" program. */
-int canBzip2(void);
-
-/* Return true if this platform can run the "grzip" program. */
-int canGrzip(void);
-
-/* Return true if this platform can run the "gzip" program. */
-int canGzip(void);
-
-/* Return true if this platform can run the specified command. */
-int canRunCommand(const char *);
-
-/* Return true if this platform can run the "lrzip" program. */
-int canLrzip(void);
-
-/* Return true if this platform can run the "lz4" program. */
-int canLz4(void);
-
-/* Return true if this platform can run the "lzip" program. */
-int canLzip(void);
-
-/* Return true if this platform can run the "lzma" program. */
-int canLzma(void);
-
-/* Return true if this platform can run the "lzop" program. */
-int canLzop(void);
-
-/* Return true if this platform can run the "xz" program. */
-int canXz(void);
-
-/* Return true if this filesystem can handle nodump flags. */
-int canNodump(void);
-
-/* Return true if the file has large i-node number(>0xffffffff). */
-int is_LargeInode(const char *);
-
-/* Suck file into string allocated via malloc(). Call free() when done. */
-/* Supports printf-style args: slurpfile(NULL, "%s/myfile", refdir); */
-char *slurpfile(size_t *, const char *fmt, ...);
-
-/* Dump block of bytes to a file. */
-void dumpfile(const char *filename, void *, size_t);
-
-/* Extracts named reference file to the current directory. */
-void extract_reference_file(const char *);
-/* Copies named reference file to the current directory. */
-void copy_reference_file(const char *);
-
-/* Extracts a list of files to the current directory.
- * List must be NULL terminated.
- */
-void extract_reference_files(const char **);
-
-/* Subtract umask from mode */
-mode_t umasked(mode_t expected_mode);
-
-/* Path to working directory for current test */
-extern const char *testworkdir;
-
-/*
- * Special interfaces for program test harness.
- */
-
-/* Pathname of exe to be tested. */
-extern const char *testprogfile;
-/* Name of exe to use in printf-formatted command strings. */
-/* On Windows, this includes leading/trailing quotes. */
-extern const char *testprog;
-
-#ifdef USE_DMALLOC
-#include <dmalloc.h>
-#endif
+#include "test_common.h"
diff --git a/tar/test/test_version.c b/tar/test/test_version.c
index 0c904d7..1b896c0 100644
--- a/tar/test/test_version.c
+++ b/tar/test/test_version.c
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2003-2017 Tim Kientzle
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -23,7 +23,6 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 #include "test.h"
-__FBSDID("$FreeBSD: src/usr.bin/tar/test/test_version.c,v 1.2 2008/05/26 17:10:10 kientzle Exp $");
 
 /*
  * Test that --version option works and generates reasonable output.
@@ -31,73 +30,5 @@
 
 DEFINE_TEST(test_version)
 {
-	int r;
-	char *p, *q;
-	size_t s;
-
-
-	r = systemf("%s --version >version.stdout 2>version.stderr", testprog);
-	if (r != 0)
-		r = systemf("%s -W version >version.stdout 2>version.stderr",
-		    testprog);
-	failure("Unable to run either %s --version or %s -W version",
-	    testprog, testprog);
-	if (!assert(r == 0))
-		return;
-
-	/* --version should generate nothing to stdout. */
-	assertEmptyFile("version.stderr");
-	/* Verify format of version message. */
-	q = p = slurpfile(&s, "version.stdout");
-	/* Version message should start with name of program, then space. */
-	assert(s > 6);
-	failure("Version must start with 'bsdtar': ``%s''", p);
-	if (!assertEqualMem(q, "bsdtar ", 7))
-		goto done;
-	q += 7; s -= 7;
-	/* Version number is a series of digits and periods. */
-	while (s > 0 && (*q == '.' || (*q >= '0' && *q <= '9'))) {
-		++q;
-		--s;
-	}
-	/* Version number terminated by space. */
-	failure("No space after bsdtar version: ``%s''", p);
-	assert(s > 1);
-	/* Skip a single trailing a,b,c, or d. */
-	if (*q == 'a' || *q == 'b' || *q == 'c' || *q == 'd')
-		++q;
-	failure("No space after bsdtar version: ``%s''", p);
-	assert(*q == ' ');
-	++q; --s;
-	/* Separator. */
-	failure("No `-' between bsdtar and libarchive versions: ``%s''", p);
-	assertEqualMem(q, "- ", 2);
-	q += 2; s -= 2;
-	/* libarchive name and version number */
-	failure("Not long enough for libarchive version: ``%s''", p);
-	assert(s > 11);
-	failure("Libarchive version must start with `libarchive': ``%s''", p);
-	assertEqualMem(q, "libarchive ", 11);
-	q += 11; s -= 11;
-	/* Version number is a series of digits and periods. */
-	while (s > 0 && (*q == '.' || (*q >= '0' && *q <= '9'))) {
-		++q;
-		--s;
-	}
-	/* Skip a single trailing a,b,c, or d. */
-	if (*q == 'a' || *q == 'b' || *q == 'c' || *q == 'd')
-		++q;
-	/* Skip arbitrary third-party version numbers. */
-	while (s > 0 && (*q == ' ' || *q == '-' || *q == '/' || *q == '.' || isalnum(*q))) {
-		++q;
-		--s;
-	}
-	/* All terminated by end-of-line. */
-	assert(s >= 1);
-	/* Skip an optional CR character (e.g., Windows) */
-	failure("Version output must end with \\n or \\r\\n");
-	if (*q == '\r') { ++q; --s; }
-	assertEqualMem(q, "\n", 1);
-done:
-	free(p);
+	assertVersion(testprog, "bsdtar");
 }
diff --git a/tar/util.c b/tar/util.c
index 8f65b17..662db5b 100644
--- a/tar/util.c
+++ b/tar/util.c
@@ -534,7 +534,7 @@
 		}
 	}
 
-	if (!bsdtar->option_absolute_paths) {
+	if ((bsdtar->flags & OPTFLAG_ABSOLUTE_PATHS) == 0) {
 		/* By default, don't write or restore absolute pathnames. */
 		name = strip_absolute_path(bsdtar, name);
 		if (*name == '\0')
diff --git a/tar/write.c b/tar/write.c
index 532abb2..9c24566 100644
--- a/tar/write.c
+++ b/tar/write.c
@@ -583,7 +583,7 @@
 	archive_read_free(bsdtar->diskreader);
 	bsdtar->diskreader = NULL;
 
-	if (bsdtar->option_totals) {
+	if (bsdtar->flags & OPTFLAG_TOTALS) {
 		fprintf(stderr, "Total bytes written: %s\n",
 		    tar_i64toa(archive_filter_bytes(a, -1)));
 	}
@@ -606,7 +606,8 @@
 
 	bsdtar->next_line_is_dir = 0;
 
-	lr = lafe_line_reader(bsdtar->names_from_file, bsdtar->option_null);
+	lr = lafe_line_reader(bsdtar->names_from_file,
+	    (bsdtar->flags & OPTFLAG_NULL));
 	while ((line = lafe_line_reader_next(lr)) != NULL) {
 		if (bsdtar->next_line_is_dir) {
 			if (*line != '\0')
@@ -617,7 +618,8 @@
 				bsdtar->return_value = 1;
 			}
 			bsdtar->next_line_is_dir = 0;
-		} else if (!bsdtar->option_null && strcmp(line, "-C") == 0)
+		} else if (((bsdtar->flags & OPTFLAG_NULL) == 0) &&
+		    strcmp(line, "-C") == 0)
 			bsdtar->next_line_is_dir = 1;
 		else {
 			if (*line != '/')
@@ -690,7 +692,7 @@
 	while (ARCHIVE_OK == (e = archive_read_next_header(ina, &in_entry))) {
 		if (archive_match_excluded(bsdtar->matching, in_entry))
 			continue;
-		if (bsdtar->option_interactive &&
+		if ((bsdtar->flags & OPTFLAG_INTERACTIVE) &&
 		    !yes("copy '%s'", archive_entry_pathname(in_entry)))
 			continue;
 		if (bsdtar->verbose > 1) {
@@ -809,11 +811,11 @@
 {
 	struct bsdtar *bsdtar = (struct bsdtar *)_data;
 
-	if (bsdtar->option_no_subdirs)
+	if (bsdtar->flags & OPTFLAG_NO_SUBDIRS)
 		return;
 	if (!archive_read_disk_can_descend(a))
 		return;
-	if (bsdtar->option_interactive &&
+	if ((bsdtar->flags & OPTFLAG_INTERACTIVE) &&
 	    !yes("add '%s'", archive_entry_pathname(entry)))
 		return;
 	archive_read_disk_descend(a);
@@ -844,12 +846,13 @@
 	 * check would veto this file, we shouldn't bother
 	 * the user with it.
 	 */
-	if (bsdtar->option_interactive &&
+	if ((bsdtar->flags & OPTFLAG_INTERACTIVE) &&
 	    !yes("add '%s'", archive_entry_pathname(entry)))
 		return (0);
 
 	/* Note: if user vetoes, we won't descend. */
-	if (!bsdtar->option_no_subdirs && archive_read_disk_can_descend(a))
+	if (((bsdtar->flags & OPTFLAG_NO_SUBDIRS) == 0) &&
+	    archive_read_disk_can_descend(a))
 		archive_read_disk_descend(a);
 
 	return (1);
diff --git a/test_utils/test_common.h b/test_utils/test_common.h
new file mode 100644
index 0000000..82e8483
--- /dev/null
+++ b/test_utils/test_common.h
@@ -0,0 +1,434 @@
+/*
+ * Copyright (c) 2003-2017 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef	TEST_COMMON_H
+#define	TEST_COMMON_H
+
+/*
+ * The goal of this file (and the matching test.c) is to
+ * simplify the very repetitive test-*.c test programs.
+ */
+#if defined(HAVE_CONFIG_H)
+/* Most POSIX platforms use the 'configure' script to build config.h */
+#include "config.h"
+#elif defined(__FreeBSD__)
+/* Building as part of FreeBSD system requires a pre-built config.h. */
+#include "config_freebsd.h"
+#elif defined(_WIN32) && !defined(__CYGWIN__)
+/* Win32 can't run the 'configure' script. */
+#include "config_windows.h"
+#else
+/* Warn if the library hasn't been (automatically or manually) configured. */
+#error Oops: No config.h and no pre-built configuration in test.h.
+#endif
+
+#include <sys/types.h>  /* Windows requires this before sys/stat.h */
+#include <sys/stat.h>
+
+#if HAVE_DIRENT_H
+#include <dirent.h>
+#endif
+#ifdef HAVE_DIRECT_H
+#include <direct.h>
+#define dirent direct
+#endif
+#include <errno.h>
+#include <fcntl.h>
+#ifdef HAVE_IO_H
+#include <io.h>
+#endif
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <wchar.h>
+#ifdef HAVE_WINDOWS_H
+#include <windows.h>
+#endif
+
+/*
+ * System-specific tweaks.  We really want to minimize these
+ * as much as possible, since they make it harder to understand
+ * the mainline code.
+ */
+
+/* Windows (including Visual Studio and MinGW but not Cygwin) */
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#if !defined(__BORLANDC__)
+#undef chdir
+#define chdir _chdir
+#define strdup _strdup
+#endif
+#endif
+
+/* Visual Studio */
+#if defined(_MSC_VER) && _MSC_VER < 1900
+#define snprintf	sprintf_s
+#endif
+
+#if defined(__BORLANDC__)
+#pragma warn -8068	/* Constant out of range in comparison. */
+#endif
+
+/* Haiku OS and QNX */
+#if defined(__HAIKU__) || defined(__QNXNTO__)
+/* Haiku and QNX have typedefs in stdint.h (needed for int64_t) */
+#include <stdint.h>
+#endif
+
+/* Get a real definition for __FBSDID if we can */
+#if HAVE_SYS_CDEFS_H
+#include <sys/cdefs.h>
+#endif
+
+/* If not, define it so as to avoid dangling semicolons. */
+#ifndef __FBSDID
+#define	__FBSDID(a)     struct _undefined_hack
+#endif
+
+#ifndef O_BINARY
+#define	O_BINARY 0
+#endif
+
+/*
+ * If this platform has <sys/acl.h>, acl_create(), acl_init(),
+ * acl_set_file(), and ACL_USER, we assume it has the rest of the
+ * POSIX.1e draft functions used in archive_read_extract.c.
+ */
+#if HAVE_SYS_ACL_H && HAVE_ACL_CREATE_ENTRY && HAVE_ACL_INIT && HAVE_ACL_SET_FILE
+#if HAVE_ACL_USER
+#define	HAVE_POSIX_ACL	1
+#elif HAVE_ACL_TYPE_EXTENDED
+#define	HAVE_DARWIN_ACL	1
+#endif
+#endif
+
+/*
+ * If this platform has <sys/acl.h>, acl_get(), facl_get(), acl_set(),
+ * facl_set() and types aclent_t and ace_t it uses Solaris-style ACL functions
+ */
+#if HAVE_SYS_ACL_H && HAVE_ACL_GET && HAVE_FACL_GET && HAVE_ACL_SET && HAVE_FACL_SET && HAVE_ACLENT_T && HAVE_ACE_T
+#define	HAVE_SUN_ACL	1
+#endif
+
+/* Define if platform supports NFSv4 ACLs */
+#if (HAVE_POSIX_ACL && HAVE_ACL_TYPE_NFS4) || HAVE_SUN_ACL || HAVE_DARWIN_ACL
+#define	HAVE_NFS4_ACL	1
+#endif
+
+/*
+ * Redefine DEFINE_TEST for use in defining the test functions.
+ */
+#undef DEFINE_TEST
+#define DEFINE_TEST(name) void name(void); void name(void)
+
+/* An implementation of the standard assert() macro */
+#define assert(e)   assertion_assert(__FILE__, __LINE__, (e), #e, NULL)
+/* chdir() and error if it fails */
+#define assertChdir(path)  \
+  assertion_chdir(__FILE__, __LINE__, path)
+/* Assert two integers are the same.  Reports value of each one if not. */
+#define assertEqualInt(v1,v2) \
+  assertion_equal_int(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL)
+/* Assert two strings are the same.  Reports value of each one if not. */
+#define assertEqualString(v1,v2)   \
+  assertion_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL, 0)
+#define assertEqualUTF8String(v1,v2)   \
+  assertion_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL, 1)
+/* As above, but v1 and v2 are wchar_t * */
+#define assertEqualWString(v1,v2)   \
+  assertion_equal_wstring(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL)
+/* As above, but raw blocks of bytes. */
+#define assertEqualMem(v1, v2, l)	\
+  assertion_equal_mem(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (l), #l, NULL)
+/* Assert that memory is full of a specified byte */
+#define assertMemoryFilledWith(v1, l, b)					\
+  assertion_memory_filled_with(__FILE__, __LINE__, (v1), #v1, (l), #l, (b), #b, NULL)
+/* Assert two files are the same. */
+#define assertEqualFile(f1, f2)	\
+  assertion_equal_file(__FILE__, __LINE__, (f1), (f2))
+/* Assert that a file is empty. */
+#define assertEmptyFile(pathname)	\
+  assertion_empty_file(__FILE__, __LINE__, (pathname))
+/* Assert that a file is not empty. */
+#define assertNonEmptyFile(pathname)		\
+  assertion_non_empty_file(__FILE__, __LINE__, (pathname))
+#define assertFileAtime(pathname, sec, nsec)	\
+  assertion_file_atime(__FILE__, __LINE__, pathname, sec, nsec)
+#define assertFileAtimeRecent(pathname)	\
+  assertion_file_atime_recent(__FILE__, __LINE__, pathname)
+#define assertFileBirthtime(pathname, sec, nsec)	\
+  assertion_file_birthtime(__FILE__, __LINE__, pathname, sec, nsec)
+#define assertFileBirthtimeRecent(pathname) \
+  assertion_file_birthtime_recent(__FILE__, __LINE__, pathname)
+/* Assert that a file exists; supports printf-style arguments. */
+#define assertFileExists(pathname) \
+  assertion_file_exists(__FILE__, __LINE__, pathname)
+/* Assert that a file exists. */
+#define assertFileNotExists(pathname) \
+  assertion_file_not_exists(__FILE__, __LINE__, pathname)
+/* Assert that file contents match a string. */
+#define assertFileContents(data, data_size, pathname) \
+  assertion_file_contents(__FILE__, __LINE__, data, data_size, pathname)
+/* Verify that a file does not contain invalid strings */
+#define assertFileContainsNoInvalidStrings(pathname, strings) \
+  assertion_file_contains_no_invalid_strings(__FILE__, __LINE__, pathname, strings)
+#define assertFileMtime(pathname, sec, nsec)	\
+  assertion_file_mtime(__FILE__, __LINE__, pathname, sec, nsec)
+#define assertFileMtimeRecent(pathname) \
+  assertion_file_mtime_recent(__FILE__, __LINE__, pathname)
+#define assertFileNLinks(pathname, nlinks)  \
+  assertion_file_nlinks(__FILE__, __LINE__, pathname, nlinks)
+#define assertFileSize(pathname, size)  \
+  assertion_file_size(__FILE__, __LINE__, pathname, size)
+#define assertFileMode(pathname, mode)  \
+  assertion_file_mode(__FILE__, __LINE__, pathname, mode)
+#define assertTextFileContents(text, pathname) \
+  assertion_text_file_contents(__FILE__, __LINE__, text, pathname)
+#define assertFileContainsLinesAnyOrder(pathname, lines)	\
+  assertion_file_contains_lines_any_order(__FILE__, __LINE__, pathname, lines)
+#define assertIsDir(pathname, mode)		\
+  assertion_is_dir(__FILE__, __LINE__, pathname, mode)
+#define assertIsHardlink(path1, path2)	\
+  assertion_is_hardlink(__FILE__, __LINE__, path1, path2)
+#define assertIsNotHardlink(path1, path2)	\
+  assertion_is_not_hardlink(__FILE__, __LINE__, path1, path2)
+#define assertIsReg(pathname, mode)		\
+  assertion_is_reg(__FILE__, __LINE__, pathname, mode)
+#define assertIsSymlink(pathname, contents)	\
+  assertion_is_symlink(__FILE__, __LINE__, pathname, contents)
+/* Create a directory, report error if it fails. */
+#define assertMakeDir(dirname, mode)	\
+  assertion_make_dir(__FILE__, __LINE__, dirname, mode)
+#define assertMakeFile(path, mode, contents) \
+  assertion_make_file(__FILE__, __LINE__, path, mode, -1, contents)
+#define assertMakeBinFile(path, mode, csize, contents) \
+  assertion_make_file(__FILE__, __LINE__, path, mode, csize, contents)
+#define assertMakeHardlink(newfile, oldfile)	\
+  assertion_make_hardlink(__FILE__, __LINE__, newfile, oldfile)
+#define assertMakeSymlink(newfile, linkto)	\
+  assertion_make_symlink(__FILE__, __LINE__, newfile, linkto)
+#define assertNodump(path)      \
+  assertion_nodump(__FILE__, __LINE__, path)
+#define assertUmask(mask)	\
+  assertion_umask(__FILE__, __LINE__, mask)
+#define assertUtimes(pathname, atime, atime_nsec, mtime, mtime_nsec)	\
+  assertion_utimes(__FILE__, __LINE__, pathname, atime, atime_nsec, mtime, mtime_nsec)
+#ifndef PROGRAM
+#define assertEntrySetAcls(entry, acls, count) \
+  assertion_entry_set_acls(__FILE__, __LINE__, entry, acls, count)
+#define assertEntryCompareAcls(entry, acls, count, type, mode) \
+  assertion_entry_compare_acls(__FILE__, __LINE__, entry, acls, count, type, mode)
+#endif
+
+/*
+ * This would be simple with C99 variadic macros, but I don't want to
+ * require that.  Instead, I insert a function call before each
+ * skipping() call to pass the file and line information down.  Crude,
+ * but effective.
+ */
+#define skipping	\
+  skipping_setup(__FILE__, __LINE__);test_skipping
+
+/* Function declarations.  These are defined in test_utility.c. */
+void failure(const char *fmt, ...);
+int assertion_assert(const char *, int, int, const char *, void *);
+int assertion_chdir(const char *, int, const char *);
+int assertion_empty_file(const char *, int, const char *);
+int assertion_equal_file(const char *, int, const char *, const char *);
+int assertion_equal_int(const char *, int, long long, const char *, long long, const char *, void *);
+int assertion_equal_mem(const char *, int, const void *, const char *, const void *, const char *, size_t, const char *, void *);
+int assertion_memory_filled_with(const char *, int, const void *, const char *, size_t, const char *, char, const char *, void *);
+int assertion_equal_string(const char *, int, const char *v1, const char *, const char *v2, const char *, void *, int);
+int assertion_equal_wstring(const char *, int, const wchar_t *v1, const char *, const wchar_t *v2, const char *, void *);
+int assertion_file_atime(const char *, int, const char *, long, long);
+int assertion_file_atime_recent(const char *, int, const char *);
+int assertion_file_birthtime(const char *, int, const char *, long, long);
+int assertion_file_birthtime_recent(const char *, int, const char *);
+int assertion_file_contains_lines_any_order(const char *, int, const char *, const char **);
+int assertion_file_contains_no_invalid_strings(const char *, int, const char *, const char **);
+int assertion_file_contents(const char *, int, const void *, int, const char *);
+int assertion_file_exists(const char *, int, const char *);
+int assertion_file_mode(const char *, int, const char *, int);
+int assertion_file_mtime(const char *, int, const char *, long, long);
+int assertion_file_mtime_recent(const char *, int, const char *);
+int assertion_file_nlinks(const char *, int, const char *, int);
+int assertion_file_not_exists(const char *, int, const char *);
+int assertion_file_size(const char *, int, const char *, long);
+int assertion_is_dir(const char *, int, const char *, int);
+int assertion_is_hardlink(const char *, int, const char *, const char *);
+int assertion_is_not_hardlink(const char *, int, const char *, const char *);
+int assertion_is_reg(const char *, int, const char *, int);
+int assertion_is_symlink(const char *, int, const char *, const char *);
+int assertion_make_dir(const char *, int, const char *, int);
+int assertion_make_file(const char *, int, const char *, int, int, const void *);
+int assertion_make_hardlink(const char *, int, const char *newpath, const char *);
+int assertion_make_symlink(const char *, int, const char *newpath, const char *);
+int assertion_nodump(const char *, int, const char *);
+int assertion_non_empty_file(const char *, int, const char *);
+int assertion_text_file_contents(const char *, int, const char *buff, const char *f);
+int assertion_umask(const char *, int, int);
+int assertion_utimes(const char *, int, const char *, long, long, long, long );
+int assertion_version(const char*, int, const char *, const char *);
+
+void skipping_setup(const char *, int);
+void test_skipping(const char *fmt, ...);
+
+/* Like sprintf, then system() */
+int systemf(const char * fmt, ...);
+
+/* Delay until time() returns a value after this. */
+void sleepUntilAfter(time_t);
+
+/* Return true if this platform can create symlinks. */
+int canSymlink(void);
+
+/* Return true if this platform can run the "bzip2" program. */
+int canBzip2(void);
+
+/* Return true if this platform can run the "grzip" program. */
+int canGrzip(void);
+
+/* Return true if this platform can run the "gzip" program. */
+int canGzip(void);
+
+/* Return true if this platform can run the specified command. */
+int canRunCommand(const char *);
+
+/* Return true if this platform can run the "lrzip" program. */
+int canLrzip(void);
+
+/* Return true if this platform can run the "lz4" program. */
+int canLz4(void);
+
+/* Return true if this platform can run the "lzip" program. */
+int canLzip(void);
+
+/* Return true if this platform can run the "lzma" program. */
+int canLzma(void);
+
+/* Return true if this platform can run the "lzop" program. */
+int canLzop(void);
+
+/* Return true if this platform can run the "xz" program. */
+int canXz(void);
+
+/* Return true if this filesystem can handle nodump flags. */
+int canNodump(void);
+
+/* Return true if the file has large i-node number(>0xffffffff). */
+int is_LargeInode(const char *);
+
+/* Suck file into string allocated via malloc(). Call free() when done. */
+/* Supports printf-style args: slurpfile(NULL, "%s/myfile", refdir); */
+char *slurpfile(size_t *, const char *fmt, ...);
+
+/* Dump block of bytes to a file. */
+void dumpfile(const char *filename, void *, size_t);
+
+/* Extracts named reference file to the current directory. */
+void extract_reference_file(const char *);
+/* Copies named reference file to the current directory. */
+void copy_reference_file(const char *);
+
+/* Extracts a list of files to the current directory.
+ * List must be NULL terminated.
+ */
+void extract_reference_files(const char **);
+
+/* Subtract umask from mode */
+mode_t umasked(mode_t expected_mode);
+
+/* Path to working directory for current test */
+extern const char *testworkdir;
+
+#ifndef PROGRAM
+/*
+ * Special interfaces for libarchive test harness.
+ */
+
+#include "archive.h"
+#include "archive_entry.h"
+
+/* ACL structure */
+struct archive_test_acl_t {
+	int type;  /* Type of ACL */
+	int permset; /* Permissions for this class of users. */
+	int tag; /* Owner, User, Owning group, group, other, etc. */
+	int qual; /* GID or UID of user/group, depending on tag. */
+	const char *name; /* Name of user/group, depending on tag. */
+};
+
+/* Set ACLs */
+int assertion_entry_set_acls(const char *, int, struct archive_entry *,
+    struct archive_test_acl_t *, int);
+
+/* Compare ACLs */
+int assertion_entry_compare_acls(const char *, int, struct archive_entry *,
+    struct archive_test_acl_t *, int, int, int);
+
+/* Special customized read-from-memory interface. */
+int read_open_memory(struct archive *, const void *, size_t, size_t);
+/* _minimal version exercises a slightly different set of libarchive APIs. */
+int read_open_memory_minimal(struct archive *, const void *, size_t, size_t);
+/* _seek version produces a seekable file. */
+int read_open_memory_seek(struct archive *, const void *, size_t, size_t);
+
+/* Versions of above that accept an archive argument for additional info. */
+#define assertA(e)   assertion_assert(__FILE__, __LINE__, (e), #e, (a))
+#define assertEqualIntA(a,v1,v2)   \
+  assertion_equal_int(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (a))
+#define assertEqualStringA(a,v1,v2)   \
+  assertion_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (a), 0)
+
+#else	/* defined(PROGRAM) */
+/*
+ * Special interfaces for program test harness.
+ */
+
+/* Pathname of exe to be tested. */
+extern const char *testprogfile;
+/* Name of exe to use in printf-formatted command strings. */
+/* On Windows, this includes leading/trailing quotes. */
+extern const char *testprog;
+
+void assertVersion(const char *prog, const char *base);
+
+#endif	/* defined(PROGRAM) */
+
+#ifdef USE_DMALLOC
+#include <dmalloc.h>
+#endif
+
+#endif	/* TEST_COMMON_H */
diff --git a/libarchive/test/main.c b/test_utils/test_main.c
similarity index 91%
rename from libarchive/test/main.c
rename to test_utils/test_main.c
index 46685f8..2ae6b38 100644
--- a/libarchive/test/main.c
+++ b/test_utils/test_main.c
@@ -45,6 +45,9 @@
 #if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__)
 #include <ext2fs/ext2_fs.h>     /* Linux file flags, broken on Cygwin */
 #endif
+#ifdef HAVE_LINUX_FS_H
+#include <linux/fs.h>
+#endif
 #include <limits.h>
 #include <locale.h>
 #ifdef HAVE_SIGNAL_H
@@ -54,22 +57,6 @@
 #include <time.h>
 
 /*
- * This same file is used pretty much verbatim for all test harnesses.
- *
- * The next few lines are the only differences.
- * TODO: Move this into a separate configuration header, have all test
- * suites share one copy of this file.
- */
-__FBSDID("$FreeBSD: head/lib/libarchive/test/main.c 201247 2009-12-30 05:59:21Z kientzle $");
-#define KNOWNREF	"test_compat_gtar_1.tar.uu"
-#define	ENVBASE "LIBARCHIVE" /* Prefix for environment variables. */
-#undef	PROGRAM              /* Testing a library, not a program. */
-#define	LIBRARY	"libarchive"
-#define	EXTRA_DUMP(x)	archive_error_string((struct archive *)(x))
-#define	EXTRA_ERRNO(x)	archive_errno((struct archive *)(x))
-#define	EXTRA_VERSION	archive_version_details()
-
-/*
  *
  * Windows support routines
  *
@@ -1910,8 +1897,10 @@
 		failure_finish(NULL);
 		return (0);
 	}
-#elif defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)\
-	 && defined(EXT2_NODUMP_FL)
+#elif (defined(FS_IOC_GETFLAGS) && defined(HAVE_WORKING_FS_IOC_GETFLAGS) && \
+       defined(FS_NODUMP_FL)) || \
+      (defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS) \
+	 && defined(EXT2_NODUMP_FL))
 	int fd, r, flags;
 
 	assertion_count(file, line);
@@ -1921,14 +1910,31 @@
 		failure_finish(NULL);
 		return (0);
 	}
-	r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags);
+	r = ioctl(fd,
+#ifdef FS_IOC_GETFLAGS
+	    FS_IOC_GETFLAGS,
+#else
+	    EXT2_IOC_GETFLAGS,
+#endif
+	    &flags);
 	if (r < 0) {
 		failure_start(file, line, "Can't get flags %s\n", pathname);
 		failure_finish(NULL);
 		return (0);
 	}
+#ifdef FS_NODUMP_FL
+	flags |= FS_NODUMP_FL;
+#else
 	flags |= EXT2_NODUMP_FL;
-	r = ioctl(fd, EXT2_IOC_SETFLAGS, &flags);
+#endif
+
+	 r = ioctl(fd,
+#ifdef FS_IOC_SETFLAGS
+	    FS_IOC_SETFLAGS,
+#else
+	    EXT2_IOC_SETFLAGS,
+#endif
+	    &flags);
 	if (r < 0) {
 		failure_start(file, line, "Can't set nodump %s\n", pathname);
 		failure_finish(NULL);
@@ -1942,6 +1948,117 @@
 	return (1);
 }
 
+#ifdef PROGRAM
+static void assert_version_id(char **qq, size_t *ss)
+{
+	char *q = *qq;
+	size_t s = *ss;
+
+	/* Version number is a series of digits and periods. */
+	while (s > 0 && (*q == '.' || (*q >= '0' && *q <= '9'))) {
+		++q;
+		--s;
+	}
+
+	if (q[0] == 'd' && q[1] == 'e' && q[2] == 'v') {
+		q += 3;
+		s -= 3;
+	}
+	
+	/* Skip a single trailing a,b,c, or d. */
+	if (*q == 'a' || *q == 'b' || *q == 'c' || *q == 'd')
+		++q;
+
+	/* Version number terminated by space. */
+	failure("No space after version: ``%s''", q);
+	assert(s > 1);
+	failure("No space after version: ``%s''", q);
+	assert(*q == ' ');
+
+	++q; --s;
+
+	*qq = q;
+	*ss = s;
+}
+
+
+/*
+ * Check program version
+ */
+void assertVersion(const char *prog, const char *base)
+{
+	int r;
+	char *p, *q;
+	size_t s;
+	unsigned int prog_len = strlen(base);
+
+	r = systemf("%s --version >version.stdout 2>version.stderr", prog);
+	if (r != 0)
+		r = systemf("%s -W version >version.stdout 2>version.stderr",
+		    prog);
+
+	failure("Unable to run either %s --version or %s -W version",
+		prog, prog);
+	if (!assert(r == 0))
+		return;
+
+	/* --version should generate nothing to stdout. */
+	assertEmptyFile("version.stderr");
+
+	/* Verify format of version message. */
+	q = p = slurpfile(&s, "version.stdout");
+
+	/* Version message should start with name of program, then space. */
+	assert(s > prog_len + 1);
+	
+	failure("Version must start with '%s': ``%s''", base, p);
+	if (!assertEqualMem(q, base, prog_len)) {
+		free(p);
+		return;
+	}
+
+	q += prog_len; s -= prog_len;
+
+	assert(*q == ' ');
+	q++; s--;
+
+	assert_version_id(&q, &s);
+
+	/* Separator. */
+	failure("No `-' between program name and versions: ``%s''", p);
+	assertEqualMem(q, "- ", 2);
+	q += 2; s -= 2;
+
+	failure("Not long enough for libarchive version: ``%s''", p);
+	assert(s > 11);
+
+	failure("Libarchive version must start with `libarchive': ``%s''", p);
+	assertEqualMem(q, "libarchive ", 11);
+
+	q += 11; s -= 11;
+
+	assert_version_id(&q, &s);
+
+	/* Skip arbitrary third-party version numbers. */
+	while (s > 0 && (*q == ' ' || *q == '-' || *q == '/' || *q == '.' ||
+	    isalnum(*q))) {
+		++q;
+		--s;
+	}
+
+	/* All terminated by end-of-line. */
+	assert(s >= 1);
+
+	/* Skip an optional CR character (e.g., Windows) */
+	failure("Version output must end with \\n or \\r\\n");
+
+	if (*q == '\r') { ++q; --s; }
+	assertEqualMem(q, "\n", 1);
+
+	free(p);
+}
+#endif	/* PROGRAM */
+
 /*
  *
  *  UTILITIES for use by tests.
@@ -2157,9 +2274,10 @@
 	return (0);
 }
 
-#elif defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)\
-	 && defined(EXT2_NODUMP_FL)
-
+#elif (defined(FS_IOC_GETFLAGS) && defined(HAVE_WORKING_FS_IOC_GETFLAGS) \
+	 && defined(FS_NODUMP_FL)) || \
+      (defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS) \
+	 && defined(EXT2_NODUMP_FL))
 int
 canNodump(void)
 {
@@ -2170,22 +2288,48 @@
 	fd = open(path, O_RDONLY | O_NONBLOCK);
 	if (fd < 0)
 		return (0);
-	r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags);
+	r = ioctl(fd,
+#ifdef FS_IOC_GETFLAGS
+	    FS_IOC_GETFLAGS,
+#else
+	    EXT2_IOC_GETFLAGS,
+#endif
+	    &flags);
 	if (r < 0)
 		return (0);
+#ifdef FS_NODUMP_FL
+	flags |= FS_NODUMP_FL;
+#else
 	flags |= EXT2_NODUMP_FL;
-	r = ioctl(fd, EXT2_IOC_SETFLAGS, &flags);
+#endif
+	r = ioctl(fd,
+#ifdef FS_IOC_SETFLAGS
+	    FS_IOC_SETFLAGS,
+#else
+	    EXT2_IOC_SETFLAGS,
+#endif
+	   &flags);
 	if (r < 0)
 		return (0);
 	close(fd);
 	fd = open(path, O_RDONLY | O_NONBLOCK);
 	if (fd < 0)
 		return (0);
-	r = ioctl(fd, EXT2_IOC_GETFLAGS, &flags);
+	r = ioctl(fd,
+#ifdef FS_IOC_GETFLAGS
+	    FS_IOC_GETFLAGS,
+#else
+	    EXT2_IOC_GETFLAGS,
+#endif
+	    &flags);
 	if (r < 0)
 		return (0);
 	close(fd);
+#ifdef FS_NODUMP_FL
+	if (flags & FS_NODUMP_FL)
+#else
 	if (flags & EXT2_NODUMP_FL)
+#endif
 		return (1);
 	return (0);
 }
@@ -2429,23 +2573,33 @@
 		extract_reference_file(*names++);
 }
 
+#ifndef PROGRAM
 /* Set ACLs */
-void
-archive_test_set_acls(struct archive_entry *ae,
+int
+assertion_entry_set_acls(const char *file, int line, struct archive_entry *ae,
     struct archive_test_acl_t *acls, int n)
 {
-	int i;
+	int i, r, ret;
 
+	assertion_count(file, line);
+
+	ret = 0;
 	archive_entry_acl_clear(ae);
 	for (i = 0; i < n; i++) {
-		failure("type=%#010x, permset=%#010x, tag=%d, qual=%d name=%s",
+		r = archive_entry_acl_add_entry(ae,
 		    acls[i].type, acls[i].permset, acls[i].tag,
 		    acls[i].qual, acls[i].name);
-		assertEqualInt(ARCHIVE_OK,
-		    archive_entry_acl_add_entry(ae,
-			acls[i].type, acls[i].permset, acls[i].tag,
-			acls[i].qual, acls[i].name));
+		if (r != 0) {
+			ret = 1;
+			failure_start(file, line, "type=%#010x, ",
+			    "permset=%#010x, tag=%d, qual=%d name=%s",
+			    acls[i].type, acls[i].permset, acls[i].tag,
+			    acls[i].qual, acls[i].name);
+			failure_finish(NULL);
+		}
 	}
+
+	return (ret);
 }
 
 static int
@@ -2482,16 +2636,20 @@
 }
 
 /* Compare ACLs */
-void
-archive_test_compare_acls(struct archive_entry *ae,
-    struct archive_test_acl_t *acls, int cnt, int want_type, int mode)
+int
+assertion_entry_compare_acls(const char *file, int line,
+    struct archive_entry *ae, struct archive_test_acl_t *acls, int cnt,
+    int want_type, int mode)
 {
 	int *marker;
-	int i, r, n;
+	int i, r, n, ret;
 	int type, permset, tag, qual;
 	int matched;
 	const char *name;
 
+	assertion_count(file, line);
+
+	ret = 0;
 	n = 0;
 	marker = malloc(sizeof(marker[0]) * cnt);
 
@@ -2502,10 +2660,11 @@
 		}
 	}
 
-	failure("No ACL's to compare, type mask: %d", want_type);
-	assert(n > 0);
-	if (n == 0)
-		return;
+	if (n == 0) {
+		failure_start(file, line, "No ACL's to compare, type mask: %d",
+		    want_type);
+		return (1);
+	}
 
 	while (0 == (r = archive_entry_acl_next(ae, want_type,
 			 &type, &permset, &tag, &qual, &name))) {
@@ -2520,40 +2679,83 @@
 		}
 		if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS
 		    && tag == ARCHIVE_ENTRY_ACL_USER_OBJ) {
-			if (!matched) printf("No match for user_obj perm\n");
-			failure("USER_OBJ permset (%02o) != user mode (%02o)",
-			    permset, 07 & (mode >> 6));
-			assert((permset << 6) == (mode & 0700));
+			if (!matched) {
+				failure_start(file, line, "No match for "
+				    "user_obj perm");
+				failure_finish(NULL);
+				ret = 1;
+			}
+			if ((permset << 6) != (mode & 0700)) {
+				failure_start(file, line, "USER_OBJ permset "
+				    "(%02o) != user mode (%02o)", permset,
+				    07 & (mode >> 6));
+				failure_finish(NULL);
+				ret = 1;
+			}
 		} else if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS
 		    && tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ) {
-			if (!matched) printf("No match for group_obj perm\n");
-			failure("GROUP_OBJ permset %02o != group mode %02o",
-			    permset, 07 & (mode >> 3));
-			assert((permset << 3) == (mode & 0070));
+			if (!matched) {
+				failure_start(file, line, "No match for "
+				    "group_obj perm");
+				failure_finish(NULL);
+				ret = 1;
+			}
+			if ((permset << 3) != (mode & 0070)) {
+				failure_start(file, line, "GROUP_OBJ permset "
+				    "(%02o) != group mode (%02o)", permset,
+				    07 & (mode >> 3));
+				failure_finish(NULL);
+				ret = 1;
+			}
 		} else if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS
 		    && tag == ARCHIVE_ENTRY_ACL_OTHER) {
-			if (!matched) printf("No match for other perm\n");
-			failure("OTHER permset (%02o) != other mode (%02o)",
-			    permset, mode & 07);
-			assert((permset << 0) == (mode & 0007));
-		} else {
-			failure("Could not find match for ACL "
-			    "(type=%#010x,permset=%#010x,tag=%d,qual=%d,"
+			if (!matched) {
+				failure_start(file, line, "No match for "
+				    "other perm");
+				failure_finish(NULL);
+				ret = 1;
+			}
+			if ((permset << 0) != (mode & 0007)) {
+				failure_start(file, line, "OTHER permset "
+				    "(%02o) != other mode (%02o)", permset,
+				    mode & 07);
+				failure_finish(NULL);
+				ret = 1;
+			}
+		} else if (matched != 1) {
+			failure_start(file, line, "Could not find match for "
+			    "ACL (type=%#010x,permset=%#010x,tag=%d,qual=%d,"
 			    "name=``%s'')", type, permset, tag, qual, name);
-			assert(matched == 1);
+			failure_finish(NULL);
+			ret = 1;
 		}
 	}
-	assertEqualInt(ARCHIVE_EOF, r);
-	if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)
-		assert((mode_t)(mode & 0777) == (archive_entry_mode(ae)
-		    & 0777));
-	failure("Could not find match for ACL "
-	    "(type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s'')",
-	    acls[marker[0]].type, acls[marker[0]].permset,
-	    acls[marker[0]].tag, acls[marker[0]].qual, acls[marker[0]].name);
-	assert(n == 0); /* Number of ACLs not matched should == 0 */
+	if (r != ARCHIVE_EOF) {
+		failure_start(file, line, "Should not exit before EOF");
+		failure_finish(NULL);
+		ret = 1;
+	}
+	if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0 &&
+	    (mode_t)(mode & 0777) != (archive_entry_mode(ae) & 0777)) {
+		failure_start(file, line, "Mode (%02o) and entry mode (%02o) "
+		    "mismatch", mode, archive_entry_mode(ae));
+		failure_finish(NULL);
+		ret = 1;
+	}
+	if (n != 0) {
+		failure_start(file, line, "Could not find match for ACL "
+		    "(type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s'')",
+		    acls[marker[0]].type, acls[marker[0]].permset,
+		    acls[marker[0]].tag, acls[marker[0]].qual,
+		    acls[marker[0]].name);
+		failure_finish(NULL);
+		ret = 1;
+		/* Number of ACLs not matched should == 0 */
+	}
 	free(marker);
+	return (ret);
 }
+#endif	/* !defined(PROGRAM) */
 
 /*
  *