From 11f3dcb04887fccf38a8eda19d498bf7a5060486 Mon Sep 17 00:00:00 2001
From: LibArchive Upstream <libarchive-discuss@googlegroups.com>
Date: Sun, 9 Jul 2017 19:38:04 -0700
Subject: LibArchive 2017-07-09 (98a69539)

Code extracted from:

    https://github.com/libarchive/libarchive.git

at commit 98a695399e8e7420635a5448aecde8b0a82fb83a (v3.3.2).
---
 CMakeLists.txt                                     |  410 +++++--
 build/cmake/config.h.in                            |   92 +-
 build/version                                      |    2 +-
 libarchive/CMakeLists.txt                          |   15 +-
 libarchive/archive.h                               |    4 +-
 libarchive/archive_check_magic.c                   |    2 +-
 libarchive/archive_disk_acl_darwin.c               |  559 +++++++++
 libarchive/archive_disk_acl_freebsd.c              |  700 +++++++++++
 libarchive/archive_disk_acl_linux.c                |  743 +++++++++++
 libarchive/archive_disk_acl_sunos.c                |  821 +++++++++++++
 libarchive/archive_entry.3                         |    2 +-
 libarchive/archive_entry.c                         |   31 +-
 libarchive/archive_entry.h                         |    2 +-
 libarchive/archive_entry_acl.3                     |   10 +-
 libarchive/archive_entry_paths.3                   |   12 +-
 libarchive/archive_entry_perms.3                   |    4 +-
 libarchive/archive_entry_sparse.c                  |    4 +-
 libarchive/archive_getdate.c                       |    2 +-
 libarchive/archive_openssl_hmac_private.h          |    2 +-
 libarchive/archive_pack_dev.c                      |    2 +-
 libarchive/archive_platform.h                      |   26 -
 libarchive/archive_platform_acl.h                  |   49 +
 libarchive/archive_platform_xattr.h                |   41 +
 libarchive/archive_random.c                        |    5 +-
 libarchive/archive_read.c                          |    3 +-
 libarchive/archive_read_disk.3                     |   72 +-
 libarchive/archive_read_disk_entry_from_file.c     | 1285 +++-----------------
 libarchive/archive_read_disk_private.h             |    9 +
 libarchive/archive_read_format.3                   |    6 +-
 libarchive/archive_read_open.3                     |    4 +-
 libarchive/archive_read_support_filter_lz4.c       |    6 +-
 libarchive/archive_read_support_format_cab.c       |  156 +--
 libarchive/archive_read_support_format_cpio.c      |    2 +-
 libarchive/archive_read_support_format_iso9660.c   |    5 +-
 libarchive/archive_read_support_format_lha.c       |    2 +-
 libarchive/archive_read_support_format_mtree.c     |  180 +--
 libarchive/archive_read_support_format_rar.c       |    2 +-
 libarchive/archive_read_support_format_tar.c       |   18 +-
 libarchive/archive_read_support_format_warc.c      |    9 +-
 libarchive/archive_read_support_format_zip.c       |   39 +-
 libarchive/archive_string.c                        |    3 +-
 libarchive/archive_string_sprintf.c                |    2 +-
 libarchive/archive_util.c                          |   88 +-
 libarchive/archive_version_details.c               |  133 ++
 libarchive/archive_write_add_filter.c              |    2 +-
 libarchive/archive_write_add_filter_by_name.c      |    2 +-
 libarchive/archive_write_add_filter_lz4.c          |    2 +-
 libarchive/archive_write_add_filter_program.c      |    2 +-
 libarchive/archive_write_data.3                    |   24 +-
 libarchive/archive_write_disk.3                    |  185 +--
 libarchive/archive_write_disk_acl.c                |  654 ----------
 libarchive/archive_write_disk_posix.c              |  296 +++--
 libarchive/archive_write_disk_private.h            |    6 +-
 libarchive/archive_write_finish_entry.3            |    5 +-
 libarchive/archive_write_format.3                  |    1 -
 libarchive/archive_write_set_format.c              |    2 +-
 libarchive/archive_write_set_format_by_name.c      |    2 +-
 .../archive_write_set_format_filter_by_ext.c       |    2 +-
 libarchive/archive_write_set_format_pax.c          |   17 +-
 libarchive/archive_write_set_format_warc.c         |    2 +-
 libarchive/config_freebsd.h                        |  351 ++++--
 libarchive/libarchive_changes.3                    |    1 +
 libarchive/mtree.5                                 |    2 +-
 libarchive/xxhash.c                                |   12 +-
 64 files changed, 4373 insertions(+), 2761 deletions(-)
 create mode 100644 libarchive/archive_disk_acl_darwin.c
 create mode 100644 libarchive/archive_disk_acl_freebsd.c
 create mode 100644 libarchive/archive_disk_acl_linux.c
 create mode 100644 libarchive/archive_disk_acl_sunos.c
 create mode 100644 libarchive/archive_platform_acl.h
 create mode 100644 libarchive/archive_platform_xattr.h
 create mode 100644 libarchive/archive_version_details.c
 delete mode 100644 libarchive/archive_write_disk_acl.c

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1ca9d8f..73bf07b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -552,6 +552,7 @@ LA_CHECK_INCLUDE_FILE("sys/types.h" HAVE_SYS_TYPES_H)
 
 # Alphabetize the rest unless there's a compelling reason
 LA_CHECK_INCLUDE_FILE("acl/libacl.h" HAVE_ACL_LIBACL_H)
+LA_CHECK_INCLUDE_FILE("attr/xattr.h" HAVE_ATTR_XATTR_H)
 LA_CHECK_INCLUDE_FILE("ctype.h" HAVE_CTYPE_H)
 LA_CHECK_INCLUDE_FILE("copyfile.h" HAVE_COPYFILE_H)
 LA_CHECK_INCLUDE_FILE("direct.h" HAVE_DIRECT_H)
@@ -579,6 +580,7 @@ int main(void) { return FS_IOC_GETFLAGS; }" HAVE_WORKING_FS_IOC_GETFLAGS)
 
 LA_CHECK_INCLUDE_FILE("linux/magic.h" HAVE_LINUX_MAGIC_H)
 LA_CHECK_INCLUDE_FILE("locale.h" HAVE_LOCALE_H)
+LA_CHECK_INCLUDE_FILE("membership.h" HAVE_MEMBERSHIP_H)
 LA_CHECK_INCLUDE_FILE("memory.h" HAVE_MEMORY_H)
 LA_CHECK_INCLUDE_FILE("paths.h" HAVE_PATHS_H)
 LA_CHECK_INCLUDE_FILE("poll.h" HAVE_POLL_H)
@@ -596,11 +598,13 @@ LA_CHECK_INCLUDE_FILE("string.h" HAVE_STRING_H)
 LA_CHECK_INCLUDE_FILE("strings.h" HAVE_STRINGS_H)
 LA_CHECK_INCLUDE_FILE("sys/acl.h" HAVE_SYS_ACL_H)
 LA_CHECK_INCLUDE_FILE("sys/cdefs.h" HAVE_SYS_CDEFS_H)
+LA_CHECK_INCLUDE_FILE("sys/extattr.h" HAVE_SYS_EXTATTR_H)
 LA_CHECK_INCLUDE_FILE("sys/ioctl.h" HAVE_SYS_IOCTL_H)
 LA_CHECK_INCLUDE_FILE("sys/mkdev.h" HAVE_SYS_MKDEV_H)
 LA_CHECK_INCLUDE_FILE("sys/mount.h" HAVE_SYS_MOUNT_H)
 LA_CHECK_INCLUDE_FILE("sys/param.h" HAVE_SYS_PARAM_H)
 LA_CHECK_INCLUDE_FILE("sys/poll.h" HAVE_SYS_POLL_H)
+LA_CHECK_INCLUDE_FILE("sys/richacl.h" HAVE_SYS_RICHACL_H)
 LA_CHECK_INCLUDE_FILE("sys/select.h" HAVE_SYS_SELECT_H)
 LA_CHECK_INCLUDE_FILE("sys/stat.h" HAVE_SYS_STAT_H)
 LA_CHECK_INCLUDE_FILE("sys/statfs.h" HAVE_SYS_STATFS_H)
@@ -610,6 +614,7 @@ LA_CHECK_INCLUDE_FILE("sys/utime.h" HAVE_SYS_UTIME_H)
 LA_CHECK_INCLUDE_FILE("sys/utsname.h" HAVE_SYS_UTSNAME_H)
 LA_CHECK_INCLUDE_FILE("sys/vfs.h" HAVE_SYS_VFS_H)
 LA_CHECK_INCLUDE_FILE("sys/wait.h" HAVE_SYS_WAIT_H)
+LA_CHECK_INCLUDE_FILE("sys/xattr.h" HAVE_SYS_XATTR_H)
 LA_CHECK_INCLUDE_FILE("time.h" HAVE_TIME_H)
 LA_CHECK_INCLUDE_FILE("unistd.h" HAVE_UNISTD_H)
 LA_CHECK_INCLUDE_FILE("utime.h" HAVE_UTIME_H)
@@ -618,6 +623,9 @@ LA_CHECK_INCLUDE_FILE("wctype.h" HAVE_WCTYPE_H)
 LA_CHECK_INCLUDE_FILE("windows.h" HAVE_WINDOWS_H)
 IF(ENABLE_CNG)
   LA_CHECK_INCLUDE_FILE("Bcrypt.h" HAVE_BCRYPT_H)
+  IF(HAVE_BCRYPT_H)
+    LIST(APPEND ADDITIONAL_LIBS "Bcrypt")
+  ENDIF(HAVE_BCRYPT_H)
 ELSE(ENABLE_CNG)
   UNSET(HAVE_BCRYPT_H CACHE)
 ENDIF(ENABLE_CNG)
@@ -1195,7 +1203,6 @@ CHECK_FUNCTION_EXISTS_GLIBC(chflags HAVE_CHFLAGS)
 CHECK_FUNCTION_EXISTS_GLIBC(chown HAVE_CHOWN)
 CHECK_FUNCTION_EXISTS_GLIBC(chroot HAVE_CHROOT)
 CHECK_FUNCTION_EXISTS_GLIBC(ctime_r HAVE_CTIME_R)
-CHECK_FUNCTION_EXISTS_GLIBC(dirfd HAVE_DIRFD)
 CHECK_FUNCTION_EXISTS_GLIBC(fchdir HAVE_FCHDIR)
 CHECK_FUNCTION_EXISTS_GLIBC(fchflags HAVE_FCHFLAGS)
 CHECK_FUNCTION_EXISTS_GLIBC(fchmod HAVE_FCHMOD)
@@ -1295,6 +1302,10 @@ CHECK_C_SOURCE_COMPILES(
   "#include <dirent.h>\nint main() {DIR *d = opendir(\".\"); struct dirent e,*r; return readdir_r(d,&e,&r);}"
   HAVE_READDIR_R)
 
+# dirfd can be either a function or a macro.
+CHECK_C_SOURCE_COMPILES(
+  "#include <dirent.h>\nint main() {DIR *d = opendir(\".\"); return dirfd(d);}"
+  HAVE_DIRFD)
 
 # Only detect readlinkat() if we also have AT_FDCWD in unistd.h.
 # NOTE: linux requires fcntl.h for AT_FDCWD.
@@ -1527,60 +1538,105 @@ CHECK_FILE_OFFSET_BITS()
 # Check for Extended Attribute libraries, headers, and functions
 #
 IF(ENABLE_XATTR)
-  LA_CHECK_INCLUDE_FILE(attr/xattr.h     HAVE_ATTR_XATTR_H)
-  LA_CHECK_INCLUDE_FILE(sys/xattr.h      HAVE_SYS_XATTR_H)
-  LA_CHECK_INCLUDE_FILE(sys/extattr.h      HAVE_SYS_EXTATTR_H)
   CHECK_LIBRARY_EXISTS(attr "setxattr" "" HAVE_LIBATTR)
   IF(HAVE_LIBATTR)
     SET(CMAKE_REQUIRED_LIBRARIES "attr")
   ENDIF(HAVE_LIBATTR)
   CHECK_SYMBOL_EXISTS(EXTATTR_NAMESPACE_USER "sys/types.h;sys/extattr.h" HAVE_DECL_EXTATTR_NAMESPACE_USER)
-  CHECK_FUNCTION_EXISTS_GLIBC(extattr_get_file HAVE_EXTATTR_GET_FILE)
-  CHECK_FUNCTION_EXISTS_GLIBC(extattr_list_file HAVE_EXTATTR_LIST_FILE)
-  CHECK_FUNCTION_EXISTS_GLIBC(extattr_set_fd HAVE_EXTATTR_SET_FD)
-  CHECK_FUNCTION_EXISTS_GLIBC(extattr_set_file HAVE_EXTATTR_SET_FILE)
-  CHECK_FUNCTION_EXISTS_GLIBC(fgetxattr HAVE_FGETXATTR)
-  CHECK_FUNCTION_EXISTS_GLIBC(flistxattr HAVE_FLISTXATTR)
-  CHECK_FUNCTION_EXISTS_GLIBC(fsetxattr HAVE_FSETXATTR)
-  CHECK_FUNCTION_EXISTS_GLIBC(getxattr HAVE_GETXATTR)
-  CHECK_FUNCTION_EXISTS_GLIBC(lgetxattr HAVE_LGETXATTR)
-  CHECK_FUNCTION_EXISTS_GLIBC(listxattr HAVE_LISTXATTR)
-  CHECK_FUNCTION_EXISTS_GLIBC(llistxattr HAVE_LLISTXATTR)
-  CHECK_FUNCTION_EXISTS_GLIBC(lsetxattr HAVE_LSETXATTR)
-  CHECK_FUNCTION_EXISTS_GLIBC(fgetea HAVE_FGETEA)
-  CHECK_FUNCTION_EXISTS_GLIBC(flistea HAVE_FLISTEA)
-  CHECK_FUNCTION_EXISTS_GLIBC(fsetea HAVE_FSETEA)
-  CHECK_FUNCTION_EXISTS_GLIBC(getea HAVE_GETEA)
-  CHECK_FUNCTION_EXISTS_GLIBC(lgetea HAVE_LGETEA)
-  CHECK_FUNCTION_EXISTS_GLIBC(listea HAVE_LISTEA)
-  CHECK_FUNCTION_EXISTS_GLIBC(llistea HAVE_LLISTEA)
-  CHECK_FUNCTION_EXISTS_GLIBC(lsetea HAVE_LSETEA)
+  CHECK_SYMBOL_EXISTS(XATTR_NOFOLLOW "sys/xattr.h" HAVE_DECL_XATTR_NOFOLLOW)
+  IF(HAVE_SYS_XATTR_H AND HAVE_DECL_XATTR_NOFOLLOW)
+    CHECK_FUNCTION_EXISTS(fgetxattr HAVE_FGETXATTR)
+    CHECK_FUNCTION_EXISTS(flistxattr HAVE_FLISTXATTR)
+    CHECK_FUNCTION_EXISTS(fsetxattr HAVE_FSETXATTR)
+    CHECK_FUNCTION_EXISTS(getxattr HAVE_GETXATTR)
+    CHECK_FUNCTION_EXISTS(listxattr HAVE_LISTXATTR)
+    CHECK_FUNCTION_EXISTS(setxattr HAVE_SETXATTR)
+    IF(HAVE_FGETXATTR AND
+       HAVE_FLISTXATTR AND
+       HAVE_FSETXATTR AND
+       HAVE_GETXATTR AND
+       HAVE_LISTXATTR AND
+       HAVE_SETXATTR)
+      SET(ARCHIVE_XATTR_DARWIN TRUE)
+    ENDIF()
+  ELSEIF(HAVE_SYS_EXTATTR_H AND HAVE_DECL_EXTATTR_NAMESPACE_USER)
+    # FreeBSD xattr support
+    CHECK_FUNCTION_EXISTS(extattr_get_fd HAVE_EXTATTR_GET_FD)
+    CHECK_FUNCTION_EXISTS(extattr_get_file HAVE_EXTATTR_GET_FILE)
+    CHECK_FUNCTION_EXISTS(extattr_get_link HAVE_EXTATTR_GET_LINK)
+    CHECK_FUNCTION_EXISTS(extattr_list_fd HAVE_EXTATTR_LIST_FD)
+    CHECK_FUNCTION_EXISTS(extattr_list_file HAVE_EXTATTR_LIST_FILE)
+    CHECK_FUNCTION_EXISTS(extattr_list_link HAVE_EXTATTR_LIST_LINK)
+    CHECK_FUNCTION_EXISTS(extattr_set_fd HAVE_EXTATTR_SET_FD)
+    CHECK_FUNCTION_EXISTS(extattr_set_link HAVE_EXTATTR_SET_LINK)
+    IF(HAVE_EXTATTR_GET_FD AND
+       HAVE_EXTATTR_GET_FILE AND
+       HAVE_EXTATTR_GET_LINK AND
+       HAVE_EXTATTR_LIST_FD AND
+       HAVE_EXTATTR_LIST_FILE AND
+       HAVE_EXTATTR_LIST_LINK AND
+       HAVE_EXTATTR_SET_FD AND
+       HAVE_EXTATTR_SET_LINK)
+      SET(ARCHIVE_XATTR_FREEBSD TRUE)
+    ENDIF()
+  ELSEIF(HAVE_SYS_XATTR_H OR HAVE_ATTR_XATTR_H)
+    # Linux xattr support
+    CHECK_FUNCTION_EXISTS_GLIBC(fgetxattr HAVE_FGETXATTR)
+    CHECK_FUNCTION_EXISTS_GLIBC(flistxattr HAVE_FLISTXATTR)
+    CHECK_FUNCTION_EXISTS_GLIBC(fsetxattr HAVE_FSETXATTR)
+    CHECK_FUNCTION_EXISTS_GLIBC(getxattr HAVE_GETXATTR)
+    CHECK_FUNCTION_EXISTS_GLIBC(lgetxattr HAVE_LGETXATTR)
+    CHECK_FUNCTION_EXISTS_GLIBC(listxattr HAVE_LISTXATTR)
+    CHECK_FUNCTION_EXISTS_GLIBC(llistxattr HAVE_LLISTXATTR)
+    CHECK_FUNCTION_EXISTS_GLIBC(lsetxattr HAVE_LSETXATTR)
+    IF(HAVE_FGETXATTR AND
+       HAVE_FLISTXATTR AND
+       HAVE_FSETXATTR AND
+       HAVE_GETXATTR AND
+       HAVE_LGETXATTR AND
+       HAVE_LISTXATTR AND
+       HAVE_LLISTXATTR AND
+       HAVE_LSETXATTR)
+      SET(ARCHIVE_XATTR_LINUX TRUE)
+    ENDIF()
+  ELSEIF(HAVE_SYS_EA_H)
+    # AIX xattr support
+    CHECK_FUNCTION_EXISTS(fgetea HAVE_FGETEA)
+    CHECK_FUNCTION_EXISTS(flistea HAVE_FLISTEA)
+    CHECK_FUNCTION_EXISTS(fsetea HAVE_FSETEA)
+    CHECK_FUNCTION_EXISTS(getea HAVE_GETEA)
+    CHECK_FUNCTION_EXISTS(lgetea HAVE_LGETEA)
+    CHECK_FUNCTION_EXISTS(listea HAVE_LISTEA)
+    CHECK_FUNCTION_EXISTS(llistea HAVE_LLISTEA)
+    CHECK_FUNCTION_EXISTS(lsetea HAVE_LSETEA)
+    IF(HAVE_FGETEA AND
+       HAVE_FLISTEA AND
+       HAVE_FSETEA AND
+       HAVE_GETEA AND
+       HAVE_LGETEA AND
+       HAVE_LISTEA AND
+       HAVE_LLISTEA AND
+       HAVE_LSETEA)
+      SET(ARCHIVE_XATTR_AIX TRUE)
+    ENDIF()
+  ENDIF()
+
+  IF(ARCHIVE_XATTR_DARWIN)
+    MESSAGE(STATUS "Extended attributes support: Darwin")
+  ELSEIF(ARCHIVE_XATTR_FREEBSD)
+    MESSAGE(STATUS "Extended attributes support: FreeBSD")
+  ELSEIF(ARCHIVE_XATTR_LINUX)
+    MESSAGE(STATUS "Extended attributes support: Linux")
+  ELSEIF(ARCHIVE_XATTR_AIX)
+    MESSAGE(STATUS "Extended attributes support: AIX")
+  ELSE()
+    MESSAGE(STATUS "Extended attributes support: none")
+  ENDIF()
 ELSE(ENABLE_XATTR)
