Merge pull request #870 from phillipberndt/master

Seekable zip backend: Accept files with valid ZIP64 EOCD headers
diff --git a/CMakeLists.txt b/CMakeLists.txt
index dbbf797..47cf004 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -579,6 +579,7 @@
 
 LA_CHECK_INCLUDE_FILE("linux/magic.h" HAVE_LINUX_MAGIC_H)
 LA_CHECK_INCLUDE_FILE("locale.h" HAVE_LOCALE_H)
+LA_CHECK_INCLUDE_FILE("membership.h" HAVE_MEMBERSHIP_H)
 LA_CHECK_INCLUDE_FILE("memory.h" HAVE_MEMORY_H)
 LA_CHECK_INCLUDE_FILE("paths.h" HAVE_PATHS_H)
 LA_CHECK_INCLUDE_FILE("poll.h" HAVE_POLL_H)
@@ -618,6 +619,9 @@
 LA_CHECK_INCLUDE_FILE("windows.h" HAVE_WINDOWS_H)
 IF(ENABLE_CNG)
   LA_CHECK_INCLUDE_FILE("Bcrypt.h" HAVE_BCRYPT_H)
+  IF(HAVE_BCRYPT_H)
+    LIST(APPEND ADDITIONAL_LIBS "Bcrypt")
+  ENDIF(HAVE_BCRYPT_H)
 ELSE(ENABLE_CNG)
   UNSET(HAVE_BCRYPT_H CACHE)
 ENDIF(ENABLE_CNG)
@@ -1618,29 +1622,29 @@
   CHECK_FUNCTION_EXISTS(acl_get_link_np HAVE_ACL_GET_LINK_NP)
   CHECK_FUNCTION_EXISTS(acl_is_trivial_np HAVE_ACL_IS_TRIVIAL_NP)
   CHECK_FUNCTION_EXISTS(acl_set_link_np HAVE_ACL_SET_LINK_NP)
-  CHECK_SYMBOL_EXISTS(ACL_TYPE_NFS4 "${INCLUDES}" HAVE_ACL_TYPE_NFS4)
+  CHECK_SYMBOL_EXISTS(ACL_TYPE_NFS4 "${INCLUDES}" HAVE_DECL_ACL_TYPE_NFS4)
 
   # MacOS has an acl.h that isn't POSIX.  It can be detected by
   # checking for ACL_USER
-  CHECK_SYMBOL_EXISTS(ACL_USER "${INCLUDES}" HAVE_ACL_USER)
+  CHECK_SYMBOL_EXISTS(ACL_USER "${INCLUDES}" HAVE_DECL_ACL_USER)
   CHECK_C_SOURCE_COMPILES("#include <sys/types.h>
 #include <sys/acl.h>
-int main(void) { return ACL_TYPE_EXTENDED; }" HAVE_ACL_TYPE_EXTENDED)
+int main(void) { return ACL_TYPE_EXTENDED; }" HAVE_DECL_ACL_TYPE_EXTENDED)
+  CHECK_C_SOURCE_COMPILES("#include <sys/types.h>
+#include <sys/acl.h>
+int main(void) { return ACL_SYNCHRONIZE; }" HAVE_DECL_ACL_SYNCHRONIZE)
 
   # Solaris and derivates ACLs
-  CHECK_LIBRARY_EXISTS(sec "acl_get" "" HAVE_LIBSEC)
-  IF(HAVE_LIBSEC)
-    SET(CMAKE_REQUIRED_LIBRARIES "sec")
-    FIND_LIBRARY(SEC_LIBRARY NAMES sec)
-    LIST(APPEND ADDITIONAL_LIBS ${SEC_LIBRARY})
-  ENDIF(HAVE_LIBSEC)
-  #
   CHECK_TYPE_EXISTS(aclent_t "${INCLUDES}" HAVE_ACLENT_T)
   CHECK_TYPE_EXISTS(ace_t "${INCLUDES}" HAVE_ACE_T)
-  CHECK_FUNCTION_EXISTS(acl_get HAVE_FACL_GET)
-  CHECK_FUNCTION_EXISTS(facl_get HAVE_FACL_GET)
-  CHECK_FUNCTION_EXISTS(acl_set HAVE_FACL_SET)
-  CHECK_FUNCTION_EXISTS(facl_set HAVE_FACL_SET)
+  CHECK_FUNCTION_EXISTS(acl HAVE_ACL)
+  CHECK_FUNCTION_EXISTS(facl HAVE_FACL)
+  CHECK_SYMBOL_EXISTS(GETACL "${INCLUDES}" HAVE_DECL_GETACL)
+  CHECK_SYMBOL_EXISTS(GETACLCNT "${INCLUDES}" HAVE_DECL_GETACLCNT)
+  CHECK_SYMBOL_EXISTS(SETACL "${INCLUDES}" HAVE_DECL_SETACL)
+  CHECK_SYMBOL_EXISTS(ACE_GETACL "${INCLUDES}" HAVE_DECL_ACE_GETACL)
+  CHECK_SYMBOL_EXISTS(ACE_GETACLCNT "${INCLUDES}" HAVE_DECL_ACE_GETACLCNT)
+  CHECK_SYMBOL_EXISTS(ACE_SETACL "${INCLUDES}" HAVE_DECL_ACE_SETACL)
 ELSE(ENABLE_ACL)
   # If someone runs cmake, then disables ACL support, we need
   # to forcibly override the cached values for these.
@@ -1655,15 +1659,20 @@
   SET(HAVE_ACL_SET_FD FALSE)
   SET(HAVE_ACL_SET_FD_NP FALSE)
   SET(HAVE_ACL_SET_FILE FALSE)
-  SET(HAVE_ACL_TYPE_NFS4 FALSE)
-  SET(HAVE_ACL_USER FALSE)
   SET(HAVE_ACL_TYPE_EXTENDED FALSE)
-  SET(HAVE_ACL_GET FALSE)
   SET(HAVE_ACLENT_T FALSE)
   SET(HAVE_ACE_T FALSE)
-  SET(HAVE_FACL_GET FALSE)
-  SET(HAVE_ACL_SET FALSE)
-  SET(HAVE_FACL_SET FALSE)
+  SET(HAVE_DECL_ACL_TYPE_NFS4 FALSE)
+  SET(HAVE_DECL_ACL_USER FALSE)
+  SET(HAVE_DECL_ACL_SYNCHRONIZE FALSE)
+  SET(HAVE_DECL_GETACL FALSE)
+  SET(HAVE_DECL_GETACLCNT FALSE)
+  SET(HAVE_DECL_SETACL FALSE)
+  SET(HAVE_DECL_ACE_GETACL FALSE)
+  SET(HAVE_DECL_ACE_GETACLCNT FALSE)
+  SET(HAVE_DECL_ACE_SETACL FALSE)
+  SET(HAVE_ACL FALSE)
+  SET(HAVE_FACL FALSE)
 ENDIF(ENABLE_ACL)
 
 #
diff --git a/Makefile.am b/Makefile.am
index a699dc5..8c573a9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -186,6 +186,7 @@
 	libarchive/archive_string_composition.h \
 	libarchive/archive_string_sprintf.c \
 	libarchive/archive_util.c \
+	libarchive/archive_version_details.c \
 	libarchive/archive_virtual.c \
 	libarchive/archive_write.c \
 	libarchive/archive_write_disk_acl.c \
@@ -951,10 +952,12 @@
 	tar/test/test_option_T_upper.c \
 	tar/test/test_option_U_upper.c \
 	tar/test/test_option_X_upper.c \
+	tar/test/test_option_acls.c \
 	tar/test/test_option_a.c \
 	tar/test/test_option_b.c \
 	tar/test/test_option_b64encode.c \
 	tar/test/test_option_exclude.c \
+	tar/test/test_option_fflags.c \
 	tar/test/test_option_gid_gname.c \
 	tar/test/test_option_grzip.c \
 	tar/test/test_option_j.c \
diff --git a/NEWS b/NEWS
index 907ab67..fdd971d 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,6 @@
+Feb 26, 2017: libarchive 3.3.1 released
+    Security & Feature release
+
 Feb 19, 2017: libarchive 3.3.0 released
     Security & Feature release
 
@@ -290,7 +293,7 @@
 	* libarchive: Mark which entry strings are set; be accurate about
 	  distinguishing empty strings ("") from unset ones (NULL)
 	* tar: Don't crash reading entries with empty filenames
-	* libarchive_test, bsdtar_test, bsdcpio_test:  Better detaults:
+	* libarchive_test, bsdtar_test, bsdcpio_test:  Better defaults:
 	  run all tests, delete temp dirs, summarize repeated failures
 	* -no-undefined to libtool for Cygwin
 	* libarchive_test: Skip large file tests on systems with 32-bit off_t
diff --git a/build/autogen.sh b/build/autogen.sh
index 64767b6..e720e9b 100755
--- a/build/autogen.sh
+++ b/build/autogen.sh
@@ -51,6 +51,7 @@
 # Remove developer CFLAGS if a release build is being made
 if [ -n "${MAKE_LIBARCHIVE_RELEASE}" ]; then
   perl -p -i -e "s/^(DEV_CFLAGS.*)/# \$1/" Makefile.am
+  perl -p -i -e 's/CMAKE_BUILD_TYPE "[A-Za-z]*"/CMAKE_BUILD_TYPE "Release"/' CMakeLists.txt
 fi
 
 set -xe
diff --git a/build/cmake/config.h.in b/build/cmake/config.h.in
index 923a78e..8c18edf 100644
--- a/build/cmake/config.h.in
+++ b/build/cmake/config.h.in
@@ -326,15 +326,6 @@
 /* Define to 1 if you have the `acl_set_file' function. */
 #cmakedefine HAVE_ACL_SET_FILE 1
 
-/* True for FreeBSD with NFSv4 ACL support */
-#cmakedefine HAVE_ACL_TYPE_NFS4 1
-
-/* True for MacOS ACL support */
-#cmakedefine HAVE_ACL_TYPE_EXTENDED 1
-
-/* True for systems with POSIX ACL support */
-#cmakedefine HAVE_ACL_USER 1
-
 /* Define to 1 if you have the `arc4random_buf' function. */
 #cmakedefine HAVE_ARC4RANDOM_BUF 1
 
@@ -371,6 +362,34 @@
 /* Define to 1 if you have the `cygwin_conv_path' function. */
 #cmakedefine HAVE_CYGWIN_CONV_PATH 1
 
+/* Define to 1 if you have the declaration of `ACE_GETACL', and to 0 if you
+   don't. */
+#cmakedefine HAVE_DECL_ACE_GETACL 1
+
+/* Define to 1 if you have the declaration of `ACE_GETACLCNT', and to 0 if you
+   don't. */
+#cmakedefine HAVE_DECL_ACE_GETACLCNT 1
+
+/* Define to 1 if you have the declaration of `ACE_SETACL', and to 0 if you
+   don't. */
+#cmakedefine HAVE_DECL_ACE_SETACL 1
+
+/* Define to 1 if you have the declaration of `ACL_SYNCHRONIZE', and to 0 if
+   you don't. */
+#cmakedefine HAVE_DECL_ACL_SYNCHRONIZE 1
+
+/* Define to 1 if you have the declaration of `ACL_TYPE_EXTENDED', and to 0 if
+   you don't. */
+#cmakedefine HAVE_DECL_ACL_TYPE_EXTENDED 1
+
+/* Define to 1 if you have the declaration of `ACL_TYPE_NFS4', and to 0 if you
+   don't. */
+#cmakedefine HAVE_DECL_ACL_TYPE_NFS4 1
+
+/* Define to 1 if you have the declaration of `ACL_USER', and to 0 if you
+   don't. */
+#cmakedefine HAVE_DECL_ACL_USER 1
+
 /* Define to 1 if you have the declaration of `INT32_MAX', and to 0 if you
    don't. */
 #cmakedefine HAVE_DECL_INT32_MAX 1
@@ -395,6 +414,10 @@
    don't. */
 #cmakedefine HAVE_DECL_INTMAX_MIN 1
 
+/* Define to 1 if you have the declaration of `SETACL', and to 0 if you don't.
+   */
+#cmakedefine HAVE_DECL_SETACL 1
+
 /* Define to 1 if you have the declaration of `SIZE_MAX', and to 0 if you
    don't. */
 #cmakedefine HAVE_DECL_SIZE_MAX 1
@@ -468,6 +491,14 @@
 /* Define to 1 if EXTATTR_NAMESPACE_USER is defined in sys/extattr.h. */
 #cmakedefine HAVE_DECL_EXTATTR_NAMESPACE_USER 1
 
+/* Define to 1 if you have the declaration of `GETACL', and to 0 if you don't.
+   */
+#cmakedefine HAVE_DECL_GETACL 1
+
+/* Define to 1 if you have the declaration of `GETACLCNT', and to 0 if you
+   don't. */
+#cmakedefine HAVE_DECL_GETACLCNT 1
+
 /* Define to 1 if you have the `fchdir' function. */
 #cmakedefine HAVE_FCHDIR 1
 
@@ -742,6 +773,9 @@
 /* Define to 1 if you have the `mbrtowc' function. */
 #cmakedefine HAVE_MBRTOWC 1
 
+/* Define to 1 if you have the <membership.h> header file. */
+#cmakedefine HAVE_MEMBERSHIP_H 1
+
 /* Define to 1 if you have the `memmove' function. */
 #cmakedefine HAVE_MEMMOVE 1
 
diff --git a/build/version b/build/version
index 3cddc6c..6d36e9c 100644
--- a/build/version
+++ b/build/version
@@ -1 +1 @@
-3003001dev
+3003002dev
diff --git a/cat/test/CMakeLists.txt b/cat/test/CMakeLists.txt
index 7f1ce5e..0623cc3 100644
--- a/cat/test/CMakeLists.txt
+++ b/cat/test/CMakeLists.txt
@@ -29,6 +29,11 @@
   # Register target
   #
   ADD_EXECUTABLE(bsdcat_test ${bsdcat_test_SOURCES})
+  IF(ENABLE_ACL)
+    IF(HAVE_LIBACL)
+      TARGET_LINK_LIBRARIES(bsdcat_test ${ACL_LIBRARY})
+    ENDIF(HAVE_LIBACL)
+  ENDIF(ENABLE_ACL)
   SET_PROPERTY(TARGET bsdcat_test PROPERTY COMPILE_DEFINITIONS LIST_H)
 
   #
diff --git a/configure.ac b/configure.ac
index b29917e..18420dc 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.3.1dev])
-m4_define([LIBARCHIVE_VERSION_N],[3003001])
+m4_define([LIBARCHIVE_VERSION_S],[3.3.2dev])
+m4_define([LIBARCHIVE_VERSION_N],[3003002])
 
 dnl bsdtar and bsdcpio versioning tracks libarchive
 m4_define([BSDTAR_VERSION_S],LIBARCHIVE_VERSION_S())
@@ -292,7 +292,6 @@
 AC_CHECK_HEADERS([sys/time.h sys/utime.h sys/utsname.h sys/vfs.h])
 AC_CHECK_HEADERS([time.h unistd.h utime.h wchar.h wctype.h])
 AC_CHECK_HEADERS([windows.h])
