]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
New tar test: test_option_acls
authorMartin Matuska <martin@matuska.org>
Thu, 2 Mar 2017 13:19:38 +0000 (14:19 +0100)
committerMartin Matuska <martin@matuska.org>
Thu, 2 Mar 2017 15:10:26 +0000 (16:10 +0100)
Add sunacl_get() and setTestAcl() to common test code
Test for membership.h on Mac OS X and make it a requirement for ACLs

13 files changed:
CMakeLists.txt
Makefile.am
build/cmake/config.h.in
cat/test/CMakeLists.txt
configure.ac
cpio/test/CMakeLists.txt
libarchive/archive_platform.h
libarchive/test/test_acl_platform_nfs4.c
libarchive/test/test_acl_platform_posix1e.c
tar/test/CMakeLists.txt
tar/test/test_option_acls.c [new file with mode: 0644]
test_utils/test_common.h
test_utils/test_main.c

index 5bcff485be3591f26c0a9dc1d00bedc5151d52de..bddf30c71828bd4078d341dc55418a0234cb4500 100644 (file)
@@ -579,6 +579,7 @@ int main(void) { return FS_IOC_GETFLAGS; }" HAVE_WORKING_FS_IOC_GETFLAGS)
 
 LA_CHECK_INCLUDE_FILE("linux/magic.h" HAVE_LINUX_MAGIC_H)
 LA_CHECK_INCLUDE_FILE("locale.h" HAVE_LOCALE_H)
+LA_CHECK_INCLUDE_FILE("membership.h" HAVE_MEMBERSHIP_H)
 LA_CHECK_INCLUDE_FILE("memory.h" HAVE_MEMORY_H)
 LA_CHECK_INCLUDE_FILE("paths.h" HAVE_PATHS_H)
 LA_CHECK_INCLUDE_FILE("poll.h" HAVE_POLL_H)
index 600e1ff403cf1be15857f94c475346147caa8dce..b5a41f980fbd5f4230618fbf382050130becd746 100644 (file)
@@ -951,6 +951,7 @@ bsdtar_test_SOURCES= \
        tar/test/test_option_T_upper.c \
        tar/test/test_option_U_upper.c \
        tar/test/test_option_X_upper.c \
+       tar/test/test_option_acls.c \
        tar/test/test_option_a.c \
        tar/test/test_option_b.c \
        tar/test/test_option_b64encode.c \
index fd4fbdcd8ff1e3534333d61e57157b1dbae3ec90..8c18edf8a079b0b28f634a7c06a5b97ce1b6c295 100644 (file)
@@ -773,6 +773,9 @@ typedef uint64_t uintmax_t;
 /* Define to 1 if you have the `mbrtowc' function. */
 #cmakedefine HAVE_MBRTOWC 1
 
+/* Define to 1 if you have the <membership.h> header file. */
+#cmakedefine HAVE_MEMBERSHIP_H 1
+
 /* Define to 1 if you have the `memmove' function. */
 #cmakedefine HAVE_MEMMOVE 1
 
index 7f1ce5e77d1385b1089ae23f8b57b79cf7dbac7a..0623cc367227bb9a4ac12f19107c6c2c73133b26 100644 (file)
@@ -29,6 +29,11 @@ IF(ENABLE_CAT AND ENABLE_TEST)
   # Register target
   #
   ADD_EXECUTABLE(bsdcat_test ${bsdcat_test_SOURCES})
+  IF(ENABLE_ACL)
+    IF(HAVE_LIBACL)
+      TARGET_LINK_LIBRARIES(bsdcat_test ${ACL_LIBRARY})
+    ENDIF(HAVE_LIBACL)
+  ENDIF(ENABLE_ACL)
   SET_PROPERTY(TARGET bsdcat_test PROPERTY COMPILE_DEFINITIONS LIST_H)
 
   #