-  SET(HAVE_ATTR_LIB FALSE)
-  SET(HAVE_ATTR_XATTR_H FALSE)
-  SET(HAVE_DECL_EXTATTR_NAMESPACE_USER FALSE)
-  SET(HAVE_EXTATTR_GET_FILE FALSE)
-  SET(HAVE_EXTATTR_LIST_FILE FALSE)
-  SET(HAVE_EXTATTR_SET_FD FALSE)
-  SET(HAVE_EXTATTR_SET_FILE FALSE)
-  SET(HAVE_FGETEA FALSE)
-  SET(HAVE_FGETXATTR FALSE)
-  SET(HAVE_FLISTEA FALSE)
-  SET(HAVE_FLISTXATTR FALSE)
-  SET(HAVE_FSETEA FALSE)
-  SET(HAVE_FSETXATTR FALSE)
-  SET(HAVE_GETEA FALSE)
-  SET(HAVE_GETXATTR FALSE)
-  SET(HAVE_LGETEA FALSE)
-  SET(HAVE_LGETXATTR FALSE)
-  SET(HAVE_LISTEA FALSE)
-  SET(HAVE_LISTXATTR FALSE)
-  SET(HAVE_LLISTEA FALSE)
-  SET(HAVE_LLISTXATTR FALSE)
-  SET(HAVE_LSETEA FALSE)
-  SET(HAVE_LSETXATTR FALSE)
-  SET(HAVE_SYS_EXTATTR_H FALSE)
-  SET(HAVE_SYS_XATTR_H FALSE)
+  SET(ARCHIVE_XATTR_DARWIN FALSE)
+  SET(ARCHIVE_XATTR_FREEBSD FALSE)
+  SET(ARCHIVE_XATTR_LINUX FALSE)
+  SET(ARCHIVE_XATTR_AIX FALSE)
 ENDIF(ENABLE_XATTR)
 
 #
@@ -1592,78 +1648,212 @@ ENDIF(ENABLE_XATTR)
 # which makes the following checks rather more complex than I would like.
 #
 IF(ENABLE_ACL)
+  # Solaris and derivates ACLs
+  CHECK_FUNCTION_EXISTS(acl HAVE_ACL)
+  CHECK_FUNCTION_EXISTS(facl HAVE_FACL)
+
+  # Libacl
   CHECK_LIBRARY_EXISTS(acl "acl_get_file" "" HAVE_LIBACL)
   IF(HAVE_LIBACL)
     SET(CMAKE_REQUIRED_LIBRARIES "acl")
     FIND_LIBRARY(ACL_LIBRARY NAMES acl)
     LIST(APPEND ADDITIONAL_LIBS ${ACL_LIBRARY})
   ENDIF(HAVE_LIBACL)