-AC_CHECK_HEADERS([Bcrypt.h])
 # check windows.h first; the other headers require it.
 AC_CHECK_HEADERS([wincrypt.h winioctl.h],[],[],
 [[#ifdef HAVE_WINDOWS_H
@@ -399,6 +398,9 @@
   AC_CHECK_LIB(lzo2,lzo1x_decompress_safe)
 fi
 
+AC_ARG_WITH([cng],
+  AS_HELP_STRING([--without-cng], [Don't build support of CNG(Crypto Next Generation)]))
+
 AC_ARG_WITH([nettle],
   AS_HELP_STRING([--without-nettle], [Don't build with crypto support from Nettle]))
 AC_ARG_WITH([openssl],
@@ -699,6 +701,7 @@
 if test "x$enable_acl" != "xno"; then
    AC_CHECK_HEADERS([acl/libacl.h])
    AC_CHECK_HEADERS([sys/acl.h])
+   AC_CHECK_HEADERS([membership.h])
    AC_CHECK_LIB([acl],[acl_get_file])
    AC_CHECK_FUNCS([acl_create_entry acl_get_fd_np])
    AC_CHECK_FUNCS([acl_init acl_set_fd acl_set_fd_np acl_set_file])
@@ -737,31 +740,23 @@
 	#endif
 	])
 
-    # Check for ACL_TYPE_NFS4
-    AC_CHECK_DECL([ACL_TYPE_NFS4],
-		[AC_DEFINE(HAVE_ACL_TYPE_NFS4, 1, [True for FreeBSD with NFSv4 ACL support])],
-		[],
-		[#include <sys/acl.h>])
+    # FreeBSD and POSIX
+    # MacOS has no ACL_USER in acl.h
+    AC_CHECK_DECLS([ACL_TYPE_NFS4, ACL_USER],
+		[], [],
+		[#include <sys/types.h>
+		#include <sys/acl.h>])
 
-    # MacOS has an acl.h that isn't POSIX.  It can be detected by
-    # checking for ACL_USER
-    AC_CHECK_DECL([ACL_USER],
-		[AC_DEFINE(HAVE_ACL_USER, 1, [True for systems with POSIX ACL support])],
-		[],
-		[#include <sys/acl.h>])
-
-    # MacOS has ACL_TYPE_EXTENDED instead
-    AC_CHECK_DECL([ACL_TYPE_EXTENDED],
-		[AC_DEFINE(HAVE_ACL_TYPE_EXTENDED, 1, [True for MacOS ACL support])],
-		[],
+    # MacOS ACL support
+    AC_CHECK_DECLS([ACL_TYPE_EXTENDED, ACL_SYNCHRONIZE], [], [],
 		[#include <sys/types.h>
 		#include <sys/acl.h>])
 
     # Solaris and derivates ACLs
-    AC_CHECK_LIB([sec], [acl_get])
     AC_CHECK_TYPES([aclent_t], [], [], [[#include <sys/acl.h>]])
     AC_CHECK_TYPES([ace_t], [], [], [[#include <sys/acl.h>]])
-    AC_CHECK_FUNCS(acl_get facl_get acl_set facl_set)
+    AC_CHECK_FUNCS(acl facl)
+    AC_CHECK_DECLS([GETACL, SETACL, GETACLCNT, ACE_GETACL, ACE_SETACL, ACE_GETACLCNT], [], [], [#include <sys/acl.h>])
 fi
 
 # Additional requirements
@@ -852,6 +847,16 @@
 	;;
 esac
 
+if test "x$with_cng" != "xno"; then
+    AC_CHECK_HEADERS([bcrypt.h],[
+        LIBS="$LIBS -lbcrypt"
+    ],[],
+    [[#ifdef HAVE_WINDOWS_H
+    # include <windows.h>
+    #endif
+    ]])
+fi
+
 if test "x$with_nettle" != "xno"; then
     AC_CHECK_HEADERS([nettle/md5.h nettle/ripemd160.h nettle/sha.h])
     AC_CHECK_HEADERS([nettle/pbkdf2.h nettle/aes.h nettle/hmac.h])
diff --git a/cpio/cpio.c b/cpio/cpio.c
index 6c20ee6..1691c75 100644
--- a/cpio/cpio.c
+++ b/cpio/cpio.c
@@ -108,22 +108,22 @@
 static int	file_to_archive(struct cpio *, const char *);
 static void	free_cache(struct name_cache *cache);
 static void	list_item_verbose(struct cpio *, struct archive_entry *);
-static void	long_help(void);
+static void	long_help(void) __LA_DEAD;
 static const char *lookup_gname(struct cpio *, gid_t gid);
 static int	lookup_gname_helper(struct cpio *,
 		    const char **name, id_t gid);
 static const char *lookup_uname(struct cpio *, uid_t uid);
 static int	lookup_uname_helper(struct cpio *,
 		    const char **name, id_t uid);
-static void	mode_in(struct cpio *);
-static void	mode_list(struct cpio *);
+static void	mode_in(struct cpio *) __LA_DEAD;
+static void	mode_list(struct cpio *) __LA_DEAD;
 static void	mode_out(struct cpio *);
 static void	mode_pass(struct cpio *, const char *);
 static const char *remove_leading_slash(const char *);
 static int	restore_time(struct cpio *, struct archive_entry *,
 		    const char *, int fd);
-static void	usage(void);
-static void	version(void);
+static void	usage(void) __LA_DEAD;
+static void	version(void) __LA_DEAD;
 static const char * passphrase_callback(struct archive *, void *);
 static void	passphrase_free(char *);
 
@@ -1344,23 +1344,23 @@
 		cache->cache[slot].name = NULL;
 	}
 
-	if (lookup_fn(cpio, &name, id) == 0) {
-		if (name == NULL || name[0] == '\0') {
-			/* If lookup failed, format it as a number. */
-			snprintf(asnum, sizeof(asnum), "%u", (unsigned)id);
-			name = asnum;
-		}
-		cache->cache[slot].name = strdup(name);
-		if (cache->cache[slot].name != NULL) {
-			cache->cache[slot].id = id;
-			return (cache->cache[slot].name);
-		}
-		/*
-		 * Conveniently, NULL marks an empty slot, so
-		 * if the strdup() fails, we've just failed to
-		 * cache it.  No recovery necessary.
-		 */
+	if (lookup_fn(cpio, &name, id)) {
+		/* If lookup failed, format it as a number. */
+		snprintf(asnum, sizeof(asnum), "%u", (unsigned)id);
+		name = asnum;
 	}
+
+	cache->cache[slot].name = strdup(name);
+	if (cache->cache[slot].name != NULL) {
+		cache->cache[slot].id = id;
+		return (cache->cache[slot].name);
+	}
+
+	/*
+	 * Conveniently, NULL marks an empty slot, so
+	 * if the strdup() fails, we've just failed to
+	 * cache it.  No recovery necessary.
+	 */
 	return (NULL);
 }
 
@@ -1381,15 +1381,14 @@
 	errno = 0;
 	pwent = getpwuid((uid_t)id);
 	if (pwent == NULL) {
-		*name = NULL;
-		if (errno != 0 && errno != ENOENT)
+		if (errno && errno != ENOENT)
 			lafe_warnc(errno, "getpwuid(%s) failed",
 			    cpio_i64toa((int64_t)id));
-		return (errno);
+		return 1;
 	}
 
 	*name = pwent->pw_name;
-	return (0);
+	return 0;
 }
 
 static const char *
@@ -1409,15 +1408,14 @@
 	errno = 0;
 	grent = getgrgid((gid_t)id);
 	if (grent == NULL) {
-		*name = NULL;
-		if (errno != 0)
+		if (errno && errno != ENOENT)
 			lafe_warnc(errno, "getgrgid(%s) failed",
 			    cpio_i64toa((int64_t)id));
-		return (errno);
+		return 1;
 	}
 
 	*name = grent->gr_name;
-	return (0);
+	return 0;
 }
 
 /*
diff --git a/cpio/test/CMakeLists.txt b/cpio/test/CMakeLists.txt
index ec9509b..cc5fe01 100644
--- a/cpio/test/CMakeLists.txt
+++ b/cpio/test/CMakeLists.txt
@@ -62,6 +62,11 @@
   # Register target
   #
   ADD_EXECUTABLE(bsdcpio_test ${bsdcpio_test_SOURCES})
+  IF(ENABLE_ACL)
+    IF(HAVE_LIBACL)
+      TARGET_LINK_LIBRARIES(bsdcpio_test ${ACL_LIBRARY})
+    ENDIF(HAVE_LIBACL)
+  ENDIF(ENABLE_ACL)
   SET_PROPERTY(TARGET bsdcpio_test PROPERTY COMPILE_DEFINITIONS LIST_H)
 
   #
diff --git a/libarchive/CMakeLists.txt b/libarchive/CMakeLists.txt
index 1f85c01..d55fa2d 100644
--- a/libarchive/CMakeLists.txt
+++ b/libarchive/CMakeLists.txt
@@ -106,6 +106,7 @@
   archive_string_composition.h
   archive_string_sprintf.c
   archive_util.c
+  archive_version_details.c
   archive_virtual.c
   archive_write.c
   archive_write_disk_acl.c
diff --git a/libarchive/archive.h b/libarchive/archive.h
index e74be4d..d6913f3 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 3003001
+#define	ARCHIVE_VERSION_NUMBER 3003002
 
 #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.3.1dev"
+#define	ARCHIVE_VERSION_ONLY_STRING "3.3.2dev"
 #define	ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
 __LA_DECL const char *	archive_version_string(void);
 
diff --git a/libarchive/archive_check_magic.c b/libarchive/archive_check_magic.c
index c695e58..288ce23 100644
--- a/libarchive/archive_check_magic.c
+++ b/libarchive/archive_check_magic.c
@@ -62,7 +62,7 @@
 	}
 }
 
-static void
+static __LA_DEAD void
 diediedie(void)
 {
 #if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG)
diff --git a/libarchive/archive_entry.3 b/libarchive/archive_entry.3
index f5e22af..f75916c 100644
--- a/libarchive/archive_entry.3
+++ b/libarchive/archive_entry.3
@@ -25,7 +25,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd Feburary 2, 2012
+.Dd February 2, 2012
 .Dt ARCHIVE_ENTRY 3
 .Os
 .Sh NAME
diff --git a/libarchive/archive_entry.c b/libarchive/archive_entry.c
index 10eff11..e268194 100644
--- a/libarchive/archive_entry.c
+++ b/libarchive/archive_entry.c
@@ -401,7 +401,7 @@
 	return (NULL);
 }
 
-int64_t
+la_int64_t
 archive_entry_gid(struct archive_entry *entry)
 {
 	return (entry->ae_stat.aest_gid);
@@ -502,7 +502,7 @@
 	return (archive_mstring_get_mbs_l(&entry->ae_hardlink, p, len, sc));
 }
 
-int64_t
+la_int64_t
 archive_entry_ino(struct archive_entry *entry)
 {
 	return (entry->ae_stat.aest_ino);
@@ -514,7 +514,7 @@
 	return (entry->ae_set & AE_SET_INO);
 }
 
-int64_t
+la_int64_t
 archive_entry_ino64(struct archive_entry *entry)
 {
 	return (entry->ae_stat.aest_ino);
@@ -627,7 +627,7 @@
 		return minor(entry->ae_stat.aest_rdev);
 }
 
-int64_t
+la_int64_t
 archive_entry_size(struct archive_entry *entry)
 {
 	return (entry->ae_stat.aest_size);
@@ -715,7 +715,7 @@
 	return (archive_mstring_get_mbs_l( &entry->ae_symlink, p, len, sc));
 }
 
-int64_t
+la_int64_t
 archive_entry_uid(struct archive_entry *entry)
 {
 	return (entry->ae_stat.aest_uid);
@@ -819,7 +819,7 @@
 }
 
 void
-archive_entry_set_gid(struct archive_entry *entry, int64_t g)
+archive_entry_set_gid(struct archive_entry *entry, la_int64_t g)
 {
 	entry->stat_valid = 0;
 	entry->ae_stat.aest_gid = g;
@@ -868,7 +868,7 @@
 }
 
 void
-archive_entry_set_ino(struct archive_entry *entry, int64_t ino)
+archive_entry_set_ino(struct archive_entry *entry, la_int64_t ino)
 {
 	entry->stat_valid = 0;
 	entry->ae_set |= AE_SET_INO;
@@ -876,7 +876,7 @@
 }
 
 void
-archive_entry_set_ino64(struct archive_entry *entry, int64_t ino)
+archive_entry_set_ino64(struct archive_entry *entry, la_int64_t ino)
 {
 	entry->stat_valid = 0;
 	entry->ae_set |= AE_SET_INO;
@@ -1209,7 +1209,7 @@
 }
 
 void
-archive_entry_set_size(struct archive_entry *entry, int64_t s)
+archive_entry_set_size(struct archive_entry *entry, la_int64_t s)
 {
 	entry->stat_valid = 0;
 	entry->ae_stat.aest_size = s;
@@ -1306,7 +1306,7 @@
 }
 
 void
-archive_entry_set_uid(struct archive_entry *entry, int64_t u)
+archive_entry_set_uid(struct archive_entry *entry, la_int64_t u)
 {
 	entry->stat_valid = 0;
 	entry->ae_stat.aest_uid = u;
diff --git a/libarchive/archive_entry.h b/libarchive/archive_entry.h
index 7645f0c..bcc2962 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 3003001
+#define	ARCHIVE_VERSION_NUMBER 3003002
 
 /*
  * Note: archive_entry.h is for use outside of libarchive; the
diff --git a/libarchive/archive_entry_acl.3 b/libarchive/archive_entry_acl.3
index c5115f7..534dbfa 100644
--- a/libarchive/archive_entry_acl.3
+++ b/libarchive/archive_entry_acl.3
@@ -32,7 +32,7 @@
 .Nm archive_entry_acl_clear ,
 .Nm archive_entry_acl_count ,
 .Nm archive_entry_acl_from_text ,
-.Nm archive_entry_acl_from_text_w,
+.Nm archive_entry_acl_from_text_w ,
 .Nm archive_entry_acl_next ,
 .Nm archive_entry_acl_next_w ,
 .Nm archive_entry_acl_reset ,
@@ -267,7 +267,7 @@
 .It Dv ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT ( Sy n )
 Do not propagate inherit flags. Only first-level entries inherit ACLs.
 .It Dv ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS ( Sy S )
-Trigger alarm or audit on succesful access.
+Trigger alarm or audit on successful access.
 .It Dv ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS ( Sy F )
 Trigger alarm or audit on failed access.
 .It Dv ARCHIVE_ENTRY_ACL_ENTRY_INHERITED ( Sy I )
@@ -279,7 +279,7 @@
 .Fn archive_entry_acl_add_entry_w
 add a single ACL entry.
 For the access ACL and non-extended principals, the classic Unix permissions
-are updated. An archive enry cannot contain both POSIX.1e and NFSv4 ACL
+are updated. An archive entry cannot contain both POSIX.1e and NFSv4 ACL
 entries.
 .Pp
 .Fn archive_entry_acl_clear
@@ -303,7 +303,7 @@
 for NFSv4 ACLs. For POSIX.1e ACLs if
 .Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS
 is included and at least one extended ACL entry is found,
-the three non-extened ACLs are added.
+the three non-extended ACLs are added.
 .Pp
 .Fn archive_entry_acl_from_text
 and
@@ -367,7 +367,7 @@
 .Fn archive_entry_acl_to_text_w
 convert the ACL entries for the given type into a
 .Pq wide
-string of ACL entries separated by newline. If the the pointer
+string of ACL entries separated by newline. If the pointer
 .Fa len_p
 is not NULL, then the function shall return the length of the string
 .Pq not including the NULL terminator
diff --git a/libarchive/archive_entry_paths.3 b/libarchive/archive_entry_paths.3
index fd22cf7..f647212 100644
--- a/libarchive/archive_entry_paths.3
+++ b/libarchive/archive_entry_paths.3
@@ -31,25 +31,25 @@
 .Nm archive_entry_set_hardlink ,
 .Nm archive_entry_copy_hardlink ,
 .Nm archive_entry_copy_hardlink_w ,
-.Nm archve_entry_update_hardlink_utf8 ,
+.Nm archive_entry_update_hardlink_utf8 ,
 .Nm archive_entry_set_link ,
 .Nm archive_entry_copy_link ,
 .Nm archive_entry_copy_link_w ,
-.Nm archve_entry_update_link_utf8 ,
+.Nm archive_entry_update_link_utf8 ,
 .Nm archive_entry_pathname ,
 .Nm archive_entry_pathname_w ,
 .Nm archive_entry_set_pathname ,
 .Nm archive_entry_copy_pathname ,
 .Nm archive_entry_copy_pathname_w ,
-.Nm archve_entry_update_pathname_utf8 ,
+.Nm archive_entry_update_pathname_utf8 ,
 .Nm archive_entry_sourcepath ,
 .Nm archive_entry_copy_sourcepath ,
-.Nm archive_entry_symlink,
-.Nm archive_entry_symlink_w,
+.Nm archive_entry_symlink ,
+.Nm archive_entry_symlink_w ,
 .Nm archive_entry_set_symlink ,
 .Nm archive_entry_copy_symlink ,
 .Nm archive_entry_copy_symlink_w ,
-.Nm archve_entry_update_symlink_utf8
+.Nm archive_entry_update_symlink_utf8
 .Nd functions for manipulating path names in archive entry descriptions
 .Sh LIBRARY
 Streaming Archive Library (libarchive, -larchive)
diff --git a/libarchive/archive_entry_perms.3 b/libarchive/archive_entry_perms.3
index 340c5ea..aae3648 100644
--- a/libarchive/archive_entry_perms.3
+++ b/libarchive/archive_entry_perms.3
@@ -34,8 +34,8 @@
 .Nm archive_entry_perm ,
 .Nm archive_entry_set_perm ,
 .Nm archive_entry_strmode ,
-.Nm archive_entry_uname
-.Nm archive_entry_uname_w
+.Nm archive_entry_uname ,
+.Nm archive_entry_uname_w ,
 .Nm archive_entry_set_uname ,
 .Nm archive_entry_copy_uname ,
 .Nm archive_entry_copy_uname_w ,
diff --git a/libarchive/archive_platform.h b/libarchive/archive_platform.h
index c9a9602..01d6a70 100644
--- a/libarchive/archive_platform.h
+++ b/libarchive/archive_platform.h
@@ -148,23 +148,31 @@
  * 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
+#if HAVE_DECL_ACL_USER
 #define	HAVE_POSIX_ACL	1
-#elif HAVE_ACL_TYPE_EXTENDED
+#elif HAVE_DECL_ACL_TYPE_EXTENDED && HAVE_MEMBERSHIP_H
 #define HAVE_DARWIN_ACL 1
 #endif
+#if HAVE_DECL_ACL_TYPE_NFS4
+#define	HAVE_FREEBSD_NFS4_ACL 1
+#endif
 #endif
 
 /*
- * If this platform has <sys/acl.h>, acl_get(), facl_get(), acl_set(),
+ * If this platform has <sys/acl.h>, acl(), facl() and ACLENT_T
  * 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
+#if HAVE_SYS_ACL_H && HAVE_ACL && HAVE_FACL && HAVE_ACLENT_T && \
+    HAVE_DECL_GETACL && HAVE_DECL_GETACLCNT && HAVE_DECL_SETACL
 #define	HAVE_SUN_ACL	1
+#if HAVE_ACE_T && HAVE_DECL_ACE_GETACL && HAVE_DECL_ACE_GETACLCNT && \
+    HAVE_DECL_ACE_SETACL
+#define HAVE_SUN_NFS4_ACL	1
+#endif
 #endif
 
 /* Define if platform supports NFSv4 ACLs */
-#if (HAVE_POSIX_ACL && HAVE_ACL_TYPE_NFS4) || HAVE_SUN_ACL || HAVE_DARWIN_ACL
+#if HAVE_FREEBSD_NFS4_ACL || HAVE_SUN_NFS4_ACL || HAVE_DARWIN_ACL
 #define HAVE_NFS4_ACL	1
 #endif
 
diff --git a/libarchive/archive_read_disk.3 b/libarchive/archive_read_disk.3
index 2a5c130..55e4bbb 100644
--- a/libarchive/archive_read_disk.3
+++ b/libarchive/archive_read_disk.3
@@ -37,10 +37,7 @@
 .Nm archive_read_disk_uname ,
 .Nm archive_read_disk_set_uname_lookup ,
 .Nm archive_read_disk_set_gname_lookup ,
-.Nm archive_read_disk_set_standard_lookup ,
-.Nm archive_read_close ,
-.Nm archive_read_finish ,
-.Nm archive_read_free
+.Nm archive_read_disk_set_standard_lookup
 .Nd functions for reading objects from disk
 .Sh LIBRARY
 Streaming Archive Library (libarchive, -larchive)
@@ -81,12 +78,6 @@
 .Fa "int fd"
 .Fa "const struct stat *"
 .Fc
-.Ft int
-.Fn archive_read_close "struct archive *"
-.Ft int
-.Fn archive_read_finish "struct archive *"
-.Ft int
-.Fn archive_read_free "struct archive *"
 .Sh DESCRIPTION
 These functions provide an API for reading information about
 objects on disk.
@@ -181,17 +172,6 @@
 This affects the file ownership fields and ACL values in the
 .Tn struct archive_entry
 object.
-.It Fn archive_read_close
-Does nothing for
-.Tn archive_read_disk
-handles.
-.It Fn archive_read_finish
-This is a deprecated synonym for
-.Fn archive_read_free .
-.It Fn archive_read_free
-Invokes
-.Fn archive_read_close
-if it was not invoked manually, then releases all resources.
 .El
 More information about the
 .Va struct archive
diff --git a/libarchive/archive_read_disk_entry_from_file.c b/libarchive/archive_read_disk_entry_from_file.c
index b2f1d17..1c94afd 100644
--- a/libarchive/archive_read_disk_entry_from_file.c
+++ b/libarchive/archive_read_disk_entry_from_file.c
@@ -40,8 +40,6 @@
 #endif
 #ifdef HAVE_DARWIN_ACL
 #include <membership.h>
-#include <grp.h>
-#include <pwd.h>
 #endif
 #ifdef HAVE_SYS_EXTATTR_H
 #include <sys/extattr.h>
@@ -124,11 +122,9 @@
 #endif
 
 /* NFSv4 platform ACL type */
-#if HAVE_SUN_ACL
-#define	ARCHIVE_PLATFORM_ACL_TYPE_NFS4	ACE_T
-#elif HAVE_DARWIN_ACL
+#if HAVE_DARWIN_ACL
 #define	ARCHIVE_PLATFORM_ACL_TYPE_NFS4	ACL_TYPE_EXTENDED
-#elif HAVE_ACL_TYPE_NFS4
+#elif HAVE_FREEBSD_NFS4_ACL
 #define	ARCHIVE_PLATFORM_ACL_TYPE_NFS4	ACL_TYPE_NFS4
 #endif
 
@@ -435,14 +431,71 @@
 
 #if HAVE_SUN_ACL
 static int
-sun_acl_is_trivial(acl_t *, mode_t, int *trivialp);
+sun_acl_is_trivial(void *, int, mode_t, int, int, int *);
+
+static void *
+sunacl_get(int cmd, int *aclcnt, int fd, const char *path)
+{
+	int cnt, cntcmd;
+	size_t size;
+	void *aclp;
+
+	if (cmd == GETACL) {
+		cntcmd = GETACLCNT;
+		size = sizeof(aclent_t);
+	}
+#if HAVE_SUN_NFS4_ACL
+	else if (cmd == ACE_GETACL) {
+		cntcmd = ACE_GETACLCNT;
+		size = sizeof(ace_t);
+	}
 #endif
+	else {
+		errno = EINVAL;
+		*aclcnt = -1;
+		return (NULL);
+	}
+
+	aclp = NULL;
+	cnt = -2;
+
+	while (cnt == -2 || (cnt == -1 && errno == ENOSPC)) {
+		if (path != NULL)
+			cnt = acl(path, cntcmd, 0, NULL);
+		else
+			cnt = facl(fd, cntcmd, 0, NULL);
+
+		if (cnt > 0) {
+			if (aclp == NULL)
+				aclp = malloc(cnt * size);
+			else
+				aclp = realloc(NULL, cnt * size);
+			if (aclp != NULL) {
+				if (path != NULL)
+					cnt = acl(path, cmd, cnt, aclp);
+				else
+					cnt = facl(fd, cmd, cnt, aclp);
+			}
+		} else {
+			if (aclp != NULL) {
+				free(aclp);
+				aclp = NULL;
+			}
+			break;
+		}
+	}
+
+	*aclcnt = cnt;
+	return (aclp);
+}
+#endif	/* HAVE_SUN_ACL */
 
 #if HAVE_POSIX_ACL || HAVE_NFS4_ACL
 static int translate_acl(struct archive_read_disk *a,
     struct archive_entry *entry,
 #if HAVE_SUN_ACL
-    acl_t *acl,
+    void *aclp,
+    int aclcnt,
 #else
     acl_t acl,
 #endif
@@ -454,7 +507,8 @@
 {
 	const char	*accpath;
 #if HAVE_SUN_ACL
-	acl_t		*acl;
+	void		*aclp;
+	int		aclcnt;
 #else
 	acl_t		acl;
 #endif
@@ -491,14 +545,17 @@
 
 	archive_entry_acl_clear(entry);
 
+#if HAVE_SUN_ACL
+	aclp = NULL;
+#else
 	acl = NULL;
+#endif
 
 #if HAVE_NFS4_ACL
 	/* Try NFSv4 ACL first. */
 	if (*fd >= 0)
 #if HAVE_SUN_ACL
-		/* Solaris reads both POSIX.1e and NFSv4 ACL here */
-		facl_get(*fd, 0, &acl);
+		aclp = sunacl_get(ACE_GETACL, &aclcnt, *fd, NULL);
 #elif HAVE_ACL_GET_FD_NP
 		acl = acl_get_fd_np(*fd, ARCHIVE_PLATFORM_ACL_TYPE_NFS4);
 #else
@@ -512,47 +569,62 @@
 	    && (archive_entry_filetype(entry) == AE_IFLNK))
 		/* We can't get the ACL of a symlink, so we assume it can't
 		   have one. */
+#if HAVE_SUN_ACL
+		aclp = NULL;
+#else
 		acl = NULL;
 #endif
+#endif /* !HAVE_ACL_GET_LINK_NP */
 	else
 #if HAVE_SUN_ACL
 		/* Solaris reads both POSIX.1e and NFSv4 ACLs here */
-		acl_get(accpath, 0, &acl);
+		aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, accpath);
 #else
 		acl = acl_get_file(accpath, ARCHIVE_PLATFORM_ACL_TYPE_NFS4);
 #endif
 
 
-#if HAVE_ACL_IS_TRIVIAL_NP || HAVE_SUN_ACL
 	/* Ignore "trivial" ACLs that just mirror the file mode. */
-	if (acl != NULL) {
 #if HAVE_SUN_ACL
-		if (sun_acl_is_trivial(acl, archive_entry_mode(entry),
-		    &r) == 0 && r == 1)
-#elif HAVE_ACL_IS_TRIVIAL_NP
-		if (acl_is_trivial_np(acl, &r) == 0 && r == 1)
-#endif
-		{
-			acl_free(acl);
-			acl = NULL;
-			/*
-			 * Simultaneous NFSv4 and POSIX.1e ACLs for the same
-			 * entry are not allowed, so we should return here
-			 */
-			return (ARCHIVE_OK);
-		}
+	if (aclp != NULL && sun_acl_is_trivial(aclp, aclcnt,
+	    archive_entry_mode(entry), 1, S_ISDIR(archive_entry_mode(entry)),
+	    &r) == 0 && r == 1) {
+		free(aclp);
+		aclp = NULL;
+		return (ARCHIVE_OK);
 	}
-#endif	/* HAVE_ACL_IS_TRIVIAL_NP || HAVE_SUN_ACL */
-	if (acl != NULL) {
-		r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4);
+#elif HAVE_ACL_IS_TRIVIAL_NP
+	if (acl != NULL && acl_is_trivial_np(acl, &r) == 0 && r == 1) {
 		acl_free(acl);
+		acl = NULL;
+		return (ARCHIVE_OK);
+	}
+#endif
+
+#if HAVE_SUN_ACL
+	if (aclp != NULL)
+#else
+	if (acl != NULL)
+#endif
+	{
+		r = translate_acl(a, entry,
+#if HAVE_SUN_ACL
+		    aclp, aclcnt,
+#else
+		    acl,
+#endif
+		    ARCHIVE_ENTRY_ACL_TYPE_NFS4);
+#if HAVE_SUN_ACL
+		free(aclp);
+		aclp = NULL;
+#else
+		acl_free(acl);
+		acl = NULL;
+#endif
+
 		if (r != ARCHIVE_OK) {
 			archive_set_error(&a->archive, errno,
-			    "Couldn't translate "
-#if !HAVE_SUN_ACL
-			    "NFSv4 "
-#endif
-			    "ACLs");
+			    "Couldn't translate NFSv4 ACLs");
 		}
 #if HAVE_DARWIN_ACL
 		/*
@@ -569,12 +641,16 @@
 	}
 #endif	/* HAVE_NFS4_ACL */
 
-#if HAVE_POSIX_ACL
-	/* This code path is skipped on MacOS and Solaris */
+#if HAVE_POSIX_ACL || HAVE_SUN_ACL
+	/* This code path is skipped on MacOS */
 
 	/* Retrieve access ACL from file. */
 	if (*fd >= 0)
+#if HAVE_SUN_ACL
+		aclp = sunacl_get(GETACL, &aclcnt, *fd, NULL);
+#else
 		acl = acl_get_fd(*fd);
+#endif
 #if HAVE_ACL_GET_LINK_NP
 	else if (!a->follow_symlinks)
 		acl = acl_get_link_np(accpath, ACL_TYPE_ACCESS);
@@ -583,25 +659,56 @@
 	    && (archive_entry_filetype(entry) == AE_IFLNK))
 		/* We can't get the ACL of a symlink, so we assume it can't
 		   have one. */
+#if HAVE_SUN_ACL
+		aclp = NULL;
+#else
 		acl = NULL;
 #endif
+#endif /* !HAVE_ACL_GET_LINK_NP */
 	else
+#if HAVE_SUN_ACL
+		aclp = sunacl_get(GETACL, &aclcnt, 0, accpath);
+#else
 		acl = acl_get_file(accpath, ACL_TYPE_ACCESS);
+#endif
 
-#if HAVE_ACL_IS_TRIVIAL_NP
+
 	/* Ignore "trivial" ACLs that just mirror the file mode. */
-	if (acl != NULL && acl_is_trivial_np(acl, &r) == 0) {
-		if (r) {
-			acl_free(acl);
-			acl = NULL;
-		}
+#if HAVE_SUN_ACL
+	if (aclp != NULL && sun_acl_is_trivial(aclp, aclcnt,
+	    archive_entry_mode(entry), 0, S_ISDIR(archive_entry_mode(entry)),
+	    &r) == 0 && r == 1) {
+		free(aclp);
+		aclp = NULL;
+	}
+#elif HAVE_ACL_IS_TRIVIAL_NP
+	if (acl != NULL && acl_is_trivial_np(acl, &r) == 0 && r == 1) {
+		acl_free(acl);
+		acl = NULL;
 	}
 #endif
 
-	if (acl != NULL) {
-		r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
+#if HAVE_SUN_ACL
+	if (aclp != NULL)
+#else
+	if (acl != NULL)
+#endif
+	{
+		r = translate_acl(a, entry,
+#if HAVE_SUN_ACL
+		    aclp, aclcnt,
+#else
+		    acl,
+#endif
+		    ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
+#if HAVE_SUN_ACL
+		free(aclp);
+		aclp = NULL;
+#else
 		acl_free(acl);
 		acl = NULL;
+#endif
+
 		if (r != ARCHIVE_OK) {
 			archive_set_error(&a->archive, errno,
 			    "Couldn't translate access ACLs");
@@ -609,6 +716,7 @@
 		}
 	}
 
+#if !HAVE_SUN_ACL
 	/* Only directories can have default ACLs. */
 	if (S_ISDIR(archive_entry_mode(entry))) {
 #if HAVE_ACL_GET_FD_NP
@@ -628,7 +736,8 @@
 			}
 		}
 	}
-#endif	/* HAVE_POSIX_ACL */
+#endif	/* !HAVE_SUN_ACL */
+#endif	/* HAVE_POSIX_ACL || HAVE_SUN_ACL */
 	return (ARCHIVE_OK);
 }
 
@@ -674,12 +783,14 @@
 	{ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_SECURITY},
 	{ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_SECURITY},
 	{ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_CHANGE_OWNER},
+#if HAVE_DECL_ACL_SYNCHRONIZE
 	{ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
+#endif
 #else	/* POSIX.1e ACL permissions */
 	{ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
 	{ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE},
 	{ARCHIVE_ENTRY_ACL_READ, ACL_READ},
-#if HAVE_ACL_TYPE_NFS4	/* FreeBSD NFSv4 ACL permissions */
+#if HAVE_FREEBSD_NFS4_ACL	/* FreeBSD NFSv4 ACL permissions */
 	{ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
 	{ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
 	{ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
@@ -708,14 +819,16 @@
 	const int archive_inherit;
 	const int platform_inherit;
 } acl_inherit_map[] = {
-#if HAVE_SUN_ACL	/* Solaris ACL inheritance flags */
+#if HAVE_SUN_NFS4_ACL	/* Solaris ACL inheritance flags */
 	{ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACE_FILE_INHERIT_ACE},
 	{ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACE_DIRECTORY_INHERIT_ACE},
 	{ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACE_NO_PROPAGATE_INHERIT_ACE},
 	{ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACE_INHERIT_ONLY_ACE},
 	{ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACE_SUCCESSFUL_ACCESS_ACE_FLAG},
 	{ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACE_FAILED_ACCESS_ACE_FLAG},
+#ifdef ACE_INHERITED_ACE
 	{ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACE_INHERITED_ACE}
+#endif
 #elif HAVE_DARWIN_ACL	/* MacOS NFSv4 inheritance flags */
 	{ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED},
 	{ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
@@ -730,7 +843,7 @@
 	{ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACL_ENTRY_SUCCESSFUL_ACCESS},
 	{ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACL_ENTRY_FAILED_ACCESS},
 	{ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED}
-#endif	/* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
+#endif	/* !HAVE_SUN_NFS4_ACL && !HAVE_DARWIN_ACL */
 };
 #endif	/* HAVE_NFS4_ACL */
 
@@ -741,8 +854,6 @@
 	void *q;
 	uid_t ugid;
 	int r, idtype;
-	struct passwd *pwd;
-	struct group *grp;
 
 	q = acl_get_qualifier(acl_entry);
 	if (q == NULL)
@@ -754,24 +865,12 @@
 	}
 	if (idtype == ID_TYPE_UID) {
 		*ae_tag = ARCHIVE_ENTRY_ACL_USER;
-		pwd = getpwuuid(q);
-		if (pwd == NULL) {
-			*ae_id = ugid;
-			*ae_name = NULL;
-		} else {
-			*ae_id = pwd->pw_uid;
-			*ae_name = archive_read_disk_uname(a, *ae_id);
-		}
+		*ae_id = ugid;
+		*ae_name = archive_read_disk_uname(a, *ae_id);
 	} else if (idtype == ID_TYPE_GID) {
 		*ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
-		grp = getgruuid(q);
-		if (grp == NULL) {
-			*ae_id = ugid;
-			*ae_name = NULL;
-		} else {
-			*ae_id = grp->gr_gid;
-			*ae_name = archive_read_disk_gname(a, *ae_id);
-		}
+		*ae_id = ugid;
+		*ae_name = archive_read_disk_gname(a, *ae_id);
 	} else
 		r = 1;
 
@@ -873,9 +972,11 @@
  * This is a FreeBSD acl_is_trivial_np() implementation for Solaris
  */
 static int
-sun_acl_is_trivial(acl_t *acl, mode_t mode, int *trivialp)
+sun_acl_is_trivial(void *aclp, int aclcnt, mode_t mode, int is_nfs4,
+    int is_dir, int *trivialp)
 {
 	int i, p;
+#if HAVE_SUN_NFS4_ACL
 	const uint32_t rperm = ACE_READ_DATA;
 	const uint32_t wperm = ACE_WRITE_DATA | ACE_APPEND_DATA;
 	const uint32_t eperm = ACE_EXECUTE;
@@ -886,30 +987,25 @@
 
 	ace_t *ace;
 	ace_t tace[6];
+#endif
 
-	if (acl == NULL || trivialp == NULL)
+	if (aclp == NULL || trivialp == NULL)
 		return (-1);
 
 	*trivialp = 0;
 
-	/* ACL_IS_TRIVIAL flag must be set for both POSIX.1e and NFSv4 ACLs */
-	if ((acl->acl_flags & ACL_IS_TRIVIAL) == 0)
-		return (0);
-
 	/*
 	 * POSIX.1e ACLs marked with ACL_IS_TRIVIAL are compatible with
 	 * FreeBSD acl_is_trivial_np(). On Solaris they have 4 entries,
 	 * including mask.
 	 */
-	if (acl->acl_type == ACLENT_T) {
-		if (acl->acl_cnt == 4)
+	if (!is_nfs4) {
+		if (aclcnt == 4)
 			*trivialp = 1;
 		return (0);
 	}
 
-	if (acl->acl_type != ACE_T || acl->acl_entry_size != sizeof(ace_t))
-		return (-1);
-
+#if HAVE_SUN_NFS4_ACL
 	/*
 	 * Continue with checking NFSv4 ACLs
 	 *
@@ -994,13 +1090,13 @@
 		if (tace[i].a_access_mask != 0)
 			p++;
 	}
-	if (acl->acl_cnt != p)
+	if (aclcnt != p)
 		return (0);
 
 	p = 0;
 	for (i = 0; i < 6; i++) {
 		if (tace[i].a_access_mask != 0) {
-			ace = &((ace_t *)acl->acl_aclp)[p];
+			ace = &((ace_t *)aclp)[p];
 			/*
 			 * Illumos added ACE_DELETE_CHILD to write perms for
 			 * directories. We have to check against that, too.
@@ -1008,8 +1104,7 @@
 			if (ace->a_flags != tace[i].a_flags ||
 			    ace->a_type != tace[i].a_type ||
 			    (ace->a_access_mask != tace[i].a_access_mask &&
-			    ((acl->acl_flags & ACL_IS_DIR) == 0 ||
-			    (tace[i].a_access_mask & wperm) == 0 ||
+			    (!is_dir || (tace[i].a_access_mask & wperm) == 0 ||
 			    ace->a_access_mask !=
 			    (tace[i].a_access_mask | ACE_DELETE_CHILD))))
 				return (0);
@@ -1018,6 +1113,9 @@
 	}
 
 	*trivialp = 1;
+#else	/* !HAVE_SUN_NFS4_ACL */
+	(void)aclp;	/* UNUSED */
+#endif	/* !HAVE_SUN_NFS4_ACL */
 	return (0);
 }
 #endif	/* HAVE_SUN_ACL */
@@ -1028,27 +1126,29 @@
  */
 static int
 translate_acl(struct archive_read_disk *a,
-    struct archive_entry *entry, acl_t *acl, int default_entry_acl_type)
+    struct archive_entry *entry, void *aclp, int aclcnt,
+    int default_entry_acl_type)
 {
 	int e, i;
 	int ae_id, ae_tag, ae_perm;
 	int entry_acl_type;
 	const char *ae_name;
 	aclent_t *aclent;
+#if HAVE_SUN_NFS4_ACL
 	ace_t *ace;
+#endif
 
-	(void)default_entry_acl_type;
-
-	if (acl->acl_cnt <= 0)
+	if (aclcnt <= 0)
 		return (ARCHIVE_OK);
 
-	for (e = 0; e < acl->acl_cnt; e++) {
+	for (e = 0; e < aclcnt; e++) {
 		ae_name = NULL;
 		ae_tag = 0;
 		ae_perm = 0;
 
-		if (acl->acl_type == ACE_T) {
-			ace = &((ace_t *)acl->acl_aclp)[e];
+#if HAVE_SUN_NFS4_ACL
+		if (default_entry_acl_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
+			ace = &((ace_t *)aclp)[e];
 			ae_id = ace->a_who;
 
 			switch(ace->a_type) {
@@ -1100,8 +1200,10 @@
 					ae_perm |=
 					    acl_perm_map[i].archive_perm;
 			}
-		} else {
-			aclent = &((aclent_t *)acl->acl_aclp)[e];
+		} else
+#endif	/* HAVE_SUN_NFS4_ACL */
+		if (default_entry_acl_type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) {
+			aclent = &((aclent_t *)aclp)[e];
 			if ((aclent->a_type & ACL_DEFAULT) != 0)
 				entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
 			else
@@ -1148,7 +1250,8 @@
 				ae_perm |= ARCHIVE_ENTRY_ACL_WRITE;
 			if ((aclent->a_perm & 4) != 0)
 				ae_perm |= ARCHIVE_ENTRY_ACL_READ;
-		} /* default_entry_acl_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4 */
+		} else
+			return (ARCHIVE_WARN);
 
 		archive_entry_acl_add_entry(entry, entry_acl_type,
 		    ae_perm, ae_tag, ae_id, ae_name);
@@ -1165,11 +1268,11 @@
     struct archive_entry *entry, acl_t acl, int default_entry_acl_type)
 {
 	acl_tag_t	 acl_tag;
-#if HAVE_ACL_TYPE_NFS4
+#if HAVE_FREEBSD_NFS4_ACL
 	acl_entry_type_t acl_type;
 	int brand;
 #endif
-#if HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL
+#if HAVE_FREEBSD_NFS4_ACL || HAVE_DARWIN_ACL
 	acl_flagset_t	 acl_flagset;
 #endif
 	acl_entry_t	 acl_entry;
@@ -1181,7 +1284,7 @@
 #endif
 	const char	*ae_name;
 
-#if HAVE_ACL_TYPE_NFS4
+#if HAVE_FREEBSD_NFS4_ACL
 	// FreeBSD "brands" ACLs as POSIX.1e or NFSv4
 	// Make sure the "brand" on this ACL is consistent
 	// with the default_entry_acl_type bits provided.
@@ -1272,7 +1375,7 @@
 		case ACL_OTHER:
 			ae_tag = ARCHIVE_ENTRY_ACL_OTHER;
 			break;
-#if HAVE_ACL_TYPE_NFS4
+#if HAVE_FREEBSD_NFS4_ACL
 		case ACL_EVERYONE:
 			ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE;
 			break;
@@ -1307,9 +1410,9 @@
 		// XXX acl_type maps to allow/deny/audit/YYYY bits
 		entry_acl_type = default_entry_acl_type;
 #endif
-#if HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL
+#if HAVE_FREEBSD_NFS4_ACL || HAVE_DARWIN_ACL
 		if (default_entry_acl_type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
-#if HAVE_ACL_TYPE_NFS4
+#if HAVE_FREEBSD_NFS4_ACL
 			/*
 			 * acl_get_entry_type_np() fails with non-NFSv4 ACLs
 			 */
@@ -1336,7 +1439,7 @@
 				    "Invalid NFSv4 ACL entry type");
 				return (ARCHIVE_WARN);
 			}
-#endif	/* HAVE_ACL_TYPE_NFS4 */
+#endif	/* HAVE_FREEBSD_NFS4_ACL */
 
 			/*
 			 * Libarchive stores "flag" (NFSv4 inheritance bits)
@@ -1361,7 +1464,7 @@
 					ae_perm |= acl_inherit_map[i].archive_inherit;
 			}
 		}
-#endif	/* HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL */
+#endif	/* HAVE_FREEBSD_NFS4_ACL || HAVE_DARWIN_ACL */
 
 		if (acl_get_permset(acl_entry, &acl_permset) != 0) {
 			archive_set_error(&a->archive, errno,
@@ -1382,6 +1485,11 @@
 				ae_perm |= acl_perm_map[i].archive_perm;
 		}
 
+#if HAVE_DARWIN_ACL && !HAVE_DECL_ACL_SYNCHRONIZE
+		/* On Mac OS X without ACL_SYNCHRONIZE assume it is set */
+		ae_perm |= ARCHIVE_ENTRY_ACL_SYNCHRONIZE;
+#endif
+
 		archive_entry_acl_add_entry(entry, entry_acl_type,
 					    ae_perm, ae_tag,
 					    ae_id, ae_name);
diff --git a/libarchive/archive_read_format.3 b/libarchive/archive_read_format.3
index 53b9a7e..91c5d2c 100644
--- a/libarchive/archive_read_format.3
+++ b/libarchive/archive_read_format.3
@@ -37,9 +37,9 @@
 .Nm archive_read_support_format_empty ,
 .Nm archive_read_support_format_iso9660 ,
 .Nm archive_read_support_format_lha ,
-.Nm archive_read_support_format_mtree,
-.Nm archive_read_support_format_rar,
-.Nm archive_read_support_format_raw,
+.Nm archive_read_support_format_mtree ,
+.Nm archive_read_support_format_rar ,
+.Nm archive_read_support_format_raw ,
 .Nm archive_read_support_format_tar ,
 .Nm archive_read_support_format_xar ,
 .Nm archive_read_support_format_zip
diff --git a/libarchive/archive_read_open.3 b/libarchive/archive_read_open.3
index 4d8272c..0249456 100644
--- a/libarchive/archive_read_open.3
+++ b/libarchive/archive_read_open.3
@@ -33,7 +33,7 @@
 .Nm archive_read_open_fd ,
 .Nm archive_read_open_FILE ,
 .Nm archive_read_open_filename ,
-.Nm archive_read_open_memory ,
+.Nm archive_read_open_memory
 .Nd functions for reading streaming archives
 .Sh LIBRARY
 Streaming Archive Library (libarchive, -larchive)
diff --git a/libarchive/archive_read_support_format_mtree.c b/libarchive/archive_read_support_format_mtree.c
index 4231ff5..00d3250 100644
--- a/libarchive/archive_read_support_format_mtree.c
+++ b/libarchive/archive_read_support_format_mtree.c
@@ -1857,33 +1857,38 @@
  * Note that this implementation does not (and should not!) obey
  * locale settings; you cannot simply substitute strtol here, since
  * it does obey locale.
+ *
+ * Convert the number pointed to by 'p' into a 64-bit signed integer.
+ * On return, 'p' points to the first non-digit following the number.
+ * On overflow, the function returns INT64_MIN or INT64_MAX.
  */
 static int64_t
 mtree_atol10(char **p)
 {
-	int64_t l, limit, last_digit_limit;
-	int base, digit, sign;
-
-	base = 10;
+	const int base = 10;
+	const int64_t limit = INT64_MAX / base;
+	const int64_t last_digit_limit = INT64_MAX % base;
+	int64_t l;
+	int sign;
 
 	if (**p == '-') {
 		sign = -1;
-		limit = ((uint64_t)(INT64_MAX) + 1) / base;
-		last_digit_limit = ((uint64_t)(INT64_MAX) + 1) % base;
 		++(*p);
 	} else {
 		sign = 1;
-		limit = INT64_MAX / base;
-		last_digit_limit = INT64_MAX % base;
 	}
 
 	l = 0;
-	digit = **p - '0';
-	while (digit >= 0 && digit < base) {
-		if (l > limit || (l == limit && digit > last_digit_limit))
+	while (**p >= '0' && **p < '0' + base) {
+		int digit = **p - '0';
+		if (l > limit || (l == limit && digit > last_digit_limit)) {
+			while (**p >= '0' && **p < '0' + base) {
+				++(*p);
+			}
 			return (sign < 0) ? INT64_MIN : INT64_MAX;
+		}
 		l = (l * base) + digit;
-		digit = *++(*p) - '0';
+		++(*p);
 	}
 	return (sign < 0) ? -l : l;
 }
diff --git a/libarchive/archive_read_support_format_tar.c b/libarchive/archive_read_support_format_tar.c
index bd7f13d..30d5bc8 100644
--- a/libarchive/archive_read_support_format_tar.c
+++ b/libarchive/archive_read_support_format_tar.c
@@ -155,6 +155,7 @@
 	int			 compat_2x;
 	int			 process_mac_extensions;
 	int			 read_concatenated_archives;
+	int			 realsize_override;
 };
 
 static int	archive_block_is_null(const char *p);
@@ -527,6 +528,7 @@
 	tar->entry_offset = 0;
 	gnu_clear_sparse_list(tar);
 	tar->realsize = -1; /* Mark this as "unset" */
+	tar->realsize_override = 0;
 
 	/* Setup default string conversion. */
 	tar->sconv = tar->opt_sconv;
@@ -1894,6 +1896,7 @@
 		if (strcmp(key, "GNU.sparse.size") == 0) {
 			tar->realsize = tar_atol10(value, strlen(value));
 			archive_entry_set_size(entry, tar->realsize);
+			tar->realsize_override = 1;
 		}
 
 		/* GNU "0.1" sparse pax format. */
@@ -1925,6 +1928,7 @@
 		if (strcmp(key, "GNU.sparse.realsize") == 0) {
 			tar->realsize = tar_atol10(value, strlen(value));
 			archive_entry_set_size(entry, tar->realsize);
+			tar->realsize_override = 1;
 		}
 		break;
 	case 'L':
@@ -1977,6 +1981,7 @@
 			    tar_atol10(value, strlen(value)));
 		} else if (strcmp(key, "SCHILY.realsize") == 0) {
 			tar->realsize = tar_atol10(value, strlen(value));
+			tar->realsize_override = 1;
 			archive_entry_set_size(entry, tar->realsize);
 		} else if (strncmp(key, "SCHILY.xattr.", 13) == 0) {
 			pax_attribute_schily_xattr(entry, key, value,
@@ -2055,14 +2060,12 @@
 			tar->entry_bytes_remaining
 			    = tar_atol10(value, strlen(value));
 			/*
-			 * But, "size" is not necessarily the size of
-			 * the file on disk; if this is a sparse file,
-			 * the disk size may have already been set from
-			 * GNU.sparse.realsize or GNU.sparse.size or
-			 * an old GNU header field or SCHILY.realsize
-			 * or ....
+			 * The "size" pax header keyword always overrides the
+			 * "size" field in the tar header.
+			 * GNU.sparse.realsize, GNU.sparse.size and
+			 * SCHILY.realsize override this value.
 			 */
-			if (tar->realsize < 0) {
+			if (!tar->realsize_override) {
 				archive_entry_set_size(entry,
 				    tar->entry_bytes_remaining);
 				tar->realsize
@@ -2206,6 +2209,7 @@
 		tar->realsize
 		    = tar_atol(header->realsize, sizeof(header->realsize));
 		archive_entry_set_size(entry, tar->realsize);
+		tar->realsize_override = 1;
 	}
 
 	if (header->sparse[0].offset[0] != 0) {
diff --git a/libarchive/archive_read_support_format_warc.c b/libarchive/archive_read_support_format_warc.c
index b162465..e875385 100644
--- a/libarchive/archive_read_support_format_warc.c
+++ b/libarchive/archive_read_support_format_warc.c
@@ -600,9 +600,10 @@
 	/* looks good so far, read the version number for a laugh */
 	buf += sizeof(magic) - 1U;
 
-	if (isdigit(buf[0U]) && (buf[1U] == '.') && isdigit(buf[2U])) {
+	if (isdigit((unsigned char)buf[0U]) && (buf[1U] == '.') &&
+	    isdigit((unsigned char)buf[2U])) {
 		/* we support a maximum of 2 digits in the minor version */
-		if (isdigit(buf[3U]))
+		if (isdigit((unsigned char)buf[3U]))
 			end = 1U;
 		/* set up major version */
 		ver = (buf[0U] - '0') * 10000U;
@@ -686,7 +687,7 @@
 
 	/* spaces inside uri are not allowed, CRLF should follow */
 	for (p = val; p < eol; p++) {
-		if (isspace(*p))
+		if (isspace((unsigned char)*p))
 			return res;
 	}
 
@@ -736,7 +737,7 @@
 	while (val < eol && (*val == ' ' || *val == '\t'))
 		val++;
 	/* there must be at least one digit */
-	if (!isdigit(*val))
+	if (!isdigit((unsigned char)*val))
 		return -1;
 	len = strtol(val, &on, 10);
 	if (on != eol) {
diff --git a/libarchive/archive_util.c b/libarchive/archive_util.c
index 6b3bd61..a751868 100644
--- a/libarchive/archive_util.c
+++ b/libarchive/archive_util.c
@@ -89,88 +89,6 @@
 	return (ARCHIVE_VERSION_STRING);
 }
 
-const char *
-archive_version_details(void)
-{
-	static struct archive_string str;
-	static int init = 0;
-	const char *zlib = archive_zlib_version();
-	const char *liblzma = archive_liblzma_version();
-	const char *bzlib = archive_bzlib_version();
-	const char *liblz4 = archive_liblz4_version();
-
-	if (!init) {
-		archive_string_init(&str);
-
-		archive_strcat(&str, ARCHIVE_VERSION_STRING);
-		if (zlib != NULL) {
-			archive_strcat(&str, " zlib/");
-			archive_strcat(&str, zlib);
-		}
-		if (liblzma) {
-			archive_strcat(&str, " liblzma/");
-			archive_strcat(&str, liblzma);
-		}
-		if (bzlib) {
-			const char *p = bzlib;
-			const char *sep = strchr(p, ',');
-			if (sep == NULL)
-				sep = p + strlen(p);
-			archive_strcat(&str, " bz2lib/");
-			archive_strncat(&str, p, sep - p);
-		}
-		if (liblz4) {
-			archive_strcat(&str, " liblz4/");
-			archive_strcat(&str, liblz4);
-		}
-	}
-	return str.s;
-}
-
-const char *
-archive_zlib_version(void)
-{
-#ifdef HAVE_ZLIB_H
-	return ZLIB_VERSION;
-#else
-	return NULL;
-#endif
-}
-
-const char *
-archive_liblzma_version(void)
-{
-#ifdef HAVE_LZMA_H
-	return LZMA_VERSION_STRING;
-#else
-	return NULL;
-#endif
-}
-
-const char *
-archive_bzlib_version(void)
-{
-#ifdef HAVE_BZLIB_H
-	return BZ2_bzlibVersion();
-#else
-	return NULL;
-#endif
-}
-
-const char *
-archive_liblz4_version(void)
-{
-#if defined(HAVE_LZ4_H) && defined(HAVE_LIBLZ4)
-#define str(s) #s
-#define NUMBER(x) str(x)
-	return NUMBER(LZ4_VERSION_MAJOR) "." NUMBER(LZ4_VERSION_MINOR) "." NUMBER(LZ4_VERSION_RELEASE);
-#undef NUMBER
-#undef str
-#else
-	return NULL;
-#endif
-}
-
 int
 archive_errno(struct archive *a)
 {
diff --git a/libarchive/archive_version_details.c b/libarchive/archive_version_details.c
new file mode 100644
index 0000000..813f0f3
--- /dev/null
+++ b/libarchive/archive_version_details.c
@@ -0,0 +1,133 @@
+/*-
+ * Copyright (c) 2009-2012,2014 Michihiro NAKAJIMA
+ * Copyright (c) 2003-2007 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 "archive_platform.h"
+__FBSDID("$FreeBSD: head/lib/libarchive/archive_util.c 201098 2009-12-28 02:58:14Z kientzle $");
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#endif
+#ifdef HAVE_LZMA_H
+#include <lzma.h>
+#endif
+#ifdef HAVE_BZLIB_H
+#include <bzlib.h>
+#endif
+#ifdef HAVE_LZ4_H
+#include <lz4.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_string.h"
+
+const char *
+archive_version_details(void)
+{
+	static struct archive_string str;
+	static int init = 0;
+	const char *zlib = archive_zlib_version();
+	const char *liblzma = archive_liblzma_version();
+	const char *bzlib = archive_bzlib_version();
+	const char *liblz4 = archive_liblz4_version();
+
+	if (!init) {
+		archive_string_init(&str);
+
+		archive_strcat(&str, ARCHIVE_VERSION_STRING);
+		if (zlib != NULL) {
+			archive_strcat(&str, " zlib/");
+			archive_strcat(&str, zlib);
+		}
+		if (liblzma) {
+			archive_strcat(&str, " liblzma/");
+			archive_strcat(&str, liblzma);
+		}
+		if (bzlib) {
+			const char *p = bzlib;
+			const char *sep = strchr(p, ',');
+			if (sep == NULL)
+				sep = p + strlen(p);
+			archive_strcat(&str, " bz2lib/");
+			archive_strncat(&str, p, sep - p);
+		}
+		if (liblz4) {
+			archive_strcat(&str, " liblz4/");
+			archive_strcat(&str, liblz4);
+		}
+	}
+	return str.s;
+}
+
+const char *
+archive_zlib_version(void)
+{
+#ifdef HAVE_ZLIB_H
+	return ZLIB_VERSION;
+#else
+	return NULL;
+#endif
+}
+
+const char *
+archive_liblzma_version(void)
+{
+#ifdef HAVE_LZMA_H
+	return LZMA_VERSION_STRING;
+#else
+	return NULL;
+#endif
+}
+
+const char *
+archive_bzlib_version(void)
+{
+#ifdef HAVE_BZLIB_H
+	return BZ2_bzlibVersion();
+#else
+	return NULL;
+#endif
+}
+
+const char *
+archive_liblz4_version(void)
+{
+#if defined(HAVE_LZ4_H) && defined(HAVE_LIBLZ4)
+#define str(s) #s
+#define NUMBER(x) str(x)
+	return NUMBER(LZ4_VERSION_MAJOR) "." NUMBER(LZ4_VERSION_MINOR) "." NUMBER(LZ4_VERSION_RELEASE);
+#undef NUMBER
+#undef str
+#else
+	return NULL;
+#endif
+}
diff --git a/libarchive/archive_write_data.3 b/libarchive/archive_write_data.3
index 0cdd25f..9c16cd9 100644
--- a/libarchive/archive_write_data.3
+++ b/libarchive/archive_write_data.3
@@ -24,11 +24,12 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd February 2, 2012
+.Dd February 28, 2017
 .Dt ARCHIVE_WRITE_DATA 3
 .Os
 .Sh NAME
-.Nm archive_write_data
+.Nm archive_write_data ,
+.Nm archive_write_data_block
 .Nd functions for creating archives
 .Sh LIBRARY
 Streaming Archive Library (libarchive, -larchive)
@@ -36,8 +37,27 @@
 .In archive.h
 .Ft la_ssize_t
 .Fn archive_write_data "struct archive *" "const void *" "size_t"
+.Ft la_ssize_t
+.Fn archive_write_data_block "struct archive *" "const void *" "size_t size" "int64_t offset"
 .Sh DESCRIPTION
+.Bl -tag -width indent
+.It Fn archive_write_data
 Write data corresponding to the header just written.
+.It Fn archive_write_data_block
+Write data corresponding to the header just written.
+This is like
+.Fn archive_write_data
+except that it performs a seek on the file being
+written to the specified offset before writing the data.
+This is useful when restoring sparse files from archive
+formats that support sparse files.
+Returns number of bytes written or -1 on error.
+(Note: This is currently not supported for
+.Tn archive_write
+handles, only for
+.Tn archive_write_disk
+handles.
+.El
 .\" .Sh EXAMPLE
 .\"
 .Sh RETURN VALUES
diff --git a/libarchive/archive_write_disk.3 b/libarchive/archive_write_disk.3
index ba6c970..4891b85 100644
--- a/libarchive/archive_write_disk.3
+++ b/libarchive/archive_write_disk.3
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd February 2, 2012
+.Dd February 28, 2017
 .Dt ARCHIVE_WRITE_DISK 3
 .Os
 .Sh NAME
@@ -33,14 +33,7 @@
 .Nm archive_write_disk_set_skip_file ,
 .Nm archive_write_disk_set_group_lookup ,
 .Nm archive_write_disk_set_standard_lookup ,
-.Nm archive_write_disk_set_user_lookup ,
-.Nm archive_write_header ,
-.Nm archive_write_data ,
-.Nm archive_write_data_block ,
-.Nm archive_write_finish_entry ,
-.Nm archive_write_close ,
-.Nm archive_write_finish
-.Nm archive_write_free
+.Nm archive_write_disk_set_user_lookup
 .Nd functions for creating objects on disk
 .Sh LIBRARY
 Streaming Archive Library (libarchive, -larchive)
@@ -68,20 +61,6 @@
 .Fa "uid_t (*)(void *, const char *uname, uid_t uid)"
 .Fa "void (*cleanup)(void *)"
 .Fc
-.Ft int
-.Fn archive_write_header "struct archive *" "struct archive_entry *"
-.Ft la_ssize_t
-.Fn archive_write_data "struct archive *" "const void *" "size_t"
-.Ft la_ssize_t
-.Fn archive_write_data_block "struct archive *" "const void *" "size_t size" "int64_t offset"
-.Ft int
-.Fn archive_write_finish_entry "struct archive *"
-.Ft int
-.Fn archive_write_close "struct archive *"
-.Ft int
-.Fn archive_write_finish "struct archive *"
-.Ft int
-.Fn archive_write_free "struct archive *"
 .Sh DESCRIPTION
 These functions provide a complete API for creating objects on
 disk from
@@ -223,60 +202,6 @@
 .Xr getpwnam 3
 and
 .Xr getgrnam 3 .
-.It Fn archive_write_header
-Build and write a header using the data in the provided
-.Tn struct archive_entry
-structure.
-See
-.Xr archive_entry 3
-for information on creating and populating
-.Tn struct archive_entry
-objects.
-.It Fn archive_write_data
-Write data corresponding to the header just written.
-Returns number of bytes written or -1 on error.
-.It Fn archive_write_data_block
-Write data corresponding to the header just written.
-This is like
-.Fn archive_write_data
-except that it performs a seek on the file being
-written to the specified offset before writing the data.
-This is useful when restoring sparse files from archive
-formats that support sparse files.
-Returns number of bytes written or -1 on error.
-(Note: This is currently not supported for
-.Tn archive_write
-handles, only for
-.Tn archive_write_disk
-handles.)
-.It Fn archive_write_finish_entry
-Close out the entry just written.
-Ordinarily, clients never need to call this, as it
-is called automatically by
-.Fn archive_write_next_header
-and
-.Fn archive_write_close
-as needed.
-However, some file attributes are written to disk only
-after the file is closed, so this can be necessary
-if you need to work with the file on disk right away.
-.It Fn archive_write_close
-Set any attributes that could not be set during the initial restore.
-For example, directory timestamps are not restored initially because
-restoring a subsequent file would alter that timestamp.
-Similarly, non-writable directories are initially created with
-write permissions (so that their contents can be restored).
-The
-.Nm
-library maintains a list of all such deferred attributes and
-sets them when this function is invoked.
-.It Fn archive_write_finish
-This is a deprecated synonym for
-.Fn archive_write_free .
-.It Fn archive_write_free
-Invokes
-.Fn archive_write_close
-if it was not invoked manually, then releases all resources.
 .El
 More information about the
 .Va struct archive
diff --git a/libarchive/archive_write_disk_acl.c b/libarchive/archive_write_disk_acl.c
index 144ab7e..4979274 100644
--- a/libarchive/archive_write_disk_acl.c
+++ b/libarchive/archive_write_disk_acl.c
@@ -61,17 +61,18 @@
 
 #else /* HAVE_POSIX_ACL || HAVE_NFS4_ACL */
 
-#if HAVE_SUN_ACL
-#define	ARCHIVE_PLATFORM_ACL_TYPE_NFS4	ACE_T
-#elif HAVE_DARWIN_ACL
+#if HAVE_DARWIN_ACL
 #define	ARCHIVE_PLATFORM_ACL_TYPE_NFS4	ACL_TYPE_EXTENDED
-#elif HAVE_ACL_TYPE_NFS4
+#elif HAVE_FREEBSD_NFS4_ACL
 #define	ARCHIVE_PLATFORM_ACL_TYPE_NFS4	ACL_TYPE_NFS4
 #endif
 
 static int	set_acl(struct archive *, int fd, const char *,
 			struct archive_acl *,
-			acl_type_t, int archive_entry_acl_type, const char *tn);
+#if !HAVE_SUN_ACL
+			acl_type_t,
+#endif
+			int archive_entry_acl_type, const char *tn);
 
 int
 archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
@@ -84,7 +85,7 @@
 	    & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
 #if HAVE_SUN_ACL
 		/* Solaris writes POSIX.1e access and default ACLs together */
-		ret = set_acl(a, fd, name, abstract_acl, ACLENT_T,
+		ret = set_acl(a, fd, name, abstract_acl,
 		    ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, "posix1e");
 #else	/* HAVE_POSIX_ACL */
 		if ((archive_acl_types(abstract_acl)
@@ -109,13 +110,16 @@
 	if ((archive_acl_types(abstract_acl) &
 	    ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
 		ret = set_acl(a, fd, name, abstract_acl,
+#if !HAVE_SUN_ACL
 		    ARCHIVE_PLATFORM_ACL_TYPE_NFS4,
+#endif
 		    ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4");
 	}
 #endif	/* HAVE_NFS4_ACL */
 	return (ret);
 }
 
+#if !HAVE_SUN_ACL || HAVE_SUN_NFS4_ACL
 /*
  * Translate system ACL permissions into libarchive internal structure
  */
@@ -123,7 +127,7 @@
 	const int archive_perm;
 	const int platform_perm;
 } acl_perm_map[] = {
-#if HAVE_SUN_ACL	/* Solaris NFSv4 ACL permissions */
+#if HAVE_SUN_NFS4_ACL	/* Solaris NFSv4 ACL permissions */
 	{ARCHIVE_ENTRY_ACL_EXECUTE, ACE_EXECUTE},
 	{ARCHIVE_ENTRY_ACL_READ_DATA, ACE_READ_DATA},
 	{ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACE_LIST_DIRECTORY},
@@ -158,12 +162,14 @@
 	{ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_SECURITY},
 	{ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_SECURITY},
 	{ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_CHANGE_OWNER},
+#if HAVE_DECL_ACL_SYNCHRONIZE
 	{ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
+#endif
 #else	/* POSIX.1e ACL permissions */
 	{ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
 	{ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE},
 	{ARCHIVE_ENTRY_ACL_READ, ACL_READ},
-#if HAVE_ACL_TYPE_NFS4	/* FreeBSD NFSv4 ACL permissions */
+#if HAVE_FREEBSD_NFS4_ACL	/* FreeBSD NFSv4 ACL permissions */
 	{ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
 	{ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
 	{ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
@@ -183,6 +189,7 @@
 #endif
 #endif	/* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
 };
+#endif	/* !HAVE_SUN_ACL || HAVE_SUN_NFS4_ACL */
 
 #if HAVE_NFS4_ACL
 /*
@@ -192,14 +199,16 @@
 	const int archive_inherit;
 	const int platform_inherit;
 } acl_inherit_map[] = {
-#if HAVE_SUN_ACL	/* Solaris NFSv4 inheritance flags */
+#if HAVE_SUN_NFS4_ACL	/* Solaris NFSv4 inheritance flags */
 	{ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACE_FILE_INHERIT_ACE},
 	{ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACE_DIRECTORY_INHERIT_ACE},
 	{ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACE_NO_PROPAGATE_INHERIT_ACE},
 	{ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACE_INHERIT_ONLY_ACE},
 	{ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACE_SUCCESSFUL_ACCESS_ACE_FLAG},
 	{ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACE_FAILED_ACCESS_ACE_FLAG},
+#ifdef ACE_INHERITED_ACE
 	{ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACE_INHERITED_ACE}
+#endif
 #elif HAVE_DARWIN_ACL	/* MacOS NFSv4 inheritance flags */
 	{ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED},
 	{ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
@@ -214,29 +223,34 @@
 	{ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACL_ENTRY_SUCCESSFUL_ACCESS},
 	{ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACL_ENTRY_FAILED_ACCESS},
 	{ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED}
-#endif	/* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
+#endif	/* !HAVE_SUN_NFS4_ACL && !HAVE_DARWIN_ACL */
 };
 #endif	/* HAVE_NFS4_ACL */
 
 static int
 set_acl(struct archive *a, int fd, const char *name,
     struct archive_acl *abstract_acl,
-    acl_type_t acl_type, int ae_requested_type, const char *tname)
+#if !HAVE_SUN_ACL
+    acl_type_t acl_type,
+#endif
+    int ae_requested_type, const char *tname)
 {
 #if HAVE_SUN_ACL
 	aclent_t	 *aclent;
+#if HAVE_SUN_NFS4_ACL
 	ace_t		 *ace;
-	int		 e, r;
-	acl_t		 *acl;
+#endif
+	int		 cmd, e, r;
+	void		 *aclp;
 #else
 	acl_t		 acl;
 	acl_entry_t	 acl_entry;
 	acl_permset_t	 acl_permset;
-#if HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL
+#if HAVE_FREEBSD_NFS4_ACL || HAVE_DARWIN_ACL
 	acl_flagset_t	 acl_flagset;
 #endif
 #endif	/* HAVE_SUN_ACL */
-#if HAVE_ACL_TYPE_NFS4
+#if HAVE_FREEBSD_NFS4_ACL
 	int		r;
 #endif
 	int		 ret;
@@ -256,31 +270,26 @@
 		return (ARCHIVE_OK);
 
 #if HAVE_SUN_ACL
-	acl = NULL;
-	acl = malloc(sizeof(acl_t));
-	if (acl == NULL) {
-		archive_set_error(a, ARCHIVE_ERRNO_MISC,
-			"Invalid ACL type");
+	switch (ae_requested_type) {
+	case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E:
+		cmd = SETACL;
+		aclp = malloc(entries * sizeof(aclent_t));
+		break;
+#if HAVE_SUN_NFS4_ACL
+	case ARCHIVE_ENTRY_ACL_TYPE_NFS4:
+		cmd = ACE_SETACL;
+		aclp = malloc(entries * sizeof(ace_t));
+		break;
+#endif
+	default:
+		errno = ENOENT;
+		archive_set_error(a, errno, "Invalid ACL type");
 		return (ARCHIVE_FAILED);
 	}
-	if (acl_type == ACE_T)
-		acl->acl_entry_size = sizeof(ace_t);
-	else if (acl_type == ACLENT_T)
-		acl->acl_entry_size = sizeof(aclent_t);
-	else {
-		archive_set_error(a, ARCHIVE_ERRNO_MISC,
-			"Invalid ACL type");
-		acl_free(acl);
-		return (ARCHIVE_FAILED);
-	}
-	acl->acl_type = acl_type;
-	acl->acl_cnt = entries;
 
-	acl->acl_aclp = malloc(entries * acl->acl_entry_size);
-	if (acl->acl_aclp == NULL) {
+	if (aclp == NULL) {
 		archive_set_error(a, errno,
 		    "Can't allocate memory for acl buffer");
-		acl_free(acl);
 		return (ARCHIVE_FAILED);
 	}
 #else	/* !HAVE_SUN_ACL */
@@ -297,19 +306,24 @@
 	while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type,
 		   &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) {
 #if HAVE_SUN_ACL
-		ace = NULL;
 		aclent = NULL;
-		if (acl->acl_type == ACE_T)  {
-			ace = &((ace_t *)acl->acl_aclp)[e];
-			ace->a_who = -1;
-			ace->a_access_mask = 0;
-			ace->a_flags = 0;
-		} else {
-			aclent = &((aclent_t *)acl->acl_aclp)[e];
+#if HAVE_SUN_NFS4_ACL
+		ace = NULL;
+#endif
+		if (cmd == SETACL) {
+			aclent = &((aclent_t *)aclp)[e];
 			aclent->a_id = -1;
 			aclent->a_type = 0;
 			aclent->a_perm = 0;
 		}
+#if HAVE_SUN_NFS4_ACL
+		else {	/* cmd == ACE_SETACL */
+			ace = &((ace_t *)aclp)[e];
+			ace->a_who = -1;
+			ace->a_access_mask = 0;
+			ace->a_flags = 0;
+		}
+#endif	/* HAVE_SUN_NFS4_ACL */
 #else	/* !HAVE_SUN_ACL  */
 #if HAVE_DARWIN_ACL
 		/*
@@ -346,45 +360,63 @@
 #if HAVE_SUN_ACL
 		case ARCHIVE_ENTRY_ACL_USER:
 			ae_uid = archive_write_disk_uid(a, ae_name, ae_id);
-			if (acl->acl_type == ACE_T)
-				ace->a_who = ae_uid;
-			else {
+			if (aclent != NULL) {
 				aclent->a_id = ae_uid;
 				aclent->a_type |= USER;
 			}
+#if HAVE_SUN_NFS4_ACL
+			else {
+				ace->a_who = ae_uid;
+			}
+#endif
 			break;
 		case ARCHIVE_ENTRY_ACL_GROUP:
 			ae_gid = archive_write_disk_gid(a, ae_name, ae_id);
-			if (acl->acl_type == ACE_T) {
-				ace->a_who = ae_gid;
-				ace->a_flags |= ACE_IDENTIFIER_GROUP;
-			} else {
+			if (aclent != NULL) {
 				aclent->a_id = ae_gid;
 				aclent->a_type |= GROUP;
 			}
+#if HAVE_SUN_NFS4_ACL
+			else {
+				ace->a_who = ae_gid;
+				ace->a_flags |= ACE_IDENTIFIER_GROUP;
+			}
+#endif
 			break;
 		case ARCHIVE_ENTRY_ACL_USER_OBJ:
-			if (acl->acl_type == ACE_T)
-				ace->a_flags |= ACE_OWNER;
-			else
+			if (aclent != NULL)
 				aclent->a_type |= USER_OBJ;
+#if HAVE_SUN_NFS4_ACL
+			else {
+				ace->a_flags |= ACE_OWNER;
+			}
+#endif
 			break;
 		case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
-			if (acl->acl_type == ACE_T) {
+			if (aclent != NULL)
+				aclent->a_type |= GROUP_OBJ;
+#if HAVE_SUN_NFS4_ACL
+			else {
 				ace->a_flags |= ACE_GROUP;
 				ace->a_flags |= ACE_IDENTIFIER_GROUP;
-			} else
-				aclent->a_type |= GROUP_OBJ;
+			}
+
+#endif
 			break;
 		case ARCHIVE_ENTRY_ACL_MASK:
-			aclent->a_type |= CLASS_OBJ;
+			if (aclent != NULL)
+				aclent->a_type |= CLASS_OBJ;
 			break;
 		case ARCHIVE_ENTRY_ACL_OTHER:
-			aclent->a_type |= OTHER_OBJ;
+			if (aclent != NULL)
+				aclent->a_type |= OTHER_OBJ;
 			break;
+#if HAVE_SUN_NFS4_ACL
 		case ARCHIVE_ENTRY_ACL_EVERYONE:
-			ace->a_flags |= ACE_EVERYONE;
+			if (ace != NULL)
+				ace->a_flags |= ACE_EVERYONE;
 			break;
+#endif
 #else	/* !HAVE_SUN_ACL */
 		case ARCHIVE_ENTRY_ACL_USER:
 			ae_uid = archive_write_disk_uid(a, ae_name, ae_id);
@@ -392,8 +424,7 @@
 			acl_set_tag_type(acl_entry, ACL_USER);
 			acl_set_qualifier(acl_entry, &ae_uid);
 #else	/* MacOS */
-			if (mbr_identifier_to_uuid(ID_TYPE_UID, &ae_uid,
-			    sizeof(uid_t), ae_uuid) != 0)
+			if (mbr_uid_to_uuid(ae_uid, ae_uuid) != 0)
 				continue;
 			if (acl_set_qualifier(acl_entry, &ae_uuid) != 0)
 				continue;
@@ -405,8 +436,7 @@
 			acl_set_tag_type(acl_entry, ACL_GROUP);
 			acl_set_qualifier(acl_entry, &ae_gid);
 #else	/* MacOS */
-			if (mbr_identifier_to_uuid(ID_TYPE_GID, &ae_gid,
-			    sizeof(gid_t), ae_uuid) != 0)
+			if (mbr_gid_to_uuid(ae_gid, ae_uuid) != 0)
 				continue;
 			if (acl_set_qualifier(acl_entry, &ae_uuid) != 0)
 				continue;
@@ -425,7 +455,7 @@
 		case ARCHIVE_ENTRY_ACL_OTHER:
 			acl_set_tag_type(acl_entry, ACL_OTHER);
 			break;
-#if HAVE_ACL_TYPE_NFS4	/* FreeBSD only */
+#if HAVE_FREEBSD_NFS4_ACL	/* FreeBSD only */
 		case ARCHIVE_ENTRY_ACL_EVERYONE:
 			acl_set_tag_type(acl_entry, ACL_EVERYONE);
 			break;
@@ -439,10 +469,11 @@
 			goto exit_free;
 		}
 
-#if HAVE_ACL_TYPE_NFS4 || HAVE_SUN_ACL
+#if HAVE_FREEBSD_NFS4_ACL || HAVE_SUN_ACL
 		r = 0;
 		switch (ae_type) {
 #if HAVE_SUN_ACL
+#if HAVE_SUN_NFS4_ACL
 		case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
 			if (ace != NULL)
 				ace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
@@ -467,6 +498,7 @@
 			else
 				r = -1;
 			break;
+#endif
 		case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
 			if (aclent == NULL)
 				r = -1;
@@ -497,7 +529,7 @@
 #endif	/* !HAVE_SUN_ACL */
 		default:
 			archive_set_error(a, ARCHIVE_ERRNO_MISC,
-			    "Unknown ACL entry type");
+			    "Unsupported ACL entry type");
 			ret = ARCHIVE_FAILED;
 			goto exit_free;
 		}
@@ -511,17 +543,20 @@
 			ret = ARCHIVE_FAILED;
 			goto exit_free;
 		}
-#endif	/* HAVE_ACL_TYPE_NFS4 || HAVE_SUN_ACL */
+#endif	/* HAVE_FREEBSD_NFS4_ACL || HAVE_SUN_ACL */
 
 #if HAVE_SUN_ACL
-		if (acl->acl_type == ACLENT_T) {
+		if (aclent != NULL) {
 			if (ae_permset & ARCHIVE_ENTRY_ACL_EXECUTE)
 				aclent->a_perm |= 1;
 			if (ae_permset & ARCHIVE_ENTRY_ACL_WRITE)
 				aclent->a_perm |= 2;
 			if (ae_permset & ARCHIVE_ENTRY_ACL_READ)
 				aclent->a_perm |= 4;
-		} else
+		}
+#if HAVE_SUN_NFS4_ACL
+		else /* falls through to for statement below, ace != NULL */
+#endif
 #else
 		if (acl_get_permset(acl_entry, &acl_permset) != 0) {
 			archive_set_error(a, errno,
@@ -536,6 +571,7 @@
 			goto exit_free;
 		}
 #endif	/* !HAVE_SUN_ACL */
+#if HAVE_POSIX_ACL || HAVE_NFS4_ACL
 		for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) {
 			if (ae_permset & acl_perm_map[i].archive_perm) {
 #if HAVE_SUN_ACL
@@ -552,10 +588,11 @@
 #endif
 			}
 		}
+#endif /* HAVE_POSIX_ACL || HAVE_NFS4_ACL */
 
 #if HAVE_NFS4_ACL
-#if HAVE_SUN_ACL
-		if (acl_type == ACE_T)
+#if HAVE_SUN_NFS4_ACL
+		if (ace != NULL)
 #elif HAVE_DARWIN_ACL
 		if (acl_type == ACL_TYPE_EXTENDED)
 #else	/* FreeBSD */
@@ -611,7 +648,7 @@
 #endif
 	{
 #if HAVE_SUN_ACL
-		if (facl_set(fd, acl) == 0)
+		if (facl(fd, cmd, entries, aclp) == 0)
 #elif HAVE_ACL_SET_FD_NP
 		if (acl_set_fd_np(fd, acl, acl_type) == 0)
 #else	/* !HAVE_SUN_ACL && !HAVE_ACL_SET_FD_NP */
@@ -630,7 +667,7 @@
 	} else
 #endif	/* HAVE_ACL_SET_FD_NP || HAVE_ACL_SET_FD || HAVE_SUN_ACL */
 #if HAVE_SUN_ACL
-	if (acl_set(name, acl) != 0)
+	if (acl(name, cmd, entries, aclp) != 0)
 #elif HAVE_ACL_SET_LINK_NP
 	if (acl_set_link_np(name, acl_type, acl) != 0)
 #else
@@ -648,7 +685,11 @@
 		}
 	}
 exit_free:
+#if HAVE_SUN_ACL
+	free(aclp);
+#else
 	acl_free(acl);
+#endif
 	return (ret);
 }
 #endif	/* HAVE_POSIX_ACL || HAVE_NFS4_ACL */
diff --git a/libarchive/archive_write_disk_posix.c b/libarchive/archive_write_disk_posix.c
index 5a01e84..bf58b6d 100644
--- a/libarchive/archive_write_disk_posix.c
+++ b/libarchive/archive_write_disk_posix.c
@@ -2467,7 +2467,7 @@
 	if (a_eno)
 		*a_eno = err;
 	if (a_estr)
-		archive_string_sprintf(a_estr, errstr, path);
+		archive_string_sprintf(a_estr, "%s%s", errstr, path);
 }
 
 /*
@@ -2573,7 +2573,7 @@
 				 * with the deep-directory editing.
 				 */
 				fsobj_error(a_eno, a_estr, errno,
-				    "Could not stat %s", path);
+				    "Could not stat ", path);
 				res = ARCHIVE_FAILED;
 				break;
 			}
@@ -2582,7 +2582,7 @@
 				if (chdir(head) != 0) {
 					tail[0] = c;
 					fsobj_error(a_eno, a_estr, errno,
-					    "Could not chdir %s", path);
+					    "Could not chdir ", path);
 					res = (ARCHIVE_FATAL);
 					break;
 				}
@@ -2599,7 +2599,7 @@
 				if (unlink(head)) {
 					tail[0] = c;
 					fsobj_error(a_eno, a_estr, errno,
-					    "Could not remove symlink %s",
+					    "Could not remove symlink ",
 					    path);
 					res = ARCHIVE_FAILED;
 					break;
@@ -2618,7 +2618,7 @@
 				/*
 				if (!S_ISLNK(path)) {
 					fsobj_error(a_eno, a_estr, 0,
-					    "Removing symlink %s", path);
+					    "Removing symlink ", path);
 				}
 				*/
 				/* Symlink gone.  No more problem! */
@@ -2630,7 +2630,7 @@
 					tail[0] = c;
 					fsobj_error(a_eno, a_estr, 0,
 					    "Cannot remove intervening "
-					    "symlink %s", path);
+					    "symlink ", path);
 					res = ARCHIVE_FAILED;
 					break;
 				}
@@ -2652,7 +2652,7 @@
 					} else {
 						fsobj_error(a_eno, a_estr,
 						    errno,
-						    "Could not stat %s", path);
+						    "Could not stat ", path);
 						res = (ARCHIVE_FAILED);
 						break;
 					}
@@ -2661,7 +2661,7 @@
 						tail[0] = c;
 						fsobj_error(a_eno, a_estr,
 						    errno,
-						    "Could not chdir %s", path);
+						    "Could not chdir ", path);
 						res = (ARCHIVE_FATAL);
 						break;
 					}
@@ -2674,14 +2674,14 @@
 					tail[0] = c;
 					fsobj_error(a_eno, a_estr, 0,
 					    "Cannot extract through "
-					    "symlink %s", path);
+					    "symlink ", path);
 					res = ARCHIVE_FAILED;
 					break;
 				}
 			} else {
 				tail[0] = c;
 				fsobj_error(a_eno, a_estr, 0,
-				    "Cannot extract through symlink %s", path);
+				    "Cannot extract through symlink ", path);
 				res = ARCHIVE_FAILED;
 				break;
 			}
diff --git a/libarchive/archive_write_finish_entry.3 b/libarchive/archive_write_finish_entry.3
index c5ef69e..dc1b94b 100644
--- a/libarchive/archive_write_finish_entry.3
+++ b/libarchive/archive_write_finish_entry.3
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd February 2, 2012
+.Dd February 28, 2017
 .Dt ARCHIVE_WRITE_FINISH_ENTRY 3
 .Os
 .Sh NAME
@@ -45,6 +45,9 @@
 and
 .Fn archive_write_close
 as needed.
+For
+.Tn archive_write_disk
+handles, this flushes pending file attribute changes like modification time.
 .\" .Sh EXAMPLE
 .Sh RETURN VALUES
 This function returns
diff --git a/libarchive/archive_write_format.3 b/libarchive/archive_write_format.3
index d4ba6ab..aaafb0a 100644
--- a/libarchive/archive_write_format.3
+++ b/libarchive/archive_write_format.3
@@ -108,7 +108,6 @@
 These functions set the format that will be used for the archive.
 .Pp
 The library can write a variety of common archive formats.
-
 .Bl -tag -width indent
 .It Fn archive_write_set_format
 Sets the format based on the format code (see
diff --git a/libarchive/mtree.5 b/libarchive/mtree.5
index 16c8abe..e607e4a 100644
--- a/libarchive/mtree.5
+++ b/libarchive/mtree.5
@@ -48,7 +48,7 @@
 .Pp
 When encoding file or pathnames, any backslash character or
 character outside of the 95 printable ASCII characters must be
-encoded as a a backslash followed by three
+encoded as a backslash followed by three
 octal digits.
 When reading mtree files, any appearance of a backslash
 followed by three octal digits should be converted into the
diff --git a/libarchive/test/test_acl_platform_nfs4.c b/libarchive/test/test_acl_platform_nfs4.c
index 01c1dc5..c885408 100644
--- a/libarchive/test/test_acl_platform_nfs4.c
+++ b/libarchive/test/test_acl_platform_nfs4.c
@@ -254,12 +254,14 @@
 	int i;
 
 	archive_entry_acl_clear(ae);
+#if !HAVE_DARWIN_ACL
 	if (start > 0) {
 		assertEqualInt(ARCHIVE_OK,
 			archive_entry_acl_add_entry(ae,
 			    acls[0].type, acls[0].permset, acls[0].tag,
 			    acls[0].qual, acls[0].name));
 	}
+#endif
 	for (i = start; i < end; i++) {
 		assertEqualInt(ARCHIVE_OK,
 		    archive_entry_acl_add_entry(ae,
@@ -269,14 +271,14 @@
 }
 
 static int
-#ifdef HAVE_SUN_ACL
+#ifdef HAVE_SUN_NFS4_ACL
 acl_permset_to_bitmap(uint32_t a_access_mask)
 #else
 acl_permset_to_bitmap(acl_permset_t opaque_ps)
 #endif
 {
 	static struct { int machine; int portable; } perms[] = {
-#ifdef HAVE_SUN_ACL	/* Solaris NFSv4 ACL permissions */
+#ifdef HAVE_SUN_NFS4_ACL	/* Solaris NFSv4 ACL permissions */
 		{ACE_EXECUTE, ARCHIVE_ENTRY_ACL_EXECUTE},
 		{ACE_READ_DATA, ARCHIVE_ENTRY_ACL_READ_DATA},
 		{ACE_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY},
@@ -311,7 +313,9 @@
 		{ACL_READ_SECURITY, ARCHIVE_ENTRY_ACL_READ_ACL},
 		{ACL_WRITE_SECURITY, ARCHIVE_ENTRY_ACL_WRITE_ACL},
 		{ACL_CHANGE_OWNER, ARCHIVE_ENTRY_ACL_WRITE_OWNER},
+#if HAVE_DECL_ACL_SYNCHRONIZE
 		{ACL_SYNCHRONIZE, ARCHIVE_ENTRY_ACL_SYNCHRONIZE},
+#endif
 #else	/* FreeBSD NFSv4 ACL permissions */
 		{ACL_EXECUTE, ARCHIVE_ENTRY_ACL_EXECUTE},
 		{ACL_WRITE, ARCHIVE_ENTRY_ACL_WRITE},
@@ -337,7 +341,7 @@
 	int i, permset = 0;
 
 	for (i = 0; i < (int)(sizeof(perms)/sizeof(perms[0])); ++i)
-#if HAVE_SUN_ACL
+#if HAVE_SUN_NFS4_ACL
 		if (a_access_mask & perms[i].machine)
 #else
 		if (acl_get_perm_np(opaque_ps, perms[i].machine))
@@ -347,21 +351,23 @@
 }
 
 static int
-#if HAVE_SUN_ACL
+#if HAVE_SUN_NFS4_ACL
 acl_flagset_to_bitmap(uint16_t a_flags)
 #else
 acl_flagset_to_bitmap(acl_flagset_t opaque_fs)
 #endif
 {
 	static struct { int machine; int portable; } flags[] = {
-#if HAVE_SUN_ACL	/* Solaris NFSv4 ACL inheritance flags */
+#if HAVE_SUN_NFS4_ACL	/* Solaris NFSv4 ACL inheritance flags */
 		{ACE_FILE_INHERIT_ACE, ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT},
 		{ACE_DIRECTORY_INHERIT_ACE, ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT},
 		{ACE_NO_PROPAGATE_INHERIT_ACE, ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT},
 		{ACE_INHERIT_ONLY_ACE, ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY},
 		{ACE_SUCCESSFUL_ACCESS_ACE_FLAG, ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS},
 		{ACE_FAILED_ACCESS_ACE_FLAG, ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS},
+#ifdef ACE_INHERITED_ACE
 		{ACE_INHERITED_ACE, ARCHIVE_ENTRY_ACL_ENTRY_INHERITED}
+#endif
 #elif HAVE_DARWIN_ACL	/* MacOS NFSv4 ACL inheritance flags */
 		{ACL_ENTRY_INHERITED, ARCHIVE_ENTRY_ACL_ENTRY_INHERITED},
 		{ACL_ENTRY_FILE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT},
@@ -380,7 +386,7 @@
 	int i, flagset = 0;
 
 	for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); ++i)
-#if HAVE_SUN_ACL
+#if HAVE_SUN_NFS4_ACL
 		if (a_flags & flags[i].machine)
 #else
 		if (acl_get_flag_np(opaque_fs, flags[i].machine))
@@ -390,13 +396,13 @@
 }
 
 static int
-#if HAVE_SUN_ACL
+#if HAVE_SUN_NFS4_ACL
 acl_match(ace_t *ace, struct myacl_t *myacl)
 #else
 acl_match(acl_entry_t aclent, struct myacl_t *myacl)
 #endif
 {
-#if !HAVE_SUN_ACL
+#if !HAVE_SUN_NFS4_ACL
 #if HAVE_DARWIN_ACL
 	void *q;
 	uid_t ugid;
@@ -409,10 +415,10 @@
 	acl_tag_t tag_type;
 	acl_permset_t opaque_ps;
 	acl_flagset_t opaque_fs;
-#endif	/* !HAVE_SUN_ACL */
+#endif	/* !HAVE_SUN_NFS4_ACL */
 	int perms;
 
-#if HAVE_SUN_ACL
+#if HAVE_SUN_NFS4_ACL
 	perms = acl_permset_to_bitmap(ace->a_access_mask) | acl_flagset_to_bitmap(ace->a_flags);
 #else
 	acl_get_tag_type(aclent, &tag_type);
@@ -428,7 +434,7 @@
 	if (perms != myacl->permset)
 		return (0);
 
-#if HAVE_SUN_ACL
+#if HAVE_SUN_NFS4_ACL
 	switch (ace->a_type) {
 	case ACE_ACCESS_ALLOWED_ACE_TYPE:
 		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW)
@@ -507,7 +513,7 @@
 		default:
 			return (0);
 	}
-#else	/* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
+#else	/* !HAVE_SUN_NFS4_ACL && !HAVE_DARWIN_ACL */
 	switch (entry_type) {
 	case ACL_ENTRY_TYPE_ALLOW:
 		if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW)
@@ -559,14 +565,15 @@
 		if (myacl->tag != ARCHIVE_ENTRY_ACL_EVERYONE) return (0);
 		break;
 	}
-#endif	/* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
+#endif	/* !HAVE_SUN_NFS4_ACL && !HAVE_DARWIN_ACL */
 	return (1);
 }
 
 static void
 compare_acls(
-#if HAVE_SUN_ACL
-    acl_t *acl,
+#if HAVE_SUN_NFS4_ACL
+    void *aclp,
+    int aclcnt,
 #else
     acl_t acl,
 #endif
@@ -575,7 +582,7 @@
 	int *marker;
 	int matched;
 	int i, n;
-#if HAVE_SUN_ACL
+#if HAVE_SUN_NFS4_ACL
 	int e;
 	ace_t *acl_entry;
 #else
@@ -587,26 +594,28 @@
 	marker = malloc(sizeof(marker[0]) * (n + 1));
 	for (i = 0; i < n; i++)
 		marker[i] = i + start;
+#if !HAVE_DARWIN_ACL
 	/* Always include the first ACE. */
 	if (start > 0) {
 	  marker[n] = 0;
 	  ++n;
 	}
+#endif
 
 	/*
 	 * Iterate over acls in system acl object, try to match each
 	 * one with an item in the myacls array.
 	 */
-#if HAVE_SUN_ACL
-	for (e = 0; e < acl->acl_cnt; e++)
+#if HAVE_SUN_NFS4_ACL
+	for (e = 0; e < aclcnt; e++)
 #elif HAVE_DARWIN_ACL
 	while (0 == acl_get_entry(acl, entry_id, &acl_entry))
 #else
 	while (1 == acl_get_entry(acl, entry_id, &acl_entry))
 #endif
 	{
-#if HAVE_SUN_ACL
-		acl_entry = &((ace_t *)acl->acl_aclp)[e];
+#if HAVE_SUN_NFS4_ACL
+		acl_entry = &((ace_t *)aclp)[e];
 #else
 		/* After the first time... */
 		entry_id = ACL_NEXT_ENTRY;
@@ -711,11 +720,10 @@
 	skipping("NFS4 ACLs are not supported on this platform");
 #else
 	char buff[64];
+	int i;
 	struct stat st;
 	struct archive *a;
 	struct archive_entry *ae;
-	int i, n;
-	char *func;
 #if HAVE_DARWIN_ACL /* On MacOS we skip trivial ACLs in some tests */
 	const int regcnt = acls_reg_cnt - 4;
 	const int dircnt = acls_dir_cnt - 4;
@@ -723,86 +731,20 @@
 	const int regcnt = acls_reg_cnt;
 	const int dircnt = acls_dir_cnt;
 #endif
-#if HAVE_SUN_ACL
-	acl_t *acl;
-#else	/* !HAVE_SUN_ACL */
-#if HAVE_DARWIN_ACL
-	acl_entry_t aclent;
-	acl_permset_t permset;
-	const uid_t uid = 1000;
-	uuid_t uuid;
-#endif	/* HAVE_DARWIN_ACL */
+#if HAVE_SUN_NFS4_ACL
+	void *aclp;
+	int aclcnt;
+#else	/* !HAVE_SUN_NFS4_ACL */
 	acl_t acl;
-#endif	/* !HAVE_SUN_ACL */
-
-	/*
-	 * First, do a quick manual set/read of ACL data to
-	 * verify that the local filesystem does support ACLs.
-	 * If it doesn't, we'll simply skip the remaining tests.
-	 */
-#if HAVE_POSIX_ACL && HAVE_ACL_TYPE_NFS4
-	acl = acl_from_text("owner@:rwxp::allow,group@:rwp:f:allow");
-	failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno));
-	assert((void *)acl != NULL);
-#elif HAVE_DARWIN_ACL
-	acl = acl_init(1);
-	assert((void *)acl != NULL);
-	assertEqualInt(0, acl_create_entry(&acl, &aclent));
-	assertEqualInt(0, acl_set_tag_type(aclent, ACL_EXTENDED_ALLOW));
-	assertEqualInt(0, acl_get_permset(aclent, &permset));
-	assertEqualInt(0, acl_add_perm(permset, ACL_READ_DATA));
-	assertEqualInt(0, acl_add_perm(permset, ACL_WRITE_DATA));
-	assertEqualInt(0, acl_add_perm(permset, ACL_APPEND_DATA));
-	assertEqualInt(0, acl_add_perm(permset, ACL_EXECUTE));
-	assertEqualInt(0, acl_set_permset(aclent, permset));
-	assertEqualInt(0, mbr_identifier_to_uuid(ID_TYPE_UID, &uid,
-	    sizeof(uid_t), uuid));
-	assertEqualInt(0, acl_set_qualifier(aclent, uuid));
 #endif
 
-	/* Create a test dir and try to set an ACL on it. */
-	if (!assertMakeDir("pretest", 0755)) {
-#if !HAVE_SUN_ACL
-		acl_free(acl);
-#endif
+	assertMakeFile("pretest", 0644, "a");
+
+	if (setTestAcl("pretest") != ARCHIVE_TEST_ACL_TYPE_NFS4) {
+		skipping("NFS4 ACLs are not writable on this filesystem");
 		return;
 	}
 
-#if HAVE_SUN_ACL
-	func = "acl_get()";
-	n = acl_get("pretest", 0, &acl);
-#else
-	func = "acl_set_file()";
-#if HAVE_DARWIN_ACL
-	n = acl_set_file("pretest", ACL_TYPE_EXTENDED, acl);
-#else
-	n = acl_set_file("pretest", ACL_TYPE_NFS4, acl);
-#endif
-	acl_free(acl);
-#endif
-	if (n != 0) {
-#if HAVE_SUN_ACL
-		if (errno == ENOSYS)
-#else
-		if (errno == EOPNOTSUPP || errno == EINVAL)
-#endif
-		{
-			skipping("NFS4 ACL is not supported on this filesystem");
-			return;
-		}
-	}
-	failure("%s: errno = %d (%s)", func, errno, strerror(errno));
-	assertEqualInt(0, n);
-
-#if HAVE_SUN_ACL
-	if (acl->acl_type != ACE_T) {
-		acl_free(acl);
-		skipping("NFS4 ACL is not supported on this filesystem");
-		return;
-	}
-	acl_free(acl);
-#endif
-
 	/* Create a write-to-disk object. */
 	assert(NULL != (a = archive_write_disk_new()));
 	archive_write_disk_set_options(a,
@@ -848,10 +790,10 @@
 	/* Verify the data on disk. */
 	assertEqualInt(0, stat("testall", &st));
 	assertEqualInt(st.st_mtime, 123456);
-#if HAVE_SUN_ACL
-	n = acl_get("testall", 0, &acl);
-	failure("acl_get(): errno = %d (%s)", errno, strerror(errno));
-	assertEqualInt(0, n);
+#if HAVE_SUN_NFS4_ACL
+	aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, "testall");
+	failure("acl(): errno = %d (%s)", errno, strerror(errno));
+	assert(aclp != NULL);
 #else
 #if HAVE_DARWIN_ACL
 	acl = acl_get_file("testall", ACL_TYPE_EXTENDED);
@@ -861,18 +803,25 @@
 	failure("acl_get_file(): errno = %d (%s)", errno, strerror(errno));
 	assert(acl != (acl_t)NULL);
 #endif
+#if HAVE_SUN_NFS4_ACL
+	compare_acls(aclp, aclcnt, acls_reg, "testall", 0, regcnt);
+	free(aclp);
+	aclp = NULL;
+#else
 	compare_acls(acl, acls_reg, "testall", 0, regcnt);
 	acl_free(acl);
+#endif
+
 
 	/* Verify single-permission dirs on disk. */
 	for (i = 0; i < dircnt; ++i) {
 		sprintf(buff, "dir%d", i);
 		assertEqualInt(0, stat(buff, &st));
 		assertEqualInt(st.st_mtime, 123456 + i);
-#if HAVE_SUN_ACL
-		n = acl_get(buff, 0, &acl);
-		failure("acl_get(): errno = %d (%s)", errno, strerror(errno));
-		assertEqualInt(0, n);
+#if HAVE_SUN_NFS4_ACL
+		aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, buff);
+		failure("acl(): errno = %d (%s)", errno, strerror(errno));
+		assert(aclp != NULL);
 #else
 #if HAVE_DARWIN_ACL
 		acl = acl_get_file(buff, ACL_TYPE_EXTENDED);
@@ -883,17 +832,23 @@
 		    strerror(errno));
 		assert(acl != (acl_t)NULL);
 #endif
+#if HAVE_SUN_NFS4_ACL
+		compare_acls(aclp, aclcnt, acls_dir, buff, i, i + 1);
+		free(aclp);
+		aclp = NULL;
+#else
 		compare_acls(acl, acls_dir, buff, i, i + 1);
 		acl_free(acl);
+#endif
 	}
 
 	/* Verify "dirall" on disk. */
 	assertEqualInt(0, stat("dirall", &st));
 	assertEqualInt(st.st_mtime, 123456);
-#if HAVE_SUN_ACL
-	n = acl_get("dirall", 0, &acl);
-	failure("acl_get(): errno = %d (%s)", errno, strerror(errno));
-	assertEqualInt(0, n);
+#if HAVE_SUN_NFS4_ACL
+	aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, "dirall");
+	failure("acl(): errno = %d (%s)", errno, strerror(errno));
+	assert(aclp != NULL);
 #else
 #if HAVE_DARWIN_ACL
 	acl = acl_get_file("dirall", ACL_TYPE_EXTENDED);
@@ -903,8 +858,14 @@
 	failure("acl_get_file(): errno = %d (%s)", errno, strerror(errno));
 	assert(acl != (acl_t)NULL);
 #endif
+#if HAVE_SUN_NFS4_ACL
+	compare_acls(aclp, aclcnt, acls_dir, "dirall", 0, dircnt);
+	free(aclp);
+	aclp = NULL;
+#else
 	compare_acls(acl, acls_dir, "dirall", 0, dircnt);
 	acl_free(acl);
+#endif
 
 	/* Read and compare ACL via archive_read_disk */
 	a = archive_read_disk_new();
diff --git a/libarchive/test/test_acl_platform_posix1e.c b/libarchive/test/test_acl_platform_posix1e.c
index b46f658..0224a57 100644
--- a/libarchive/test/test_acl_platform_posix1e.c
+++ b/libarchive/test/test_acl_platform_posix1e.c
@@ -226,7 +226,7 @@
 
 static void
 #if HAVE_SUN_ACL
-compare_acls(acl_t *acl, struct archive_test_acl_t *myacls, int n)
+compare_acls(void *aclp, int aclcnt, struct archive_test_acl_t *myacls, int n)
 #else
 compare_acls(acl_t acl, struct archive_test_acl_t *myacls, int n)
 #endif
@@ -254,8 +254,8 @@
 	 * one with an item in the myacls array.
 	 */
 #if HAVE_SUN_ACL
-	for(e = 0; e < acl->acl_cnt; e++) {
-		acl_entry = &((aclent_t *)acl->acl_aclp)[e];
+	for(e = 0; e < aclcnt; e++) {
+		acl_entry = &((aclent_t *)aclp)[e];
 #else
 	while (1 == acl_get_entry(acl, entry_id, &acl_entry)) {
 		/* After the first time... */
@@ -304,84 +304,20 @@
 	struct stat st;
 	struct archive *a;
 	struct archive_entry *ae;
-	int n, fd;
-	char *func;
 #if HAVE_SUN_ACL
-	acl_t *acl, *acl2;
+	void *aclp;
+	int aclcnt;
 #else
 	acl_t acl;
 #endif
 
-	/*
-	 * First, do a quick manual set/read of ACL data to
-	 * verify that the local filesystem does support ACLs.
-	 * If it doesn't, we'll simply skip the remaining tests.
-	 */
-#if HAVE_SUN_ACL
-	n = acl_fromtext("user::rwx,user:1:rw-,group::rwx,group:15:r-x,other:rwx,mask:rwx", &acl);
-	failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno));
-	assertEqualInt(0, n);
-#else
-	acl = acl_from_text("u::rwx,u:1:rw,g::rwx,g:15:rx,o::rwx,m::rwx");
-	failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno));
-	assert((void *)acl != NULL);
-#endif
+	assertMakeFile("pretest", 0644, "a");
 
-	/* Create a test file and try ACL on it. */
-	fd = open("pretest", O_WRONLY | O_CREAT | O_EXCL, 0777);
-	failure("Could not create test file?!");
-	if (!assert(fd >= 0)) {
-		acl_free(acl);
+	if (setTestAcl("pretest") != ARCHIVE_TEST_ACL_TYPE_POSIX1E) {
+		skipping("POSIX.1e ACLs are not writable on this filesystem");
 		return;
 	}
 
-#if HAVE_SUN_ACL
-	n = facl_get(fd, 0, &acl2);
-	if (n != 0) {
-		close(fd);
-		acl_free(acl);
-	}
-	if (errno == ENOSYS) {
-		skipping("POSIX.1e ACLs are not supported on this filesystem");
-		return;
-	}
-	failure("facl_get(): errno = %d (%s)", errno, strerror(errno));
-	assertEqualInt(0, n);
-
-	if (acl2->acl_type != ACLENT_T) {
-		acl_free(acl2);
-		skipping("POSIX.1e ACLs are not supported on this filesystem");
-		return;
-	}
-	acl_free(acl2);
-
-	func = "facl_set()";
-	n = facl_set(fd, acl);
-#else
-	func = "acl_set_fd()";
-	n = acl_set_fd(fd, acl);
-#endif
-	acl_free(acl);
-	if (n != 0) {
-#if HAVE_SUN_ACL
-		if (errno == ENOSYS)
-#else
-		if (errno == EOPNOTSUPP || errno == EINVAL)
-#endif
-		{
-			close(fd);
-			skipping("POSIX.1e ACLs are not supported on this filesystem");
-			return;
-		}
-	}
-	failure("%s: errno = %d (%s)", func, errno, strerror(errno));
-	assertEqualInt(0, n);
-
-#if HAVE_SUN_ACL
-
-#endif
-	close(fd);
-
 	/* Create a write-to-disk object. */
 	assert(NULL != (a = archive_write_disk_new()));
 	archive_write_disk_set_options(a,
@@ -405,16 +341,23 @@
 	assertEqualInt(0, stat("test0", &st));
 	assertEqualInt(st.st_mtime, 123456);
 #if HAVE_SUN_ACL
-	n = acl_get("test0", 0, &acl);
-	failure("acl_get(): errno = %d (%s)", errno, strerror(errno));
-	assertEqualInt(0, n);
+	aclp = sunacl_get(GETACL, &aclcnt, 0, "test0");
+	failure("acl(): errno = %d (%s)", errno, strerror(errno));
+	assert(aclp != NULL);
 #else
 	acl = acl_get_file("test0", ACL_TYPE_ACCESS);
 	failure("acl_get_file(): errno = %d (%s)", errno, strerror(errno));
 	assert(acl != (acl_t)NULL);
 #endif
+#if HAVE_SUN_ACL
+	compare_acls(aclp, aclcnt, acls2, sizeof(acls2)/sizeof(acls2[0]));
+	free(aclp);
+	aclp = NULL;
+#else
 	compare_acls(acl, acls2, sizeof(acls2)/sizeof(acls2[0]));
 	acl_free(acl);
+#endif
+
 #endif	/* HAVE_SUN_ACL || HAVE_POSIX_ACL */
 }
 
@@ -432,7 +375,8 @@
 	char *func, *acl_text;
 	const char *acl1_text, *acl2_text, *acl3_text;
 #if HAVE_SUN_ACL
-	acl_t *acl, *acl1, *acl2, *acl3;
+	void *aclp;
+	int aclcnt;
 #else
 	acl_t acl1, acl2, acl3;
 #endif
@@ -451,9 +395,14 @@
 	    "user:1:rw-,"
 	    "group:15:r-x,"
 	    "mask:rwx";
-	n = acl_fromtext(acl1_text, &acl1);
-	failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno));
-	assertEqualInt(0, n);
+	aclent_t aclp1[] = {
+	    { USER_OBJ, -1, 4 | 2 | 1 },
+	    { USER, 1, 4 | 2 },
+	    { GROUP_OBJ, -1, 4 | 2 | 1 },
+	    { GROUP, 15, 4 | 1 },
+	    { CLASS_OBJ, -1, 4 | 2 | 1 },
+	    { OTHER_OBJ, -1, 4 | 2 | 1 }
+	};
 #else
 	acl1_text = "user::rwx\n"
 	    "group::rwx\n"
@@ -468,41 +417,36 @@
 	fd = open("f1", O_WRONLY | O_CREAT | O_EXCL, 0777);
 	failure("Could not create test file?!");
 	if (!assert(fd >= 0)) {
+#if !HAVE_SUN_ACL
 		acl_free(acl1);
+#endif
 		return;
 	}
 #if HAVE_SUN_ACL
 	/* Check if Solaris filesystem supports POSIX.1e ACLs */
-	n = facl_get(fd, 0, &acl);
-	if (n != 0)
+	aclp = sunacl_get(GETACL, &aclcnt, fd, NULL);
+	if (aclp == 0)
 		close(fd);
-	if (n != 0 && errno == ENOSYS) {
-		acl_free(acl1);
+	if (errno == ENOSYS || errno == ENOTSUP) {
 		skipping("POSIX.1e ACLs are not supported on this filesystem");
 		return;
 	}
-	failure("facl_get(): errno = %d (%s)", errno, strerror(errno));
-	assertEqualInt(0, n);
+	failure("facl(): errno = %d (%s)", errno, strerror(errno));
+	assert(aclp != NULL);
 
-	if (acl->acl_type != ACLENT_T) {
-		acl_free(acl);
-		acl_free(acl1);
-		close(fd);
-		skipping("POSIX.1e ACLs are not supported on this filesystem");
-		return;
-	}
-
-	func = "facl_set()";
-	n = facl_set(fd, acl1);
+	func = "facl()";
+	n = facl(fd, SETACL, (int)(sizeof(aclp1)/sizeof(aclp1[0])), aclp1);
 #else
 	func = "acl_set_fd()";
 	n = acl_set_fd(fd, acl1);
 #endif
+#if !HAVE_SUN_ACL
 	acl_free(acl1);
+#endif
 
 	if (n != 0) {
 #if HAVE_SUN_ACL
-		if (errno == ENOSYS)
+		if (errno == ENOSYS || errno == ENOTSUP)
 #else
 		if (errno == EOPNOTSUPP || errno == EINVAL)
 #endif
@@ -537,9 +481,14 @@
 	    "user:1:r--,"
 	    "group:15:r--,"
 	    "mask:rwx";
-	n = acl_fromtext(acl2_text, &acl2);
-	failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno));
-	assertEqualInt(0, n);
+	aclent_t aclp2[] = {
+	    { USER_OBJ, -1, 4 | 2 | 1 },
+	    { USER, 1, 4 },
+	    { GROUP_OBJ, -1, 4 | 2 | 1},
+	    { GROUP, 15, 4 },
+	    { CLASS_OBJ, -1, 4 | 2 | 1},
+	    { OTHER_OBJ, -1, 0 }
+	};
 #else
 	acl2_text = "user::rwx\n"
 	    "group::rwx\n"
@@ -554,17 +503,19 @@
 	fd = open("d/f1", O_WRONLY | O_CREAT | O_EXCL, 0777);
 	failure("Could not create test file?!");
 	if (!assert(fd >= 0)) {
+#if !HAVE_SUN_ACL
 		acl_free(acl2);
+#endif
 		return;
 	}
 #if HAVE_SUN_ACL
-	func = "facl_set()";
-	n = facl_set(fd, acl2);
+	func = "facl()";
+	n = facl(fd, SETACL, (int)(sizeof(aclp2) / sizeof(aclp2[0])), aclp2);
 #else
 	func = "acl_set_fd()";
 	n = acl_set_fd(fd, acl2);
-#endif
 	acl_free(acl2);
+#endif
 	if (n != 0)
 		close(fd);
 	failure("%s: errno = %d (%s)", func, errno, strerror(errno));
@@ -587,9 +538,20 @@
 	    "default:group:15:r--,"
 	    "default:mask:rwx,"
 	    "default:other:r-x";
-	n = acl_fromtext(acl3_text, &acl3);
-	failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno));
-	assertEqualInt(0, n);
+	aclent_t aclp3[] = {
+	    { USER_OBJ, -1, 4 | 2 | 1 },
+	    { USER, 2, 4 },
+	    { GROUP_OBJ, -1, 4 | 1 },
+	    { GROUP, 16, 2 },
+	    { CLASS_OBJ, -1, 4 | 2 | 1 },
+	    { OTHER_OBJ, -1, 4 | 1 },
+	    { USER_OBJ | ACL_DEFAULT, -1, 4 | 2 | 1 },
+	    { USER | ACL_DEFAULT, 1, 4 },
+	    { GROUP_OBJ | ACL_DEFAULT, -1, 4 | 1 },
+	    { GROUP | ACL_DEFAULT, 15, 4 },
+	    { CLASS_OBJ | ACL_DEFAULT, -1, 4 | 2 | 1},
+	    { OTHER_OBJ | ACL_DEFAULT, -1, 4 | 1 }
+	};
 #else
 	acl3_text = "user::rwx\n"
 	    "user:1:r--\n"
@@ -603,14 +565,13 @@
 #endif
 
 #if HAVE_SUN_ACL
-	func = "acl_set()";
-	n = acl_set("d/d2", acl3);
+	func = "acl()";
+	n = acl("d/d2", SETACL, (int)(sizeof(aclp3) / sizeof(aclp3[0])), aclp3);
 #else
 	func = "acl_set_file()";
 	n = acl_set_file("d/d2", ACL_TYPE_DEFAULT, acl3);
-#endif
 	acl_free(acl3);
-
+#endif
 	failure("%s: errno = %d (%s)", func, errno, strerror(errno));
 	assertEqualInt(0, n);
 
diff --git a/libarchive/test/test_read_disk_directory_traversals.c b/libarchive/test/test_read_disk_directory_traversals.c
index fdbfbec..705b3d9 100644
--- a/libarchive/test/test_read_disk_directory_traversals.c
+++ b/libarchive/test/test_read_disk_directory_traversals.c
@@ -1231,8 +1231,8 @@
 	 * Test4: Traversals with ARCHIVE_READDISK_RESTORE_ATIME and
 	 * ARCHIVE_READDISK_HONOR_NODUMP
 	 */
-	assertNodump("at/f1");
-	assertNodump("at/f2");
+	assertSetNodump("at/f1");
+	assertSetNodump("at/f2");
 	assertUtimes("at/f1", 886600, 0, 886600, 0);
 	assertUtimes("at/f2", 886611, 0, 886611, 0);
 	assertUtimes("at/fe", 886611, 0, 886611, 0);
@@ -1450,7 +1450,7 @@
 	assertMakeFile("nd/f1", 0644, "0123456789");
 	assertMakeFile("nd/f2", 0644, "hello world");
 	assertMakeFile("nd/fe", 0644, NULL);
-	assertNodump("nd/f2");
+	assertSetNodump("nd/f2");
 	assertUtimes("nd/f1", 886600, 0, 886600, 0);
 	assertUtimes("nd/f2", 886611, 0, 886611, 0);
 	assertUtimes("nd/fe", 886611, 0, 886611, 0);
diff --git a/tar/bsdtar.1 b/tar/bsdtar.1
index b60f09c..0537bf3 100644
--- a/tar/bsdtar.1
+++ b/tar/bsdtar.1
@@ -25,7 +25,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd February 24, 2017
+.Dd February 25, 2017
 .Dt TAR 1
 .Os
 .Sh NAME
@@ -450,14 +450,7 @@
 .Fl p
 and the default behavior if
 .Nm
-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 .
+is run as non-root.
 .It Fl Fl no-xattrs
 (c, r, u, x modes only)
 Do not archive or extract extended attributes. This is the reverse of
@@ -647,16 +640,16 @@
 (x mode only)
 Preserve file permissions.
 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
+extended attributes and extended file flags, if available, for each item
+extracted from the archive. This is te reverse of
+.Fl Fl no-same-permissions
+and the default if
 .Nm
-is being run by root and can be overridden by also specifying
+is being run by root and can be partially overridden by also specifying
 .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-mac-metadata
+or
 .Fl Fl no-xattrs .
 .It Fl Fl passphrase Ar passphrase
 The
diff --git a/tar/bsdtar.c b/tar/bsdtar.c
index a9252a5..9fc6833 100644
--- a/tar/bsdtar.c
+++ b/tar/bsdtar.c
@@ -118,11 +118,11 @@
 }
 #endif
 
-static void		 long_help(void);
+static void		 long_help(void) __LA_DEAD;
 static void		 only_mode(struct bsdtar *, const char *opt,
 			     const char *valid);
 static void		 set_mode(struct bsdtar *, char opt);
-static void		 version(void);
+static void		 version(void) __LA_DEAD;
 
 /* A basic set of security flags to request from libarchive. */
 #define	SECURITY					\
diff --git a/tar/bsdtar.h b/tar/bsdtar.h
index ee9c648..10a2cf2 100644
--- a/tar/bsdtar.h
+++ b/tar/bsdtar.h
@@ -189,7 +189,7 @@
 int	edit_pathname(struct bsdtar *, struct archive_entry *);
 int	need_report(void);
 int	pathcmp(const char *a, const char *b);
-void	safe_fprintf(FILE *, const char *fmt, ...);
+void	safe_fprintf(FILE *, const char *fmt, ...) __LA_PRINTF(2, 3);
 void	set_chdir(struct bsdtar *, const char *newdir);
 const char *tar_i64toa(int64_t);
 void	tar_mode_c(struct bsdtar *bsdtar);
@@ -197,8 +197,8 @@
 void	tar_mode_t(struct bsdtar *bsdtar);
 void	tar_mode_u(struct bsdtar *bsdtar);
 void	tar_mode_x(struct bsdtar *bsdtar);
-void	usage(void);
-int	yes(const char *fmt, ...);
+void	usage(void) __LA_DEAD;
+int	yes(const char *fmt, ...) __LA_PRINTF(1, 2);
 
 #if defined(HAVE_REGEX_H) || defined(HAVE_PCREPOSIX_H)
 void	add_substitution(struct bsdtar *, const char *);
diff --git a/tar/test/CMakeLists.txt b/tar/test/CMakeLists.txt
index 3dd3601..e6054ba 100644
--- a/tar/test/CMakeLists.txt
+++ b/tar/test/CMakeLists.txt
@@ -34,9 +34,11 @@
     test_option_U_upper.c
     test_option_X_upper.c
     test_option_a.c
+    test_option_acls.c
     test_option_b.c
     test_option_b64encode.c
     test_option_exclude.c
+    test_option_fflags.c
     test_option_gid_gname.c
     test_option_grzip.c
     test_option_j.c
@@ -71,6 +73,11 @@
   # Register target
   #
   ADD_EXECUTABLE(bsdtar_test ${bsdtar_test_SOURCES})
+  IF(ENABLE_ACL)
+    IF(HAVE_LIBACL)
+      TARGET_LINK_LIBRARIES(bsdtar_test ${ACL_LIBRARY})
+    ENDIF(HAVE_LIBACL)
+  ENDIF(ENABLE_ACL)
   SET_PROPERTY(TARGET bsdtar_test PROPERTY COMPILE_DEFINITIONS LIST_H)
 
   #
diff --git a/tar/test/test_option_acls.c b/tar/test/test_option_acls.c
new file mode 100644
index 0000000..bfe2b99
--- /dev/null
+++ b/tar/test/test_option_acls.c
@@ -0,0 +1,469 @@
+/*-
+ * Copyright (c) 2017 Martin Matuska
+ * 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"
+__FBSDID("$FreeBSD$");
+
+#if HAVE_POSIX_ACL || HAVE_DARWIN_ACL
+static const acl_perm_t acl_perms[] = {
+#if HAVE_DARWIN_ACL
+    ACL_READ_DATA,
+    ACL_LIST_DIRECTORY,
+    ACL_WRITE_DATA,
+    ACL_ADD_FILE,
+    ACL_EXECUTE,
+    ACL_SEARCH,
+    ACL_DELETE,
+    ACL_APPEND_DATA,
+    ACL_ADD_SUBDIRECTORY,
+    ACL_DELETE_CHILD,
+    ACL_READ_ATTRIBUTES,
+    ACL_WRITE_ATTRIBUTES,
+    ACL_READ_EXTATTRIBUTES,
+    ACL_WRITE_EXTATTRIBUTES,
+    ACL_READ_SECURITY,
+    ACL_WRITE_SECURITY,
+    ACL_CHANGE_OWNER,
+    ACL_SYNCHRONIZE
+#else /* !HAVE_DARWIN_ACL */
+    ACL_EXECUTE,
+    ACL_WRITE,
+    ACL_READ,
+#if HAVE_FREEBSD_NFS4_ACL
+    ACL_READ_DATA,
+    ACL_LIST_DIRECTORY,
+    ACL_WRITE_DATA,
+    ACL_ADD_FILE,
+    ACL_APPEND_DATA,
+    ACL_ADD_SUBDIRECTORY,
+    ACL_READ_NAMED_ATTRS,
+    ACL_WRITE_NAMED_ATTRS,
+    ACL_DELETE_CHILD,
+    ACL_READ_ATTRIBUTES,
+    ACL_WRITE_ATTRIBUTES,
+    ACL_DELETE,
+    ACL_READ_ACL,
+    ACL_WRITE_ACL,
+    ACL_WRITE_OWNER,
+    ACL_SYNCHRONIZE
+#endif	/* HAVE_FREEBSD_NFS4_ACL */
+#endif /* !HAVE_DARWIN_ACL */
+};
+#if HAVE_DARWIN_ACL || HAVE_FREEBSD_NFS4_ACL
+static const acl_flag_t acl_flags[] = {
+#if HAVE_DARWIN_ACL
+    ACL_ENTRY_INHERITED,
+    ACL_ENTRY_FILE_INHERIT,
+    ACL_ENTRY_DIRECTORY_INHERIT,
+    ACL_ENTRY_LIMIT_INHERIT,
+    ACL_ENTRY_ONLY_INHERIT
+#else	/* HAVE_FREEBSD_NFS4_ACL */
+    ACL_ENTRY_FILE_INHERIT,
+    ACL_ENTRY_DIRECTORY_INHERIT,
+    ACL_ENTRY_NO_PROPAGATE_INHERIT,
+    ACL_ENTRY_INHERIT_ONLY,
+    ACL_ENTRY_SUCCESSFUL_ACCESS,
+    ACL_ENTRY_FAILED_ACCESS,
+    ACL_ENTRY_INHERITED
+#endif	/* HAVE_FREEBSD_NFS4_ACL */
+};
+#endif /* HAVE_DARWIN_ACL || HAVE_FREEBSD_NFS4_ACL */
+
+/*
+ * Compare two ACL entries on FreeBSD or on Mac OS X
+ */
+static int
+compare_acl_entry(acl_entry_t ae_a, acl_entry_t ae_b, int is_nfs4)
+{
+	acl_tag_t tag_a, tag_b;
+	acl_permset_t permset_a, permset_b;
+	int perm_a, perm_b, perm_start, perm_end;
+	void *qual_a, *qual_b;
+#if HAVE_FREEBSD_NFS4_ACL
+	acl_entry_type_t type_a, type_b;
+#endif
+#if HAVE_FREEBSD_NFS4_ACL || HAVE_DARWIN_ACL
+	acl_flagset_t flagset_a, flagset_b;
+	int flag_a, flag_b;
+#endif
+	int i, r;
+
+
+	/* Compare ACL tag */
+	r = acl_get_tag_type(ae_a, &tag_a);
+	failure("acl_get_tag_type() error: %s", strerror(errno));
+	if (assertEqualInt(r, 0) == 0)
+		return (-1);
+	r = acl_get_tag_type(ae_b, &tag_b);
+	failure("acl_get_tag_type() error: %s", strerror(errno));
+	if (assertEqualInt(r, 0) == 0)
+		return (-1);
+	if (tag_a != tag_b)
+		return (0);
+
+	/* Compare ACL qualifier */
+#if HAVE_DARWIN_ACL
+	if (tag_a == ACL_EXTENDED_ALLOW || tag_b == ACL_EXTENDED_DENY)
+#else
+	if (tag_a == ACL_USER || tag_a == ACL_GROUP)
+#endif
+	{
+		qual_a = acl_get_qualifier(ae_a);
+		failure("acl_get_qualifier() error: %s", strerror(errno));
+		if (assert(qual_a != NULL) == 0)
+			return (-1);
+		qual_b = acl_get_qualifier(ae_b);
+		failure("acl_get_qualifier() error: %s", strerror(errno));
+		if (assert(qual_b != NULL) == 0) {
+			acl_free(qual_a);
+			return (-1);
+		}
+#if HAVE_DARWIN_ACL
+		if (memcmp(((guid_t *)qual_a)->g_guid,
+		    ((guid_t *)qual_b)->g_guid, KAUTH_GUID_SIZE) != 0)
+#else
+		if ((tag_a == ACL_USER &&
+		    (*(uid_t *)qual_a != *(uid_t *)qual_b)) ||
+		    (tag_a == ACL_GROUP &&
+		    (*(gid_t *)qual_a != *(gid_t *)qual_b)))
+#endif
+		{
+			acl_free(qual_a);
+			acl_free(qual_b);
+			return (0);
+		}
+		acl_free(qual_a);
+		acl_free(qual_b);
+	}
+
+#if HAVE_FREEBSD_NFS4_ACL
+	if (is_nfs4) {
+		/* Compare NFS4 ACL type */
+		r = acl_get_entry_type_np(ae_a, &type_a);
+		failure("acl_get_entry_type_np() error: %s", strerror(errno));
+		if (assertEqualInt(r, 0) == 0)
+			return (-1);
+		r = acl_get_entry_type_np(ae_b, &type_b);
+		failure("acl_get_entry_type_np() error: %s", strerror(errno));
+		if (assertEqualInt(r, 0) == 0)
+			return (-1);
+		if (type_a != type_b)
+			return (0);
+	}
+#endif
+
+	/* Compare ACL perms */
+	r = acl_get_permset(ae_a, &permset_a);
+	failure("acl_get_permset() error: %s", strerror(errno));
+	if (assertEqualInt(r, 0) == 0)
+		return (-1);
+	r = acl_get_permset(ae_b, &permset_b);
+	failure("acl_get_permset() error: %s", strerror(errno));
+	if (assertEqualInt(r, 0) == 0)
+		return (-1);
+
+	perm_start = 0;
+	perm_end = (int)(sizeof(acl_perms) / sizeof(acl_perms[0]));
+#if HAVE_FREEBSD_NFS4_ACL
+	if (is_nfs4)
+		perm_start = 3;
+	else
+		perm_end = 3;
+#endif
+	/* Cycle through all perms and compare their value */
+	for (i = perm_start; i < perm_end; i++) {
+#if HAVE_LIBACL
+		perm_a = acl_get_perm(permset_a, acl_perms[i]);
+		perm_b = acl_get_perm(permset_b, acl_perms[i]);
+#else
+		perm_a = acl_get_perm_np(permset_a, acl_perms[i]);
+		perm_b = acl_get_perm_np(permset_b, acl_perms[i]);
+#endif
+		if (perm_a == -1 || perm_b == -1)
+			return (-1);
+		if (perm_a != perm_b)
+			return (0);
+	}
+
+#if HAVE_FREEBSD_NFS4_ACL || HAVE_DARWIN_ACL
+	if (is_nfs4) {
+		r = acl_get_flagset_np(ae_a, &flagset_a);
+		failure("acl_get_flagset_np() error: %s", strerror(errno));
+		if (assertEqualInt(r, 0) == 0)
+			return (-1);
+		r = acl_get_flagset_np(ae_b, &flagset_b);
+		failure("acl_get_flagset_np() error: %s", strerror(errno));
+		if (assertEqualInt(r, 0) == 0)
+			return (-1);
+		/* Cycle through all flags and compare their status */
+		for (i = 0; i < (int)(sizeof(acl_flags) / sizeof(acl_flags[0]));
+		    i++) {
+			flag_a = acl_get_flag_np(flagset_a, acl_flags[i]);
+			flag_b = acl_get_flag_np(flagset_b, acl_flags[i]);
+			if (flag_a == -1 || flag_b == -1)
+				return (-1);
+			if (flag_a != flag_b)
+				return (0);
+		}
+	}
+#else	/* HAVE_FREEBSD_NFS4_ACL || HAVE_DARWIN_ACL*/
+	(void)is_nfs4;	/* UNUSED */
+#endif
+	return (1);
+}
+#endif	/* HAVE_POSIX_ACL || HAVE_DARWIN_ACL */
+
+#if HAVE_SUN_ACL || HAVE_DARWIN_ACL || HAVE_POSIX_ACL
+/*
+ * Clear default ACLs or inheritance flags
+ */
+static void
+clear_inheritance_flags(const char *path, int type)
+{
+	switch (type) {
+	case ARCHIVE_TEST_ACL_TYPE_POSIX1E:
+#if HAVE_POSIX_ACL
+		acl_delete_def_file(path);
+#else
+		/* Solaris */
+		setTestAcl(path);
+#endif
+		break;
+	case ARCHIVE_TEST_ACL_TYPE_NFS4:
+#if HAVE_NFS4_ACL
+		setTestAcl(path);
+#endif
+		break;
+	default:
+		(void)path;	/* UNUSED */
+		break;
+	}
+}
+
+static int
+compare_acls(const char *path_a, const char *path_b)
+{
+	int ret = 1;
+	int is_nfs4 = 0;
+#if HAVE_SUN_ACL
+	void *acl_a, *acl_b;
+	int aclcnt_a, aclcnt_b;
+        aclent_t *aclent_a, *aclent_b;
+        ace_t *ace_a, *ace_b;
+	int e;
+#else
+	acl_t acl_a, acl_b;
+	acl_entry_t aclent_a, aclent_b;
+	int a, b, r;
+#endif
+
+	acl_a = NULL;
+	acl_b = NULL;
+#if HAVE_SUN_ACL
+	acl_a = sunacl_get(GETACL, &aclcnt_a, 0, path_a);
+	if (acl_a == NULL) {
+#if HAVE_SUN_NFS4_ACL
+		is_nfs4 = 1;
+		acl_a = sunacl_get(ACE_GETACL, &aclcnt_a, 0, path_a);
+#endif
+		failure("acl_get() error: %s", strerror(errno));
+		if (assert(acl_a != NULL) == 0)
+			return (-1);
+#if HAVE_SUN_NFS4_ACL
+		acl_b = sunacl_get(ACE_GETACL, &aclcnt_b, 0, path_b);
+#endif
+	} else
+		acl_b = sunacl_get(GETACL, &aclcnt_b, 0, path_b);
+	if (acl_b == NULL && (errno == ENOSYS || errno == ENOTSUP)) {
+		free(acl_a);
+		return (0);
+	}
+	failure("acl_get() error: %s", strerror(errno));
+	if (assert(acl_b != NULL) == 0) {
+		free(acl_a);
+		return (-1);
+	}
+
+	if (aclcnt_a != aclcnt_b) {
+		ret = 0;
+		goto exit_free;
+	}
+
+	for (e = 0; e < aclcnt_a; e++) {
+		if (!is_nfs4) {
+			aclent_a = &((aclent_t *)acl_a)[e];
+			aclent_b = &((aclent_t *)acl_b)[e];
+			if (aclent_a->a_type != aclent_b->a_type ||
+			    aclent_a->a_id != aclent_b->a_id ||
+			    aclent_a->a_perm != aclent_b->a_perm) {
+				ret = 0;
+				goto exit_free;
+			}
+		}
+#if HAVE_SUN_NFS4_ACL
+		else {
+			ace_a = &((ace_t *)acl_a)[e];
+			ace_b = &((ace_t *)acl_b)[e];
+			if (ace_a->a_who != ace_b->a_who ||
+			    ace_a->a_access_mask != ace_b->a_access_mask ||
+			    ace_a->a_flags != ace_b->a_flags ||
+			    ace_a->a_type != ace_b->a_type) {
+				ret = 0;
+				goto exit_free;
+			}
+		}
+#endif
+	}
+#else	/* !HAVE_SUN_ACL */
+#if HAVE_DARWIN_ACL
+	is_nfs4 = 1;
+	acl_a = acl_get_file(path_a, ACL_TYPE_EXTENDED);
+#elif HAVE_FREEBSD_NFS4_ACL
+	acl_a = acl_get_file(path_a, ACL_TYPE_NFS4);
+	if (acl_a != NULL)
+		is_nfs4 = 1;
+#endif
+#if !HAVE_DARWIN_ACL
+	if (acl_a == NULL)
+		acl_a = acl_get_file(path_a, ACL_TYPE_ACCESS);
+#endif
+	failure("acl_get_file() error: %s (%s)", path_a, strerror(errno));
+	if (assert(acl_a != NULL) == 0)
+		return (-1);
+#if HAVE_DARWIN_ACL
+	acl_b = acl_get_file(path_b, ACL_TYPE_EXTENDED);
+#elif HAVE_FREEBSD_NFS4_ACL
+	acl_b = acl_get_file(path_b, ACL_TYPE_NFS4);
+#endif
+#if !HAVE_DARWIN_ACL
+	if (acl_b == NULL) {
+#if HAVE_FREEBSD_NFS4_ACL
+		if (is_nfs4) {
+			acl_free(acl_a);
+			return (0);
+		}
+#endif
+		acl_b = acl_get_file(path_b, ACL_TYPE_ACCESS);
+	}
+	failure("acl_get_file() error: %s (%s)", path_b, strerror(errno));
+	if (assert(acl_b != NULL) == 0) {
+		acl_free(acl_a);
+		return (-1);
+	}
+#endif
+	a = acl_get_entry(acl_a, ACL_FIRST_ENTRY, &aclent_a);
+	if (a == -1) {
+		ret = 0;
+		goto exit_free;
+	}
+	b = acl_get_entry(acl_b, ACL_FIRST_ENTRY, &aclent_b);
+	if (b == -1) {
+		ret = 0;
+		goto exit_free;
+	}
+#if HAVE_DARWIN_ACL
+	while (a == 0 && b == 0)
+#else	/* FreeBSD, Linux */
+	while (a == 1 && b == 1)
+#endif
+	{
+		r = compare_acl_entry(aclent_a, aclent_b, is_nfs4);
+		if (r != 1) {
+			ret = r;
+			goto exit_free;
+		}
+		a = acl_get_entry(acl_a, ACL_NEXT_ENTRY, &aclent_a);
+		b = acl_get_entry(acl_b, ACL_NEXT_ENTRY, &aclent_b);
+	}
+	/* Entry count must match */
+	if (a != b)
+		ret = 0;
+#endif	/* !HAVE_SUN_ACL */
+exit_free:
+#if HAVE_SUN_ACL
+	free(acl_a);
+	free(acl_b);
+#else
+	acl_free(acl_a);
+	acl_free(acl_b);
+#endif
+	return (ret);
+}
+#endif	/* HAVE_SUN_ACL || HAVE_DARWIN_ACL || HAVE_POSIX_ACL */
+
+DEFINE_TEST(test_option_acls)
+{
+#if !HAVE_SUN_ACL && !HAVE_DARWIN_ACL && !HAVE_POSIX_ACL
+        skipping("ACLs are not supported on this platform");
+#else   /* HAVE_SUN_ACL || HAVE_DARWIN_ACL || HAVE_POSIX_ACL */
+	int acltype, r;
+
+	assertMakeFile("f", 0644, "a");
+	acltype = setTestAcl("f");
+	if (acltype == 0) {
+		skipping("Can't write ACLs on the filesystem");
+		return;
+	}
+
+	/* Archive it with acls */
+        r = systemf("%s -c --no-mac-metadata --acls -f acls.tar f >acls.out 2>acls.err", testprog);
+        assertEqualInt(r, 0);
+
+	/* Archive it without acls */
+	r = systemf("%s -c --no-mac-metadata --no-acls -f noacls.tar f >noacls.out 2>noacls.err", testprog);
+	assertEqualInt(r, 0);
+
+	/* Extract acls with acls */
+	assertMakeDir("acls_acls", 0755);
+	clear_inheritance_flags("acls_acls", acltype);
+	r = systemf("%s -x -C acls_acls --no-same-permissions --acls -f acls.tar >acls_acls.out 2>acls_acls.err", testprog);
+	assertEqualInt(r, 0);
+	r = compare_acls("f", "acls_acls/f");
+	assertEqualInt(r, 1);
+
+	/* Extractl acls without acls */
+	assertMakeDir("acls_noacls", 0755);
+	clear_inheritance_flags("acls_noacls", acltype);
+	r = systemf("%s -x -C acls_noacls -p --no-acls -f acls.tar >acls_noacls.out 2>acls_noacls.err", testprog);
+	assertEqualInt(r, 0);
+	r = compare_acls("f", "acls_noacls/f");
+	assertEqualInt(r, 0);
+
+	/* Extract noacls with acls flag */
+	assertMakeDir("noacls_acls", 0755);
+	clear_inheritance_flags("noacls_acls", acltype);
+	r = systemf("%s -x -C noacls_acls --no-same-permissions --acls -f noacls.tar >noacls_acls.out 2>noacls_acls.err", testprog);
+	assertEqualInt(r, 0);
+	r = compare_acls("f", "noacls_acls/f");
+	assertEqualInt(r, 0);
+
+	/* Extract noacls with noacls */
+	assertMakeDir("noacls_noacls", 0755);
+	clear_inheritance_flags("noacls_noacls", acltype);
+	r = systemf("%s -x -C noacls_noacls -p --no-acls -f noacls.tar >noacls_noacls.out 2>noacls_noacls.err", testprog);
+	assertEqualInt(r, 0);
+	r = compare_acls("f", "noacls_noacls/f");
+	assertEqualInt(r, 0);
+#endif	/* HAVE_SUN_ACL || HAVE_DARWIN_ACL || HAVE_POSIX_ACL */
+}
diff --git a/tar/test/test_option_fflags.c b/tar/test/test_option_fflags.c
new file mode 100644
index 0000000..77a4e3e
--- /dev/null
+++ b/tar/test/test_option_fflags.c
@@ -0,0 +1,106 @@
+/*-
+ * Copyright (c) 2017 Martin Matuska
+ * 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"
+__FBSDID("$FreeBSD$");
+
+static void
+clear_fflags(const char *pathname)
+{
+#if defined(HAVE_STRUCT_STAT_ST_FLAGS)
+	chflags(pathname, 0);
+#elif (defined(FS_IOC_GETFLAGS) && defined(HAVE_WORKING_FS_IOC_GETFLAGS)) || \
+      (defined(EXT2_IOC_GETFLAGS) && defined(HAVE_WORKING_EXT2_IOC_GETFLAGS))
+	int fd;
+
+	fd = open(pathname, O_RDONLY | O_NONBLOCK);
+	if (fd < 0)
+		return;
+	ioctl(fd,
+#ifdef FS_IOC_GETFLAGS
+	    FS_IOC_GETFLAGS,
+#else
+	    EXT2_IOC_GETFLAGS,
+#endif
+	    0);
+#else
+	(void)pathname; /* UNUSED */
+#endif
+	return;
+}
+
+DEFINE_TEST(test_option_fflags)
+{
+	int r;
+
+	if (!canNodump()) {
+		skipping("Can't test nodump flag on this filesystem");
+		return;
+	}
+
+	/* Create a file. */
+	assertMakeFile("f", 0644, "a");
+
+	/* Set nodump flag on the file */
+	assertSetNodump("f");
+
+	/* FreeBSD ZFS workaround: ZFS sets uarch on all touched files and dirs */
+	chmod("f", 0644);
+
+	/* Archive it with fflags */
+	r = systemf("%s -c --fflags -f fflags.tar f >fflags.out 2>fflags.err", testprog);
+	assertEqualInt(r, 0);
+
+	/* Archive it without fflags */
+	r = systemf("%s -c --no-fflags -f nofflags.tar f >nofflags.out 2>nofflags.err", testprog);
+	assertEqualInt(r, 0);
+
+	/* Extract fflags with fflags */
+	assertMakeDir("fflags_fflags", 0755);
+	clear_fflags("fflags_fflags");
+	r = systemf("%s -x -C fflags_fflags --no-same-permissions --fflags -f fflags.tar >fflags_fflags.out 2>fflags_fflags.err", testprog);
+	assertEqualInt(r, 0);
+	assertEqualFflags("f", "fflags_fflags/f");
+
+	/* Extract fflags without fflags */
+	assertMakeDir("fflags_nofflags", 0755);
+	clear_fflags("fflags_nofflags");
+	r = systemf("%s -x -C fflags_nofflags -p --no-fflags -f fflags.tar >fflags_nofflags.out 2>fflags_nofflags.err", testprog);
+	assertEqualInt(r, 0);
+	assertUnequalFflags("f", "fflags_nofflags/f");
+
+	/* Extract nofflags with fflags */
+	assertMakeDir("nofflags_fflags", 0755);
+	clear_fflags("nofflags_fflags");
+	r = systemf("%s -x -C nofflags_fflags --no-same-permissions --fflags -f nofflags.tar >nofflags_fflags.out 2>nofflags_fflags.err", testprog);
+	assertEqualInt(r, 0);	
+	assertUnequalFflags("f", "nofflags_fflags/f");
+
+	/* Extract nofflags with nofflags */
+	assertMakeDir("nofflags_nofflags", 0755);
+	clear_fflags("nofflags_nofflags");
+	r = systemf("%s -x -C nofflags_nofflags -p --no-fflags -f nofflags.tar >nofflags_nofflags.out 2>nofflags_nofflags.err", testprog);
+	assertEqualInt(r, 0);
+	assertUnequalFflags("f", "nofflags_nofflags/f");
+}
diff --git a/tar/test/test_option_nodump.c b/tar/test/test_option_nodump.c
index 768f64a..815b08e 100644
--- a/tar/test/test_option_nodump.c
+++ b/tar/test/test_option_nodump.c
@@ -36,7 +36,7 @@
 	assertMakeFile("file1", 0644, "file1");
 	assertMakeFile("file2", 0644, "file2");
 	assertMakeFile("file3", 0644, "file3");
-	assertNodump("file2");
+	assertSetNodump("file2");
 
 	/* Test 1: Without --nodump */
 	assertEqualInt(0, systemf("%s -cf test1.tar file1 file2 file3",
diff --git a/test_utils/test_common.h b/test_utils/test_common.h
index 82e8483..44215a3 100644
--- a/test_utils/test_common.h
+++ b/test_utils/test_common.h
@@ -73,6 +73,12 @@
 #include <unistd.h>
 #endif
 #include <wchar.h>
+#ifdef HAVE_ACL_LIBACL_H
+#include <acl/libacl.h>
+#endif
+#ifdef HAVE_SYS_ACL_H
+#include <sys/acl.h>
+#endif
 #ifdef HAVE_WINDOWS_H
 #include <windows.h>
 #endif
@@ -127,26 +133,37 @@
  * 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
+#if HAVE_DECL_ACL_USER
 #define	HAVE_POSIX_ACL	1
-#elif HAVE_ACL_TYPE_EXTENDED
+#elif HAVE_DECL_ACL_TYPE_EXTENDED && HAVE_MEMBERSHIP_H
 #define	HAVE_DARWIN_ACL	1
 #endif
+#if HAVE_DECL_ACL_TYPE_NFS4
+#define	HAVE_FREEBSD_NFS4_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
+#if HAVE_SYS_ACL_H && HAVE_ACL && HAVE_FACL && HAVE_ACLENT_T && \
+    HAVE_DECL_GETACL && HAVE_DECL_GETACLCNT && HAVE_DECL_SETACL
+#define HAVE_SUN_ACL    1
+#if HAVE_ACE_T && HAVE_DECL_ACE_GETACL && HAVE_DECL_ACE_GETACLCNT && \
+    HAVE_DECL_ACE_SETACL
+#define HAVE_SUN_NFS4_ACL       1
+#endif
 #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
+#if HAVE_FREEBSD_NFS4_ACL || HAVE_SUN_NFS4_ACL || HAVE_DARWIN_ACL
+#define HAVE_NFS4_ACL   1
 #endif
 
+#define	ARCHIVE_TEST_ACL_TYPE_POSIX1E	1
+#define	ARCHIVE_TEST_ACL_TYPE_NFS4	2
+
 /*
  * Redefine DEFINE_TEST for use in defining the test functions.
  */
@@ -158,6 +175,9 @@
 /* chdir() and error if it fails */
 #define assertChdir(path)  \
   assertion_chdir(__FILE__, __LINE__, path)
+/* Assert two files have the same file flags */
+#define assertEqualFflags(patha, pathb)	\
+  assertion_compare_fflags(__FILE__, __LINE__, patha, pathb, 0)
 /* 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)
@@ -239,10 +259,13 @@
   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 assertSetNodump(path)	\
+  assertion_set_nodump(__FILE__, __LINE__, path)
 #define assertUmask(mask)	\
   assertion_umask(__FILE__, __LINE__, mask)
+/* Assert that two files have unequal file flags */
+#define assertUnequalFflags(patha, pathb)	\
+  assertion_compare_fflags(__FILE__, __LINE__, patha, pathb, 1)
 #define assertUtimes(pathname, atime, atime_nsec, mtime, mtime_nsec)	\
   assertion_utimes(__FILE__, __LINE__, pathname, atime, atime_nsec, mtime, mtime_nsec)
 #ifndef PROGRAM
@@ -265,6 +288,8 @@
 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_compare_fflags(const char *, int, const char *, const char *,
+    int);
 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 *);
@@ -295,8 +320,8 @@
 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_set_nodump(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 );
@@ -347,9 +372,17 @@
 /* Return true if this filesystem can handle nodump flags. */
 int canNodump(void);
 
+/* Set test ACLs */
+int setTestAcl(const char *path);
+
 /* Return true if the file has large i-node number(>0xffffffff). */
 int is_LargeInode(const char *);
 
+#if HAVE_SUN_ACL
+/* Fetch ACLs on Solaris using acl() or facl() */
+void *sunacl_get(int cmd, int *aclcnt, int fd, const char *path);
+#endif
+
 /* 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, ...);
diff --git a/test_utils/test_main.c b/test_utils/test_main.c
index 2ae6b38..5d0e287 100644
--- a/test_utils/test_main.c
+++ b/test_utils/test_main.c
@@ -56,6 +56,20 @@
 #include <stdarg.h>
 #include <time.h>
 
+/* ACL support */
+#ifdef HAVE_ACL_LIBACL_H
+#include <acl/libacl.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_ACL_H
+#include <sys/acl.h>
+#endif
+#if HAVE_DARWIN_ACL
+#include <membership.h>
+#endif
+
 /*
  *
  * Windows support routines
@@ -1883,9 +1897,103 @@
 #endif /* defined(_WIN32) && !defined(__CYGWIN__) */
 }
 
+/* Compare file flags */
+int
+assertion_compare_fflags(const char *file, int line, const char *patha,
+    const char *pathb, int nomatch)
+{
+#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP)
+	struct stat sa, sb;
+
+	assertion_count(file, line);
+
+	if (stat(patha, &sa) < 0)
+		return (0);
+	if (stat(pathb, &sb) < 0)
+		return (0);
+	if (!nomatch && sa.st_flags != sb.st_flags) {
+		failure_start(file, line, "File flags should be identical: "
+		    "%s=%#010x %s=%#010x", patha, sa.st_flags, pathb,
+		    sb.st_flags);
+		failure_finish(NULL);
+		return (0);
+	}
+	if (nomatch && sa.st_flags == sb.st_flags) {
+		failure_start(file, line, "File flags should be different: "
+		    "%s=%#010x %s=%#010x", patha, sa.st_flags, pathb,
+		    sb.st_flags);
+		failure_finish(NULL);
+		return (0);
+	}
+#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, flagsa, flagsb;
+
+	assertion_count(file, line);
+	fd = open(patha, O_RDONLY | O_NONBLOCK);
+	if (fd < 0) {
+		failure_start(file, line, "Can't open %s\n", patha);
+		failure_finish(NULL);
+		return (0);
+	}
+	r = ioctl(fd,
+#ifdef FS_IOC_GETFLAGS
+	    FS_IOC_GETFLAGS,
+#else
+	    EXT2_IOC_GETFLAGS,
+#endif
+	    &flagsa);
+	close(fd);
+	if (r < 0) {
+		failure_start(file, line, "Can't get flags %s\n", patha);
+		failure_finish(NULL);
+		return (0);
+	}
+	fd = open(pathb, O_RDONLY | O_NONBLOCK);
+	if (fd < 0) {
+		failure_start(file, line, "Can't open %s\n", pathb);
+		failure_finish(NULL);
+		return (0);
+	}
+	r = ioctl(fd,
+#ifdef FS_IOC_GETFLAGS
+	    FS_IOC_GETFLAGS,
+#else
+	    EXT2_IOC_GETFLAGS,
+#endif
+	    &flagsb);
+	close(fd);
+	if (r < 0) {
+		failure_start(file, line, "Can't get flags %s\n", pathb);
+		failure_finish(NULL);
+		return (0);
+	}
+	if (!nomatch && flagsa != flagsb) {
+		failure_start(file, line, "File flags should be identical: "
+		    "%s=%#010x %s=%#010x", patha, flagsa, pathb, flagsb);
+		failure_finish(NULL);
+		return (0);
+	}
+	if (nomatch && flagsa == flagsb) {
+		failure_start(file, line, "File flags should be different: "
+		    "%s=%#010x %s=%#010x", patha, flagsa, pathb, flagsb);
+		failure_finish(NULL);
+		return (0);
+	}
+#else
+	(void)patha; /* UNUSED */
+	(void)pathb; /* UNUSED */
+	(void)nomatch; /* UNUSED */
+	assertion_count(file, line);
+#endif
+	return (1);
+}
+
 /* Set nodump, report failures. */
 int
-assertion_nodump(const char *file, int line, const char *pathname)
+assertion_set_nodump(const char *file, int line, const char *pathname)
 {
 #if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP)
 	int r;
@@ -2256,11 +2364,10 @@
 /*
  * Can this filesystem handle nodump flags.
  */
-#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP)
-
 int
 canNodump(void)
 {
+#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP)
 	const char *path = "cannodumptest";
 	struct stat sb;
 
@@ -2271,16 +2378,10 @@
 		return (0);
 	if (sb.st_flags & UF_NODUMP)
 		return (1);
-	return (0);
-}
-
 #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)
-{
 	const char *path = "cannodumptest";
 	int fd, r, flags;
 
@@ -2331,18 +2432,230 @@
 	if (flags & EXT2_NODUMP_FL)
 #endif
 		return (1);
-	return (0);
-}
-
-#else
-
-int
-canNodump()
-{
-	return (0);
-}
-
 #endif
+	return (0);
+}
+
+#if HAVE_SUN_ACL
+/* Fetch ACLs on Solaris using acl() or facl() */
+void *
+sunacl_get(int cmd, int *aclcnt, int fd, const char *path)
+{
+	int cnt, cntcmd;
+	size_t size;
+	void *aclp;
+
+	if (cmd == GETACL) {
+		cntcmd = GETACLCNT;
+		size = sizeof(aclent_t);
+	}
+#if HAVE_SUN_NFS4_ACL
+	else if (cmd == ACE_GETACL) {
+		cntcmd = ACE_GETACLCNT;
+		size = sizeof(ace_t);
+	}
+#endif
+	else {
+		errno = EINVAL;
+		*aclcnt = -1;
+		return (NULL);
+	}
+
+	aclp = NULL;
+	cnt = -2;
+	while (cnt == -2 || (cnt == -1 && errno == ENOSPC)) {
+		if (path != NULL)
+			cnt = acl(path, cntcmd, 0, NULL);
+		else
+			cnt = facl(fd, cntcmd, 0, NULL);
+
+		if (cnt > 0) {
+			if (aclp == NULL)
+				aclp = malloc(cnt * size);
+			else
+				aclp = realloc(NULL, cnt * size);
+			if (aclp != NULL) {
+				if (path != NULL)
+					cnt = acl(path, cmd, cnt, aclp);
+				else
+					cnt = facl(fd, cmd, cnt, aclp);
+			}
+		} else {
+			if (aclp != NULL) {
+				free(aclp);
+				aclp = NULL;
+			}
+			break;
+		}
+	}
+
+	*aclcnt = cnt;
+	return (aclp);
+}
+#endif /* HAVE_SUN_ACL */
+
+/*
+ * Set test ACLs on a path
+ * Return values:
+ * 0: error setting ACLs
+ * ARCHIVE_TEST_ACL_TYPE_POSIX1E: POSIX.1E ACLs have been set
+ * ARCHIVE_TEST_ACL_TYPE_NFS4: NFSv4 or extended ACLs have been set
+ */
+int
+setTestAcl(const char *path)
+{
+#if HAVE_POSIX_ACL || HAVE_NFS4_ACL
+	int r = 1;
+#if !HAVE_SUN_ACL
+	acl_t acl;
+#endif
+#if HAVE_POSIX_ACL /* Linux, FreeBSD POSIX.1e */
+	const char *acltext_posix1e = "user:1:rw-,"
+	    "group:15:r-x,"
+	    "user::rwx,"
+	    "group::rwx,"
+	    "other::r-x,"
+	    "mask::rwx";
+#elif HAVE_SUN_ACL /* Solaris POSIX.1e */
+	aclent_t aclp_posix1e[] = {
+	    { USER_OBJ, -1, 4 | 2 | 1 },
+	    { USER, 1, 4 | 2 },
+	    { GROUP_OBJ, -1, 4 | 2 | 1 },
+	    { GROUP, 15, 4 | 1 },
+	    { CLASS_OBJ, -1, 4 | 2 | 1 },
+	    { OTHER_OBJ, -1, 4 | 2 | 1 }
+	};
+#endif
+#if HAVE_FREEBSD_NFS4_ACL /* FreeBSD NFS4 */
+	const char *acltext_nfs4 = "user:1:rwpaRcs::allow:1,"
+	    "group:15:rxaRcs::allow:15,"
+	    "owner@:rwpxaARWcCos::allow,"
+	    "group@:rwpxaRcs::allow,"
+	    "everyone@:rxaRcs::allow";
+#elif HAVE_SUN_NFS4_ACL /* Solaris NFS4 */
+	ace_t aclp_nfs4[] = {
+	    { 1, ACE_READ_DATA | ACE_WRITE_DATA | ACE_APPEND_DATA |
+	      ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS | ACE_READ_ACL |
+	      ACE_SYNCHRONIZE, 0, ACE_ACCESS_ALLOWED_ACE_TYPE },
+	    { 15, ACE_READ_DATA | ACE_EXECUTE | ACE_READ_ATTRIBUTES |
+	      ACE_READ_NAMED_ATTRS | ACE_READ_ACL | ACE_SYNCHRONIZE,
+	      ACE_IDENTIFIER_GROUP, ACE_ACCESS_ALLOWED_ACE_TYPE },
+	    { -1, ACE_READ_DATA | ACE_WRITE_DATA | ACE_APPEND_DATA |
+	      ACE_EXECUTE | ACE_READ_ATTRIBUTES | ACE_WRITE_ATTRIBUTES |
+	      ACE_READ_NAMED_ATTRS | ACE_WRITE_NAMED_ATTRS |
+	      ACE_READ_ACL | ACE_WRITE_ACL | ACE_WRITE_OWNER | ACE_SYNCHRONIZE,
+	      ACE_OWNER, ACE_ACCESS_ALLOWED_ACE_TYPE },
+	    { -1, ACE_READ_DATA | ACE_WRITE_DATA | ACE_APPEND_DATA |
+	      ACE_EXECUTE | ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS |
+	      ACE_READ_ACL | ACE_SYNCHRONIZE, ACE_GROUP | ACE_IDENTIFIER_GROUP,
+	      ACE_ACCESS_ALLOWED_ACE_TYPE },
+	    { -1, ACE_READ_DATA | ACE_EXECUTE | ACE_READ_ATTRIBUTES |
+	      ACE_READ_NAMED_ATTRS | ACE_READ_ACL | ACE_SYNCHRONIZE,
+	      ACE_EVERYONE, ACE_ACCESS_ALLOWED_ACE_TYPE }
+	};
+#elif HAVE_DARWIN_ACL /* Mac OS X */
+	acl_entry_t aclent;
+	acl_permset_t permset;
+	const uid_t uid = 1;
+	uuid_t uuid;
+	int i;
+	const acl_perm_t acl_perms[] = {
+		ACL_READ_DATA,
+		ACL_WRITE_DATA,
+		ACL_APPEND_DATA,
+		ACL_EXECUTE,
+		ACL_READ_ATTRIBUTES,
+		ACL_READ_EXTATTRIBUTES,
+		ACL_READ_SECURITY,
+#if HAVE_DECL_ACL_SYNCHRONIZE
+		ACL_SYNCHRONIZE
+#endif
+	};
+#endif /* HAVE_DARWIN_ACL */
+
+#if HAVE_FREEBSD_NFS4_ACL
+	acl = acl_from_text(acltext_nfs4);
+	failure("acl_from_text() error: %s", strerror(errno));
+	if (assert(acl != NULL) == 0)
+		return (0);
+#elif HAVE_DARWIN_ACL
+	acl = acl_init(1);
+	failure("acl_init() error: %s", strerror(errno));
+	if (assert(acl != NULL) == 0)
+		return (0);
+	r = acl_create_entry(&acl, &aclent);
+	failure("acl_create_entry() error: %s", strerror(errno));
+	if (assertEqualInt(r, 0) == 0)
+		goto testacl_free;
+	r = acl_set_tag_type(aclent, ACL_EXTENDED_ALLOW);
+	failure("acl_set_tag_type() error: %s", strerror(errno));
+	if (assertEqualInt(r, 0) == 0)
+		goto testacl_free;
+	r = acl_get_permset(aclent, &permset);
+	failure("acl_get_permset() error: %s", strerror(errno));
+	if (assertEqualInt(r, 0) == 0)
+		goto testacl_free;
+	for (i = 0; i < (int)(sizeof(acl_perms) / sizeof(acl_perms[0])); i++) {
+		r = acl_add_perm(permset, acl_perms[i]);
+		failure("acl_add_perm() error: %s", strerror(errno));
+		if (assertEqualInt(r, 0) == 0)
+			goto testacl_free;
+	}
+	r = acl_set_permset(aclent, permset);
+	failure("acl_set_permset() error: %s", strerror(errno));
+	if (assertEqualInt(r, 0) == 0)
+		goto testacl_free;
+	r = mbr_uid_to_uuid(uid, uuid);
+	failure("mbr_uid_to_uuid() error: %s", strerror(errno));
+	if (assertEqualInt(r, 0) == 0)
+		goto testacl_free;
+	r = acl_set_qualifier(aclent, uuid);
+	failure("acl_set_qualifier() error: %s", strerror(errno));
+	if (assertEqualInt(r, 0) == 0)
+		goto testacl_free;
+#endif /* HAVE_DARWIN_ACL */
+
+#if HAVE_NFS4_ACL
+#if HAVE_FREEBSD_NFS4_ACL
+	r = acl_set_file(path, ACL_TYPE_NFS4, acl);
+	acl_free(acl);
+#elif HAVE_SUN_NFS4_ACL
+	r = acl(path, ACE_SETACL,
+	    (int)(sizeof(aclp_nfs4)/sizeof(aclp_nfs4[0])), aclp_nfs4);
+#elif HAVE_DARWIN_ACL
+	r = acl_set_file(path, ACL_TYPE_EXTENDED, acl);
+	acl_free(acl);
+#endif
+	if (r == 0)
+		return (ARCHIVE_TEST_ACL_TYPE_NFS4);
+#endif	/* HAVE_NFS4_ACL */
+
+#if HAVE_POSIX_ACL || HAVE_SUN_ACL
+#if HAVE_POSIX_ACL
+	acl = acl_from_text(acltext_posix1e);
+	failure("acl_from_text() error: %s", strerror(errno));
+	if (assert(acl != NULL) == 0)
+		return (0);
+
+	r = acl_set_file(path, ACL_TYPE_ACCESS, acl);
+	acl_free(acl);
+#elif HAVE_SUN_ACL
+	r = acl(path, SETACL,
+	    (int)(sizeof(aclp_posix1e)/sizeof(aclp_posix1e[0])), aclp_posix1e);
+#endif
+	if (r == 0)
+		return (ARCHIVE_TEST_ACL_TYPE_POSIX1E);
+	else
+		return (0);
+#endif /* HAVE_POSIX_ACL || HAVE_SUN_ACL */
+#if HAVE_DARWIN_ACL
+testacl_free:
+	acl_free(acl);
+#endif
+#endif /* HAVE_POSIX_ACL || HAVE_NFS4_ACL */
+	(void)path;	/* UNUSED */
+	return (0);
+}
 
 /*
  * Sleep as needed; useful for verifying disk timestamp changes by