]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Add NFSv4 ACL support for Linux via librichacl
authorMartin Matuska <martin@matuska.org>
Wed, 15 Mar 2017 22:27:48 +0000 (23:27 +0100)
committerMartin Matuska <martin@matuska.org>
Thu, 16 Mar 2017 10:39:08 +0000 (11:39 +0100)
Richacls are interpreted as NFSv4 ACLs and stored in archive_acl (Richacl
flags and masks are not stored). Analog to mac_metadata, NFSv4 ACLs do not
get extracted when the extraction of extended attributes is enabled and the
"trusted.richacl" extended attribute is present.

RichACL masks and are calculated from file mode on extraction.

mac_metadata acl check has been moved in the code to be together with the
richacl check.

18 files changed:
CMakeLists.txt
NEWS
build/cmake/config.h.in
cat/test/CMakeLists.txt
configure.ac
cpio/test/CMakeLists.txt
libarchive/archive_acl_maps_linux.c
libarchive/archive_platform_acl.h
libarchive/archive_read_disk_acl_linux.c
libarchive/archive_write_disk_acl_darwin.c
libarchive/archive_write_disk_acl_freebsd.c
libarchive/archive_write_disk_acl_linux.c
libarchive/archive_write_disk_acl_sunos.c
libarchive/archive_write_disk_posix.c
libarchive/archive_write_disk_private.h
libarchive/test/test_acl_platform_nfs4.c
tar/test/CMakeLists.txt
test_utils/test_main.c

index c91b1deac8129d11b5cb2a8e6342f22c9c4f7c53..f62153cb1fcc19c39333e90f8d84880926f817c1 100644 (file)
@@ -602,6 +602,7 @@ 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)
@@ -1739,21 +1740,59 @@ int main(void) { return ACL_SYNCHRONIZE; }" HAVE_DECL_ACL_SYNCHRONIZE)
   ENDIF(HAVE_ACL_T AND HAVE_ACL_ENTRY_T AND HAVE_ACL_PERMSET_T AND
         HAVE_ACL_TAG_T)
 
-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)
-  MESSAGE(STATUS "ACL support: libacl (POSIX.1e)")
-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()
+  # 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()
 
 ELSE(ENABLE_ACL)
   # If someone runs cmake, then disables ACL support, we need
diff --git a/NEWS b/NEWS
index fdd971d7142cb1a20bd22b40a8033c10578a20fc..9e517934547ef31a8ae6bf41a2f3f5cb93a0d096 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,5 @@
+Mar 16, 2017: NFSv4 ACL support for Linux (librichacl)
+
 Feb 26, 2017: libarchive 3.3.1 released
     Security & Feature release
 
index c46a341a40b7aa9b4979c66bcb39a6084e72e887..cfd2a5c0aa83a4192eb1e15047008975134625aa 100644 (file)
@@ -188,9 +188,12 @@ typedef uint64_t uintmax_t;
 /* FreeBSD NFSv4 ACL support */
 #cmakedefine ARCHIVE_ACL_FREEBSD_NFS4 1
 
-/* Linux ACL support via libacl */
+/* 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
 
@@ -1031,6 +1034,9 @@ typedef uint64_t uintmax_t;
 /* Define to 1 if you have the <sys/poll.h> header file. */
 #cmakedefine HAVE_SYS_POLL_H 1
 
+/* Define to 1 if you have the <sys/richacl.h> header file. */
+#cmakedefine HAVE_SYS_RICHACL_H 1
+
 /* Define to 1 if you have the <sys/select.h> header file. */
 #cmakedefine HAVE_SYS_SELECT_H 1
 
index 0623cc367227bb9a4ac12f19107c6c2c73133b26..0cd3aad84f49584ae57307f578eefe3f1bb9eb3e 100644 (file)
@@ -30,9 +30,14 @@ IF(ENABLE_CAT AND ENABLE_TEST)
   #
   ADD_EXECUTABLE(bsdcat_test ${bsdcat_test_SOURCES})
   IF(ENABLE_ACL)
+    SET(TEST_ACL_LIBS "")
     IF(HAVE_LIBACL)
-      TARGET_LINK_LIBRARIES(bsdcat_test ${ACL_LIBRARY})
+      LIST(APPEND TEST_ACL_LIBS ${ACL_LIBRARY})
     ENDIF(HAVE_LIBACL)
+    IF(HAVE_LIBRICHACL)
+      LIST(APPEND TEST_ACL_LIBS ${RICHACL_LIBRARY})
+    ENDIF(HAVE_LIBRICHACL)
+    TARGET_LINK_LIBRARIES(bsdcat_test ${TEST_ACL_LIBS})
   ENDIF(ENABLE_ACL)
   SET_PROPERTY(TARGET bsdcat_test PROPERTY COMPILE_DEFINITIONS LIST_H)
 
index 24e96d68f897245a5337742ab4dc106d307441bd..05b5a09939c01595a8b53dc43d1cec66f735079e 100644 (file)
@@ -289,7 +289,8 @@ AC_CHECK_HEADERS([readpassphrase.h signal.h spawn.h])
 AC_CHECK_HEADERS([stdarg.h stdint.h stdlib.h string.h])
 AC_CHECK_HEADERS([sys/acl.h sys/cdefs.h sys/extattr.h])
 AC_CHECK_HEADERS([sys/ioctl.h sys/mkdev.h sys/mount.h])
-AC_CHECK_HEADERS([sys/param.h sys/poll.h sys/select.h sys/statfs.h sys/statvfs.h])
+AC_CHECK_HEADERS([sys/param.h sys/poll.h sys/richacl.h])
+AC_CHECK_HEADERS([sys/select.h sys/statfs.h sys/statvfs.h])
 AC_CHECK_HEADERS([sys/time.h sys/utime.h sys/utsname.h sys/vfs.h])
 AC_CHECK_HEADERS([time.h unistd.h utime.h wchar.h wctype.h])
 AC_CHECK_HEADERS([windows.h])
@@ -712,9 +713,31 @@ if test "x$enable_acl" != "xno"; then
       #endif
     ])
 
+    AC_CHECK_LIB([richacl], [richacl_get_file])
+
+    AC_CHECK_TYPES([[struct richace], [struct richacl]], [], [], [
+      #if HAVE_SYS_RICHACL_H
+      #include <sys/richacl.h>
+      #endif
+    ])
+
     # Solaris and derivates ACLs
     AC_CHECK_FUNCS(acl facl)
 
