+--- Makefile.am.orig
++++ Makefile.am
+@@ -23,7 +23,7 @@ TESTS_ENVIRONMENT= $(libarchive_TESTS_ENVIRONMENT) $(bsdtar_TESTS_ENVIRONMENT) $
+ DISTCHECK_CONFIGURE_FLAGS = --enable-bsdtar --enable-bsdcpio
+ # The next line is commented out by default in shipping libarchive releases.
+ # It is uncommented by default in trunk.
+-# DEV_CFLAGS=-Werror -Wextra -Wunused -Wshadow -Wmissing-prototypes -Wcast-qual -g
++DEV_CFLAGS=-Werror -Wextra -Wunused -Wshadow -Wmissing-prototypes -Wcast-qual -g
+ AM_CFLAGS=$(DEV_CFLAGS)
+ PLATFORMCPPFLAGS = @PLATFORMCPPFLAGS@
+ AM_CPPFLAGS=$(PLATFORMCPPFLAGS)
+@@ -127,6 +127,7 @@ libarchive_la_SOURCES= \
+ libarchive/archive_pathmatch.c \
+ libarchive/archive_pathmatch.h \
+ libarchive/archive_platform.h \
++ libarchive/archive_platform_acl.h \
+ libarchive/archive_ppmd_private.h \
+ libarchive/archive_ppmd7.c \
+ libarchive/archive_ppmd7_private.h \
+@@ -186,9 +187,9 @@ libarchive_la_SOURCES= \
+ 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 \
+ libarchive/archive_write_disk_posix.c \
+ libarchive/archive_write_disk_private.h \
+ libarchive/archive_write_disk_set_standard_lookup.c \
+@@ -247,6 +248,38 @@ libarchive_la_SOURCES+= \
+ libarchive/filter_fork_windows.c
+ endif
+
++if INC_LINUX_ACL
++libarchive_la_SOURCES+= \
++ libarchive/archive_acl_maps.h \
++ libarchive/archive_acl_maps_linux.c \
++ libarchive/archive_read_disk_acl_linux.c \
++ libarchive/archive_write_disk_acl_linux.c
++else
++if INC_SUNOS_ACL
++libarchive_la_SOURCES+= \
++ libarchive/archive_acl_maps.h \
++ libarchive/archive_acl_maps_sunos.c \
++ libarchive/archive_read_disk_acl_sunos.c \
++ libarchive/archive_write_disk_acl_sunos.c
++else
++if INC_DARWIN_ACL
++libarchive_la_SOURCES+= \
++ libarchive/archive_acl_maps.h \
++ libarchive/archive_acl_maps_darwin.c \
++ libarchive/archive_read_disk_acl_darwin.c \
++ libarchive/archive_write_disk_acl_darwin.c
++else
++if INC_FREEBSD_ACL
++libarchive_la_SOURCES+= \
++ libarchive/archive_acl_maps.h \
++ libarchive/archive_acl_maps_freebsd.c \
++ libarchive/archive_read_disk_acl_freebsd.c \
++ libarchive/archive_write_disk_acl_freebsd.c
++endif
++endif
++endif
++endif
++
+ # -no-undefined marks that libarchive doesn't rely on symbols
+ # defined in the application. This is mandatory for cygwin.
+ libarchive_la_LDFLAGS= -no-undefined -version-info $(ARCHIVE_LIBTOOL_VERSION)
+@@ -951,10 +984,12 @@ bsdtar_test_SOURCES= \
+ 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 \
+--- NEWS.orig
++++ NEWS
+@@ -1,3 +1,5 @@
++Mar 16, 2017: NFSv4 ACL support for Linux (librichacl)
++
+ Feb 26, 2017: libarchive 3.3.1 released
+ Security & Feature release
+
+@@ -293,7 +295,7 @@ May 04, 2008: libarchive 2.5.3b released
+ * 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
+--- build/cmake/config.h.in.orig
++++ build/cmake/config.h.in
+@@ -179,6 +179,27 @@ typedef uint64_t uintmax_t;
+ /* Define ZLIB_WINAPI if zlib was built on Visual Studio. */
+ #cmakedefine ZLIB_WINAPI 1
+
++/* Darwin ACL support */
++#cmakedefine ARCHIVE_ACL_DARWIN 1
++
++/* FreeBSD ACL support */
++#cmakedefine ARCHIVE_ACL_FREEBSD 1
++
++/* FreeBSD NFSv4 ACL support */
++#cmakedefine ARCHIVE_ACL_FREEBSD_NFS4 1
++
++/* Linux POSIX.1e ACL support via libacl */
++#cmakedefine ARCHIVE_ACL_LIBACL 1
++
++/* Linux NFSv4 ACL support via librichacl */
++#cmakedefine ARCHIVE_ACL_LIBRICHACL 1
++
++/* Solaris ACL support */
++#cmakedefine ARCHIVE_ACL_SUNOS 1
++
++/* Solaris NFSv4 ACL support */
++#cmakedefine ARCHIVE_ACL_SUNOS_NFS4 1
++
+ /* MD5 via ARCHIVE_CRYPTO_MD5_LIBC supported. */
+ #cmakedefine ARCHIVE_CRYPTO_MD5_LIBC 1
+
+@@ -326,15 +347,6 @@ typedef uint64_t uintmax_t;
+ /* 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 +383,34 @@ typedef uint64_t uintmax_t;
+ /* 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 +435,10 @@ typedef uint64_t uintmax_t;
+ 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 +512,14 @@ typedef uint64_t uintmax_t;
+ /* 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 +794,9 @@ typedef uint64_t uintmax_t;
+ /* 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
+
+@@ -979,6 +1034,9 @@ typedef uint64_t uintmax_t;
+ /* Define to 1 if you have the <sys/poll.h> header file. */
+ #cmakedefine HAVE_SYS_POLL_H 1
+
++/* Define to 1 if you have the <sys/richacl.h> header file. */
++#cmakedefine HAVE_SYS_RICHACL_H 1
++
+ /* Define to 1 if you have the <sys/select.h> header file. */
+ #cmakedefine HAVE_SYS_SELECT_H 1
+
+--- build/version.orig
++++ build/version
+@@ -1 +1 @@
+-3003001
++3003002dev
+--- cat/test/CMakeLists.txt.orig
++++ cat/test/CMakeLists.txt
+@@ -29,6 +29,16 @@ IF(ENABLE_CAT AND ENABLE_TEST)
+ # Register target
+ #
+ ADD_EXECUTABLE(bsdcat_test ${bsdcat_test_SOURCES})
++ IF(ENABLE_ACL)
++ SET(TEST_ACL_LIBS "")
++ IF(HAVE_LIBACL)
++ LIST(APPEND TEST_ACL_LIBS ${ACL_LIBRARY})
++ ENDIF(HAVE_LIBACL)
++ IF(HAVE_LIBRICHACL)
++ LIST(APPEND TEST_ACL_LIBS ${RICHACL_LIBRARY})
++ ENDIF(HAVE_LIBRICHACL)
++ TARGET_LINK_LIBRARIES(bsdcat_test ${TEST_ACL_LIBS})
++ ENDIF(ENABLE_ACL)
+ SET_PROPERTY(TARGET bsdcat_test PROPERTY COMPILE_DEFINITIONS LIST_H)
+
+ #
+--- configure.ac.orig
++++ configure.ac
+@@ -4,8 +4,8 @@ dnl First, define all of the version numbers up front.
+ 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.1])
+-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())
+@@ -253,6 +253,7 @@ esac
+ # Checks for header files.
+ AC_HEADER_DIRENT
+ AC_HEADER_SYS_WAIT
++AC_CHECK_HEADERS([acl/libacl.h])
+ AC_CHECK_HEADERS([copyfile.h ctype.h])
+ AC_CHECK_HEADERS([errno.h ext2fs/ext2_fs.h fcntl.h grp.h])
+
+@@ -283,16 +284,16 @@ AS_VAR_IF([ac_cv_have_decl_FS_IOC_GETFLAGS], [yes],
+ [AC_DEFINE_UNQUOTED([HAVE_WORKING_FS_IOC_GETFLAGS], [1],
+ [Define to 1 if you have a working FS_IOC_GETFLAGS])])
+
+-AC_CHECK_HEADERS([locale.h paths.h poll.h pthread.h pwd.h])
++AC_CHECK_HEADERS([locale.h membership.h paths.h poll.h pthread.h pwd.h])
+ AC_CHECK_HEADERS([readpassphrase.h signal.h spawn.h])
+ AC_CHECK_HEADERS([stdarg.h stdint.h stdlib.h string.h])
+-AC_CHECK_HEADERS([sys/cdefs.h sys/extattr.h])
++AC_CHECK_HEADERS([sys/acl.h sys/cdefs.h sys/extattr.h])
+ AC_CHECK_HEADERS([sys/ioctl.h sys/mkdev.h sys/mount.h])
+-AC_CHECK_HEADERS([sys/param.h sys/poll.h sys/select.h sys/statfs.h sys/statvfs.h])
++AC_CHECK_HEADERS([sys/param.h sys/poll.h sys/richacl.h])
++AC_CHECK_HEADERS([sys/select.h sys/statfs.h sys/statvfs.h])
+ 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 +400,9 @@ if test "x$with_lzo2" = "xyes"; then
+ 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],
+@@ -697,72 +701,211 @@ AC_ARG_ENABLE([acl],
+ [Disable ACL support (default: check)]))
+
+ if test "x$enable_acl" != "xno"; then
+- AC_CHECK_HEADERS([acl/libacl.h])
+- AC_CHECK_HEADERS([sys/acl.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])
++ # Libacl
++ AC_CHECK_LIB([acl], [acl_get_file])
++
++ AC_CHECK_TYPES([acl_t, acl_entry_t, acl_permset_t, acl_tag_t], [], [], [
++ #if HAVE_SYS_TYPES_H
++ #include <sys/types.h>
++ #endif
++ #if HAVE_SYS_ACL_H
++ #include <sys/acl.h>
++ #endif
++ ])
++
++ AC_CHECK_LIB([richacl], [richacl_get_file])
++
++ AC_CHECK_TYPES([[struct richace], [struct richacl]], [], [], [
++ #if HAVE_SYS_RICHACL_H
++ #include <sys/richacl.h>
++ #endif
++ ])
+
+- AC_CHECK_TYPES(acl_permset_t,,,
+- [#if HAVE_SYS_TYPES_H
+- #include <sys/types.h>
+- #endif
+- #if HAVE_SYS_ACL_H
+- #include <sys/acl.h>
+- #endif
+- ])
+-
+- # The "acl_get_perm()" function was omitted from the POSIX draft.
+- # (It's a pretty obvious oversight; otherwise, there's no way to
+- # test for specific permissions in a permset.) Linux uses the obvious
+- # name, FreeBSD adds _np to mark it as "non-Posix extension."
+- # Test for both as a double-check that we really have POSIX-style ACL
+- # support.
+- AC_CHECK_FUNCS(acl_get_perm_np acl_get_perm acl_get_link acl_get_link_np,,,
+- [#if HAVE_SYS_TYPES_H
+- #include <sys/types.h>
+- #endif
+- #if HAVE_SYS_ACL_H
+- #include <sys/acl.h>
+- #endif
+- ])
++ # Solaris and derivates ACLs
++ AC_CHECK_FUNCS(acl facl)
++
++ if test "x$ac_cv_lib_richacl_richacl_get_file" = "xyes" \
++ -a "x$ac_cv_type_struct_richace" = "xyes" \
++ -a "x$ac_cv_type_struct_richacl" = "xyes"; then
++ AC_CACHE_VAL([ac_cv_archive_acl_librichacl],
++ [AC_CHECK_FUNCS(richacl_alloc \
++ richacl_equiv_mode \
++ richacl_free \
++ richacl_get_fd \
++ richacl_get_file \
++ richacl_set_fd \
++ richacl_set_file,
++ [ac_cv_archive_acl_librichacl=yes], [ac_cv_archive_acl_librichacl=no], [#include <sys/richacl.h>])])
++ fi
+
+- # Check for acl_is_trivial_np on FreeBSD
+- AC_CHECK_FUNCS(acl_is_trivial_np,,,
+- [#if HAVE_SYS_TYPES_H
+- #include <sys/types.h>
+- #endif
+- #if HAVE_SYS_ACL_H
+- #include <sys/acl.h>
+- #endif
++ if test "x$ac_cv_func_acl" = "xyes" \
++ -a "x$ac_cv_func_facl" = "xyes"; then
++ AC_CHECK_TYPES([aclent_t], [], [], [[#include <sys/acl.h>]])
++ if test "x$ac_cv_type_aclent_t" = "xyes"; then
++ AC_CACHE_VAL([ac_cv_archive_acl_sunos],
++ [AC_CHECK_DECLS([GETACL, SETACL, GETACLCNT],
++ [ac_cv_archive_acl_sunos=yes], [ac_cv_archive_acl_sunos=no],
++ [#include <sys/acl.h>])])
++ AC_CHECK_TYPES([ace_t], [], [], [[#include <sys/acl.h>]])
++ if test "x$ac_cv_type_ace_t" = "xyes"; then
++ AC_CACHE_VAL([ac_cv_archive_acl_sunos_nfs4],
++ [AC_CHECK_DECLS([ACE_GETACL, ACE_SETACL, ACE_GETACLCNT],
++ [ac_cv_archive_acl_sunos_nfs4=yes],
++ [ac_cv_archive_acl_sonos_nfs4=no],
++ [#include <sys/acl.h>])])
++ fi
++ fi
++ elif test "x$ac_cv_type_acl_t" = "xyes" \
++ -a "x$ac_cv_type_acl_entry_t" = "xyes" \
++ -a "x$ac_cv_type_acl_permset_t" = "xyes" \
++ -a "x$ac_cv_type_acl_tag_t" = "xyes"; then
++ # POSIX.1e ACL functions
++ AC_CACHE_VAL([ac_cv_posix_acl_funcs],
++ [AC_CHECK_FUNCS(acl_add_perm \
++ acl_clear_perms \
++ acl_create_entry \
++ acl_delete_def_file \
++ acl_free \
++ acl_get_entry \
++ acl_get_fd \
++ acl_get_file \
++ acl_get_permset \
++ acl_get_qualifier \
++ acl_get_tag_type \
++ acl_init \
++ acl_set_fd \
++ acl_set_file \
++ acl_set_qualifier \
++ acl_set_tag_type,
++ [ac_cv_posix_acl_funcs=yes], [ac_cv_posix_acl_funcs=no],
++ [#if HAVE_SYS_TYPES_H
++ #include <sys/types.h>
++ #endif
++ #if HAVE_SYS_ACL_H
++ #include <sys/acl.h>
++ #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>])
++ AC_CHECK_FUNCS(acl_get_perm)
+
+- # 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>])
++ if test "x$ac_cv_posix_acl_funcs" = "xyes" \
++ -a "x$ac_cv_header_acl_libacl_h" = "xyes" \
++ -a "x$ac_cv_lib_acl_acl_get_file" = "xyes" \
++ -a "x$ac_cv_func_acl_get_perm"; then
++ AC_CACHE_VAL([ac_cv_archive_acl_libacl],
++ [ac_cv_archive_acl_libacl=yes])
++ AC_DEFINE([ARCHIVE_ACL_LIBACL], [1],
++ [POSIX.1e ACL support via libacl])
++ else
++ # FreeBSD/Darwin
++ AC_CHECK_FUNCS(acl_add_flag_np \
++ acl_clear_flags_np \
++ acl_get_brand_np \
++ acl_get_entry_type_np \
++ acl_get_flag_np \
++ acl_get_flagset_np \
++ acl_get_fd_np \
++ acl_get_link_np \
++ acl_get_perm_np \
++ acl_is_trivial_np \
++ acl_set_entry_type_np \
++ acl_set_fd_np \
++ acl_set_link_np,,,
++ [#include <sys/types.h>
++ #include <sys/acl.h>])
++
++ AC_CHECK_FUNCS(mbr_uid_to_uuid \
++ mbr_uuid_to_id \
++ mbr_gid_to_uuid,,,
++ [#include <membership.h>])
++
++ AC_CHECK_DECLS([ACL_TYPE_EXTENDED, ACL_TYPE_NFS4, ACL_USER,
++ ACL_SYNCHRONIZE], [], [],
++ [#include <sys/types.h>
++ #include <sys/acl.h>])
++ if test "x$ac_cv_posix_acl_funcs" = "xyes" \
++ -a "x$ac_cv_func_acl_get_fd_np" = "xyes" \
++ -a "x$ac_cv_func_acl_get_perm" != "xyes" \
++ -a "x$ac_cv_func_acl_get_perm_np" = "xyes" \
++ -a "x$ac_cv_func_acl_set_fd_np" = "xyes"; then
++ if test "x$ac_cv_have_decl_ACL_USER" = "xyes"; then
++ AC_CACHE_VAL([ac_cv_archive_acl_freebsd],
++ [ac_cv_archive_acl_freebsd=yes])
++ if test "x$ac_cv_have_decl_ACL_TYPE_NFS4" = "xyes" \
++ -a "x$ac_cv_func_acl_add_flag_np" = "xyes" \
++ -a "x$ac_cv_func_acl_get_brand_np" = "xyes" \
++ -a "x$ac_cv_func_acl_get_entry_type_np" = "xyes" \
++ -a "x$ac_cv_func_acl_get_flagset_np" = "xyes" \
++ -a "x$ac_cv_func_acl_set_entry_type_np" = "xyes"; then
++ AC_CACHE_VAL([ac_cv_archive_acl_freebsd_nfs4],
++ [ac_cv_archive_acl_freebsd_nfs4=yes])
++ fi
++ elif test "x$ac_cv_have_decl_ACL_TYPE_EXTENDED" = "xyes" \
++ -a "x$ac_cv_func_acl_add_flag_np" = "xyes" \
++ -a "x$ac_cv_func_acl_get_flagset_np" = "xyes" \
++ -a "x$ac_cv_func_acl_get_link_np" = "xyes" \
++ -a "x$ac_cv_func_acl_set_link_np" = "xyes" \
++ -a "x$ac_cv_func_mbr_uid_to_uuid" = "xyes" \
++ -a "x$ac_cv_func_mbr_uuid_to_id" = "xyes" \
++ -a "x$ac_cv_func_mbr_gid_to_uuid" = "xyes"; then
++ AC_CACHE_VAL([ac_cv_archive_acl_darwin],
++ [ac_cv_archive_acl_darwin=yes])
++ fi
++ fi
++ fi
++ fi
++ AC_MSG_CHECKING([for ACL support])
++ if test "x$ac_cv_archive_acl_libacl" = "xyes" \
++ -a "x$ac_cv_archive_acl_librichacl" = "xyes"; then
++ AC_MSG_RESULT([libacl (POSIX.1e) + librichacl (NFSv4)])
++ AC_DEFINE([ARCHIVE_ACL_LIBACL], [1],
++ [Linux POSIX.1e ACL support via libacl])
++ AC_DEFINE([ARCHIVE_ACL_LIBRICHACL], [1],
++ [Linux NFSv4 ACL support via librichacl])
++ elif test "x$ac_cv_archive_acl_libacl" = "xyes"; then
++ AC_MSG_RESULT([libacl (POSIX.1e)])
++ AC_DEFINE([ARCHIVE_ACL_LIBACL], [1],
++ [Linux POSIX.1e ACL support via libacl])
++ elif test "x$ac_cv_archive_acl_librichacl" = "xyes"; then
++ AC_MSG_RESULT([librichacl (NFSv4)])
++ AC_DEFINE([ARCHIVE_ACL_LIBRICHACL], [1],
++ [Linux NFSv4 ACL support via librichacl])
++ elif test "x$ac_cv_archive_acl_darwin" = "xyes"; then
++ AC_DEFINE([ARCHIVE_ACL_DARWIN], [1], [Darwin ACL support])
++ AC_MSG_RESULT([Darwin (limited NFSv4)])
++ elif test "x$ac_cv_archive_acl_sunos" = "xyes"; then
++ AC_DEFINE([ARCHIVE_ACL_SUNOS], [1], [Solaris ACL support])
++ if test "x$ac_cv_archive_acl_sunos_nfs4" = "xyes"; then
++ AC_DEFINE([ARCHIVE_ACL_SUNOS_NFS4], [1],
++ [Solaris NFSv4 ACL support])
++ AC_MSG_RESULT([Solaris (POSIX.1e and NFSv4)])
++ else
++ AC_MSG_RESULT([Solaris (POSIX.1e)])
++ fi
++ elif test "x$ac_cv_archive_acl_freebsd" = "xyes"; then
++ AC_DEFINE([ARCHIVE_ACL_FREEBSD], [1], [FreeBSD ACL support])
++ if test "x$ac_cv_archive_acl_freebsd_nfs4" = "xyes"; then
++ AC_DEFINE([ARCHIVE_ACL_FREEBSD_NFS4], [1],
++ [FreeBSD NFSv4 ACL support])
++ AC_MSG_RESULT([FreeBSD (POSIX.1e and NFSv4)])
++ else
++ AC_MSG_RESULT([FreeBSD (POSIX.1e)])
++ fi
++ else
++ AC_MSG_RESULT([none])
++ fi
++fi
+
+- # MacOS has ACL_TYPE_EXTENDED instead
+- AC_CHECK_DECL([ACL_TYPE_EXTENDED],
+- [AC_DEFINE(HAVE_ACL_TYPE_EXTENDED, 1, [True for MacOS ACL support])],
+- [],
+- [#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)
+-fi
++AM_CONDITIONAL([INC_LINUX_ACL],
++ [test "x$ac_cv_archive_acl_libacl" = "xyes" \
++ -o "x$ac_cv_archive_acl_librichacl" = "xyes"])
++AM_CONDITIONAL([INC_SUNOS_ACL], [test "x$ac_cv_archive_acl_sunos" = "xyes"])
++AM_CONDITIONAL([INC_DARWIN_ACL],
++ [test "x$ac_cv_archive_acl_darwin" = "xyes"])
++AM_CONDITIONAL([INC_FREEBSD_ACL],
++ [test "x$ac_cv_archive_acl_freebsd" = "xyes"])
+
+ # Additional requirements
+ AC_SYS_LARGEFILE
+@@ -852,6 +995,16 @@ case "$host_os" in
+ ;;
+ 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])
+--- cpio/cpio.c.orig
++++ cpio/cpio.c
+@@ -108,22 +108,22 @@ static int entry_to_archive(struct cpio *, struct archive_entry *);
+ 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 @@ lookup_name(struct cpio *cpio, struct name_cache **name_cache_variable,
+ 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 @@ lookup_uname_helper(struct cpio *cpio, const char **name, id_t id)
+ 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 @@ lookup_gname_helper(struct cpio *cpio, const char **name, id_t id)
+ 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;
+ }
+
+ /*
+--- cpio/test/CMakeLists.txt.orig
++++ cpio/test/CMakeLists.txt
+@@ -62,6 +62,16 @@ IF(ENABLE_CPIO AND ENABLE_TEST)
+ # Register target
+ #
+ ADD_EXECUTABLE(bsdcpio_test ${bsdcpio_test_SOURCES})
++ IF(ENABLE_ACL)
++ SET(TEST_ACL_LIBS "")
++ IF(HAVE_LIBACL)
++ LIST(APPEND TEST_ACL_LIBS ${ACL_LIBRARY})
++ ENDIF(HAVE_LIBACL)
++ IF(HAVE_LIBRICHACL)
++ LIST(APPEND TEST_ACL_LIBS ${RICHACL_LIBRARY})
++ ENDIF(HAVE_LIBRICHACL)
++ TARGET_LINK_LIBRARIES(bsdcpio_test ${TEST_ACL_LIBS})
++ ENDIF(ENABLE_ACL)
+ SET_PROPERTY(TARGET bsdcpio_test PROPERTY COMPILE_DEFINITIONS LIST_H)
+
+ #
+--- libarchive/CMakeLists.txt.orig
++++ libarchive/CMakeLists.txt
+@@ -14,6 +14,7 @@ SET(include_HEADERS
+ # Sources and private headers
+ SET(libarchive_SOURCES
+ archive_acl.c
++ archive_acl_private.h
+ archive_check_magic.c
+ archive_cmdline.c
+ archive_cmdline_private.h
+@@ -47,6 +48,7 @@ SET(libarchive_SOURCES
+ archive_pathmatch.c
+ archive_pathmatch.h
+ archive_platform.h
++ archive_platform_acl.h
+ archive_ppmd_private.h
+ archive_ppmd7.c
+ archive_ppmd7_private.h
+@@ -106,9 +108,9 @@ SET(libarchive_SOURCES
+ 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
+ archive_write_disk_posix.c
+ archive_write_disk_private.h
+ archive_write_disk_set_standard_lookup.c
+@@ -210,6 +212,28 @@ IF(WIN32 AND NOT CYGWIN)
+ LIST(APPEND libarchive_SOURCES filter_fork_windows.c)
+ ENDIF(WIN32 AND NOT CYGWIN)
+
++IF(ARCHIVE_ACL_DARWIN)
++ LIST(APPEND libarchive_SOURCES archive_acl_maps.h)
++ LIST(APPEND libarchive_SOURCES archive_acl_maps_darwin.c)
++ LIST(APPEND libarchive_SOURCES archive_read_disk_acl_darwin.c)
++ LIST(APPEND libarchive_SOURCES archive_write_disk_acl_darwin.c)
++ELSEIF(ARCHIVE_ACL_FREEBSD)
++ LIST(APPEND libarchive_SOURCES archive_acl_maps.h)
++ LIST(APPEND libarchive_SOURCES archive_acl_maps_freebsd.c)
++ LIST(APPEND libarchive_SOURCES archive_read_disk_acl_freebsd.c)
++ LIST(APPEND libarchive_SOURCES archive_write_disk_acl_freebsd.c)
++ELSEIF(ARCHIVE_ACL_LIBACL)
++ LIST(APPEND libarchive_SOURCES archive_acl_maps.h)
++ LIST(APPEND libarchive_SOURCES archive_acl_maps_linux.c)
++ LIST(APPEND libarchive_SOURCES archive_read_disk_acl_linux.c)
++ LIST(APPEND libarchive_SOURCES archive_write_disk_acl_linux.c)
++ELSEIF(ARCHIVE_ACL_SUNOS)
++ LIST(APPEND libarchive_SOURCES archive_acl_maps.h)
++ LIST(APPEND libarchive_SOURCES archive_acl_maps_sunos.c)
++ LIST(APPEND libarchive_SOURCES archive_read_disk_acl_sunos.c)
++ LIST(APPEND libarchive_SOURCES archive_write_disk_acl_sunos.c)
++ENDIF()
++
+ # Libarchive is a shared library
+ ADD_LIBRARY(archive SHARED ${libarchive_SOURCES} ${include_HEADERS})
+ TARGET_LINK_LIBRARIES(archive ${ADDITIONAL_LIBS})
+--- libarchive/archive.h.orig
++++ 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 @@ __LA_DECL int archive_version_number(void);
+ /*
+ * Textual name/version of the library, useful for version displays.
+ */
+-#define ARCHIVE_VERSION_ONLY_STRING "3.3.1"
++#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);
+
+--- /dev/null
++++ libarchive/archive_acl_maps.h
+@@ -0,0 +1,52 @@
++/*-
++ * 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.
++ */
++
++#ifndef __LIBARCHIVE_BUILD
++#error This header is only to be used internally to libarchive.
++#endif
++
++#ifndef ARCHIVE_ACL_MAPS_H_INCLUDED
++#define ARCHIVE_ACL_MAPS_H_INCLUDED
++
++#include "archive_platform_acl.h"
++
++typedef struct {
++ const int a_perm; /* Libarchive permission or flag */
++ const int p_perm; /* Platform permission or flag */
++} acl_perm_map_t;
++
++#ifndef _ARCHIVE_ACL_MAPS_DEFS
++#if ARCHIVE_ACL_POSIX1E
++extern const acl_perm_map_t acl_posix_perm_map[];
++extern const int acl_posix_perm_map_size;
++#endif
++#if ARCHIVE_ACL_NFS4
++extern const acl_perm_map_t acl_nfs4_perm_map[];
++extern const int acl_nfs4_perm_map_size;
++extern const acl_perm_map_t acl_nfs4_flag_map[];
++extern const int acl_nfs4_flag_map_size;
++#endif
++#endif /* !_ARCHIVE_ACL_MAPS_DEFS */
++#endif /* ARCHIVE_ACL_MAPS_H_INCLUDED */
+--- /dev/null
++++ libarchive/archive_acl_maps_darwin.c
+@@ -0,0 +1,76 @@
++/*-
++ * 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 "archive_platform.h"
++
++#ifdef HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++#ifdef HAVE_SYS_ACL_H
++#define _ACL_PRIVATE /* For debugging */
++#include <sys/acl.h>
++#endif
++
++#include "archive_entry.h"
++#include "archive_private.h"
++#include "archive_read_disk_private.h"
++#define _ARCHIVE_ACL_MAPS_DEFS
++#include "archive_acl_maps.h"
++
++const acl_perm_map_t acl_nfs4_perm_map[] = {
++ {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
++ {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
++ {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
++ {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
++ {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
++ {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
++ {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
++ {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
++ {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
++ {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
++ {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
++ {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_EXTATTRIBUTES},
++ {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_EXTATTRIBUTES},
++ {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
++};
++
++const int acl_nfs4_perm_map_size =
++ (int)(sizeof(acl_nfs4_perm_map)/sizeof(acl_nfs4_perm_map[0]));
++
++const acl_perm_map_t acl_nfs4_flag_map[] = {
++ {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED},
++ {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
++ {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
++ {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_LIMIT_INHERIT},
++ {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_ONLY_INHERIT}
++};
++
++const int acl_nfs4_flag_map_size =
++ (int)(sizeof(acl_nfs4_flag_map)/sizeof(acl_nfs4_flag_map[0]));
+--- /dev/null
++++ libarchive/archive_acl_maps_freebsd.c
+@@ -0,0 +1,87 @@
++/*-
++ * 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 "archive_platform.h"
++
++#ifdef HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++#ifdef HAVE_SYS_ACL_H
++#define _ACL_PRIVATE /* For debugging */
++#include <sys/acl.h>
++#endif
++
++#include "archive_entry.h"
++#include "archive_private.h"
++#include "archive_read_disk_private.h"
++#define _ARCHIVE_ACL_MAPS_DEFS
++#include "archive_acl_maps.h"
++
++const acl_perm_map_t acl_posix_perm_map[] = {
++ {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
++ {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE},
++ {ARCHIVE_ENTRY_ACL_READ, ACL_READ},
++};
++
++const int acl_posix_perm_map_size =
++ (int)(sizeof(acl_posix_perm_map)/sizeof(acl_posix_perm_map[0]));
++
++#if ARCHIVE_ACL_FREEBSD_NFS4
++const acl_perm_map_t acl_nfs4_perm_map[] = {
++ {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
++ {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
++ {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
++ {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
++ {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
++ {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
++ {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
++ {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS},
++ {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS},
++ {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
++ {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
++ {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
++ {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
++ {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL},
++ {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL},
++ {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER},
++ {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
++};
++
++const int acl_nfs4_perm_map_size =
++ (int)(sizeof(acl_nfs4_perm_map)/sizeof(acl_nfs4_perm_map[0]));
++
++const acl_perm_map_t acl_nfs4_flag_map[] = {
++ {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
++ {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
++ {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT},
++ {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY},
++ {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}
++};
++
++const int acl_nfs4_flag_map_size =
++ (int)(sizeof(acl_nfs4_flag_map)/sizeof(acl_nfs4_flag_map[0]));
++#endif /* ARCHIVE_ACL_FREEBSD_NFS4 */
+--- /dev/null
++++ libarchive/archive_acl_maps_linux.c
+@@ -0,0 +1,90 @@
++/*-
++ * 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 "archive_platform.h"
++
++#ifdef HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++#ifdef HAVE_SYS_ACL_H
++#define _ACL_PRIVATE /* For debugging */
++#include <sys/acl.h>
++#endif
++#ifdef HAVE_SYS_RICHACL_H
++#include <sys/richacl.h>
++#endif
++
++#include "archive_entry.h"
++#include "archive_private.h"
++#include "archive_read_disk_private.h"
++#define _ARCHIVE_ACL_MAPS_DEFS
++#include "archive_acl_maps.h"
++
++#if ARCHIVE_ACL_LIBACL
++const acl_perm_map_t acl_posix_perm_map[] = {
++ {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
++ {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE},
++ {ARCHIVE_ENTRY_ACL_READ, ACL_READ},
++};
++
++const int acl_posix_perm_map_size =
++ (int)(sizeof(acl_posix_perm_map)/sizeof(acl_posix_perm_map[0]));
++#endif /* ARCHIVE_ACL_LIBACL */
++
++#if ARCHIVE_ACL_LIBRICHACL
++const acl_perm_map_t acl_nfs4_perm_map[] = {
++ {ARCHIVE_ENTRY_ACL_EXECUTE, RICHACE_EXECUTE},
++ {ARCHIVE_ENTRY_ACL_READ_DATA, RICHACE_READ_DATA},
++ {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, RICHACE_LIST_DIRECTORY},
++ {ARCHIVE_ENTRY_ACL_WRITE_DATA, RICHACE_WRITE_DATA},
++ {ARCHIVE_ENTRY_ACL_ADD_FILE, RICHACE_ADD_FILE},
++ {ARCHIVE_ENTRY_ACL_APPEND_DATA, RICHACE_APPEND_DATA},
++ {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, RICHACE_ADD_SUBDIRECTORY},
++ {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, RICHACE_READ_NAMED_ATTRS},
++ {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, RICHACE_WRITE_NAMED_ATTRS},
++ {ARCHIVE_ENTRY_ACL_DELETE_CHILD, RICHACE_DELETE_CHILD},
++ {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, RICHACE_READ_ATTRIBUTES},
++ {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, RICHACE_WRITE_ATTRIBUTES},
++ {ARCHIVE_ENTRY_ACL_DELETE, RICHACE_DELETE},
++ {ARCHIVE_ENTRY_ACL_READ_ACL, RICHACE_READ_ACL},
++ {ARCHIVE_ENTRY_ACL_WRITE_ACL, RICHACE_WRITE_ACL},
++ {ARCHIVE_ENTRY_ACL_WRITE_OWNER, RICHACE_WRITE_OWNER},
++ {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, RICHACE_SYNCHRONIZE}
++};
++
++const int acl_nfs4_perm_map_size =
++ (int)(sizeof(acl_nfs4_perm_map)/sizeof(acl_nfs4_perm_map[0]));
++
++const acl_perm_map_t acl_nfs4_flag_map[] = {
++ {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, RICHACE_FILE_INHERIT_ACE},
++ {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, RICHACE_DIRECTORY_INHERIT_ACE},
++ {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, RICHACE_NO_PROPAGATE_INHERIT_ACE},
++ {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, RICHACE_INHERIT_ONLY_ACE},
++ {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, RICHACE_INHERITED_ACE}
++};
++
++const int acl_nfs4_flag_map_size =
++ (int)(sizeof(acl_nfs4_flag_map)/sizeof(acl_nfs4_flag_map[0]));
++#endif /* ARCHIVE_ACL_LIBRICHACL */
+--- /dev/null
++++ libarchive/archive_acl_maps_sunos.c
+@@ -0,0 +1,90 @@
++/*-
++ * 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 "archive_platform.h"
++
++#ifdef HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++#ifdef HAVE_SYS_ACL_H
++#define _ACL_PRIVATE /* For debugging */
++#include <sys/acl.h>
++#endif
++
++#include "archive_entry.h"
++#include "archive_private.h"
++#include "archive_read_disk_private.h"
++#define _ARCHIVE_ACL_MAPS_DEFS
++#include "archive_acl_maps.h"
++
++const acl_perm_map_t acl_posix_perm_map[] = {
++ {ARCHIVE_ENTRY_ACL_EXECUTE, S_IXOTH },
++ {ARCHIVE_ENTRY_ACL_WRITE, S_IWOTH },
++ {ARCHIVE_ENTRY_ACL_READ, S_IROTH }
++};
++
++const int acl_posix_perm_map_size =
++ (int)(sizeof(acl_posix_perm_map)/sizeof(acl_posix_perm_map[0]));
++
++#if ARCHIVE_ACL_SUNOS_NFS4
++const acl_perm_map_t acl_nfs4_perm_map[] = {
++ {ARCHIVE_ENTRY_ACL_EXECUTE, ACE_EXECUTE},
++ {ARCHIVE_ENTRY_ACL_READ_DATA, ACE_READ_DATA},
++ {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACE_LIST_DIRECTORY},
++ {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACE_WRITE_DATA},
++ {ARCHIVE_ENTRY_ACL_ADD_FILE, ACE_ADD_FILE},
++ {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACE_APPEND_DATA},
++ {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACE_ADD_SUBDIRECTORY},
++ {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACE_READ_NAMED_ATTRS},
++ {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACE_WRITE_NAMED_ATTRS},
++ {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACE_DELETE_CHILD},
++ {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACE_READ_ATTRIBUTES},
++ {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACE_WRITE_ATTRIBUTES},
++ {ARCHIVE_ENTRY_ACL_DELETE, ACE_DELETE},
++ {ARCHIVE_ENTRY_ACL_READ_ACL, ACE_READ_ACL},
++ {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACE_WRITE_ACL},
++ {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACE_WRITE_OWNER},
++ {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACE_SYNCHRONIZE}
++};
++
++const int acl_nfs4_perm_map_size =
++ (int)(sizeof(acl_nfs4_perm_map)/sizeof(acl_nfs4_perm_map[0]));
++
++const acl_perm_map_t acl_nfs4_flag_map[] = {
++ {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
++};
++
++const int acl_nfs4_flag_map_size =
++ (int)(sizeof(acl_nfs4_flag_map)/sizeof(acl_nfs4_flag_map[0]));
++
++#endif /* ARCHIVE_ACL_SUNOS_NFS4 */
+--- libarchive/archive_check_magic.c.orig
++++ libarchive/archive_check_magic.c
+@@ -62,7 +62,7 @@ errmsg(const char *m)
+ }
+ }
+
+-static void
++static __LA_DEAD void
+ diediedie(void)
+ {
+ #if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG)
+--- libarchive/archive_entry.3.orig
++++ libarchive/archive_entry.3
+@@ -25,7 +25,7 @@
+ .\"
+ .\" $FreeBSD$
+ .\"
+-.Dd Feburary 2, 2012
++.Dd February 2, 2012
+ .Dt ARCHIVE_ENTRY 3
+ .Os
+ .Sh NAME
+--- libarchive/archive_entry.c.orig
++++ libarchive/archive_entry.c
+@@ -401,7 +401,7 @@ archive_entry_fflags_text(struct archive_entry *entry)
+ return (NULL);
+ }
+
+-int64_t
++la_int64_t
+ archive_entry_gid(struct archive_entry *entry)
+ {
+ return (entry->ae_stat.aest_gid);
+@@ -502,7 +502,7 @@ _archive_entry_hardlink_l(struct archive_entry *entry,
+ 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 @@ archive_entry_ino_is_set(struct archive_entry *entry)
+ 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 @@ archive_entry_rdevminor(struct archive_entry *entry)
+ 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 @@ _archive_entry_symlink_l(struct archive_entry *entry,
+ 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 @@ archive_entry_copy_fflags_text_w(struct archive_entry *entry,
+ }
+
+ 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 @@ _archive_entry_copy_gname_l(struct archive_entry *entry,
+ }
+
+ 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 @@ archive_entry_set_ino(struct archive_entry *entry, int64_t ino)
+ }
+
+ 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 @@ archive_entry_set_rdevminor(struct archive_entry *entry, dev_t m)
+ }
+
+ 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 @@ _archive_entry_copy_symlink_l(struct archive_entry *entry,
+ }
+
+ 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;
+--- libarchive/archive_entry.h.orig
++++ 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
+--- libarchive/archive_entry_acl.3.orig
++++ 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 @@ Only inherit, do not apply the permission on the directory itself.
+ .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 @@ and
+ .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 POSIX.1e ACLs and
+ 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 @@ and
+ .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
+--- libarchive/archive_entry_paths.3.orig
++++ 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)
+--- libarchive/archive_entry_perms.3.orig
++++ 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 ,
+--- libarchive/archive_platform.h.orig
++++ libarchive/archive_platform.h
+@@ -143,32 +143,6 @@
+ #endif
+
+ /*
+- * If this platform has <sys/acl.h>, acl_create(), acl_init(),
+- * acl_set_file(), and ACL_USER, we assume it has the rest of the
+- * POSIX.1e draft functions used in archive_read_extract.c.
+- */
+-#if HAVE_SYS_ACL_H && HAVE_ACL_CREATE_ENTRY && HAVE_ACL_INIT && HAVE_ACL_SET_FILE
+-#if HAVE_ACL_USER
+-#define HAVE_POSIX_ACL 1
+-#elif HAVE_ACL_TYPE_EXTENDED
+-#define HAVE_DARWIN_ACL 1
+-#endif
+-#endif
+-
+-/*
+- * If this platform has <sys/acl.h>, acl_get(), facl_get(), acl_set(),
+- * facl_set() and types aclent_t and ace_t it uses Solaris-style ACL functions
+- */
+-#if HAVE_SYS_ACL_H && HAVE_ACL_GET && HAVE_FACL_GET && HAVE_ACL_SET && HAVE_FACL_SET && HAVE_ACLENT_T && HAVE_ACE_T
+-#define HAVE_SUN_ACL 1
+-#endif
+-
+-/* Define if platform supports NFSv4 ACLs */
+-#if (HAVE_POSIX_ACL && HAVE_ACL_TYPE_NFS4) || HAVE_SUN_ACL || HAVE_DARWIN_ACL
+-#define HAVE_NFS4_ACL 1
+-#endif
+-
+-/*
+ * If we can't restore metadata using a file descriptor, then
+ * for compatibility's sake, close files before trying to restore metadata.
+ */
+--- /dev/null
++++ libarchive/archive_platform_acl.h
+@@ -0,0 +1,49 @@
++/*-
++ * 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.
++ *
++ * $FreeBSD$
++ */
++
++/* !!ONLY FOR USE INTERNALLY TO LIBARCHIVE!! */
++
++#ifndef ARCHIVE_PLATFORM_ACL_H_INCLUDED
++#define ARCHIVE_PLATFORM_ACL_H_INCLUDED
++
++/*
++ * Determine what ACL types are supported
++ */
++#if ARCHIVE_ACL_FREEBSD || ARCHIVE_ACL_SUNOS || ARCHIVE_ACL_LIBACL
++#define ARCHIVE_ACL_POSIX1E 1
++#endif
++
++#if ARCHIVE_ACL_FREEBSD_NFS4 || ARCHIVE_ACL_SUNOS_NFS4 || \
++ ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_LIBRICHACL
++#define ARCHIVE_ACL_NFS4 1
++#endif
++
++#if ARCHIVE_ACL_POSIX1E || ARCHIVE_ACL_NFS4
++#define ARCHIVE_ACL_SUPPORT 1
++#endif
++
++#endif /* ARCHIVE_PLATFORM_ACL_H_INCLUDED */
+--- libarchive/archive_read_disk.3.orig
++++ 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 @@ Streaming Archive Library (libarchive, -larchive)
+ .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 @@ using the currently registered lookup functions above.
+ 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
+--- /dev/null
++++ libarchive/archive_read_disk_acl_darwin.c
+@@ -0,0 +1,337 @@
++/*-
++ * 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 "archive_platform.h"
++
++#ifdef HAVE_FCNTL_H
++#include <fcntl.h>
++#endif
++#if HAVE_ERRNO_H
++#include <errno.h>
++#endif
++#if HAVE_MEMBERSHIP_H
++#include <membership.h>
++#endif
++#ifdef HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++#ifdef HAVE_SYS_ACL_H
++#define _ACL_PRIVATE /* For debugging */
++#include <sys/acl.h>
++#endif
++
++#include "archive_entry.h"
++#include "archive_private.h"
++#include "archive_read_disk_private.h"
++#include "archive_acl_maps.h"
++
++
++/*
++ * Darwin-specific ACL functions and helper functions
++ *
++ * Exported functions:
++ * none
++ */
++static int translate_guid(struct archive *a, acl_entry_t acl_entry,
++ int *ae_id, int *ae_tag, const char **ae_name)
++{
++ void *q;
++ uid_t ugid;
++ int r, idtype;
++
++ q = acl_get_qualifier(acl_entry);
++ if (q == NULL)
++ return (1);
++ r = mbr_uuid_to_id((const unsigned char *)q, &ugid, &idtype);
++ if (r != 0) {
++ acl_free(q);
++ return (1);
++ }
++ if (idtype == ID_TYPE_UID) {
++ *ae_tag = ARCHIVE_ENTRY_ACL_USER;
++ *ae_id = ugid;
++ *ae_name = archive_read_disk_uname(a, *ae_id);
++ } else if (idtype == ID_TYPE_GID) {
++ *ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
++ *ae_id = ugid;
++ *ae_name = archive_read_disk_gname(a, *ae_id);
++ } else
++ r = 1;
++
++ acl_free(q);
++ return (r);
++}
++
++/*
++ * Add trivial NFSv4 ACL entries from mode
++ */
++static void
++add_trivial_nfs4_acl(struct archive_entry *entry)
++{
++ mode_t mode;
++ int i;
++ const int rperm = ARCHIVE_ENTRY_ACL_READ_DATA;
++ const int wperm = ARCHIVE_ENTRY_ACL_WRITE_DATA |
++ ARCHIVE_ENTRY_ACL_APPEND_DATA;
++ const int eperm = ARCHIVE_ENTRY_ACL_EXECUTE;
++ const int pubset = ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
++ ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
++ ARCHIVE_ENTRY_ACL_READ_ACL |
++ ARCHIVE_ENTRY_ACL_SYNCHRONIZE;
++ const int ownset = pubset | ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES |
++ ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS |
++ ARCHIVE_ENTRY_ACL_WRITE_ACL |
++ ARCHIVE_ENTRY_ACL_WRITE_OWNER;
++
++ struct {
++ const int type;
++ const int tag;
++ int permset;
++ } tacl_entry[] = {
++ {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_USER_OBJ, 0},
++ {ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_USER_OBJ, 0},
++ {ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_GROUP_OBJ, 0},
++ {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_USER_OBJ, ownset},
++ {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_GROUP_OBJ, pubset},
++ {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EVERYONE, pubset}
++ };
++
++ mode = archive_entry_mode(entry);
++
++ /* Permissions for everyone@ */
++ if (mode & 0004)
++ tacl_entry[5].permset |= rperm;
++ if (mode & 0002)
++ tacl_entry[5].permset |= wperm;
++ if (mode & 0001)
++ tacl_entry[5].permset |= eperm;
++
++ /* Permissions for group@ */
++ if (mode & 0040)
++ tacl_entry[4].permset |= rperm;
++ else if (mode & 0004)
++ tacl_entry[2].permset |= rperm;
++ if (mode & 0020)
++ tacl_entry[4].permset |= wperm;
++ else if (mode & 0002)
++ tacl_entry[2].permset |= wperm;
++ if (mode & 0010)
++ tacl_entry[4].permset |= eperm;
++ else if (mode & 0001)
++ tacl_entry[2].permset |= eperm;
++
++ /* Permissions for owner@ */
++ if (mode & 0400) {
++ tacl_entry[3].permset |= rperm;
++ if (!(mode & 0040) && (mode & 0004))
++ tacl_entry[0].permset |= rperm;
++ } else if ((mode & 0040) || (mode & 0004))
++ tacl_entry[1].permset |= rperm;
++ if (mode & 0200) {
++ tacl_entry[3].permset |= wperm;
++ if (!(mode & 0020) && (mode & 0002))
++ tacl_entry[0].permset |= wperm;
++ } else if ((mode & 0020) || (mode & 0002))
++ tacl_entry[1].permset |= wperm;
++ if (mode & 0100) {
++ tacl_entry[3].permset |= eperm;
++ if (!(mode & 0010) && (mode & 0001))
++ tacl_entry[0].permset |= eperm;
++ } else if ((mode & 0010) || (mode & 0001))
++ tacl_entry[1].permset |= eperm;
++
++ for (i = 0; i < 6; i++) {
++ if (tacl_entry[i].permset != 0) {
++ archive_entry_acl_add_entry(entry,
++ tacl_entry[i].type, tacl_entry[i].permset,
++ tacl_entry[i].tag, -1, NULL);
++ }
++ }
++
++ return;
++}
++
++static int
++translate_acl(struct archive_read_disk *a,
++ struct archive_entry *entry, acl_t acl)
++{
++ acl_tag_t acl_tag;
++ acl_flagset_t acl_flagset;
++ acl_entry_t acl_entry;
++ acl_permset_t acl_permset;
++ int i, entry_acl_type;
++ int r, s, ae_id, ae_tag, ae_perm;
++ const char *ae_name;
++
++ s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry);
++ if (s == -1) {
++ archive_set_error(&a->archive, errno,
++ "Failed to get first ACL entry");
++ return (ARCHIVE_WARN);
++ }
++
++ while (s == 0) {
++ ae_id = -1;
++ ae_name = NULL;
++ ae_perm = 0;
++
++ if (acl_get_tag_type(acl_entry, &acl_tag) != 0) {
++ archive_set_error(&a->archive, errno,
++ "Failed to get ACL tag type");
++ return (ARCHIVE_WARN);
++ }
++ switch (acl_tag) {
++ case ACL_EXTENDED_ALLOW:
++ entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
++ r = translate_guid(&a->archive, acl_entry,
++ &ae_id, &ae_tag, &ae_name);
++ break;
++ case ACL_EXTENDED_DENY:
++ entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
++ r = translate_guid(&a->archive, acl_entry,
++ &ae_id, &ae_tag, &ae_name);
++ break;
++ default:
++ /* Skip types that libarchive can't support. */
++ s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
++ continue;
++ }
++
++ /* Skip if translate_guid() above failed */
++ if (r != 0) {
++ s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
++ continue;
++ }
++
++ /*
++ * Libarchive stores "flag" (NFSv4 inheritance bits)
++ * in the ae_perm bitmap.
++ *
++ * acl_get_flagset_np() fails with non-NFSv4 ACLs
++ */
++ if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) {
++ archive_set_error(&a->archive, errno,
++ "Failed to get flagset from a NFSv4 ACL entry");
++ return (ARCHIVE_WARN);
++ }
++ for (i = 0; i < acl_nfs4_flag_map_size; ++i) {
++ r = acl_get_flag_np(acl_flagset,
++ acl_nfs4_flag_map[i].p_perm);
++ if (r == -1) {
++ archive_set_error(&a->archive, errno,
++ "Failed to check flag in a NFSv4 "
++ "ACL flagset");
++ return (ARCHIVE_WARN);
++ } else if (r)
++ ae_perm |= acl_nfs4_flag_map[i].a_perm;
++ }
++
++ if (acl_get_permset(acl_entry, &acl_permset) != 0) {
++ archive_set_error(&a->archive, errno,
++ "Failed to get ACL permission set");
++ return (ARCHIVE_WARN);
++ }
++
++ for (i = 0; i < acl_nfs4_perm_map_size; ++i) {
++ /*
++ * acl_get_perm() is spelled differently on different
++ * platforms; see above.
++ */
++ r = acl_get_perm_np(acl_permset,
++ acl_nfs4_perm_map[i].p_perm);
++ if (r == -1) {
++ archive_set_error(&a->archive, errno,
++ "Failed to check permission in an ACL "
++ "permission set");
++ return (ARCHIVE_WARN);
++ } else if (r)
++ ae_perm |= acl_nfs4_perm_map[i].a_perm;
++ }
++
++#if !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);
++
++ s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
++ }
++ return (ARCHIVE_OK);
++}
++
++int
++archive_read_disk_entry_setup_acls(struct archive_read_disk *a,
++ struct archive_entry *entry, int *fd)
++{
++ const char *accpath;
++ acl_t acl;
++ int r;
++
++ accpath = NULL;
++
++ if (*fd < 0) {
++ accpath = archive_read_disk_entry_setup_path(a, entry, fd);
++ if (accpath == NULL)
++ return (ARCHIVE_WARN);
++ }
++
++ archive_entry_acl_clear(entry);
++
++ acl = NULL;
++
++ if (*fd >= 0)
++ acl = acl_get_fd_np(*fd, ACL_TYPE_EXTENDED);
++ else if (!a->follow_symlinks)
++ acl = acl_get_link_np(accpath, ACL_TYPE_EXTENDED);
++ else
++ acl = acl_get_file(accpath, ACL_TYPE_EXTENDED);
++
++ if (acl != NULL) {
++ r = translate_acl(a, entry, acl);
++ acl_free(acl);
++ acl = NULL;
++
++ if (r != ARCHIVE_OK) {
++ archive_set_error(&a->archive, errno,
++ "Couldn't translate NFSv4 ACLs");
++ }
++
++ /*
++ * Because Mac OS doesn't support owner@, group@ and everyone@
++ * ACLs we need to add NFSv4 ACLs mirroring the file mode to
++ * the archive entry. Otherwise extraction on non-Mac platforms
++ * would lead to an invalid file mode.
++ */
++ if ((archive_entry_acl_types(entry) &
++ ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0)
++ add_trivial_nfs4_acl(entry);
++
++ return (r);
++ }
++ return (ARCHIVE_OK);
++}
+--- /dev/null
++++ libarchive/archive_read_disk_acl_freebsd.c
+@@ -0,0 +1,371 @@
++/*-
++ * Copyright (c) 2003-2009 Tim Kientzle
++ * Copyright (c) 2010-2012 Michihiro NAKAJIMA
++ * Copyright (c) 2016-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 "archive_platform.h"
++
++#ifdef HAVE_ERRNO_H
++#include <errno.h>
++#endif
++#ifdef HAVE_FCNTL_H
++#include <fcntl.h>
++#endif
++#ifdef HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++#ifdef HAVE_SYS_ACL_H
++#define _ACL_PRIVATE /* For debugging */
++#include <sys/acl.h>
++#endif
++
++#include "archive_entry.h"
++#include "archive_private.h"
++#include "archive_read_disk_private.h"
++#include "archive_acl_maps.h"
++
++/*
++ * Translate FreeBSD ACLs into libarchive internal structure
++ */
++static int
++translate_acl(struct archive_read_disk *a,
++ struct archive_entry *entry, acl_t acl, int default_entry_acl_type)
++{
++#if ARCHIVE_ACL_FREEBSD_NFS4
++ int brand;
++ acl_flagset_t acl_flagset;
++#endif
++ acl_tag_t acl_tag;
++ acl_entry_t acl_entry;
++ acl_permset_t acl_permset;
++ acl_entry_type_t acl_type;
++ int i, entry_acl_type, perm_map_size;
++ const acl_perm_map_t *perm_map;
++ int r, s, ae_id, ae_tag, ae_perm;
++ void *q;
++ const char *ae_name;
++
++#if ARCHIVE_ACL_FREEBSD_NFS4
++ // 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.
++ if (acl_get_brand_np(acl, &brand) != 0) {
++ archive_set_error(&a->archive, errno,
++ "Failed to read ACL brand");
++ return (ARCHIVE_WARN);
++ }
++ switch (brand) {
++ case ACL_BRAND_POSIX:
++ switch (default_entry_acl_type) {
++ case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
++ case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
++ break;
++ default:
++ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
++ "Invalid ACL entry type for POSIX.1e ACL");
++ return (ARCHIVE_WARN);
++ }
++ break;
++ case ACL_BRAND_NFS4:
++ if (default_entry_acl_type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
++ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
++ "Invalid ACL entry type for NFSv4 ACL");
++ return (ARCHIVE_WARN);
++ }
++ break;
++ default:
++ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
++ "Unknown ACL brand");
++ return (ARCHIVE_WARN);
++ }
++#endif
++
++ s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry);
++ if (s == -1) {
++ archive_set_error(&a->archive, errno,
++ "Failed to get first ACL entry");
++ return (ARCHIVE_WARN);
++ }
++
++ while (s == 1) {
++ ae_id = -1;
++ ae_name = NULL;
++ ae_perm = 0;
++
++ if (acl_get_tag_type(acl_entry, &acl_tag) != 0) {
++ archive_set_error(&a->archive, errno,
++ "Failed to get ACL tag type");
++ return (ARCHIVE_WARN);
++ }
++ switch (acl_tag) {
++ case ACL_USER:
++ q = acl_get_qualifier(acl_entry);
++ if (q != NULL) {
++ ae_id = (int)*(uid_t *)q;
++ acl_free(q);
++ ae_name = archive_read_disk_uname(&a->archive,
++ ae_id);
++ }
++ ae_tag = ARCHIVE_ENTRY_ACL_USER;
++ break;
++ case ACL_GROUP:
++ q = acl_get_qualifier(acl_entry);
++ if (q != NULL) {
++ ae_id = (int)*(gid_t *)q;
++ acl_free(q);
++ ae_name = archive_read_disk_gname(&a->archive,
++ ae_id);
++ }
++ ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
++ break;
++ case ACL_MASK:
++ ae_tag = ARCHIVE_ENTRY_ACL_MASK;
++ break;
++ case ACL_USER_OBJ:
++ ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
++ break;
++ case ACL_GROUP_OBJ:
++ ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
++ break;
++ case ACL_OTHER:
++ ae_tag = ARCHIVE_ENTRY_ACL_OTHER;
++ break;
++#if ARCHIVE_ACL_FREEBSD_NFS4
++ case ACL_EVERYONE:
++ ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE;
++ break;
++#endif
++ default:
++ /* Skip types that libarchive can't support. */
++ s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
++ continue;
++ }
++
++ // XXX acl_type maps to allow/deny/audit/YYYY bits
++ entry_acl_type = default_entry_acl_type;
++
++#if ARCHIVE_ACL_FREEBSD_NFS4
++ if (default_entry_acl_type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
++ /*
++ * acl_get_entry_type_np() fails with non-NFSv4 ACLs
++ */
++ if (acl_get_entry_type_np(acl_entry, &acl_type) != 0) {
++ archive_set_error(&a->archive, errno, "Failed "
++ "to get ACL type from a NFSv4 ACL entry");
++ return (ARCHIVE_WARN);
++ }
++ switch (acl_type) {
++ case ACL_ENTRY_TYPE_ALLOW:
++ entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
++ break;
++ case ACL_ENTRY_TYPE_DENY:
++ entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
++ break;
++ case ACL_ENTRY_TYPE_AUDIT:
++ entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT;
++ break;
++ case ACL_ENTRY_TYPE_ALARM:
++ entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
++ break;
++ default:
++ archive_set_error(&a->archive, errno,
++ "Invalid NFSv4 ACL entry type");
++ return (ARCHIVE_WARN);
++ }
++
++ /*
++ * Libarchive stores "flag" (NFSv4 inheritance bits)
++ * in the ae_perm bitmap.
++ *
++ * acl_get_flagset_np() fails with non-NFSv4 ACLs
++ */
++ if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) {
++ archive_set_error(&a->archive, errno,
++ "Failed to get flagset from a NFSv4 "
++ "ACL entry");
++ return (ARCHIVE_WARN);
++ }
++ for (i = 0; i < acl_nfs4_flag_map_size; ++i) {
++ r = acl_get_flag_np(acl_flagset,
++ acl_nfs4_flag_map[i].p_perm);
++ if (r == -1) {
++ archive_set_error(&a->archive, errno,
++ "Failed to check flag in a NFSv4 "
++ "ACL flagset");
++ return (ARCHIVE_WARN);
++ } else if (r)
++ ae_perm |= acl_nfs4_flag_map[i].a_perm;
++ }
++ }
++#endif
++
++ if (acl_get_permset(acl_entry, &acl_permset) != 0) {
++ archive_set_error(&a->archive, errno,
++ "Failed to get ACL permission set");
++ return (ARCHIVE_WARN);
++ }
++
++#if ARCHIVE_ACL_FREEBSD_NFS4
++ if (default_entry_acl_type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
++ perm_map_size = acl_nfs4_perm_map_size;
++ perm_map = acl_nfs4_perm_map;
++ } else {
++#endif
++ perm_map_size = acl_posix_perm_map_size;
++ perm_map = acl_posix_perm_map;
++#if ARCHIVE_ACL_FREEBSD_NFS4
++ }
++#endif
++
++ for (i = 0; i < perm_map_size; ++i) {
++ r = acl_get_perm_np(acl_permset, perm_map[i].p_perm);
++ if (r == -1) {
++ archive_set_error(&a->archive, errno,
++ "Failed to check permission in an ACL "
++ "permission set");
++ return (ARCHIVE_WARN);
++ } else if (r)
++ ae_perm |= perm_map[i].a_perm;
++ }
++
++ archive_entry_acl_add_entry(entry, entry_acl_type,
++ ae_perm, ae_tag,
++ ae_id, ae_name);
++
++ s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
++ if (s == -1) {
++ archive_set_error(&a->archive, errno,
++ "Failed to get next ACL entry");
++ return (ARCHIVE_WARN);
++ }
++ }
++ return (ARCHIVE_OK);
++}
++
++int
++archive_read_disk_entry_setup_acls(struct archive_read_disk *a,
++ struct archive_entry *entry, int *fd)
++{
++ const char *accpath;
++ acl_t acl;
++ int r;
++
++ accpath = NULL;
++
++ if (*fd < 0) {
++ accpath = archive_read_disk_entry_setup_path(a, entry, fd);
++ if (accpath == NULL)
++ return (ARCHIVE_WARN);
++ }
++
++ archive_entry_acl_clear(entry);
++
++ acl = NULL;
++
++#if ARCHIVE_ACL_FREEBSD_NFS4
++ /* Try NFSv4 ACL first. */
++ if (*fd >= 0)
++ acl = acl_get_fd_np(*fd, ACL_TYPE_NFS4);
++ else if (!a->follow_symlinks)
++ acl = acl_get_link_np(accpath, ACL_TYPE_NFS4);
++ else
++ acl = acl_get_file(accpath, ACL_TYPE_NFS4);
++
++ /* Ignore "trivial" ACLs that just mirror the file mode. */
++ if (acl != NULL && acl_is_trivial_np(acl, &r) == 0 && r == 1) {
++ acl_free(acl);
++ acl = NULL;
++ return (ARCHIVE_OK);
++ }
++
++ if (acl != NULL) {
++ r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4);
++ acl_free(acl);
++ acl = NULL;
++
++ if (r != ARCHIVE_OK) {
++ archive_set_error(&a->archive, errno,
++ "Couldn't translate NFSv4 ACLs");
++ }
++
++ return (r);
++ }
++#endif
++
++ /* Retrieve access ACL from file. */
++ if (*fd >= 0)
++ acl = acl_get_fd_np(*fd, ACL_TYPE_ACCESS);
++#if HAVE_ACL_GET_LINK_NP
++ else if (!a->follow_symlinks)
++ acl = acl_get_link_np(accpath, ACL_TYPE_ACCESS);
++#else
++ else if ((!a->follow_symlinks)
++ && (archive_entry_filetype(entry) == AE_IFLNK))
++ /* We can't get the ACL of a symlink, so we assume it can't
++ have one. */
++ acl = NULL;
++#endif
++ else
++ acl = acl_get_file(accpath, ACL_TYPE_ACCESS);
++
++#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 && r == 1) {
++ acl_free(acl);
++ acl = NULL;
++ }
++#endif
++
++ if (acl != NULL) {
++ r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
++ acl_free(acl);
++ acl = NULL;
++
++ if (r != ARCHIVE_OK) {
++ archive_set_error(&a->archive, errno,
++ "Couldn't translate access ACLs");
++ return (r);
++ }
++ }
++
++ /* Only directories can have default ACLs. */
++ if (S_ISDIR(archive_entry_mode(entry))) {
++ if (*fd >= 0)
++ acl = acl_get_fd_np(*fd, ACL_TYPE_DEFAULT);
++ else
++ acl = acl_get_file(accpath, ACL_TYPE_DEFAULT);
++ if (acl != NULL) {
++ r = translate_acl(a, entry, acl,
++ ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
++ acl_free(acl);
++ if (r != ARCHIVE_OK) {
++ archive_set_error(&a->archive, errno,
++ "Couldn't translate default ACLs");
++ return (r);
++ }
++ }
++ }
++ return (ARCHIVE_OK);
++}
+--- /dev/null
++++ libarchive/archive_read_disk_acl_linux.c
+@@ -0,0 +1,352 @@
++/*-
++ * Copyright (c) 2003-2009 Tim Kientzle
++ * Copyright (c) 2010-2012 Michihiro NAKAJIMA
++ * Copyright (c) 2016-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 "archive_platform.h"
++
++#ifdef HAVE_ERRNO_H
++#include <errno.h>
++#endif
++#ifdef HAVE_FCNTL_H
++#include <fcntl.h>
++#endif
++#if HAVE_ACL_LIBACL_H
++#include <acl/libacl.h>
++#endif
++#ifdef HAVE_SYS_ACL_H
++#include <sys/acl.h>
++#endif
++#if HAVE_SYS_RICHACL_H
++#include <sys/richacl.h>
++#endif
++
++#include "archive_entry.h"
++#include "archive_private.h"
++#include "archive_read_disk_private.h"
++#include "archive_acl_maps.h"
++
++#if HAVE_LIBACL
++#include <acl/libacl.h>
++#endif
++
++#if ARCHIVE_ACL_LIBACL
++/*
++ * Translate POSIX.1e ACLs into libarchive internal structure
++ */
++static int
++translate_acl(struct archive_read_disk *a,
++ struct archive_entry *entry, acl_t acl, int default_entry_acl_type)
++{
++ acl_tag_t acl_tag;
++ acl_entry_t acl_entry;
++ acl_permset_t acl_permset;
++ int i, entry_acl_type;
++ int r, s, ae_id, ae_tag, ae_perm;
++ void *q;
++ const char *ae_name;
++
++ s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry);
++ if (s == -1) {
++ archive_set_error(&a->archive, errno,
++ "Failed to get first ACL entry");
++ return (ARCHIVE_WARN);
++ }
++
++ while (s == 1) {
++ ae_id = -1;
++ ae_name = NULL;
++ ae_perm = 0;
++
++ if (acl_get_tag_type(acl_entry, &acl_tag) != 0) {
++ archive_set_error(&a->archive, errno,
++ "Failed to get ACL tag type");
++ return (ARCHIVE_WARN);
++ }
++ switch (acl_tag) {
++ case ACL_USER:
++ q = acl_get_qualifier(acl_entry);
++ if (q != NULL) {
++ ae_id = (int)*(uid_t *)q;
++ acl_free(q);
++ ae_name = archive_read_disk_uname(&a->archive,
++ ae_id);
++ }
++ ae_tag = ARCHIVE_ENTRY_ACL_USER;
++ break;
++ case ACL_GROUP:
++ q = acl_get_qualifier(acl_entry);
++ if (q != NULL) {
++ ae_id = (int)*(gid_t *)q;
++ acl_free(q);
++ ae_name = archive_read_disk_gname(&a->archive,
++ ae_id);
++ }
++ ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
++ break;
++ case ACL_MASK:
++ ae_tag = ARCHIVE_ENTRY_ACL_MASK;
++ break;
++ case ACL_USER_OBJ:
++ ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
++ break;
++ case ACL_GROUP_OBJ:
++ ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
++ break;
++ case ACL_OTHER:
++ ae_tag = ARCHIVE_ENTRY_ACL_OTHER;
++ break;
++ default:
++ /* Skip types that libarchive can't support. */
++ s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
++ continue;
++ }
++
++ // XXX acl_type maps to allow/deny/audit/YYYY bits
++ entry_acl_type = default_entry_acl_type;
++
++ if (acl_get_permset(acl_entry, &acl_permset) != 0) {
++ archive_set_error(&a->archive, errno,
++ "Failed to get ACL permission set");
++ return (ARCHIVE_WARN);
++ }
++
++ for (i = 0; i < acl_posix_perm_map_size; ++i) {
++ r = acl_get_perm(acl_permset,
++ acl_posix_perm_map[i].p_perm);
++ if (r == -1) {
++ archive_set_error(&a->archive, errno,
++ "Failed to check permission in an ACL "
++ "permission set");
++ return (ARCHIVE_WARN);
++ } else if (r)
++ ae_perm |= acl_posix_perm_map[i].a_perm;
++ }
++
++ archive_entry_acl_add_entry(entry, entry_acl_type,
++ ae_perm, ae_tag,
++ ae_id, ae_name);
++
++ s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
++ if (s == -1) {
++ archive_set_error(&a->archive, errno,
++ "Failed to get next ACL entry");
++ return (ARCHIVE_WARN);
++ }
++ }
++ return (ARCHIVE_OK);
++}
++#endif /* ARCHIVE_ACL_LIBACL */
++
++#if ARCHIVE_ACL_LIBRICHACL
++/*
++ * Translate RichACL into libarchive internal ACL
++ */
++static int
++translate_richacl(struct archive_read_disk *a, struct archive_entry *entry,
++ struct richacl *richacl)
++{
++ int ae_id, ae_tag, ae_perm;
++ int entry_acl_type, i;
++ const char *ae_name;
++
++ struct richace *richace;
++
++ richacl_for_each_entry(richace, richacl) {
++ ae_name = NULL;
++ ae_tag = 0;
++ ae_perm = 0;
++ ae_id = -1;
++
++ switch (richace->e_type) {
++ case RICHACE_ACCESS_ALLOWED_ACE_TYPE:
++ entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
++ break;
++ case RICHACE_ACCESS_DENIED_ACE_TYPE:
++ entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
++ break;
++ default: /* Unknown entry type, skip */
++ continue;
++ }
++
++ /* Unsupported */
++ if (richace->e_flags & RICHACE_UNMAPPED_WHO)
++ continue;
++
++ if (richace->e_flags & RICHACE_SPECIAL_WHO) {
++ switch (richace->e_id) {
++ case RICHACE_OWNER_SPECIAL_ID:
++ ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
++ break;
++ case RICHACE_GROUP_SPECIAL_ID:
++ ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
++ break;
++ case RICHACE_EVERYONE_SPECIAL_ID:
++ ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE;
++ break;
++ default: /* Unknown special ID type */
++ continue;
++ }
++ } else {
++ ae_id = richace->e_id;
++ if (richace->e_flags & RICHACE_IDENTIFIER_GROUP) {
++ ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
++ ae_name = archive_read_disk_gname(&a->archive,
++ (gid_t)(richace->e_id));
++ } else {
++ ae_tag = ARCHIVE_ENTRY_ACL_USER;
++ ae_name = archive_read_disk_uname(&a->archive,
++ (uid_t)(richace->e_id));
++ }
++ }
++ for (i = 0; i < acl_nfs4_flag_map_size; ++i) {
++ if ((richace->e_flags &
++ acl_nfs4_flag_map[i].p_perm) != 0)
++ ae_perm |= acl_nfs4_flag_map[i].a_perm;
++ }
++ for (i = 0; i < acl_nfs4_perm_map_size; ++i) {
++ if ((richace->e_mask &
++ acl_nfs4_perm_map[i].p_perm) != 0)
++ ae_perm |=
++ acl_nfs4_perm_map[i].a_perm;
++ }
++
++ archive_entry_acl_add_entry(entry, entry_acl_type,
++ ae_perm, ae_tag, ae_id, ae_name);
++ }
++ return (ARCHIVE_OK);
++}
++#endif /* ARCHIVE_ACL_LIBRICHACL */
++
++int
++archive_read_disk_entry_setup_acls(struct archive_read_disk *a,
++ struct archive_entry *entry, int *fd)
++{
++ const char *accpath;
++ int r;
++#if ARCHIVE_ACL_LIBACL
++ acl_t acl;
++#endif
++#if ARCHIVE_ACL_LIBRICHACL
++ struct richacl *richacl;
++ mode_t mode;
++#endif
++
++ accpath = NULL;
++ r = ARCHIVE_OK;
++
++ /* For default ACLs we need reachable accpath */
++ if (*fd < 0 || S_ISDIR(archive_entry_mode(entry))) {
++ accpath = archive_read_disk_entry_setup_path(a, entry, fd);
++ if (accpath == NULL)
++ return (ARCHIVE_WARN);
++ }
++
++ archive_entry_acl_clear(entry);
++
++#if ARCHIVE_ACL_LIBACL
++ acl = NULL;
++#endif
++#if ARCHIVE_ACL_LIBRICHACL
++ richacl = NULL;
++#endif
++
++#if ARCHIVE_ACL_LIBRICHACL
++ /* Try NFSv4 ACL first. */
++ if (*fd >= 0)
++ richacl = richacl_get_fd(*fd);
++ else if ((!a->follow_symlinks)
++ && (archive_entry_filetype(entry) == AE_IFLNK))
++ /* We can't get the ACL of a symlink, so we assume it can't
++ have one */
++ richacl = NULL;
++ else
++ richacl = richacl_get_file(accpath);
++
++ /* Ignore "trivial" ACLs that just mirror the file mode. */
++ if (richacl != NULL) {
++ mode = archive_entry_mode(entry);
++ if (richacl_equiv_mode(richacl, &mode) == 0) {
++ richacl_free(richacl);
++ richacl = NULL;
++ return (ARCHIVE_OK);
++ }
++ }
++
++ if (richacl != NULL) {
++ r = translate_richacl(a, entry, richacl);
++ richacl_free(richacl);
++ richacl = NULL;
++
++ if (r != ARCHIVE_OK) {
++ archive_set_error(&a->archive, errno,
++ "Couldn't translate NFSv4 ACLs");
++ }
++
++ return (r);
++ }
++#endif /* ARCHIVE_ACL_LIBRICHACL */
++
++#if ARCHIVE_ACL_LIBACL
++ /* Retrieve access ACL from file. */
++ if (*fd >= 0)
++ acl = acl_get_fd(*fd);
++ else if ((!a->follow_symlinks)
++ && (archive_entry_filetype(entry) == AE_IFLNK))
++ /* We can't get the ACL of a symlink, so we assume it can't
++ have one. */
++ acl = NULL;
++ else
++ acl = acl_get_file(accpath, ACL_TYPE_ACCESS);
++
++ if (acl != NULL) {
++ r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
++ acl_free(acl);
++ acl = NULL;
++
++ if (r != ARCHIVE_OK) {
++ archive_set_error(&a->archive, errno,
++ "Couldn't translate access ACLs");
++ return (r);
++ }
++ }
++
++ /* Only directories can have default ACLs. */
++ if (S_ISDIR(archive_entry_mode(entry))) {
++ acl = acl_get_file(accpath, ACL_TYPE_DEFAULT);
++ if (acl != NULL) {
++ r = translate_acl(a, entry, acl,
++ ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
++ acl_free(acl);
++ if (r != ARCHIVE_OK) {
++ archive_set_error(&a->archive, errno,
++ "Couldn't translate default ACLs");
++ return (r);
++ }
++ }
++ }
++#endif /* ARCHIVE_ACL_LIBACL */
++ return (r);
++}
+--- /dev/null
++++ libarchive/archive_read_disk_acl_sunos.c
+@@ -0,0 +1,482 @@
++/*-
++ * 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 "archive_platform.h"
++
++#ifdef HAVE_ERRNO_H
++#include <errno.h>
++#endif
++#ifdef HAVE_FCNTL_H
++#include <fcntl.h>
++#endif
++#ifdef HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++#ifdef HAVE_SYS_ACL_H
++#include <sys/acl.h>
++#endif
++
++#include "archive_entry.h"
++#include "archive_private.h"
++#include "archive_read_disk_private.h"
++#include "archive_acl_maps.h"
++
++/*
++ * Solaris-specific ACL functions and helper functions
++ *
++ * Exported functions:
++ * translate_acl()
++ */
++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 ARCHIVE_ACL_SUNOS_NFS4
++ 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);
++}
++
++/*
++ * Check if acl is trivial
++ * This is a FreeBSD acl_is_trivial_np() implementation for Solaris
++ */
++static int
++sun_acl_is_trivial(void *aclp, int aclcnt, mode_t mode, int is_nfs4,
++ int is_dir, int *trivialp)
++{
++#if ARCHIVE_ACL_SUNOS_NFS4
++ int i, p;
++ const uint32_t rperm = ACE_READ_DATA;
++ const uint32_t wperm = ACE_WRITE_DATA | ACE_APPEND_DATA;
++ const uint32_t eperm = ACE_EXECUTE;
++ const uint32_t pubset = ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS |
++ ACE_READ_ACL | ACE_SYNCHRONIZE;
++ const uint32_t ownset = pubset | ACE_WRITE_ATTRIBUTES |
++ ACE_WRITE_NAMED_ATTRS | ACE_WRITE_ACL | ACE_WRITE_OWNER;
++
++ ace_t *ace;
++ ace_t tace[6];
++#endif
++
++ if (aclp == NULL || trivialp == NULL)
++ return (-1);
++
++ *trivialp = 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 (!is_nfs4) {
++ if (aclcnt == 4)
++ *trivialp = 1;
++ return (0);
++ }
++
++#if ARCHIVE_ACL_SUNOS_NFS4
++ /*
++ * Continue with checking NFSv4 ACLs
++ *
++ * Create list of trivial ace's to be compared
++ */
++
++ /* owner@ allow pre */
++ tace[0].a_flags = ACE_OWNER;
++ tace[0].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
++ tace[0].a_access_mask = 0;
++
++ /* owner@ deny */
++ tace[1].a_flags = ACE_OWNER;
++ tace[1].a_type = ACE_ACCESS_DENIED_ACE_TYPE;
++ tace[1].a_access_mask = 0;
++
++ /* group@ deny */
++ tace[2].a_flags = ACE_GROUP | ACE_IDENTIFIER_GROUP;
++ tace[2].a_type = ACE_ACCESS_DENIED_ACE_TYPE;
++ tace[2].a_access_mask = 0;
++
++ /* owner@ allow */
++ tace[3].a_flags = ACE_OWNER;
++ tace[3].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
++ tace[3].a_access_mask = ownset;
++
++ /* group@ allow */
++ tace[4].a_flags = ACE_GROUP | ACE_IDENTIFIER_GROUP;
++ tace[4].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
++ tace[4].a_access_mask = pubset;
++
++ /* everyone@ allow */
++ tace[5].a_flags = ACE_EVERYONE;
++ tace[5].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
++ tace[5].a_access_mask = pubset;
++
++ /* Permissions for everyone@ */
++ if (mode & 0004)
++ tace[5].a_access_mask |= rperm;
++ if (mode & 0002)
++ tace[5].a_access_mask |= wperm;
++ if (mode & 0001)
++ tace[5].a_access_mask |= eperm;
++
++ /* Permissions for group@ */
++ if (mode & 0040)
++ tace[4].a_access_mask |= rperm;
++ else if (mode & 0004)
++ tace[2].a_access_mask |= rperm;
++ if (mode & 0020)
++ tace[4].a_access_mask |= wperm;
++ else if (mode & 0002)
++ tace[2].a_access_mask |= wperm;
++ if (mode & 0010)
++ tace[4].a_access_mask |= eperm;
++ else if (mode & 0001)
++ tace[2].a_access_mask |= eperm;
++
++ /* Permissions for owner@ */
++ if (mode & 0400) {
++ tace[3].a_access_mask |= rperm;
++ if (!(mode & 0040) && (mode & 0004))
++ tace[0].a_access_mask |= rperm;
++ } else if ((mode & 0040) || (mode & 0004))
++ tace[1].a_access_mask |= rperm;
++ if (mode & 0200) {
++ tace[3].a_access_mask |= wperm;
++ if (!(mode & 0020) && (mode & 0002))
++ tace[0].a_access_mask |= wperm;
++ } else if ((mode & 0020) || (mode & 0002))
++ tace[1].a_access_mask |= wperm;
++ if (mode & 0100) {
++ tace[3].a_access_mask |= eperm;
++ if (!(mode & 0010) && (mode & 0001))
++ tace[0].a_access_mask |= eperm;
++ } else if ((mode & 0010) || (mode & 0001))
++ tace[1].a_access_mask |= eperm;
++
++ /* Check if the acl count matches */
++ p = 3;
++ for (i = 0; i < 3; i++) {
++ if (tace[i].a_access_mask != 0)
++ p++;
++ }
++ if (aclcnt != p)
++ return (0);
++
++ p = 0;
++ for (i = 0; i < 6; i++) {
++ if (tace[i].a_access_mask != 0) {
++ ace = &((ace_t *)aclp)[p];
++ /*
++ * Illumos added ACE_DELETE_CHILD to write perms for
++ * directories. We have to check against that, too.
++ */
++ if (ace->a_flags != tace[i].a_flags ||
++ ace->a_type != tace[i].a_type ||
++ (ace->a_access_mask != tace[i].a_access_mask &&
++ (!is_dir || (tace[i].a_access_mask & wperm) == 0 ||
++ ace->a_access_mask !=
++ (tace[i].a_access_mask | ACE_DELETE_CHILD))))
++ return (0);
++ p++;
++ }
++ }
++
++ *trivialp = 1;
++#else /* !ARCHIVE_ACL_SUNOS_NFS4 */
++ (void)is_dir; /* UNUSED */
++ (void)aclp; /* UNUSED */
++#endif /* !ARCHIVE_ACL_SUNOS_NFS4 */
++ return (0);
++}
++
++/*
++ * Translate Solaris POSIX.1e and NFSv4 ACLs into libarchive internal ACL
++ */
++static int
++translate_acl(struct archive_read_disk *a,
++ 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 ARCHIVE_ACL_SUNOS_NFS4
++ ace_t *ace;
++#endif
++
++ if (aclcnt <= 0)
++ return (ARCHIVE_OK);
++
++ for (e = 0; e < aclcnt; e++) {
++ ae_name = NULL;
++ ae_tag = 0;
++ ae_perm = 0;
++
++#if ARCHIVE_ACL_SUNOS_NFS4
++ if (default_entry_acl_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
++ ace = &((ace_t *)aclp)[e];
++ ae_id = ace->a_who;
++
++ switch(ace->a_type) {
++ case ACE_ACCESS_ALLOWED_ACE_TYPE:
++ entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
++ break;
++ case ACE_ACCESS_DENIED_ACE_TYPE:
++ entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
++ break;
++ case ACE_SYSTEM_AUDIT_ACE_TYPE:
++ entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
++ break;
++ case ACE_SYSTEM_ALARM_ACE_TYPE:
++ entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
++ break;
++ default:
++ /* Unknown entry type, skip */
++ continue;
++ }
++
++ if ((ace->a_flags & ACE_OWNER) != 0)
++ ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
++ else if ((ace->a_flags & ACE_GROUP) != 0)
++ ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
++ else if ((ace->a_flags & ACE_EVERYONE) != 0)
++ ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE;
++ else if ((ace->a_flags & ACE_IDENTIFIER_GROUP) != 0) {
++ ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
++ ae_name = archive_read_disk_gname(&a->archive,
++ ae_id);
++ } else {
++ ae_tag = ARCHIVE_ENTRY_ACL_USER;
++ ae_name = archive_read_disk_uname(&a->archive,
++ ae_id);
++ }
++
++ for (i = 0; i < acl_nfs4_flag_map_size; ++i) {
++ if ((ace->a_flags &
++ acl_nfs4_flag_map[i].p_perm) != 0)
++ ae_perm |= acl_nfs4_flag_map[i].a_perm;
++ }
++
++ for (i = 0; i < acl_nfs4_perm_map_size; ++i) {
++ if ((ace->a_access_mask &
++ acl_nfs4_perm_map[i].p_perm) != 0)
++ ae_perm |= acl_nfs4_perm_map[i].a_perm;
++ }
++ } else
++#endif /* ARCHIVE_ACL_SUNOS_NFS4 */
++ 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
++ entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
++ ae_id = aclent->a_id;
++
++ switch(aclent->a_type) {
++ case DEF_USER:
++ case USER:
++ ae_name = archive_read_disk_uname(&a->archive,
++ ae_id);
++ ae_tag = ARCHIVE_ENTRY_ACL_USER;
++ break;
++ case DEF_GROUP:
++ case GROUP:
++ ae_name = archive_read_disk_gname(&a->archive,
++ ae_id);
++ ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
++ break;
++ case DEF_CLASS_OBJ:
++ case CLASS_OBJ:
++ ae_tag = ARCHIVE_ENTRY_ACL_MASK;
++ break;
++ case DEF_USER_OBJ:
++ case USER_OBJ:
++ ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
++ break;
++ case DEF_GROUP_OBJ:
++ case GROUP_OBJ:
++ ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
++ break;
++ case DEF_OTHER_OBJ:
++ case OTHER_OBJ:
++ ae_tag = ARCHIVE_ENTRY_ACL_OTHER;
++ break;
++ default:
++ /* Unknown tag type, skip */
++ continue;
++ }
++
++ for (i = 0; i < acl_posix_perm_map_size; ++i) {
++ if ((aclent->a_perm &
++ acl_posix_perm_map[i].p_perm) != 0)
++ ae_perm |= acl_posix_perm_map[i].a_perm;
++ }
++ } else
++ return (ARCHIVE_WARN);
++
++ archive_entry_acl_add_entry(entry, entry_acl_type,
++ ae_perm, ae_tag, ae_id, ae_name);
++ }
++ return (ARCHIVE_OK);
++}
++
++int
++archive_read_disk_entry_setup_acls(struct archive_read_disk *a,
++ struct archive_entry *entry, int *fd)
++{
++ const char *accpath;
++ void *aclp;
++ int aclcnt;
++ int r;
++
++ accpath = NULL;
++
++ if (*fd < 0) {
++ accpath = archive_read_disk_entry_setup_path(a, entry, fd);
++ if (accpath == NULL)
++ return (ARCHIVE_WARN);
++ }
++
++ archive_entry_acl_clear(entry);
++
++ aclp = NULL;
++
++#if ARCHIVE_ACL_SUNOS_NFS4
++ if (*fd >= 0)
++ aclp = sunacl_get(ACE_GETACL, &aclcnt, *fd, NULL);
++ else if ((!a->follow_symlinks)
++ && (archive_entry_filetype(entry) == AE_IFLNK))
++ /* We can't get the ACL of a symlink, so we assume it can't
++ have one. */
++ aclp = NULL;
++ else
++ aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, accpath);
++
++ 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);
++ }
++
++ if (aclp != NULL) {
++ r = translate_acl(a, entry, aclp, aclcnt,
++ ARCHIVE_ENTRY_ACL_TYPE_NFS4);
++ free(aclp);
++ aclp = NULL;
++
++ if (r != ARCHIVE_OK) {
++ archive_set_error(&a->archive, errno,
++ "Couldn't translate NFSv4 ACLs");
++ }
++ return (r);
++ }
++#endif /* ARCHIVE_ACL_SUNOS_NFS4 */
++
++ /* Retrieve POSIX.1e ACLs from file. */
++ if (*fd >= 0)
++ aclp = sunacl_get(GETACL, &aclcnt, *fd, NULL);
++ else if ((!a->follow_symlinks)
++ && (archive_entry_filetype(entry) == AE_IFLNK))
++ /* We can't get the ACL of a symlink, so we assume it can't
++ have one. */
++ aclp = NULL;
++ else
++ aclp = sunacl_get(GETACL, &aclcnt, 0, accpath);
++
++ /* Ignore "trivial" ACLs that just mirror the file mode. */
++ 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;
++ }
++
++ if (aclp != NULL)
++ {
++ r = translate_acl(a, entry, aclp, aclcnt,
++ ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
++ free(aclp);
++ aclp = NULL;
++
++ if (r != ARCHIVE_OK) {
++ archive_set_error(&a->archive, errno,
++ "Couldn't translate access ACLs");
++ return (r);
++ }
++ }
++
++ return (ARCHIVE_OK);
++}
+--- libarchive/archive_read_disk_entry_from_file.c.orig
++++ libarchive/archive_read_disk_entry_from_file.c
+@@ -26,23 +26,14 @@
+ */
+
+ #include "archive_platform.h"
+-__FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 201084 2009-12-28 02:14:09Z kientzle $");
++__FBSDID("$FreeBSD");
+
+ /* This is the tree-walking code for POSIX systems. */
+ #if !defined(_WIN32) || defined(__CYGWIN__)
+
+ #ifdef HAVE_SYS_TYPES_H
+-/* Mac OSX requires sys/types.h before sys/acl.h. */
+ #include <sys/types.h>
+ #endif
+-#ifdef HAVE_SYS_ACL_H
+-#include <sys/acl.h>
+-#endif
+-#ifdef HAVE_DARWIN_ACL
+-#include <membership.h>
+-#include <grp.h>
+-#include <pwd.h>
+-#endif
+ #ifdef HAVE_SYS_EXTATTR_H
+ #include <sys/extattr.h>
+ #endif
+@@ -63,9 +54,6 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 2010
+ #ifdef HAVE_SYS_EA_H
+ #include <sys/ea.h>
+ #endif
+-#ifdef HAVE_ACL_LIBACL_H
+-#include <acl/libacl.h>
+-#endif
+ #ifdef HAVE_COPYFILE_H
+ #include <copyfile.h>
+ #endif
+@@ -113,27 +101,6 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 2010
+ #define O_CLOEXEC 0
+ #endif
+
+-/*
+- * Linux and FreeBSD plug this obvious hole in POSIX.1e in
+- * different ways.
+- */
+-#if HAVE_ACL_GET_PERM
+-#define ACL_GET_PERM acl_get_perm
+-#elif HAVE_ACL_GET_PERM_NP
+-#define ACL_GET_PERM acl_get_perm_np
+-#endif
+-
+-/* NFSv4 platform ACL type */
+-#if HAVE_SUN_ACL
+-#define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACE_T
+-#elif HAVE_DARWIN_ACL
+-#define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACL_TYPE_EXTENDED
+-#elif HAVE_ACL_TYPE_NFS4
+-#define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACL_TYPE_NFS4
+-#endif
+-
+-static int setup_acls(struct archive_read_disk *,
+- struct archive_entry *, int *fd);
+ static int setup_mac_metadata(struct archive_read_disk *,
+ struct archive_entry *, int *fd);
+ static int setup_xattrs(struct archive_read_disk *,
+@@ -145,6 +112,45 @@ static int setup_sparse_fiemap(struct archive_read_disk *,
+ struct archive_entry *, int *fd);
+ #endif
+
++#if !ARCHIVE_ACL_SUPPORT
++int
++archive_read_disk_entry_setup_acls(struct archive_read_disk *a,
++ struct archive_entry *entry, int *fd)
++{
++ (void)a; /* UNUSED */
++ (void)entry; /* UNUSED */
++ (void)fd; /* UNUSED */
++ return (ARCHIVE_OK);
++}
++#endif
++
++/*
++ * Enter working directory and return working pathname of archive_entry.
++ * If a pointer to an integer is provided and its value is below zero
++ * open a file descriptor on this pahtname.
++ */
++const char *
++archive_read_disk_entry_setup_path(struct archive_read_disk *a,
++ struct archive_entry *entry, int *fd)
++{
++ const char *path;
++
++ path = archive_entry_sourcepath(entry);
++
++ if (path == NULL || (a->tree != NULL &&
++ a->tree_enter_working_dir(a->tree) != 0))
++ path = archive_entry_pathname(entry);
++ if (path == NULL) {
++ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
++ "Couldn't determine path");
++ } else if (fd != NULL && *fd < 0 && a->tree != NULL &&
++ (a->follow_symlinks || archive_entry_filetype(entry) != AE_IFLNK)) {
++ *fd = a->open_on_current_dir(a->tree, path,
++ O_RDONLY | O_NONBLOCK);
++ }
++ return (path);
++}
++
+ int
+ archive_read_disk_entry_from_file(struct archive *_a,
+ struct archive_entry *entry,
+@@ -279,7 +285,7 @@ archive_read_disk_entry_from_file(struct archive *_a,
+
+ r = 0;
+ if ((a->flags & ARCHIVE_READDISK_NO_ACL) == 0)
+- r = setup_acls(a, entry, &fd);
++ r = archive_read_disk_entry_setup_acls(a, entry, &fd);
+ if ((a->flags & ARCHIVE_READDISK_NO_XATTR) == 0) {
+ r1 = setup_xattrs(a, entry, &fd);
+ if (r1 < r)
+@@ -328,19 +334,10 @@ setup_mac_metadata(struct archive_read_disk *a,
+ struct archive_string tempfile;
+
+ (void)fd; /* UNUSED */
+- name = archive_entry_sourcepath(entry);
++
++ name = archive_read_disk_entry_setup_path(a, entry, NULL);
+ if (name == NULL)
+- name = archive_entry_pathname(entry);
+- else if (a->tree != NULL && a->tree_enter_working_dir(a->tree) != 0) {
+- archive_set_error(&a->archive, errno,
+- "Can't change dir to read extended attributes");
+- return (ARCHIVE_FAILED);
+- }
+- if (name == NULL) {
+- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+- "Can't open file to read extended attributes: No name");
+ return (ARCHIVE_WARN);
+- }
+
+ /* Short-circuit if there's nothing to do. */
+ have_attrs = copyfile(name, NULL, 0, copyfile_flags | COPYFILE_CHECK);
+@@ -426,990 +423,6 @@ setup_mac_metadata(struct archive_read_disk *a,
+ }
+ #endif
+
+-#if HAVE_DARWIN_ACL
+-static int translate_guid(struct archive *, acl_entry_t,
+- int *, int *, const char **);
+-
+-static void add_trivial_nfs4_acl(struct archive_entry *);
+-#endif
+-
+-#if HAVE_SUN_ACL
+-static int
+-sun_acl_is_trivial(acl_t *, mode_t, int *trivialp);
+-#endif
+-
+-#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,
+-#else
+- acl_t acl,
+-#endif
+- int archive_entry_acl_type);
+-
+-static int
+-setup_acls(struct archive_read_disk *a,
+- struct archive_entry *entry, int *fd)
+-{
+- const char *accpath;
+-#if HAVE_SUN_ACL
+- acl_t *acl;
+-#else
+- acl_t acl;
+-#endif
+- int r;
+-
+- accpath = NULL;
+-
+-#if HAVE_SUN_ACL || HAVE_DARWIN_ACL || HAVE_ACL_GET_FD_NP
+- if (*fd < 0)
+-#else
+- /* For default ACLs on Linux we need reachable accpath */
+- if (*fd < 0 || S_ISDIR(archive_entry_mode(entry)))
+-#endif
+- {
+- accpath = archive_entry_sourcepath(entry);
+- if (accpath == NULL || (a->tree != NULL &&
+- a->tree_enter_working_dir(a->tree) != 0))
+- accpath = archive_entry_pathname(entry);
+- if (accpath == NULL) {
+- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+- "Couldn't determine file path to read ACLs");
+- return (ARCHIVE_WARN);
+- }
+- if (a->tree != NULL &&
+-#if !HAVE_SUN_ACL && !HAVE_DARWIN_ACL && !HAVE_ACL_GET_FD_NP
+- *fd < 0 &&
+-#endif
+- (a->follow_symlinks ||
+- archive_entry_filetype(entry) != AE_IFLNK)) {
+- *fd = a->open_on_current_dir(a->tree,
+- accpath, O_RDONLY | O_NONBLOCK);
+- }
+- }
+-
+- archive_entry_acl_clear(entry);
+-
+- acl = NULL;
+-
+-#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);
+-#elif HAVE_ACL_GET_FD_NP
+- acl = acl_get_fd_np(*fd, ARCHIVE_PLATFORM_ACL_TYPE_NFS4);
+-#else
+- acl = acl_get_fd(*fd);
+-#endif
+-#if HAVE_ACL_GET_LINK_NP
+- else if (!a->follow_symlinks)
+- acl = acl_get_link_np(accpath, ARCHIVE_PLATFORM_ACL_TYPE_NFS4);
+-#else
+- else if ((!a->follow_symlinks)
+- && (archive_entry_filetype(entry) == AE_IFLNK))
+- /* We can't get the ACL of a symlink, so we assume it can't
+- have one. */
+- acl = NULL;
+-#endif
+- else
+-#if HAVE_SUN_ACL
+- /* Solaris reads both POSIX.1e and NFSv4 ACLs here */
+- acl_get(accpath, 0, &acl);
+-#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);
+- }
+- }
+-#endif /* HAVE_ACL_IS_TRIVIAL_NP || HAVE_SUN_ACL */
+- if (acl != NULL) {
+- r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4);
+- acl_free(acl);
+- if (r != ARCHIVE_OK) {
+- archive_set_error(&a->archive, errno,
+- "Couldn't translate "
+-#if !HAVE_SUN_ACL
+- "NFSv4 "
+-#endif
+- "ACLs");
+- }
+-#if HAVE_DARWIN_ACL
+- /*
+- * Because Mac OS doesn't support owner@, group@ and everyone@
+- * ACLs we need to add NFSv4 ACLs mirroring the file mode to
+- * the archive entry. Otherwise extraction on non-Mac platforms
+- * would lead to an invalid file mode.
+- */
+- if ((archive_entry_acl_types(entry) &
+- ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0)
+- add_trivial_nfs4_acl(entry);
+-#endif
+- return (r);
+- }
+-#endif /* HAVE_NFS4_ACL */
+-
+-#if HAVE_POSIX_ACL
+- /* This code path is skipped on MacOS and Solaris */
+-
+- /* Retrieve access ACL from file. */
+- if (*fd >= 0)
+- acl = acl_get_fd(*fd);
+-#if HAVE_ACL_GET_LINK_NP
+- else if (!a->follow_symlinks)
+- acl = acl_get_link_np(accpath, ACL_TYPE_ACCESS);
+-#else
+- else if ((!a->follow_symlinks)
+- && (archive_entry_filetype(entry) == AE_IFLNK))
+- /* We can't get the ACL of a symlink, so we assume it can't
+- have one. */
+- acl = NULL;
+-#endif
+- else
+- acl = acl_get_file(accpath, ACL_TYPE_ACCESS);
+-
+-#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;
+- }
+- }
+-#endif
+-
+- if (acl != NULL) {
+- r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
+- acl_free(acl);
+- acl = NULL;
+- if (r != ARCHIVE_OK) {
+- archive_set_error(&a->archive, errno,
+- "Couldn't translate access ACLs");
+- return (r);
+- }
+- }
+-
+- /* Only directories can have default ACLs. */
+- if (S_ISDIR(archive_entry_mode(entry))) {
+-#if HAVE_ACL_GET_FD_NP
+- if (*fd >= 0)
+- acl = acl_get_fd_np(*fd, ACL_TYPE_DEFAULT);
+- else
+-#endif
+- acl = acl_get_file(accpath, ACL_TYPE_DEFAULT);
+- if (acl != NULL) {
+- r = translate_acl(a, entry, acl,
+- ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
+- acl_free(acl);
+- if (r != ARCHIVE_OK) {
+- archive_set_error(&a->archive, errno,
+- "Couldn't translate default ACLs");
+- return (r);
+- }
+- }
+- }
+-#endif /* HAVE_POSIX_ACL */
+- return (ARCHIVE_OK);
+-}
+-
+-/*
+- * Translate system ACL permissions into libarchive internal structure
+- */
+-static const struct {
+- const int archive_perm;
+- const int platform_perm;
+-} acl_perm_map[] = {
+-#if HAVE_SUN_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},
+- {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACE_WRITE_DATA},
+- {ARCHIVE_ENTRY_ACL_ADD_FILE, ACE_ADD_FILE},
+- {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACE_APPEND_DATA},
+- {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACE_ADD_SUBDIRECTORY},
+- {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACE_READ_NAMED_ATTRS},
+- {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACE_WRITE_NAMED_ATTRS},
+- {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACE_DELETE_CHILD},
+- {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACE_READ_ATTRIBUTES},
+- {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACE_WRITE_ATTRIBUTES},
+- {ARCHIVE_ENTRY_ACL_DELETE, ACE_DELETE},
+- {ARCHIVE_ENTRY_ACL_READ_ACL, ACE_READ_ACL},
+- {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACE_WRITE_ACL},
+- {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACE_WRITE_OWNER},
+- {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACE_SYNCHRONIZE}
+-#elif HAVE_DARWIN_ACL /* MacOS 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},
+- {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
+- {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
+- {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
+- {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
+- {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
+- {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
+- {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
+- {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
+- {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_EXTATTRIBUTES},
+- {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_EXTATTRIBUTES},
+- {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_SECURITY},
+- {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_SECURITY},
+- {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_CHANGE_OWNER},
+- {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
+-#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 */
+- {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
+- {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
+- {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
+- {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
+- {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
+- {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
+- {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS},
+- {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS},
+- {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
+- {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
+- {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
+- {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
+- {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL},
+- {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL},
+- {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER},
+- {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
+-#endif
+-#endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
+-};
+-
+-#if HAVE_NFS4_ACL
+-/*
+- * Translate system NFSv4 inheritance flags into libarchive internal structure
+- */
+-static const struct {
+- const int archive_inherit;
+- const int platform_inherit;
+-} acl_inherit_map[] = {
+-#if HAVE_SUN_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},
+- {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACE_INHERITED_ACE}
+-#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},
+- {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
+- {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_LIMIT_INHERIT},
+- {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_ONLY_INHERIT}
+-#else /* FreeBSD NFSv4 ACL inheritance flags */
+- {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
+- {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
+- {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT},
+- {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY},
+- {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_NFS4_ACL */
+-
+-#if HAVE_DARWIN_ACL
+-static int translate_guid(struct archive *a, acl_entry_t acl_entry,
+- int *ae_id, int *ae_tag, const char **ae_name)
+-{
+- void *q;
+- uid_t ugid;
+- int r, idtype;
+- struct passwd *pwd;
+- struct group *grp;
+-
+- q = acl_get_qualifier(acl_entry);
+- if (q == NULL)
+- return (1);
+- r = mbr_uuid_to_id((const unsigned char *)q, &ugid, &idtype);
+- if (r != 0) {
+- acl_free(q);
+- return (1);
+- }
+- 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);
+- }
+- } 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);
+- }
+- } else
+- r = 1;
+-
+- acl_free(q);
+- return (r);
+-}
+-
+-/*
+- * Add trivial NFSv4 ACL entries from mode
+- */
+-static void
+-add_trivial_nfs4_acl(struct archive_entry *entry)
+-{
+- mode_t mode;
+- int i;
+- const int rperm = ARCHIVE_ENTRY_ACL_READ_DATA;
+- const int wperm = ARCHIVE_ENTRY_ACL_WRITE_DATA |
+- ARCHIVE_ENTRY_ACL_APPEND_DATA;
+- const int eperm = ARCHIVE_ENTRY_ACL_EXECUTE;
+- const int pubset = ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
+- ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
+- ARCHIVE_ENTRY_ACL_READ_ACL |
+- ARCHIVE_ENTRY_ACL_SYNCHRONIZE;
+- const int ownset = pubset | ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES |
+- ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS |
+- ARCHIVE_ENTRY_ACL_WRITE_ACL |
+- ARCHIVE_ENTRY_ACL_WRITE_OWNER;
+-
+- struct {
+- const int type;
+- const int tag;
+- int permset;
+- } tacl_entry[] = {
+- {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_USER_OBJ, 0},
+- {ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_USER_OBJ, 0},
+- {ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_GROUP_OBJ, 0},
+- {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_USER_OBJ, ownset},
+- {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_GROUP_OBJ, pubset},
+- {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EVERYONE, pubset}
+- };
+-
+- mode = archive_entry_mode(entry);
+-
+- /* Permissions for everyone@ */
+- if (mode & 0004)
+- tacl_entry[5].permset |= rperm;
+- if (mode & 0002)
+- tacl_entry[5].permset |= wperm;
+- if (mode & 0001)
+- tacl_entry[5].permset |= eperm;
+-
+- /* Permissions for group@ */
+- if (mode & 0040)
+- tacl_entry[4].permset |= rperm;
+- else if (mode & 0004)
+- tacl_entry[2].permset |= rperm;
+- if (mode & 0020)
+- tacl_entry[4].permset |= wperm;
+- else if (mode & 0002)
+- tacl_entry[2].permset |= wperm;
+- if (mode & 0010)
+- tacl_entry[4].permset |= eperm;
+- else if (mode & 0001)
+- tacl_entry[2].permset |= eperm;
+-
+- /* Permissions for owner@ */
+- if (mode & 0400) {
+- tacl_entry[3].permset |= rperm;
+- if (!(mode & 0040) && (mode & 0004))
+- tacl_entry[0].permset |= rperm;
+- } else if ((mode & 0040) || (mode & 0004))
+- tacl_entry[1].permset |= rperm;
+- if (mode & 0200) {
+- tacl_entry[3].permset |= wperm;
+- if (!(mode & 0020) && (mode & 0002))
+- tacl_entry[0].permset |= wperm;
+- } else if ((mode & 0020) || (mode & 0002))
+- tacl_entry[1].permset |= wperm;
+- if (mode & 0100) {
+- tacl_entry[3].permset |= eperm;
+- if (!(mode & 0010) && (mode & 0001))
+- tacl_entry[0].permset |= eperm;
+- } else if ((mode & 0010) || (mode & 0001))
+- tacl_entry[1].permset |= eperm;
+-
+- for (i = 0; i < 6; i++) {
+- if (tacl_entry[i].permset != 0) {
+- archive_entry_acl_add_entry(entry,
+- tacl_entry[i].type, tacl_entry[i].permset,
+- tacl_entry[i].tag, -1, NULL);
+- }
+- }
+-
+- return;
+-}
+-#elif HAVE_SUN_ACL
+-/*
+- * Check if acl is trivial
+- * 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)
+-{
+- int i, p;
+- const uint32_t rperm = ACE_READ_DATA;
+- const uint32_t wperm = ACE_WRITE_DATA | ACE_APPEND_DATA;
+- const uint32_t eperm = ACE_EXECUTE;
+- const uint32_t pubset = ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS |
+- ACE_READ_ACL | ACE_SYNCHRONIZE;
+- const uint32_t ownset = pubset | ACE_WRITE_ATTRIBUTES |
+- ACE_WRITE_NAMED_ATTRS | ACE_WRITE_ACL | ACE_WRITE_OWNER;
+-
+- ace_t *ace;
+- ace_t tace[6];
+-
+- if (acl == 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)
+- *trivialp = 1;
+- return (0);
+- }
+-
+- if (acl->acl_type != ACE_T || acl->acl_entry_size != sizeof(ace_t))
+- return (-1);
+-
+- /*
+- * Continue with checking NFSv4 ACLs
+- *
+- * Create list of trivial ace's to be compared
+- */
+-
+- /* owner@ allow pre */
+- tace[0].a_flags = ACE_OWNER;
+- tace[0].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
+- tace[0].a_access_mask = 0;
+-
+- /* owner@ deny */
+- tace[1].a_flags = ACE_OWNER;
+- tace[1].a_type = ACE_ACCESS_DENIED_ACE_TYPE;
+- tace[1].a_access_mask = 0;
+-
+- /* group@ deny */
+- tace[2].a_flags = ACE_GROUP | ACE_IDENTIFIER_GROUP;
+- tace[2].a_type = ACE_ACCESS_DENIED_ACE_TYPE;
+- tace[2].a_access_mask = 0;
+-
+- /* owner@ allow */
+- tace[3].a_flags = ACE_OWNER;
+- tace[3].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
+- tace[3].a_access_mask = ownset;
+-
+- /* group@ allow */
+- tace[4].a_flags = ACE_GROUP | ACE_IDENTIFIER_GROUP;
+- tace[4].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
+- tace[4].a_access_mask = pubset;
+-
+- /* everyone@ allow */
+- tace[5].a_flags = ACE_EVERYONE;
+- tace[5].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
+- tace[5].a_access_mask = pubset;
+-
+- /* Permissions for everyone@ */
+- if (mode & 0004)
+- tace[5].a_access_mask |= rperm;
+- if (mode & 0002)
+- tace[5].a_access_mask |= wperm;
+- if (mode & 0001)
+- tace[5].a_access_mask |= eperm;
+-
+- /* Permissions for group@ */
+- if (mode & 0040)
+- tace[4].a_access_mask |= rperm;
+- else if (mode & 0004)
+- tace[2].a_access_mask |= rperm;
+- if (mode & 0020)
+- tace[4].a_access_mask |= wperm;
+- else if (mode & 0002)
+- tace[2].a_access_mask |= wperm;
+- if (mode & 0010)
+- tace[4].a_access_mask |= eperm;
+- else if (mode & 0001)
+- tace[2].a_access_mask |= eperm;
+-
+- /* Permissions for owner@ */
+- if (mode & 0400) {
+- tace[3].a_access_mask |= rperm;
+- if (!(mode & 0040) && (mode & 0004))
+- tace[0].a_access_mask |= rperm;
+- } else if ((mode & 0040) || (mode & 0004))
+- tace[1].a_access_mask |= rperm;
+- if (mode & 0200) {
+- tace[3].a_access_mask |= wperm;
+- if (!(mode & 0020) && (mode & 0002))
+- tace[0].a_access_mask |= wperm;
+- } else if ((mode & 0020) || (mode & 0002))
+- tace[1].a_access_mask |= wperm;
+- if (mode & 0100) {
+- tace[3].a_access_mask |= eperm;
+- if (!(mode & 0010) && (mode & 0001))
+- tace[0].a_access_mask |= eperm;
+- } else if ((mode & 0010) || (mode & 0001))
+- tace[1].a_access_mask |= eperm;
+-
+- /* Check if the acl count matches */
+- p = 3;
+- for (i = 0; i < 3; i++) {
+- if (tace[i].a_access_mask != 0)
+- p++;
+- }
+- if (acl->acl_cnt != 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];
+- /*
+- * Illumos added ACE_DELETE_CHILD to write perms for
+- * directories. We have to check against that, too.
+- */
+- 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 ||
+- ace->a_access_mask !=
+- (tace[i].a_access_mask | ACE_DELETE_CHILD))))
+- return (0);
+- p++;
+- }
+- }
+-
+- *trivialp = 1;
+- return (0);
+-}
+-#endif /* HAVE_SUN_ACL */
+-
+-#if HAVE_SUN_ACL
+-/*
+- * Translate Solaris POSIX.1e and NFSv4 ACLs into libarchive internal ACL
+- */
+-static int
+-translate_acl(struct archive_read_disk *a,
+- struct archive_entry *entry, acl_t *acl, 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;
+- ace_t *ace;
+-
+- (void)default_entry_acl_type;
+-
+- if (acl->acl_cnt <= 0)
+- return (ARCHIVE_OK);
+-
+- for (e = 0; e < acl->acl_cnt; e++) {
+- ae_name = NULL;
+- ae_tag = 0;
+- ae_perm = 0;
+-
+- if (acl->acl_type == ACE_T) {
+- ace = &((ace_t *)acl->acl_aclp)[e];
+- ae_id = ace->a_who;
+-
+- switch(ace->a_type) {
+- case ACE_ACCESS_ALLOWED_ACE_TYPE:
+- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
+- break;
+- case ACE_ACCESS_DENIED_ACE_TYPE:
+- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
+- break;
+- case ACE_SYSTEM_AUDIT_ACE_TYPE:
+- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
+- break;
+- case ACE_SYSTEM_ALARM_ACE_TYPE:
+- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
+- break;
+- default:
+- /* Unknown entry type, skip */
+- continue;
+- }
+-
+- if ((ace->a_flags & ACE_OWNER) != 0)
+- ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
+- else if ((ace->a_flags & ACE_GROUP) != 0)
+- ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+- else if ((ace->a_flags & ACE_EVERYONE) != 0)
+- ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE;
+- else if ((ace->a_flags & ACE_IDENTIFIER_GROUP) != 0) {
+- ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
+- ae_name = archive_read_disk_gname(&a->archive,
+- ae_id);
+- } else {
+- ae_tag = ARCHIVE_ENTRY_ACL_USER;
+- ae_name = archive_read_disk_uname(&a->archive,
+- ae_id);
+- }
+-
+- for (i = 0; i < (int)(sizeof(acl_inherit_map) /
+- sizeof(acl_inherit_map[0])); ++i) {
+- if ((ace->a_flags &
+- acl_inherit_map[i].platform_inherit) != 0)
+- ae_perm |=
+- acl_inherit_map[i].archive_inherit;
+- }
+-
+- for (i = 0; i < (int)(sizeof(acl_perm_map) /
+- sizeof(acl_perm_map[0])); ++i) {
+- if ((ace->a_access_mask &
+- acl_perm_map[i].platform_perm) != 0)
+- ae_perm |=
+- acl_perm_map[i].archive_perm;
+- }
+- } else {
+- aclent = &((aclent_t *)acl->acl_aclp)[e];
+- if ((aclent->a_type & ACL_DEFAULT) != 0)
+- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
+- else
+- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
+- ae_id = aclent->a_id;
+-
+- switch(aclent->a_type) {
+- case DEF_USER:
+- case USER:
+- ae_name = archive_read_disk_uname(&a->archive,
+- ae_id);
+- ae_tag = ARCHIVE_ENTRY_ACL_USER;
+- break;
+- case DEF_GROUP:
+- case GROUP:
+- ae_name = archive_read_disk_gname(&a->archive,
+- ae_id);
+- ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
+- break;
+- case DEF_CLASS_OBJ:
+- case CLASS_OBJ:
+- ae_tag = ARCHIVE_ENTRY_ACL_MASK;
+- break;
+- case DEF_USER_OBJ:
+- case USER_OBJ:
+- ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
+- break;
+- case DEF_GROUP_OBJ:
+- case GROUP_OBJ:
+- ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+- break;
+- case DEF_OTHER_OBJ:
+- case OTHER_OBJ:
+- ae_tag = ARCHIVE_ENTRY_ACL_OTHER;
+- break;
+- default:
+- /* Unknown tag type, skip */
+- continue;
+- }
+-
+- if ((aclent->a_perm & 1) != 0)
+- ae_perm |= ARCHIVE_ENTRY_ACL_EXECUTE;
+- if ((aclent->a_perm & 2) != 0)
+- 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 */
+-
+- archive_entry_acl_add_entry(entry, entry_acl_type,
+- ae_perm, ae_tag, ae_id, ae_name);
+- }
+- return (ARCHIVE_OK);
+-}
+-#else /* !HAVE_SUN_ACL */
+-/*
+- * Translate POSIX.1e (Linux), FreeBSD (both POSIX.1e and NFSv4) and
+- * MacOS (NFSv4 only) ACLs into libarchive internal structure
+- */
+-static int
+-translate_acl(struct archive_read_disk *a,
+- struct archive_entry *entry, acl_t acl, int default_entry_acl_type)
+-{
+- acl_tag_t acl_tag;
+-#if HAVE_ACL_TYPE_NFS4
+- acl_entry_type_t acl_type;
+- int brand;
+-#endif
+-#if HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL
+- acl_flagset_t acl_flagset;
+-#endif
+- acl_entry_t acl_entry;
+- acl_permset_t acl_permset;
+- int i, entry_acl_type;
+- int r, s, ae_id, ae_tag, ae_perm;
+-#if !HAVE_DARWIN_ACL
+- void *q;
+-#endif
+- const char *ae_name;
+-
+-#if HAVE_ACL_TYPE_NFS4
+- // 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.
+- if (acl_get_brand_np(acl, &brand) != 0) {
+- archive_set_error(&a->archive, errno,
+- "Failed to read ACL brand");
+- return (ARCHIVE_WARN);
+- }
+- switch (brand) {
+- case ACL_BRAND_POSIX:
+- switch (default_entry_acl_type) {
+- case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
+- case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
+- break;
+- default:
+- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+- "Invalid ACL entry type for POSIX.1e ACL");
+- return (ARCHIVE_WARN);
+- }
+- break;
+- case ACL_BRAND_NFS4:
+- if (default_entry_acl_type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
+- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+- "Invalid ACL entry type for NFSv4 ACL");
+- return (ARCHIVE_WARN);
+- }
+- break;
+- default:
+- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+- "Unknown ACL brand");
+- return (ARCHIVE_WARN);
+- }
+-#endif
+-
+- s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry);
+- if (s == -1) {
+- archive_set_error(&a->archive, errno,
+- "Failed to get first ACL entry");
+- return (ARCHIVE_WARN);
+- }
+-
+-#if HAVE_DARWIN_ACL
+- while (s == 0)
+-#else /* FreeBSD, Linux */
+- while (s == 1)
+-#endif
+- {
+- ae_id = -1;
+- ae_name = NULL;
+- ae_perm = 0;
+-
+- if (acl_get_tag_type(acl_entry, &acl_tag) != 0) {
+- archive_set_error(&a->archive, errno,
+- "Failed to get ACL tag type");
+- return (ARCHIVE_WARN);
+- }
+- switch (acl_tag) {
+-#if !HAVE_DARWIN_ACL /* FreeBSD, Linux */
+- case ACL_USER:
+- q = acl_get_qualifier(acl_entry);
+- if (q != NULL) {
+- ae_id = (int)*(uid_t *)q;
+- acl_free(q);
+- ae_name = archive_read_disk_uname(&a->archive,
+- ae_id);
+- }
+- ae_tag = ARCHIVE_ENTRY_ACL_USER;
+- break;
+- case ACL_GROUP:
+- q = acl_get_qualifier(acl_entry);
+- if (q != NULL) {
+- ae_id = (int)*(gid_t *)q;
+- acl_free(q);
+- ae_name = archive_read_disk_gname(&a->archive,
+- ae_id);
+- }
+- ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
+- break;
+- case ACL_MASK:
+- ae_tag = ARCHIVE_ENTRY_ACL_MASK;
+- break;
+- case ACL_USER_OBJ:
+- ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
+- break;
+- case ACL_GROUP_OBJ:
+- ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+- break;
+- case ACL_OTHER:
+- ae_tag = ARCHIVE_ENTRY_ACL_OTHER;
+- break;
+-#if HAVE_ACL_TYPE_NFS4
+- case ACL_EVERYONE:
+- ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE;
+- break;
+-#endif
+-#else /* HAVE_DARWIN_ACL */
+- case ACL_EXTENDED_ALLOW:
+- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
+- r = translate_guid(&a->archive, acl_entry, &ae_id,
+- &ae_tag, &ae_name);
+- break;
+- case ACL_EXTENDED_DENY:
+- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
+- r = translate_guid(&a->archive, acl_entry, &ae_id,
+- &ae_tag, &ae_name);
+- break;
+-#endif /* HAVE_DARWIN_ACL */
+- default:
+- /* Skip types that libarchive can't support. */
+- s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
+- continue;
+- }
+-
+-#if HAVE_DARWIN_ACL
+- /* Skip if translate_guid() above failed */
+- if (r != 0) {
+- s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
+- continue;
+- }
+-#endif
+-
+-#if !HAVE_DARWIN_ACL
+- // 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 (default_entry_acl_type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
+-#if HAVE_ACL_TYPE_NFS4
+- /*
+- * acl_get_entry_type_np() fails with non-NFSv4 ACLs
+- */
+- if (acl_get_entry_type_np(acl_entry, &acl_type) != 0) {
+- archive_set_error(&a->archive, errno, "Failed "
+- "to get ACL type from a NFSv4 ACL entry");
+- return (ARCHIVE_WARN);
+- }
+- switch (acl_type) {
+- case ACL_ENTRY_TYPE_ALLOW:
+- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
+- break;
+- case ACL_ENTRY_TYPE_DENY:
+- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
+- break;
+- case ACL_ENTRY_TYPE_AUDIT:
+- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT;
+- break;
+- case ACL_ENTRY_TYPE_ALARM:
+- entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
+- break;
+- default:
+- archive_set_error(&a->archive, errno,
+- "Invalid NFSv4 ACL entry type");
+- return (ARCHIVE_WARN);
+- }
+-#endif /* HAVE_ACL_TYPE_NFS4 */
+-
+- /*
+- * Libarchive stores "flag" (NFSv4 inheritance bits)
+- * in the ae_perm bitmap.
+- *
+- * acl_get_flagset_np() fails with non-NFSv4 ACLs
+- */
+- if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) {
+- archive_set_error(&a->archive, errno,
+- "Failed to get flagset from a NFSv4 ACL entry");
+- return (ARCHIVE_WARN);
+- }
+- for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) {
+- r = acl_get_flag_np(acl_flagset,
+- acl_inherit_map[i].platform_inherit);
+- if (r == -1) {
+- archive_set_error(&a->archive, errno,
+- "Failed to check flag in a NFSv4 "
+- "ACL flagset");
+- return (ARCHIVE_WARN);
+- } else if (r)
+- ae_perm |= acl_inherit_map[i].archive_inherit;
+- }
+- }
+-#endif /* HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL */
+-
+- if (acl_get_permset(acl_entry, &acl_permset) != 0) {
+- archive_set_error(&a->archive, errno,
+- "Failed to get ACL permission set");
+- return (ARCHIVE_WARN);
+- }
+- for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) {
+- /*
+- * acl_get_perm() is spelled differently on different
+- * platforms; see above.
+- */
+- r = ACL_GET_PERM(acl_permset, acl_perm_map[i].platform_perm);
+- if (r == -1) {
+- archive_set_error(&a->archive, errno,
+- "Failed to check permission in an ACL permission set");
+- return (ARCHIVE_WARN);
+- } else if (r)
+- ae_perm |= acl_perm_map[i].archive_perm;
+- }
+-
+- archive_entry_acl_add_entry(entry, entry_acl_type,
+- ae_perm, ae_tag,
+- ae_id, ae_name);
+-
+- s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
+-#if !HAVE_DARWIN_ACL
+- if (s == -1) {
+- archive_set_error(&a->archive, errno,
+- "Failed to get next ACL entry");
+- return (ARCHIVE_WARN);
+- }
+-#endif
+- }
+- return (ARCHIVE_OK);
+-}
+-#endif /* !HAVE_SUN_ACL */
+-#else /* !HAVE_POSIX_ACL && !HAVE_NFS4_ACL */
+-static int
+-setup_acls(struct archive_read_disk *a,
+- struct archive_entry *entry, int *fd)
+-{
+- (void)a; /* UNUSED */
+- (void)entry; /* UNUSED */
+- (void)fd; /* UNUSED */
+- return (ARCHIVE_OK);
+-}
+-#endif /* !HAVE_POSIX_ACL && !HAVE_NFS4_ACL */
+-
+ #if (HAVE_FGETXATTR && HAVE_FLISTXATTR && HAVE_LISTXATTR && \
+ HAVE_LLISTXATTR && HAVE_GETXATTR && HAVE_LGETXATTR) || \
+ (HAVE_FGETEA && HAVE_FLISTEA && HAVE_LISTEA)
+@@ -1499,21 +512,9 @@ setup_xattrs(struct archive_read_disk *a,
+ path = NULL;
+
+ if (*fd < 0) {
+- path = archive_entry_sourcepath(entry);
+- if (path == NULL || (a->tree != NULL &&
+- a->tree_enter_working_dir(a->tree) != 0))
+- path = archive_entry_pathname(entry);
+- if (path == NULL) {
+- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+- "Couldn't determine file path to read "
+- "extended attributes");
++ path = archive_read_disk_entry_setup_path(a, entry, fd);
++ if (path == NULL)
+ return (ARCHIVE_WARN);
+- }
+- if (a->tree != NULL && (a->follow_symlinks ||
+- archive_entry_filetype(entry) != AE_IFLNK)) {
+- *fd = a->open_on_current_dir(a->tree,
+- path, O_RDONLY | O_NONBLOCK);
+- }
+ }
+
+ #if HAVE_FLISTXATTR
+@@ -1658,21 +659,9 @@ setup_xattrs(struct archive_read_disk *a,
+ path = NULL;
+
+ if (*fd < 0) {
+- path = archive_entry_sourcepath(entry);
+- if (path == NULL || (a->tree != NULL &&
+- a->tree_enter_working_dir(a->tree) != 0))
+- path = archive_entry_pathname(entry);
+- if (path == NULL) {
+- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+- "Couldn't determine file path to read "
+- "extended attributes");
++ path = archive_read_disk_entry_setup_path(a, entry, fd);
++ if (path == NULL)
+ return (ARCHIVE_WARN);
+- }
+- if (a->tree != NULL && (a->follow_symlinks ||
+- archive_entry_filetype(entry) != AE_IFLNK)) {
+- *fd = a->open_on_current_dir(a->tree,
+- path, O_RDONLY | O_NONBLOCK);
+- }
+ }
+
+ if (*fd >= 0)
+@@ -1773,6 +762,7 @@ setup_sparse_fiemap(struct archive_read_disk *a,
+ int64_t size;
+ int count, do_fiemap, iters;
+ int exit_sts = ARCHIVE_OK;
++ const char *path;
+
+ if (archive_entry_filetype(entry) != AE_IFREG
+ || archive_entry_size(entry) <= 0
+@@ -1780,11 +770,10 @@ setup_sparse_fiemap(struct archive_read_disk *a,
+ return (ARCHIVE_OK);
+
+ if (*fd < 0) {
+- const char *path;
+-
+- path = archive_entry_sourcepath(entry);
++ path = archive_read_disk_entry_setup_path(a, entry, NULL);
+ if (path == NULL)
+- path = archive_entry_pathname(entry);
++ return (ARCHIVE_FAILED);
++
+ if (a->tree != NULL)
+ *fd = a->open_on_current_dir(a->tree, path,
+ O_RDONLY | O_NONBLOCK | O_CLOEXEC);
+@@ -1880,6 +869,7 @@ setup_sparse(struct archive_read_disk *a,
+ off_t off_s, off_e;
+ int exit_sts = ARCHIVE_OK;
+ int check_fully_sparse = 0;
++ const char *path;
+
+ if (archive_entry_filetype(entry) != AE_IFREG
+ || archive_entry_size(entry) <= 0
+@@ -1887,19 +877,10 @@ setup_sparse(struct archive_read_disk *a,
+ return (ARCHIVE_OK);
+
+ /* Does filesystem support the reporting of hole ? */
+- if (*fd < 0 && a->tree != NULL) {
+- const char *path;
+-
+- path = archive_entry_sourcepath(entry);
++ if (*fd < 0) {
++ path = archive_read_disk_entry_setup_path(a, entry, fd);
+ if (path == NULL)
+- path = archive_entry_pathname(entry);
+- *fd = a->open_on_current_dir(a->tree, path,
+- O_RDONLY | O_NONBLOCK);
+- if (*fd < 0) {
+- archive_set_error(&a->archive, errno,
+- "Can't open `%s'", path);
+ return (ARCHIVE_FAILED);
+- }
+ }
+
+ if (*fd >= 0) {
+@@ -1911,12 +892,6 @@ setup_sparse(struct archive_read_disk *a,
+ if (initial_off != 0)
+ lseek(*fd, 0, SEEK_SET);
+ } else {
+- const char *path;
+-
+- path = archive_entry_sourcepath(entry);
+- if (path == NULL)
+- path = archive_entry_pathname(entry);
+-
+ #ifdef _PC_MIN_HOLE_SIZE
+ if (pathconf(path, _PC_MIN_HOLE_SIZE) <= 0)
+ return (ARCHIVE_OK);
+--- libarchive/archive_read_disk_private.h.orig
++++ libarchive/archive_read_disk_private.h
+@@ -33,6 +33,8 @@
+ #ifndef ARCHIVE_READ_DISK_PRIVATE_H_INCLUDED
+ #define ARCHIVE_READ_DISK_PRIVATE_H_INCLUDED
+
++#include "archive_platform_acl.h"
++
+ struct tree;
+ struct archive_entry;
+
+@@ -86,4 +88,11 @@ struct archive_read_disk {
+ void *excluded_cb_data;
+ };
+
++const char *
++archive_read_disk_entry_setup_path(struct archive_read_disk *,
++ struct archive_entry *, int *);
++
++int
++archive_read_disk_entry_setup_acls(struct archive_read_disk *,
++ struct archive_entry *, int *);
+ #endif
+--- libarchive/archive_read_format.3.orig
++++ 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
+--- libarchive/archive_read_open.3.orig
++++ 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)
+--- libarchive/archive_read_support_format_mtree.c.orifg
++++ libarchive/archive_read_support_format_mtree.c
+@@ -1857,33 +1857,38 @@ mtree_atol8(char **p)
+ * 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;
+ }
+--- libarchive/archive_read_support_format_tar.c.orig
++++ libarchive/archive_read_support_format_tar.c
+@@ -155,6 +155,7 @@ struct tar {
+ 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 @@ archive_read_format_tar_read_header(struct archive_read *a,
+ 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 @@ pax_attribute(struct archive_read *a, struct tar *tar,
+ 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 @@ pax_attribute(struct archive_read *a, struct tar *tar,
+ 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 @@ pax_attribute(struct archive_read *a, struct tar *tar,
+ 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 @@ pax_attribute(struct archive_read *a, struct tar *tar,
+ 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 @@ header_gnutar(struct archive_read *a, struct tar *tar,
+ 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) {
+--- libarchive/archive_read_support_format_warc.c.orig
++++ libarchive/archive_read_support_format_warc.c
+@@ -600,9 +600,10 @@ _warc_rdver(const char *buf, size_t bsz)
+ /* 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 @@ _warc_rduri(const char *buf, size_t bsz)
+
+ /* 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 @@ _warc_rdlen(const char *buf, size_t bsz)
+ 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) {
+--- libarchive/archive_read_support_format_zip.c.orig
++++ libarchive/archive_read_support_format_zip.c
+@@ -2407,7 +2407,7 @@ read_eocd(struct zip *zip, const char *p, int64_t current_offset)
+ * Examine Zip64 EOCD locator: If it's valid, store the information
+ * from it.
+ */
+-static void
++static int
+ read_zip64_eocd(struct archive_read *a, struct zip *zip, const char *p)
+ {
+ int64_t eocd64_offset;
+@@ -2417,35 +2417,37 @@ read_zip64_eocd(struct archive_read *a, struct zip *zip, const char *p)
+
+ /* Central dir must be on first volume. */
+ if (archive_le32dec(p + 4) != 0)
+- return;
++ return 0;
+ /* Must be only a single volume. */
+ if (archive_le32dec(p + 16) != 1)
+- return;
++ return 0;
+
+ /* Find the Zip64 EOCD record. */
+ eocd64_offset = archive_le64dec(p + 8);
+ if (__archive_read_seek(a, eocd64_offset, SEEK_SET) < 0)
+- return;
++ return 0;
+ if ((p = __archive_read_ahead(a, 56, NULL)) == NULL)
+- return;
++ return 0;
+ /* Make sure we can read all of it. */
+ eocd64_size = archive_le64dec(p + 4) + 12;
+ if (eocd64_size < 56 || eocd64_size > 16384)
+- return;
++ return 0;
+ if ((p = __archive_read_ahead(a, (size_t)eocd64_size, NULL)) == NULL)
+- return;
++ return 0;
+
+ /* Sanity-check the EOCD64 */
+ if (archive_le32dec(p + 16) != 0) /* Must be disk #0 */
+- return;
++ return 0;
+ if (archive_le32dec(p + 20) != 0) /* CD must be on disk #0 */
+- return;
++ return 0;
+ /* CD can't be split. */
+ if (archive_le64dec(p + 24) != archive_le64dec(p + 32))
+- return;
++ return 0;
+
+ /* Save the central directory offset for later use. */
+ zip->central_directory_offset = archive_le64dec(p + 48);
++
++ return 32;
+ }
+
+ static int
+@@ -2483,15 +2485,14 @@ archive_read_format_zip_seekable_bid(struct archive_read *a, int best_bid)
+ if (memcmp(p + i, "PK\005\006", 4) == 0) {
+ int ret = read_eocd(zip, p + i,
+ current_offset + i);
+- if (ret > 0) {
+- /* Zip64 EOCD locator precedes
+- * regular EOCD if present. */
+- if (i >= 20
+- && memcmp(p + i - 20, "PK\006\007", 4) == 0) {
+- read_zip64_eocd(a, zip, p + i - 20);
+- }
+- return (ret);
++ /* Zip64 EOCD locator precedes
++ * regular EOCD if present. */
++ if (i >= 20 && memcmp(p + i - 20, "PK\006\007", 4) == 0) {
++ int ret_zip64 = read_zip64_eocd(a, zip, p + i - 20);
++ if (ret_zip64 > ret)
++ ret = ret_zip64;
+ }
++ return (ret);
+ }
+ i -= 4;
+ break;
+--- libarchive/archive_util.c.orig
++++ libarchive/archive_util.c
+@@ -89,88 +89,6 @@ archive_version_string(void)
+ 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)
+ {
+--- /dev/null
++++ 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
++}
+--- libarchive/archive_write_data.3.orig
++++ 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 @@ Streaming Archive Library (libarchive, -larchive)
+ .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
+--- libarchive/archive_write_disk.3.orig
++++ 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 @@ Streaming Archive Library (libarchive, -larchive)
+ .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 @@ the number of calls to
+ .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
+--- libarchive/archive_write_disk_acl.c
++++ /dev/null
+@@ -1,654 +0,0 @@
+-/*-
+- * Copyright (c) 2003-2010 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
+- * in this position and unchanged.
+- * 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_write_disk.c 201159 2009-12-29 05:35:40Z kientzle $");
+-
+-#ifdef HAVE_SYS_TYPES_H
+-#include <sys/types.h>
+-#endif
+-#ifdef HAVE_SYS_ACL_H
+-#define _ACL_PRIVATE /* For debugging */
+-#include <sys/acl.h>
+-#endif
+-#if HAVE_DARWIN_ACL
+-#include <membership.h>
+-#endif
+-#ifdef HAVE_ERRNO_H
+-#include <errno.h>
+-#endif
+-
+-#include "archive.h"
+-#include "archive_entry.h"
+-#include "archive_acl_private.h"
+-#include "archive_write_disk_private.h"
+-
+-#if !HAVE_POSIX_ACL && !HAVE_NFS4_ACL
+-/* Default empty function body to satisfy mainline code. */
+-int
+-archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
+- struct archive_acl *abstract_acl)
+-{
+- (void)a; /* UNUSED */
+- (void)fd; /* UNUSED */
+- (void)name; /* UNUSED */
+- (void)abstract_acl; /* UNUSED */
+- return (ARCHIVE_OK);
+-}
+-
+-#else /* HAVE_POSIX_ACL || HAVE_NFS4_ACL */
+-
+-#if HAVE_SUN_ACL
+-#define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACE_T
+-#elif HAVE_DARWIN_ACL
+-#define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACL_TYPE_EXTENDED
+-#elif HAVE_ACL_TYPE_NFS4
+-#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);
+-
+-int
+-archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
+- struct archive_acl *abstract_acl)
+-{
+- int ret = ARCHIVE_OK;
+-
+-#if !HAVE_DARWIN_ACL
+- if ((archive_acl_types(abstract_acl)
+- & 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,
+- ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, "posix1e");
+-#else /* HAVE_POSIX_ACL */
+- if ((archive_acl_types(abstract_acl)
+- & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
+- ret = set_acl(a, fd, name, abstract_acl,
+- ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+- "access");
+- if (ret != ARCHIVE_OK)
+- return (ret);
+- }
+- if ((archive_acl_types(abstract_acl)
+- & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)
+- ret = set_acl(a, fd, name, abstract_acl,
+- ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT,
+- "default");
+-#endif /* !HAVE_SUN_ACL */
+- /* Simultaneous POSIX.1e and NFSv4 is not supported */
+- return (ret);
+- }
+-#endif /* !HAVE_DARWIN_ACL */
+-#if HAVE_NFS4_ACL
+- if ((archive_acl_types(abstract_acl) &
+- ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
+- ret = set_acl(a, fd, name, abstract_acl,
+- ARCHIVE_PLATFORM_ACL_TYPE_NFS4,
+- ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4");
+- }
+-#endif /* HAVE_NFS4_ACL */
+- return (ret);
+-}
+-
+-/*
+- * Translate system ACL permissions into libarchive internal structure
+- */
+-static const struct {
+- const int archive_perm;
+- const int platform_perm;
+-} acl_perm_map[] = {
+-#if HAVE_SUN_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},
+- {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACE_WRITE_DATA},
+- {ARCHIVE_ENTRY_ACL_ADD_FILE, ACE_ADD_FILE},
+- {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACE_APPEND_DATA},
+- {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACE_ADD_SUBDIRECTORY},
+- {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACE_READ_NAMED_ATTRS},
+- {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACE_WRITE_NAMED_ATTRS},
+- {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACE_DELETE_CHILD},
+- {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACE_READ_ATTRIBUTES},
+- {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACE_WRITE_ATTRIBUTES},
+- {ARCHIVE_ENTRY_ACL_DELETE, ACE_DELETE},
+- {ARCHIVE_ENTRY_ACL_READ_ACL, ACE_READ_ACL},
+- {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACE_WRITE_ACL},
+- {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACE_WRITE_OWNER},
+- {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACE_SYNCHRONIZE}
+-#elif HAVE_DARWIN_ACL /* MacOS 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},
+- {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
+- {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
+- {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
+- {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
+- {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
+- {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
+- {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
+- {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
+- {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_EXTATTRIBUTES},
+- {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_EXTATTRIBUTES},
+- {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_SECURITY},
+- {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_SECURITY},
+- {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_CHANGE_OWNER},
+- {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
+-#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 */
+- {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
+- {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
+- {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
+- {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
+- {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
+- {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
+- {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS},
+- {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS},
+- {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
+- {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
+- {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
+- {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
+- {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL},
+- {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL},
+- {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER},
+- {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
+-#endif
+-#endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
+-};
+-
+-#if HAVE_NFS4_ACL
+-/*
+- * Translate system NFSv4 inheritance flags into libarchive internal structure
+- */
+-static const struct {
+- const int archive_inherit;
+- const int platform_inherit;
+-} acl_inherit_map[] = {
+-#if HAVE_SUN_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},
+- {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACE_INHERITED_ACE}
+-#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},
+- {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
+- {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_LIMIT_INHERIT},
+- {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_ONLY_INHERIT}
+-#else /* FreeBSD NFSv4 ACL inheritance flags */
+- {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
+- {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
+- {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT},
+- {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY},
+- {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_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
+- aclent_t *aclent;
+- ace_t *ace;
+- int e, r;
+- acl_t *acl;
+-#else
+- acl_t acl;
+- acl_entry_t acl_entry;
+- acl_permset_t acl_permset;
+-#if HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL
+- acl_flagset_t acl_flagset;
+-#endif
+-#endif /* HAVE_SUN_ACL */
+-#if HAVE_ACL_TYPE_NFS4
+- int r;
+-#endif
+- int ret;
+- int ae_type, ae_permset, ae_tag, ae_id;
+-#if HAVE_DARWIN_ACL
+- uuid_t ae_uuid;
+-#endif
+- uid_t ae_uid;
+- gid_t ae_gid;
+- const char *ae_name;
+- int entries;
+- int i;
+-
+- ret = ARCHIVE_OK;
+- entries = archive_acl_reset(abstract_acl, ae_requested_type);
+- if (entries == 0)
+- 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");
+- 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) {
+- archive_set_error(a, errno,
+- "Can't allocate memory for acl buffer");
+- acl_free(acl);
+- return (ARCHIVE_FAILED);
+- }
+-#else /* !HAVE_SUN_ACL */
+- acl = acl_init(entries);
+- if (acl == (acl_t)NULL) {
+- archive_set_error(a, errno,
+- "Failed to initialize ACL working storage");
+- return (ARCHIVE_FAILED);
+- }
+-#endif /* !HAVE_SUN_ACL */
+-#if HAVE_SUN_ACL
+- e = 0;
+-#endif
+- 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];
+- aclent->a_id = -1;
+- aclent->a_type = 0;
+- aclent->a_perm = 0;
+- }
+-#else /* !HAVE_SUN_ACL */
+-#if HAVE_DARWIN_ACL
+- /*
+- * Mac OS doesn't support NFSv4 ACLs for
+- * owner@, group@ and everyone@.
+- * We skip any of these ACLs found.
+- */
+- if (ae_tag == ARCHIVE_ENTRY_ACL_USER_OBJ ||
+- ae_tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ ||
+- ae_tag == ARCHIVE_ENTRY_ACL_EVERYONE)
+- continue;
+-#endif
+- if (acl_create_entry(&acl, &acl_entry) != 0) {
+- archive_set_error(a, errno,
+- "Failed to create a new ACL entry");
+- ret = ARCHIVE_FAILED;
+- goto exit_free;
+- }
+-#endif /* !HAVE_SUN_ACL */
+-#if HAVE_DARWIN_ACL
+- switch (ae_type) {
+- case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
+- acl_set_tag_type(acl_entry, ACL_EXTENDED_ALLOW);
+- break;
+- case ARCHIVE_ENTRY_ACL_TYPE_DENY:
+- acl_set_tag_type(acl_entry, ACL_EXTENDED_DENY);
+- break;
+- default:
+- /* We don't support any other types on MacOS */
+- continue;
+- }
+-#endif
+- switch (ae_tag) {
+-#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 {
+- aclent->a_id = ae_uid;
+- aclent->a_type |= USER;
+- }
+- 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 {
+- aclent->a_id = ae_gid;
+- aclent->a_type |= GROUP;
+- }
+- break;
+- case ARCHIVE_ENTRY_ACL_USER_OBJ:
+- if (acl->acl_type == ACE_T)
+- ace->a_flags |= ACE_OWNER;
+- else
+- aclent->a_type |= USER_OBJ;
+- break;
+- case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+- if (acl->acl_type == ACE_T) {
+- ace->a_flags |= ACE_GROUP;
+- ace->a_flags |= ACE_IDENTIFIER_GROUP;
+- } else
+- aclent->a_type |= GROUP_OBJ;
+- break;
+- case ARCHIVE_ENTRY_ACL_MASK:
+- aclent->a_type |= CLASS_OBJ;
+- break;
+- case ARCHIVE_ENTRY_ACL_OTHER:
+- aclent->a_type |= OTHER_OBJ;
+- break;
+- case ARCHIVE_ENTRY_ACL_EVERYONE:
+- ace->a_flags |= ACE_EVERYONE;
+- break;
+-#else /* !HAVE_SUN_ACL */
+- case ARCHIVE_ENTRY_ACL_USER:
+- ae_uid = archive_write_disk_uid(a, ae_name, ae_id);
+-#if !HAVE_DARWIN_ACL /* FreeBSD, Linux */
+- 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)
+- continue;
+- if (acl_set_qualifier(acl_entry, &ae_uuid) != 0)
+- continue;
+-#endif /* HAVE_DARWIN_ACL */
+- break;
+- case ARCHIVE_ENTRY_ACL_GROUP:
+- ae_gid = archive_write_disk_gid(a, ae_name, ae_id);
+-#if !HAVE_DARWIN_ACL /* FreeBSD, Linux */
+- 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)
+- continue;
+- if (acl_set_qualifier(acl_entry, &ae_uuid) != 0)
+- continue;
+-#endif /* HAVE_DARWIN_ACL */
+- break;
+-#if !HAVE_DARWIN_ACL /* FreeBSD, Linux */
+- case ARCHIVE_ENTRY_ACL_USER_OBJ:
+- acl_set_tag_type(acl_entry, ACL_USER_OBJ);
+- break;
+- case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+- acl_set_tag_type(acl_entry, ACL_GROUP_OBJ);
+- break;
+- case ARCHIVE_ENTRY_ACL_MASK:
+- acl_set_tag_type(acl_entry, ACL_MASK);
+- break;
+- case ARCHIVE_ENTRY_ACL_OTHER:
+- acl_set_tag_type(acl_entry, ACL_OTHER);
+- break;
+-#if HAVE_ACL_TYPE_NFS4 /* FreeBSD only */
+- case ARCHIVE_ENTRY_ACL_EVERYONE:
+- acl_set_tag_type(acl_entry, ACL_EVERYONE);
+- break;
+-#endif
+-#endif /* !HAVE_DARWIN_ACL */
+-#endif /* !HAVE_SUN_ACL */
+- default:
+- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+- "Unknown ACL tag");
+- ret = ARCHIVE_FAILED;
+- goto exit_free;
+- }
+-
+-#if HAVE_ACL_TYPE_NFS4 || HAVE_SUN_ACL
+- r = 0;
+- switch (ae_type) {
+-#if HAVE_SUN_ACL
+- case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
+- if (ace != NULL)
+- ace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
+- else
+- r = -1;
+- break;
+- case ARCHIVE_ENTRY_ACL_TYPE_DENY:
+- if (ace != NULL)
+- ace->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
+- else
+- r = -1;
+- break;
+- case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
+- if (ace != NULL)
+- ace->a_type = ACE_SYSTEM_AUDIT_ACE_TYPE;
+- else
+- r = -1;
+- break;
+- case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
+- if (ace != NULL)
+- ace->a_type = ACE_SYSTEM_ALARM_ACE_TYPE;
+- else
+- r = -1;
+- break;
+- case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
+- if (aclent == NULL)
+- r = -1;
+- break;
+- case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
+- if (aclent != NULL)
+- aclent->a_type |= ACL_DEFAULT;
+- else
+- r = -1;
+- break;
+-#else /* !HAVE_SUN_ACL */
+- case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
+- r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALLOW);
+- break;
+- case ARCHIVE_ENTRY_ACL_TYPE_DENY:
+- r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_DENY);
+- break;
+- case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
+- r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_AUDIT);
+- break;
+- case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
+- r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALARM);
+- break;
+- case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
+- case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
+- // These don't translate directly into the system ACL.
+- break;
+-#endif /* !HAVE_SUN_ACL */
+- default:
+- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+- "Unknown ACL entry type");
+- ret = ARCHIVE_FAILED;
+- goto exit_free;
+- }
+-
+- if (r != 0) {
+-#if HAVE_SUN_ACL
+- errno = EINVAL;
+-#endif
+- archive_set_error(a, errno,
+- "Failed to set ACL entry type");
+- ret = ARCHIVE_FAILED;
+- goto exit_free;
+- }
+-#endif /* HAVE_ACL_TYPE_NFS4 || HAVE_SUN_ACL */
+-
+-#if HAVE_SUN_ACL
+- if (acl->acl_type == ACLENT_T) {
+- 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
+-#else
+- if (acl_get_permset(acl_entry, &acl_permset) != 0) {
+- archive_set_error(a, errno,
+- "Failed to get ACL permission set");
+- ret = ARCHIVE_FAILED;
+- goto exit_free;
+- }
+- if (acl_clear_perms(acl_permset) != 0) {
+- archive_set_error(a, errno,
+- "Failed to clear ACL permissions");
+- ret = ARCHIVE_FAILED;
+- goto exit_free;
+- }
+-#endif /* !HAVE_SUN_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
+- ace->a_access_mask |=
+- acl_perm_map[i].platform_perm;
+-#else
+- if (acl_add_perm(acl_permset,
+- acl_perm_map[i].platform_perm) != 0) {
+- archive_set_error(a, errno,
+- "Failed to add ACL permission");
+- ret = ARCHIVE_FAILED;
+- goto exit_free;
+- }
+-#endif
+- }
+- }
+-
+-#if HAVE_NFS4_ACL
+-#if HAVE_SUN_ACL
+- if (acl_type == ACE_T)
+-#elif HAVE_DARWIN_ACL
+- if (acl_type == ACL_TYPE_EXTENDED)
+-#else /* FreeBSD */
+- if (acl_type == ACL_TYPE_NFS4)
+-#endif
+- {
+-#if HAVE_POSIX_ACL || HAVE_DARWIN_ACL
+- /*
+- * acl_get_flagset_np() fails with non-NFSv4 ACLs
+- */
+- if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) {
+- archive_set_error(a, errno,
+- "Failed to get flagset from an NFSv4 ACL entry");
+- ret = ARCHIVE_FAILED;
+- goto exit_free;
+- }
+- if (acl_clear_flags_np(acl_flagset) != 0) {
+- archive_set_error(a, errno,
+- "Failed to clear flags from an NFSv4 ACL flagset");
+- ret = ARCHIVE_FAILED;
+- goto exit_free;
+- }
+-#endif /* HAVE_POSIX_ACL || HAVE_DARWIN_ACL */
+- for (i = 0; i < (int)(sizeof(acl_inherit_map) /sizeof(acl_inherit_map[0])); ++i) {
+- if (ae_permset & acl_inherit_map[i].archive_inherit) {
+-#if HAVE_SUN_ACL
+- ace->a_flags |=
+- acl_inherit_map[i].platform_inherit;
+-#else /* !HAVE_SUN_ACL */
+- if (acl_add_flag_np(acl_flagset,
+- acl_inherit_map[i].platform_inherit) != 0) {
+- archive_set_error(a, errno,
+- "Failed to add flag to NFSv4 ACL flagset");
+- ret = ARCHIVE_FAILED;
+- goto exit_free;
+- }
+-#endif /* HAVE_SUN_ACL */
+- }
+- }
+- }
+-#endif /* HAVE_NFS4_ACL */
+-#if HAVE_SUN_ACL
+- e++;
+-#endif
+- }
+-
+-#if HAVE_ACL_SET_FD_NP || HAVE_ACL_SET_FD || HAVE_SUN_ACL
+- /* Try restoring the ACL through 'fd' if we can. */
+-#if HAVE_SUN_ACL || HAVE_ACL_SET_FD_NP
+- if (fd >= 0)
+-#else /* !HAVE_SUN_ACL && !HAVE_ACL_SET_FD_NP */
+- if (fd >= 0 && acl_type == ACL_TYPE_ACCESS)
+-#endif
+- {
+-#if HAVE_SUN_ACL
+- if (facl_set(fd, acl) == 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 */
+- if (acl_set_fd(fd, acl) == 0)
+-#endif
+- ret = ARCHIVE_OK;
+- else {
+- if (errno == EOPNOTSUPP) {
+- /* Filesystem doesn't support ACLs */
+- ret = ARCHIVE_OK;
+- } else {
+- archive_set_error(a, errno,
+- "Failed to set %s acl on fd", tname);
+- }
+- }
+- } else
+-#endif /* HAVE_ACL_SET_FD_NP || HAVE_ACL_SET_FD || HAVE_SUN_ACL */
+-#if HAVE_SUN_ACL
+- if (acl_set(name, acl) != 0)
+-#elif HAVE_ACL_SET_LINK_NP
+- if (acl_set_link_np(name, acl_type, acl) != 0)
+-#else
+- /* TODO: Skip this if 'name' is a symlink. */
+- if (acl_set_file(name, acl_type, acl) != 0)
+-#endif
+- {
+- if (errno == EOPNOTSUPP) {
+- /* Filesystem doesn't support ACLs */
+- ret = ARCHIVE_OK;
+- } else {
+- archive_set_error(a, errno, "Failed to set %s acl",
+- tname);
+- ret = ARCHIVE_WARN;
+- }
+- }
+-exit_free:
+- acl_free(acl);
+- return (ret);
+-}
+-#endif /* HAVE_POSIX_ACL || HAVE_NFS4_ACL */
+--- /dev/null
++++ libarchive/archive_write_disk_acl_darwin.c
+@@ -0,0 +1,234 @@
++/*-
++ * 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
++ * in this position and unchanged.
++ * 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"
++
++#ifdef HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++#if HAVE_MEMBERSHIP_H
++#include <membership.h>
++#endif
++#ifdef HAVE_ERRNO_H
++#include <errno.h>
++#endif
++#ifdef HAVE_SYS_ACL_H
++#define _ACL_PRIVATE /* For debugging */
++#include <sys/acl.h>
++#endif
++
++#include "archive.h"
++#include "archive_entry.h"
++#include "archive_write_disk_private.h"
++#include "archive_acl_maps.h"
++
++static int
++set_acl(struct archive *a, int fd, const char *name,
++ struct archive_acl *abstract_acl,
++ int ae_requested_type, const char *tname)
++{
++ acl_t acl;
++ acl_entry_t acl_entry;
++ acl_permset_t acl_permset;
++ acl_flagset_t acl_flagset;
++ int ret;
++ int ae_type, ae_permset, ae_tag, ae_id;
++ uuid_t ae_uuid;
++ uid_t ae_uid;
++ gid_t ae_gid;
++ const char *ae_name;
++ int entries;
++ int i;
++
++ ret = ARCHIVE_OK;
++ entries = archive_acl_reset(abstract_acl, ae_requested_type);
++ if (entries == 0)
++ return (ARCHIVE_OK);
++
++ if (ae_requested_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
++ errno = ENOENT;
++ archive_set_error(a, errno, "Unsupported ACL type");
++ return (ARCHIVE_FAILED);
++ }
++
++ acl = acl_init(entries);
++ if (acl == (acl_t)NULL) {
++ archive_set_error(a, errno,
++ "Failed to initialize ACL working storage");
++ return (ARCHIVE_FAILED);
++ }
++
++ while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type,
++ &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) {
++ /*
++ * Mac OS doesn't support NFSv4 ACLs for
++ * owner@, group@ and everyone@.
++ * We skip any of these ACLs found.
++ */
++ if (ae_tag == ARCHIVE_ENTRY_ACL_USER_OBJ ||
++ ae_tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ ||
++ ae_tag == ARCHIVE_ENTRY_ACL_EVERYONE)
++ continue;
++
++ if (acl_create_entry(&acl, &acl_entry) != 0) {
++ archive_set_error(a, errno,
++ "Failed to create a new ACL entry");
++ ret = ARCHIVE_FAILED;
++ goto exit_free;
++ }
++
++ switch (ae_type) {
++ case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
++ acl_set_tag_type(acl_entry, ACL_EXTENDED_ALLOW);
++ break;
++ case ARCHIVE_ENTRY_ACL_TYPE_DENY:
++ acl_set_tag_type(acl_entry, ACL_EXTENDED_DENY);
++ break;
++ default:
++ /* We don't support any other types on MacOS */
++ continue;
++ }
++
++ switch (ae_tag) {
++ case ARCHIVE_ENTRY_ACL_USER:
++ ae_uid = archive_write_disk_uid(a, ae_name, ae_id);
++ if (mbr_uid_to_uuid(ae_uid, ae_uuid) != 0)
++ continue;
++ if (acl_set_qualifier(acl_entry, &ae_uuid) != 0)
++ continue;
++ break;
++ case ARCHIVE_ENTRY_ACL_GROUP:
++ ae_gid = archive_write_disk_gid(a, ae_name, ae_id);
++ if (mbr_gid_to_uuid(ae_gid, ae_uuid) != 0)
++ continue;
++ if (acl_set_qualifier(acl_entry, &ae_uuid) != 0)
++ continue;
++ break;
++ default:
++ archive_set_error(a, ARCHIVE_ERRNO_MISC,
++ "Unsupported ACL tag");
++ ret = ARCHIVE_FAILED;
++ goto exit_free;
++ }
++
++ if (acl_get_permset(acl_entry, &acl_permset) != 0) {
++ archive_set_error(a, errno,
++ "Failed to get ACL permission set");
++ ret = ARCHIVE_FAILED;
++ goto exit_free;
++ }
++ if (acl_clear_perms(acl_permset) != 0) {
++ archive_set_error(a, errno,
++ "Failed to clear ACL permissions");
++ ret = ARCHIVE_FAILED;
++ goto exit_free;
++ }
++
++ for (i = 0; i < acl_nfs4_perm_map_size; ++i) {
++ if (ae_permset & acl_nfs4_perm_map[i].a_perm) {
++ if (acl_add_perm(acl_permset,
++ acl_nfs4_perm_map[i].p_perm) != 0) {
++ archive_set_error(a, errno,
++ "Failed to add ACL permission");
++ ret = ARCHIVE_FAILED;
++ goto exit_free;
++ }
++ }
++ }
++
++ /*
++ * acl_get_flagset_np() fails with non-NFSv4 ACLs
++ */
++ if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) {
++ archive_set_error(a, errno,
++ "Failed to get flagset from an NFSv4 ACL entry");
++ ret = ARCHIVE_FAILED;
++ goto exit_free;
++ }
++ if (acl_clear_flags_np(acl_flagset) != 0) {
++ archive_set_error(a, errno,
++ "Failed to clear flags from an NFSv4 ACL flagset");
++ ret = ARCHIVE_FAILED;
++ goto exit_free;
++ }
++
++ for (i = 0; i < acl_nfs4_flag_map_size; ++i) {
++ if (ae_permset & acl_nfs4_flag_map[i].a_perm) {
++ if (acl_add_flag_np(acl_flagset,
++ acl_nfs4_flag_map[i].p_perm) != 0) {
++ archive_set_error(a, errno,
++ "Failed to add flag to "
++ "NFSv4 ACL flagset");
++ ret = ARCHIVE_FAILED;
++ goto exit_free;
++ }
++ }
++ }
++ }
++
++ if (fd >= 0) {
++ if (acl_set_fd_np(fd, acl, ACL_TYPE_EXTENDED) == 0)
++ ret = ARCHIVE_OK;
++ else {
++ if (errno == EOPNOTSUPP) {
++ /* Filesystem doesn't support ACLs */
++ ret = ARCHIVE_OK;
++ } else {
++ archive_set_error(a, errno,
++ "Failed to set acl on fd: %s", tname);
++ ret = ARCHIVE_WARN;
++ }
++ }
++ } else if (acl_set_link_np(name, ACL_TYPE_EXTENDED, acl) != 0) {
++ if (errno == EOPNOTSUPP) {
++ /* Filesystem doesn't support ACLs */
++ ret = ARCHIVE_OK;
++ } else {
++ archive_set_error(a, errno, "Failed to set acl: %s",
++ tname);
++ ret = ARCHIVE_WARN;
++ }
++ }
++exit_free:
++ acl_free(acl);
++ return (ret);
++}
++
++int
++archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
++ struct archive_acl *abstract_acl, __LA_MODE_T mode)
++{
++ int ret = ARCHIVE_OK;
++
++ (void)mode; /* UNUSED */
++
++ if ((archive_acl_types(abstract_acl) &
++ ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
++ ret = set_acl(a, fd, name, abstract_acl,
++ ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4");
++ }
++ return (ret);
++}
+--- /dev/null
++++ libarchive/archive_write_disk_acl_freebsd.c
+@@ -0,0 +1,321 @@
++/*-
++ * Copyright (c) 2003-2010 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
++ * in this position and unchanged.
++ * 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$");
++
++#ifdef HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++#ifdef HAVE_ERRNO_H
++#include <errno.h>
++#endif
++#ifdef HAVE_SYS_ACL_H
++#define _ACL_PRIVATE /* For debugging */
++#include <sys/acl.h>
++#endif
++
++#include "archive.h"
++#include "archive_entry.h"
++#include "archive_write_disk_private.h"
++#include "archive_acl_maps.h"
++
++static int
++set_acl(struct archive *a, int fd, const char *name,
++ struct archive_acl *abstract_acl,
++ int ae_requested_type, const char *tname)
++{
++ int acl_type = 0;
++ acl_t acl;
++ acl_entry_t acl_entry;
++ acl_permset_t acl_permset;
++#if ARCHIVE_ACL_FREEBSD_NFS4
++ acl_flagset_t acl_flagset;
++ int r;
++#endif
++ int ret;
++ int ae_type, ae_permset, ae_tag, ae_id;
++ int perm_map_size;
++ const acl_perm_map_t *perm_map;
++ uid_t ae_uid;
++ gid_t ae_gid;
++ const char *ae_name;
++ int entries;
++ int i;
++
++ ret = ARCHIVE_OK;
++ entries = archive_acl_reset(abstract_acl, ae_requested_type);
++ if (entries == 0)
++ return (ARCHIVE_OK);
++
++
++ switch (ae_requested_type) {
++ case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
++ acl_type = ACL_TYPE_ACCESS;
++ break;
++ case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
++ acl_type = ACL_TYPE_DEFAULT;
++ break;
++#if ARCHIVE_ACL_FREEBSD_NFS4
++ case ARCHIVE_ENTRY_ACL_TYPE_NFS4:
++ acl_type = ACL_TYPE_NFS4;
++ break;
++#endif
++ default:
++ errno = ENOENT;
++ archive_set_error(a, errno, "Unsupported ACL type");
++ return (ARCHIVE_FAILED);
++ }
++
++ acl = acl_init(entries);
++ if (acl == (acl_t)NULL) {
++ archive_set_error(a, errno,
++ "Failed to initialize ACL working storage");
++ return (ARCHIVE_FAILED);
++ }
++
++ while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type,
++ &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) {
++ if (acl_create_entry(&acl, &acl_entry) != 0) {
++ archive_set_error(a, errno,
++ "Failed to create a new ACL entry");
++ ret = ARCHIVE_FAILED;
++ goto exit_free;
++ }
++ switch (ae_tag) {
++ case ARCHIVE_ENTRY_ACL_USER:
++ ae_uid = archive_write_disk_uid(a, ae_name, ae_id);
++ acl_set_tag_type(acl_entry, ACL_USER);
++ acl_set_qualifier(acl_entry, &ae_uid);
++ break;
++ case ARCHIVE_ENTRY_ACL_GROUP:
++ ae_gid = archive_write_disk_gid(a, ae_name, ae_id);
++ acl_set_tag_type(acl_entry, ACL_GROUP);
++ acl_set_qualifier(acl_entry, &ae_gid);
++ break;
++ case ARCHIVE_ENTRY_ACL_USER_OBJ:
++ acl_set_tag_type(acl_entry, ACL_USER_OBJ);
++ break;
++ case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
++ acl_set_tag_type(acl_entry, ACL_GROUP_OBJ);
++ break;
++ case ARCHIVE_ENTRY_ACL_MASK:
++ acl_set_tag_type(acl_entry, ACL_MASK);
++ break;
++ case ARCHIVE_ENTRY_ACL_OTHER:
++ acl_set_tag_type(acl_entry, ACL_OTHER);
++ break;
++#if ARCHIVE_ACL_FREEBSD_NFS4
++ case ARCHIVE_ENTRY_ACL_EVERYONE:
++ acl_set_tag_type(acl_entry, ACL_EVERYONE);
++ break;
++#endif
++ default:
++ archive_set_error(a, ARCHIVE_ERRNO_MISC,
++ "Unsupported ACL tag");
++ ret = ARCHIVE_FAILED;
++ goto exit_free;
++ }
++
++#if ARCHIVE_ACL_FREEBSD_NFS4
++ r = 0;
++ switch (ae_type) {
++ case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
++ r = acl_set_entry_type_np(acl_entry,
++ ACL_ENTRY_TYPE_ALLOW);
++ break;
++ case ARCHIVE_ENTRY_ACL_TYPE_DENY:
++ r = acl_set_entry_type_np(acl_entry,
++ ACL_ENTRY_TYPE_DENY);
++ break;
++ case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
++ r = acl_set_entry_type_np(acl_entry,
++ ACL_ENTRY_TYPE_AUDIT);
++ break;
++ case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
++ r = acl_set_entry_type_np(acl_entry,
++ ACL_ENTRY_TYPE_ALARM);
++ break;
++ case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
++ case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
++ // These don't translate directly into the system ACL.
++ break;
++ default:
++ archive_set_error(a, ARCHIVE_ERRNO_MISC,
++ "Unsupported ACL entry type");
++ ret = ARCHIVE_FAILED;
++ goto exit_free;
++ }
++
++ if (r != 0) {
++ archive_set_error(a, errno,
++ "Failed to set ACL entry type");
++ ret = ARCHIVE_FAILED;
++ goto exit_free;
++ }
++#endif
++
++ if (acl_get_permset(acl_entry, &acl_permset) != 0) {
++ archive_set_error(a, errno,
++ "Failed to get ACL permission set");
++ ret = ARCHIVE_FAILED;
++ goto exit_free;
++ }
++ if (acl_clear_perms(acl_permset) != 0) {
++ archive_set_error(a, errno,
++ "Failed to clear ACL permissions");
++ ret = ARCHIVE_FAILED;
++ goto exit_free;
++ }
++#if ARCHIVE_ACL_FREEBSD_NFS4
++ if (ae_requested_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
++ perm_map_size = acl_nfs4_perm_map_size;
++ perm_map = acl_nfs4_perm_map;
++ } else {
++#endif
++ perm_map_size = acl_posix_perm_map_size;
++ perm_map = acl_posix_perm_map;
++#if ARCHIVE_ACL_FREEBSD_NFS4
++ }
++#endif
++
++ for (i = 0; i < perm_map_size; ++i) {
++ if (ae_permset & perm_map[i].a_perm) {
++ if (acl_add_perm(acl_permset,
++ perm_map[i].p_perm) != 0) {
++ archive_set_error(a, errno,
++ "Failed to add ACL permission");
++ ret = ARCHIVE_FAILED;
++ goto exit_free;
++ }
++ }
++ }
++
++#if ARCHIVE_ACL_FREEBSD_NFS4
++ if (ae_requested_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
++ /*
++ * acl_get_flagset_np() fails with non-NFSv4 ACLs
++ */
++ if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) {
++ archive_set_error(a, errno,
++ "Failed to get flagset from an NFSv4 "
++ "ACL entry");
++ ret = ARCHIVE_FAILED;
++ goto exit_free;
++ }
++ if (acl_clear_flags_np(acl_flagset) != 0) {
++ archive_set_error(a, errno,
++ "Failed to clear flags from an NFSv4 "
++ "ACL flagset");
++ ret = ARCHIVE_FAILED;
++ goto exit_free;
++ }
++ for (i = 0; i < acl_nfs4_flag_map_size; ++i) {
++ if (ae_permset & acl_nfs4_flag_map[i].a_perm) {
++ if (acl_add_flag_np(acl_flagset,
++ acl_nfs4_flag_map[i].p_perm) != 0) {
++ archive_set_error(a, errno,
++ "Failed to add flag to "
++ "NFSv4 ACL flagset");
++ ret = ARCHIVE_FAILED;
++ goto exit_free;
++ }
++ }
++ }
++ }
++#endif
++ }
++
++ /* Try restoring the ACL through 'fd' if we can. */
++ if (fd >= 0) {
++ if (acl_set_fd_np(fd, acl, acl_type) == 0)
++ ret = ARCHIVE_OK;
++ else {
++ if (errno == EOPNOTSUPP) {
++ /* Filesystem doesn't support ACLs */
++ ret = ARCHIVE_OK;
++ } else {
++ archive_set_error(a, errno,
++ "Failed to set acl on fd: %s", tname);
++ ret = ARCHIVE_WARN;
++ }
++ }
++ }
++#if HAVE_ACL_SET_LINK_NP
++ else if (acl_set_link_np(name, acl_type, acl) != 0)
++#else
++ /* FreeBSD older than 8.0 */
++ else if (acl_set_file(name, acl_type, acl) != 0)
++#endif
++ {
++ if (errno == EOPNOTSUPP) {
++ /* Filesystem doesn't support ACLs */
++ ret = ARCHIVE_OK;
++ } else {
++ archive_set_error(a, errno, "Failed to set acl: %s",
++ tname);
++ ret = ARCHIVE_WARN;
++ }
++ }
++exit_free:
++ acl_free(acl);
++ return (ret);
++}
++
++int
++archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
++ struct archive_acl *abstract_acl, __LA_MODE_T mode)
++{
++ int ret = ARCHIVE_OK;
++
++ (void)mode; /* UNUSED */
++
++ if ((archive_acl_types(abstract_acl)
++ & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
++ if ((archive_acl_types(abstract_acl)
++ & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
++ ret = set_acl(a, fd, name, abstract_acl,
++ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access");
++ if (ret != ARCHIVE_OK)
++ return (ret);
++ }
++ if ((archive_acl_types(abstract_acl)
++ & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)
++ ret = set_acl(a, fd, name, abstract_acl,
++ ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default");
++
++ /* Simultaneous POSIX.1e and NFSv4 is not supported */
++ return (ret);
++ }
++#if ARCHIVE_ACL_FREEBSD_NFS4
++ else if ((archive_acl_types(abstract_acl) &
++ ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
++ ret = set_acl(a, fd, name, abstract_acl,
++ ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4");
++ }
++#endif
++ return (ret);
++}
+--- /dev/null
++++ libarchive/archive_write_disk_acl_linux.c
+@@ -0,0 +1,388 @@
++/*-
++ * Copyright (c) 2003-2010 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
++ * in this position and unchanged.
++ * 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"
++
++#ifdef HAVE_ERRNO_H
++#include <errno.h>
++#endif
++#ifdef HAVE_FCNTL_H
++#include <fcntl.h>
++#endif
++#if HAVE_ACL_LIBACL_H
++#include <acl/libacl.h>
++#endif
++#ifdef HAVE_SYS_ACL_H
++#include <sys/acl.h>
++#endif
++#if HAVE_SYS_RICHACL_H
++#include <sys/richacl.h>
++#endif
++
++#include "archive.h"
++#include "archive_entry.h"
++#include "archive_write_disk_private.h"
++#include "archive_acl_maps.h"
++
++#if ARCHIVE_ACL_LIBRICHACL
++static int
++_richacl_mode_to_mask(short mode)
++{
++ int mask = 0;
++
++ if (mode & S_IROTH)
++ mask |= RICHACE_POSIX_MODE_READ;
++ if (mode & S_IWOTH)
++ mask |= RICHACE_POSIX_MODE_WRITE;
++ if (mode & S_IXOTH)
++ mask |= RICHACE_POSIX_MODE_EXEC;
++
++ return (mask);
++}
++
++static void
++_richacl_mode_to_masks(struct richacl *richacl, __LA_MODE_T mode)
++{
++ richacl->a_owner_mask = _richacl_mode_to_mask((mode & 0700) >> 6);
++ richacl->a_group_mask = _richacl_mode_to_mask((mode & 0070) >> 3);
++ richacl->a_other_mask = _richacl_mode_to_mask(mode & 0007);
++}
++#endif /* ARCHIVE_ACL_LIBRICHACL */
++
++#if ARCHIVE_ACL_LIBRICHACL
++static int
++set_richacl(struct archive *a, int fd, const char *name,
++ struct archive_acl *abstract_acl, __LA_MODE_T mode,
++ int ae_requested_type, const char *tname)
++{
++ int ae_type, ae_permset, ae_tag, ae_id;
++ uid_t ae_uid;
++ gid_t ae_gid;
++ const char *ae_name;
++ int entries;
++ int i;
++ int ret;
++ int e = 0;
++ struct richacl *richacl = NULL;
++ struct richace *richace;
++
++ ret = ARCHIVE_OK;
++ entries = archive_acl_reset(abstract_acl, ae_requested_type);
++ if (entries == 0)
++ return (ARCHIVE_OK);
++
++ if (ae_requested_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
++ errno = ENOENT;
++ archive_set_error(a, errno, "Unsupported ACL type");
++ return (ARCHIVE_FAILED);
++ }
++
++ richacl = richacl_alloc(entries);
++ if (richacl == NULL) {
++ archive_set_error(a, errno,
++ "Failed to initialize RichACL working storage");
++ return (ARCHIVE_FAILED);
++ }
++
++ e = 0;
++
++ while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type,
++ &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) {
++ richace = &(richacl->a_entries[e]);
++
++ richace->e_flags = 0;
++ richace->e_mask = 0;
++
++ switch (ae_tag) {
++ case ARCHIVE_ENTRY_ACL_USER:
++ ae_uid = archive_write_disk_uid(a, ae_name, ae_id);
++ richace->e_id = ae_uid;
++ break;
++ case ARCHIVE_ENTRY_ACL_GROUP:
++ ae_gid = archive_write_disk_gid(a, ae_name, ae_id);
++ richace->e_id = ae_gid;
++ richace->e_flags |= RICHACE_IDENTIFIER_GROUP;
++ break;
++ case ARCHIVE_ENTRY_ACL_USER_OBJ:
++ richace->e_flags |= RICHACE_SPECIAL_WHO;
++ richace->e_id = RICHACE_OWNER_SPECIAL_ID;
++ break;
++ case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
++ richace->e_flags |= RICHACE_SPECIAL_WHO;
++ richace->e_id = RICHACE_GROUP_SPECIAL_ID;
++ break;
++ case ARCHIVE_ENTRY_ACL_EVERYONE:
++ richace->e_flags |= RICHACE_SPECIAL_WHO;
++ richace->e_id = RICHACE_EVERYONE_SPECIAL_ID;
++ break;
++ default:
++ archive_set_error(a, ARCHIVE_ERRNO_MISC,
++ "Unsupported ACL tag");
++ ret = ARCHIVE_FAILED;
++ goto exit_free;
++ }
++
++ switch (ae_type) {
++ case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
++ richace->e_type =
++ RICHACE_ACCESS_ALLOWED_ACE_TYPE;
++ break;
++ case ARCHIVE_ENTRY_ACL_TYPE_DENY:
++ richace->e_type =
++ RICHACE_ACCESS_DENIED_ACE_TYPE;
++ break;
++ case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
++ case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
++ break;
++ default:
++ archive_set_error(a, ARCHIVE_ERRNO_MISC,
++ "Unsupported ACL entry type");
++ ret = ARCHIVE_FAILED;
++ goto exit_free;
++ }
++
++ for (i = 0; i < acl_nfs4_perm_map_size; ++i) {
++ if (ae_permset & acl_nfs4_perm_map[i].a_perm)
++ richace->e_mask |= acl_nfs4_perm_map[i].p_perm;
++ }
++
++ for (i = 0; i < acl_nfs4_flag_map_size; ++i) {
++ if (ae_permset &
++ acl_nfs4_flag_map[i].a_perm)
++ richace->e_flags |= acl_nfs4_flag_map[i].p_perm;
++ }
++ e++;
++ }
++
++ /* Fill RichACL masks */
++ _richacl_mode_to_masks(richacl, mode);
++
++ if (fd >= 0) {
++ if (richacl_set_fd(fd, richacl) == 0)
++ ret = ARCHIVE_OK;
++ else {
++ if (errno == EOPNOTSUPP) {
++ /* Filesystem doesn't support ACLs */
++ ret = ARCHIVE_OK;
++ } else {
++ archive_set_error(a, errno,
++ "Failed to set richacl on fd: %s", tname);
++ ret = ARCHIVE_WARN;
++ }
++ }
++ } else if (richacl_set_file(name, richacl) != 0) {
++ if (errno == EOPNOTSUPP) {
++ /* Filesystem doesn't support ACLs */
++ ret = ARCHIVE_OK;
++ } else {
++ archive_set_error(a, errno, "Failed to set richacl: %s",
++ tname);
++ ret = ARCHIVE_WARN;
++ }
++ }
++exit_free:
++ richacl_free(richacl);
++ return (ret);
++}
++#endif /* ARCHIVE_ACL_RICHACL */
++
++#if ARCHIVE_ACL_LIBACL
++static int
++set_acl(struct archive *a, int fd, const char *name,
++ struct archive_acl *abstract_acl,
++ int ae_requested_type, const char *tname)
++{
++ int acl_type = 0;
++ int ae_type, ae_permset, ae_tag, ae_id;
++ uid_t ae_uid;
++ gid_t ae_gid;
++ const char *ae_name;
++ int entries;
++ int i;
++ int ret;
++ acl_t acl = NULL;
++ acl_entry_t acl_entry;
++ acl_permset_t acl_permset;
++
++ ret = ARCHIVE_OK;
++ entries = archive_acl_reset(abstract_acl, ae_requested_type);
++ if (entries == 0)
++ return (ARCHIVE_OK);
++
++ switch (ae_requested_type) {
++ case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
++ acl_type = ACL_TYPE_ACCESS;
++ break;
++ case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
++ acl_type = ACL_TYPE_DEFAULT;
++ break;
++ default:
++ errno = ENOENT;
++ archive_set_error(a, errno, "Unsupported ACL type");
++ return (ARCHIVE_FAILED);
++ }
++
++ acl = acl_init(entries);
++ if (acl == (acl_t)NULL) {
++ archive_set_error(a, errno,
++ "Failed to initialize ACL working storage");
++ return (ARCHIVE_FAILED);
++ }
++
++ while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type,
++ &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) {
++
++ if (acl_create_entry(&acl, &acl_entry) != 0) {
++ archive_set_error(a, errno,
++ "Failed to create a new ACL entry");
++ ret = ARCHIVE_FAILED;
++ goto exit_free;
++ }
++
++ switch (ae_tag) {
++ case ARCHIVE_ENTRY_ACL_USER:
++ ae_uid = archive_write_disk_uid(a, ae_name, ae_id);
++ acl_set_tag_type(acl_entry, ACL_USER);
++ acl_set_qualifier(acl_entry, &ae_uid);
++ break;
++ case ARCHIVE_ENTRY_ACL_GROUP:
++ ae_gid = archive_write_disk_gid(a, ae_name, ae_id);
++ acl_set_tag_type(acl_entry, ACL_GROUP);
++ acl_set_qualifier(acl_entry, &ae_gid);
++ break;
++ case ARCHIVE_ENTRY_ACL_USER_OBJ:
++ acl_set_tag_type(acl_entry, ACL_USER_OBJ);
++ break;
++ case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
++ acl_set_tag_type(acl_entry, ACL_GROUP_OBJ);
++ break;
++ case ARCHIVE_ENTRY_ACL_MASK:
++ acl_set_tag_type(acl_entry, ACL_MASK);
++ break;
++ case ARCHIVE_ENTRY_ACL_OTHER:
++ acl_set_tag_type(acl_entry, ACL_OTHER);
++ break;
++ default:
++ archive_set_error(a, ARCHIVE_ERRNO_MISC,
++ "Unsupported ACL tag");
++ ret = ARCHIVE_FAILED;
++ goto exit_free;
++ }
++
++ if (acl_get_permset(acl_entry, &acl_permset) != 0) {
++ archive_set_error(a, errno,
++ "Failed to get ACL permission set");
++ ret = ARCHIVE_FAILED;
++ goto exit_free;
++ }
++ if (acl_clear_perms(acl_permset) != 0) {
++ archive_set_error(a, errno,
++ "Failed to clear ACL permissions");
++ ret = ARCHIVE_FAILED;
++ goto exit_free;
++ }
++
++ for (i = 0; i < acl_posix_perm_map_size; ++i) {
++ if (ae_permset & acl_posix_perm_map[i].a_perm) {
++ if (acl_add_perm(acl_permset,
++ acl_posix_perm_map[i].p_perm) != 0) {
++ archive_set_error(a, errno,
++ "Failed to add ACL permission");
++ ret = ARCHIVE_FAILED;
++ goto exit_free;
++ }
++ }
++ }
++
++ }
++
++ if (fd >= 0 && ae_requested_type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) {
++ if (acl_set_fd(fd, acl) == 0)
++ ret = ARCHIVE_OK;
++ else {
++ if (errno == EOPNOTSUPP) {
++ /* Filesystem doesn't support ACLs */
++ ret = ARCHIVE_OK;
++ } else {
++ archive_set_error(a, errno,
++ "Failed to set acl on fd: %s", tname);
++ ret = ARCHIVE_WARN;
++ }
++ }
++ } else if (acl_set_file(name, acl_type, acl) != 0) {
++ if (errno == EOPNOTSUPP) {
++ /* Filesystem doesn't support ACLs */
++ ret = ARCHIVE_OK;
++ } else {
++ archive_set_error(a, errno, "Failed to set acl: %s",
++ tname);
++ ret = ARCHIVE_WARN;
++ }
++ }
++exit_free:
++ acl_free(acl);
++ return (ret);
++}
++#endif /* ARCHIVE_ACL_LIBACL */
++
++int
++archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
++ struct archive_acl *abstract_acl, __LA_MODE_T mode)
++{
++ int ret = ARCHIVE_OK;
++
++#if !ARCHIVE_ACL_LIBRICHACL
++ (void)mode; /* UNUSED */
++#endif
++
++#if ARCHIVE_ACL_LIBRICHACL
++ if ((archive_acl_types(abstract_acl)
++ & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
++ ret = set_richacl(a, fd, name, abstract_acl, mode,
++ ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4");
++ }
++#if ARCHIVE_ACL_LIBACL
++ else
++#endif
++#endif /* ARCHIVE_ACL_LIBRICHACL */
++#if ARCHIVE_ACL_LIBACL
++ if ((archive_acl_types(abstract_acl)
++ & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
++ if ((archive_acl_types(abstract_acl)
++ & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
++ ret = set_acl(a, fd, name, abstract_acl,
++ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access");
++ if (ret != ARCHIVE_OK)
++ return (ret);
++ }
++ if ((archive_acl_types(abstract_acl)
++ & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)
++ ret = set_acl(a, fd, name, abstract_acl,
++ ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default");
++ }
++#endif /* ARCHIVE_ACL_LIBACL */
++ return (ret);
++}
+--- /dev/null
++++ libarchive/archive_write_disk_acl_sunos.c
+@@ -0,0 +1,329 @@
++/*-
++ * 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
++ * in this position and unchanged.
++ * 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"
++
++#ifdef HAVE_SYS_TYPES_H
++#include <sys/types.h>
++#endif
++#ifdef HAVE_ERRNO_H
++#include <errno.h>
++#endif
++#ifdef HAVE_SYS_ACL_H
++#define _ACL_PRIVATE /* For debugging */
++#include <sys/acl.h>
++#endif
++
++#include "archive.h"
++#include "archive_entry.h"
++#include "archive_write_disk_private.h"
++#include "archive_acl_maps.h"
++
++static int
++set_acl(struct archive *a, int fd, const char *name,
++ struct archive_acl *abstract_acl,
++ int ae_requested_type, const char *tname)
++{
++ aclent_t *aclent;
++#if ARCHIVE_ACL_SUNOS_NFS4
++ ace_t *ace;
++#endif
++ int cmd, e, r;
++ void *aclp;
++ int ret;
++ int ae_type, ae_permset, ae_tag, ae_id;
++ int perm_map_size;
++ const acl_perm_map_t *perm_map;
++ uid_t ae_uid;
++ gid_t ae_gid;
++ const char *ae_name;
++ int entries;
++ int i;
++
++ ret = ARCHIVE_OK;
++ entries = archive_acl_reset(abstract_acl, ae_requested_type);
++ if (entries == 0)
++ return (ARCHIVE_OK);
++
++
++ switch (ae_requested_type) {
++ case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E:
++ cmd = SETACL;
++ aclp = malloc(entries * sizeof(aclent_t));
++ break;
++#if ARCHIVE_ACL_SUNOS_NFS4
++ 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, "Unsupported ACL type");
++ return (ARCHIVE_FAILED);
++ }
++
++ if (aclp == NULL) {
++ archive_set_error(a, errno,
++ "Can't allocate memory for acl buffer");
++ return (ARCHIVE_FAILED);
++ }
++
++ e = 0;
++
++ while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type,
++ &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) {
++ aclent = NULL;
++#if ARCHIVE_ACL_SUNOS_NFS4
++ ace = NULL;
++#endif
++ if (cmd == SETACL) {
++ aclent = &((aclent_t *)aclp)[e];
++ aclent->a_id = -1;
++ aclent->a_type = 0;
++ aclent->a_perm = 0;
++ }
++#if ARCHIVE_ACL_SUNOS_NFS4
++ else { /* cmd == ACE_SETACL */
++ ace = &((ace_t *)aclp)[e];
++ ace->a_who = -1;
++ ace->a_access_mask = 0;
++ ace->a_flags = 0;
++ }
++#endif /* ARCHIVE_ACL_SUNOS_NFS4 */
++
++ switch (ae_tag) {
++ case ARCHIVE_ENTRY_ACL_USER:
++ ae_uid = archive_write_disk_uid(a, ae_name, ae_id);
++ if (aclent != NULL) {
++ aclent->a_id = ae_uid;
++ aclent->a_type |= USER;
++ }
++#if ARCHIVE_ACL_SUNOS_NFS4
++ 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 (aclent != NULL) {
++ aclent->a_id = ae_gid;
++ aclent->a_type |= GROUP;
++ }
++#if ARCHIVE_ACL_SUNOS_NFS4
++ else {
++ ace->a_who = ae_gid;
++ ace->a_flags |= ACE_IDENTIFIER_GROUP;
++ }
++#endif
++ break;
++ case ARCHIVE_ENTRY_ACL_USER_OBJ:
++ if (aclent != NULL)
++ aclent->a_type |= USER_OBJ;
++#if ARCHIVE_ACL_SUNOS_NFS4
++ else {
++ ace->a_flags |= ACE_OWNER;
++ }
++#endif
++ break;
++ case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
++ if (aclent != NULL)
++ aclent->a_type |= GROUP_OBJ;
++#if ARCHIVE_ACL_SUNOS_NFS4
++ else {
++ ace->a_flags |= ACE_GROUP;
++ ace->a_flags |= ACE_IDENTIFIER_GROUP;
++ }
++#endif
++ break;
++ case ARCHIVE_ENTRY_ACL_MASK:
++ if (aclent != NULL)
++ aclent->a_type |= CLASS_OBJ;
++ break;
++ case ARCHIVE_ENTRY_ACL_OTHER:
++ if (aclent != NULL)
++ aclent->a_type |= OTHER_OBJ;
++ break;
++#if ARCHIVE_ACL_SUNOS_NFS4
++ case ARCHIVE_ENTRY_ACL_EVERYONE:
++ if (ace != NULL)
++ ace->a_flags |= ACE_EVERYONE;
++ break;
++#endif
++ default:
++ archive_set_error(a, ARCHIVE_ERRNO_MISC,
++ "Unsupported ACL tag");
++ ret = ARCHIVE_FAILED;
++ goto exit_free;
++ }
++
++ r = 0;
++ switch (ae_type) {
++#if ARCHIVE_ACL_SUNOS_NFS4
++ case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
++ if (ace != NULL)
++ ace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE;
++ else
++ r = -1;
++ break;
++ case ARCHIVE_ENTRY_ACL_TYPE_DENY:
++ if (ace != NULL)
++ ace->a_type = ACE_ACCESS_DENIED_ACE_TYPE;
++ else
++ r = -1;
++ break;
++ case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
++ if (ace != NULL)
++ ace->a_type = ACE_SYSTEM_AUDIT_ACE_TYPE;
++ else
++ r = -1;
++ break;
++ case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
++ if (ace != NULL)
++ ace->a_type = ACE_SYSTEM_ALARM_ACE_TYPE;
++ else
++ r = -1;
++ break;
++#endif
++ case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
++ if (aclent == NULL)
++ r = -1;
++ break;
++ case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
++ if (aclent != NULL)
++ aclent->a_type |= ACL_DEFAULT;
++ else
++ r = -1;
++ break;
++ default:
++ archive_set_error(a, ARCHIVE_ERRNO_MISC,
++ "Unsupported ACL entry type");
++ ret = ARCHIVE_FAILED;
++ goto exit_free;
++ }
++
++ if (r != 0) {
++ errno = EINVAL;
++ archive_set_error(a, errno,
++ "Failed to set ACL entry type");
++ ret = ARCHIVE_FAILED;
++ goto exit_free;
++ }
++
++#if ARCHIVE_ACL_SUNOS_NFS4
++ if (ae_requested_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
++ perm_map_size = acl_nfs4_perm_map_size;
++ perm_map = acl_nfs4_perm_map;
++ } else {
++#endif
++ perm_map_size = acl_posix_perm_map_size;
++ perm_map = acl_posix_perm_map;
++#if ARCHIVE_ACL_SUNOS_NFS4
++ }
++#endif
++ for (i = 0; i < perm_map_size; ++i) {
++ if (ae_permset & perm_map[i].a_perm) {
++#if ARCHIVE_ACL_SUNOS_NFS4
++ if (ae_requested_type ==
++ ARCHIVE_ENTRY_ACL_TYPE_NFS4)
++ ace->a_access_mask |=
++ perm_map[i].p_perm;
++ else
++#endif
++ aclent->a_perm |= perm_map[i].p_perm;
++ }
++ }
++
++#if ARCHIVE_ACL_SUNOS_NFS4
++ if (ae_requested_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
++ for (i = 0; i < acl_nfs4_flag_map_size; ++i) {
++ if (ae_permset & acl_nfs4_flag_map[i].a_perm) {
++ ace->a_flags |=
++ acl_nfs4_flag_map[i].p_perm;
++ }
++ }
++ }
++#endif
++ e++;
++ }
++
++ /* Try restoring the ACL through 'fd' if we can. */
++ if (fd >= 0) {
++ if (facl(fd, cmd, entries, aclp) == 0)
++ ret = ARCHIVE_OK;
++ else {
++ if (errno == EOPNOTSUPP) {
++ /* Filesystem doesn't support ACLs */
++ ret = ARCHIVE_OK;
++ } else {
++ archive_set_error(a, errno,
++ "Failed to set acl on fd: %s", tname);
++ ret = ARCHIVE_WARN;
++ }
++ }
++ } else if (acl(name, cmd, entries, aclp) != 0) {
++ if (errno == EOPNOTSUPP) {
++ /* Filesystem doesn't support ACLs */
++ ret = ARCHIVE_OK;
++ } else {
++ archive_set_error(a, errno, "Failed to set acl: %s",
++ tname);
++ ret = ARCHIVE_WARN;
++ }
++ }
++exit_free:
++ free(aclp);
++ return (ret);
++}
++
++int
++archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
++ struct archive_acl *abstract_acl, __LA_MODE_T mode)
++{
++ int ret = ARCHIVE_OK;
++
++ (void)mode; /* UNUSED */
++
++ if ((archive_acl_types(abstract_acl)
++ & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
++ /* Solaris writes POSIX.1e access and default ACLs together */
++ ret = set_acl(a, fd, name, abstract_acl,
++ ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, "posix1e");
++
++ /* Simultaneous POSIX.1e and NFSv4 is not supported */
++ return (ret);
++ }
++#if ARCHIVE_ACL_SUNOS_NFS4
++ else if ((archive_acl_types(abstract_acl) &
++ ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
++ ret = set_acl(a, fd, name, abstract_acl,
++ ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4");
++ }
++#endif
++ return (ret);
++}
+--- libarchive/archive_write_disk_posix.c.orig
++++ libarchive/archive_write_disk_posix.c
+@@ -575,10 +575,55 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
+ if (a->flags & ARCHIVE_EXTRACT_TIME)
+ a->todo |= TODO_TIMES;
+ if (a->flags & ARCHIVE_EXTRACT_ACL) {
++#if ARCHIVE_ACL_DARWIN
++ /*
++ * On MacOS, platform ACLs get stored in mac_metadata, too.
++ * If we intend to extract mac_metadata and it is present
++ * we skip extracting libarchive NFSv4 ACLs.
++ */
++ size_t metadata_size;
++
++ if ((a->flags & ARCHIVE_EXTRACT_MAC_METADATA) == 0 ||
++ archive_entry_mac_metadata(a->entry,
++ &metadata_size) == NULL || metadata_size == 0)
++#endif
++#if ARCHIVE_ACL_LIBRICHACL
++ /*
++ * RichACLs are stored in an extended attribute.
++ * If we intend to extract extended attributes and have this
++ * attribute we skip extracting libarchive NFSv4 ACLs.
++ */
++ short extract_acls = 1;
++ if (a->flags & ARCHIVE_EXTRACT_XATTR && (
++ archive_entry_acl_types(a->entry) &
++ ARCHIVE_ENTRY_ACL_TYPE_NFS4)) {
++ const char *attr_name;
++ const void *attr_value;
++ size_t attr_size;
++ int i = archive_entry_xattr_reset(a->entry);
++ while (i--) {
++ archive_entry_xattr_next(a->entry, &attr_name,
++ &attr_value, &attr_size);
++ if (attr_name != NULL && attr_value != NULL &&
++ attr_size > 0 && strcmp(attr_name,
++ "trusted.richacl") == 0) {
++ extract_acls = 0;
++ break;
++ }
++ }
++ }
++ if (extract_acls)
++#endif
++#if ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_LIBRICHACL
++ {
++#endif
+ if (archive_entry_filetype(a->entry) == AE_IFDIR)
+ a->deferred |= TODO_ACLS;
+ else
+ a->todo |= TODO_ACLS;
++#if ARCHIVE_ACL_DARWIN || ARCHIVE_ACL_LIBRICHACL
++ }
++#endif
+ }
+ if (a->flags & ARCHIVE_EXTRACT_MAC_METADATA) {
+ if (archive_entry_filetype(a->entry) == AE_IFDIR)
+@@ -1703,25 +1748,11 @@ _archive_write_disk_finish_entry(struct archive *_a)
+ */
+ if (a->todo & TODO_ACLS) {
+ int r2;
+-#ifdef HAVE_DARWIN_ACL
+- /*
+- * On Mac OS, platform ACLs are stored also in mac_metadata by
+- * the operating system. If mac_metadata is present it takes
+- * precedence and we skip extracting libarchive NFSv4 ACLs
+- */
+- const void *metadata;
+- size_t metadata_size;
+- metadata = archive_entry_mac_metadata(a->entry, &metadata_size);
+- if ((a->todo & TODO_MAC_METADATA) == 0 ||
+- metadata == NULL || metadata_size == 0) {
+-#endif
+ r2 = archive_write_disk_set_acls(&a->archive, a->fd,
+ archive_entry_pathname(a->entry),
+- archive_entry_acl(a->entry));
++ archive_entry_acl(a->entry),
++ archive_entry_mode(a->entry));
+ if (r2 < ret) ret = r2;
+-#ifdef HAVE_DARWIN_ACL
+- }
+-#endif
+ }
+
+ finish_metadata:
+@@ -2293,13 +2324,8 @@ _archive_write_disk_close(struct archive *_a)
+ if (p->fixup & TODO_MODE_BASE)
+ chmod(p->name, p->mode);
+ if (p->fixup & TODO_ACLS)
+-#ifdef HAVE_DARWIN_ACL
+- if ((p->fixup & TODO_MAC_METADATA) == 0 ||
+- p->mac_metadata == NULL ||
+- p->mac_metadata_size == 0)
+-#endif
+- archive_write_disk_set_acls(&a->archive,
+- -1, p->name, &p->acl);
++ archive_write_disk_set_acls(&a->archive, -1, p->name,
++ &p->acl, p->mode);
+ if (p->fixup & TODO_FFLAGS)
+ set_fflags_platform(a, -1, p->name,
+ p->mode, p->fflags_set, 0);
+@@ -2467,7 +2493,7 @@ fsobj_error(int *a_eno, struct archive_string *a_estr,
+ 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 +2599,7 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
+ * 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 +2608,7 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
+ 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 +2625,7 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
+ 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 +2644,7 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
+ /*
+ 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 +2656,7 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
+ tail[0] = c;
+ fsobj_error(a_eno, a_estr, 0,
+ "Cannot remove intervening "
+- "symlink %s", path);
++ "symlink ", path);
+ res = ARCHIVE_FAILED;
+ break;
+ }
+@@ -2652,7 +2678,7 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
+ } else {
+ fsobj_error(a_eno, a_estr,
+ errno,
+- "Could not stat %s", path);
++ "Could not stat ", path);
+ res = (ARCHIVE_FAILED);
+ break;
+ }
+@@ -2661,7 +2687,7 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
+ 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 +2700,14 @@ check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr,
+ 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;
+ }
+@@ -4239,5 +4265,19 @@ older(struct stat *st, struct archive_entry *entry)
+ return (0);
+ }
+
++#ifndef ARCHIVE_ACL_SUPPORT
++int
++archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
++ struct archive_acl *abstract_acl, __LA_MODE_T mode)
++{
++ (void)a; /* UNUSED */
++ (void)fd; /* UNUSED */
++ (void)name; /* UNUSED */
++ (void)abstract_acl; /* UNUSED */
++ (void)mode; /* UNUSED */
++ return (ARCHIVE_OK);
++}
++#endif
++
+ #endif /* !_WIN32 || __CYGWIN__ */
+
+--- libarchive/archive_write_disk_private.h.orig
++++ libarchive/archive_write_disk_private.h
+@@ -33,11 +33,13 @@
+ #ifndef ARCHIVE_WRITE_DISK_PRIVATE_H_INCLUDED
+ #define ARCHIVE_WRITE_DISK_PRIVATE_H_INCLUDED
+
++#include "archive_platform_acl.h"
+ #include "archive_acl_private.h"
++#include "archive_entry.h"
+
+ struct archive_write_disk;
+
+-int
+-archive_write_disk_set_acls(struct archive *, int /* fd */, const char * /* pathname */, struct archive_acl *);
++int archive_write_disk_set_acls(struct archive *, int, const char *,
++ struct archive_acl *, __LA_MODE_T);
+
+ #endif
+--- libarchive/archive_write_finish_entry.3.orig
++++ 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 @@ is called automatically by
+ 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
+--- libarchive/archive_write_format.3.orig
++++ libarchive/archive_write_format.3
+@@ -108,7 +108,6 @@ Streaming Archive Library (libarchive, -larchive)
+ 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
+--- libarchive/mtree.5.orig
++++ libarchive/mtree.5
+@@ -48,7 +48,7 @@ Leading whitespace is always ignored.
+ .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
+--- libarchive/test/test_acl_platform_nfs4.c.orig
++++ libarchive/test/test_acl_platform_nfs4.c
+@@ -26,15 +26,18 @@
+ #include "test.h"
+ __FBSDID("$FreeBSD$");
+
+-#if HAVE_POSIX_ACL || HAVE_NFS4_ACL
++#if ARCHIVE_ACL_NFS4
++#if HAVE_SYS_ACL_H
+ #define _ACL_PRIVATE
+ #include <sys/acl.h>
+-#if HAVE_DARWIN_ACL
+-#include <membership.h>
+ #endif
++#if HAVE_SYS_RICHACL_H
++#include <sys/richacl.h>
++#endif
++#if HAVE_MEMBERSHIP_H
++#include <membership.h>
+ #endif
+
+-#if HAVE_NFS4_ACL
+ struct myacl_t {
+ int type;
+ int permset;
+@@ -44,7 +47,7 @@ struct myacl_t {
+ };
+
+ static struct myacl_t acls_reg[] = {
+-#if !HAVE_DARWIN_ACL
++#if !ARCHIVE_ACL_DARWIN
+ /* For this test, we need the file owner to be able to read and write the ACL. */
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
+ ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_READ_ACL | ARCHIVE_ENTRY_ACL_WRITE_ACL | ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES,
+@@ -91,7 +94,7 @@ static struct myacl_t acls_reg[] = {
+ // ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
+ ARCHIVE_ENTRY_ACL_GROUP, 136, "group136" },
+-#if !HAVE_DARWIN_ACL
++#if !ARCHIVE_ACL_DARWIN
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
+ ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
+@@ -134,7 +137,7 @@ static const int acls_reg_cnt = (int)(sizeof(acls_reg)/sizeof(acls_reg[0]));
+
+ static struct myacl_t acls_dir[] = {
+ /* For this test, we need to be able to read and write the ACL. */
+-#if !HAVE_DARWIN_ACL
++#if !ARCHIVE_ACL_DARWIN
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_READ_ACL,
+ ARCHIVE_ENTRY_ACL_USER_OBJ, -1, ""},
+ #endif
+@@ -180,13 +183,17 @@ static struct myacl_t acls_dir[] = {
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
+ ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT,
+ ARCHIVE_ENTRY_ACL_USER, 302, "user302" },
+-#if 0
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
+- ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT,
++ ARCHIVE_ENTRY_ACL_READ_DATA |
++ ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT |
++ ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT,
+ ARCHIVE_ENTRY_ACL_USER, 303, "user303" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
+- ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY,
++ ARCHIVE_ENTRY_ACL_READ_DATA |
++ ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT |
++ ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY,
+ ARCHIVE_ENTRY_ACL_USER, 304, "user304" },
++#if !defined(ARCHIVE_ACL_SUNOS_NFS4) || defined(ACE_INHERITED_ACE)
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
+ ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_INHERITED,
+ ARCHIVE_ENTRY_ACL_USER, 305, "user305" },
+@@ -207,7 +214,7 @@ static struct myacl_t acls_dir[] = {
+ ARCHIVE_ENTRY_ACL_USER, 501, "user501" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
+ ARCHIVE_ENTRY_ACL_GROUP, 502, "group502" },
+-#if !HAVE_DARWIN_ACL
++#if !ARCHIVE_ACL_DARWIN
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
+ ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
+@@ -254,12 +261,14 @@ set_acls(struct archive_entry *ae, struct myacl_t *acls, int start, int end)
+ int i;
+
+ archive_entry_acl_clear(ae);
++#if !ARCHIVE_ACL_DARWIN
+ 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,76 +278,96 @@ set_acls(struct archive_entry *ae, struct myacl_t *acls, int start, int end)
+ }
+
+ static int
+-#ifdef HAVE_SUN_ACL
+-acl_permset_to_bitmap(uint32_t a_access_mask)
++#if ARCHIVE_ACL_SUNOS_NFS4
++acl_permset_to_bitmap(uint32_t mask)
++#elif ARCHIVE_ACL_LIBRICHACL
++acl_permset_to_bitmap(unsigned int 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 */
+- {ACE_EXECUTE, ARCHIVE_ENTRY_ACL_EXECUTE},
+- {ACE_READ_DATA, ARCHIVE_ENTRY_ACL_READ_DATA},
+- {ACE_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY},
+- {ACE_WRITE_DATA, ARCHIVE_ENTRY_ACL_WRITE_DATA},
+- {ACE_ADD_FILE, ARCHIVE_ENTRY_ACL_ADD_FILE},
+- {ACE_APPEND_DATA, ARCHIVE_ENTRY_ACL_APPEND_DATA},
+- {ACE_ADD_SUBDIRECTORY, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY},
+- {ACE_READ_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS},
+- {ACE_WRITE_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS},
+- {ACE_DELETE_CHILD, ARCHIVE_ENTRY_ACL_DELETE_CHILD},
+- {ACE_READ_ATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES},
+- {ACE_WRITE_ATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES},
+- {ACE_DELETE, ARCHIVE_ENTRY_ACL_DELETE},
+- {ACE_READ_ACL, ARCHIVE_ENTRY_ACL_READ_ACL},
+- {ACE_WRITE_ACL, ARCHIVE_ENTRY_ACL_WRITE_ACL},
+- {ACE_WRITE_OWNER, ARCHIVE_ENTRY_ACL_WRITE_OWNER},
+- {ACE_SYNCHRONIZE, ARCHIVE_ENTRY_ACL_SYNCHRONIZE}
+-#elif HAVE_DARWIN_ACL /* MacOS NFSv4 ACL permissions */
+- {ACL_READ_DATA, ARCHIVE_ENTRY_ACL_READ_DATA},
+- {ACL_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY},
+- {ACL_WRITE_DATA, ARCHIVE_ENTRY_ACL_WRITE_DATA},
+- {ACL_ADD_FILE, ARCHIVE_ENTRY_ACL_ADD_FILE},
+- {ACL_EXECUTE, ARCHIVE_ENTRY_ACL_EXECUTE},
+- {ACL_DELETE, ARCHIVE_ENTRY_ACL_DELETE},
+- {ACL_APPEND_DATA, ARCHIVE_ENTRY_ACL_APPEND_DATA},
+- {ACL_ADD_SUBDIRECTORY, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY},
+- {ACL_DELETE_CHILD, ARCHIVE_ENTRY_ACL_DELETE_CHILD},
+- {ACL_READ_ATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES},
+- {ACL_WRITE_ATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES},
+- {ACL_READ_EXTATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS},
+- {ACL_WRITE_EXTATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS},
+- {ACL_READ_SECURITY, ARCHIVE_ENTRY_ACL_READ_ACL},
+- {ACL_WRITE_SECURITY, ARCHIVE_ENTRY_ACL_WRITE_ACL},
+- {ACL_CHANGE_OWNER, ARCHIVE_ENTRY_ACL_WRITE_OWNER},
+- {ACL_SYNCHRONIZE, ARCHIVE_ENTRY_ACL_SYNCHRONIZE},
++ static struct { int portable; int machine; } perms[] = {
++#ifdef ARCHIVE_ACL_SUNOS_NFS4 /* 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},
++ {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACE_WRITE_DATA},
++ {ARCHIVE_ENTRY_ACL_ADD_FILE, ACE_ADD_FILE},
++ {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACE_APPEND_DATA},
++ {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACE_ADD_SUBDIRECTORY},
++ {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACE_READ_NAMED_ATTRS},
++ {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACE_WRITE_NAMED_ATTRS},
++ {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACE_DELETE_CHILD},
++ {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACE_READ_ATTRIBUTES},
++ {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACE_WRITE_ATTRIBUTES},
++ {ARCHIVE_ENTRY_ACL_DELETE, ACE_DELETE},
++ {ARCHIVE_ENTRY_ACL_READ_ACL, ACE_READ_ACL},
++ {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACE_WRITE_ACL},
++ {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACE_WRITE_OWNER},
++ {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACE_SYNCHRONIZE}
++#elif ARCHIVE_ACL_DARWIN /* MacOS 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},
++ {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
++ {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
++ {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
++ {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
++ {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
++ {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
++ {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
++ {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
++ {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_EXTATTRIBUTES},
++ {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_EXTATTRIBUTES},
++ {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
++#elif ARCHIVE_ACL_LIBRICHACL
++ {ARCHIVE_ENTRY_ACL_EXECUTE, RICHACE_EXECUTE},
++ {ARCHIVE_ENTRY_ACL_READ_DATA, RICHACE_READ_DATA},
++ {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, RICHACE_LIST_DIRECTORY},
++ {ARCHIVE_ENTRY_ACL_WRITE_DATA, RICHACE_WRITE_DATA},
++ {ARCHIVE_ENTRY_ACL_ADD_FILE, RICHACE_ADD_FILE},
++ {ARCHIVE_ENTRY_ACL_APPEND_DATA, RICHACE_APPEND_DATA},
++ {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, RICHACE_ADD_SUBDIRECTORY},
++ {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, RICHACE_READ_NAMED_ATTRS},
++ {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, RICHACE_WRITE_NAMED_ATTRS},
++ {ARCHIVE_ENTRY_ACL_DELETE_CHILD, RICHACE_DELETE_CHILD},
++ {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, RICHACE_READ_ATTRIBUTES},
++ {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, RICHACE_WRITE_ATTRIBUTES},
++ {ARCHIVE_ENTRY_ACL_DELETE, RICHACE_DELETE},
++ {ARCHIVE_ENTRY_ACL_READ_ACL, RICHACE_READ_ACL},
++ {ARCHIVE_ENTRY_ACL_WRITE_ACL, RICHACE_WRITE_ACL},
++ {ARCHIVE_ENTRY_ACL_WRITE_OWNER, RICHACE_WRITE_OWNER},
++ {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, RICHACE_SYNCHRONIZE}
+ #else /* FreeBSD NFSv4 ACL permissions */
+- {ACL_EXECUTE, ARCHIVE_ENTRY_ACL_EXECUTE},
+- {ACL_WRITE, ARCHIVE_ENTRY_ACL_WRITE},
+- {ACL_READ, ARCHIVE_ENTRY_ACL_READ},
+- {ACL_READ_DATA, ARCHIVE_ENTRY_ACL_READ_DATA},
+- {ACL_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY},
+- {ACL_WRITE_DATA, ARCHIVE_ENTRY_ACL_WRITE_DATA},
+- {ACL_ADD_FILE, ARCHIVE_ENTRY_ACL_ADD_FILE},
+- {ACL_APPEND_DATA, ARCHIVE_ENTRY_ACL_APPEND_DATA},
+- {ACL_ADD_SUBDIRECTORY, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY},
+- {ACL_READ_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS},
+- {ACL_WRITE_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS},
+- {ACL_DELETE_CHILD, ARCHIVE_ENTRY_ACL_DELETE_CHILD},
+- {ACL_READ_ATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES},
+- {ACL_WRITE_ATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES},
+- {ACL_DELETE, ARCHIVE_ENTRY_ACL_DELETE},
+- {ACL_READ_ACL, ARCHIVE_ENTRY_ACL_READ_ACL},
+- {ACL_WRITE_ACL, ARCHIVE_ENTRY_ACL_WRITE_ACL},
+- {ACL_WRITE_OWNER, ARCHIVE_ENTRY_ACL_WRITE_OWNER},
+- {ACL_SYNCHRONIZE, ARCHIVE_ENTRY_ACL_SYNCHRONIZE}
++ {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
++ {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
++ {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
++ {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
++ {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
++ {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
++ {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
++ {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS},
++ {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS},
++ {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
++ {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
++ {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
++ {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
++ {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL},
++ {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL},
++ {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER},
++ {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
+ #endif
+ };
+ int i, permset = 0;
+
+ for (i = 0; i < (int)(sizeof(perms)/sizeof(perms[0])); ++i)
+-#if HAVE_SUN_ACL
+- if (a_access_mask & perms[i].machine)
++#if ARCHIVE_ACL_SUNOS_NFS4 || ARCHIVE_ACL_LIBRICHACL
++ if (mask & perms[i].machine)
+ #else
+ if (acl_get_perm_np(opaque_ps, perms[i].machine))
+ #endif
+@@ -347,88 +376,70 @@ acl_permset_to_bitmap(acl_permset_t opaque_ps)
+ }
+
+ static int
+-#if HAVE_SUN_ACL
+-acl_flagset_to_bitmap(uint16_t a_flags)
++#if ARCHIVE_ACL_SUNOS_NFS4
++acl_flagset_to_bitmap(uint16_t flags)
++#elif ARCHIVE_ACL_LIBRICHACL
++acl_flagset_to_bitmap(int 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 */
+- {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},
+- {ACE_INHERITED_ACE, ARCHIVE_ENTRY_ACL_ENTRY_INHERITED}
+-#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},
+- {ACL_ENTRY_DIRECTORY_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT},
+- {ACL_ENTRY_LIMIT_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT},
+- {ACL_ENTRY_ONLY_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY}
++ static struct { int portable; int machine; } perms[] = {
++#if ARCHIVE_ACL_SUNOS_NFS4 /* Solaris NFSv4 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 ARCHIVE_ACL_DARWIN /* MacOS NFSv4 ACL inheritance flags */
++ {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED},
++ {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
++ {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
++ {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_LIMIT_INHERIT},
++ {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_ONLY_INHERIT}
++#elif ARCHIVE_ACL_LIBRICHACL
++ {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, RICHACE_FILE_INHERIT_ACE},
++ {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, RICHACE_DIRECTORY_INHERIT_ACE},
++ {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, RICHACE_NO_PROPAGATE_INHERIT_ACE},
++ {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, RICHACE_INHERIT_ONLY_ACE},
++ {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, RICHACE_INHERITED_ACE}
+ #else /* FreeBSD NFSv4 ACL inheritance flags */
+- {ACL_ENTRY_FILE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT},
+- {ACL_ENTRY_DIRECTORY_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT},
+- {ACL_ENTRY_NO_PROPAGATE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT},
+- {ACL_ENTRY_SUCCESSFUL_ACCESS, ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS},
+- {ACL_ENTRY_NO_PROPAGATE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS},
+- {ACL_ENTRY_INHERIT_ONLY, ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY},
++ {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED},
++ {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
++ {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
++ {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT},
++ {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACL_ENTRY_SUCCESSFUL_ACCESS},
++ {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACL_ENTRY_FAILED_ACCESS},
++ {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY}
+ #endif
+ };
+ int i, flagset = 0;
+
+- for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); ++i)
+-#if HAVE_SUN_ACL
+- if (a_flags & flags[i].machine)
++ for (i = 0; i < (int)(sizeof(perms)/sizeof(perms[0])); ++i)
++#if ARCHIVE_ACL_SUNOS_NFS4 || ARCHIVE_ACL_LIBRICHACL
++ if (flags & perms[i].machine)
+ #else
+- if (acl_get_flag_np(opaque_fs, flags[i].machine))
++ if (acl_get_flag_np(opaque_fs, perms[i].machine))
+ #endif
+- flagset |= flags[i].portable;
++ flagset |= perms[i].portable;
+ return flagset;
+ }
+
++#if ARCHIVE_ACL_SUNOS_NFS4
+ static int
+-#if HAVE_SUN_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_DARWIN_ACL
+- void *q;
+- uid_t ugid;
+- int r, idtype;
+-#else
+- gid_t g, *gp;
+- uid_t u, *up;
+- acl_entry_type_t entry_type;
+-#endif /* !HAVE_DARWIN_ACL */
+- acl_tag_t tag_type;
+- acl_permset_t opaque_ps;
+- acl_flagset_t opaque_fs;
+-#endif /* !HAVE_SUN_ACL */
+ int perms;
+
+-#if HAVE_SUN_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);
+-#if !HAVE_DARWIN_ACL
+- acl_get_entry_type_np(aclent, &entry_type);
+-#endif
+
+- /* translate the silly opaque permset to a bitmap */
+- acl_get_permset(aclent, &opaque_ps);
+- acl_get_flagset_np(aclent, &opaque_fs);
+- perms = acl_permset_to_bitmap(opaque_ps) | acl_flagset_to_bitmap(opaque_fs);
+-#endif
+ if (perms != myacl->permset)
+ return (0);
+
+-#if HAVE_SUN_ACL
+ switch (ace->a_type) {
+ case ACE_ACCESS_ALLOWED_ACE_TYPE:
+ if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW)
+@@ -470,7 +481,85 @@ acl_match(acl_entry_t aclent, struct myacl_t *myacl)
+ if ((uid_t)myacl->qual != ace->a_who)
+ return (0);
+ }
+-#elif HAVE_DARWIN_ACL
++ return (1);
++}
++#elif ARCHIVE_ACL_LIBRICHACL
++static int
++acl_match(struct richace *richace, struct myacl_t *myacl)
++{
++ int perms;
++
++ perms = acl_permset_to_bitmap(richace->e_mask) |
++ acl_flagset_to_bitmap(richace->e_flags);
++
++ if (perms != myacl->permset)
++ return (0);
++
++ switch (richace->e_type) {
++ case RICHACE_ACCESS_ALLOWED_ACE_TYPE:
++ if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW)
++ return (0);
++ break;
++ case RICHACE_ACCESS_DENIED_ACE_TYPE:
++ if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_DENY)
++ return (0);
++ break;
++ default:
++ return (0);
++ }
++
++ if (richace->e_flags & RICHACE_SPECIAL_WHO) {
++ switch (richace->e_id) {
++ case RICHACE_OWNER_SPECIAL_ID:
++ if (myacl->tag != ARCHIVE_ENTRY_ACL_USER_OBJ)
++ return (0);
++ break;
++ case RICHACE_GROUP_SPECIAL_ID:
++ if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP_OBJ)
++ return (0);
++ break;
++ case RICHACE_EVERYONE_SPECIAL_ID:
++ if (myacl->tag != ARCHIVE_ENTRY_ACL_EVERYONE)
++ return (0);
++ break;
++ default:
++ /* Invalid e_id */
++ return (0);
++ }
++ } else if (richace->e_flags & RICHACE_IDENTIFIER_GROUP) {
++ if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP)
++ return (0);
++ if ((gid_t)myacl->qual != richace->e_id)
++ return (0);
++ } else {
++ if (myacl->tag != ARCHIVE_ENTRY_ACL_USER)
++ return (0);
++ if ((uid_t)myacl->qual != richace->e_id)
++ return (0);
++ }
++ return (1);
++}
++#elif ARCHIVE_ACL_DARWIN
++static int
++acl_match(acl_entry_t aclent, struct myacl_t *myacl)
++{
++ void *q;
++ uid_t ugid;
++ int r, idtype;
++ acl_tag_t tag_type;
++ acl_permset_t opaque_ps;
++ acl_flagset_t opaque_fs;
++ int perms;
++
++ acl_get_tag_type(aclent, &tag_type);
++
++ /* translate the silly opaque permset to a bitmap */
++ acl_get_permset(aclent, &opaque_ps);
++ acl_get_flagset_np(aclent, &opaque_fs);
++ perms = acl_permset_to_bitmap(opaque_ps) | acl_flagset_to_bitmap(opaque_fs);
++ if (perms != myacl->permset)
++ return (0);
++
+ r = 0;
+ switch (tag_type) {
+ case ACL_EXTENDED_ALLOW:
+@@ -507,7 +596,30 @@ acl_match(acl_entry_t aclent, struct myacl_t *myacl)
+ default:
+ return (0);
+ }
+-#else /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
++ return (1);
++}
++#else /* ARCHIVE_ACL_FREEBSD_NFS4 */
++static int
++acl_match(acl_entry_t aclent, struct myacl_t *myacl)
++{
++ gid_t g, *gp;
++ uid_t u, *up;
++ acl_entry_type_t entry_type;
++ acl_tag_t tag_type;
++ acl_permset_t opaque_ps;
++ acl_flagset_t opaque_fs;
++ int perms;
++
++ acl_get_tag_type(aclent, &tag_type);
++ acl_get_entry_type_np(aclent, &entry_type);
++
++ /* translate the silly opaque permset to a bitmap */
++ acl_get_permset(aclent, &opaque_ps);
++ acl_get_flagset_np(aclent, &opaque_fs);
++ perms = acl_permset_to_bitmap(opaque_ps) | acl_flagset_to_bitmap(opaque_fs);
++ if (perms != myacl->permset)
++ return (0);
++
+ switch (entry_type) {
+ case ACL_ENTRY_TYPE_ALLOW:
+ if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW)
+@@ -559,14 +671,17 @@ acl_match(acl_entry_t aclent, struct myacl_t *myacl)
+ if (myacl->tag != ARCHIVE_ENTRY_ACL_EVERYONE) return (0);
+ break;
+ }
+-#endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
+ return (1);
+ }
++#endif /* various ARCHIVE_ACL_NFS4 implementations */
+
+ static void
+ compare_acls(
+-#if HAVE_SUN_ACL
+- acl_t *acl,
++#if ARCHIVE_ACL_SUNOS_NFS4
++ void *aclp,
++ int aclcnt,
++#elif ARCHIVE_ACL_LIBRICHACL
++ struct richacl *richacl,
+ #else
+ acl_t acl,
+ #endif
+@@ -575,38 +690,61 @@ compare_acls(
+ int *marker;
+ int matched;
+ int i, n;
+-#if HAVE_SUN_ACL
++#if ARCHIVE_ACL_SUNOS_NFS4
+ int e;
+ ace_t *acl_entry;
++#elif ARCHIVE_ACL_LIBRICHACL
++ int e;
++ struct richace *acl_entry;
++ int aclcnt;
+ #else
+ int entry_id = ACL_FIRST_ENTRY;
+ acl_entry_t acl_entry;
++#if ARCHIVE_ACL_DARWIN
++ const int acl_get_entry_ret = 0;
++#else
++ const int acl_get_entry_ret = 1;
++#endif
++#endif
++
++#if ARCHIVE_ACL_SUNOS_NFS4
++ if (aclp == NULL)
++ return;
++#elif ARCHIVE_ACL_LIBRICHACL
++ if (richacl == NULL)
++ return;
++ aclcnt = richacl->a_count;
++#else
++ if (acl == NULL)
++ return;
+ #endif
+
+ n = end - start;
+ marker = malloc(sizeof(marker[0]) * (n + 1));
+ for (i = 0; i < n; i++)
+ marker[i] = i + start;
++#if !ARCHIVE_ACL_DARWIN
+ /* 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++)
+-#elif HAVE_DARWIN_ACL
+- while (0 == acl_get_entry(acl, entry_id, &acl_entry))
++#if ARCHIVE_ACL_SUNOS_NFS4 || ARCHIVE_ACL_LIBRICHACL
++ for (e = 0; e < aclcnt; e++)
+ #else
+- while (1 == acl_get_entry(acl, entry_id, &acl_entry))
++ while (acl_get_entry_ret == acl_get_entry(acl, entry_id, &acl_entry))
+ #endif
+ {
+-#if HAVE_SUN_ACL
+- acl_entry = &((ace_t *)acl->acl_aclp)[e];
++#if ARCHIVE_ACL_SUNOS_NFS4
++ acl_entry = &((ace_t *)aclp)[e];
++#elif ARCHIVE_ACL_LIBRICHACL
++ acl_entry = &(richacl->a_entries[e]);
+ #else
+ /* After the first time... */
+ entry_id = ACL_NEXT_ENTRY;
+@@ -699,7 +837,7 @@ compare_entry_acls(struct archive_entry *ae, struct myacl_t *myacls, const char
+ }
+ free(marker);
+ }
+-#endif /* HAVE_NFS4_ACL */
++#endif /* ARCHIVE_ACL_NFS4 */
+
+ /*
+ * Verify ACL restore-to-disk. This test is Platform-specific.
+@@ -707,101 +845,36 @@ compare_entry_acls(struct archive_entry *ae, struct myacl_t *myacls, const char
+
+ DEFINE_TEST(test_acl_platform_nfs4)
+ {
+-#if !HAVE_NFS4_ACL
++#if !ARCHIVE_ACL_NFS4
+ skipping("NFS4 ACLs are not supported on this platform");
+-#else
++#else /* ARCHIVE_ACL_NFS4 */
+ 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 */
++#if ARCHIVE_ACL_DARWIN /* On MacOS we skip trivial ACLs in some tests */
+ const int regcnt = acls_reg_cnt - 4;
+ const int dircnt = acls_dir_cnt - 4;
+ #else
+ 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 ARCHIVE_ACL_SUNOS_NFS4
++ void *aclp;
++ int aclcnt;
++#elif ARCHIVE_ACL_LIBRICHACL
++ struct richacl *richacl;
++#else /* !ARCHIVE_ACL_SUNOS_NFS4 */
+ 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
+- 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);
++ assertMakeFile("pretest", 0644, "a");
+
+-#if HAVE_SUN_ACL
+- if (acl->acl_type != ACE_T) {
+- acl_free(acl);
+- skipping("NFS4 ACL is not supported on this filesystem");
++ if (setTestAcl("pretest") != ARCHIVE_TEST_ACL_TYPE_NFS4) {
++ skipping("NFS4 ACLs are not writable on this filesystem");
+ return;
+ }
+- acl_free(acl);
+-#endif
+
+ /* Create a write-to-disk object. */
+ assert(NULL != (a = archive_write_disk_new()));
+@@ -848,63 +921,115 @@ DEFINE_TEST(test_acl_platform_nfs4)
+ /* 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 ARCHIVE_ACL_SUNOS_NFS4
++ aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, "testall");
++ failure("acl(\"%s\"): errno = %d (%s)", "testall", errno,
++ strerror(errno));
++ assert(aclp != NULL);
++#elif ARCHIVE_ACL_LIBRICHACL
++ richacl = richacl_get_file("testall");
++ failure("richacl_get_file(\"%s\"): errno = %d (%s)", "testall", errno,
++ strerror(errno));
++ assert(richacl != NULL);
+ #else
+-#if HAVE_DARWIN_ACL
++#if ARCHIVE_ACL_DARWIN
+ acl = acl_get_file("testall", ACL_TYPE_EXTENDED);
+ #else
+ acl = acl_get_file("testall", ACL_TYPE_NFS4);
+ #endif
+- failure("acl_get_file(): errno = %d (%s)", errno, strerror(errno));
++ failure("acl_get_file(\"%s\"): errno = %d (%s)", "testall", errno,
++ strerror(errno));
+ assert(acl != (acl_t)NULL);
+ #endif
++#if ARCHIVE_ACL_SUNOS_NFS4
++ compare_acls(aclp, aclcnt, acls_reg, "testall", 0, regcnt);
++ free(aclp);
++ aclp = NULL;
++#elif ARCHIVE_ACL_LIBRICHACL
++ compare_acls(richacl, acls_reg, "testall", 0, regcnt);
++ richacl_free(richacl);
++#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 ARCHIVE_ACL_SUNOS_NFS4
++ aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, buff);
++ failure("acl(\"%s\"): errno = %d (%s)", buff, errno,
++ strerror(errno));
++ assert(aclp != NULL);
++#elif ARCHIVE_ACL_LIBRICHACL
++ richacl = richacl_get_file(buff);
++ /* First and last two dir do not return a richacl */
++ if ((i == 0 || i >= dircnt - 2) && richacl == NULL &&
++ errno == ENODATA)
++ continue;
++ failure("richacl_get_file(\"%s\"): errno = %d (%s)", buff,
++ errno, strerror(errno));
++ assert(richacl != NULL);
+ #else
+-#if HAVE_DARWIN_ACL
++#if ARCHIVE_ACL_DARWIN
+ acl = acl_get_file(buff, ACL_TYPE_EXTENDED);
+ #else
+ acl = acl_get_file(buff, ACL_TYPE_NFS4);
+ #endif
+- failure("acl_get_file(): errno = %d (%s)", errno,
++ failure("acl_get_file(\"%s\"): errno = %d (%s)", buff, errno,
+ strerror(errno));
+ assert(acl != (acl_t)NULL);
+ #endif
++#if ARCHIVE_ACL_SUNOS_NFS4
++ compare_acls(aclp, aclcnt, acls_dir, buff, i, i + 1);
++ free(aclp);
++ aclp = NULL;
++#elif ARCHIVE_ACL_LIBRICHACL
++ compare_acls(richacl, acls_dir, buff, i, i + 1);
++ richacl_free(richacl);
++#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 ARCHIVE_ACL_SUNOS_NFS4
++ aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, "dirall");
++ failure("acl(\"%s\"): errno = %d (%s)", "dirall", errno,
++ strerror(errno));
++ assert(aclp != NULL);
++#elif ARCHIVE_ACL_LIBRICHACL
++ richacl = richacl_get_file("dirall");
++ failure("richacl_get_file(\"%s\"): errno = %d (%s)", "dirall",
++ errno, strerror(errno));
++ assert(richacl != NULL);
+ #else
+-#if HAVE_DARWIN_ACL
++#if ARCHIVE_ACL_DARWIN
+ acl = acl_get_file("dirall", ACL_TYPE_EXTENDED);
+ #else
+ acl = acl_get_file("dirall", ACL_TYPE_NFS4);
+ #endif
+- failure("acl_get_file(): errno = %d (%s)", errno, strerror(errno));
++ failure("acl_get_file(\"%s\"): errno = %d (%s)", "dirall", errno,
++ strerror(errno));
+ assert(acl != (acl_t)NULL);
+ #endif
++#if ARCHIVE_ACL_SUNOS_NFS4
++ compare_acls(aclp, aclcnt, acls_dir, "dirall", 0, dircnt);
++ free(aclp);
++ aclp = NULL;
++#elif ARCHIVE_ACL_LIBRICHACL
++ compare_acls(richacl, acls_dir, "dirall", 0, dircnt);
++ richacl_free(richacl);
++#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();
+@@ -929,5 +1054,5 @@ DEFINE_TEST(test_acl_platform_nfs4)
+ compare_entry_acls(ae, acls_dir, "dirall", 0, acls_dir_cnt);
+ archive_entry_free(ae);
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+-#endif /* HAVE_NFS4_ACL */
++#endif /* ARCHIVE_ACL_NFS4 */
+ }
+--- libarchive/test/test_acl_platform_posix1e.c.orig
++++ libarchive/test/test_acl_platform_posix1e.c
+@@ -26,7 +26,7 @@
+ #include "test.h"
+ __FBSDID("$FreeBSD: head/lib/libarchive/test/test_acl_freebsd.c 189427 2009-03-06 04:21:23Z kientzle $");
+
+-#if HAVE_POSIX_ACL || HAVE_SUN_ACL
++#if ARCHIVE_ACL_POSIX1E
+ #include <sys/acl.h>
+ #if HAVE_ACL_GET_PERM
+ #include <acl/libacl.h>
+@@ -55,18 +55,18 @@ static struct archive_test_acl_t acls2[] = {
+ };
+
+ static int
+-#if HAVE_SUN_ACL
++#if ARCHIVE_ACL_SUNOS
+ acl_entry_get_perm(aclent_t *aclent)
+ #else
+ acl_entry_get_perm(acl_entry_t aclent)
+ #endif
+ {
+ int permset = 0;
+-#if HAVE_POSIX_ACL
++#if ARCHIVE_ACL_FREEBSD || ARCHIVE_ACL_LIBACL
+ acl_permset_t opaque_ps;
+ #endif
+
+-#if HAVE_SUN_ACL
++#if ARCHIVE_ACL_SUNOS
+ if (aclent->a_perm & 1)
+ permset |= ARCHIVE_ENTRY_ACL_EXECUTE;
+ if (aclent->a_perm & 2)
+@@ -127,114 +127,108 @@ acl_get_specific_entry(acl_t acl, acl_tag_t requested_tag_type, int requested_ta
+ }
+ #endif
+
++#if ARCHIVE_ACL_SUNOS
+ static int
+-#if HAVE_SUN_ACL
+ acl_match(aclent_t *aclent, struct archive_test_acl_t *myacl)
+-#else
++{
++
++ if (myacl->permset != acl_entry_get_perm(aclent))
++ return (0);
++
++ switch (aclent->a_type) {
++ case DEF_USER_OBJ:
++ case USER_OBJ:
++ if (myacl->tag != ARCHIVE_ENTRY_ACL_USER_OBJ) return (0);
++ break;
++ if (myacl->tag != ARCHIVE_ENTRY_ACL_USER)
++ return (0);
++ if ((uid_t)myacl->qual != aclent->a_id)
++ return (0);
++ break;
++ case DEF_GROUP_OBJ:
++ case GROUP_OBJ:
++ if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP_OBJ) return (0);
++ break;
++ case DEF_GROUP:
++ case GROUP:
++ if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP)
++ return (0);
++ if ((gid_t)myacl->qual != aclent->a_id)
++ return (0);
++ break;
++ case DEF_CLASS_OBJ:
++ case CLASS_OBJ:
++ if (myacl->tag != ARCHIVE_ENTRY_ACL_MASK) return (0);
++ break;
++ case DEF_OTHER_OBJ:
++ case OTHER_OBJ:
++ if (myacl->tag != ARCHIVE_ENTRY_ACL_OTHER) return (0);
++ break;
++ }
++ return (1);
++}
++
++#else /* ARCHIVE_ACL_FREEBSD || ARCHIVE_ACL_LIBACL */
++static int
+ acl_match(acl_entry_t aclent, struct archive_test_acl_t *myacl)
+-#endif
+ {
+-#if HAVE_POSIX_ACL
+ gid_t g, *gp;
+ uid_t u, *up;
+ acl_tag_t tag_type;
+-#endif
+
+ if (myacl->permset != acl_entry_get_perm(aclent))
+ return (0);
+
+-#if HAVE_SUN_ACL
+- switch (aclent->a_type)
+-#else
+ acl_get_tag_type(aclent, &tag_type);
+- switch (tag_type)
+-#endif
+- {
+-#if HAVE_SUN_ACL
+- case DEF_USER_OBJ:
+- case USER_OBJ:
+-#else
++ switch (tag_type) {
+ case ACL_USER_OBJ:
+-#endif
+ if (myacl->tag != ARCHIVE_ENTRY_ACL_USER_OBJ) return (0);
+ break;
+-#if HAVE_SUN_ACL
+- case DEF_USER:
+- case USER:
+-#else
+ case ACL_USER:
+-#endif
+ if (myacl->tag != ARCHIVE_ENTRY_ACL_USER)
+ return (0);
+-#if HAVE_SUN_ACL
+- if ((uid_t)myacl->qual != aclent->a_id)
+- return (0);
+-#else
+ up = acl_get_qualifier(aclent);
+ u = *up;
+ acl_free(up);
+ if ((uid_t)myacl->qual != u)
+ return (0);
+-#endif
+ break;
+-#if HAVE_SUN_ACL
+- case DEF_GROUP_OBJ:
+- case GROUP_OBJ:
+-#else
+ case ACL_GROUP_OBJ:
+-#endif
+ if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP_OBJ) return (0);
+ break;
+-#if HAVE_SUN_ACL
+- case DEF_GROUP:
+- case GROUP:
+-#else
+ case ACL_GROUP:
+-#endif
+ if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP)
+ return (0);
+-#if HAVE_SUN_ACL
+- if ((gid_t)myacl->qual != aclent->a_id)
+- return (0);
+-#else
+ gp = acl_get_qualifier(aclent);
+ g = *gp;
+ acl_free(gp);
+ if ((gid_t)myacl->qual != g)
+ return (0);
+-#endif
+ break;
+-#if HAVE_SUN_ACL
+- case DEF_CLASS_OBJ:
+- case CLASS_OBJ:
+-#else
+ case ACL_MASK:
+-#endif
+ if (myacl->tag != ARCHIVE_ENTRY_ACL_MASK) return (0);
+ break;
+-#if HAVE_SUN_ACL
+- case DEF_OTHER_OBJ:
+- case OTHER_OBJ:
+-#else
+ case ACL_OTHER:
+-#endif
+ if (myacl->tag != ARCHIVE_ENTRY_ACL_OTHER) return (0);
+ break;
+ }
+ return (1);
+ }
++#endif
+
+ static void
+-#if HAVE_SUN_ACL
+-compare_acls(acl_t *acl, struct archive_test_acl_t *myacls, int n)
++compare_acls(
++#if ARCHIVE_ACL_SUNOS
++ void *aclp, int aclcnt,
+ #else
+-compare_acls(acl_t acl, struct archive_test_acl_t *myacls, int n)
++ acl_t acl,
+ #endif
++ struct archive_test_acl_t *myacls, int n)
+ {
+ int *marker;
+ int matched;
+ int i;
+-#if HAVE_SUN_ACL
++#if ARCHIVE_ACL_SUNOS
+ int e;
+ aclent_t *acl_entry;
+ #else
+@@ -253,9 +247,9 @@ compare_acls(acl_t acl, struct archive_test_acl_t *myacls, int n)
+ * 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++) {
+- acl_entry = &((aclent_t *)acl->acl_aclp)[e];
++#if ARCHIVE_ACL_SUNOS
++ 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... */
+@@ -288,99 +282,33 @@ compare_acls(acl_t acl, struct archive_test_acl_t *myacls, int n)
+ }
+ free(marker);
+ }
+-
+ #endif
+
+-
+ /*
+ * Verify ACL restore-to-disk. This test is Platform-specific.
+ */
+
+ DEFINE_TEST(test_acl_platform_posix1e_restore)
+ {
+-#if !HAVE_SUN_ACL && !HAVE_POSIX_ACL
++#if !ARCHIVE_ACL_POSIX1E
+ skipping("POSIX.1e ACLs are not supported on this platform");
+-#else /* HAVE_SUN_ACL || HAVE_POSIX_ACL */
++#else /* ARCHIVE_ACL_POSIX1E */
+ struct stat st;
+ struct archive *a;
+ struct archive_entry *ae;
+- int n, fd;
+- char *func;
+-#if HAVE_SUN_ACL
+- acl_t *acl, *acl2;
++#if ARCHIVE_ACL_SUNOS
++ 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
+-
+- /* 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);
+- 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);
++ assertMakeFile("pretest", 0644, "a");
+
+- if (acl2->acl_type != ACLENT_T) {
+- acl_free(acl2);
+- skipping("POSIX.1e ACLs are not supported on this filesystem");
++ if (setTestAcl("pretest") != ARCHIVE_TEST_ACL_TYPE_POSIX1E) {
++ skipping("POSIX.1e ACLs are not writable 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()));
+@@ -404,18 +332,25 @@ DEFINE_TEST(test_acl_platform_posix1e_restore)
+ /* Verify the data on disk. */
+ 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);
++#if ARCHIVE_ACL_SUNOS
++ 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 ARCHIVE_ACL_SUNOS
++ 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 /* HAVE_SUN_ACL || HAVE_POSIX_ACL */
++#endif
++
++#endif /* ARCHIVE_ACL_POSIX1E */
+ }
+
+ /*
+@@ -423,16 +358,17 @@ DEFINE_TEST(test_acl_platform_posix1e_restore)
+ */
+ DEFINE_TEST(test_acl_platform_posix1e_read)
+ {
+-#if !HAVE_SUN_ACL && !HAVE_POSIX_ACL
++#if !ARCHIVE_ACL_POSIX1E
+ skipping("POSIX.1e ACLs are not supported on this platform");
+-#else
++#else /* ARCHIVE_ACL_POSIX1E */
+ struct archive *a;
+ struct archive_entry *ae;
+ int n, fd, flags, dflags;
+ char *func, *acl_text;
+ const char *acl1_text, *acl2_text, *acl3_text;
+-#if HAVE_SUN_ACL
+- acl_t *acl, *acl1, *acl2, *acl3;
++#if ARCHIVE_ACL_SUNOS
++ void *aclp;
++ int aclcnt;
+ #else
+ acl_t acl1, acl2, acl3;
+ #endif
+@@ -444,16 +380,21 @@ DEFINE_TEST(test_acl_platform_posix1e_read)
+ */
+
+ /* Create a test file f1 with acl1 */
+-#if HAVE_SUN_ACL
++#if ARCHIVE_ACL_SUNOS
+ acl1_text = "user::rwx,"
+ "group::rwx,"
+ "other:rwx,"
+ "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 +409,36 @@ DEFINE_TEST(test_acl_platform_posix1e_read)
+ fd = open("f1", O_WRONLY | O_CREAT | O_EXCL, 0777);
+ failure("Could not create test file?!");
+ if (!assert(fd >= 0)) {
++#if !ARCHIVE_ACL_SUNOS
+ acl_free(acl1);
++#endif
+ return;
+ }
+-#if HAVE_SUN_ACL
++#if ARCHIVE_ACL_SUNOS
+ /* 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 !ARCHIVE_ACL_SUNOS
+ acl_free(acl1);
++#endif
+
+ if (n != 0) {
+-#if HAVE_SUN_ACL
+- if (errno == ENOSYS)
++#if ARCHIVE_ACL_SUNOS
++ if (errno == ENOSYS || errno == ENOTSUP)
+ #else
+ if (errno == EOPNOTSUPP || errno == EINVAL)
+ #endif
+@@ -530,16 +466,21 @@ DEFINE_TEST(test_acl_platform_posix1e_read)
+ * to read ACLs, resulting in reading the ACL from a like-named
+ * file in the wrong directory.
+ */
+-#if HAVE_SUN_ACL
++#if ARCHIVE_ACL_SUNOS
+ acl2_text = "user::rwx,"
+ "group::rwx,"
+ "other:---,"
+ "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 +495,19 @@ DEFINE_TEST(test_acl_platform_posix1e_read)
+ fd = open("d/f1", O_WRONLY | O_CREAT | O_EXCL, 0777);
+ failure("Could not create test file?!");
+ if (!assert(fd >= 0)) {
++#if !ARCHIVE_ACL_SUNOS
+ acl_free(acl2);
++#endif
+ return;
+ }
+-#if HAVE_SUN_ACL
+- func = "facl_set()";
+- n = facl_set(fd, acl2);
++#if ARCHIVE_ACL_SUNOS
++ 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));
+@@ -574,7 +517,7 @@ DEFINE_TEST(test_acl_platform_posix1e_read)
+ /* Create nested directory d2 with default ACLs */
+ assertMakeDir("d/d2", 0755);
+
+-#if HAVE_SUN_ACL
++#if ARCHIVE_ACL_SUNOS
+ acl3_text = "user::rwx,"
+ "group::r-x,"
+ "other:r-x,"
+@@ -587,9 +530,20 @@ DEFINE_TEST(test_acl_platform_posix1e_read)
+ "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"
+@@ -602,15 +556,14 @@ DEFINE_TEST(test_acl_platform_posix1e_read)
+ assert((void *)acl3 != NULL);
+ #endif
+
+-#if HAVE_SUN_ACL
+- func = "acl_set()";
+- n = acl_set("d/d2", acl3);
++#if ARCHIVE_ACL_SUNOS
++ 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);
+
+@@ -619,7 +572,7 @@ DEFINE_TEST(test_acl_platform_posix1e_read)
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, "."));
+ assert(NULL != (ae = archive_entry_new()));
+
+-#if HAVE_SUN_ACL
++#if ARCHIVE_ACL_SUNOS
+ flags = ARCHIVE_ENTRY_ACL_TYPE_POSIX1E
+ | ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA
+ | ARCHIVE_ENTRY_ACL_STYLE_SOLARIS;
+@@ -649,5 +602,5 @@ DEFINE_TEST(test_acl_platform_posix1e_read)
+
+ archive_entry_free(ae);
+ assertEqualInt(ARCHIVE_OK, archive_free(a));
+-#endif
++#endif /* ARCHIVE_ACL_POSIX1E */
+ }
+--- libarchive/test/test_read_disk_directory_traversals.c.orig
++++ libarchive/test/test_read_disk_directory_traversals.c
+@@ -1231,8 +1231,8 @@ test_restore_atime(void)
+ * 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 @@ test_nodump(void)
+ 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);
+--- tar/bsdtar.1.orig
++++ 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 @@ This is the reverse of
+ .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 @@ This option suppresses these behaviors.
+ (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
+--- tar/bsdtar.c.orig
++++ tar/bsdtar.c
+@@ -118,11 +118,11 @@ need_report(void)
+ }
+ #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 \
+--- tar/bsdtar.h.orig
++++ tar/bsdtar.h
+@@ -189,7 +189,7 @@ void do_chdir(struct bsdtar *);
+ 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_r(struct bsdtar *bsdtar);
+ 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 *);
+--- tar/test/CMakeLists.txt.orig
++++ tar/test/CMakeLists.txt
+@@ -34,9 +34,11 @@ IF(ENABLE_TAR AND ENABLE_TEST)
+ 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,16 @@ IF(ENABLE_TAR AND ENABLE_TEST)
+ # Register target
+ #
+ ADD_EXECUTABLE(bsdtar_test ${bsdtar_test_SOURCES})
++ IF(ENABLE_ACL)
++ SET(TEST_ACL_LIBS "")
++ IF(HAVE_LIBACL)
++ LIST(APPEND TEST_ACL_LIBS ${ACL_LIBRARY})
++ ENDIF(HAVE_LIBACL)
++ IF(HAVE_LIBRICHACL)
++ LIST(APPEND TEST_ACL_LIBS ${RICHACL_LIBRARY})
++ ENDIF(HAVE_LIBRICHACL)
++ TARGET_LINK_LIBRARIES(bsdtar_test ${TEST_ACL_LIBS})
++ ENDIF(ENABLE_ACL)
+ SET_PROPERTY(TARGET bsdtar_test PROPERTY COMPILE_DEFINITIONS LIST_H)
+
+ #
+--- /dev/null
++++ 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 */
++}
+--- /dev/null
++++ 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");
++}
+--- tar/test/test_option_nodump.c.orig
++++ tar/test/test_option_nodump.c
+@@ -36,7 +36,7 @@ DEFINE_TEST(test_option_nodump)
+ 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",
+--- test_utils/test_common.h.orig
++++ 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
+@@ -121,31 +127,10 @@
+ #define O_BINARY 0
+ #endif
+
+-/*
+- * If this platform has <sys/acl.h>, acl_create(), acl_init(),
+- * acl_set_file(), and ACL_USER, we assume it has the rest of the
+- * POSIX.1e draft functions used in archive_read_extract.c.
+- */
+-#if HAVE_SYS_ACL_H && HAVE_ACL_CREATE_ENTRY && HAVE_ACL_INIT && HAVE_ACL_SET_FILE
+-#if HAVE_ACL_USER
+-#define HAVE_POSIX_ACL 1
+-#elif HAVE_ACL_TYPE_EXTENDED
+-#define HAVE_DARWIN_ACL 1
+-#endif
+-#endif
+-
+-/*
+- * If this platform has <sys/acl.h>, acl_get(), facl_get(), acl_set(),
+- * facl_set() and types aclent_t and ace_t it uses Solaris-style ACL functions
+- */
+-#if HAVE_SYS_ACL_H && HAVE_ACL_GET && HAVE_FACL_GET && HAVE_ACL_SET && HAVE_FACL_SET && HAVE_ACLENT_T && HAVE_ACE_T
+-#define HAVE_SUN_ACL 1
+-#endif
++#include "archive_platform_acl.h"
++#define ARCHIVE_TEST_ACL_TYPE_POSIX1E 1
++#define ARCHIVE_TEST_ACL_TYPE_NFS4 2
+
+-/* Define if platform supports NFSv4 ACLs */
+-#if (HAVE_POSIX_ACL && HAVE_ACL_TYPE_NFS4) || HAVE_SUN_ACL || HAVE_DARWIN_ACL
+-#define HAVE_NFS4_ACL 1
+-#endif
+
+ /*
+ * Redefine DEFINE_TEST for use in defining the test functions.
+@@ -158,6 +143,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 +227,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 +256,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 +288,8 @@ int assertion_make_dir(const char *, int, const char *, int);
+ int assertion_make_file(const char *, int, const char *, int, int, const void *);
+ int assertion_make_hardlink(const char *, int, const char *newpath, const char *);
+ int assertion_make_symlink(const char *, int, const char *newpath, const char *);
+-int assertion_nodump(const char *, int, const char *);
+ int assertion_non_empty_file(const char *, int, const char *);
++int assertion_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 +340,17 @@ int canXz(void);
+ /* 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 ARCHIVE_ACL_SUNOS
++/* 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, ...);
+--- test_utils/test_main.c.orig
++++ test_utils/test_main.c
+@@ -56,6 +56,24 @@
+ #include <stdarg.h>
+ #include <time.h>
+
++#ifdef HAVE_SIGNAL_H
++#endif
++#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
++#ifdef HAVE_SYS_RICHACL_H
++#include <sys/richacl.h>
++#endif
++#if HAVE_MEMBERSHIP_H
++#include <membership.h>
++#endif
++
+ /*
+ *
+ * Windows support routines
+@@ -1883,9 +1901,103 @@ assertion_utimes(const char *file, int line,
+ #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 +2368,10 @@ canXz(void)
+ /*
+ * 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 +2382,10 @@ canNodump(void)
+ 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 +2436,250 @@ canNodump(void)
+ if (flags & EXT2_NODUMP_FL)
+ #endif
+ return (1);
++#endif
+ return (0);
+ }
+
+-#else
+-
+-int
+-canNodump()
++#if ARCHIVE_ACL_SUNOS
++/* Fetch ACLs on Solaris using acl() or facl() */
++void *
++sunacl_get(int cmd, int *aclcnt, int fd, const char *path)
+ {
+- return (0);
++ int cnt, cntcmd;
++ size_t size;
++ void *aclp;
++
++ if (cmd == GETACL) {
++ cntcmd = GETACLCNT;
++ size = sizeof(aclent_t);
++ }
++#if ARCHIVE_ACL_SUNOS_NFS4
++ 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 /* ARCHIVE_ACL_SUNOS */
++
++/*
++ * 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 ARCHIVE_ACL_SUPPORT
++ int r = 1;
++#if ARCHIVE_ACL_LIBACL || ARCHIVE_ACL_FREEBSD || ARCHIVE_ACL_DARWIN
++ acl_t acl;
++#endif
++#if ARCHIVE_ACL_LIBRICHACL
++ struct richacl *richacl;
++#endif
++#if ARCHIVE_ACL_LIBACL || ARCHIVE_ACL_FREEBSD
++ const char *acltext_posix1e = "user:1:rw-,"
++ "group:15:r-x,"
++ "user::rwx,"
++ "group::rwx,"
++ "other::r-x,"
++ "mask::rwx";
++#elif ARCHIVE_ACL_SUNOS /* 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 ARCHIVE_ACL_FREEBSD /* 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 ARCHIVE_ACL_LIBRICHACL
++ const char *acltext_nfs4 = "owner:rwpxaARWcCoS::mask,"
++ "group:rwpxaRcS::mask,"
++ "other:rxaRcS::mask,"
++ "user:1:rwpaRcS::allow,"
++ "group:15:rxaRcS::allow,"
++ "owner@:rwpxaARWcCoS::allow,"
++ "group@:rwpxaRcS::allow,"
++ "everyone@:rxaRcS::allow";
++#elif ARCHIVE_ACL_SUNOS_NFS4 /* 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 ARCHIVE_ACL_DARWIN /* 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 /* ARCHIVE_ACL_DARWIN */
+
++#if ARCHIVE_ACL_FREEBSD
++ acl = acl_from_text(acltext_nfs4);
++ failure("acl_from_text() error: %s", strerror(errno));
++ if (assert(acl != NULL) == 0)
++ return (0);
++#elif ARCHIVE_ACL_LIBRICHACL
++ richacl = richacl_from_text(acltext_nfs4, NULL, NULL);
++ failure("richacl_from_text() error: %s", strerror(errno));
++ if (assert(richacl != NULL) == 0)
++ return (0);
++#elif ARCHIVE_ACL_DARWIN
++ 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 /* ARCHIVE_ACL_DARWIN */
++
++#if ARCHIVE_ACL_NFS4
++#if ARCHIVE_ACL_FREEBSD
++ r = acl_set_file(path, ACL_TYPE_NFS4, acl);
++ acl_free(acl);
++#elif ARCHIVE_ACL_LIBRICHACL
++ r = richacl_set_file(path, richacl);
++ richacl_free(richacl);
++#elif ARCHIVE_ACL_SUNOS_NFS4
++ r = acl(path, ACE_SETACL,
++ (int)(sizeof(aclp_nfs4)/sizeof(aclp_nfs4[0])), aclp_nfs4);
++#elif ARCHIVE_ACL_DARWIN
++ r = acl_set_file(path, ACL_TYPE_EXTENDED, acl);
++ acl_free(acl);
++#endif
++ if (r == 0)
++ return (ARCHIVE_TEST_ACL_TYPE_NFS4);
++#endif /* ARCHIVE_ACL_NFS4 */
++
++#if ARCHIVE_ACL_POSIX1E
++#if ARCHIVE_ACL_FREEBSD || ARCHIVE_ACL_LIBACL
++ 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 ARCHIVE_ACL_SUNOS
++ 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 /* ARCHIVE_ACL_POSIX1E */
++#if ARCHIVE_ACL_DARWIN
++testacl_free:
++ acl_free(acl);
++#endif
++#endif /* ARCHIVE_ACL_SUPPORT */
++ (void)path; /* UNUSED */
++ return (0);
++}
+
+ /*
+ * Sleep as needed; useful for verifying disk timestamp changes by
diff --git libarchive/files/patch-Makefile.am.diff libarchive/files/patch-Makefile.am.diff
new file mode 100644
index 0000000000..05e51c0eb0
-
|
+
|
|
| 1 | --- Makefile.am.orig |
| 2 | +++ Makefile.am |
| 3 | @@ -23,7 +23,7 @@ |
| 4 | DISTCHECK_CONFIGURE_FLAGS = --enable-bsdtar --enable-bsdcpio |
| 5 | # The next line is commented out by default in shipping libarchive releases. |
| 6 | # It is uncommented by default in trunk. |
| 7 | -DEV_CFLAGS=-Werror -Wextra -Wunused -Wshadow -Wmissing-prototypes -Wcast-qual -g |
| 8 | +# DEV_CFLAGS=-Werror -Wextra -Wunused -Wshadow -Wmissing-prototypes -Wcast-qual -g |
| 9 | AM_CFLAGS=$(DEV_CFLAGS) |
| 10 | PLATFORMCPPFLAGS = @PLATFORMCPPFLAGS@ |
| 11 | AM_CPPFLAGS=$(PLATFORMCPPFLAGS) |