-  #
-  CHECK_FUNCTION_EXISTS_GLIBC(acl_create_entry HAVE_ACL_CREATE_ENTRY)
-  CHECK_FUNCTION_EXISTS_GLIBC(acl_init HAVE_ACL_INIT)
-  CHECK_FUNCTION_EXISTS_GLIBC(acl_set_fd HAVE_ACL_SET_FD)
-  CHECK_FUNCTION_EXISTS_GLIBC(acl_set_fd_np HAVE_ACL_SET_FD_NP)
-  CHECK_FUNCTION_EXISTS_GLIBC(acl_set_file HAVE_ACL_SET_FILE)
-  CHECK_TYPE_EXISTS(acl_permset_t "${INCLUDES}"    HAVE_ACL_PERMSET_T)
-
-  # 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.
-  CHECK_FUNCTION_EXISTS(acl_get_fd_np HAVE_ACL_GET_FD_NP)
-  CHECK_FUNCTION_EXISTS(acl_get_perm HAVE_ACL_GET_PERM)
-  CHECK_FUNCTION_EXISTS(acl_get_perm_np HAVE_ACL_GET_PERM_NP)
-  CHECK_FUNCTION_EXISTS(acl_get_link HAVE_ACL_GET_LINK)
-  CHECK_FUNCTION_EXISTS(acl_get_link_np HAVE_ACL_GET_LINK_NP)
-  CHECK_FUNCTION_EXISTS(acl_is_trivial_np HAVE_ACL_IS_TRIVIAL_NP)
-  CHECK_FUNCTION_EXISTS(acl_set_link_np HAVE_ACL_SET_LINK_NP)
-  CHECK_SYMBOL_EXISTS(ACL_TYPE_NFS4 "${INCLUDES}" HAVE_ACL_TYPE_NFS4)
-
-  # MacOS has an acl.h that isn't POSIX.  It can be detected by
-  # checking for ACL_USER
-  CHECK_SYMBOL_EXISTS(ACL_USER "${INCLUDES}" HAVE_ACL_USER)
-  CHECK_C_SOURCE_COMPILES("#include <sys/types.h>
+
+  CHECK_TYPE_EXISTS(acl_t "sys/types.h;sys/acl.h" HAVE_ACL_T)
+  CHECK_TYPE_EXISTS(acl_entry_t "sys/types.h;sys/acl.h" HAVE_ACL_ENTRY_T)
+  CHECK_TYPE_EXISTS(acl_permset_t "sys/types.h;sys/acl.h" HAVE_ACL_PERMSET_T)
+  CHECK_TYPE_EXISTS(acl_tag_t "sys/types.h;sys/acl.h" HAVE_ACL_TAG_T)
+
+  IF(HAVE_ACL AND HAVE_FACL)
+    CHECK_TYPE_EXISTS(aclent_t "sys/acl.h" HAVE_ACLENT_T)
+    IF(HAVE_ACLENT_T)
+      CHECK_SYMBOL_EXISTS(GETACL "sys/acl.h" HAVE_DECL_GETACL)
+      CHECK_SYMBOL_EXISTS(GETACLCNT "sys/acl.h" HAVE_DECL_GETACLCNT)
+      CHECK_SYMBOL_EXISTS(SETACL "sys/acl.h" HAVE_DECL_SETACL)
+      IF(HAVE_DECL_GETACL AND
+         HAVE_DECL_GETACLCNT AND
+         HAVE_DECL_SETACL)
+        SET(ARCHIVE_ACL_SUNOS TRUE)
+      ENDIF()
+      CHECK_TYPE_EXISTS(ace_t "sys/acl.h" HAVE_ACE_T)
+      IF(HAVE_ACE_T)
+        CHECK_SYMBOL_EXISTS(ACE_GETACL "sys/acl.h" HAVE_DECL_ACE_GETACL)
+        CHECK_SYMBOL_EXISTS(ACE_GETACLCNT "sys/acl.h" HAVE_DECL_ACE_GETACLCNT)
+        CHECK_SYMBOL_EXISTS(ACE_SETACL "sys/acl.h" HAVE_DECL_ACE_SETACL)
+        IF(HAVE_DECL_ACE_GETACL AND
+           HAVE_DECL_ACE_GETACLCNT AND
+           HAVE_DECL_ACE_SETACL)
+          SET(ARCHIVE_ACL_SUNOS_NFS4 TRUE)
+        ENDIF()
+      ENDIF(HAVE_ACE_T)
+    ENDIF(HAVE_ACLENT_T)
+  ENDIF(HAVE_ACL AND HAVE_FACL)
+
+  IF(HAVE_ACL_T AND HAVE_ACL_ENTRY_T AND HAVE_ACL_PERMSET_T AND HAVE_ACL_TAG_T)
+    CHECK_FUNCTION_EXISTS_GLIBC(acl_add_perm HAVE_ACL_ADD_PERM)
+    CHECK_FUNCTION_EXISTS_GLIBC(acl_clear_perms HAVE_ACL_CLEAR_PERMS)
+    CHECK_FUNCTION_EXISTS_GLIBC(acl_create_entry HAVE_ACL_CREATE_ENTRY)
+    CHECK_FUNCTION_EXISTS_GLIBC(acl_delete_def_file HAVE_ACL_DELETE_DEF_FILE)
+    CHECK_FUNCTION_EXISTS_GLIBC(acl_free HAVE_ACL_FREE)
+    CHECK_FUNCTION_EXISTS_GLIBC(acl_get_entry HAVE_ACL_GET_ENTRY)
+    CHECK_FUNCTION_EXISTS_GLIBC(acl_get_fd HAVE_ACL_GET_FD)
+    CHECK_FUNCTION_EXISTS_GLIBC(acl_get_file HAVE_ACL_GET_FILE)
+    CHECK_FUNCTION_EXISTS_GLIBC(acl_get_permset HAVE_ACL_GET_PERMSET)
+    CHECK_FUNCTION_EXISTS_GLIBC(acl_get_qualifier HAVE_ACL_GET_QUALIFIER)
+    CHECK_FUNCTION_EXISTS_GLIBC(acl_get_tag_type HAVE_ACL_GET_TAG_TYPE)
+    CHECK_FUNCTION_EXISTS_GLIBC(acl_init HAVE_ACL_INIT)
+    CHECK_FUNCTION_EXISTS_GLIBC(acl_set_fd HAVE_ACL_SET_FD)
+    CHECK_FUNCTION_EXISTS_GLIBC(acl_set_file HAVE_ACL_SET_FILE)
+    CHECK_FUNCTION_EXISTS_GLIBC(acl_set_qualifier HAVE_ACL_SET_QUALIFIER)
+    CHECK_FUNCTION_EXISTS_GLIBC(acl_set_tag_type HAVE_ACL_SET_TAG_TYPE)
+    IF(HAVE_ACL_ADD_PERM AND
+       HAVE_ACL_CLEAR_PERMS AND
+       HAVE_ACL_CREATE_ENTRY AND
+       HAVE_ACL_DELETE_DEF_FILE AND
+       HAVE_ACL_FREE AND
+       HAVE_ACL_GET_ENTRY AND
+       HAVE_ACL_GET_FD AND
+       HAVE_ACL_GET_FILE AND
+       HAVE_ACL_GET_PERMSET AND
+       HAVE_ACL_GET_QUALIFIER AND
+       HAVE_ACL_GET_TAG_TYPE AND
+       HAVE_ACL_INIT AND
+       HAVE_ACL_SET_FD AND
+       HAVE_ACL_SET_FILE AND
+       HAVE_ACL_SET_QUALIFIER AND
+       HAVE_ACL_SET_TAG_TYPE)
+         SET(HAVE_POSIX_ACL_FUNCS 1)
+    ENDIF()
+
+    CHECK_FUNCTION_EXISTS_GLIBC(acl_get_perm HAVE_ACL_GET_PERM)
+
+    IF(HAVE_POSIX_ACL_FUNCS AND HAVE_ACL_LIBACL_H AND HAVE_LIBACL AND
+       HAVE_ACL_GET_PERM)
+      SET(ARCHIVE_ACL_LIBACL TRUE)
+    ELSE()
+      CHECK_FUNCTION_EXISTS(acl_add_flag_np HAVE_ACL_ADD_FLAG_NP)
+      CHECK_FUNCTION_EXISTS(acl_clear_flags_np HAVE_ACL_CLEAR_FLAGS_NP)
+      CHECK_FUNCTION_EXISTS(acl_get_brand_np HAVE_ACL_GET_BRAND_NP)
+      CHECK_FUNCTION_EXISTS(acl_get_entry_type_np HAVE_ACL_GET_ENTRY_TYPE_NP)
+      CHECK_FUNCTION_EXISTS(acl_get_flag_np HAVE_ACL_GET_FLAG_NP)
+      CHECK_FUNCTION_EXISTS(acl_get_flagset_np HAVE_ACL_GET_FLAGSET_NP)
+      CHECK_FUNCTION_EXISTS(acl_get_fd_np HAVE_ACL_GET_FD_NP)
+      CHECK_FUNCTION_EXISTS(acl_get_link_np HAVE_ACL_GET_LINK_NP)
+      CHECK_FUNCTION_EXISTS(acl_get_perm_np HAVE_ACL_GET_PERM_NP)
+      CHECK_FUNCTION_EXISTS(acl_is_trivial_np HAVE_ACL_IS_TRIVIAL_NP)
+      CHECK_FUNCTION_EXISTS(acl_set_entry_type_np HAVE_ACL_SET_ENTRY_TYPE_NP)
+      CHECK_FUNCTION_EXISTS(acl_set_fd_np HAVE_ACL_SET_FD_NP)
+      CHECK_FUNCTION_EXISTS(acl_set_link_np HAVE_ACL_SET_LINK_NP)
+      CHECK_FUNCTION_EXISTS(mbr_gid_to_uuid HAVE_MBR_GID_TO_UUID)
+      CHECK_FUNCTION_EXISTS(mbr_uid_to_uuid HAVE_MBR_UID_TO_UUID)
+      CHECK_FUNCTION_EXISTS(mbr_uuid_to_id HAVE_MBR_UUID_TO_ID)
+
+      CHECK_C_SOURCE_COMPILES("#include <sys/types.h>
 #include <sys/acl.h>
-int main(void) { return ACL_TYPE_EXTENDED; }" HAVE_ACL_TYPE_EXTENDED)
+int main(void) { return ACL_TYPE_EXTENDED; }" HAVE_DECL_ACL_TYPE_EXTENDED)
+      CHECK_C_SOURCE_COMPILES("#include <sys/types.h>
+#include <sys/acl.h>
+int main(void) { return ACL_SYNCHRONIZE; }" HAVE_DECL_ACL_SYNCHRONIZE)
+      CHECK_SYMBOL_EXISTS(ACL_TYPE_NFS4 "sys/acl.h" HAVE_DECL_ACL_TYPE_NFS4)
+      CHECK_SYMBOL_EXISTS(ACL_USER "sys/acl.h" HAVE_DECL_ACL_USER)
+
+      IF(HAVE_POSIX_ACL_FUNCS AND
+         HAVE_ACL_GET_FD_NP AND
+         HAVE_ACL_GET_PERM_NP AND
+         NOT HAVE_ACL_GET_PERM AND
+         HAVE_ACL_SET_FD_NP)
+        IF(HAVE_DECL_ACL_USER)
+          SET(ARCHIVE_ACL_FREEBSD TRUE)
+          IF(HAVE_DECL_ACL_TYPE_NFS4 AND
+             HAVE_ACL_ADD_FLAG_NP AND
+             HAVE_ACL_CLEAR_FLAGS_NP AND
+             HAVE_ACL_GET_BRAND_NP AND
+             HAVE_ACL_GET_ENTRY_TYPE_NP AND
+             HAVE_ACL_GET_FLAGSET_NP AND
+             HAVE_ACL_SET_ENTRY_TYPE_NP)
+            SET(ARCHIVE_ACL_FREEBSD_NFS4 TRUE)
+          ENDIF()
+        ELSEIF(HAVE_DECL_ACL_TYPE_EXTENDED AND
+               HAVE_MEMBERSHIP_H AND
+               HAVE_ACL_ADD_FLAG_NP AND
+               HAVE_ACL_CLEAR_FLAGS_NP AND
+               HAVE_ACL_GET_FLAGSET_NP AND
+               HAVE_ACL_GET_LINK_NP AND
+               HAVE_ACL_SET_LINK_NP AND
+               HAVE_MBR_UID_TO_UUID AND
+               HAVE_MBR_GID_TO_UUID AND
+               HAVE_MBR_UUID_TO_ID)
+          SET(ARCHIVE_ACL_DARWIN TRUE)
+        ENDIF()
+      ENDIF()
+    ENDIF()
+  ENDIF(HAVE_ACL_T AND HAVE_ACL_ENTRY_T AND HAVE_ACL_PERMSET_T AND
+        HAVE_ACL_TAG_T)
+
+  # Richacl
+  CHECK_LIBRARY_EXISTS(richacl "richacl_get_file" "" HAVE_LIBRICHACL)
+  IF(HAVE_LIBRICHACL)
+    SET(CMAKE_REQUIRED_LIBRARIES "richacl")
+    FIND_LIBRARY(RICHACL_LIBRARY NAMES richacl)
+    LIST(APPEND ADDITIONAL_LIBS ${RICHACL_LIBRARY})
+  ENDIF(HAVE_LIBRICHACL)
+
+  CHECK_STRUCT_HAS_MEMBER("struct richace" e_type "sys/richacl.h"
+    HAVE_STRUCT_RICHACE)
+  CHECK_STRUCT_HAS_MEMBER("struct richacl" a_flags "sys/richacl.h"
+    HAVE_STRUCT_RICHACL)
+
+  IF(HAVE_LIBRICHACL AND HAVE_STRUCT_RICHACL AND HAVE_STRUCT_RICHACE)
+    CHECK_FUNCTION_EXISTS_GLIBC(richacl_alloc HAVE_RICHACL_ALLOC)
+    CHECK_FUNCTION_EXISTS_GLIBC(richacl_equiv_mode HAVE_RICHACL_EQUIV_MODE)
+    CHECK_FUNCTION_EXISTS_GLIBC(richacl_free HAVE_RICHACL_FREE)
+    CHECK_FUNCTION_EXISTS_GLIBC(richacl_get_fd HAVE_RICHACL_GET_FD)
+    CHECK_FUNCTION_EXISTS_GLIBC(richacl_get_file HAVE_RICHACL_GET_FILE)
+    CHECK_FUNCTION_EXISTS_GLIBC(richacl_set_fd HAVE_RICHACL_SET_FD)
+    CHECK_FUNCTION_EXISTS_GLIBC(richacl_set_file HAVE_RICHACL_SET_FILE)
+    IF(HAVE_RICHACL_ALLOC AND
+       HAVE_RICHACL_EQUIV_MODE AND
+       HAVE_RICHACL_FREE AND
+       HAVE_RICHACL_GET_FD AND
+       HAVE_RICHACL_GET_FILE AND
+       HAVE_RICHACL_SET_FD AND
+       HAVE_RICHACL_SET_FILE)
+      SET(ARCHIVE_ACL_LIBRICHACL TRUE)
+    ENDIF()
+  ENDIF(HAVE_LIBRICHACL AND HAVE_STRUCT_RICHACL AND HAVE_STRUCT_RICHACE)
+
+  IF(ARCHIVE_ACL_DARWIN)
+    MESSAGE(STATUS "ACL support: Darwin (limited NFSv4)")
+  ELSEIF(ARCHIVE_ACL_FREEBSD_NFS4)
+    MESSAGE(STATUS "ACL support: FreeBSD (POSIX.1e and NFSv4)")
+  ELSEIF(ARCHIVE_ACL_FREEBSD)
+    MESSAGE(STATUS "ACL support: FreeBSD (POSIX.1e)")
+  ELSEIF(ARCHIVE_ACL_LIBACL OR ARCHIVE_ACL_LIBRICHACL)
+    IF(ARCHIVE_ACL_LIBACL AND ARCHIVE_ACL_LIBRICHACL)
+      MESSAGE(STATUS "ACL support: libacl (POSIX.1e) + librichacl (NFSv4)")
+    ELSEIF(ARCHIVE_ACL_LIBRICHACL)
+      MESSAGE(STATUS "ACL support: librichacl (NFSv4)")
+    ELSE()
+      MESSAGE(STATUS "ACL support: libacl (POSIX.1e)")
+    ENDIF()
+  ELSEIF(ARCHIVE_ACL_SUNOS_NFS4)
+    MESSAGE(STATUS "ACL support: Solaris (POSIX.1e and NFSv4)")
+  ELSEIF(ARCHIVE_ACL_SUNOS)
+    MESSAGE(STATUS "ACL support: Solaris (POSIX.1e)")
+  ELSE()
+    MESSAGE(STATUS "ACL support: none")
+  ENDIF()
 
-  # Solaris and derivates ACLs
-  CHECK_LIBRARY_EXISTS(sec "acl_get" "" HAVE_LIBSEC)
-  IF(HAVE_LIBSEC)
-    SET(CMAKE_REQUIRED_LIBRARIES "sec")
-    FIND_LIBRARY(SEC_LIBRARY NAMES sec)
-    LIST(APPEND ADDITIONAL_LIBS ${SEC_LIBRARY})
-  ENDIF(HAVE_LIBSEC)
-  #
-  CHECK_TYPE_EXISTS(aclent_t "${INCLUDES}" HAVE_ACLENT_T)
-  CHECK_TYPE_EXISTS(ace_t "${INCLUDES}" HAVE_ACE_T)
-  CHECK_FUNCTION_EXISTS(acl_get HAVE_FACL_GET)
-  CHECK_FUNCTION_EXISTS(facl_get HAVE_FACL_GET)
-  CHECK_FUNCTION_EXISTS(acl_set HAVE_FACL_SET)
-  CHECK_FUNCTION_EXISTS(facl_set HAVE_FACL_SET)
 ELSE(ENABLE_ACL)
   # If someone runs cmake, then disables ACL support, we need
   # to forcibly override the cached values for these.
-  SET(HAVE_ACL_CREATE_ENTRY FALSE)
-  SET(HAVE_ACL_GET_LINK FALSE)
-  SET(HAVE_ACL_GET_LINK_NP FALSE)
-  SET(HAVE_ACL_GET_PERM FALSE)
-  SET(HAVE_ACL_GET_PERM_NP FALSE)
-  SET(HAVE_ACL_INIT FALSE)
-  SET(HAVE_ACL_LIB FALSE)
-  SET(HAVE_ACL_PERMSET_T FALSE)
-  SET(HAVE_ACL_SET_FD FALSE)
-  SET(HAVE_ACL_SET_FD_NP FALSE)
-  SET(HAVE_ACL_SET_FILE FALSE)
-  SET(HAVE_ACL_TYPE_NFS4 FALSE)
-  SET(HAVE_ACL_USER FALSE)
-  SET(HAVE_ACL_TYPE_EXTENDED FALSE)
-  SET(HAVE_ACL_GET FALSE)
-  SET(HAVE_ACLENT_T FALSE)
-  SET(HAVE_ACE_T FALSE)
-  SET(HAVE_FACL_GET FALSE)
-  SET(HAVE_ACL_SET FALSE)
-  SET(HAVE_FACL_SET FALSE)
+  SET(ARCHIVE_ACL_DARWIN FALSE)
+  SET(ARCHIVE_ACL_FREEBSD FALSE)
+  SET(ARCHIVE_ACL_FREEBSD_NFS4 FALSE)
+  SET(ARCHIVE_ACL_LIBACL FALSE)
+  SET(ARCHIVE_ACL_SUNOS FALSE)
+  SET(ARCHIVE_ACL_SUNOS_NFS4 FALSE)
 ENDIF(ENABLE_ACL)
 
 #
diff --git a/build/cmake/config.h.in b/build/cmake/config.h.in
index 923a78e..e646213 100644
--- a/build/cmake/config.h.in
+++ b/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
 
@@ -281,6 +302,18 @@ typedef uint64_t uintmax_t;
 /* SHA512 via ARCHIVE_CRYPTO_SHA512_WIN supported. */
 #cmakedefine ARCHIVE_CRYPTO_SHA512_WIN 1
 
+/* AIX xattr support */
+#cmakedefine ARCHIVE_XATTR_AIX 1
+
+/* Darwin xattr support */
+#cmakedefine ARCHIVE_XATTR_DARWIN 1
+
+/* FreeBSD xattr support */
+#cmakedefine ARCHIVE_XATTR_FREEBSD 1
+
+/* Linux xattr support */
+#cmakedefine ARCHIVE_XATTR_LINUX 1
+
 /* Version number of bsdcpio */
 #cmakedefine BSDCPIO_VERSION_STRING "${BSDCPIO_VERSION_STRING}"
 
@@ -326,15 +359,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 +395,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 +447,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
@@ -419,6 +475,10 @@ typedef uint64_t uintmax_t;
    don't. */
 #cmakedefine HAVE_DECL_UINTMAX_MAX 1
 
+/* Define to 1 if you have the declaration of `XATTR_NOFOLLOW', and to 0 if
+   you don't. */
+#cmakedefine HAVE_DECL_XATTR_NOFOLLOW 1
+
 /* Define to 1 if you have the <direct.h> header file. */
 #cmakedefine HAVE_DIRECT_H 1
 
@@ -468,6 +528,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 +810,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 +1050,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
 
diff --git a/build/version b/build/version
index ef83457..2dd0839 100644
--- a/build/version
+++ b/build/version
@@ -1 +1 @@
-3003001
+3003002
diff --git a/libarchive/CMakeLists.txt b/libarchive/CMakeLists.txt
index 1f85c01..5e958da 100644
--- a/libarchive/CMakeLists.txt
+++ b/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,8 @@ SET(libarchive_SOURCES
   archive_pathmatch.c
   archive_pathmatch.h
   archive_platform.h
+  archive_platform_acl.h
+  archive_platform_xattr.h
   archive_ppmd_private.h
   archive_ppmd7.c
   archive_ppmd7_private.h
@@ -106,9 +109,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 +213,16 @@ 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_disk_acl_darwin.c)
+ELSEIF(ARCHIVE_ACL_FREEBSD)
+  LIST(APPEND libarchive_SOURCES archive_disk_acl_freebsd.c)
+ELSEIF(ARCHIVE_ACL_LIBACL)
+  LIST(APPEND libarchive_SOURCES archive_disk_acl_linux.c)
+ELSEIF(ARCHIVE_ACL_SUNOS)
+  LIST(APPEND libarchive_SOURCES archive_disk_acl_sunos.c)
+ENDIF()
+
 # Libarchive is a shared library
 ADD_LIBRARY(archive SHARED ${libarchive_SOURCES} ${include_HEADERS})
 TARGET_LINK_LIBRARIES(archive ${ADDITIONAL_LIBS})
diff --git a/libarchive/archive.h b/libarchive/archive.h
index d400735..316a68a 100644
--- a/libarchive/archive.h
+++ b/libarchive/archive.h
@@ -36,7 +36,7 @@
  * assert that ARCHIVE_VERSION_NUMBER >= 2012108.
  */
 /* Note: Compiler will complain if this does not match archive_entry.h! */
-#define	ARCHIVE_VERSION_NUMBER 3003001
+#define	ARCHIVE_VERSION_NUMBER 3003002
 
 #include <sys/stat.h>
 #include <stddef.h>  /* for wchar_t */
@@ -155,7 +155,7 @@ __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.2"
 #define	ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
 __LA_DECL const char *	archive_version_string(void);
 
diff --git a/libarchive/archive_check_magic.c b/libarchive/archive_check_magic.c
index c695e58..288ce23 100644
--- a/libarchive/archive_check_magic.c
+++ b/libarchive/archive_check_magic.c
@@ -62,7 +62,7 @@ errmsg(const char *m)
 	}
 }
 
-static void
+static __LA_DEAD void
 diediedie(void)
 {
 #if defined(_WIN32) && !defined(__CYGWIN__) && defined(_DEBUG)
diff --git a/libarchive/archive_disk_acl_darwin.c b/libarchive/archive_disk_acl_darwin.c
new file mode 100644
index 0000000..48ad016
--- /dev/null
+++ b/libarchive/archive_disk_acl_darwin.c
@@ -0,0 +1,559 @@
+/*-
+ * 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"
+
+#if ARCHIVE_ACL_DARWIN
+
+#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_write_disk_private.h"
+
+typedef struct {
+	const int a_perm;	/* Libarchive permission or flag */
+	const int p_perm;	/* Platform permission or flag */
+} acl_perm_map_t;
+
+static 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
+};
+
+static const int acl_nfs4_perm_map_size =
+    (int)(sizeof(acl_nfs4_perm_map)/sizeof(acl_nfs4_perm_map[0]));
+
+static 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}
+};
+
+static const int acl_nfs4_flag_map_size =
+    (int)(sizeof(acl_nfs4_flag_map)/sizeof(acl_nfs4_flag_map[0]));
+
+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);
+}
+
+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);
+}
+
+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_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);
+}
+
+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);
+}
+#endif	/* ARCHIVE_ACL_DARWIN */
diff --git a/libarchive/archive_disk_acl_freebsd.c b/libarchive/archive_disk_acl_freebsd.c
new file mode 100644
index 0000000..07d08ff
--- /dev/null
+++ b/libarchive/archive_disk_acl_freebsd.c
@@ -0,0 +1,700 @@
+/*-
+ * Copyright (c) 2003-2009 Tim Kientzle
+ * Copyright (c) 2010-2012 Michihiro NAKAJIMA
+ * 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"
+
+#if ARCHIVE_ACL_FREEBSD
+
+#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_write_disk_private.h"
+
+typedef struct {
+	const int a_perm;	/* Libarchive permission or flag */
+	const int p_perm;	/* Platform permission or flag */
+} acl_perm_map_t;
+
+static 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},
+};
+
+static const int acl_posix_perm_map_size =
+    (int)(sizeof(acl_posix_perm_map)/sizeof(acl_posix_perm_map[0]));
+
+#if ARCHIVE_ACL_FREEBSD_NFS4
+static 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}
+};
+
+static const int acl_nfs4_perm_map_size =
+    (int)(sizeof(acl_nfs4_perm_map)/sizeof(acl_nfs4_perm_map[0]));
+
+static 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}
+};
+
+static const int acl_nfs4_flag_map_size =
+    (int)(sizeof(acl_nfs4_flag_map)/sizeof(acl_nfs4_flag_map[0]));
+#endif /* ARCHIVE_ACL_FREEBSD_NFS4 */
+
+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;
+	acl_entry_type_t acl_type;
+#endif
+	acl_tag_t	 acl_tag;
+	acl_entry_t	 acl_entry;
+	acl_permset_t	 acl_permset;
+	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);
+}
+
+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_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);
+}
+
+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);
+}
+#endif	/* ARCHIVE_ACL_FREEBSD */
diff --git a/libarchive/archive_disk_acl_linux.c b/libarchive/archive_disk_acl_linux.c
new file mode 100644
index 0000000..3928f3d
--- /dev/null
+++ b/libarchive/archive_disk_acl_linux.c
@@ -0,0 +1,743 @@
+/*-
+ * Copyright (c) 2003-2009 Tim Kientzle
+ * Copyright (c) 2010-2012 Michihiro NAKAJIMA
+ * 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"
+
+#if ARCHIVE_ACL_LIBACL || ARCHIVE_ACL_LIBRICHACL
+
+#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
+#ifdef 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_write_disk_private.h"
+
+typedef struct {
+	const int a_perm;	/* Libarchive permission or flag */
+	const int p_perm;	/* Platform permission or flag */
+} acl_perm_map_t;
+
+#if ARCHIVE_ACL_LIBACL
+static 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},
+};
+
+static 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
+static 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}
+};
+
+static const int acl_nfs4_perm_map_size =
+    (int)(sizeof(acl_nfs4_perm_map)/sizeof(acl_nfs4_perm_map[0]));
+
+static 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}
+};
+
+static const int acl_nfs4_flag_map_size =
+    (int)(sizeof(acl_nfs4_flag_map)/sizeof(acl_nfs4_flag_map[0]));
+#endif /* ARCHIVE_ACL_LIBRICHACL */
+
+#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 */
+
+#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_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);
+}
+
+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);
+}
+#endif /* ARCHIVE_ACL_LIBACL || ARCHIVE_ACL_LIBRICHACL */
diff --git a/libarchive/archive_disk_acl_sunos.c b/libarchive/archive_disk_acl_sunos.c
new file mode 100644
index 0000000..bc84fd6
--- /dev/null
+++ b/libarchive/archive_disk_acl_sunos.c
@@ -0,0 +1,821 @@
+/*-
+ * 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"
+
+#if ARCHIVE_ACL_SUNOS
+
+#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_write_disk_private.h"
+
+typedef struct {
+	const int a_perm;	/* Libarchive permission or flag */
+	const int p_perm;	/* Platform permission or flag */
+} acl_perm_map_t;
+
+static 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 }
+};
+
+static const int acl_posix_perm_map_size =
+    (int)(sizeof(acl_posix_perm_map)/sizeof(acl_posix_perm_map[0]));
+
+#if ARCHIVE_ACL_SUNOS_NFS4
+static 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}
+};
+
+static const int acl_nfs4_perm_map_size =
+    (int)(sizeof(acl_nfs4_perm_map)/sizeof(acl_nfs4_perm_map[0]));
+
+static 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 */
+
+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);
+}
+
+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_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);
+}
+
+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);
+}
+#endif	/* ARCHIVE_ACL_SUNOS */
diff --git a/libarchive/archive_entry.3 b/libarchive/archive_entry.3
index f5e22af..f75916c 100644
--- a/libarchive/archive_entry.3
+++ b/libarchive/archive_entry.3
@@ -25,7 +25,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd Feburary 2, 2012
+.Dd February 2, 2012
 .Dt ARCHIVE_ENTRY 3
 .Os
 .Sh NAME