+    if test "x$ac_cv_lib_richacl_richacl_get_file" = "xyes" \
+        -a "x$ac_cv_type_struct_richace" = "xyes" \
+        -a "x$ac_cv_type_struct_richacl" = "xyes"; then
+       AC_CACHE_VAL([ac_cv_archive_acl_librichacl],
+         [AC_CHECK_FUNCS(richacl_alloc \
+                         richacl_equiv_mode \
+                         richacl_free \
+                         richacl_get_fd \
+                         richacl_get_file \
+                         richacl_set_fd \
+                         richacl_set_file,
+         [ac_cv_archive_acl_librichacl=yes], [ac_cv_archive_acl_librichacl=no],          [#include <sys/richacl.h>])])
+    fi
+
     if test "x$ac_cv_func_acl" = "xyes" \
         -a "x$ac_cv_func_facl" = "xyes"; then
        AC_CHECK_TYPES([aclent_t], [], [], [[#include <sys/acl.h>]])
@@ -833,9 +856,21 @@ if test "x$enable_acl" != "xno"; then
        fi
     fi
     AC_MSG_CHECKING([for ACL support])
-    if test "x$ac_cv_archive_acl_libacl" = "xyes"; then
+    if test "x$ac_cv_archive_acl_libacl" = "xyes" \
+        -a "x$ac_cv_archive_acl_librichacl" = "xyes"; then
+       AC_MSG_RESULT([libacl (POSIX.1e) + librichacl (NFSv4)])
+       AC_DEFINE([ARCHIVE_ACL_LIBACL], [1],
+         [Linux POSIX.1e ACL support via libacl])
+       AC_DEFINE([ARCHIVE_ACL_LIBRICHACL], [1],
+         [Linux NFSv4 ACL support via librichacl])
+    elif test "x$ac_cv_archive_acl_libacl" = "xyes"; then
        AC_MSG_RESULT([libacl (POSIX.1e)])
-       AC_DEFINE([ARCHIVE_ACL_LIBACL], [1], [Linux ACL support via libacl])
+       AC_DEFINE([ARCHIVE_ACL_LIBACL], [1],
+         [Linux POSIX.1e ACL support via libacl])
+    elif test "x$ac_cv_archive_acl_librichacl" = "xyes"; then
+       AC_MSG_RESULT([librichacl (NFSv4)])
+       AC_DEFINE([ARCHIVE_ACL_LIBRICHACL], [1],
+         [Linux NFSv4 ACL support via librichacl])
     elif test "x$ac_cv_archive_acl_darwin" = "xyes"; then
        AC_DEFINE([ARCHIVE_ACL_DARWIN], [1], [Darwin ACL support])
        AC_MSG_RESULT([Darwin (limited NFSv4)])
@@ -863,7 +898,9 @@ if test "x$enable_acl" != "xno"; then
 fi
 
 
-AM_CONDITIONAL([INC_LINUX_ACL], [test "x$ac_cv_archive_acl_libacl" = "xyes"])
+AM_CONDITIONAL([INC_LINUX_ACL],
+  [test "x$ac_cv_archive_acl_libacl" = "xyes" \
+     -o "x$ac_cv_archive_acl_librichacl" = "xyes"])
 AM_CONDITIONAL([INC_SUNOS_ACL], [test "x$ac_cv_archive_acl_sunos" = "xyes"])
 AM_CONDITIONAL([INC_DARWIN_ACL],
          [test "x$ac_cv_archive_acl_darwin" = "xyes"])
index cc5fe0117db3f19b995869debbdbc0dd222c812f..4c3fb88a61fd67fd7420f91bc17172169ef86e7a 100644 (file)
@@ -63,9 +63,14 @@ IF(ENABLE_CPIO AND ENABLE_TEST)
   #
   ADD_EXECUTABLE(bsdcpio_test ${bsdcpio_test_SOURCES})
   IF(ENABLE_ACL)
+    SET(TEST_ACL_LIBS "")
     IF(HAVE_LIBACL)
-      TARGET_LINK_LIBRARIES(bsdcpio_test ${ACL_LIBRARY})
+      LIST(APPEND TEST_ACL_LIBS ${ACL_LIBRARY})
     ENDIF(HAVE_LIBACL)
+    IF(HAVE_LIBRICHACL)
+      LIST(APPEND TEST_ACL_LIBS ${RICHACL_LIBRARY})
+    ENDIF(HAVE_LIBRICHACL)
+    TARGET_LINK_LIBRARIES(bsdcpio_test ${TEST_ACL_LIBS})
   ENDIF(ENABLE_ACL)
   SET_PROPERTY(TARGET bsdcpio_test PROPERTY COMPILE_DEFINITIONS LIST_H)
 
index c184f20b4421fa818c89250383326c529d545f23..3476e12c19e1ec24dd2031c98b1e9ebd460f78e4 100644 (file)
@@ -32,6 +32,9 @@
 #define _ACL_PRIVATE /* For debugging */
 #include <sys/acl.h>
 #endif
+#ifdef HAVE_SYS_RICHACL_H
+#include <sys/richacl.h>
+#endif
 
 #include "archive_entry.h"
 #include "archive_private.h"
@@ -39,6 +42,7 @@
 #define _ARCHIVE_ACL_MAPS_DEFS
 #include "archive_acl_maps.h"
 
+#if ARCHIVE_ACL_LIBACL
 const acl_perm_map_t acl_posix_perm_map[] = {
        {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
        {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE},
@@ -47,3 +51,40 @@ const acl_perm_map_t acl_posix_perm_map[] = {
 
 const int acl_posix_perm_map_size =
     (int)(sizeof(acl_posix_perm_map)/sizeof(acl_posix_perm_map[0]));
+#endif /* ARCHIVE_ACL_LIBACL */
+
+#if ARCHIVE_ACL_LIBRICHACL
+const acl_perm_map_t acl_nfs4_perm_map[] = {
+       {ARCHIVE_ENTRY_ACL_EXECUTE, RICHACE_EXECUTE},
+       {ARCHIVE_ENTRY_ACL_READ_DATA, RICHACE_READ_DATA},
+       {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, RICHACE_LIST_DIRECTORY},
+       {ARCHIVE_ENTRY_ACL_WRITE_DATA, RICHACE_WRITE_DATA},
+       {ARCHIVE_ENTRY_ACL_ADD_FILE, RICHACE_ADD_FILE},
+       {ARCHIVE_ENTRY_ACL_APPEND_DATA, RICHACE_APPEND_DATA},
+       {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, RICHACE_ADD_SUBDIRECTORY},
+       {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, RICHACE_READ_NAMED_ATTRS},
+       {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, RICHACE_WRITE_NAMED_ATTRS},
+       {ARCHIVE_ENTRY_ACL_DELETE_CHILD, RICHACE_DELETE_CHILD},
+       {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, RICHACE_READ_ATTRIBUTES},
+       {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, RICHACE_WRITE_ATTRIBUTES},
+       {ARCHIVE_ENTRY_ACL_DELETE, RICHACE_DELETE},
+       {ARCHIVE_ENTRY_ACL_READ_ACL, RICHACE_READ_ACL},
+       {ARCHIVE_ENTRY_ACL_WRITE_ACL, RICHACE_WRITE_ACL},
+       {ARCHIVE_ENTRY_ACL_WRITE_OWNER, RICHACE_WRITE_OWNER},
+       {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, RICHACE_SYNCHRONIZE}
+};
+
+const int acl_nfs4_perm_map_size =
+    (int)(sizeof(acl_nfs4_perm_map)/sizeof(acl_nfs4_perm_map[0]));
+
+const acl_perm_map_t acl_nfs4_flag_map[] = {
+       {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, RICHACE_FILE_INHERIT_ACE},
+       {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, RICHACE_DIRECTORY_INHERIT_ACE},
+       {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, RICHACE_NO_PROPAGATE_INHERIT_ACE},
+       {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, RICHACE_INHERIT_ONLY_ACE},
+       {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, RICHACE_INHERITED_ACE}
+};
+
+const int acl_nfs4_flag_map_size =
+    (int)(sizeof(acl_nfs4_flag_map)/sizeof(acl_nfs4_flag_map[0]));
+#endif /* ARCHIVE_ACL_LIBRICHACL */
index 8c091cf5112dac664b09607789a8ee9bb435dad9..3498f78b3c8577646c617d819aa568dda2ed004f 100644 (file)
@@ -37,7 +37,8 @@
 #define ARCHIVE_ACL_POSIX1E     1
 #endif
 
-#if ARCHIVE_ACL_FREEBSD_NFS4 || ARCHIVE_ACL_SUNOS_NFS4 || ARCHIVE_ACL_DARWIN
+#if ARCHIVE_ACL_FREEBSD_NFS4 || ARCHIVE_ACL_SUNOS_NFS4 || \
+    ARCHIVE_ACL_DARWIN  || ARCHIVE_ACL_LIBRICHACL
 #define ARCHIVE_ACL_NFS4        1
 #endif
 
index 23146dba74a600189324375b02ad76ce2f2859f4..3ddee2fef16a3c7bc4c19accc7b3fce73cccb101 100644 (file)
 #ifdef HAVE_FCNTL_H
 #include <fcntl.h>
 #endif
-#if HAVE_ACL_LIBACL_H && HAVE_LIBACL
+#if HAVE_ACL_LIBACL_H
 #include <acl/libacl.h>
 #endif
 #ifdef HAVE_SYS_ACL_H
 #include <sys/acl.h>
 #endif
+#if HAVE_SYS_RICHACL_H
+#include <sys/richacl.h>
+#endif
 
 #include "archive_entry.h"
 #include "archive_private.h"
@@ -49,6 +52,7 @@
 #include <acl/libacl.h>
 #endif
 
+#if ARCHIVE_ACL_LIBACL
 /*
  * Translate POSIX.1e ACLs into libarchive internal structure
  */
@@ -154,15 +158,104 @@ translate_acl(struct archive_read_disk *a,
        }
        return (ARCHIVE_OK);
 }
+#endif /* ARCHIVE_ACL_LIBACL */
+
+#if ARCHIVE_ACL_LIBRICHACL
+/*
+ * Translate RichACL into libarchive internal ACL
+ */
+static int
+translate_richacl(struct archive_read_disk *a, struct archive_entry *entry,
+    struct richacl *richacl)
+{
+       int ae_id, ae_tag, ae_perm;
+       int entry_acl_type, i;
+       const char *ae_name;
+
+       struct richace *richace;
+
+       richacl_for_each_entry(richace, richacl) {
+               ae_name = NULL;
+               ae_tag = 0;
+               ae_perm = 0;
+               ae_id = -1;
+
+               switch (richace->e_type) {
+               case RICHACE_ACCESS_ALLOWED_ACE_TYPE:
+                       entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
+                       break;
+               case RICHACE_ACCESS_DENIED_ACE_TYPE:
+                       entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
+                       break;
+               default: /* Unknown entry type, skip */
+                       continue;
+               }
+
+               /* Unsupported */
+               if (richace->e_flags & RICHACE_UNMAPPED_WHO)
+                       continue;
+
+               if (richace->e_flags & RICHACE_SPECIAL_WHO) {
+                       switch (richace->e_id) {
+                       case RICHACE_OWNER_SPECIAL_ID:
+                               ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
+                               break;
+                       case RICHACE_GROUP_SPECIAL_ID:
+                               ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+                               break;
+                       case RICHACE_EVERYONE_SPECIAL_ID:
+                               ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE;
+                               break;
+                       default: /* Unknown special ID type */
+                               continue;
+                       }
+               } else {
+                       ae_id = richace->e_id;
+                       if (richace->e_flags & RICHACE_IDENTIFIER_GROUP) {
+                               ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
+                               ae_name = archive_read_disk_gname(&a->archive,
+                                   (gid_t)(richace->e_id));
+                       } else {
+                               ae_tag = ARCHIVE_ENTRY_ACL_USER;
+                               ae_name = archive_read_disk_uname(&a->archive,
+                                   (uid_t)(richace->e_id));
+                       }
+               }
+               for (i = 0; i < acl_nfs4_flag_map_size; ++i) {
+                       if ((richace->e_flags &
+                           acl_nfs4_flag_map[i].p_perm) != 0)
+                               ae_perm |= acl_nfs4_flag_map[i].a_perm;
+               }
+               for (i = 0; i < acl_nfs4_perm_map_size; ++i) {
+                       if ((richace->e_mask &
+                           acl_nfs4_perm_map[i].p_perm) != 0)
+                               ae_perm |=
+                                   acl_nfs4_perm_map[i].a_perm;
+               }
+
+               archive_entry_acl_add_entry(entry, entry_acl_type,
+                   ae_perm, ae_tag, ae_id, ae_name);
+       }
+       return (ARCHIVE_OK);
+}
+#endif /* ARCHIVE_ACL_LIBRICHACL */
+
 int
 archive_read_disk_entry_setup_acls(struct archive_read_disk *a,
     struct archive_entry *entry, int *fd)
 {
        const char      *accpath;
-       acl_t           acl;
        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)))
@@ -185,8 +278,50 @@ archive_read_disk_entry_setup_acls(struct archive_read_disk *a,
 
        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);
@@ -224,5 +359,6 @@ archive_read_disk_entry_setup_acls(struct archive_read_disk *a,
                        }
                }
        }
-       return (ARCHIVE_OK);
+#endif /* ARCHIVE_ACL_LIBACL */
+       return (r);
 }
index 22375c76414e6bb566160482575786a08011d9d2..4ffdd66b4333e26cbb5336cc915c590176f6e39e 100644 (file)
@@ -219,10 +219,12 @@ exit_free:
 
 int
 archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
-    struct archive_acl *abstract_acl)
+    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,
index d6b8767137758270027e287ec3594d4c75aa5d4b..29e64adf0f337143797e71205457e96f4e78a41d 100644 (file)
@@ -287,10 +287,12 @@ exit_free:
 
 int
 archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
-    struct archive_acl *abstract_acl)
+    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)
index 15af1a1baa1f1f26d37c2f39ca981d34a4d10e5f..2239df6c10f70b4f482b8493b89135b2acdedd80 100644 (file)
 #ifdef HAVE_FCNTL_H
 #include <fcntl.h>
 #endif
-#if HAVE_ACL_LIBACL_H && HAVE_LIBACL
+#if HAVE_ACL_LIBACL_H
 #include <acl/libacl.h>
 #endif
 #ifdef HAVE_SYS_ACL_H
 #include <sys/acl.h>
 #endif
+#if HAVE_SYS_RICHACL_H
+#include <sys/richacl.h>
+#endif
 
 #include "archive.h"
 #include "archive_entry.h"
 #include "archive_write_disk_private.h"
 #include "archive_acl_maps.h"
 
+#if ARCHIVE_ACL_LIBRICHACL
+static int
+_richacl_mode_to_mask(short mode)
+{
+       int mask = 0;
+
+       if (mode & S_IROTH)
+               mask |= RICHACE_POSIX_MODE_READ;
+       if (mode & S_IWOTH)
+               mask |= RICHACE_POSIX_MODE_WRITE;
+       if (mode & S_IXOTH)
+               mask |= RICHACE_POSIX_MODE_EXEC;
+
+       return (mask);
+}
+
+static void
+_richacl_mode_to_masks(struct richacl *richacl, __LA_MODE_T mode)
+{
+       richacl->a_owner_mask = _richacl_mode_to_mask((mode & 0700) >> 6);
+       richacl->a_group_mask = _richacl_mode_to_mask((mode & 0070) >> 3);
+       richacl->a_other_mask = _richacl_mode_to_mask(mode & 0007);
+}
+#endif /* ARCHIVE_ACL_LIBRICHACL */
+
+#if ARCHIVE_ACL_LIBRICHACL
+static int
+set_richacl(struct archive *a, int fd, const char *name,
+    struct archive_acl *abstract_acl, __LA_MODE_T mode,
+    int ae_requested_type, const char *tname)
+{
+       int              ae_type, ae_permset, ae_tag, ae_id;
+       uid_t            ae_uid;
+       gid_t            ae_gid;
+       const char      *ae_name;
+       int              entries;
+       int              i;
+       int              ret;
+       int              e = 0;
+       struct richacl  *richacl = NULL;
+       struct richace  *richace;
+
+       ret = ARCHIVE_OK;
+       entries = archive_acl_reset(abstract_acl, ae_requested_type);
+       if (entries == 0)
+               return (ARCHIVE_OK);
+
+       if (ae_requested_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
+               errno = ENOENT;
+               archive_set_error(a, errno, "Unsupported ACL type");
+               return (ARCHIVE_FAILED);
+       }
+
+       richacl = richacl_alloc(entries);
+       if (richacl == NULL) {
+               archive_set_error(a, errno,
+                       "Failed to initialize RichACL working storage");
+               return (ARCHIVE_FAILED);
+       }
+
+       e = 0;
+
+       while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type,
+                  &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) {
+               richace = &(richacl->a_entries[e]);
+
+               richace->e_flags = 0;
+               richace->e_mask = 0;
+
+               switch (ae_tag) {
+               case ARCHIVE_ENTRY_ACL_USER:
+                       ae_uid = archive_write_disk_uid(a, ae_name, ae_id);
+                       richace->e_id = ae_uid;
+                       break;
+               case ARCHIVE_ENTRY_ACL_GROUP:
+                       ae_gid = archive_write_disk_gid(a, ae_name, ae_id);
+                       richace->e_id = ae_gid;
+                       richace->e_flags |= RICHACE_IDENTIFIER_GROUP;
+                       break;
+               case ARCHIVE_ENTRY_ACL_USER_OBJ:
+                       richace->e_flags |= RICHACE_SPECIAL_WHO;
+                       richace->e_id = RICHACE_OWNER_SPECIAL_ID;
+                       break;
+               case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+                       richace->e_flags |= RICHACE_SPECIAL_WHO;
+                       richace->e_id = RICHACE_GROUP_SPECIAL_ID;
+                       break;
+               case ARCHIVE_ENTRY_ACL_EVERYONE:
+                       richace->e_flags |= RICHACE_SPECIAL_WHO;
+                       richace->e_id = RICHACE_EVERYONE_SPECIAL_ID;
+                       break;
+               default:
+                       archive_set_error(a, ARCHIVE_ERRNO_MISC,
+                           "Unsupported ACL tag");
+                       ret = ARCHIVE_FAILED;
+                       goto exit_free;
+               }
+
+               switch (ae_type) {
+                       case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
+                               richace->e_type =
+                                   RICHACE_ACCESS_ALLOWED_ACE_TYPE;
+                               break;
+                       case ARCHIVE_ENTRY_ACL_TYPE_DENY:
+                               richace->e_type =
+                                   RICHACE_ACCESS_DENIED_ACE_TYPE;
+                               break;
+                       case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
+                       case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
+                               break;
+               default:
+                       archive_set_error(a, ARCHIVE_ERRNO_MISC,
+                           "Unsupported ACL entry type");
+                       ret = ARCHIVE_FAILED;
+                       goto exit_free;
+               }
+
+               for (i = 0; i < acl_nfs4_perm_map_size; ++i) {
+                       if (ae_permset & acl_nfs4_perm_map[i].a_perm)
+                               richace->e_mask |= acl_nfs4_perm_map[i].p_perm;
+               }
+
+               for (i = 0; i < acl_nfs4_flag_map_size; ++i) {
+                       if (ae_permset &
+                           acl_nfs4_flag_map[i].a_perm)
+                               richace->e_flags |= acl_nfs4_flag_map[i].p_perm;
+               }
+       e++;
+       }
+
+       /* Fill RichACL masks */
+       _richacl_mode_to_masks(richacl, mode);
+
+       if (fd >= 0) {
+               if (richacl_set_fd(fd, richacl) == 0)
+                       ret = ARCHIVE_OK;
+               else {
+                       if (errno == EOPNOTSUPP) {
+                               /* Filesystem doesn't support ACLs */
+                               ret = ARCHIVE_OK;
+                       } else {
+                               archive_set_error(a, errno,
+                                   "Failed to set richacl on fd: %s", tname);
+                               ret = ARCHIVE_WARN;
+                       }
+               }
+       } else if (richacl_set_file(name, richacl) != 0) {
+               if (errno == EOPNOTSUPP) {
+                       /* Filesystem doesn't support ACLs */
+                       ret = ARCHIVE_OK;
+               } else {
+                       archive_set_error(a, errno, "Failed to set richacl: %s",
+                           tname);
+                       ret = ARCHIVE_WARN;
+               }
+       }
+exit_free:
+       richacl_free(richacl);
+       return (ret);
+}
+#endif /* ARCHIVE_ACL_RICHACL */
+
+#if ARCHIVE_ACL_LIBACL
 static int
 set_acl(struct archive *a, int fd, const char *name,
     struct archive_acl *abstract_acl,
     int ae_requested_type, const char *tname)
 {
        int              acl_type = 0;
-       acl_t            acl;
-       acl_entry_t      acl_entry;
-       acl_permset_t    acl_permset;
-       int              ret;
        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;
@@ -89,12 +254,14 @@ set_acl(struct archive *a, int fd, const char *name,
 
        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);
@@ -179,13 +346,29 @@ exit_free:
        acl_free(acl);
        return (ret);
 }