index b9f7f53d3ca41b2803d76c61133c0d35d53e912a..0592279d96a31bfd1edb70c861573d099d34eef3 100644 (file)
@@ -699,6 +699,7 @@ AC_ARG_ENABLE([acl],
 if test "x$enable_acl" != "xno"; then
    AC_CHECK_HEADERS([acl/libacl.h])
    AC_CHECK_HEADERS([sys/acl.h])
+   AC_CHECK_HEADERS([membership.h])
    AC_CHECK_LIB([acl],[acl_get_file])
    AC_CHECK_FUNCS([acl_create_entry acl_get_fd_np])
    AC_CHECK_FUNCS([acl_init acl_set_fd acl_set_fd_np acl_set_file])
index ec9509be98fa20fd1195c553f3720c0499a72643..cc5fe0117db3f19b995869debbdbc0dd222c812f 100644 (file)
@@ -62,6 +62,11 @@ IF(ENABLE_CPIO AND ENABLE_TEST)
   # Register target
   #
   ADD_EXECUTABLE(bsdcpio_test ${bsdcpio_test_SOURCES})
+  IF(ENABLE_ACL)
+    IF(HAVE_LIBACL)
+      TARGET_LINK_LIBRARIES(bsdcpio_test ${ACL_LIBRARY})
+    ENDIF(HAVE_LIBACL)
+  ENDIF(ENABLE_ACL)
   SET_PROPERTY(TARGET bsdcpio_test PROPERTY COMPILE_DEFINITIONS LIST_H)
 
   #
index 128f0e08878cb724d9fd0013d0d8d2d19207b7da..01d6a70d10f848fc1e9c2a79fb049a752fabf040 100644 (file)
 #if HAVE_SYS_ACL_H && HAVE_ACL_CREATE_ENTRY && HAVE_ACL_INIT && HAVE_ACL_SET_FILE
 #if HAVE_DECL_ACL_USER
 #define        HAVE_POSIX_ACL  1
-#elif HAVE_DECL_ACL_TYPE_EXTENDED
+#elif HAVE_DECL_ACL_TYPE_EXTENDED && HAVE_MEMBERSHIP_H
 #define HAVE_DARWIN_ACL 1
 #endif
 #if HAVE_DECL_ACL_TYPE_NFS4
index 5783e5234d29c86fd1cb77d20cfd5ebab4cb72e2..c8854082ab1b00fce49461dfd9746157b79b3172 100644 (file)
@@ -248,63 +248,6 @@ static struct myacl_t acls_dir[] = {
 
 static const int acls_dir_cnt = (int)(sizeof(acls_dir)/sizeof(acls_dir[0]));
 
-#if HAVE_SUN_ACL
-static void *
-sunacl_get(int cmd, int *aclcnt, int fd, const char *path)
-{
-       int cnt, cntcmd;
-       size_t size;
-       void *aclp;
-
-       if (cmd == GETACL) {
-               cntcmd = GETACLCNT;
-               size = sizeof(aclent_t);
-       }
-#if HAVE_SUN_NFS4_ACL
-       else if (cmd == ACE_GETACL) {
-               cntcmd = ACE_GETACLCNT;
-               size = sizeof(ace_t);
-       }
-#endif
-       else {
-               errno = EINVAL;
-               *aclcnt = -1;
-               return (NULL);
-       }
-
-       aclp = NULL;
-       cnt = -2;
-       while (cnt == -2 || (cnt == -1 && errno == ENOSPC)) {
-               if (path != NULL)
-                       cnt = acl(path, cntcmd, 0, NULL);
-               else
-                       cnt = facl(fd, cntcmd, 0, NULL);
-
-               if (cnt > 0) {
-                       if (aclp == NULL)
-                               aclp = malloc(cnt * size);
-                       else
-                               aclp = realloc(NULL, cnt * size);
-                       if (aclp != NULL) {
-                               if (path != NULL)
-                                       cnt = acl(path, cmd, cnt, aclp);
-                               else
-                                       cnt = facl(fd, cmd, cnt, aclp);
-                       }
-               } else {
-                       if (aclp != NULL) {
-                               free(aclp);
-                               aclp = NULL;
-                       }
-                       break;
-               }
-       }
-
-       *aclcnt = cnt;
-       return (aclp);
-}
-#endif /* HAVE_SUN_ACL */
-
 static void
 set_acls(struct archive_entry *ae, struct myacl_t *acls, int start, int end)
 {
@@ -777,11 +720,10 @@ DEFINE_TEST(test_acl_platform_nfs4)
        skipping("NFS4 ACLs are not supported on this platform");
 #else
        char buff[64];
+       int i;
        struct stat st;
        struct archive *a;
        struct archive_entry *ae;
-       int i;
-       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;
@@ -793,92 +735,15 @@ DEFINE_TEST(test_acl_platform_nfs4)
        void *aclp;
        int aclcnt;
 #else  /* !HAVE_SUN_NFS4_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 */
-       int n;
        acl_t acl;
-#endif /* !HAVE_SUN_NFS4_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_FREEBSD_NFS4_ACL
-       acl = acl_from_text("owner@:rwxp::allow,group@:rwp:f:allow");
-       failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno));
-       assert((void *)acl != NULL);
-#elif HAVE_DARWIN_ACL
-       acl = acl_init(1);
-       assert((void *)acl != NULL);
-       assertEqualInt(0, acl_create_entry(&acl, &aclent));
-       assertEqualInt(0, acl_set_tag_type(aclent, ACL_EXTENDED_ALLOW));
-       assertEqualInt(0, acl_get_permset(aclent, &permset));
-       assertEqualInt(0, acl_add_perm(permset, ACL_READ_DATA));
-       assertEqualInt(0, acl_add_perm(permset, ACL_WRITE_DATA));
-       assertEqualInt(0, acl_add_perm(permset, ACL_APPEND_DATA));
-       assertEqualInt(0, acl_add_perm(permset, ACL_EXECUTE));
-       assertEqualInt(0, acl_set_permset(aclent, permset));
-       assertEqualInt(0, mbr_identifier_to_uuid(ID_TYPE_UID, &uid,
-           sizeof(uid_t), uuid));
-       assertEqualInt(0, acl_set_qualifier(aclent, uuid));
 #endif
 
-       /* Create a test dir and try to set an ACL on it. */
-       if (!assertMakeDir("pretest", 0755)) {
-#if !HAVE_SUN_NFS4_ACL
-               acl_free(acl);
-#endif
-               return;
-       }
+       assertMakeFile("pretest", 0644, "a");
 
-#if HAVE_SUN_NFS4_ACL
-       func = "acl()";
-       aclp = sunacl_get(GETACL, &aclcnt, 0, "pretest");
-       if (aclp != NULL) {
-               skipping("NFS4 ACL is not supported on this filesystem");
-               free(aclp);
+       if (setTestAcl("pretest") != ARCHIVE_TEST_ACL_TYPE_NFS4) {
+               skipping("NFS4 ACLs are not writable on this filesystem");
                return;
        }
-       free(aclp);
-       aclp = sunacl_get(ACE_GETACL, &aclcnt, 0, "pretest");
-#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 HAVE_SUN_NFS4_ACL
-       if (aclp == NULL)
-#else
-       if (n != 0)
-#endif
-       {
-#if HAVE_SUN_NFS4_ACL
-               if (errno == ENOSYS || errno == ENOTSUP)
-#else
-               if (errno == EOPNOTSUPP || errno == EINVAL)
-#endif
-               {
-                       skipping("NFS4 ACL is not supported on this filesystem");
-                       return;
-               }
-       }
-       failure("%s: errno = %d (%s)", func, errno, strerror(errno));
-#if HAVE_SUN_NFS4_ACL
-       assert(aclp != NULL);
-       free(aclp);
-       aclp = NULL;
-#else
-       assertEqualInt(0, n);
-#endif
 
        /* Create a write-to-disk object. */
        assert(NULL != (a = archive_write_disk_new()));
index a0da2273e2a478c23654af277d89ea17ba50d396..0224a57f1c23ecff54ed44f6cdc1d70f905d701d 100644 (file)
@@ -35,63 +35,6 @@ __FBSDID("$FreeBSD: head/lib/libarchive/test/test_acl_freebsd.c 189427 2009-03-0
 #define ACL_GET_PERM acl_get_perm_np
 #endif
 
-#if HAVE_SUN_ACL
-static void *
-sunacl_get(int cmd, int *aclcnt, int fd, const char *path)
-{
-       int cnt, cntcmd;
-       size_t size;
-       void *aclp;
-
-       if (cmd == GETACL) {
-               cntcmd = GETACLCNT;
-               size = sizeof(aclent_t);
-       }
-#if HAVE_SUN_NFS4_ACL
-       else if (cmd == ACE_GETACL) {
-               cntcmd = ACE_GETACLCNT;
-               size = sizeof(ace_t);
-       }
-#endif
-       else {
-               errno = EINVAL;
-               *aclcnt = -1;
-               return (NULL);
-       }
-
-       aclp = NULL;
-       cnt = -2;
-       while (cnt == -2 || (cnt == -1 && errno == ENOSPC)) {
-               if (path != NULL)
-                       cnt = acl(path, cntcmd, 0, NULL);
-               else
-                       cnt = facl(fd, cntcmd, 0, NULL);
-
-               if (cnt > 0) {
-                       if (aclp == NULL)
-                               aclp = malloc(cnt * size);
-                       else
-                               aclp = realloc(NULL, cnt * size);
-                       if (aclp != NULL) {
-                               if (path != NULL)
-                                       cnt = acl(path, cmd, cnt, aclp);
-                               else
-                                       cnt = facl(fd, cmd, cnt, aclp);
-                       }
-               } else {
-                       if (aclp != NULL) {
-                               free(aclp);
-                               aclp = NULL;
-                       }
-                       break;
-               }
-       }
-
-       *aclcnt = cnt;
-       return (aclp);
-}
-#endif  /* HAVE_SUN_ACL */
-
 static struct archive_test_acl_t acls2[] = {
        { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE | ARCHIVE_ENTRY_ACL_READ,
          ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
@@ -361,8 +304,6 @@ DEFINE_TEST(test_acl_platform_posix1e_restore)
        struct stat st;
        struct archive *a;
        struct archive_entry *ae;
-       int n, fd;
-       char *func;
 #if HAVE_SUN_ACL
        void *aclp;
        int aclcnt;
@@ -370,77 +311,12 @@ DEFINE_TEST(test_acl_platform_posix1e_restore)
        acl_t acl;
 #endif
 
-       /*
-        * First, do a quick manual set/read of ACL data to
-        * verify that the local filesystem does support ACLs.
-        * If it doesn't, we'll simply skip the remaining tests.
-        */
-#if HAVE_SUN_ACL
-       aclent_t aclp1[] = {
-           { USER_OBJ, -1, 4 | 2 | 1 },
-           { USER, 1, 4 | 2 },
-           { GROUP_OBJ, -1, 4 | 2 | 1 },
-           { GROUP, 15, 4 | 1 },
-           { CLASS_OBJ, -1, 4 | 2 | 1 },
-           { OTHER_OBJ, -1, 4 | 2 | 1 }
-       };
-#else
-       acl = acl_from_text("u::rwx,u:1:rw,g::rwx,g:15:rx,o::rwx,m::rwx");
-       failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno));
-       assert((void *)acl != NULL);
-#endif
-
-       /* Create a test file and try ACL on it. */
-       fd = open("pretest", O_WRONLY | O_CREAT | O_EXCL, 0777);
-       failure("Could not create test file?!");
-       if (!assert(fd >= 0)) {
-#if !HAVE_SUN_ACL
-               acl_free(acl);
-#endif
-               return;
-       }
+       assertMakeFile("pretest", 0644, "a");
 
-#if HAVE_SUN_ACL
-       aclp = sunacl_get(GETACL, &aclcnt, fd, NULL);
-       if (aclp == NULL)
-               close(fd);
-       if (errno == ENOSYS || errno == ENOTSUP) {
-               skipping("POSIX.1e ACLs are not supported on this filesystem");
-               return;
-       }
-       failure("facl(): errno = %d (%s)", errno, strerror(errno));
-       if (assert(aclp != NULL) == 0) {
-               free(aclp);
+       if (setTestAcl("pretest") != ARCHIVE_TEST_ACL_TYPE_POSIX1E) {
+               skipping("POSIX.1e ACLs are not writable on this filesystem");
                return;
        }
-       free(aclp);
-       aclp = NULL;
-
-       func = "facl()";
-       n = facl(fd, SETACL, (int)(sizeof(aclp1)/sizeof(aclp1[0])), &aclp1);
-#else
-       func = "acl_set_fd()";
-       n = acl_set_fd(fd, acl);
-#endif
-#if !HAVE_SUN_ACL
-       acl_free(acl);
-#endif
-       if (n != 0) {
-#if HAVE_SUN_ACL
-               if (errno == ENOSYS || errno == ENOTSUP)
-#else
-               if (errno == EOPNOTSUPP || errno == EINVAL)
-#endif
-               {
-                       close(fd);
-                       skipping("POSIX.1e ACLs are not supported on this filesystem");
-                       return;
-               }
-       }
-       failure("%s: errno = %d (%s)", func, errno, strerror(errno));
-       assertEqualInt(0, n);
-
-       close(fd);
 
        /* Create a write-to-disk object. */
        assert(NULL != (a = archive_write_disk_new()));
index 9115d6f643d1ba495c3ce5ac46e4e5fc9d1cd326..e6054babcf4605f9a348bac0a595d45097221bed 100644 (file)
@@ -34,6 +34,7 @@ IF(ENABLE_TAR AND ENABLE_TEST)
     test_option_U_upper.c
     test_option_X_upper.c
     test_option_a.c
+    test_option_acls.c
     test_option_b.c
     test_option_b64encode.c
     test_option_exclude.c
@@ -72,6 +73,11 @@ IF(ENABLE_TAR AND ENABLE_TEST)
   # Register target
   #
   ADD_EXECUTABLE(bsdtar_test ${bsdtar_test_SOURCES})
+  IF(ENABLE_ACL)
+    IF(HAVE_LIBACL)
+      TARGET_LINK_LIBRARIES(bsdtar_test ${ACL_LIBRARY})
+    ENDIF(HAVE_LIBACL)
+  ENDIF(ENABLE_ACL)
   SET_PROPERTY(TARGET bsdtar_test PROPERTY COMPILE_DEFINITIONS LIST_H)
 
   #
diff --git a/tar/test/test_option_acls.c b/tar/test/test_option_acls.c
new file mode 100644 (file)
index 0000000..5c3fbfd
--- /dev/null
@@ -0,0 +1,471 @@
+/*-
+ * Copyright (c) 2017 Martin Matuska
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+#if HAVE_POSIX_ACL || HAVE_DARWIN_ACL
+static const acl_perm_t acl_perms[] = {
+#if HAVE_DARWIN_ACL
+    ACL_READ_DATA,
+    ACL_LIST_DIRECTORY,
+    ACL_WRITE_DATA,
+    ACL_ADD_FILE,
+    ACL_EXECUTE,
+    ACL_SEARCH,
+    ACL_DELETE,
+    ACL_APPEND_DATA,
+    ACL_ADD_SUBDIRECTORY,
+    ACL_DELETE_CHILD,
+    ACL_READ_ATTRIBUTES,
+    ACL_WRITE_ATTRIBUTES,
+    ACL_READ_EXTATTRIBUTES,
+    ACL_WRITE_EXTATTRIBUTES,
+    ACL_READ_SECURITY,
+    ACL_WRITE_SECURITY,
+    ACL_CHANGE_OWNER,
+    ACL_SYNCHRONIZE
+#else /* !HAVE_DARWIN_ACL */
+    ACL_EXECUTE,
+    ACL_WRITE,
+    ACL_READ,
+#if HAVE_FREEBSD_NFS4_ACL
+    ACL_READ_DATA,
+    ACL_LIST_DIRECTORY,
+    ACL_WRITE_DATA,
+    ACL_ADD_FILE,
+    ACL_APPEND_DATA,
+    ACL_ADD_SUBDIRECTORY,
+    ACL_READ_NAMED_ATTRS,
+    ACL_WRITE_NAMED_ATTRS,
+    ACL_DELETE_CHILD,
+    ACL_READ_ATTRIBUTES,
+    ACL_WRITE_ATTRIBUTES,
+    ACL_DELETE,
+    ACL_READ_ACL,
+    ACL_WRITE_ACL,
+    ACL_WRITE_OWNER,
+    ACL_SYNCHRONIZE
+#endif /* HAVE_FREEBSD_NFS4_ACL */
+#endif /* !HAVE_DARWIN_ACL */
+};
+#if HAVE_DARWIN_ACL || HAVE_FREEBSD_NFS4_ACL
+static const acl_flag_t acl_flags[] = {
+#if HAVE_DARWIN_ACL
+    ACL_FLAG_DEFER_INHERIT,
+    ACL_FLAG_NO_INHERIT,
+    ACL_ENTRY_INHERITED,
+    ACL_ENTRY_FILE_INHERIT,
+    ACL_ENTRY_DIRECTORY_INHERIT,
+    ACL_ENTRY_LIMIT_INHERIT,
+    ACL_ENTRY_ONLY_INHERIT
+#else  /* HAVE_FREEBSD_NFS4_ACL */
+    ACL_ENTRY_FILE_INHERIT,
+    ACL_ENTRY_DIRECTORY_INHERIT,
+    ACL_ENTRY_NO_PROPAGATE_INHERIT,
+    ACL_ENTRY_INHERIT_ONLY,
+    ACL_ENTRY_SUCCESSFUL_ACCESS,
+    ACL_ENTRY_FAILED_ACCESS,
+    ACL_ENTRY_INHERITED
+#endif /* HAVE_FREEBSD_NFS4_ACL */
+};
+#endif /* HAVE_DARWIN_ACL || HAVE_FREEBSD_NFS4_ACL */
+
+/*
+ * Compare two ACL entries on FreeBSD or on Mac OS X
+ */
+static int
+compare_acl_entry(acl_entry_t ae_a, acl_entry_t ae_b, int is_nfs4)
+{
+       acl_tag_t tag_a, tag_b;
+       acl_permset_t permset_a, permset_b;
+       int perm_a, perm_b, perm_start, perm_end;
+       void *qual_a, *qual_b;
+#if HAVE_FREEBSD_NFS4_ACL
+       acl_entry_type_t type_a, type_b;
+#endif
+#if HAVE_FREEBSD_NFS4_ACL || HAVE_DARWIN_ACL
+       acl_flagset_t flagset_a, flagset_b;
+       int flag_a, flag_b;
+#endif
+       int i, r;
+
+
+       /* Compare ACL tag */
+       r = acl_get_tag_type(ae_a, &tag_a);
+       failure("acl_get_tag_type() error: %s", strerror(errno));
+       if (assertEqualInt(r, 0) == 0)
+               return (-1);
+       r = acl_get_tag_type(ae_b, &tag_b);
+       failure("acl_get_tag_type() error: %s", strerror(errno));
+       if (assertEqualInt(r, 0) == 0)
+               return (-1);
+       if (tag_a != tag_b)
+               return (0);
+
+       /* Compare ACL qualifier */
+#if HAVE_DARWIN_ACL
+       if (tag_a == ACL_EXTENDED_ALLOW || tag_b == ACL_EXTENDED_DENY)
+#else
+       if (tag_a == ACL_USER || tag_a == ACL_GROUP)
+#endif
+       {
+               qual_a = acl_get_qualifier(ae_a);
+               failure("acl_get_qualifier() error: %s", strerror(errno));
+               if (assert(qual_a != NULL) == 0)
+                       return (-1);
+               qual_b = acl_get_qualifier(ae_b);
+               failure("acl_get_qualifier() error: %s", strerror(errno));
+               if (assert(qual_b != NULL) == 0) {
+                       acl_free(qual_a);
+                       return (-1);
+               }
+#if HAVE_DARWIN_ACL
+               if (memcmp(((guid_t *)qual_a)->g_guid,
+                   ((guid_t *)qual_b)->g_guid, KAUTH_GUID_SIZE) != 0)
+#else
+               if ((tag_a == ACL_USER &&
+                   (*(uid_t *)qual_a != *(uid_t *)qual_b)) ||
+                   (tag_a == ACL_GROUP &&
+                   (*(gid_t *)qual_a != *(gid_t *)qual_b)))
+#endif
+               {
+                       acl_free(qual_a);
+                       acl_free(qual_b);
+                       return (0);
+               }
+               acl_free(qual_a);
+               acl_free(qual_b);
+       }
+
+#if HAVE_FREEBSD_NFS4_ACL
+       if (is_nfs4) {
+               /* Compare NFS4 ACL type */
+               r = acl_get_entry_type_np(ae_a, &type_a);
+               failure("acl_get_entry_type_np() error: %s", strerror(errno));
+               if (assertEqualInt(r, 0) == 0)
+                       return (-1);
+               r = acl_get_entry_type_np(ae_b, &type_b);
+               failure("acl_get_entry_type_np() error: %s", strerror(errno));
+               if (assertEqualInt(r, 0) == 0)
+                       return (-1);
+               if (type_a != type_b)
+                       return (0);
+       }
+#endif
+
+       /* Compare ACL perms */
+       r = acl_get_permset(ae_a, &permset_a);
+       failure("acl_get_permset() error: %s", strerror(errno));
+       if (assertEqualInt(r, 0) == 0)
+               return (-1);
+       r = acl_get_permset(ae_b, &permset_b);
+       failure("acl_get_permset() error: %s", strerror(errno));
+       if (assertEqualInt(r, 0) == 0)
+               return (-1);
+
+       perm_start = 0;
+       perm_end = (int)(sizeof(acl_perms) / sizeof(acl_perms[0]));
+#if HAVE_FREEBSD_NFS4_ACL
+       if (is_nfs4)
+               perm_start = 3;
+       else
+               perm_end = 3;
+#endif
+       /* Cycle through all perms and compare their value */
+       for (i = perm_start; i < perm_end; i++) {
+#if HAVE_LIBACL
+               perm_a = acl_get_perm(permset_a, acl_perms[i]);
+               perm_b = acl_get_perm(permset_b, acl_perms[i]);
+#else
+               perm_a = acl_get_perm_np(permset_a, acl_perms[i]);
+               perm_b = acl_get_perm_np(permset_b, acl_perms[i]);
+#endif
+               if (perm_a == -1 || perm_b == -1)
+                       return (-1);
+               if (perm_a != perm_b)
+                       return (0);
+       }
+
+#if HAVE_FREEBSD_NFS4_ACL || HAVE_DARWIN_ACL
+       if (is_nfs4) {
+               r = acl_get_flagset_np(ae_a, &flagset_a);
+               failure("acl_get_flagset_np() error: %s", strerror(errno));
+               if (assertEqualInt(r, 0) == 0)
+                       return (-1);
+               r = acl_get_flagset_np(ae_b, &flagset_b);
+               failure("acl_get_flagset_np() error: %s", strerror(errno));
+               if (assertEqualInt(r, 0) == 0)
+                       return (-1);
+               /* Cycle through all flags and compare their status */
+               for (i = 0; i < (int)(sizeof(acl_flags) / sizeof(acl_flags[0]));
+                   i++) {
+                       flag_a = acl_get_flag_np(flagset_a, acl_flags[i]);
+                       flag_b = acl_get_flag_np(flagset_b, acl_flags[i]);
+                       if (flag_a == -1 || flag_b == -1)
+                               return (-1);
+                       if (flag_a != flag_b)
+                               return (0);
+               }
+       }
+#else  /* HAVE_FREEBSD_NFS4_ACL || HAVE_DARWIN_ACL*/
+       (void)is_nfs4;  /* UNUSED */
+#endif
+       return (1);
+}
+#endif /* HAVE_POSIX_ACL || HAVE_DARWIN_ACL */
+
+#if HAVE_SUN_ACL || HAVE_DARWIN_ACL || HAVE_POSIX_ACL
+/*
+ * Clear default ACLs or inheritance flags
+ */
+static void
+clear_inheritance_flags(const char *path, int type)
+{
+       switch (type) {
+       case ARCHIVE_TEST_ACL_TYPE_POSIX1E:
+#if HAVE_POSIX_ACL
+               acl_delete_def_file(path);
+#else
+               /* Solaris */
+               setTestAcl(path);
+#endif
+               break;
+       case ARCHIVE_TEST_ACL_TYPE_NFS4:
+#if HAVE_NFS4_ACL
+               setTestAcl(path);
+#endif
+               break;
+       default:
+               (void)path;     /* UNUSED */
+               break;
+       }
+}
+
+static int
+compare_acls(const char *path_a, const char *path_b)
+{
+       int ret = 1;
+       int is_nfs4 = 0;
+#if HAVE_SUN_ACL
+       void *acl_a, *acl_b;
+       int aclcnt_a, aclcnt_b;
+        aclent_t *aclent_a, *aclent_b;
+        ace_t *ace_a, *ace_b;
+       int e;
+#else
+       acl_t acl_a, acl_b;
+       acl_entry_t aclent_a, aclent_b;
+       int a, b, r;
+#endif
+
+       acl_a = NULL;
+       acl_b = NULL;
+#if HAVE_SUN_ACL
+       acl_a = sunacl_get(GETACL, &aclcnt_a, 0, path_a);
+       if (acl_a == NULL) {
+#if HAVE_SUN_NFS4_ACL
+               is_nfs4 = 1;
+               acl_a = sunacl_get(ACE_GETACL, &aclcnt_a, 0, path_a);
+#endif
+               failure("acl_get() error: %s", strerror(errno));
+               if (assert(acl_a != NULL) == 0)
+                       return (-1);
+#if HAVE_SUN_NFS4_ACL
+               acl_b = sunacl_get(ACE_GETACL, &aclcnt_b, 0, path_b);
+#endif
+       } else
+               acl_b = sunacl_get(GETACL, &aclcnt_b, 0, path_b);
+       if (acl_b == NULL && (errno == ENOSYS || errno == ENOTSUP)) {
+               free(acl_a);
+               return (0);
+       }
+       failure("acl_get() error: %s", strerror(errno));
+       if (assert(acl_b != NULL) == 0) {
+               free(acl_a);
+               return (-1);
+       }
+
+       if (aclcnt_a != aclcnt_b) {
+               ret = 0;
+               goto exit_free;
+       }
+
+       for (e = 0; e < aclcnt_a; e++) {
+               if (!is_nfs4) {
+                       aclent_a = &((aclent_t *)acl_a)[e];
+                       aclent_b = &((aclent_t *)acl_b)[e];
+                       if (aclent_a->a_type != aclent_b->a_type ||
+                           aclent_a->a_id != aclent_b->a_id ||
+                           aclent_a->a_perm != aclent_b->a_perm) {
+                               ret = 0;
+                               goto exit_free;
+                       }
+               }
+#if HAVE_SUN_NFS4_ACL
+               else {
+                       ace_a = &((ace_t *)acl_a)[e];
+                       ace_b = &((ace_t *)acl_b)[e];
+                       if (ace_a->a_who != ace_b->a_who ||
+                           ace_a->a_access_mask != ace_b->a_access_mask ||
+                           ace_a->a_flags != ace_b->a_flags ||
+                           ace_a->a_type != ace_b->a_type) {
+                               ret = 0;
+                               goto exit_free;
+                       }
+               }
+#endif
+       }
+#else  /* !HAVE_SUN_ACL */
+#if HAVE_DARWIN_ACL
+       is_nfs4 = 1;
+       acl_a = acl_get_file(path_a, ACL_TYPE_EXTENDED);
+#elif HAVE_FREEBSD_NFS4_ACL
+       acl_a = acl_get_file(path_a, ACL_TYPE_NFS4);
+       if (acl_a != NULL)
+               is_nfs4 = 1;
+#endif
+#if !HAVE_DARWIN_ACL
+       if (acl_a == NULL)
+               acl_a = acl_get_file(path_a, ACL_TYPE_ACCESS);
+#endif
+       failure("acl_get_file() error: %s (%s)", path_a, strerror(errno));
+       if (assert(acl_a != NULL) == 0)
+               return (-1);
+#if HAVE_DARWIN_ACL
+       acl_b = acl_get_file(path_b, ACL_TYPE_EXTENDED);
+#elif HAVE_FREEBSD_NFS4_ACL
+       acl_b = acl_get_file(path_b, ACL_TYPE_NFS4);
+#endif
+#if !HAVE_DARWIN_ACL
+       if (acl_b == NULL) {
+#if HAVE_FREEBSD_NFS4_ACL
+               if (is_nfs4) {
+                       acl_free(acl_a);
+                       return (0);
+               }
+#endif
+               acl_b = acl_get_file(path_b, ACL_TYPE_ACCESS);
+       }
+       failure("acl_get_file() error: %s (%s)", path_b, strerror(errno));
+       if (assert(acl_b != NULL) == 0) {
+               acl_free(acl_a);
+               return (-1);
+       }
+#endif
+       a = acl_get_entry(acl_a, ACL_FIRST_ENTRY, &aclent_a);
+       if (a == -1) {
+               ret = 0;
+               goto exit_free;
+       }
+       b = acl_get_entry(acl_b, ACL_FIRST_ENTRY, &aclent_b);
+       if (b == -1) {
+               ret = 0;
+               goto exit_free;
+       }
+#if HAVE_DARWIN_ACL
+       while (a == 0 && b == 0)
+#else  /* FreeBSD, Linux */
+       while (a == 1 && b == 1)
+#endif
+       {
+               r = compare_acl_entry(aclent_a, aclent_b, is_nfs4);
+               if (r != 1) {
+                       ret = r;
+                       goto exit_free;
+               }
+               a = acl_get_entry(acl_a, ACL_NEXT_ENTRY, &aclent_a);
+               b = acl_get_entry(acl_b, ACL_NEXT_ENTRY, &aclent_b);
+       }
+       /* Entry count must match */
+       if (a != b)
+               ret = 0;
+#endif /* !HAVE_SUN_ACL */
+exit_free:
+#if HAVE_SUN_ACL
+       free(acl_a);
+       free(acl_b);
+#else
+       acl_free(acl_a);
+       acl_free(acl_b);
+#endif
+       return (ret);
+}
+#endif /* HAVE_SUN_ACL || HAVE_DARWIN_ACL || HAVE_POSIX_ACL */
+
+DEFINE_TEST(test_option_acls)
+{
+#if !HAVE_SUN_ACL && !HAVE_DARWIN_ACL && !HAVE_POSIX_ACL
+        skipping("ACLs are not supported on this platform");
+#else   /* HAVE_SUN_ACL || HAVE_DARWIN_ACL || HAVE_POSIX_ACL */
+       int acltype, r;
+
+       assertMakeFile("f", 0644, "a");
+       acltype = setTestAcl("f");
+       if (acltype == 0) {
+               skipping("Can't write ACLs on the filesystem");
+               return;
+       }
+
+       /* Archive it with acls */
+        r = systemf("%s -c --no-mac-metadata --acls -f acls.tar f >acls.out 2>acls.err", testprog);
+        assertEqualInt(r, 0);
+
+       /* Archive it without acls */
+       r = systemf("%s -c --no-mac-metadata --no-acls -f noacls.tar f >noacls.out 2>noacls.err", testprog);
+       assertEqualInt(r, 0);
+
+       /* Extract acls with acls */
+       assertMakeDir("acls_acls", 0755);
+       clear_inheritance_flags("acls_acls", acltype);
+       r = systemf("%s -x -C acls_acls --no-same-permissions --acls -f acls.tar >acls_acls.out 2>acls_acls.err", testprog);
+       assertEqualInt(r, 0);
+       r = compare_acls("f", "acls_acls/f");
+       assertEqualInt(r, 1);
+
+       /* Extractl acls without acls */
+       assertMakeDir("acls_noacls", 0755);
+       clear_inheritance_flags("acls_noacls", acltype);
+       r = systemf("%s -x -C acls_noacls -p --no-acls -f acls.tar >acls_noacls.out 2>acls_noacls.err", testprog);
+       assertEqualInt(r, 0);
+       r = compare_acls("f", "acls_noacls/f");
+       assertEqualInt(r, 0);
+
+       /* Extract noacls with acls flag */
+       assertMakeDir("noacls_acls", 0755);
+       clear_inheritance_flags("noacls_acls", acltype);
+       r = systemf("%s -x -C noacls_acls --no-same-permissions --acls -f noacls.tar >noacls_acls.out 2>noacls_acls.err", testprog);
+       assertEqualInt(r, 0);
+       r = compare_acls("f", "noacls_acls/f");
+       assertEqualInt(r, 0);
+
+       /* Extract noacls with noacls */
+       assertMakeDir("noacls_noacls", 0755);
+       clear_inheritance_flags("noacls_noacls", acltype);
+       r = systemf("%s -x -C noacls_noacls -p --no-acls -f noacls.tar >noacls_noacls.out 2>noacls_noacls.err", testprog);
+       assertEqualInt(r, 0);
+       r = compare_acls("f", "noacls_noacls/f");
+       assertEqualInt(r, 0);
+#endif /* HAVE_SUN_ACL || HAVE_DARWIN_ACL || HAVE_POSIX_ACL */
+}
index 1e5c1fec526c6ae3d2b37f4f3b0adb49391a454a..0078054178f06a68783d9bac56d17f80597b4d22 100644 (file)
 #include <unistd.h>
 #endif
 #include <wchar.h>
+#ifdef HAVE_ACL_LIBACL_H
+#include <acl/libacl.h>
+#endif
+#ifdef HAVE_SYS_ACL_H
+#include <sys/acl.h>
+#endif
 #ifdef HAVE_WINDOWS_H
 #include <windows.h>
 #endif
 #define HAVE_NFS4_ACL   1
 #endif
 
+#define        ARCHIVE_TEST_ACL_TYPE_POSIX1E   1
+#define        ARCHIVE_TEST_ACL_TYPE_NFS4      2
+
 /*
  * Redefine DEFINE_TEST for use in defining the test functions.
  */
@@ -363,9 +372,17 @@ int canXz(void);
 /* Return true if this filesystem can handle nodump flags. */
 int canNodump(void);
 
+/* Set test ACLs */
+int setTestAcl(const char *path);
+
 /* Return true if the file has large i-node number(>0xffffffff). */
 int is_LargeInode(const char *);
 
+#if HAVE_SUN_ACL
+/* Fetch ACLs on Solaris using acl() or facl() */
+void *sunacl_get(int cmd, int *aclcnt, int fd, const char *path);
+#endif
+
 /* Suck file into string allocated via malloc(). Call free() when done. */
 /* Supports printf-style args: slurpfile(NULL, "%s/myfile", refdir); */
 char *slurpfile(size_t *, const char *fmt, ...);
index ec2fbfedcf4ef0fe5a71322de4edd3695ae446bf..86ab5f1a489f765671fa45e1df2d26db6067a9e6 100644 (file)
 #include <stdarg.h>
 #include <time.h>
 
+/* ACL support */
+#ifdef HAVE_ACL_LIBACL_H
+#include <acl/libacl.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_ACL_H
+#include <sys/acl.h>
+#endif
+#if HAVE_DARWIN_ACL
+#include <membership.h>
+#endif
+
 /*
  *
  * Windows support routines
@@ -2422,6 +2436,227 @@ canNodump(void)
        return (0);
 }
 
+#if HAVE_SUN_ACL
+/* Fetch ACLs on Solaris using acl() or facl() */
+void *
+sunacl_get(int cmd, int *aclcnt, int fd, const char *path)
+{
+       int cnt, cntcmd;
+       size_t size;
+       void *aclp;
+
+       if (cmd == GETACL) {
+               cntcmd = GETACLCNT;
+               size = sizeof(aclent_t);
+       }
+#if HAVE_SUN_NFS4_ACL
+       else if (cmd == ACE_GETACL) {
+               cntcmd = ACE_GETACLCNT;
+               size = sizeof(ace_t);
+       }
+#endif
+       else {
+               errno = EINVAL;
+               *aclcnt = -1;
+               return (NULL);
+       }
+
+       aclp = NULL;
+       cnt = -2;
+       while (cnt == -2 || (cnt == -1 && errno == ENOSPC)) {
+               if (path != NULL)
+                       cnt = acl(path, cntcmd, 0, NULL);
+               else
+                       cnt = facl(fd, cntcmd, 0, NULL);
+
+               if (cnt > 0) {
+                       if (aclp == NULL)
+                               aclp = malloc(cnt * size);
+                       else
+                               aclp = realloc(NULL, cnt * size);
+                       if (aclp != NULL) {
+                               if (path != NULL)
+                                       cnt = acl(path, cmd, cnt, aclp);
+                               else
+                                       cnt = facl(fd, cmd, cnt, aclp);
+                       }
+               } else {
+                       if (aclp != NULL) {
+                               free(aclp);
+                               aclp = NULL;
+                       }
+                       break;
+               }
+       }
+
+       *aclcnt = cnt;
+       return (aclp);
+}
+#endif /* HAVE_SUN_ACL */
+
+/*
+ * Set test ACLs on a path
+ * Return values:
+ * 0: error setting ACLs
+ * ARCHIVE_TEST_ACL_TYPE_POSIX1E: POSIX.1E ACLs have been set
+ * ARCHIVE_TEST_ACL_TYPE_NFS4: NFSv4 or extended ACLs have been set
+ */
+int
+setTestAcl(const char *path)
+{
+#if HAVE_POSIX_ACL || HAVE_NFS4_ACL
+       int r = 1;
+#if !HAVE_SUN_ACL
+       acl_t acl;
+#endif
+#if HAVE_POSIX_ACL /* Linux, FreeBSD POSIX.1e */
+       const char *acltext_posix1e = "user:1:rw-,"
+           "group:15:r-x,"
+           "user::rwx,"
+           "group::rwx,"
+           "other::r-x,"
+           "mask::rwx";
+#elif HAVE_SUN_ACL /* Solaris POSIX.1e */
+       aclent_t aclp_posix1e[] = {
+           { USER_OBJ, -1, 4 | 2 | 1 },
+           { USER, 1, 4 | 2 },
+           { GROUP_OBJ, -1, 4 | 2 | 1 },
+           { GROUP, 15, 4 | 1 },
+           { CLASS_OBJ, -1, 4 | 2 | 1 },
+           { OTHER_OBJ, -1, 4 | 2 | 1 }
+       };
+#endif
+#if HAVE_FREEBSD_NFS4_ACL /* FreeBSD NFS4 */
+       const char *acltext_nfs4 = "user:1:rwpaRcs::allow:1,"
+           "group:15:rxaRcs::allow:15,"
+           "owner@:rwpxaARWcCos::allow,"
+           "group@:rwpxaRcs::allow,"
+           "everyone@:rxaRcs::allow";
+#elif HAVE_SUN_NFS4_ACL /* Solaris NFS4 */
+       ace_t aclp_nfs4[] = {
+           { 1, ACE_READ_DATA | ACE_WRITE_DATA | ACE_APPEND_DATA |
+             ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS | ACE_READ_ACL |
+             ACE_SYNCHRONIZE, 0, ACE_ACCESS_ALLOWED_ACE_TYPE },
+           { 15, ACE_READ_DATA | ACE_EXECUTE | ACE_READ_ATTRIBUTES |
+             ACE_READ_NAMED_ATTRS | ACE_READ_ACL | ACE_SYNCHRONIZE,
+             ACE_IDENTIFIER_GROUP, ACE_ACCESS_ALLOWED_ACE_TYPE },
+           { -1, ACE_READ_DATA | ACE_WRITE_DATA | ACE_APPEND_DATA |
+             ACE_EXECUTE | ACE_READ_ATTRIBUTES | ACE_WRITE_ATTRIBUTES |
+             ACE_READ_NAMED_ATTRS | ACE_WRITE_NAMED_ATTRS |
+             ACE_READ_ACL | ACE_WRITE_ACL | ACE_WRITE_OWNER | ACE_SYNCHRONIZE,
+             ACE_OWNER, ACE_ACCESS_ALLOWED_ACE_TYPE },
+           { -1, ACE_READ_DATA | ACE_WRITE_DATA | ACE_APPEND_DATA |
+             ACE_EXECUTE | ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS |
+             ACE_READ_ACL | ACE_SYNCHRONIZE, ACE_GROUP | ACE_IDENTIFIER_GROUP,
+             ACE_ACCESS_ALLOWED_ACE_TYPE },
+           { -1, ACE_READ_DATA | ACE_EXECUTE | ACE_READ_ATTRIBUTES |
+             ACE_READ_NAMED_ATTRS | ACE_READ_ACL | ACE_SYNCHRONIZE,
+             ACE_EVERYONE, ACE_ACCESS_ALLOWED_ACE_TYPE }
+       };
+#elif HAVE_DARWIN_ACL /* Mac OS X */
+       acl_entry_t aclent;
+       acl_permset_t permset;
+       const uid_t uid = 1;
+       uuid_t uuid;
+       int i;
+       const acl_perm_t acl_perms[] = {
+               ACL_READ_DATA,
+               ACL_WRITE_DATA,
+               ACL_APPEND_DATA,
+               ACL_EXECUTE,
+               ACL_READ_ATTRIBUTES,
+               ACL_READ_EXTATTRIBUTES,
+               ACL_READ_SECURITY,
+#if HAVE_DECL_ACL_SYNCHRONIZE
+               ACL_SYNCHRONIZE
+#endif
+       };
+#endif /* HAVE_DARWIN_ACL */
+
+#if HAVE_FREEBSD_NFS4_ACL
+       acl = acl_from_text(acltext_nfs4);
+       failure("acl_from_text() error: %s", strerror(errno));
+       if (assert(acl != NULL) == 0)
+               return (0);
+#elif HAVE_DARWIN_ACL
+       acl = acl_init(1);
+       failure("acl_init() error: %s", strerror(errno));
+       if (assert(acl != NULL) == 0)
+               return (0);
+       r = acl_create_entry(&acl, &aclent);
+       failure("acl_create_entry() error: %s", strerror(errno));
+       if (assertEqualInt(r, 0) == 0)
+               goto testacl_free;
+       r = acl_set_tag_type(aclent, ACL_EXTENDED_ALLOW);
+       failure("acl_set_tag_type() error: %s", strerror(errno));
+       if (assertEqualInt(r, 0) == 0)
+               goto testacl_free;
+       r = acl_get_permset(aclent, &permset);
+       failure("acl_get_permset() error: %s", strerror(errno));
+       if (assertEqualInt(r, 0) == 0)
+               goto testacl_free;
+       for (i = 0; i < (int)(sizeof(acl_perms) / sizeof(acl_perms[0])); i++) {
+               r = acl_add_perm(permset, acl_perms[i]);
+               failure("acl_add_perm() error: %s", strerror(errno));
+               if (assertEqualInt(r, 0) == 0)
+                       goto testacl_free;
+       }
+       r = acl_set_permset(aclent, permset);
+       failure("acl_set_permset() error: %s", strerror(errno));
+       if (assertEqualInt(r, 0) == 0)
+               goto testacl_free;
+       r = mbr_identifier_to_uuid(ID_TYPE_UID, &uid, sizeof(uid_t), uuid);
+       failure("mbr_identifier_to_uuid() error: %s", strerror(errno));
+       if (assertEqualInt(r, 0) == 0)
+               goto testacl_free;
+       r = acl_set_qualifier(aclent, uuid);
+       failure("acl_set_qualifier() error: %s", strerror(errno));
+       if (assertEqualInt(r, 0) == 0)
+               goto testacl_free;
+#endif /* HAVE_DARWIN_ACL */
+
+#if HAVE_NFS4_ACL
+#if HAVE_FREEBSD_NFS4_ACL
+       r = acl_set_file(path, ACL_TYPE_NFS4, acl);
+       acl_free(acl);
+#elif HAVE_SUN_NFS4_ACL
+       r = acl(path, ACE_SETACL,
+           (int)(sizeof(aclp_nfs4)/sizeof(aclp_nfs4[0])), aclp_nfs4);
+#elif HAVE_DARWIN_ACL
+       r = acl_set_file(path, ACL_TYPE_EXTENDED, acl);
+       acl_free(acl);
+#endif
+       if (r == 0)
+               return (ARCHIVE_TEST_ACL_TYPE_NFS4);
+#endif /* HAVE_NFS4_ACL */
+
+#if HAVE_POSIX_ACL || HAVE_SUN_ACL
+#if HAVE_POSIX_ACL
+       acl = acl_from_text(acltext_posix1e);
+       failure("acl_from_text() error: %s", strerror(errno));
+       if (assert(acl != NULL) == 0)
+               return (0);
+
+       r = acl_set_file(path, ACL_TYPE_ACCESS, acl);
+       acl_free(acl);
+#elif HAVE_SUN_ACL
+       r = acl(path, SETACL,
+           (int)(sizeof(aclp_posix1e)/sizeof(aclp_posix1e[0])), aclp_posix1e);
+#endif
+       if (r == 0)
+               return (ARCHIVE_TEST_ACL_TYPE_POSIX1E);
+       else
+               return (0);
+#endif /* HAVE_POSIX_ACL || HAVE_SUN_ACL */
+#if HAVE_DARWIN_ACL
+testacl_free:
+       acl_free(acl);
+#endif
+#endif /* HAVE_POSIX_ACL || HAVE_NFS4_ACL */
+       (void)path;     /* UNUSED */
+       return (0);
+}
+
 /*
  * Sleep as needed; useful for verifying disk timestamp changes by
  * ensuring that the wall-clock time has actually changed before we