diff --git a/libarchive/archive_entry.c b/libarchive/archive_entry.c
index 10eff11..30fb456 100644
--- a/libarchive/archive_entry.c
+++ b/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;
@@ -1638,7 +1638,7 @@ _archive_entry_acl_text_l(struct archive_entry *entry, int flags,
  * SUCH DAMAGE.
  */
 
-static struct flag {
+static const struct flag {
 	const char	*name;
 	const wchar_t	*wname;
 	unsigned long	 set;
@@ -1708,6 +1708,9 @@ static struct flag {
 #ifdef UF_COMPRESSED
 	{ "nocompressed",L"nocompressed",	UF_COMPRESSED,	0 },
 #endif
+#ifdef UF_HIDDEN
+	{ "nohidden",	L"nohidden",		UF_HIDDEN,	0 },
+#endif
 #if defined(FS_UNRM_FL)
         { "nouunlink",	L"nouunlink",		FS_UNRM_FL,	0},
 #elif defined(EXT2_UNRM_FL)
@@ -1840,7 +1843,7 @@ ae_fflagstostr(unsigned long bitset, unsigned long bitclear)
 	char *string, *dp;
 	const char *sp;
 	unsigned long bits;
-	struct flag *flag;
+	const struct flag *flag;
 	size_t	length;
 
 	bits = bitset | bitclear;
@@ -1892,7 +1895,7 @@ static const char *
 ae_strtofflags(const char *s, unsigned long *setp, unsigned long *clrp)
 {
 	const char *start, *end;
-	struct flag *flag;
+	const struct flag *flag;
 	unsigned long set, clear;
 	const char *failed;
 
@@ -1960,7 +1963,7 @@ static const wchar_t *
 ae_wcstofflags(const wchar_t *s, unsigned long *setp, unsigned long *clrp)
 {
 	const wchar_t *start, *end;
-	struct flag *flag;
+	const struct flag *flag;
 	unsigned long set, clear;
 	const wchar_t *failed;
 
diff --git a/libarchive/archive_entry.h b/libarchive/archive_entry.h
index 7645f0c..bcc2962 100644
--- a/libarchive/archive_entry.h
+++ b/libarchive/archive_entry.h
@@ -30,7 +30,7 @@
 #define	ARCHIVE_ENTRY_H_INCLUDED
 
 /* Note: Compiler will complain if this does not match archive.h! */
-#define	ARCHIVE_VERSION_NUMBER 3003001
+#define	ARCHIVE_VERSION_NUMBER 3003002
 
 /*
  * Note: archive_entry.h is for use outside of libarchive; the
diff --git a/libarchive/archive_entry_acl.3 b/libarchive/archive_entry_acl.3
index c5115f7..534dbfa 100644
--- a/libarchive/archive_entry_acl.3
+++ b/libarchive/archive_entry_acl.3
@@ -32,7 +32,7 @@
 .Nm archive_entry_acl_clear ,
 .Nm archive_entry_acl_count ,
 .Nm archive_entry_acl_from_text ,
-.Nm archive_entry_acl_from_text_w,
+.Nm archive_entry_acl_from_text_w ,
 .Nm archive_entry_acl_next ,
 .Nm archive_entry_acl_next_w ,
 .Nm archive_entry_acl_reset ,
@@ -267,7 +267,7 @@ 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
diff --git a/libarchive/archive_entry_paths.3 b/libarchive/archive_entry_paths.3
index fd22cf7..f647212 100644
--- a/libarchive/archive_entry_paths.3
+++ b/libarchive/archive_entry_paths.3
@@ -31,25 +31,25 @@
 .Nm archive_entry_set_hardlink ,
 .Nm archive_entry_copy_hardlink ,
 .Nm archive_entry_copy_hardlink_w ,
-.Nm archve_entry_update_hardlink_utf8 ,
+.Nm archive_entry_update_hardlink_utf8 ,
 .Nm archive_entry_set_link ,
 .Nm archive_entry_copy_link ,
 .Nm archive_entry_copy_link_w ,
-.Nm archve_entry_update_link_utf8 ,
+.Nm archive_entry_update_link_utf8 ,
 .Nm archive_entry_pathname ,
 .Nm archive_entry_pathname_w ,
 .Nm archive_entry_set_pathname ,
 .Nm archive_entry_copy_pathname ,
 .Nm archive_entry_copy_pathname_w ,
-.Nm archve_entry_update_pathname_utf8 ,
+.Nm archive_entry_update_pathname_utf8 ,
 .Nm archive_entry_sourcepath ,
 .Nm archive_entry_copy_sourcepath ,
-.Nm archive_entry_symlink,
-.Nm archive_entry_symlink_w,
+.Nm archive_entry_symlink ,
+.Nm archive_entry_symlink_w ,
 .Nm archive_entry_set_symlink ,
 .Nm archive_entry_copy_symlink ,
 .Nm archive_entry_copy_symlink_w ,
-.Nm archve_entry_update_symlink_utf8
+.Nm archive_entry_update_symlink_utf8
 .Nd functions for manipulating path names in archive entry descriptions
 .Sh LIBRARY
 Streaming Archive Library (libarchive, -larchive)
diff --git a/libarchive/archive_entry_perms.3 b/libarchive/archive_entry_perms.3
index 340c5ea..aae3648 100644
--- a/libarchive/archive_entry_perms.3
+++ b/libarchive/archive_entry_perms.3
@@ -34,8 +34,8 @@
 .Nm archive_entry_perm ,
 .Nm archive_entry_set_perm ,
 .Nm archive_entry_strmode ,
-.Nm archive_entry_uname
-.Nm archive_entry_uname_w
+.Nm archive_entry_uname ,
+.Nm archive_entry_uname_w ,
 .Nm archive_entry_set_uname ,
 .Nm archive_entry_copy_uname ,
 .Nm archive_entry_copy_uname_w ,
diff --git a/libarchive/archive_entry_sparse.c b/libarchive/archive_entry_sparse.c
index fed74f5..74917b3 100644
--- a/libarchive/archive_entry_sparse.c
+++ b/libarchive/archive_entry_sparse.c
@@ -51,7 +51,7 @@ archive_entry_sparse_clear(struct archive_entry *entry)
 
 void
 archive_entry_sparse_add_entry(struct archive_entry *entry,
-	int64_t offset, int64_t length)
+	la_int64_t offset, la_int64_t length)
 {
 	struct ae_sparse *sp;
 
@@ -135,7 +135,7 @@ archive_entry_sparse_reset(struct archive_entry * entry)
 
 int
 archive_entry_sparse_next(struct archive_entry * entry,
-	int64_t *offset, int64_t *length)
+	la_int64_t *offset, la_int64_t *length)
 {
 	if (entry->sparse_p) {
 		*offset = entry->sparse_p->offset;
diff --git a/libarchive/archive_getdate.c b/libarchive/archive_getdate.c
index beb0cba..030c083 100644
--- a/libarchive/archive_getdate.c
+++ b/libarchive/archive_getdate.c
@@ -691,7 +691,7 @@ Convert(time_t Month, time_t Day, time_t Year,
 	time_t Hours, time_t Minutes, time_t Seconds,
 	time_t Timezone, enum DSTMODE DSTmode)
 {
-	static int DaysInMonth[12] = {
+	signed char DaysInMonth[12] = {
 		31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
 	};
 	time_t	Julian;
diff --git a/libarchive/archive_openssl_hmac_private.h b/libarchive/archive_openssl_hmac_private.h
index 2deeb5f..59f95b8 100644
--- a/libarchive/archive_openssl_hmac_private.h
+++ b/libarchive/archive_openssl_hmac_private.h
@@ -28,7 +28,7 @@
 #include <openssl/hmac.h>
 #include <openssl/opensslv.h>
 
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
 #include <stdlib.h> /* malloc, free */
 #include <string.h> /* memset */
 static inline HMAC_CTX *HMAC_CTX_new(void)
diff --git a/libarchive/archive_pack_dev.c b/libarchive/archive_pack_dev.c
index 6b7b472..098881b 100644
--- a/libarchive/archive_pack_dev.c
+++ b/libarchive/archive_pack_dev.c
@@ -280,7 +280,7 @@ pack_bsdos(int n, unsigned long numbers[], const char **error)
 
 		/* list of formats and pack functions */
 		/* this list must be sorted lexically */
-static struct format {
+static const struct format {
 	const char	*name;
 	pack_t		*pack;
 } formats[] = {
diff --git a/libarchive/archive_platform.h b/libarchive/archive_platform.h
index c9a9602..34be8ed 100644
--- a/libarchive/archive_platform.h
+++ b/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.
  */
diff --git a/libarchive/archive_platform_acl.h b/libarchive/archive_platform_acl.h
new file mode 100644
index 0000000..3498f78
--- /dev/null
+++ b/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 */
diff --git a/libarchive/archive_platform_xattr.h b/libarchive/archive_platform_xattr.h
new file mode 100644
index 0000000..4edfecf
--- /dev/null
+++ b/libarchive/archive_platform_xattr.h
@@ -0,0 +1,41 @@
+/*-
+ * 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_XATTR_H_INCLUDED
+#define ARCHIVE_PLATFORM_XATTR_H_INCLUDED
+
+/*
+ * Determine if we support extended attributes
+ */
+#if ARCHIVE_XATTR_LINUX || ARCHIVE_XATTR_DARWIN || ARCHIVE_XATTR_FREEBSD || \
+    ARCHIVE_XATTR_AIX
+#define ARCHIVE_XATTR_SUPPORT     1
+#endif
+
+#endif	/* ARCHIVE_PLATFORM_XATTR_H_INCLUDED */
diff --git a/libarchive/archive_random.c b/libarchive/archive_random.c
index 357f973..65ea691 100644
--- a/libarchive/archive_random.c
+++ b/libarchive/archive_random.c
@@ -221,8 +221,11 @@ arc4_stir(void)
 	/*
 	 * Discard early keystream, as per recommendations in:
 	 * "(Not So) Random Shuffles of RC4" by Ilya Mironov.
+	 * As per the Network Operations Division, cryptographic requirements
+	 * published on wikileaks on March 2017.
 	 */
-	for (i = 0; i < 1024; i++)
+
+	for (i = 0; i < 3072; i++)
 		(void)arc4_getbyte();
 	arc4_count = 1600000;
 }
diff --git a/libarchive/archive_read.c b/libarchive/archive_read.c
index d1feceb..a642a33 100644
--- a/libarchive/archive_read.c
+++ b/libarchive/archive_read.c
@@ -881,7 +881,8 @@ archive_read_data(struct archive *_a, void *buff, size_t s)
 			len = a->read_data_remaining;
 			if (len > s)
 				len = s;
-			memcpy(dest, a->read_data_block, len);
+			if (len)
+				memcpy(dest, a->read_data_block, len);
 			s -= len;
 			a->read_data_block += len;
 			a->read_data_remaining -= len;
diff --git a/libarchive/archive_read_disk.3 b/libarchive/archive_read_disk.3
index 2a5c130..027f63c 100644
--- a/libarchive/archive_read_disk.3
+++ b/libarchive/archive_read_disk.3
@@ -24,11 +24,12 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd December 30, 2016
+.Dd April 3, 2017
 .Dt ARCHIVE_READ_DISK 3
 .Os
 .Sh NAME
 .Nm archive_read_disk_new ,
+.Nm archive_read_disk_set_behavior ,
 .Nm archive_read_disk_set_symlink_logical ,
 .Nm archive_read_disk_set_symlink_physical ,
 .Nm archive_read_disk_set_symlink_hybrid ,
@@ -37,10 +38,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)
@@ -49,6 +47,8 @@ Streaming Archive Library (libarchive, -larchive)
 .Ft struct archive *
 .Fn archive_read_disk_new "void"
 .Ft int
+.Fn archive_read_disk_set_behavior "struct archive *" "int"
+.Ft int
 .Fn archive_read_disk_set_symlink_logical "struct archive *"
 .Ft int
 .Fn archive_read_disk_set_symlink_physical "struct archive *"
@@ -81,12 +81,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.
@@ -98,6 +92,51 @@ objects.
 Allocates and initializes a
 .Tn struct archive
 object suitable for reading object information from disk.
+.It Fn archive_read_disk_set_behavior
+Configures various behavior options when reading entries from disk.
+The flags field consists of a bitwise OR of one or more of the
+following values:
+.Bl -tag -compact -width "indent"
+.It Cm ARCHIVE_READDISK_HONOR_NODUMP
+Skip files and directories with the nodump file attribute (file flag) set.
+By default, the nodump file atrribute is ignored.
+.It Cm ARCHIVE_READDISK_MAC_COPYFILE
+Mac OS X specific. Read metadata (ACLs and extended attributes) with
+.Xr copyfile 3 .
+By default, metadata is read using
+.Xr copyfile 3 .
+.It Cm ARCHIVE_READDISK_NO_ACL
+Do not read Access Control Lists.
+By default, ACLs are read from disk.
+.It Cm ARCHIVE_READDISK_NO_FFLAGS
+Do not read file attributes (file flags).
+By default, file attributes are read from disk.
+See
+.Xr chattr 1
+.Pq Linux
+or
+.Xr chflags 1
+.Pq FreeBSD, Mac OS X
+for more information on file attributes.
+.It Cm ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS
+Do not traverse mount points.
+By defaut, moint points are traversed.
+.It Cm ARCHIVE_READDISK_NO_XATTR
+Do not read extended file attributes (xattrs).
+By default, extended file attributes are read from disk.
+See
+.Xr xattr 7
+.Pq Linux ,
+.Xr xattr 2
+.Pq Mac OS X ,
+or
+.Xr getextattr 8
+.Pq FreeBSD
+for more information on extended file attributes.
+.It Cm ARCHIVE_READDISK_RESTORE_ATIME
+Restore access time of traversed files.
+By default, access time of traversed files is not restored.
+.El
 .It Xo
 .Fn archive_read_disk_set_symlink_logical ,
 .Fn archive_read_disk_set_symlink_physical ,
@@ -181,17 +220,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
diff --git a/libarchive/archive_read_disk_entry_from_file.c b/libarchive/archive_read_disk_entry_from_file.c
index b2f1d17..548ba89 100644
--- a/libarchive/archive_read_disk_entry_from_file.c
+++ b/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,996 +423,10 @@ 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 */
+#if ARCHIVE_XATTR_LINUX || ARCHIVE_XATTR_DARWIN || ARCHIVE_XATTR_AIX
 
-	/* 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)
-
-/*
- * Linux and AIX extended attribute support.
+ * Linux, Darwin and AIX extended attribute support.
  *
  * TODO:  By using a stack-allocated buffer for the first
  * call to getxattr(), we might be able to avoid the second
@@ -1433,21 +444,32 @@ setup_xattr(struct archive_read_disk *a,
 	ssize_t size;
 	void *value = NULL;
 
-#if HAVE_FGETXATTR
-	if (fd >= 0)
+
+	if (fd >= 0) {
+#if ARCHIVE_XATTR_LINUX
 		size = fgetxattr(fd, name, NULL, 0);
-	else if (!a->follow_symlinks)
-		size = lgetxattr(accpath, name, NULL, 0);
-	else
-		size = getxattr(accpath, name, NULL, 0);
-#elif HAVE_FGETEA
-	if (fd >= 0)
+#elif ARCHIVE_XATTR_DARWIN
+		size = fgetxattr(fd, name, NULL, 0, 0, 0);
+#elif ARCHIVE_XATTR_AIX
 		size = fgetea(fd, name, NULL, 0);
-	else if (!a->follow_symlinks)
+#endif
+	} else if (!a->follow_symlinks) {
+#if ARCHIVE_XATTR_LINUX
+		size = lgetxattr(accpath, name, NULL, 0);
+#elif ARCHIVE_XATTR_DARWIN
+		size = getxattr(accpath, name, NULL, 0, 0, XATTR_NOFOLLOW);
+#elif ARCHIVE_XATTR_AIX
 		size = lgetea(accpath, name, NULL, 0);
-	else
+#endif
+	} else {
+#if ARCHIVE_XATTR_LINUX
+		size = getxattr(accpath, name, NULL, 0);
+#elif ARCHIVE_XATTR_DARWIN
+		size = getxattr(accpath, name, NULL, 0, 0, 0);
+#elif ARCHIVE_XATTR_AIX
 		size = getea(accpath, name, NULL, 0);
 #endif
+	}
 
 	if (size == -1) {
 		archive_set_error(&a->archive, errno,
@@ -1460,21 +482,32 @@ setup_xattr(struct archive_read_disk *a,
 		return (ARCHIVE_FATAL);
 	}
 
-#if HAVE_FGETXATTR
-	if (fd >= 0)
+
+	if (fd >= 0) {
+#if ARCHIVE_XATTR_LINUX
 		size = fgetxattr(fd, name, value, size);
-	else if (!a->follow_symlinks)
-		size = lgetxattr(accpath, name, value, size);
-	else
-		size = getxattr(accpath, name, value, size);
-#elif HAVE_FGETEA
-	if (fd >= 0)
+#elif ARCHIVE_XATTR_DARWIN
+		size = fgetxattr(fd, name, value, size, 0, 0);
+#elif ARCHIVE_XATTR_AIX
 		size = fgetea(fd, name, value, size);
-	else if (!a->follow_symlinks)
+#endif
+	} else if (!a->follow_symlinks) {
+#if ARCHIVE_XATTR_LINUX
+		size = lgetxattr(accpath, name, value, size);
+#elif ARCHIVE_XATTR_DARWIN
+		size = getxattr(accpath, name, value, size, 0, XATTR_NOFOLLOW);
+#elif ARCHIVE_XATTR_AIX
 		size = lgetea(accpath, name, value, size);
-	else
+#endif
+	} else {
+#if ARCHIVE_XATTR_LINUX
+		size = getxattr(accpath, name, value, size);
+#elif ARCHIVE_XATTR_DARWIN
+		size = getxattr(accpath, name, value, size, 0, 0);
+#elif ARCHIVE_XATTR_AIX
 		size = getea(accpath, name, value, size);
 #endif
+	}
 
 	if (size == -1) {
 		archive_set_error(&a->archive, errno,
@@ -1499,38 +532,36 @@ 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
-	if (*fd >= 0)
+	if (*fd >= 0) {
+#if ARCHIVE_XATTR_LINUX
 		list_size = flistxattr(*fd, NULL, 0);
-	else if (!a->follow_symlinks)
-		list_size = llistxattr(path, NULL, 0);
-	else
-		list_size = listxattr(path, NULL, 0);
-#elif HAVE_FLISTEA
-	if (*fd >= 0)
+#elif ARCHIVE_XATTR_DARWIN
+		list_size = flistxattr(*fd, NULL, 0, 0);
+#elif ARCHIVE_XATTR_AIX
 		list_size = flistea(*fd, NULL, 0);
-	else if (!a->follow_symlinks)
+#endif
+	} else if (!a->follow_symlinks) {
+#if ARCHIVE_XATTR_LINUX
+		list_size = llistxattr(path, NULL, 0);
+#elif ARCHIVE_XATTR_DARWIN
+		list_size = listxattr(path, NULL, 0, XATTR_NOFOLLOW);
+#elif ARCHIVE_XATTR_AIX
 		list_size = llistea(path, NULL, 0);
-	else
+#endif
+	} else {
+#if ARCHIVE_XATTR_LINUX
+		list_size = listxattr(path, NULL, 0);
+#elif ARCHIVE_XATTR_DARWIN
+		list_size = listxattr(path, NULL, 0, 0);
+#elif ARCHIVE_XATTR_AIX
 		list_size = listea(path, NULL, 0);
 #endif
+	}
 
 	if (list_size == -1) {
 		if (errno == ENOTSUP || errno == ENOSYS)
@@ -1548,21 +579,31 @@ setup_xattrs(struct archive_read_disk *a,
 		return (ARCHIVE_FATAL);
 	}
 
-#if HAVE_FLISTXATTR
-	if (*fd >= 0)
+	if (*fd >= 0) {
+#if ARCHIVE_XATTR_LINUX
 		list_size = flistxattr(*fd, list, list_size);
-	else if (!a->follow_symlinks)
-		list_size = llistxattr(path, list, list_size);
-	else
-		list_size = listxattr(path, list, list_size);
-#elif HAVE_FLISTEA
-	if (*fd >= 0)
+#elif ARCHIVE_XATTR_DARWIN
+		list_size = flistxattr(*fd, list, list_size, 0);
+#elif ARCHIVE_XATTR_AIX
 		list_size = flistea(*fd, list, list_size);
-	else if (!a->follow_symlinks)
+#endif
+	} else if (!a->follow_symlinks) {
+#if ARCHIVE_XATTR_LINUX
+		list_size = llistxattr(path, list, list_size);
+#elif ARCHIVE_XATTR_DARWIN
+		list_size = listxattr(path, list, list_size, XATTR_NOFOLLOW);
+#elif ARCHIVE_XATTR_AIX
 		list_size = llistea(path, list, list_size);
-	else
+#endif
+	} else {
+#if ARCHIVE_XATTR_LINUX
+		list_size = listxattr(path, list, list_size);
+#elif ARCHIVE_XATTR_DARWIN
+		list_size = listxattr(path, list, list_size, 0);
+#elif ARCHIVE_XATTR_AIX
 		list_size = listea(path, list, list_size);
 #endif
+	}
 
 	if (list_size == -1) {
 		archive_set_error(&a->archive, errno,
@@ -1572,9 +613,21 @@ setup_xattrs(struct archive_read_disk *a,
 	}
 
 	for (p = list; (p - list) < list_size; p += strlen(p) + 1) {
-		if (strncmp(p, "system.", 7) == 0 ||
-				strncmp(p, "xfsroot.", 8) == 0)
+#if ARCHIVE_XATTR_LINUX
+		/* Linux: skip POSIX.1e ACL extended attributes */
+		if (strncmp(p, "system.", 7) == 0 &&
+		   (strcmp(p + 7, "posix_acl_access") == 0 ||
+		    strcmp(p + 7, "posix_acl_default") == 0))
+			continue;
+		if (strncmp(p, "trusted.SGI_", 12) == 0 &&
+		   (strcmp(p + 12, "ACL_DEFAULT") == 0 ||
+		    strcmp(p + 12, "ACL_FILE") == 0))
+			continue;
+
+		/* Linux: xfsroot namespace is obsolete and unsupported */
+		if (strncmp(p, "xfsroot.", 8) == 0)
 			continue;
+#endif
 		setup_xattr(a, entry, p, *fd, path);
 	}
 
@@ -1582,8 +635,7 @@ setup_xattrs(struct archive_read_disk *a,
 	return (ARCHIVE_OK);
 }
 
-#elif HAVE_EXTATTR_GET_FILE && HAVE_EXTATTR_LIST_FILE && \
-    HAVE_DECL_EXTATTR_NAMESPACE_USER
+#elif ARCHIVE_XATTR_FREEBSD
 
 /*
  * FreeBSD extattr interface.
@@ -1658,21 +710,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 +813,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 +821,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 +920,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,20 +928,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 (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)
+		path = archive_read_disk_entry_setup_path(a, entry, fd);
+	else
+		path = NULL;
 
 	if (*fd >= 0) {
 #ifdef _PC_MIN_HOLE_SIZE
@@ -1911,12 +942,8 @@ 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);
-			
+			return (ARCHIVE_FAILED);
 #ifdef _PC_MIN_HOLE_SIZE
 		if (pathconf(path, _PC_MIN_HOLE_SIZE) <= 0)
 			return (ARCHIVE_OK);
diff --git a/libarchive/archive_read_disk_private.h b/libarchive/archive_read_disk_private.h
index b5a8328..f03a0a9 100644
--- a/libarchive/archive_read_disk_private.h
+++ b/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
diff --git a/libarchive/archive_read_format.3 b/libarchive/archive_read_format.3
index 53b9a7e..91c5d2c 100644
--- a/libarchive/archive_read_format.3
+++ b/libarchive/archive_read_format.3
@@ -37,9 +37,9 @@
 .Nm archive_read_support_format_empty ,
 .Nm archive_read_support_format_iso9660 ,
 .Nm archive_read_support_format_lha ,
-.Nm archive_read_support_format_mtree,
-.Nm archive_read_support_format_rar,
-.Nm archive_read_support_format_raw,
+.Nm archive_read_support_format_mtree ,
+.Nm archive_read_support_format_rar ,
+.Nm archive_read_support_format_raw ,
 .Nm archive_read_support_format_tar ,
 .Nm archive_read_support_format_xar ,
 .Nm archive_read_support_format_zip
diff --git a/libarchive/archive_read_open.3 b/libarchive/archive_read_open.3
index 4d8272c..2278ebc 100644
--- a/libarchive/archive_read_open.3
+++ b/libarchive/archive_read_open.3
@@ -33,7 +33,7 @@
 .Nm archive_read_open_fd ,
 .Nm archive_read_open_FILE ,
 .Nm archive_read_open_filename ,
-.Nm archive_read_open_memory ,
+.Nm archive_read_open_memory
 .Nd functions for reading streaming archives
 .Sh LIBRARY
 Streaming Archive Library (libarchive, -larchive)
@@ -67,7 +67,7 @@ Streaming Archive Library (libarchive, -larchive)
 .Fa "size_t block_size"
 .Fc
 .Ft int
-.Fn archive_read_open_memory "struct archive *" "void *buff" "size_t size"
+.Fn archive_read_open_memory "struct archive *" "const void *buff" "size_t size"
 .Sh DESCRIPTION
 .Bl -tag -compact -width indent
 .It Fn archive_read_open
diff --git a/libarchive/archive_read_support_filter_lz4.c b/libarchive/archive_read_support_filter_lz4.c
index 663e2d3..147f502 100644
--- a/libarchive/archive_read_support_filter_lz4.c
+++ b/libarchive/archive_read_support_filter_lz4.c
@@ -494,7 +494,7 @@ lz4_filter_read_data_block(struct archive_read_filter *self, const void **p)
 	if (read_buf == NULL)
 		goto truncated_error;
 	compressed_size = archive_le32dec(read_buf);
-	if ((compressed_size & ~(1 << 31)) > state->flags.block_maximum_size)
+	if ((compressed_size & 0x7fffffff) > state->flags.block_maximum_size)
 		goto malformed_error;
 	/* A compressed size == 0 means the end of stream blocks. */
 	if (compressed_size == 0) {
@@ -504,8 +504,8 @@ lz4_filter_read_data_block(struct archive_read_filter *self, const void **p)
 
 	checksum_size = state->flags.block_checksum;
 	/* Check if the block is uncompressed. */
-	if (compressed_size & (1 << 31)) {
-		compressed_size &= ~(1 << 31);
+	if (compressed_size & 0x80000000U) {
+		compressed_size &= 0x7fffffff;
 		uncompressed_size = compressed_size;
 	} else
 		uncompressed_size = 0;/* Unknown yet. */
diff --git a/libarchive/archive_read_support_format_cab.c b/libarchive/archive_read_support_format_cab.c
index e2f8c6b..e5ff5a1 100644
--- a/libarchive/archive_read_support_format_cab.c
+++ b/libarchive/archive_read_support_format_cab.c
@@ -116,19 +116,11 @@ struct lzx_dec {
 		 * coding tree, which is a binary tree. But a use of a large
 		 * index table causes L1 cache read miss many times.
 		 */
-#define HTBL_BITS	10
 		int		 max_bits;
-		int		 shift_bits;
 		int		 tbl_bits;
 		int		 tree_used;
-		int		 tree_avail;
 		/* Direct access table. */
 		uint16_t	*tbl;
-		/* Binary tree table for extra bits over the direct access. */
-		struct htree_t {
-			uint16_t left;
-			uint16_t right;
-		}		*tree;
 	}			 at, lt, mt, pt;
 
 	int			 loop;
@@ -187,7 +179,7 @@ struct lzx_stream {
 #define CFDATA_cbData		4
 #define CFDATA_cbUncomp		6
 
-static const char *compression_name[] = {
+static const char * const compression_name[] = {
 	"NONE",
 	"MSZIP",
 	"Quantum",
@@ -352,7 +344,6 @@ static int	lzx_huffman_init(struct huffman *, size_t, int);
 static void	lzx_huffman_free(struct huffman *);
 static int	lzx_make_huffman_table(struct huffman *);
 static inline int lzx_decode_huffman(struct huffman *, unsigned);
-static int	lzx_decode_huffman_tree(struct huffman *, unsigned, int);
 
 
 int
@@ -3127,7 +3118,6 @@ getdata:
 static int
 lzx_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits)
 {
-	int bits;
 
 	if (hf->bitlen == NULL || hf->len_size != (int)len_size) {
 		free(hf->bitlen);
@@ -3138,21 +3128,11 @@ lzx_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits)
 	} else
 		memset(hf->bitlen, 0, len_size *  sizeof(hf->bitlen[0]));
 	if (hf->tbl == NULL) {
-		if (tbl_bits < HTBL_BITS)
-			bits = tbl_bits;
-		else
-			bits = HTBL_BITS;
-		hf->tbl = malloc(((size_t)1 << bits) * sizeof(hf->tbl[0]));
+		hf->tbl = malloc(((size_t)1 << tbl_bits) * sizeof(hf->tbl[0]));
 		if (hf->tbl == NULL)
 			return (ARCHIVE_FATAL);
 		hf->tbl_bits = tbl_bits;
 	}
-	if (hf->tree == NULL && tbl_bits > HTBL_BITS) {
-		hf->tree_avail = 1 << (tbl_bits - HTBL_BITS + 4);
-		hf->tree = malloc(hf->tree_avail * sizeof(hf->tree[0]));
-		if (hf->tree == NULL)
-			return (ARCHIVE_FATAL);
-	}
 	return (ARCHIVE_OK);
 }
 
@@ -3161,7 +3141,6 @@ lzx_huffman_free(struct huffman *hf)
 {
 	free(hf->bitlen);
 	free(hf->tbl);
-	free(hf->tree);
 }
 
 /*
@@ -3174,7 +3153,7 @@ lzx_make_huffman_table(struct huffman *hf)
 	const unsigned char *bitlen;
 	int bitptn[17], weight[17];
 	int i, maxbits = 0, ptn, tbl_size, w;
-	int diffbits, len_avail;
+	int len_avail;
 
 	/*
 	 * Initialize bit patterns.
@@ -3205,28 +3184,11 @@ lzx_make_huffman_table(struct huffman *hf)
 			weight[i] >>= ebits;
 		}
 	}
-	if (maxbits > HTBL_BITS) {
-		int htbl_max;
-		uint16_t *p;
-
-		diffbits = maxbits - HTBL_BITS;
-		for (i = 1; i <= HTBL_BITS; i++) {
-			bitptn[i] >>= diffbits;
-			weight[i] >>= diffbits;
-		}
-		htbl_max = bitptn[HTBL_BITS] +
-		    weight[HTBL_BITS] * hf->freq[HTBL_BITS];
-		p = &(hf->tbl[htbl_max]);
-		while (p < &hf->tbl[1U<<HTBL_BITS])
-			*p++ = 0;
-	} else
-		diffbits = 0;
-	hf->shift_bits = diffbits;
 
 	/*
 	 * Make the table.
 	 */
-	tbl_size = 1 << HTBL_BITS;
+	tbl_size = 1 << hf->tbl_bits;
 	tbl = hf->tbl;
 	bitlen = hf->bitlen;
 	len_avail = hf->len_size;
@@ -3234,120 +3196,32 @@ lzx_make_huffman_table(struct huffman *hf)
 	for (i = 0; i < len_avail; i++) {
 		uint16_t *p;
 		int len, cnt;
-		uint16_t bit;
-		int extlen;
-		struct htree_t *ht;
 
 		if (bitlen[i] == 0)
 			continue;
 		/* Get a bit pattern */
 		len = bitlen[i];
+		if (len > tbl_size)
+			return (0);
 		ptn = bitptn[len];
 		cnt = weight[len];
-		if (len <= HTBL_BITS) {
-			/* Calculate next bit pattern */
-			if ((bitptn[len] = ptn + cnt) > tbl_size)
-				return (0);/* Invalid */
-			/* Update the table */
-			p = &(tbl[ptn]);
-			while (--cnt >= 0)
-				p[cnt] = (uint16_t)i;
-			continue;
-		}
-
-		/*
-		 * A bit length is too big to be housed to a direct table,
-		 * so we use a tree model for its extra bits.
-		 */
-		bitptn[len] = ptn + cnt;
-		bit = 1U << (diffbits -1);
-		extlen = len - HTBL_BITS;
-		
-		p = &(tbl[ptn >> diffbits]);
-		if (*p == 0) {
-			*p = len_avail + hf->tree_used;
-			ht = &(hf->tree[hf->tree_used++]);
-			if (hf->tree_used > hf->tree_avail)
-				return (0);/* Invalid */
-			ht->left = 0;
-			ht->right = 0;
-		} else {
-			if (*p < len_avail ||
-			    *p >= (len_avail + hf->tree_used))
-				return (0);/* Invalid */
-			ht = &(hf->tree[*p - len_avail]);
-		}
-		while (--extlen > 0) {
-			if (ptn & bit) {
-				if (ht->left < len_avail) {
-					ht->left = len_avail + hf->tree_used;
-					ht = &(hf->tree[hf->tree_used++]);
-					if (hf->tree_used > hf->tree_avail)
-						return (0);/* Invalid */
-					ht->left = 0;
-					ht->right = 0;
-				} else {
-					ht = &(hf->tree[ht->left - len_avail]);
-				}
-			} else {
-				if (ht->right < len_avail) {
-					ht->right = len_avail + hf->tree_used;
-					ht = &(hf->tree[hf->tree_used++]);
-					if (hf->tree_used > hf->tree_avail)
-						return (0);/* Invalid */
-					ht->left = 0;
-					ht->right = 0;
-				} else {
-					ht = &(hf->tree[ht->right - len_avail]);
-				}
-			}
-			bit >>= 1;
-		}
-		if (ptn & bit) {
-			if (ht->left != 0)
-				return (0);/* Invalid */
-			ht->left = (uint16_t)i;
-		} else {
-			if (ht->right != 0)
-				return (0);/* Invalid */
-			ht->right = (uint16_t)i;
-		}
+		/* Calculate next bit pattern */
+		if ((bitptn[len] = ptn + cnt) > tbl_size)
+			return (0);/* Invalid */
+		/* Update the table */
+		p = &(tbl[ptn]);
+		while (--cnt >= 0)
+			p[cnt] = (uint16_t)i;
 	}
 	return (1);
 }
 
-static int
-lzx_decode_huffman_tree(struct huffman *hf, unsigned rbits, int c)
-{
-	struct htree_t *ht;
-	int extlen;
-
-	ht = hf->tree;
-	extlen = hf->shift_bits;
-	while (c >= hf->len_size) {
-		c -= hf->len_size;
-		if (extlen-- <= 0 || c >= hf->tree_used)
-			return (0);
-		if (rbits & (1U << extlen))
-			c = ht[c].left;
-		else
-			c = ht[c].right;
-	}
-	return (c);
-}
-
 static inline int
 lzx_decode_huffman(struct huffman *hf, unsigned rbits)
 {
 	int c;
-	/*
-	 * At first search an index table for a bit pattern.
-	 * If it fails, search a huffman tree for.
-	 */
-	c = hf->tbl[rbits >> hf->shift_bits];
+	c = hf->tbl[rbits];
 	if (c < hf->len_size)
 		return (c);
-	/* This bit pattern needs to be found out at a huffman tree. */
-	return (lzx_decode_huffman_tree(hf, rbits, c));
+	return (0);
 }
-
diff --git a/libarchive/archive_read_support_format_cpio.c b/libarchive/archive_read_support_format_cpio.c
index ffd4a85..ad9f782 100644
--- a/libarchive/archive_read_support_format_cpio.c
+++ b/libarchive/archive_read_support_format_cpio.c
@@ -165,7 +165,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_cpio.c 20116
 struct links_entry {
         struct links_entry      *next;
         struct links_entry      *previous;
-        int                      links;
+        unsigned int             links;
         dev_t                    dev;
         int64_t                  ino;
         char                    *name;
diff --git a/libarchive/archive_read_support_format_iso9660.c b/libarchive/archive_read_support_format_iso9660.c
index 76da406..f01d37b 100644
--- a/libarchive/archive_read_support_format_iso9660.c
+++ b/libarchive/archive_read_support_format_iso9660.c
@@ -3021,8 +3021,9 @@ heap_add_entry(struct archive_read *a, struct heap_queue *heap,
 			    ENOMEM, "Out of memory");
 			return (ARCHIVE_FATAL);
 		}
-		memcpy(new_pending_files, heap->files,
-		    heap->allocated * sizeof(new_pending_files[0]));
+		if (heap->allocated)
+			memcpy(new_pending_files, heap->files,
+			    heap->allocated * sizeof(new_pending_files[0]));
 		if (heap->files != NULL)
 			free(heap->files);
 		heap->files = new_pending_files;
diff --git a/libarchive/archive_read_support_format_lha.c b/libarchive/archive_read_support_format_lha.c
index d77a7c2..b8ef4ae 100644
--- a/libarchive/archive_read_support_format_lha.c
+++ b/libarchive/archive_read_support_format_lha.c
@@ -2477,7 +2477,7 @@ lzh_huffman_free(struct huffman *hf)
 	free(hf->tree);
 }
 
-static char bitlen_tbl[0x400] = {
+static const char bitlen_tbl[0x400] = {
 	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
 	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
 	 7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,  7,
diff --git a/libarchive/archive_read_support_format_mtree.c b/libarchive/archive_read_support_format_mtree.c
index 4231ff5..44b6083 100644
--- a/libarchive/archive_read_support_format_mtree.c
+++ b/libarchive/archive_read_support_format_mtree.c
@@ -130,9 +130,7 @@ static ssize_t	readline(struct archive_read *, struct mtree *, char **, ssize_t)
 static int	skip(struct archive_read *a);
 static int	read_header(struct archive_read *,
 		    struct archive_entry *);
-static int64_t	mtree_atol10(char **);
-static int64_t	mtree_atol8(char **);
-static int64_t	mtree_atol(char **);
+static int64_t	mtree_atol(char **, int base);
 
 /*
  * There's no standard for TIME_T_MAX/TIME_T_MIN.  So we compute them
@@ -399,41 +397,41 @@ bid_keycmp(const char *p, const char *key, ssize_t len)
 static int
 bid_keyword(const char *p,  ssize_t len)
 {
-	static const char *keys_c[] = {
+	static const char * const keys_c[] = {
 		"content", "contents", "cksum", NULL
 	};
-	static const char *keys_df[] = {
+	static const char * const keys_df[] = {
 		"device", "flags", NULL
 	};
-	static const char *keys_g[] = {
+	static const char * const keys_g[] = {
 		"gid", "gname", NULL
 	};
-	static const char *keys_il[] = {
+	static const char * const keys_il[] = {
 		"ignore", "inode", "link", NULL
 	};
-	static const char *keys_m[] = {
+	static const char * const keys_m[] = {
 		"md5", "md5digest", "mode", NULL
 	};
-	static const char *keys_no[] = {
+	static const char * const keys_no[] = {
 		"nlink", "nochange", "optional", NULL
 	};
-	static const char *keys_r[] = {
+	static const char * const keys_r[] = {
 		"resdevice", "rmd160", "rmd160digest", NULL
 	};
-	static const char *keys_s[] = {
+	static const char * const keys_s[] = {
 		"sha1", "sha1digest",
 		"sha256", "sha256digest",
 		"sha384", "sha384digest",
 		"sha512", "sha512digest",
 		"size", NULL
 	};
-	static const char *keys_t[] = {
+	static const char * const keys_t[] = {
 		"tags", "time", "type", NULL
 	};
-	static const char *keys_u[] = {
+	static const char * const keys_u[] = {
 		"uid", "uname",	NULL
 	};
-	const char **keys;
+	const char * const *keys;
 	int i;
 
 	switch (*p) {
@@ -1418,7 +1416,7 @@ parse_device(dev_t *pdev, struct archive *a, char *val)
 				    "Too many arguments");
 				return ARCHIVE_WARN;
 			}
-			numbers[argc++] = (unsigned long)mtree_atol(&p);
+			numbers[argc++] = (unsigned long)mtree_atol(&p, 0);
 		}
 		if (argc < 2) {
 			archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
@@ -1433,7 +1431,7 @@ parse_device(dev_t *pdev, struct archive *a, char *val)
 		}
 	} else {
 		/* file system raw value. */
-		result = (dev_t)mtree_atol(&val);
+		result = (dev_t)mtree_atol(&val, 0);
 	}
 	*pdev = result;
 	return ARCHIVE_OK;
@@ -1513,7 +1511,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
 	case 'g':
 		if (strcmp(key, "gid") == 0) {
 			*parsed_kws |= MTREE_HAS_GID;
-			archive_entry_set_gid(entry, mtree_atol10(&val));
+			archive_entry_set_gid(entry, mtree_atol(&val, 10));
 			break;
 		}
 		if (strcmp(key, "gname") == 0) {
@@ -1523,7 +1521,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
 		}
 	case 'i':
 		if (strcmp(key, "inode") == 0) {
-			archive_entry_set_ino(entry, mtree_atol10(&val));
+			archive_entry_set_ino(entry, mtree_atol(&val, 10));
 			break;
 		}
 	case 'l':
@@ -1535,14 +1533,14 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
 		if (strcmp(key, "md5") == 0 || strcmp(key, "md5digest") == 0)
 			break;
 		if (strcmp(key, "mode") == 0) {
-			if (val[0] >= '0' && val[0] <= '9') {
+			if (val[0] >= '0' && val[0] <= '7') {
 				*parsed_kws |= MTREE_HAS_PERM;
 				archive_entry_set_perm(entry,
-				    (mode_t)mtree_atol8(&val));
+				    (mode_t)mtree_atol(&val, 8));
 			} else {
 				archive_set_error(&a->archive,
 				    ARCHIVE_ERRNO_FILE_FORMAT,
-				    "Symbolic mode \"%s\" unsupported", val);
+				    "Symbolic or non-octal mode \"%s\" unsupported", val);
 				return ARCHIVE_WARN;
 			}
 			break;
@@ -1551,7 +1549,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
 		if (strcmp(key, "nlink") == 0) {
 			*parsed_kws |= MTREE_HAS_NLINK;
 			archive_entry_set_nlink(entry,
-				(unsigned int)mtree_atol10(&val));
+				(unsigned int)mtree_atol(&val, 10));
 			break;
 		}
 	case 'r':
@@ -1582,7 +1580,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
 		    strcmp(key, "sha512digest") == 0)
 			break;
 		if (strcmp(key, "size") == 0) {
-			archive_entry_set_size(entry, mtree_atol10(&val));
+			archive_entry_set_size(entry, mtree_atol(&val, 10));
 			break;
 		}
 	case 't':
@@ -1601,13 +1599,13 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
 			long ns = 0;
 
 			*parsed_kws |= MTREE_HAS_MTIME;
-			m = mtree_atol10(&val);
+			m = mtree_atol(&val, 10);
 			/* Replicate an old mtree bug:
 			 * 123456789.1 represents 123456789
 			 * seconds and 1 nanosecond. */
 			if (*val == '.') {
 				++val;
-				ns = (long)mtree_atol10(&val);
+				ns = (long)mtree_atol(&val, 10);
 				if (ns < 0)
 					ns = 0;
 				else if (ns > 999999999)
@@ -1670,7 +1668,7 @@ parse_keyword(struct archive_read *a, struct mtree *mtree,
 	case 'u':
 		if (strcmp(key, "uid") == 0) {
 			*parsed_kws |= MTREE_HAS_UID;
-			archive_entry_set_uid(entry, mtree_atol10(&val));
+			archive_entry_set_uid(entry, mtree_atol(&val, 10));
 			break;
 		}
 		if (strcmp(key, "uname") == 0) {
@@ -1825,72 +1823,9 @@ parse_escapes(char *src, struct mtree_entry *mentry)
 	*dest = '\0';
 }
 
-/*
- * Note that this implementation does not (and should not!) obey
- * locale settings; you cannot simply substitute strtol here, since
- * it does obey locale.
- */
-static int64_t
-mtree_atol8(char **p)
-{
-	int64_t	l, limit, last_digit_limit;
-	int digit, base;
-
-	base = 8;
-	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)) {
-			l = INT64_MAX; /* Truncate on overflow. */
-			break;
-		}
-		l = (l * base) + digit;
-		digit = *++(*p) - '0';
-	}
-	return (l);
-}
-
-/*
- * Note that this implementation does not (and should not!) obey
- * locale settings; you cannot simply substitute strtol here, since
- * it does obey locale.
- */
-static int64_t
-mtree_atol10(char **p)
-{
-	int64_t l, limit, last_digit_limit;
-	int base, digit, sign;
-
-	base = 10;
-
-	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))
-			return (sign < 0) ? INT64_MIN : INT64_MAX;
-		l = (l * base) + digit;
-		digit = *++(*p) - '0';
-	}
-	return (sign < 0) ? -l : l;
-}
-
 /* Parse a hex digit. */
 static int
-parsehex(char c)
+parsedigit(char c)
 {
 	if (c >= '0' && c <= '9')
 		return c - '0';
@@ -1908,45 +1843,50 @@ parsehex(char c)
  * it does obey locale.
  */
 static int64_t
-mtree_atol16(char **p)
+mtree_atol(char **p, int base)
 {
-	int64_t l, limit, last_digit_limit;
-	int base, digit, sign;
-
-	base = 16;
+	int64_t l, limit;
+	int digit, last_digit_limit;
+
+	if (base == 0) {
+		if (**p != '0')
+			base = 10;
+		else if ((*p)[1] == 'x' || (*p)[1] == 'X') {
+			*p += 2;
+			base = 16;
+		} else {
+			base = 8;
+		}
+	}
 
 	if (**p == '-') {
-		sign = -1;
-		limit = ((uint64_t)(INT64_MAX) + 1) / base;
-		last_digit_limit = ((uint64_t)(INT64_MAX) + 1) % base;
+		limit = INT64_MIN / base;
+		last_digit_limit = INT64_MIN % base;
 		++(*p);
+
+		l = 0;
+		digit = parsedigit(**p);
+		while (digit >= 0 && digit < base) {
+			if (l < limit || (l == limit && digit > last_digit_limit))
+				return INT64_MIN;
+			l = (l * base) - digit;
+			digit = parsedigit(*++(*p));
+		}
+		return l;
 	} else {
-		sign = 1;
 		limit = INT64_MAX / base;
 		last_digit_limit = INT64_MAX % base;
-	}
 
-	l = 0;
-	digit = parsehex(**p);
-	while (digit >= 0 && digit < base) {
-		if (l > limit || (l == limit && digit > last_digit_limit))
-			return (sign < 0) ? INT64_MIN : INT64_MAX;
-		l = (l * base) + digit;
-		digit = parsehex(*++(*p));
-	}
-	return (sign < 0) ? -l : l;
-}
-
-static int64_t
-mtree_atol(char **p)
-{
-	if (**p != '0')
-		return mtree_atol10(p);
-	if ((*p)[1] == 'x' || (*p)[1] == 'X') {
-		*p += 2;
-		return mtree_atol16(p);
+		l = 0;
+		digit = parsedigit(**p);
+		while (digit >= 0 && digit < base) {
+			if (l > limit || (l == limit && digit > last_digit_limit))
+				return INT64_MAX;
+			l = (l * base) + digit;
+			digit = parsedigit(*++(*p));
+		}
+		return l;
 	}
-	return mtree_atol8(p);
 }
 
 /*
diff --git a/libarchive/archive_read_support_format_rar.c b/libarchive/archive_read_support_format_rar.c
index 1e9849f..cbb14c3 100644
--- a/libarchive/archive_read_support_format_rar.c
+++ b/libarchive/archive_read_support_format_rar.c
@@ -1750,7 +1750,7 @@ read_exttime(const char *p, struct rar *rar, const char *endp)
         return (-1);
       for (j = 0; j < count; j++)
       {
-        rem = ((*p) << 16) | (rem >> 8);
+        rem = (((unsigned)(unsigned char)*p) << 16) | (rem >> 8);
         p++;
       }
       tm = localtime(&t);
diff --git a/libarchive/archive_read_support_format_tar.c b/libarchive/archive_read_support_format_tar.c
index bd7f13d..30d5bc8 100644
--- a/libarchive/archive_read_support_format_tar.c
+++ b/libarchive/archive_read_support_format_tar.c
@@ -155,6 +155,7 @@ 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) {
diff --git a/libarchive/archive_read_support_format_warc.c b/libarchive/archive_read_support_format_warc.c
index b162465..e875385 100644
--- a/libarchive/archive_read_support_format_warc.c
+++ b/libarchive/archive_read_support_format_warc.c
@@ -600,9 +600,10 @@ _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) {
diff --git a/libarchive/archive_read_support_format_zip.c b/libarchive/archive_read_support_format_zip.c
index 08bcf1f..4c4f6fa 100644
--- a/libarchive/archive_read_support_format_zip.c
+++ b/libarchive/archive_read_support_format_zip.c
@@ -347,7 +347,7 @@ fake_crc32(unsigned long crc, const void *buff, size_t len)
 	return 0;
 }
 
-static struct {
+static const struct {
 	int id;
 	const char * name;
 } compression_methods[] = {
@@ -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;
diff --git a/libarchive/archive_string.c b/libarchive/archive_string.c
index 592ead2..5ae09b6 100644
--- a/libarchive/archive_string.c
+++ b/libarchive/archive_string.c
@@ -202,7 +202,8 @@ archive_string_append(struct archive_string *as, const char *p, size_t s)
 {
 	if (archive_string_ensure(as, as->length + s + 1) == NULL)
 		return (NULL);
-	memmove(as->s + as->length, p, s);
+	if (s)
+		memmove(as->s + as->length, p, s);
 	as->length += s;
 	as->s[as->length] = 0;
 	return (as);
diff --git a/libarchive/archive_string_sprintf.c b/libarchive/archive_string_sprintf.c
index 964ea2b..969a560 100644
--- a/libarchive/archive_string_sprintf.c
+++ b/libarchive/archive_string_sprintf.c
@@ -53,7 +53,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_string_sprintf.c 189435 2009-03-
 static void
 append_uint(struct archive_string *as, uintmax_t d, unsigned base)
 {
-	static const char *digits = "0123456789abcdef";
+	static const char digits[] = "0123456789abcdef";
 	if (d >= base)
 		append_uint(as, d/base, base);
 	archive_strappend_char(as, digits[d % base]);
diff --git a/libarchive/archive_util.c b/libarchive/archive_util.c
index 6b3bd61..bac9ba1 100644
--- a/libarchive/archive_util.c
+++ b/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)
 {
@@ -275,7 +193,7 @@ archive_copy_error(struct archive *dest, struct archive *src)
 void
 __archive_errx(int retvalue, const char *msg)
 {
-	static const char *msg1 = "Fatal Internal Error in libarchive: ";
+	static const char msg1[] = "Fatal Internal Error in libarchive: ";
 	size_t s;
 
 	s = write(2, msg1, strlen(msg1));
@@ -303,8 +221,8 @@ __archive_errx(int retvalue, const char *msg)
 int
 __archive_mktemp(const char *tmpdir)
 {
-	static const wchar_t *prefix = L"libarchive_";
-	static const wchar_t *suffix = L"XXXXXXXXXX";
+	static const wchar_t prefix[] = L"libarchive_";
+	static const wchar_t suffix[] = L"XXXXXXXXXX";
 	static const wchar_t num[] = {
 		L'0', L'1', L'2', L'3', L'4', L'5', L'6', L'7',
 		L'8', L'9', L'A', L'B', L'C', L'D', L'E', L'F',
diff --git a/libarchive/archive_version_details.c b/libarchive/archive_version_details.c
new file mode 100644
index 0000000..813f0f3
--- /dev/null
+++ b/libarchive/archive_version_details.c
@@ -0,0 +1,133 @@
+/*-
+ * Copyright (c) 2009-2012,2014 Michihiro NAKAJIMA
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD: head/lib/libarchive/archive_util.c 201098 2009-12-28 02:58:14Z kientzle $");
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#endif
+#ifdef HAVE_LZMA_H
+#include <lzma.h>
+#endif
+#ifdef HAVE_BZLIB_H
+#include <bzlib.h>
+#endif
+#ifdef HAVE_LZ4_H
+#include <lz4.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_string.h"
+
+const char *
+archive_version_details(void)
+{
+	static struct archive_string str;
+	static int init = 0;
+	const char *zlib = archive_zlib_version();
+	const char *liblzma = archive_liblzma_version();
+	const char *bzlib = archive_bzlib_version();
+	const char *liblz4 = archive_liblz4_version();
+
+	if (!init) {
+		archive_string_init(&str);
+
+		archive_strcat(&str, ARCHIVE_VERSION_STRING);
+		if (zlib != NULL) {
+			archive_strcat(&str, " zlib/");
+			archive_strcat(&str, zlib);
+		}
+		if (liblzma) {
+			archive_strcat(&str, " liblzma/");
+			archive_strcat(&str, liblzma);
+		}
+		if (bzlib) {
+			const char *p = bzlib;
+			const char *sep = strchr(p, ',');
+			if (sep == NULL)
+				sep = p + strlen(p);
+			archive_strcat(&str, " bz2lib/");
+			archive_strncat(&str, p, sep - p);
+		}
+		if (liblz4) {
+			archive_strcat(&str, " liblz4/");
+			archive_strcat(&str, liblz4);
+		}
+	}
+	return str.s;
+}
+
+const char *
+archive_zlib_version(void)
+{
+#ifdef HAVE_ZLIB_H
+	return ZLIB_VERSION;
+#else
+	return NULL;
+#endif
+}
+
+const char *
+archive_liblzma_version(void)
+{
+#ifdef HAVE_LZMA_H
+	return LZMA_VERSION_STRING;
+#else
+	return NULL;
+#endif
+}
+
+const char *
+archive_bzlib_version(void)
+{
+#ifdef HAVE_BZLIB_H
+	return BZ2_bzlibVersion();
+#else
+	return NULL;
+#endif
+}
+
+const char *
+archive_liblz4_version(void)
+{
+#if defined(HAVE_LZ4_H) && defined(HAVE_LIBLZ4)
+#define str(s) #s
+#define NUMBER(x) str(x)
+	return NUMBER(LZ4_VERSION_MAJOR) "." NUMBER(LZ4_VERSION_MINOR) "." NUMBER(LZ4_VERSION_RELEASE);
+#undef NUMBER
+#undef str
+#else
+	return NULL;
+#endif
+}
diff --git a/libarchive/archive_write_add_filter.c b/libarchive/archive_write_add_filter.c
index ad5dc83..08f518a 100644
--- a/libarchive/archive_write_add_filter.c
+++ b/libarchive/archive_write_add_filter.c
@@ -38,7 +38,7 @@ __FBSDID("$FreeBSD$");
 #include "archive_private.h"
 
 /* A table that maps filter codes to functions. */
-static
+static const
 struct { int code; int (*setter)(struct archive *); } codes[] =
 {
 	{ ARCHIVE_FILTER_NONE,		archive_write_add_filter_none },
diff --git a/libarchive/archive_write_add_filter_by_name.c b/libarchive/archive_write_add_filter_by_name.c
index eac4011..85a8d47 100644
--- a/libarchive/archive_write_add_filter_by_name.c
+++ b/libarchive/archive_write_add_filter_by_name.c
@@ -42,7 +42,7 @@ __FBSDID("$FreeBSD$");
 #include "archive_private.h"
 
 /* A table that maps names to functions. */
-static
+static const
 struct { const char *name; int (*setter)(struct archive *); } names[] =
 {
 	{ "b64encode",		archive_write_add_filter_b64encode },
diff --git a/libarchive/archive_write_add_filter_lz4.c b/libarchive/archive_write_add_filter_lz4.c
index e655185..15fd494 100644
--- a/libarchive/archive_write_add_filter_lz4.c
+++ b/libarchive/archive_write_add_filter_lz4.c
@@ -225,7 +225,7 @@ archive_filter_lz4_open(struct archive_write_filter *f)
 	struct private_data *data = (struct private_data *)f->data;
 	int ret;
 	size_t required_size;
-	static size_t bkmap[] = { 64 * 1024, 256 * 1024, 1 * 1024 * 1024,
+	static size_t const bkmap[] = { 64 * 1024, 256 * 1024, 1 * 1024 * 1024,
 			   4 * 1024 * 1024 };
 	size_t pre_block_size;
 
diff --git a/libarchive/archive_write_add_filter_program.c b/libarchive/archive_write_add_filter_program.c
index 55b5e8e..660f693 100644
--- a/libarchive/archive_write_add_filter_program.c
+++ b/libarchive/archive_write_add_filter_program.c
@@ -92,7 +92,7 @@ archive_write_add_filter_program(struct archive *_a, const char *cmd)
 {
 	struct archive_write_filter *f = __archive_write_allocate_filter(_a);
 	struct private_data *data;
-	static const char *prefix = "Program: ";
+	static const char prefix[] = "Program: ";
 
 	archive_check_magic(_a, ARCHIVE_WRITE_MAGIC,
 	    ARCHIVE_STATE_NEW, "archive_write_add_filter_program");
diff --git a/libarchive/archive_write_data.3 b/libarchive/archive_write_data.3
index 0cdd25f..9c16cd9 100644
--- a/libarchive/archive_write_data.3
+++ b/libarchive/archive_write_data.3
@@ -24,11 +24,12 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd February 2, 2012
+.Dd February 28, 2017
 .Dt ARCHIVE_WRITE_DATA 3
 .Os
 .Sh NAME
-.Nm archive_write_data
+.Nm archive_write_data ,
+.Nm archive_write_data_block
 .Nd functions for creating archives
 .Sh LIBRARY
 Streaming Archive Library (libarchive, -larchive)
@@ -36,8 +37,27 @@ 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
diff --git a/libarchive/archive_write_disk.3 b/libarchive/archive_write_disk.3
index ba6c970..949c9ef 100644
--- a/libarchive/archive_write_disk.3
+++ b/libarchive/archive_write_disk.3
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd February 2, 2012
+.Dd April 3, 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
@@ -117,6 +96,33 @@ performance optimization in practice.
 The options field consists of a bitwise OR of one or more of the
 following values:
 .Bl -tag -compact -width "indent"
+.It Cm ARCHIVE_EXTRACT_ACL
+Attempt to restore Access Control Lists.
+By default, extended ACLs are ignored.
+.It Cm ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS
+Before removing a file system object prior to replacing it, clear
+platform-specific file flags which might prevent its removal.
+.It Cm ARCHIVE_EXTRACT_FFLAGS
+Attempt to restore file attributes (file flags).
+By default, file attributes are ignored.
+See
+.Xr chattr 1
+.Pq Linux
+or
+.Xr chflags 1
+.Pq FreeBSD, Mac OS X
+for more information on file attributes.
+.It Cm ARCHIVE_EXTRACT_MAC_METADATA
+Mac OS X specific. Restore metadata using
+.Xr copyfile 3 .
+By default,
+.Xr copyfile 3
+metadata is ignored.
+.It Cm ARCHIVE_EXTRACT_NO_OVERWRITE
+Existing files on disk will not be overwritten.
+By default, existing regular files are truncated and overwritten;
+existing directories will have their permissions updated;
+other pre-existing objects are unlinked and recreated from scratch.
 .It Cm ARCHIVE_EXTRACT_OWNER
 The user and group IDs should be set on the restored file.
 By default, the user and group IDs are not restored.
@@ -132,15 +138,37 @@ is not specified, then SUID and SGID bits will only be restored
 if the default user and group IDs of newly-created objects on disk
 happen to match those specified in the archive entry.
 By default, only basic permissions are restored, and umask is obeyed.
+.It Cm ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS
+Refuse to extract an absolute path.
+The default is to not refuse such paths.
+.It Cm ARCHIVE_EXTRACT_SECURE_NODOTDOT
+Refuse to extract a path that contains a
+.Pa ..
+element anywhere within it.
+The default is to not refuse such paths.
+Note that paths ending in
+.Pa ..
+always cause an error, regardless of this flag.
+.It Cm ARCHIVE_EXTRACT_SECURE_SYMLINKS
+Refuse to extract any object whose final location would be altered
+by a symlink on disk.
+This is intended to help guard against a variety of mischief
+caused by archives that (deliberately or otherwise) extract
+files outside of the current directory.
+The default is not to perform this check.
+If
+.It Cm ARCHIVE_EXTRACT_SPARSE
+Scan data for blocks of NUL bytes and try to recreate them with holes.
+This results in sparse files, independent of whether the archive format
+supports or uses them.
+.Cm ARCHIVE_EXTRACT_UNLINK
+is specified together with this option, the library will
+remove any intermediate symlinks it finds and return an
+error only if such symlink could not be removed.
 .It Cm ARCHIVE_EXTRACT_TIME
 The timestamps (mtime, ctime, and atime) should be restored.
 By default, they are ignored.
 Note that restoring of atime is not currently supported.
-.It Cm ARCHIVE_EXTRACT_NO_OVERWRITE
-Existing files on disk will not be overwritten.
-By default, existing regular files are truncated and overwritten;
-existing directories will have their permissions updated;
-other pre-existing objects are unlinked and recreated from scratch.
 .It Cm ARCHIVE_EXTRACT_UNLINK
 Existing files on disk will be unlinked before any attempt to
 create them.
@@ -148,45 +176,18 @@ In some cases, this can prove to be a significant performance improvement.
 By default, existing files are truncated and rewritten, but
 the file is not recreated.
 In particular, the default behavior does not break existing hard links.
-.It Cm ARCHIVE_EXTRACT_ACL
-Attempt to restore ACLs.
-By default, extended ACLs are ignored.
-.It Cm ARCHIVE_EXTRACT_FFLAGS
-Attempt to restore extended file flags.
-By default, file flags are ignored.
 .It Cm ARCHIVE_EXTRACT_XATTR
-Attempt to restore POSIX.1e extended attributes.
+Attempt to restore extended file attributes.
 By default, they are ignored.
-.It Cm ARCHIVE_EXTRACT_SECURE_SYMLINKS
-Refuse to extract any object whose final location would be altered
-by a symlink on disk.
-This is intended to help guard against a variety of mischief
-caused by archives that (deliberately or otherwise) extract
-files outside of the current directory.
-The default is not to perform this check.
-If
-.Cm ARCHIVE_EXTRACT_UNLINK
-is specified together with this option, the library will
-remove any intermediate symlinks it finds and return an
-error only if such symlink could not be removed.
-.It Cm ARCHIVE_EXTRACT_SECURE_NODOTDOT
-Refuse to extract a path that contains a
-.Pa ..
-element anywhere within it.
-The default is to not refuse such paths.
-Note that paths ending in
-.Pa ..
-always cause an error, regardless of this flag.
-.It Cm ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS
-Refuse to extract an absolute path.
-The default is to not refuse such paths.
-.It Cm ARCHIVE_EXTRACT_SPARSE
-Scan data for blocks of NUL bytes and try to recreate them with holes.
-This results in sparse files, independent of whether the archive format
-supports or uses them.
-.It Cm ARCHIVE_EXTRACT_CLEAR_NOCHANGE_FFLAGS
-Before removing a file system object prior to replacing it, clear
-platform-specific file flags which might prevent its removal.
+See
+.Xr xattr 7
+.Pq Linux ,
+.Xr xattr 2
+.Pq Mac OS X ,
+or
+.Xr getextattr 8
+.Pq FreeBSD
+for more information on extended file attributes.
 .El
 .It Xo
 .Fn archive_write_disk_set_group_lookup ,
@@ -223,60 +224,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
diff --git a/libarchive/archive_write_disk_acl.c b/libarchive/archive_write_disk_acl.c
deleted file mode 100644
index 144ab7e..0000000
--- a/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 */
diff --git a/libarchive/archive_write_disk_posix.c b/libarchive/archive_write_disk_posix.c
index 5a01e84..6ad5399 100644
--- a/libarchive/archive_write_disk_posix.c
+++ b/libarchive/archive_write_disk_posix.c
@@ -39,9 +39,9 @@ __FBSDID("$FreeBSD$");
 #ifdef HAVE_SYS_EXTATTR_H
 #include <sys/extattr.h>
 #endif
-#if defined(HAVE_SYS_XATTR_H)
+#if HAVE_SYS_XATTR_H
 #include <sys/xattr.h>
-#elif defined(HAVE_ATTR_XATTR_H)
+#elif HAVE_ATTR_XATTR_H
 #include <attr/xattr.h>
 #endif
 #ifdef HAVE_SYS_EA_H
@@ -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)
@@ -619,8 +664,21 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
 	}
 #endif
 
-	if (a->flags & ARCHIVE_EXTRACT_XATTR)
+	if (a->flags & ARCHIVE_EXTRACT_XATTR) {
+#if ARCHIVE_XATTR_DARWIN
+		/*
+		 * On MacOS, extended attributes get stored in mac_metadata,
+		 * too. If we intend to extract mac_metadata and it is present
+		 * we skip extracting extended attributes.
+		 */
+		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
 		a->todo |= TODO_XATTR;
+	}
 	if (a->flags & ARCHIVE_EXTRACT_FFLAGS)
 		a->todo |= TODO_FFLAGS;
 	if (a->flags & ARCHIVE_EXTRACT_SECURE_SYMLINKS) {
@@ -1703,25 +1761,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 +2337,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 +2506,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 +2612,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 +2621,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 +2638,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 +2657,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 +2669,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 +2691,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 +2700,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 +2713,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;
 			}
@@ -4044,71 +4083,98 @@ skip_appledouble:
 }
 #endif
 
-#if HAVE_LSETXATTR || HAVE_LSETEA
+#if ARCHIVE_XATTR_LINUX || ARCHIVE_XATTR_DARWIN || ARCHIVE_XATTR_AIX
 /*
- * Restore extended attributes -  Linux and AIX implementations:
+ * Restore extended attributes -  Linux, Darwin and AIX implementations:
  * AIX' ea interface is syntaxwise identical to the Linux xattr interface.
  */
 static int
 set_xattrs(struct archive_write_disk *a)
 {
 	struct archive_entry *entry = a->entry;
-	static int warning_done = 0;
+	struct archive_string errlist;
 	int ret = ARCHIVE_OK;
 	int i = archive_entry_xattr_reset(entry);
+	short fail = 0;
+
+	archive_string_init(&errlist);
 
 	while (i--) {
 		const char *name;
 		const void *value;
 		size_t size;
+		int e;
+
 		archive_entry_xattr_next(entry, &name, &value, &size);
-		if (name != NULL &&
-				strncmp(name, "xfsroot.", 8) != 0 &&
-				strncmp(name, "system.", 7) != 0) {
-			int e;
-#if HAVE_FSETXATTR
-			if (a->fd >= 0)
-				e = fsetxattr(a->fd, name, value, size, 0);
-			else
-#elif HAVE_FSETEA
-			if (a->fd >= 0)
-				e = fsetea(a->fd, name, value, size, 0);
-			else
+
+		if (name == NULL)
+			continue;
+#if ARCHIVE_XATTR_LINUX
+		/* Linux: quietly skip POSIX.1e ACL extended attributes */
+		if (strncmp(name, "system.", 7) == 0 &&
+		   (strcmp(name + 7, "posix_acl_access") == 0 ||
+		    strcmp(name + 7, "posix_acl_default") == 0))
+			continue;
+		if (strncmp(name, "trusted.SGI_", 12) == 0 &&
+		   (strcmp(name + 12, "ACL_DEFAULT") == 0 ||
+		    strcmp(name + 12, "ACL_FILE") == 0))
+			continue;
+
+		/* Linux: xfsroot namespace is obsolete and unsupported */
+		if (strncmp(name, "xfsroot.", 8) == 0) {
+			fail = 1;
+			archive_strcat(&errlist, name);
+			archive_strappend_char(&errlist, ' ');
+			continue;
+		}
 #endif
-			{
-#if HAVE_LSETXATTR
-				e = lsetxattr(archive_entry_pathname(entry),
-				    name, value, size, 0);
-#elif HAVE_LSETEA
-				e = lsetea(archive_entry_pathname(entry),
-				    name, value, size, 0);
+
+		if (a->fd >= 0) {
+#if ARCHIVE_XATTR_LINUX
+			e = fsetxattr(a->fd, name, value, size, 0);
+#elif ARCHIVE_XATTR_DARWIN
+			e = fsetxattr(a->fd, name, value, size, 0, 0);
+#elif ARCHIVE_XATTR_AIX
+			e = fsetea(a->fd, name, value, size, 0);
 #endif
-			}
-			if (e == -1) {
-				if (errno == ENOTSUP || errno == ENOSYS) {
-					if (!warning_done) {
-						warning_done = 1;
-						archive_set_error(&a->archive,
-						    errno,
-						    "Cannot restore extended "
-						    "attributes on this file "
-						    "system");
-					}
-				} else
-					archive_set_error(&a->archive, errno,
-					    "Failed to set extended attribute");
-				ret = ARCHIVE_WARN;
-			}
 		} else {
-			archive_set_error(&a->archive,
-			    ARCHIVE_ERRNO_FILE_FORMAT,
-			    "Invalid extended attribute encountered");
+#if ARCHIVE_XATTR_LINUX
+			e = lsetxattr(archive_entry_pathname(entry),
+			    name, value, size, 0);
+#elif ARCHIVE_XATTR_DARWIN
+			e = setxattr(archive_entry_pathname(entry),
+			    name, value, size, 0, XATTR_NOFOLLOW);
+#elif ARCHIVE_XATTR_AIX
+			e = lsetea(archive_entry_pathname(entry),
+			    name, value, size, 0);
+#endif
+		}
+		if (e == -1) {
 			ret = ARCHIVE_WARN;
+			archive_strcat(&errlist, name);
+			archive_strappend_char(&errlist, ' ');
+			if (errno != ENOTSUP && errno != ENOSYS)
+				fail = 1;
 		}
 	}
+
+	if (ret == ARCHIVE_WARN) {
+		if (fail && errlist.length > 0) {
+			errlist.length--;
+			errlist.s[errlist.length] = '\0';
+			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+			    "Cannot restore extended attributes: %s",
+			    errlist.s);
+		} else
+			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+			    "Cannot restore extended "
+			    "attributes on this file system.");
+	}
+
+	archive_string_free(&errlist);
 	return (ret);
 }
-#elif HAVE_EXTATTR_SET_FILE && HAVE_DECL_EXTATTR_NAMESPACE_USER
+#elif ARCHIVE_XATTR_FREEBSD
 /*
  * Restore extended attributes -  FreeBSD implementation
  */
@@ -4116,9 +4182,12 @@ static int
 set_xattrs(struct archive_write_disk *a)
 {
 	struct archive_entry *entry = a->entry;
-	static int warning_done = 0;
+	struct archive_string errlist;
 	int ret = ARCHIVE_OK;
 	int i = archive_entry_xattr_reset(entry);
+	short fail = 0;
+
+	archive_string_init(&errlist);
 
 	while (i--) {
 		const char *name;
@@ -4134,46 +4203,47 @@ set_xattrs(struct archive_write_disk *a)
 				name += 5;
 				namespace = EXTATTR_NAMESPACE_USER;
 			} else {
-				/* Warn about other extended attributes. */
-				archive_set_error(&a->archive,
-				    ARCHIVE_ERRNO_FILE_FORMAT,
-				    "Can't restore extended attribute ``%s''",
-				    name);
+				/* Other namespaces are unsupported */
+				archive_strcat(&errlist, name);
+				archive_strappend_char(&errlist, ' ');
+				fail = 1;
 				ret = ARCHIVE_WARN;
 				continue;
 			}
-			errno = 0;
-#if HAVE_EXTATTR_SET_FD
-			if (a->fd >= 0)
+
+			if (a->fd >= 0) {
 				e = extattr_set_fd(a->fd, namespace, name,
 				    value, size);
-			else
-#endif
-			/* TODO: should we use extattr_set_link() instead? */
-			{
-				e = extattr_set_file(
+			} else {
+				e = extattr_set_link(
 				    archive_entry_pathname(entry), namespace,
 				    name, value, size);
 			}
 			if (e != (int)size) {
-				if (errno == ENOTSUP || errno == ENOSYS) {
-					if (!warning_done) {
-						warning_done = 1;
-						archive_set_error(&a->archive,
-						    errno,
-						    "Cannot restore extended "
-						    "attributes on this file "
-						    "system");
-					}
-				} else {
-					archive_set_error(&a->archive, errno,
-					    "Failed to set extended attribute");
-				}
-
+				archive_strcat(&errlist, name);
+				archive_strappend_char(&errlist, ' ');
 				ret = ARCHIVE_WARN;
+				if (errno != ENOTSUP && errno != ENOSYS)
+					fail = 1;
 			}
 		}
 	}
+
+	if (ret == ARCHIVE_WARN) {
+		if (fail && errlist.length > 0) {
+			errlist.length--;
+			errlist.s[errlist.length] = '\0';
+
+			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+			    "Cannot restore extended attributes: %s",
+			    errlist.s);
+		} else
+			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+			    "Cannot restore extended "
+			    "attributes on this file system.");
+	}
+
+	archive_string_free(&errlist);
 	return (ret);
 }
 #else