+#endif /* ARCHIVE_ACL_LIBACL */
 
 int
 archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
-    struct archive_acl *abstract_acl)
+    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)
@@ -200,5 +383,6 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
                        ret = set_acl(a, fd, name, abstract_acl,
                            ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default");
        }
+#endif /* ARCHIVE_ACL_LIBACL */
        return (ret);
 }
index e8002396a1c021be535bdb170325dd4a870510a6..ebc0b095db932d44a4b614ba0ea0e35a28ced627 100644 (file)
@@ -303,10 +303,12 @@ exit_free:
 
 int
 archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
-    struct archive_acl *abstract_acl)
+    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 */
index 6c0dd19b75ccc1328936ac009e039af441828602..adb15c0e216d0c599fcd63354509a95084693c5b 100644 (file)
@@ -369,10 +369,6 @@ static ssize_t     hfs_write_data_block(struct archive_write_disk *,
 static int     fixup_appledouble(struct archive_write_disk *, const char *);
 static int     older(struct stat *, struct archive_entry *);
 static int     restore_entry(struct archive_write_disk *);
-#ifndef ARCHIVE_ACL_SUPPORT
-static int     archive_write_disk_set_acls(struct archive *, int, const char *,
-                                           struct archive_acl *);
-#endif
 static int     set_mac_metadata(struct archive_write_disk *, const char *,
                                 const void *, size_t);
 static int     set_xattrs(struct archive_write_disk *);
@@ -429,19 +425,6 @@ lazy_stat(struct archive_write_disk *a)
        return (ARCHIVE_WARN);
 }
 
