Implement ACL triviality check for Solaris
diff --git a/libarchive/archive_read_disk_entry_from_file.c b/libarchive/archive_read_disk_entry_from_file.c
index 7daa393..aa69dce 100644
--- a/libarchive/archive_read_disk_entry_from_file.c
+++ b/libarchive/archive_read_disk_entry_from_file.c
@@ -405,6 +405,11 @@
}
#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
static int translate_acl(struct archive_read_disk *a,
struct archive_entry *entry,
@@ -481,9 +486,8 @@
/* Ignore "trivial" ACLs that just mirror the file mode. */
if (acl != NULL) {
#if HAVE_SUN_ACL
- /* TODO: Check if ace_t is trivial like acl_is_trivial_np() */
- if (acl->acl_type == ACLENT_T &&
- (acl->acl_flags & ACL_IS_TRIVIAL) != 0)
+ if (sun_acl_is_trivial(acl, archive_entry_mode(entry),
+ &r) == 0 && r == 1)
#elif HAVE_ACL_IS_TRIVIAL_NP
if (acl_is_trivial_np(acl, &r) == 0 && r == 1)
#endif
@@ -655,6 +659,158 @@
#if HAVE_SUN_ACL
/*
+ * Check if acl is trivial
+ * This is a FreeBSD acl_is_trivial_np() implementation for Solaris
+ */
+static int
+sun_acl_is_trivial(acl_t *acl, mode_t mode, int *trivialp)
+{
+ uint32_t pubset, ownset;
+ uint32_t o_allow_pre, o_allow, g_allow, e_allow;
+ uint32_t o_deny, g_deny;
+ int i;
+
+ ace_t *ace;
+
+ if (acl == NULL || trivialp == NULL)
+ return (-1);
+
+ *trivialp = 0;
+
+ /* ACL_IS_TRIVIAL flag must be set for both POSIX.1e and NFSv4 ACLs */
+ if ((acl->acl_flags & ACL_IS_TRIVIAL) == 0)
+ return (0);
+
+ /*
+ * POSIX.1e ACLs marked with ACL_IS_TRIVIAL are compatible with
+ * FreeBSD acl_is_trivial_np(). On Solaris they have 4 entries,
+ * incuding mask.
+ */
+ if (acl->acl_type == ACLENT_T) {
+ if (acl->acl_cnt == 4)
+ *trivialp = 1;
+ return (0);
+ }
+
+ if (acl->acl_type != ACE_T || acl->acl_entry_size != sizeof(ace_t))
+ return (-1);
+
+ /* Continue with checking NFSv4 ACLs */
+ pubset = ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS | ACE_READ_ACL |
+ ACE_SYNCHRONIZE;
+ ownset = pubset | ACE_WRITE_ATTRIBUTES | ACE_WRITE_NAMED_ATTRS |
+ ACE_WRITE_ACL | ACE_WRITE_OWNER;
+
+ o_allow = ownset;
+ o_allow_pre = o_deny = g_deny = 0;
+ g_allow = e_allow = pubset;
+
+ /* Permissions for everyone@ */
+ if (mode & 0004)
+ e_allow |= ACE_READ_DATA;
+ if (mode & 0002)
+ e_allow |= ACE_WRITE_DATA | ACE_APPEND_DATA;
+ if (mode & 0001)
+ e_allow |= ACE_EXECUTE;
+
+ /* Permissions for group@ */
+ if (mode & 0040)
+ g_allow |= ACE_READ_DATA;
+ else if (mode & 0004)
+ g_deny |= ACE_READ_DATA;
+ if (mode & 0020)
+ g_allow |= ACE_WRITE_DATA | ACE_APPEND_DATA;
+ else if (mode & 0002)
+ g_deny |= ACE_WRITE_DATA | ACE_APPEND_DATA;
+ if (mode & 0010)
+ g_allow |= ACE_EXECUTE;
+ else if (mode & 0001)
+ g_deny |= ACE_EXECUTE;
+
+ /* Permissions for owner@ */
+ if (mode & 0400) {
+ o_allow |= ACE_READ_DATA;
+ if (!(mode & 0040) && (mode & 0004))
+ o_allow_pre |= ACE_READ_DATA;
+ } else if ((mode & 0040) || (mode & 0004))
+ o_deny |= ACE_READ_DATA;
+ if (mode & 0200) {
+ o_allow |= ACE_WRITE_DATA | ACE_APPEND_DATA;
+ if (!(mode & 0020) && (mode & 0002))
+ o_allow_pre |= ACE_WRITE_DATA | ACE_APPEND_DATA;
+ } else if ((mode & 0020) || (mode & 0002))
+ o_deny |= ACE_WRITE_DATA | ACE_APPEND_DATA;
+ if (mode & 0100) {
+ o_allow |= ACE_EXECUTE;
+ if (!(mode & 0010) && (mode & 0001))
+ o_allow_pre |= ACE_EXECUTE;
+ } else if ((mode & 0010) || (mode & 0001))
+ o_deny |= ACE_EXECUTE;
+
+ i = 3;
+
+ if (o_allow_pre != 0)
+ i++;
+ if (o_deny != 0)
+ i++;
+ if (g_deny != 0)
+ i++;
+
+ /* Check if the acl count matches */
+ if (acl->acl_cnt != i)
+ return (0);
+
+ i = 0;
+ if (o_allow_pre != 0) {
+ ace = &((ace_t *)acl->acl_aclp)[i];
+ if (ace->a_flags != ACE_OWNER ||
+ ace->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE ||
+ ace->a_access_mask != o_allow_pre)
+ return (0);
+ i++;
+ }
+ if (o_deny != 0) {
+ ace = &((ace_t *)acl->acl_aclp)[i];
+ if (ace->a_flags != ACE_OWNER ||
+ ace->a_type != ACE_ACCESS_DENIED_ACE_TYPE ||
+ ace->a_access_mask != o_deny)
+ return (0);
+ i++;
+ }
+ if (g_deny != 0) {
+ ace = &((ace_t *)acl->acl_aclp)[i];
+ if (ace->a_flags != (ACE_GROUP | ACE_IDENTIFIER_GROUP) ||
+ ace->a_type != ACE_ACCESS_DENIED_ACE_TYPE ||
+ ace->a_access_mask != g_deny)
+ return (0);
+ i++;
+ }
+
+ ace = &((ace_t *)acl->acl_aclp)[i];
+ if (ace->a_flags != ACE_OWNER ||
+ ace->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE ||
+ ace->a_access_mask != o_allow)
+ return (0);
+ i++;
+
+ ace = &((ace_t *)acl->acl_aclp)[i];
+ if (ace->a_flags != (ACE_GROUP | ACE_IDENTIFIER_GROUP) ||
+ ace->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE ||
+ ace->a_access_mask != g_allow)
+ return (0);
+ i++;
+
+ ace = &((ace_t *)acl->acl_aclp)[i];
+ if (ace->a_flags != ACE_EVERYONE ||
+ ace->a_type != ACE_ACCESS_ALLOWED_ACE_TYPE ||
+ ace->a_access_mask != e_allow)
+ return (0);
+
+ *trivialp = 1;
+ return (0);
+}
+
+/*
* Translate Solaris POSIX.1e and NFSv4 ACLs into libarchive internal ACL
*/
static int