@@ -4239,5 +4309,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__ */
 
diff --git a/libarchive/archive_write_disk_private.h b/libarchive/archive_write_disk_private.h
index d84e7e1..b655dea 100644
--- a/libarchive/archive_write_disk_private.h
+++ b/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
diff --git a/libarchive/archive_write_finish_entry.3 b/libarchive/archive_write_finish_entry.3
index c5ef69e..dc1b94b 100644
--- a/libarchive/archive_write_finish_entry.3
+++ b/libarchive/archive_write_finish_entry.3
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd February 2, 2012
+.Dd February 28, 2017
 .Dt ARCHIVE_WRITE_FINISH_ENTRY 3
 .Os
 .Sh NAME
@@ -45,6 +45,9 @@ 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
diff --git a/libarchive/archive_write_format.3 b/libarchive/archive_write_format.3
index d4ba6ab..aaafb0a 100644
--- a/libarchive/archive_write_format.3
+++ b/libarchive/archive_write_format.3
@@ -108,7 +108,6 @@ 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
diff --git a/libarchive/archive_write_set_format.c b/libarchive/archive_write_set_format.c
index 744302d..0f70623 100644
--- a/libarchive/archive_write_set_format.c
+++ b/libarchive/archive_write_set_format.c
@@ -38,7 +38,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format.c 201168 2009-1
 #include "archive_private.h"
 
 /* A table that maps format codes to functions. */