-#ifndef ARCHIVE_ACL_SUPPORT
-static 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);
-}
-#endif
-
 static struct archive_vtable *
 archive_write_disk_vtable(void)
 {
@@ -592,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)
@@ -1720,25 +1748,11 @@ _archive_write_disk_finish_entry(struct archive *_a)
         */
        if (a->todo & TODO_ACLS) {
                int r2;
-#if ARCHIVE_ACL_DARWIN
-               /*
-                * 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;
-#if ARCHIVE_ACL_DARWIN
-               }
-#endif
        }
 
 finish_metadata:
@@ -2310,13 +2324,8 @@ _archive_write_disk_close(struct archive *_a)
                if (p->fixup & TODO_MODE_BASE)
                        chmod(p->name, p->mode);
                if (p->fixup & TODO_ACLS)
-#if ARCHIVE_ACL_DARWIN
-                       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);
@@ -4256,5 +4265,19 @@ older(struct stat *st, struct archive_entry *entry)
        return (0);
 }
 
+#ifndef ARCHIVE_ACL_SUPPORT
+int
+archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
+    struct archive_acl *abstract_acl, __LA_MODE_T mode)
+{
+       (void)a; /* UNUSED */
+       (void)fd; /* UNUSED */
+       (void)name; /* UNUSED */
+       (void)abstract_acl; /* UNUSED */
+       (void)mode; /* UNUSED */
+       return (ARCHIVE_OK);
+}
+#endif
+
 #endif /* !_WIN32 || __CYGWIN__ */
 
