]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Add NFSv4 ACL support for Mac OS X
authorMartin Matuska <martin@matuska.org>
Sun, 29 Jan 2017 14:51:02 +0000 (15:51 +0100)
committerMartin Matuska <martin@matuska.org>
Sun, 29 Jan 2017 15:06:30 +0000 (16:06 +0100)
Mac OS X supports user and group NFSv4-style ACLs only (extended ACLs).
File-mode ACLs (owner@, group@ and everyone@) are not supported.

Behavior on Mac OS X:
- libarchive does not store GUID of Mac OS X extended ACLs. Only
  uid or gid (and the corresponding user or group name) are stored.
- When extracting an archive entry that has mac_metadata, NFSv4 ACLs
  are not written to disk (mac_metadata already contains ACLs)
- When writing ACLs to disk from an archive entry with NFSv4 ACLs
  owner@, group@ and everyone@ ACLs are ignored. User and group ids
  are converted to a GUID (this may lead to a fabricated GUID if
  the user or group ID is not present on the system)
- When reading ACL from disk and there is at least one user or group
  extended ACL entry, owner@, group@ and everyone@ entries mirroring
  the file mode are added to the end of the entry's ACL.

CMakeLists.txt
build/cmake/config.h.in
configure.ac
libarchive/archive_platform.h
libarchive/archive_read_disk_entry_from_file.c
libarchive/archive_write_disk_acl.c
libarchive/archive_write_disk_posix.c
libarchive/test/test.h
libarchive/test/test_acl_platform_nfs4.c

index bad694abaea7b8365780f3dc3aa9a6a2ff56f2fc..cda1506f282dbdcb92bb8c38f30f652c3d1ee762 100644 (file)
@@ -1610,6 +1610,9 @@ IF(ENABLE_ACL)
   # 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>
+#include <sys/acl.h>
+int main(void) { return ACL_TYPE_EXTENDED; }" HAVE_ACL_TYPE_EXTENDED)
 
   # Solaris and derivates ACLs
   CHECK_LIBRARY_EXISTS(sec "acl_get" "" HAVE_LIBSEC)
@@ -1641,6 +1644,7 @@ ELSE(ENABLE_ACL)
   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)
index cd87c94ed57fa5242e7a56a87b53312ac19e84d7..ec64d9937fab3caaf67f4c78bdbdf8fd06609db8 100644 (file)
@@ -329,6 +329,9 @@ typedef uint64_t uintmax_t;
 /* 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
 
index a2bce2cf920c44781859bdeabcca69c0ea0415ce..0afb59cef11fe0fc17d948644ba9ca85620bdc06 100644 (file)
@@ -737,6 +737,13 @@ if test "x$enable_acl" != "xno"; then
                [],
                [#include <sys/acl.h>])
 
+    # MacOS has ACL_TYPE_EXTENDED instead
+    AC_CHECK_DECL([ACL_TYPE_EXTENDED],
+               [AC_DEFINE(HAVE_ACL_TYPE_EXTENDED, 1, [True for MacOS ACL support])],
+               [],
+               [#include <sys/types.h>
+               #include <sys/acl.h>])
+
     # Solaris and derivates ACLs
     AC_CHECK_LIB([sec], [acl_get])
     AC_CHECK_TYPES([aclent_t], [], [], [[#include <sys/acl.h>]])
index eb9d4bbe89caaf9f7151264675c5cad8a5723803..c9a96020162efea3fd2960334b497e4244a382d2 100644 (file)
  * 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 && HAVE_ACL_USER
+#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
 
 /*
 #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.
index 26f8fad14840c3c655dd5797918e920cd2bacc82..47085cb7b9ada947fdd7a91d029fc17b6084d4f9 100644 (file)
@@ -38,6 +38,11 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 2010
 #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
@@ -118,6 +123,15 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 2010
 #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 *,
@@ -405,12 +419,19 @@ 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_SUN_ACL
+#if HAVE_POSIX_ACL || HAVE_NFS4_ACL
 static int translate_acl(struct archive_read_disk *a,
     struct archive_entry *entry,
 #if HAVE_SUN_ACL
@@ -454,19 +475,20 @@ setup_acls(struct archive_read_disk *a,
 
        acl = NULL;
 
-#if HAVE_ACL_TYPE_NFS4 || HAVE_SUN_ACL
+#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, ACL_TYPE_NFS4);
+               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, ACL_TYPE_NFS4);
+               acl = acl_get_link_np(accpath, ARCHIVE_PLATFORM_ACL_TYPE_NFS4);
 #else
        else if ((!a->follow_symlinks)
            && (archive_entry_filetype(entry) == AE_IFLNK))
@@ -476,9 +498,10 @@ setup_acls(struct archive_read_disk *a,
 #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, ACL_TYPE_NFS4);
+               acl = acl_get_file(accpath, ARCHIVE_PLATFORM_ACL_TYPE_NFS4);
 #endif
 
 
@@ -513,11 +536,24 @@ setup_acls(struct archive_read_disk *a,
                            "Couldn't translate NFSv4 ACLs: %s", accpath);
 #endif
                }
+#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_count(entry,
+                   ARCHIVE_ENTRY_ACL_TYPE_NFS4) > 0)
+                       add_trivial_nfs4_acl(entry);
+#endif
                return (r);
        }
-#endif /* HAVE_ACL_TYPE_NFS4 || HAVE_SUN_ACL */
+#endif /* HAVE_NFS4_ACL */
+
+#if HAVE_POSIX_ACL
+       /* This code path is skipped on MacOS and Solaris */
 