-static
+static const
 struct { int code; int (*setter)(struct archive *); } codes[] =
 {
 	{ ARCHIVE_FORMAT_7ZIP,		archive_write_set_format_7zip },
diff --git a/libarchive/archive_write_set_format_by_name.c b/libarchive/archive_write_set_format_by_name.c
index a2ce7c6..86e8621 100644
--- a/libarchive/archive_write_set_format_by_name.c
+++ b/libarchive/archive_write_set_format_by_name.c
@@ -41,7 +41,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_by_name.c 20116
 #include "archive_private.h"
 
 /* A table that maps names to functions. */
-static
+static const
 struct { const char *name; int (*setter)(struct archive *); } names[] =
 {
 	{ "7zip",	archive_write_set_format_7zip },
diff --git a/libarchive/archive_write_set_format_filter_by_ext.c b/libarchive/archive_write_set_format_filter_by_ext.c
index adec9b2..9fe21e4 100644
--- a/libarchive/archive_write_set_format_filter_by_ext.c
+++ b/libarchive/archive_write_set_format_filter_by_ext.c
@@ -42,7 +42,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_set_format_by_name.c 20116
 #include "archive_private.h"
 
 /* A table that maps names to functions. */
-static
+static const
 struct { const char *name; int (*format)(struct archive *); int (*filter)(struct archive *);  } names[] =
 {
 	{ ".7z",	archive_write_set_format_7zip,            archive_write_add_filter_none},
diff --git a/libarchive/archive_write_set_format_pax.c b/libarchive/archive_write_set_format_pax.c
index 6a301ac..0eaf733 100644
--- a/libarchive/archive_write_set_format_pax.c
+++ b/libarchive/archive_write_set_format_pax.c
@@ -1196,8 +1196,12 @@ archive_write_pax_header(struct archive_write *a,
 			    "GNU.sparse.major", 1);
 			add_pax_attr_int(&(pax->pax_header),
 			    "GNU.sparse.minor", 0);
+			/*
+			 * Make sure to store the original path, since
+			 * truncation to ustar limit happened already.
+			 */
 			add_pax_attr(&(pax->pax_header),
-			    "GNU.sparse.name", entry_name.s);
+			    "GNU.sparse.name", path);
 			add_pax_attr_int(&(pax->pax_header),
 			    "GNU.sparse.realsize",
 			    archive_entry_size(entry_main));
@@ -1650,13 +1654,14 @@ build_pax_attribute_name(char *dest, const char *src)
  * GNU PAX Format 1.0 requires the special name, which pattern is:
  * <dir>/GNUSparseFile.<pid>/<original file name>
  *
+ * Since reproducable archives are more important, use 0 as pid.
+ *
  * This function is used for only Sparse file, a file type of which
  * is regular file.
  */
 static char *
 build_gnu_sparse_name(char *dest, const char *src)
 {
-	char buff[64];
 	const char *p;
 
 	/* Handle the null filename case. */
@@ -1682,15 +1687,9 @@ build_gnu_sparse_name(char *dest, const char *src)
 		break;
 	}
 
-#if HAVE_GETPID && 0  /* Disable this as pax attribute name. */
-	sprintf(buff, "GNUSparseFile.%d", getpid());
-#else
-	/* If the platform can't fetch the pid, don't include it. */
-	strcpy(buff, "GNUSparseFile");
-#endif
 	/* General case: build a ustar-compatible name adding
 	 * "/GNUSparseFile/". */
-	build_ustar_entry_name(dest, src, p - src, buff);
+	build_ustar_entry_name(dest, src, p - src, "GNUSparseFile.0");
 
 	return (dest);
 }
diff --git a/libarchive/archive_write_set_format_warc.c b/libarchive/archive_write_set_format_warc.c
index 8b6daf9..edad072 100644
--- a/libarchive/archive_write_set_format_warc.c
+++ b/libarchive/archive_write_set_format_warc.c
@@ -354,7 +354,7 @@ static ssize_t
 _popul_ehdr(struct archive_string *tgt, size_t tsz, warc_essential_hdr_t hdr)
 {
 	static const char _ver[] = "WARC/1.0\r\n";
-	static const char *_typ[LAST_WT] = {
+	static const char * const _typ[LAST_WT] = {
 		NULL, "warcinfo", "metadata", "resource", NULL
 	};
 	char std_uuid[48U];
diff --git a/libarchive/config_freebsd.h b/libarchive/config_freebsd.h
index 215e886..be25258 100644
--- a/libarchive/config_freebsd.h
+++ b/libarchive/config_freebsd.h
@@ -22,141 +22,238 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: head/lib/libarchive/config_freebsd.h 201079 2009-12-28 02:01:42Z kientzle $
+ * $FreeBSD$
  */
 
-/* FreeBSD 5.0 and later have ACL and extattr support. */
+#include <osreldate.h>
+
+/* FreeBSD 5.0 and later has ACL and extattr support. */
 #if __FreeBSD__ > 4
-#define	HAVE_ACL_CREATE_ENTRY 1
-#define	HAVE_ACL_GET_FD_NP 1
-#define	HAVE_ACL_GET_LINK_NP 1
-#define	HAVE_ACL_GET_PERM_NP 1
-#define	HAVE_ACL_INIT 1
-#define	HAVE_ACL_SET_FD 1
-#define	HAVE_ACL_SET_FD_NP 1
-#define	HAVE_ACL_SET_FILE 1
-#define	HAVE_ACL_USER 1
-#define	HAVE_EXTATTR_GET_FILE 1
-#define	HAVE_EXTATTR_LIST_FILE 1
-#define	HAVE_EXTATTR_SET_FD 1
-#define	HAVE_EXTATTR_SET_FILE 1
-#define	HAVE_STRUCT_XVFSCONF 1
-#define	HAVE_SYS_ACL_H 1
-#define	HAVE_SYS_EXTATTR_H 1
-#endif
+#define ARCHIVE_ACL_FREEBSD 1
+#define HAVE_ACL_GET_PERM_NP 1
+#define HAVE_ARC4RANDOM_BUF 1
+#define HAVE_EXTATTR_GET_FILE 1
+#define HAVE_EXTATTR_LIST_FILE 1
+#define HAVE_EXTATTR_SET_FD 1
+#define HAVE_EXTATTR_SET_FILE 1
+#define HAVE_STRUCT_XVFSCONF 1
+#define HAVE_SYS_ACL_H 1
+#define HAVE_SYS_EXTATTR_H 1
+#if __FreeBSD__ > 7
+/* FreeBSD 8.0 and later has NFSv4 ACL support */
+#define ARCHIVE_ACL_FREEBSD_NFS4 1
+#define HAVE_ACL_GET_LINK_NP 1
+#define HAVE_ACL_IS_TRIVIAL_NP 1
+#define HAVE_ACL_SET_LINK_NP 1
+#endif /* __FreeBSD__ > 7 */
+#endif /* __FreeBSD__ > 4 */
 
 #ifdef WITH_OPENSSL
-#define	HAVE_OPENSSL_MD5_H 1
-#define	HAVE_OPENSSL_RIPEMD_H 1
-#define	HAVE_OPENSSL_SHA_H 1
-#define	HAVE_SHA384 1
-#define	HAVE_SHA512 1
+#define HAVE_LIBCRYPTO 1
+#define HAVE_OPENSSL_EVP_H 1
+#define HAVE_OPENSSL_MD5_H 1
+#define HAVE_OPENSSL_RIPEMD_H 1
+#define HAVE_OPENSSL_SHA_H 1
+#define HAVE_OPENSSL_SHA256_INIT 1
+#define HAVE_OPENSSL_SHA384_INIT 1
+#define HAVE_OPENSSL_SHA512_INIT 1
+#define HAVE_PKCS5_PBKDF2_HMAC_SHA1 1
+#define HAVE_SHA256 1
+#define HAVE_SHA384 1
+#define HAVE_SHA512 1
+#else
+#define HAVE_LIBMD 1
+#define HAVE_MD5_H 1
+#define HAVE_MD5INIT 1
+#define HAVE_RIPEMD_H 1
+#define HAVE_SHA_H 1
+#define HAVE_SHA1 1
+#define HAVE_SHA1_INIT 1
+#define HAVE_SHA256 1
+#define HAVE_SHA256_H 1
+#define HAVE_SHA256_INIT 1
+#define HAVE_SHA512 1
+#define HAVE_SHA512_H 1
+#define HAVE_SHA512_INIT 1
 #endif
 
-#define	HAVE_BSDXML_H 1
-#define	HAVE_BZLIB_H 1
-#define	HAVE_CHFLAGS 1
-#define	HAVE_CHOWN 1
-#define	HAVE_DECL_INT64_MAX 1
-#define	HAVE_DECL_INT64_MIN 1
-#define	HAVE_DECL_SIZE_MAX 1
-#define	HAVE_DECL_SSIZE_MAX 1
-#define	HAVE_DECL_STRERROR_R 1
-#define	HAVE_DECL_UINT32_MAX 1
-#define	HAVE_DECL_UINT64_MAX 1
-#define	HAVE_DIRENT_H 1
-#define	HAVE_EFTYPE 1
-#define	HAVE_EILSEQ 1
-#define	HAVE_ERRNO_H 1
-#define	HAVE_FCHDIR 1
-#define	HAVE_FCHFLAGS 1
-#define	HAVE_FCHMOD 1
-#define	HAVE_FCHOWN 1
-#define	HAVE_FCNTL 1
-#define	HAVE_FCNTL_H 1
-#define	HAVE_FSEEKO 1
-#define	HAVE_FSTAT 1
-#define	HAVE_FTRUNCATE 1
-#define	HAVE_FUTIMES 1
-#define	HAVE_GETEUID 1
-#define	HAVE_GETGRGID_R 1
-#define	HAVE_GETPID 1
-#define	HAVE_GETPWUID_R 1
-#define	HAVE_GRP_H 1
-#define	HAVE_INTTYPES_H 1
-#define	HAVE_LCHFLAGS 1
-#define	HAVE_LCHMOD 1
-#define	HAVE_LCHOWN 1
-#define	HAVE_LIMITS_H 1
-#define	HAVE_LINK 1
-#define	HAVE_LSTAT 1
-#define	HAVE_LUTIMES 1
-#define	HAVE_MALLOC 1
-#define	HAVE_MD5 1
-#define	HAVE_MD5_H 1
-#define	HAVE_MEMMOVE 1
-#define	HAVE_MKDIR 1
-#define	HAVE_MKFIFO 1
-#define	HAVE_MKNOD 1
-#define	HAVE_PIPE 1
-#define	HAVE_POLL 1
-#define	HAVE_POLL_H 1
-#define	HAVE_PWD_H 1
-#define	HAVE_READLINK 1
-#define	HAVE_RMD160 1
-#define	HAVE_SELECT 1
-#define	HAVE_SETENV 1
-#define	HAVE_SHA_H 1
-#define	HAVE_SHA1 1
-#define	HAVE_SHA256 1
-#define	HAVE_SHA256_H 1
-#define	HAVE_SIGNAL_H 1
-#define	HAVE_STDINT_H 1
-#define	HAVE_STDLIB_H 1
-#define	HAVE_STRCHR 1
-#define	HAVE_STRDUP 1
-#define	HAVE_STRERROR 1
-#define	HAVE_STRERROR_R 1
-#define	HAVE_STRINGS_H 1
-#define	HAVE_STRING_H 1
-#define	HAVE_STRRCHR 1
-#define	HAVE_STRUCT_STAT_ST_BLKSIZE 1
-#define	HAVE_STRUCT_STAT_ST_BIRTHTIME 1
-#define	HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC 1
-#define	HAVE_STRUCT_STAT_ST_FLAGS 1
-#define	HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1
-#define	HAVE_STRUCT_TM_TM_GMTOFF 1
-#define	HAVE_SYMLINK 1
-#define	HAVE_SYS_CDEFS_H 1
-#define	HAVE_SYS_IOCTL_H 1
-#define	HAVE_SYS_MOUNT_H 1
-#define	HAVE_SYS_PARAM_H 1
-#define	HAVE_SYS_SELECT_H 1
-#define	HAVE_SYS_STAT_H 1
-#define	HAVE_SYS_TIME_H 1
-#define	HAVE_SYS_TYPES_H 1
-#undef	HAVE_SYS_UTIME_H
-#define	HAVE_SYS_UTSNAME_H 1
-#define	HAVE_SYS_WAIT_H 1
-#define	HAVE_TIMEGM 1
-#define	HAVE_TZSET 1
-#define	HAVE_UNISTD_H 1
-#define	HAVE_UNSETENV 1
-#define	HAVE_UTIME 1
-#define	HAVE_UTIMES 1
-#define	HAVE_UTIME_H 1
-#define	HAVE_VFORK 1
-#define	HAVE_WCHAR_H 1
-#define	HAVE_WCSCPY 1
-#define	HAVE_WCSLEN 1
-#define	HAVE_WCTOMB 1
-#define	HAVE_WMEMCMP 1
-#define	HAVE_WMEMCPY 1
-#define	HAVE_ZLIB_H 1
-#define	TIME_WITH_SYS_TIME 1
+#define HAVE_BSDXML_H 1
+#define HAVE_BZLIB_H 1
+#define HAVE_CHFLAGS 1
+#define HAVE_CHOWN 1
+#define HAVE_CHROOT 1
+#define HAVE_CTIME_R 1
+#define HAVE_CTYPE_H 1
+#define HAVE_DECL_EXTATTR_NAMESPACE_USER 1
+#define HAVE_DECL_INT32_MAX 1
+#define HAVE_DECL_INT32_MIN 1
+#define HAVE_DECL_INT64_MAX 1
+#define HAVE_DECL_INT64_MIN 1
+#define HAVE_DECL_INTMAX_MAX 1
+#define HAVE_DECL_INTMAX_MIN 1
+#define HAVE_DECL_SIZE_MAX 1
+#define HAVE_DECL_SSIZE_MAX 1
+#define HAVE_DECL_STRERROR_R 1
+#define HAVE_DECL_UINT32_MAX 1
+#define HAVE_DECL_UINT64_MAX 1
+#define HAVE_DECL_UINTMAX_MAX 1
+#define HAVE_DIRENT_H 1
+#define HAVE_DLFCN_H 1
+#define HAVE_D_MD_ORDER 1
+#define HAVE_EFTYPE 1
+#define HAVE_EILSEQ 1
+#define HAVE_ERRNO_H 1
+#define HAVE_FCHDIR 1
+#define HAVE_FCHFLAGS 1
+#define HAVE_FCHMOD 1
+#define HAVE_FCHOWN 1
+#define HAVE_FCNTL 1
+#define HAVE_FCNTL_H 1
+#define HAVE_FDOPENDIR 1
+#define HAVE_FORK 1
+#define HAVE_FSEEKO 1
+#define HAVE_FSTAT 1
+#define HAVE_FSTATAT 1
+#define HAVE_FSTATFS 1
+#define HAVE_FSTATVFS 1
+#define HAVE_FTRUNCATE 1
+#define HAVE_FUTIMES 1
+#define HAVE_FUTIMESAT 1
+#define HAVE_GETEUID 1
+#define HAVE_GETGRGID_R 1
+#define HAVE_GETGRNAM_R 1
+#define HAVE_GETPID 1
+#define HAVE_GETPWNAM_R 1
+#define HAVE_GETPWUID_R 1
+#define HAVE_GETVFSBYNAME 1
+#define HAVE_GMTIME_R 1
+#define HAVE_GRP_H 1
+#define HAVE_INTMAX_T 1
+#define HAVE_INTTYPES_H 1
+#define HAVE_LANGINFO_H 1
+#define HAVE_LCHFLAGS 1
+#define HAVE_LCHMOD 1
+#define HAVE_LCHOWN 1
+#define HAVE_LIBZ 1
+#define HAVE_LIMITS_H 1
+#define HAVE_LINK 1
+#define HAVE_LOCALE_H 1
+#define HAVE_LOCALTIME_R 1
+#define HAVE_LONG_LONG_INT 1
+#define HAVE_LSTAT 1
+#define HAVE_LUTIMES 1
+#define HAVE_MBRTOWC 1
+#define HAVE_MEMMOVE 1
+#define HAVE_MEMORY_H 1
+#define HAVE_MEMSET 1
+#define HAVE_MKDIR 1
+#define HAVE_MKFIFO 1
+#define HAVE_MKNOD 1
+#define HAVE_MKSTEMP 1
+#define HAVE_NL_LANGINFO 1
+#define HAVE_OPENAT 1
+#define HAVE_PATHS_H 1
+#define HAVE_PIPE 1
+#define HAVE_POLL 1
+#define HAVE_POLL_H 1
+#define HAVE_POSIX_SPAWNP 1
+#define HAVE_PTHREAD_H 1
+#define HAVE_PWD_H 1
+#define HAVE_READDIR_R 1
+#define HAVE_READLINK 1
+#define HAVE_READLINKAT 1
+#define HAVE_READPASSPHRASE 1
+#define HAVE_READPASSPHRASE_H 1
+#define HAVE_REGEX_H 1
+#define HAVE_SELECT 1
+#define HAVE_SETENV 1
+#define HAVE_SETLOCALE 1
+#define HAVE_SIGACTION 1
+#define HAVE_SIGNAL_H 1
+#define HAVE_SPAWN_H 1
+#define HAVE_STATFS 1
+#define HAVE_STATVFS 1
+#define HAVE_STDARG_H 1
+#define HAVE_STDINT_H 1
+#define HAVE_STDLIB_H 1
+#define HAVE_STRCHR 1
+#define HAVE_STRDUP 1
+#define HAVE_STRERROR 1
+#define HAVE_STRERROR_R 1
+#define HAVE_STRFTIME 1
+#define HAVE_STRINGS_H 1
+#define HAVE_STRING_H 1
+#define HAVE_STRRCHR 1
+#define HAVE_STRUCT_STATFS_F_NAMEMAX 1
+#define HAVE_STRUCT_STAT_ST_BIRTHTIME 1
+#define HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC_TV_NSEC 1
+#define HAVE_STRUCT_STAT_ST_BLKSIZE 1
+#define HAVE_STRUCT_STAT_ST_FLAGS 1
+#define HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1
+#define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1
+#define HAVE_STRUCT_TM_TM_GMTOFF 1
+#define HAVE_SYMLINK 1
+#define HAVE_SYS_CDEFS_H 1
+#define HAVE_SYS_IOCTL_H 1
+#define HAVE_SYS_MOUNT_H 1
+#define HAVE_SYS_PARAM_H 1
+#define HAVE_SYS_POLL_H 1
+#define HAVE_SYS_SELECT_H 1
+#define HAVE_SYS_STATVFS_H 1
+#define HAVE_SYS_STAT_H 1
+#define HAVE_SYS_TIME_H 1
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_SYS_UTSNAME_H 1
+#define HAVE_SYS_WAIT_H 1
+#define HAVE_TIMEGM 1
+#define HAVE_TIME_H 1
+#define HAVE_TZSET 1
+#define HAVE_UINTMAX_T 1
+#define HAVE_UNISTD_H 1
+#define HAVE_UNSETENV 1
+#define HAVE_UNSIGNED_LONG_LONG 1
+#define HAVE_UNSIGNED_LONG_LONG_INT 1
+#define HAVE_UTIME 1
+#define HAVE_UTIMES 1
+#define HAVE_UTIME_H 1
+#define HAVE_VFORK 1
+#define HAVE_VPRINTF 1
+#define HAVE_WCHAR_H 1
+#define HAVE_WCHAR_T 1
+#define HAVE_WCRTOMB 1
+#define HAVE_WCSCMP 1
+#define HAVE_WCSCPY 1
+#define HAVE_WCSLEN 1
+#define HAVE_WCTOMB 1
+#define HAVE_WCTYPE_H 1
+#define HAVE_WMEMCMP 1
+#define HAVE_WMEMCPY 1
+#define HAVE_WMEMMOVE 1
+#define HAVE_ZLIB_H 1
+#define TIME_WITH_SYS_TIME 1
+
+#if __FreeBSD_version >= 1100056
+#define HAVE_FUTIMENS 1
+#define HAVE_UTIMENSAT 1
+#endif
 
 /* FreeBSD 4 and earlier lack intmax_t/uintmax_t */
 #if __FreeBSD__ < 5
-#define	intmax_t int64_t
-#define	uintmax_t uint64_t
+#define intmax_t int64_t
+#define uintmax_t uint64_t
+#endif
+
+/* FreeBSD defines for archive_hash.h */
+#ifdef WITH_OPENSSL
+#define ARCHIVE_CRYPTO_MD5_OPENSSL 1
+#define ARCHIVE_CRYPTO_RMD160_OPENSSL 1
+#define ARCHIVE_CRYPTO_SHA1_OPENSSL
+#define ARCHIVE_CRYPTO_SHA256_OPENSSL 1
+#define ARCHIVE_CRYPTO_SHA384_OPENSSL 1
+#define ARCHIVE_CRYPTO_SHA512_OPENSSL 1
+#else
+#define ARCHIVE_CRYPTO_MD5_LIBMD 1
+#define ARCHIVE_CRYPTO_SHA1_LIBMD 1
+#define ARCHIVE_CRYPTO_SHA256_LIBMD 1
+#define ARCHIVE_CRYPTO_SHA512_LIBMD 1
 #endif
diff --git a/libarchive/libarchive_changes.3 b/libarchive/libarchive_changes.3
index 881a67c..adc87fe 100644
--- a/libarchive/libarchive_changes.3
+++ b/libarchive/libarchive_changes.3
@@ -28,6 +28,7 @@
 .Dt LIBARCHIVE_CHANGES 3
 .Os
 .Sh NAME
+.Nm libarchive_changes
 .Nd changes in libarchive interface
 .\"
 .Sh CHANGES IN LIBARCHIVE 3
diff --git a/libarchive/mtree.5 b/libarchive/mtree.5
index 16c8abe..e607e4a 100644
--- a/libarchive/mtree.5
+++ b/libarchive/mtree.5
@@ -48,7 +48,7 @@ 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
diff --git a/libarchive/xxhash.c b/libarchive/xxhash.c
index 6f5ba52..70750ba 100644
--- a/libarchive/xxhash.c
+++ b/libarchive/xxhash.c
@@ -141,13 +141,19 @@ typedef struct _U32_S { U32 v; } _PACKED U32_S;
 #  pragma pack(pop)
 #endif
 
-#define A32(x) (((const U32_S *)(x))->v)
-
 
 /****************************************
 ** Compiler-specific Functions and Macros
 *****************************************/
-#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
+#define GCC_VERSION ((__GNUC__-0) * 100 + (__GNUC_MINOR__ - 0))
+
+#if GCC_VERSION >= 409
+__attribute__((__no_sanitize_undefined__))
+#endif
+static inline U32 A32(const void * x)
+{
+    return (((const U32_S *)(x))->v);
+}
 
 /* Note : although _rotl exists for minGW (GCC under windows), performance seems poor */
 #if defined(_MSC_VER)
-- 
cgit v0.12