index c5814b4bc6939584c9eac1b66290b130f54890cd..b655dea2b659b832426cc8e226fe784b9476b66e 100644 (file)
 
 #include "archive_platform_acl.h"
 #include "archive_acl_private.h"
+#include "archive_entry.h"
 
 struct archive_write_disk;
 
-#if ARCHIVE_ACL_SUPPORT
-int
-archive_write_disk_set_acls(struct archive *, int /* fd */, const char * /* pathname */, struct archive_acl *);
-#endif
+int archive_write_disk_set_acls(struct archive *, int, const char *,
+    struct archive_acl *, __LA_MODE_T);
 
 #endif
index b8dce1223bb64117ed8bf058430ada618171b3c1..a3868a627eeae9d5c77f01eebd225442a9bc9d1c 100644 (file)
 __FBSDID("$FreeBSD$");
 
 #if ARCHIVE_ACL_NFS4
+#if HAVE_SYS_ACL_H
 #define _ACL_PRIVATE
 #include <sys/acl.h>
+#endif
+#if HAVE_SYS_RICHACL_H
+#include <sys/richacl.h>
+#endif
 #if HAVE_MEMBERSHIP_H
 #include <membership.h>
 #endif
@@ -273,78 +278,96 @@ set_acls(struct archive_entry *ae, struct myacl_t *acls, int start, int end)
 }
 
 static int