-#if !HAVE_SUN_ACL
        /* Retrieve access ACL from file. */
        if (*fd >= 0)
                acl = acl_get_fd(*fd);
@@ -575,7 +611,7 @@ setup_acls(struct archive_read_disk *a,
                        }
                }
        }
-#endif /* !HAVE_SUN_ACL */
+#endif /* HAVE_POSIX_ACL */
        return (ARCHIVE_OK);
 }
 
@@ -604,6 +640,24 @@ static struct {
        {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},
@@ -626,10 +680,10 @@ static struct {
        {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER},
        {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
 #endif
-#endif /* !HAVE_SUN_ACL */
+#endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
 };
 
-#if HAVE_ACL_TYPE_NFS4 || HAVE_SUN_ACL
+#if HAVE_NFS4_ACL
 /*
  * Translate system NFSv4 inheritance flags into libarchive internal structure
  */
@@ -637,7 +691,7 @@ static struct {
        int archive_inherit;
        int platform_inherit;
 } acl_inherit_map[] = {
-#if HAVE_SUN_ACL
+#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},
@@ -645,7 +699,13 @@ static struct {
        {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}
-#else  /* !HAVE_SUN_ACL */
+#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},
@@ -653,11 +713,140 @@ static struct {
        {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 */
+#endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
 };
-#endif /* HAVE_ACL_TYPE_NFS4 || HAVE_SUN_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)
+               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
+               return (1);
+       return (0);
+}
 
-#if HAVE_SUN_ACL
+/*
+ * 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
@@ -810,7 +999,9 @@ sun_acl_is_trivial(acl_t *acl, mode_t mode, int *trivialp)
        *trivialp = 1;
        return (0);
 }
+#endif /* HAVE_SUN_ACL */
 
+#if HAVE_SUN_ACL
 /*
  * Translate Solaris POSIX.1e and NFSv4 ACLs into libarchive internal ACL
  */
@@ -945,8 +1136,8 @@ translate_acl(struct archive_read_disk *a,
 }
 #else  /* !HAVE_SUN_ACL */
 /*
- * Translate POSIX.1e (Linux) and FreeBSD (both POSIX.1e and NFSv4)
- * ACLs into libarchive internal structure
+ * 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,
@@ -955,8 +1146,10 @@ translate_acl(struct archive_read_disk *a,
        acl_tag_t        acl_tag;
 #if HAVE_ACL_TYPE_NFS4
        acl_entry_type_t acl_type;
-       acl_flagset_t    acl_flagset;
        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;
@@ -964,7 +1157,6 @@ translate_acl(struct archive_read_disk *a,
        int              r, s, ae_id, ae_tag, ae_perm;
        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
@@ -1006,7 +1198,13 @@ translate_acl(struct archive_read_disk *a,
                    "Failed to get first ACL entry");
                return (ARCHIVE_WARN);
        }
-       while (s == 1) {
+
+#if HAVE_DARWIN_ACL
+       while (s == 0)
+#else  /* FreeBSD, Linux */
+       while (s == 1)
+#endif
+       {
                ae_id = -1;
                ae_name = NULL;
                ae_perm = 0;
@@ -1017,6 +1215,7 @@ translate_acl(struct archive_read_disk *a,
                        return (ARCHIVE_WARN);
                }
                switch (acl_tag) {
+#if !HAVE_DARWIN_ACL   /* FreeBSD, Linux */
                case ACL_USER:
                        ae_id = (int)*(uid_t *)acl_get_qualifier(acl_entry);
                        ae_name = archive_read_disk_uname(&a->archive, ae_id);
@@ -1044,16 +1243,39 @@ translate_acl(struct archive_read_disk *a,
                        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;
-#if HAVE_ACL_TYPE_NFS4
+#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
                         */
@@ -1080,6 +1302,7 @@ translate_acl(struct archive_read_disk *a,
                                    "Invalid NFSv4 ACL entry type");
                                return (ARCHIVE_WARN);
                        }
+#endif /* HAVE_ACL_TYPE_NFS4 */
 
                        /*
                         * Libarchive stores "flag" (NFSv4 inheritance bits)
@@ -1104,7 +1327,7 @@ translate_acl(struct archive_read_disk *a,
                                        ae_perm |= acl_inherit_map[i].archive_inherit;
                        }
                }
-#endif
+#endif /* HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL */
 
                if (acl_get_permset(acl_entry, &acl_permset) != 0) {
                        archive_set_error(&a->archive, errno,
@@ -1130,16 +1353,18 @@ translate_acl(struct archive_read_disk *a,
                                            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_SUN_ACL */
+#else  /* !HAVE_POSIX_ACL && !HAVE_NFS4_ACL */
 static int
 setup_acls(struct archive_read_disk *a,
     struct archive_entry *entry, int *fd)
@@ -1149,7 +1374,7 @@ setup_acls(struct archive_read_disk *a,
        (void)fd;     /* UNUSED */
        return (ARCHIVE_OK);
 }
-#endif /* !HAVE_POSIX_ACL && !HAVE_SUN_ACL */
+#endif /* !HAVE_POSIX_ACL && !HAVE_NFS4_ACL */
 
 #if (HAVE_FGETXATTR && HAVE_FLISTXATTR && HAVE_LISTXATTR && \
     HAVE_LLISTXATTR && HAVE_GETXATTR && HAVE_LGETXATTR) || \
index a20852665ece8b0203956965e7779d0776d941c2..311aebf0331f27fb6372b6f4c3ea2bf3266df655 100644 (file)
@@ -34,6 +34,9 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_disk.c 201159 2009-12-29 0
 #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
@@ -43,7 +46,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_disk.c 201159 2009-12-29 0
 #include "archive_acl_private.h"
 #include "archive_write_disk_private.h"
 
-#if !HAVE_POSIX_ACL && !HAVE_SUN_ACL
+#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,
@@ -56,7 +59,15 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
        return (ARCHIVE_OK);
 }
 
-#else /* HAVE_POSIX_ACL || HAVE_SUN_ACL */
+#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 *,
@@ -67,19 +78,15 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
         struct archive_acl *abstract_acl)
 {
        int             ret = ARCHIVE_OK;
-#if HAVE_SUN_ACL
-       const int       acltype_nfs4 = ACE_T;
-#elif HAVE_ACL_TYPE_NFS4
-       const int       acltype_nfs4 = ACL_TYPE_NFS4;
-#endif
 
+#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
+#else  /* HAVE_POSIX_ACL */
                if ((archive_acl_types(abstract_acl)
                    & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
                        ret = set_acl(a, fd, name, abstract_acl,
@@ -93,15 +100,19 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
                        ret = set_acl(a, fd, name, abstract_acl,
                            ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT,
                            "default");
-#endif
+#endif /* !HAVE_SUN_ACL */
+               /* Simultaeous POSIX.1e and NFSv4 is not supported */
+               return (ret);
        }
-#if HAVE_ACL_TYPE_NFS4 || HAVE_SUN_ACL
-       else if ((archive_acl_types(abstract_acl) &
+#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, acltype_nfs4,
+               ret = set_acl(a, fd, name, abstract_acl,
+                   ARCHIVE_PLATFORM_ACL_TYPE_NFS4,
                    ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4");
        }
-#endif /* HAVE_ACL_TYPE_NFS4 || HAVE_SUN_ACL */
+#endif /* HAVE_NFS4_ACL */
        return (ret);
 }
 
@@ -130,6 +141,24 @@ static struct {
        {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},
@@ -152,10 +181,10 @@ static struct {
        {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER},
        {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
 #endif
-#endif /* !HAVE_SUN_ACL */
+#endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
 };
 
-#if HAVE_ACL_TYPE_NFS4 || HAVE_SUN_ACL
+#if HAVE_NFS4_ACL
 /*
  * Translate system NFSv4 inheritance flags into libarchive internal structure
  */
@@ -163,7 +192,7 @@ static struct {
        int archive_inherit;
        int platform_inherit;
 } acl_inherit_map[] = {
-#if HAVE_SUN_ACL
+#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},
@@ -171,7 +200,13 @@ static struct {
        {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}
-#else  /* !HAVE_SUN_ACL */
+#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},
@@ -179,9 +214,9 @@ static struct {
        {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 */
+#endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
 };
-#endif /* HAVE_ACL_TYPE_NFS4 || HAVE_SUN_ACL */
+#endif /* HAVE_NFS4_ACL */
 
 static int
 set_acl(struct archive *a, int fd, const char *name,
@@ -197,13 +232,18 @@ set_acl(struct archive *a, int fd, const char *name,
        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
-       acl_flagset_t    acl_flagset;
-       int              r;
+       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;
@@ -270,7 +310,18 @@ set_acl(struct archive *a, int fd, const char *name,
                        aclent->a_type = 0;
                        aclent->a_perm = 0;
                }
-#else  /* !HAVE_SUN_ACL */
+#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");
@@ -278,6 +329,19 @@ set_acl(struct archive *a, int fd, const char *name,
                        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:
@@ -323,15 +387,32 @@ set_acl(struct archive *a, int fd, const char *name,
                        break;
 #else  /* !HAVE_SUN_ACL */
                case ARCHIVE_ENTRY_ACL_USER:
-                       acl_set_tag_type(acl_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:
-                       acl_set_tag_type(acl_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;
@@ -344,11 +425,12 @@ set_acl(struct archive *a, int fd, const char *name,
                case ARCHIVE_ENTRY_ACL_OTHER:
                        acl_set_tag_type(acl_entry, ACL_OTHER);
                        break;
-#if HAVE_ACL_TYPE_NFS4
+#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,
@@ -471,14 +553,16 @@ set_acl(struct archive *a, int fd, const char *name,
                        }
                }
 
-#if HAVE_ACL_TYPE_NFS4 || HAVE_SUN_ACL
+#if HAVE_NFS4_ACL
 #if HAVE_SUN_ACL
                if (acl_type == ACE_T)
-#else
+#elif HAVE_DARWIN_ACL
+               if (acl_type == ACL_TYPE_EXTENDED)
+#else  /* FreeBSD */
                if (acl_type == ACL_TYPE_NFS4)
 #endif
                {
-#ifdef HAVE_POSIX_ACL
+#if HAVE_POSIX_ACL || HAVE_DARWIN_ACL
                        /*
                         * acl_get_flagset_np() fails with non-NFSv4 ACLs
                         */
@@ -494,7 +578,7 @@ set_acl(struct archive *a, int fd, const char *name,
                                ret = ARCHIVE_FAILED;
                                goto exit_free;
                        }
-#endif
+#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
@@ -508,11 +592,11 @@ set_acl(struct archive *a, int fd, const char *name,
                                                ret = ARCHIVE_FAILED;
                                                goto exit_free;
                                        }
-#endif /* HAVE_SUN_ACLi */
+#endif /* HAVE_SUN_ACL */
                                }
                        }
                }
-#endif
+#endif /* HAVE_NFS4_ACL */
 #if HAVE_SUN_ACL
        e++;
 #endif
@@ -567,4 +651,4 @@ exit_free:
        acl_free(acl);
        return (ret);
 }
-#endif /* HAVE_POSIX_ACL || HAVE_SUN_ACL */
+#endif /* HAVE_POSIX_ACL || HAVE_NFS4_ACL */
index fabe6bcae0550d7d10af88550d5c700f8aa9fd5a..29d687bf2d626da90671bada3c8164992e563bc9 100644 (file)
@@ -1702,10 +1702,25 @@ _archive_write_disk_finish_entry(struct archive *_a)
         * ACLs that prevent attribute changes (including time).
         */
        if (a->todo & TODO_ACLS) {
-               int r2 = archive_write_disk_set_acls(&a->archive, a->fd,
-                                 archive_entry_pathname(a->entry),
-                                 archive_entry_acl(a->entry));
+               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 (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));
                if (r2 < ret) ret = r2;
+#ifdef HAVE_DARWIN_ACL
+               }
+#endif
        }
 
 finish_metadata:
@@ -2264,8 +2279,12 @@ _archive_write_disk_close(struct archive *_a)
                if (p->fixup & TODO_MODE_BASE)
                        chmod(p->name, p->mode);
                if (p->fixup & TODO_ACLS)
-                       archive_write_disk_set_acls(&a->archive,
-                                                   -1, p->name, &p->acl);
+#ifdef HAVE_DARWIN_ACL
+                       if (p->mac_metadata == NULL ||
+                           p->mac_metadata_size == 0)
+#endif
+                               archive_write_disk_set_acls(&a->archive,
+                                   -1, p->name, &p->acl);
                if (p->fixup & TODO_FFLAGS)
                        set_fflags_platform(a, -1, p->name,
                            p->mode, p->fflags_set, 0);
index dd1ee8fe5f9eb963c8040e929fb6f4cd8e8bdadd..58df1cbfb8935e808f6fcc659cd9e2e308ad66e9 100644 (file)
  * 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 && HAVE_ACL_USER
+#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
 
 /*
 #define        HAVE_SUN_ACL    1
 #endif
 
+/* Define if platform supports NFSv4 ACLs */
+#if (HAVE_POSIX_ACL && HAVE_ACL_TYPE_NFS4) || HAVE_SUN_ACL || HAVE_DARWIN_ACL
+#define        HAVE_NFS4_ACL   1
+#endif
+
 /*
  * Redefine DEFINE_TEST for use in defining the test functions.
  */
index 4d865f983d49c01cc43103c8f37508c234e44bc8..be282610009d686d2c94e13cdb031f8147b5e214 100644 (file)
 #include "test.h"
 __FBSDID("$FreeBSD$");
 
-#if HAVE_SUN_ACL || HAVE_POSIX_ACL
+#if HAVE_POSIX_ACL || HAVE_NFS4_ACL
 #define _ACL_PRIVATE
 #include <sys/acl.h>
+#if HAVE_DARWIN_ACL
+#include <membership.h>
+#endif
 #endif
 
-#if HAVE_SUN_ACL || (HAVE_POSIX_ACL && HAVE_ACL_TYPE_NFS4)
-
+#if HAVE_NFS4_ACL
 struct myacl_t {
        int type;
        int permset;
@@ -42,11 +44,12 @@ struct myacl_t {
 };
 
 static struct myacl_t acls_reg[] = {
+#if !HAVE_DARWIN_ACL
        /* For this test, we need the file owner to be able to read and write the ACL. */
        { ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
          ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_READ_ACL | ARCHIVE_ENTRY_ACL_WRITE_ACL | ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES,
          ARCHIVE_ENTRY_ACL_USER_OBJ, -1, ""},
-
+#endif
        /* An entry for each type. */
        { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
          ARCHIVE_ENTRY_ACL_USER, 108, "user108" },
@@ -88,16 +91,53 @@ static struct myacl_t acls_reg[] = {
 //       ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
        { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
          ARCHIVE_ENTRY_ACL_GROUP, 136, "group136" },
+#if !HAVE_DARWIN_ACL
        { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
          ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
        { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
          ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }
+#else  /* MacOS - mode 0654 */
+       { ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_EXECUTE,
+         ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
+       { ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
+           ARCHIVE_ENTRY_ACL_READ_DATA |
+           ARCHIVE_ENTRY_ACL_WRITE_DATA |
+           ARCHIVE_ENTRY_ACL_APPEND_DATA |
+           ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
+           ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES |
+           ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
+           ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS |
+           ARCHIVE_ENTRY_ACL_READ_ACL |
+           ARCHIVE_ENTRY_ACL_WRITE_ACL |
+           ARCHIVE_ENTRY_ACL_WRITE_OWNER |
+           ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
+         ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
+       { ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
+           ARCHIVE_ENTRY_ACL_READ_DATA |
+           ARCHIVE_ENTRY_ACL_EXECUTE |
+           ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
+           ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
+           ARCHIVE_ENTRY_ACL_READ_ACL |
+           ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
+         ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
+       { ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
+           ARCHIVE_ENTRY_ACL_READ_DATA |
+           ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
+           ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
+           ARCHIVE_ENTRY_ACL_READ_ACL |
+           ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
+         ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }
+#endif
 };
 
+static const int acls_reg_cnt = (int)(sizeof(acls_reg)/sizeof(acls_reg[0]));
+
 static struct myacl_t acls_dir[] = {
        /* For this test, we need to be able to read and write the ACL. */
+#if !HAVE_DARWIN_ACL
        { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_READ_ACL,
          ARCHIVE_ENTRY_ACL_USER_OBJ, -1, ""},
+#endif
 
        /* An entry for each type. */
        { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
@@ -167,12 +207,47 @@ static struct myacl_t acls_dir[] = {
          ARCHIVE_ENTRY_ACL_USER, 501, "user501" },
        { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
          ARCHIVE_ENTRY_ACL_GROUP, 502, "group502" },
+#if !HAVE_DARWIN_ACL
        { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
          ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
        { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
          ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }
+#else  /* MacOS - mode 0654 */
+       { ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_EXECUTE,
+         ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
+       { ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
+           ARCHIVE_ENTRY_ACL_READ_DATA |
+           ARCHIVE_ENTRY_ACL_WRITE_DATA |
+           ARCHIVE_ENTRY_ACL_APPEND_DATA |
+           ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
+           ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES |
+           ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
+           ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS |
+           ARCHIVE_ENTRY_ACL_READ_ACL |
+           ARCHIVE_ENTRY_ACL_WRITE_ACL |
+           ARCHIVE_ENTRY_ACL_WRITE_OWNER |
+           ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
+         ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
+       { ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
+           ARCHIVE_ENTRY_ACL_READ_DATA |
+           ARCHIVE_ENTRY_ACL_EXECUTE |
+           ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
+           ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
+           ARCHIVE_ENTRY_ACL_READ_ACL |
+           ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
+         ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
+       { ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
+           ARCHIVE_ENTRY_ACL_READ_DATA |
+           ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
+           ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
+           ARCHIVE_ENTRY_ACL_READ_ACL |
+           ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
+         ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }
+#endif
 };
 
+static const int acls_dir_cnt = (int)(sizeof(acls_dir)/sizeof(acls_dir[0]));
+
 static void
 set_acls(struct archive_entry *ae, struct myacl_t *acls, int start, int end)
 {
@@ -219,6 +294,24 @@ acl_permset_to_bitmap(acl_permset_t opaque_ps)
                {ACE_WRITE_ACL, ARCHIVE_ENTRY_ACL_WRITE_ACL},
                {ACE_WRITE_OWNER, ARCHIVE_ENTRY_ACL_WRITE_OWNER},
                {ACE_SYNCHRONIZE, ARCHIVE_ENTRY_ACL_SYNCHRONIZE}
+#elif HAVE_DARWIN_ACL  /* MacOS NFSv4 ACL permissions */
+               {ACL_READ_DATA, ARCHIVE_ENTRY_ACL_READ_DATA},
+               {ACL_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY},
+               {ACL_WRITE_DATA, ARCHIVE_ENTRY_ACL_WRITE_DATA},
+               {ACL_ADD_FILE, ARCHIVE_ENTRY_ACL_ADD_FILE},
+               {ACL_EXECUTE, ARCHIVE_ENTRY_ACL_EXECUTE},
+               {ACL_DELETE, ARCHIVE_ENTRY_ACL_DELETE},
+               {ACL_APPEND_DATA, ARCHIVE_ENTRY_ACL_APPEND_DATA},
+               {ACL_ADD_SUBDIRECTORY, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY},
+               {ACL_DELETE_CHILD, ARCHIVE_ENTRY_ACL_DELETE_CHILD},
+               {ACL_READ_ATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES},
+               {ACL_WRITE_ATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES},
+               {ACL_READ_EXTATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS},
+               {ACL_WRITE_EXTATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS},
+               {ACL_READ_SECURITY, ARCHIVE_ENTRY_ACL_READ_ACL},
+               {ACL_WRITE_SECURITY, ARCHIVE_ENTRY_ACL_WRITE_ACL},
+               {ACL_CHANGE_OWNER, ARCHIVE_ENTRY_ACL_WRITE_OWNER},
+               {ACL_SYNCHRONIZE, ARCHIVE_ENTRY_ACL_SYNCHRONIZE},
 #else  /* FreeBSD NFSv4 ACL permissions */
                {ACL_EXECUTE, ARCHIVE_ENTRY_ACL_EXECUTE},
                {ACL_WRITE, ARCHIVE_ENTRY_ACL_WRITE},
@@ -269,8 +362,13 @@ acl_flagset_to_bitmap(acl_flagset_t opaque_fs)
                {ACE_SUCCESSFUL_ACCESS_ACE_FLAG, ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS},
                {ACE_FAILED_ACCESS_ACE_FLAG, ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS},
                {ACE_INHERITED_ACE, ARCHIVE_ENTRY_ACL_ENTRY_INHERITED}
-#else  /* FreeBSD NFSv4 ACL inheritance flags */
+#elif HAVE_DARWIN_ACL  /* MacOS NFSv4 ACL inheritance flags */
                {ACL_ENTRY_INHERITED, ARCHIVE_ENTRY_ACL_ENTRY_INHERITED},
+               {ACL_ENTRY_FILE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT},
+               {ACL_ENTRY_DIRECTORY_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT},
+               {ACL_ENTRY_LIMIT_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT},
+               {ACL_ENTRY_ONLY_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY}
+#else  /* FreeBSD NFSv4 ACL inheritance flags */
                {ACL_ENTRY_FILE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT},
                {ACL_ENTRY_DIRECTORY_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT},
                {ACL_ENTRY_NO_PROPAGATE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT},
@@ -299,20 +397,28 @@ acl_match(acl_entry_t aclent, struct myacl_t *myacl)
 #endif
 {
 #if !HAVE_SUN_ACL
+#if HAVE_DARWIN_ACL
+       void *q;
+       uid_t ugid;
+       int r, idtype;
+#else
        gid_t g, *gp;
        uid_t u, *up;
+       acl_entry_type_t entry_type;
+#endif /* !HAVE_DARWIN_ACL */
        acl_tag_t tag_type;
        acl_permset_t opaque_ps;
        acl_flagset_t opaque_fs;
-       acl_entry_type_t entry_type;
-#endif
+#endif /* !HAVE_SUN_ACL */
        int perms;
 
 #if HAVE_SUN_ACL
        perms = acl_permset_to_bitmap(ace->a_access_mask) | acl_flagset_to_bitmap(ace->a_flags);
 #else
        acl_get_tag_type(aclent, &tag_type);
+#if !HAVE_DARWIN_ACL
        acl_get_entry_type_np(aclent, &entry_type);
+#endif
 
        /* translate the silly opaque permset to a bitmap */
        acl_get_permset(aclent, &opaque_ps);
@@ -364,7 +470,43 @@ acl_match(acl_entry_t aclent, struct myacl_t *myacl)
                if ((uid_t)myacl->qual != ace->a_who)
                        return (0);
        }
-#else  /* !HAVE_SUN_ACL */
+#elif HAVE_DARWIN_ACL
+       r = 0;
+       switch (tag_type) {
+       case ACL_EXTENDED_ALLOW:
+               if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW)
+                       return (0);
+               break;
+       case ACL_EXTENDED_DENY:
+               if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_DENY)
+                       return (0);
+               break;
+       default:
+               return (0);
+       }
+       q = acl_get_qualifier(aclent);
+       if (q == NULL)
+               return (0);
+       r = mbr_uuid_to_id((const unsigned char *)q, &ugid, &idtype);
+       if (r != 0)
+               return (0);
+       switch (idtype) {
+               case ID_TYPE_UID:
+                       if (myacl->tag != ARCHIVE_ENTRY_ACL_USER)
+                               return (0);
+                       if ((uid_t)myacl->qual != ugid)
+                               return (0);
+                       break;
+               case ID_TYPE_GID:
+                       if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP)
+                               return (0);
+                       if ((gid_t)myacl->qual != ugid)
+                               return (0);
+                       break;
+               default:
+                       return (0);
+       }
+#else  /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
        switch (entry_type) {
        case ACL_ENTRY_TYPE_ALLOW:
                if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW)
@@ -416,7 +558,7 @@ acl_match(acl_entry_t aclent, struct myacl_t *myacl)
                if (myacl->tag != ARCHIVE_ENTRY_ACL_EVERYONE) return (0);
                break;
        }
-#endif /* !HAVE_SUN_ACL */
+#endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */
        return (1);
 }
 
@@ -456,6 +598,8 @@ compare_acls(
         */
 #if HAVE_SUN_ACL
        for (e = 0; e < acl->acl_cnt; e++)
+#elif HAVE_DARWIN_ACL
+       while (0 == acl_get_entry(acl, entry_id, &acl_entry))
 #else
        while (1 == acl_get_entry(acl, entry_id, &acl_entry))
 #endif
@@ -554,7 +698,7 @@ compare_entry_acls(struct archive_entry *ae, struct myacl_t *myacls, const char
        }
        free(marker);
 }
-#endif /* HAVE_SUN_ACL || (HAVE_POSIX_ACL && HAVE_ACL_TYPE_NFS4) */
+#endif /* HAVE_NFS4_ACL */
 
 /*
  * Verify ACL restore-to-disk.  This test is Platform-specific.
@@ -562,7 +706,7 @@ compare_entry_acls(struct archive_entry *ae, struct myacl_t *myacls, const char
 
 DEFINE_TEST(test_acl_platform_nfs4)
 {
-#if !HAVE_SUN_ACL && (!HAVE_POSIX_ACL || !HAVE_ACL_TYPE_NFS4)
+#if !HAVE_NFS4_ACL
        skipping("NFS4 ACLs are not supported on this platform");
 #else
        char buff[64];
@@ -571,21 +715,48 @@ DEFINE_TEST(test_acl_platform_nfs4)
        struct archive_entry *ae;
        int i, n;
        char *func;
+#if HAVE_DARWIN_ACL /* On MacOS we skip trivial ACLs in some tests */
+       const int regcnt = acls_reg_cnt - 4;
+       const int dircnt = acls_dir_cnt - 4;
+#else
+       const int regcnt = acls_reg_cnt;
+       const int dircnt = acls_dir_cnt;
+#endif
 #if HAVE_SUN_ACL
        acl_t *acl;
-#else
+#else  /* !HAVE_SUN_ACL */
+#if HAVE_DARWIN_ACL
+       acl_entry_t aclent;
+       acl_permset_t permset;
+       const uid_t uid = 1000;
+       uuid_t uuid;
+#endif /* HAVE_DARWIN_ACL */
        acl_t acl;
-#endif
+#endif /* !HAVE_SUN_ACL */
 
        /*
         * First, do a quick manual set/read of ACL data to
         * verify that the local filesystem does support ACLs.
         * If it doesn't, we'll simply skip the remaining tests.
         */
-#if !HAVE_SUN_ACL
+#if HAVE_POSIX_ACL && HAVE_ACL_TYPE_NFS4
        acl = acl_from_text("owner@:rwxp::allow,group@:rwp:f:allow");
        failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno));
        assert((void *)acl != NULL);
+#elif HAVE_DARWIN_ACL
+       acl = acl_init(1);
+       assert((void *)acl != NULL);
+       assertEqualInt(0, acl_create_entry(&acl, &aclent));
+       assertEqualInt(0, acl_set_tag_type(aclent, ACL_EXTENDED_ALLOW));
+       assertEqualInt(0, acl_get_permset(aclent, &permset));
+       assertEqualInt(0, acl_add_perm(permset, ACL_READ_DATA));
+       assertEqualInt(0, acl_add_perm(permset, ACL_WRITE_DATA));
+       assertEqualInt(0, acl_add_perm(permset, ACL_APPEND_DATA));
+       assertEqualInt(0, acl_add_perm(permset, ACL_EXECUTE));
+       assertEqualInt(0, acl_set_permset(aclent, permset));
+       assertEqualInt(0, mbr_identifier_to_uuid(ID_TYPE_UID, &uid,
+           sizeof(uid_t), uuid));
+       assertEqualInt(0, acl_set_qualifier(aclent, uuid));
 #endif
 
        /* Create a test dir and try to set an ACL on it. */
@@ -601,7 +772,11 @@ DEFINE_TEST(test_acl_platform_nfs4)
        n = acl_get("pretest", 0, &acl);
 #else
        func = "acl_set_file()";
+#if HAVE_DARWIN_ACL
+       n = acl_set_file("pretest", ACL_TYPE_EXTENDED, acl);
+#else
        n = acl_set_file("pretest", ACL_TYPE_NFS4, acl);
+#endif
        acl_free(acl);
 #endif
        if (n != 0) {
@@ -640,7 +815,7 @@ DEFINE_TEST(test_acl_platform_nfs4)
        archive_entry_set_perm(ae, 0654);
        archive_entry_set_mtime(ae, 123456, 7890);
        archive_entry_set_size(ae, 0);
-       set_acls(ae, acls_reg, 0, (int)(sizeof(acls_reg)/sizeof(acls_reg[0])));
+       set_acls(ae, acls_reg, 0, acls_reg_cnt);
 
        /* Write the entry to disk, including ACLs. */
        assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
@@ -650,10 +825,10 @@ DEFINE_TEST(test_acl_platform_nfs4)
        archive_entry_set_filetype(ae, AE_IFDIR);
        archive_entry_set_perm(ae, 0654);
        archive_entry_set_mtime(ae, 123456, 7890);
-       set_acls(ae, acls_dir, 0, (int)(sizeof(acls_dir)/sizeof(acls_dir[0])));
+       set_acls(ae, acls_dir, 0, acls_dir_cnt);
        assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
 
-       for (i = 0; i < (int)(sizeof(acls_dir)/sizeof(acls_dir[0])); ++i) {
+       for (i = 0; i < acls_dir_cnt; ++i) {
          sprintf(buff, "dir%d", i);
          archive_entry_set_pathname(ae, buff);
          archive_entry_set_filetype(ae, AE_IFDIR);
@@ -676,16 +851,20 @@ DEFINE_TEST(test_acl_platform_nfs4)
        n = acl_get("testall", 0, &acl);
        failure("acl_get(): errno = %d (%s)", errno, strerror(errno));
        assertEqualInt(0, n);
+#else
+#if HAVE_DARWIN_ACL
+       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));
        assert(acl != (acl_t)NULL);
 #endif
-       compare_acls(acl, acls_reg, "testall", 0, (int)(sizeof(acls_reg)/sizeof(acls_reg[0])));
+       compare_acls(acl, acls_reg, "testall", 0, regcnt);
        acl_free(acl);
 
        /* Verify single-permission dirs on disk. */
-       for (i = 0; i < (int)(sizeof(acls_dir)/sizeof(acls_dir[0])); ++i) {
+       for (i = 0; i < dircnt; ++i) {
                sprintf(buff, "dir%d", i);
                assertEqualInt(0, stat(buff, &st));
                assertEqualInt(st.st_mtime, 123456 + i);
@@ -693,8 +872,12 @@ DEFINE_TEST(test_acl_platform_nfs4)
                n = acl_get(buff, 0, &acl);
                failure("acl_get(): errno = %d (%s)", errno, strerror(errno));
                assertEqualInt(0, n);
+#else
+#if HAVE_DARWIN_ACL
+               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,
                    strerror(errno));
                assert(acl != (acl_t)NULL);
@@ -710,13 +893,16 @@ DEFINE_TEST(test_acl_platform_nfs4)
        n = acl_get("dirall", 0, &acl);
        failure("acl_get(): errno = %d (%s)", errno, strerror(errno));
        assertEqualInt(0, n);
+#else
+#if HAVE_DARWIN_ACL
+       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));
        assert(acl != (acl_t)NULL);
 #endif
-       compare_acls(acl, acls_dir, "dirall", 0,
-           (int)(sizeof(acls_dir)/sizeof(acls_dir[0])));
+       compare_acls(acl, acls_dir, "dirall", 0, dircnt);
        acl_free(acl);
 
        /* Read and compare ACL via archive_read_disk */
@@ -727,8 +913,7 @@ DEFINE_TEST(test_acl_platform_nfs4)
        archive_entry_set_pathname(ae, "testall");
        assertEqualInt(ARCHIVE_OK,
                       archive_read_disk_entry_from_file(a, ae, -1, NULL));
-       compare_entry_acls(ae, acls_reg, "testall", 0,
-           (int)(sizeof(acls_reg)/sizeof(acls_reg[0])));
+       compare_entry_acls(ae, acls_reg, "testall", 0, acls_reg_cnt);
        archive_entry_free(ae);
        assertEqualInt(ARCHIVE_OK, archive_read_free(a));
 
@@ -740,9 +925,8 @@ DEFINE_TEST(test_acl_platform_nfs4)
        archive_entry_set_pathname(ae, "dirall");
        assertEqualInt(ARCHIVE_OK,
        archive_read_disk_entry_from_file(a, ae, -1, NULL));
-       compare_entry_acls(ae, acls_dir, "dirall", 0,
-           (int)(sizeof(acls_dir)/sizeof(acls_dir[0])));
+       compare_entry_acls(ae, acls_dir, "dirall", 0, acls_dir_cnt);
        archive_entry_free(ae);
        assertEqualInt(ARCHIVE_OK, archive_read_free(a));
-#endif /* HAVE_SUN_ACL || (HAVE_POSIX_ACL && HAVE_ACL_TYPE_NFS4) */
+#endif /* HAVE_NFS4_ACL */
 }