-#ifdef ARCHIVE_ACL_SUNOS_NFS4
-acl_permset_to_bitmap(uint32_t a_access_mask)
+#if ARCHIVE_ACL_SUNOS_NFS4
+acl_permset_to_bitmap(uint32_t mask)
+#elif ARCHIVE_ACL_LIBRICHACL
+acl_permset_to_bitmap(unsigned int mask)
 #else
 acl_permset_to_bitmap(acl_permset_t opaque_ps)
 #endif
 {
-       static struct { int machine; int portable; } perms[] = {
+       static struct { int portable; int machine; } perms[] = {
 #ifdef ARCHIVE_ACL_SUNOS_NFS4  /* Solaris NFSv4 ACL permissions */
-               {ACE_EXECUTE, ARCHIVE_ENTRY_ACL_EXECUTE},
-               {ACE_READ_DATA, ARCHIVE_ENTRY_ACL_READ_DATA},
-               {ACE_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY},
-               {ACE_WRITE_DATA, ARCHIVE_ENTRY_ACL_WRITE_DATA},
-               {ACE_ADD_FILE, ARCHIVE_ENTRY_ACL_ADD_FILE},
-               {ACE_APPEND_DATA, ARCHIVE_ENTRY_ACL_APPEND_DATA},
-               {ACE_ADD_SUBDIRECTORY, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY},
-               {ACE_READ_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS},
-               {ACE_WRITE_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS},
-               {ACE_DELETE_CHILD, ARCHIVE_ENTRY_ACL_DELETE_CHILD},
-               {ACE_READ_ATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES},
-               {ACE_WRITE_ATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES},
-               {ACE_DELETE, ARCHIVE_ENTRY_ACL_DELETE},
-               {ACE_READ_ACL, ARCHIVE_ENTRY_ACL_READ_ACL},
-               {ACE_WRITE_ACL, ARCHIVE_ENTRY_ACL_WRITE_ACL},
-               {ACE_WRITE_OWNER, ARCHIVE_ENTRY_ACL_WRITE_OWNER},
-               {ACE_SYNCHRONIZE, ARCHIVE_ENTRY_ACL_SYNCHRONIZE}
+               {ARCHIVE_ENTRY_ACL_EXECUTE, ACE_EXECUTE},
+               {ARCHIVE_ENTRY_ACL_READ_DATA, ACE_READ_DATA},
+               {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACE_LIST_DIRECTORY},
+               {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACE_WRITE_DATA},
+               {ARCHIVE_ENTRY_ACL_ADD_FILE, ACE_ADD_FILE},
+               {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACE_APPEND_DATA},
+               {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACE_ADD_SUBDIRECTORY},
+               {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACE_READ_NAMED_ATTRS},
+               {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACE_WRITE_NAMED_ATTRS},
+               {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACE_DELETE_CHILD},
+               {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACE_READ_ATTRIBUTES},
+               {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACE_WRITE_ATTRIBUTES},
+               {ARCHIVE_ENTRY_ACL_DELETE, ACE_DELETE},
+               {ARCHIVE_ENTRY_ACL_READ_ACL, ACE_READ_ACL},
+               {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACE_WRITE_ACL},
+               {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACE_WRITE_OWNER},
+               {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACE_SYNCHRONIZE}
 #elif ARCHIVE_ACL_DARWIN       /* MacOS NFSv4 ACL permissions */
-               {ACL_READ_DATA, ARCHIVE_ENTRY_ACL_READ_DATA},
-               {ACL_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY},
-               {ACL_WRITE_DATA, ARCHIVE_ENTRY_ACL_WRITE_DATA},
-               {ACL_ADD_FILE, ARCHIVE_ENTRY_ACL_ADD_FILE},
-               {ACL_EXECUTE, ARCHIVE_ENTRY_ACL_EXECUTE},
-               {ACL_DELETE, ARCHIVE_ENTRY_ACL_DELETE},
-               {ACL_APPEND_DATA, ARCHIVE_ENTRY_ACL_APPEND_DATA},
-               {ACL_ADD_SUBDIRECTORY, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY},
-               {ACL_DELETE_CHILD, ARCHIVE_ENTRY_ACL_DELETE_CHILD},
-               {ACL_READ_ATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES},
-               {ACL_WRITE_ATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES},
-               {ACL_READ_EXTATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS},
-               {ACL_WRITE_EXTATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS},
-               {ACL_READ_SECURITY, ARCHIVE_ENTRY_ACL_READ_ACL},
-               {ACL_WRITE_SECURITY, ARCHIVE_ENTRY_ACL_WRITE_ACL},
-               {ACL_CHANGE_OWNER, ARCHIVE_ENTRY_ACL_WRITE_OWNER},
+               {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
-               {ACL_SYNCHRONIZE, ARCHIVE_ENTRY_ACL_SYNCHRONIZE},
+               {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
 #endif
+#elif ARCHIVE_ACL_LIBRICHACL
+               {ARCHIVE_ENTRY_ACL_EXECUTE, RICHACE_EXECUTE},
+               {ARCHIVE_ENTRY_ACL_READ_DATA, RICHACE_READ_DATA},
+               {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, RICHACE_LIST_DIRECTORY},
+               {ARCHIVE_ENTRY_ACL_WRITE_DATA, RICHACE_WRITE_DATA},
+               {ARCHIVE_ENTRY_ACL_ADD_FILE, RICHACE_ADD_FILE},
+               {ARCHIVE_ENTRY_ACL_APPEND_DATA, RICHACE_APPEND_DATA},
+               {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, RICHACE_ADD_SUBDIRECTORY},
+               {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, RICHACE_READ_NAMED_ATTRS},
+               {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, RICHACE_WRITE_NAMED_ATTRS},
+               {ARCHIVE_ENTRY_ACL_DELETE_CHILD, RICHACE_DELETE_CHILD},
+               {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, RICHACE_READ_ATTRIBUTES},
+               {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, RICHACE_WRITE_ATTRIBUTES},
+               {ARCHIVE_ENTRY_ACL_DELETE, RICHACE_DELETE},
+               {ARCHIVE_ENTRY_ACL_READ_ACL, RICHACE_READ_ACL},
+               {ARCHIVE_ENTRY_ACL_WRITE_ACL, RICHACE_WRITE_ACL},
+               {ARCHIVE_ENTRY_ACL_WRITE_OWNER, RICHACE_WRITE_OWNER},
+               {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, RICHACE_SYNCHRONIZE}
 #else  /* FreeBSD NFSv4 ACL permissions */
-               {ACL_EXECUTE, ARCHIVE_ENTRY_ACL_EXECUTE},
-               {ACL_WRITE, ARCHIVE_ENTRY_ACL_WRITE},
-               {ACL_READ, ARCHIVE_ENTRY_ACL_READ},
-               {ACL_READ_DATA, ARCHIVE_ENTRY_ACL_READ_DATA},
-               {ACL_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY},
-               {ACL_WRITE_DATA, ARCHIVE_ENTRY_ACL_WRITE_DATA},
-               {ACL_ADD_FILE, ARCHIVE_ENTRY_ACL_ADD_FILE},
-               {ACL_APPEND_DATA, ARCHIVE_ENTRY_ACL_APPEND_DATA},
-               {ACL_ADD_SUBDIRECTORY, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY},
-               {ACL_READ_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS},
-               {ACL_WRITE_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS},
-               {ACL_DELETE_CHILD, ARCHIVE_ENTRY_ACL_DELETE_CHILD},
-               {ACL_READ_ATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES},
-               {ACL_WRITE_ATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES},
-               {ACL_DELETE, ARCHIVE_ENTRY_ACL_DELETE},
-               {ACL_READ_ACL, ARCHIVE_ENTRY_ACL_READ_ACL},
-               {ACL_WRITE_ACL, ARCHIVE_ENTRY_ACL_WRITE_ACL},
-               {ACL_WRITE_OWNER, ARCHIVE_ENTRY_ACL_WRITE_OWNER},
-               {ACL_SYNCHRONIZE, ARCHIVE_ENTRY_ACL_SYNCHRONIZE}
+               {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
+               {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
+               {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
+               {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
+               {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
+               {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
+               {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
+               {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS},
+               {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS},
+               {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
+               {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
+               {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
+               {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
+               {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL},
+               {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL},
+               {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER},
+               {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
 #endif
        };
        int i, permset = 0;
 
        for (i = 0; i < (int)(sizeof(perms)/sizeof(perms[0])); ++i)
-#if ARCHIVE_ACL_SUNOS_NFS4
-               if (a_access_mask & perms[i].machine)
+#if ARCHIVE_ACL_SUNOS_NFS4 || ARCHIVE_ACL_LIBRICHACL
+               if (mask & perms[i].machine)
 #else
                if (acl_get_perm_np(opaque_ps, perms[i].machine))
 #endif
@@ -354,47 +377,55 @@ acl_permset_to_bitmap(acl_permset_t opaque_ps)
 
 static int
 #if ARCHIVE_ACL_SUNOS_NFS4
-acl_flagset_to_bitmap(uint16_t a_flags)
+acl_flagset_to_bitmap(uint16_t flags)
+#elif ARCHIVE_ACL_LIBRICHACL
+acl_flagset_to_bitmap(int flags)
 #else
 acl_flagset_to_bitmap(acl_flagset_t opaque_fs)
 #endif
 {
-       static struct { int machine; int portable; } flags[] = {
+       static struct { int portable; int machine; } perms[] = {
 #if ARCHIVE_ACL_SUNOS_NFS4     /* Solaris NFSv4 ACL inheritance flags */
-               {ACE_FILE_INHERIT_ACE, ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT},
-               {ACE_DIRECTORY_INHERIT_ACE, ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT},
-               {ACE_NO_PROPAGATE_INHERIT_ACE, ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT},
-               {ACE_INHERIT_ONLY_ACE, ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY},
-               {ACE_SUCCESSFUL_ACCESS_ACE_FLAG, ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS},
-               {ACE_FAILED_ACCESS_ACE_FLAG, ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS},
+               {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
-               {ACE_INHERITED_ACE, ARCHIVE_ENTRY_ACL_ENTRY_INHERITED}
+               {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACE_INHERITED_ACE}
 #endif
 #elif ARCHIVE_ACL_DARWIN       /* MacOS NFSv4 ACL inheritance flags */
-               {ACL_ENTRY_INHERITED, ARCHIVE_ENTRY_ACL_ENTRY_INHERITED},
-               {ACL_ENTRY_FILE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT},
-               {ACL_ENTRY_DIRECTORY_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT},
-               {ACL_ENTRY_LIMIT_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT},
-               {ACL_ENTRY_ONLY_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY}
+               {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED},
+               {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
+               {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
+               {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_LIMIT_INHERIT},
+               {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_ONLY_INHERIT}
+#elif ARCHIVE_ACL_LIBRICHACL
+               {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, RICHACE_FILE_INHERIT_ACE},
+               {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, RICHACE_DIRECTORY_INHERIT_ACE},
+               {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, RICHACE_NO_PROPAGATE_INHERIT_ACE},
+               {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, RICHACE_INHERIT_ONLY_ACE},
+               {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, RICHACE_INHERITED_ACE}
 #else  /* FreeBSD NFSv4 ACL inheritance flags */
-               {ACL_ENTRY_INHERITED, ARCHIVE_ENTRY_ACL_ENTRY_INHERITED},
-               {ACL_ENTRY_FILE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT},
-               {ACL_ENTRY_DIRECTORY_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT},
-               {ACL_ENTRY_NO_PROPAGATE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT},
-               {ACL_ENTRY_SUCCESSFUL_ACCESS, ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS},
-               {ACL_ENTRY_FAILED_ACCESS, ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS},
-               {ACL_ENTRY_INHERIT_ONLY, ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY},
+               {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED},
+               {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
+               {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
+               {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT},
+               {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACL_ENTRY_SUCCESSFUL_ACCESS},
+               {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACL_ENTRY_FAILED_ACCESS},
+               {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY}
 #endif
        };
        int i, flagset = 0;
 
-       for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); ++i)
-#if ARCHIVE_ACL_SUNOS_NFS4
-               if (a_flags & flags[i].machine)
+       for (i = 0; i < (int)(sizeof(perms)/sizeof(perms[0])); ++i)
+#if ARCHIVE_ACL_SUNOS_NFS4 || ARCHIVE_ACL_LIBRICHACL
+               if (flags & perms[i].machine)
 #else
-               if (acl_get_flag_np(opaque_fs, flags[i].machine))
+               if (acl_get_flag_np(opaque_fs, perms[i].machine))
 #endif
-                       flagset |= flags[i].portable;
+                       flagset |= perms[i].portable;
        return flagset;
 }
 
@@ -452,6 +483,62 @@ acl_match(ace_t *ace, struct myacl_t *myacl)
        }
        return (1);
 }
+#elif ARCHIVE_ACL_LIBRICHACL
+static int
+acl_match(struct richace *richace, struct myacl_t *myacl)
+{
+       int perms;
+
+       perms = acl_permset_to_bitmap(richace->e_mask) |
+           acl_flagset_to_bitmap(richace->e_flags);
+
+       if (perms != myacl->permset)
+               return (0);
+
+       switch (richace->e_type) {
+       case RICHACE_ACCESS_ALLOWED_ACE_TYPE:
+               if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW)
+                       return (0);
+               break;
+       case RICHACE_ACCESS_DENIED_ACE_TYPE:
+               if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_DENY)
+                       return (0);
+               break;
+       default:
+               return (0);
+       }
+
+       if (richace->e_flags & RICHACE_SPECIAL_WHO) {
+               switch (richace->e_id) {
+               case RICHACE_OWNER_SPECIAL_ID:
+                       if (myacl->tag != ARCHIVE_ENTRY_ACL_USER_OBJ)
+                               return (0);
+                       break;
+               case RICHACE_GROUP_SPECIAL_ID:
+                       if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP_OBJ)
+                               return (0);
+                       break;
+               case RICHACE_EVERYONE_SPECIAL_ID:
+                       if (myacl->tag != ARCHIVE_ENTRY_ACL_EVERYONE)
+                               return (0);
+                       break;
+               default:
+                       /* Invalid e_id */
+                       return (0);
+               }
+       } else if (richace->e_flags & RICHACE_IDENTIFIER_GROUP) {
+               if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP)
+                       return (0);
+               if ((gid_t)myacl->qual != richace->e_id)
+                       return (0);
+       } else {
+               if (myacl->tag != ARCHIVE_ENTRY_ACL_USER)
+                       return (0);
+               if ((uid_t)myacl->qual != richace->e_id)
+                       return (0);
+       }
+       return (1);
+}
 #elif ARCHIVE_ACL_DARWIN
 static int
 acl_match(acl_entry_t aclent, struct myacl_t *myacl)
@@ -593,6 +680,8 @@ compare_acls(
 #if ARCHIVE_ACL_SUNOS_NFS4
     void *aclp,
     int aclcnt,
+#elif ARCHIVE_ACL_LIBRICHACL
+    struct richacl *richacl,
 #else
     acl_t acl,
 #endif
@@ -604,6 +693,10 @@ compare_acls(
 #if ARCHIVE_ACL_SUNOS_NFS4
        int e;
        ace_t *acl_entry;
+#elif ARCHIVE_ACL_LIBRICHACL
+       int e;
+       struct richace *acl_entry;
+       int aclcnt;
 #else
        int entry_id = ACL_FIRST_ENTRY;
        acl_entry_t acl_entry;
@@ -614,6 +707,18 @@ compare_acls(
 #endif
 #endif
 
+#if ARCHIVE_ACL_SUNOS_NFS4
+       if (aclp == NULL)
+               return;
+#elif ARCHIVE_ACL_LIBRICHACL
+       if (richacl == NULL)
+               return;
+       aclcnt = richacl->a_count;
+#else
+       if (acl == NULL)
+               return;
+#endif
+
        n = end - start;
        marker = malloc(sizeof(marker[0]) * (n + 1));
        for (i = 0; i < n; i++)
@@ -630,7 +735,7 @@ compare_acls(
         * Iterate over acls in system acl object, try to match each
         * one with an item in the myacls array.
         */
-#if ARCHIVE_ACL_SUNOS_NFS4
+#if ARCHIVE_ACL_SUNOS_NFS4 || ARCHIVE_ACL_LIBRICHACL
        for (e = 0; e < aclcnt; e++)
 #else
        while (acl_get_entry_ret == acl_get_entry(acl, entry_id, &acl_entry))
@@ -638,6 +743,8 @@ compare_acls(
        {
 #if ARCHIVE_ACL_SUNOS_NFS4
                acl_entry = &((ace_t *)aclp)[e];
+#elif ARCHIVE_ACL_LIBRICHACL
+               acl_entry = &(richacl->a_entries[e]);
 #else
                /* After the first time... */
                entry_id = ACL_NEXT_ENTRY;
@@ -756,6 +863,8 @@ DEFINE_TEST(test_acl_platform_nfs4)
 #if ARCHIVE_ACL_SUNOS_NFS4
        void *aclp;
        int aclcnt;
+#elif ARCHIVE_ACL_LIBRICHACL
+       struct richacl *richacl;
 #else  /* !ARCHIVE_ACL_SUNOS_NFS4 */
        acl_t acl;
 #endif
@@ -814,21 +923,31 @@ DEFINE_TEST(test_acl_platform_nfs4)
        assertEqualInt(st.st_mtime, 123456);
 #if ARCHIVE_ACL_SUNOS_NFS4
        aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, "testall");
-       failure("acl(): errno = %d (%s)", errno, strerror(errno));
+       failure("acl(\"%s\"): errno = %d (%s)", "testall", errno,
+           strerror(errno));
        assert(aclp != NULL);
+#elif ARCHIVE_ACL_LIBRICHACL
+       richacl = richacl_get_file("testall");
+       failure("richacl_get_file(\"%s\"): errno = %d (%s)", "testall", errno,
+           strerror(errno));
+       assert(richacl != NULL);
 #else
 #if ARCHIVE_ACL_DARWIN
        acl = acl_get_file("testall", ACL_TYPE_EXTENDED);
 #else
        acl = acl_get_file("testall", ACL_TYPE_NFS4);
 #endif
-       failure("acl_get_file(): errno = %d (%s)", errno, strerror(errno));
+       failure("acl_get_file(\"%s\"): errno = %d (%s)", "testall", errno,
+           strerror(errno));
        assert(acl != (acl_t)NULL);
 #endif
 #if ARCHIVE_ACL_SUNOS_NFS4
        compare_acls(aclp, aclcnt, acls_reg, "testall", 0, regcnt);
        free(aclp);
        aclp = NULL;
+#elif ARCHIVE_ACL_LIBRICHACL
+       compare_acls(richacl, acls_reg, "testall", 0, regcnt);
+       richacl_free(richacl);
 #else
        compare_acls(acl, acls_reg, "testall", 0, regcnt);
        acl_free(acl);
@@ -842,15 +961,25 @@ DEFINE_TEST(test_acl_platform_nfs4)
                assertEqualInt(st.st_mtime, 123456 + i);
 #if ARCHIVE_ACL_SUNOS_NFS4
                aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, buff);
-               failure("acl(): errno = %d (%s)", errno, strerror(errno));
+               failure("acl(\"%s\"): errno = %d (%s)", buff, errno,
+                   strerror(errno));
                assert(aclp != NULL);
+#elif ARCHIVE_ACL_LIBRICHACL
+               richacl = richacl_get_file(buff);
+               /* First and last two dir do not return a richacl */
+               if ((i == 0 || i >= dircnt - 2) && richacl == NULL &&
+                   errno == ENODATA)
+                       continue;
+               failure("richacl_get_file(\"%s\"): errno = %d (%s)", buff,
+                   errno, strerror(errno));
+               assert(richacl != NULL);
 #else
 #if ARCHIVE_ACL_DARWIN
                acl = acl_get_file(buff, ACL_TYPE_EXTENDED);
 #else
                acl = acl_get_file(buff, ACL_TYPE_NFS4);
 #endif
-               failure("acl_get_file(): errno = %d (%s)", errno,
+               failure("acl_get_file(\"%s\"): errno = %d (%s)", buff, errno,
                    strerror(errno));
                assert(acl != (acl_t)NULL);
 #endif
@@ -858,6 +987,9 @@ DEFINE_TEST(test_acl_platform_nfs4)
                compare_acls(aclp, aclcnt, acls_dir, buff, i, i + 1);
                free(aclp);
                aclp = NULL;
+#elif ARCHIVE_ACL_LIBRICHACL
+               compare_acls(richacl, acls_dir, buff, i, i + 1);
+               richacl_free(richacl);
 #else
                compare_acls(acl, acls_dir, buff, i, i + 1);
                acl_free(acl);
@@ -869,21 +1001,31 @@ DEFINE_TEST(test_acl_platform_nfs4)
        assertEqualInt(st.st_mtime, 123456);
 #if ARCHIVE_ACL_SUNOS_NFS4
        aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, "dirall");
-       failure("acl(): errno = %d (%s)", errno, strerror(errno));
+       failure("acl(\"%s\"): errno = %d (%s)", "dirall", errno,
+           strerror(errno));
        assert(aclp != NULL);
+#elif ARCHIVE_ACL_LIBRICHACL
+       richacl = richacl_get_file("dirall");
+       failure("richacl_get_file(\"%s\"): errno = %d (%s)", "dirall",
+           errno, strerror(errno));
+       assert(richacl != NULL);
 #else
 #if ARCHIVE_ACL_DARWIN
        acl = acl_get_file("dirall", ACL_TYPE_EXTENDED);
 #else
        acl = acl_get_file("dirall", ACL_TYPE_NFS4);
 #endif
-       failure("acl_get_file(): errno = %d (%s)", errno, strerror(errno));
+       failure("acl_get_file(\"%s\"): errno = %d (%s)", "dirall", errno,
+           strerror(errno));
        assert(acl != (acl_t)NULL);
 #endif
 #if ARCHIVE_ACL_SUNOS_NFS4
        compare_acls(aclp, aclcnt, acls_dir, "dirall", 0, dircnt);
        free(aclp);
        aclp = NULL;
+#elif ARCHIVE_ACL_LIBRICHACL
+       compare_acls(richacl, acls_dir, "dirall", 0, dircnt);
+       richacl_free(richacl);
 #else
        compare_acls(acl, acls_dir, "dirall", 0, dircnt);
        acl_free(acl);
index e6054babcf4605f9a348bac0a595d45097221bed..318eb06e0b6bedd5129d48e32b1315f054734c05 100644 (file)
@@ -74,9 +74,14 @@ IF(ENABLE_TAR AND ENABLE_TEST)
   #
   ADD_EXECUTABLE(bsdtar_test ${bsdtar_test_SOURCES})
   IF(ENABLE_ACL)
+    SET(TEST_ACL_LIBS "")
     IF(HAVE_LIBACL)
-      TARGET_LINK_LIBRARIES(bsdtar_test ${ACL_LIBRARY})
+      LIST(APPEND TEST_ACL_LIBS ${ACL_LIBRARY})
     ENDIF(HAVE_LIBACL)
+    IF(HAVE_LIBRICHACL)
+      LIST(APPEND TEST_ACL_LIBS ${RICHACL_LIBRARY})
+    ENDIF(HAVE_LIBRICHACL)
+    TARGET_LINK_LIBRARIES(bsdtar_test ${TEST_ACL_LIBS})
   ENDIF(ENABLE_ACL)
   SET_PROPERTY(TARGET bsdtar_test PROPERTY COMPILE_DEFINITIONS LIST_H)
 
index 699dcf8df38ad0d90017026f23e936f0984da872..0ef6d6fcf7f07954afd3b9a3207e59c049dae930 100644 (file)
@@ -67,6 +67,9 @@
 #ifdef HAVE_SYS_ACL_H
 #include <sys/acl.h>
 #endif
+#ifdef HAVE_SYS_RICHACL_H
+#include <sys/richacl.h>
+#endif
 #if HAVE_MEMBERSHIP_H
 #include <membership.h>
 #endif
@@ -2507,9 +2510,12 @@ setTestAcl(const char *path)
 {
 #if ARCHIVE_ACL_SUPPORT
        int r = 1;
-#if !ARCHIVE_ACL_SUNOS
+#if ARCHIVE_ACL_LIBACL || ARCHIVE_ACL_FREEBSD || ARCHIVE_ACL_DARWIN
        acl_t acl;
 #endif
+#if ARCHIVE_ACL_LIBRICHACL
+       struct richacl *richacl;
+#endif
 #if ARCHIVE_ACL_LIBACL || ARCHIVE_ACL_FREEBSD
        const char *acltext_posix1e = "user:1:rw-,"
            "group:15:r-x,"
@@ -2533,6 +2539,15 @@ setTestAcl(const char *path)
            "owner@:rwpxaARWcCos::allow,"
            "group@:rwpxaRcs::allow,"
            "everyone@:rxaRcs::allow";
+#elif ARCHIVE_ACL_LIBRICHACL
+       const char *acltext_nfs4 = "owner:rwpxaARWcCoS::mask,"
+           "group:rwpxaRcS::mask,"
+           "other:rxaRcS::mask,"
+           "user:1:rwpaRcS::allow,"
+           "group:15:rxaRcS::allow,"
+           "owner@:rwpxaARWcCoS::allow,"
+           "group@:rwpxaRcS::allow,"
+           "everyone@:rxaRcS::allow";
 #elif ARCHIVE_ACL_SUNOS_NFS4 /* Solaris NFS4 */
        ace_t aclp_nfs4[] = {
            { 1, ACE_READ_DATA | ACE_WRITE_DATA | ACE_APPEND_DATA |
@@ -2579,6 +2594,11 @@ setTestAcl(const char *path)
        failure("acl_from_text() error: %s", strerror(errno));
        if (assert(acl != NULL) == 0)
                return (0);
+#elif ARCHIVE_ACL_LIBRICHACL
+       richacl = richacl_from_text(acltext_nfs4, NULL, NULL);
+       failure("richacl_from_text() error: %s", strerror(errno));
+       if (assert(richacl != NULL) == 0)
+               return (0);
 #elif ARCHIVE_ACL_DARWIN
        acl = acl_init(1);
        failure("acl_init() error: %s", strerror(errno));
@@ -2620,6 +2640,9 @@ setTestAcl(const char *path)
 #if ARCHIVE_ACL_FREEBSD
        r = acl_set_file(path, ACL_TYPE_NFS4, acl);
        acl_free(acl);
+#elif ARCHIVE_ACL_LIBRICHACL
+       r = richacl_set_file(path, richacl);
+       richacl_free(richacl);
 #elif ARCHIVE_ACL_SUNOS_NFS4
        r = acl(path, ACE_SETACL,
            (int)(sizeof(aclp_nfs4)/sizeof(aclp_nfs4[0])), aclp_nfs4);