aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Matuska <mm@FreeBSD.org>2016-12-30 01:27:27 +0000
committerMartin Matuska <mm@FreeBSD.org>2016-12-30 01:27:27 +0000
commitdc8e86c53b2b64153a65a95fc8d0ac06c7e08f9a (patch)
treeeb0dc6939db602762104f47188462fb878a2f4f5
parentcda329a1ca4579ea4cef22edbcc299737dd8cb76 (diff)
downloadsrc-dc8e86c53b2b64153a65a95fc8d0ac06c7e08f9a.tar.gz
src-dc8e86c53b2b64153a65a95fc8d0ac06c7e08f9a.zip
Update vendor/libarchive to git to 379867ecb330b3a952fb7bfa7bffb7bbd5547205
Vendor changes: PR #771: Add NFSv4 ACL support to pax and restricted pax
Notes
Notes: svn path=/vendor/libarchive/dist/; revision=310796
-rw-r--r--Makefile.am7
-rw-r--r--NEWS3
-rw-r--r--libarchive/archive_acl.c1613
-rw-r--r--libarchive/archive_acl_private.h21
-rw-r--r--libarchive/archive_entry.c112
-rw-r--r--libarchive/archive_entry.h57
-rw-r--r--libarchive/archive_entry_acl.3317
-rw-r--r--libarchive/archive_entry_locale.h11
-rw-r--r--libarchive/archive_read_disk_entry_from_file.c3
-rw-r--r--libarchive/archive_read_support_format_tar.c112
-rw-r--r--libarchive/archive_write_set_format_pax.c112
-rw-r--r--libarchive/libarchive-formats.54
-rw-r--r--libarchive/tar.511
-rw-r--r--libarchive/test/CMakeLists.txt3
-rw-r--r--libarchive/test/main.c126
-rw-r--r--libarchive/test/test.h17
-rw-r--r--libarchive/test/test_acl_freebsd_nfs4.c6
-rw-r--r--libarchive/test/test_acl_freebsd_posix1e.c69
-rw-r--r--libarchive/test/test_acl_nfs4.c126
-rw-r--r--libarchive/test/test_acl_pax.c366
-rw-r--r--libarchive/test/test_acl_pax_nfs4.tar.uu129
-rw-r--r--libarchive/test/test_acl_pax_posix1e.tar.uu (renamed from libarchive/test/test_acl_pax.tar.uu)2
-rw-r--r--libarchive/test/test_acl_posix1e.c144
-rw-r--r--libarchive/test/test_acl_text.c456
-rw-r--r--libarchive/test/test_compat_star_acl.c321
-rw-r--r--libarchive/test/test_compat_star_acl_nfs4.tar.uu231
-rw-r--r--libarchive/test/test_compat_star_acl_posix1e.c215
27 files changed, 3370 insertions, 1224 deletions
diff --git a/Makefile.am b/Makefile.am
index 6ed04959aff4..580fa2a6ec3b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -328,6 +328,7 @@ libarchive_test_SOURCES= \
libarchive/test/test_acl_nfs4.c \
libarchive/test/test_acl_pax.c \
libarchive/test/test_acl_posix1e.c \
+ libarchive/test/test_acl_text.c \
libarchive/test/test_archive_api_feature.c \
libarchive/test/test_archive_clear_error.c \
libarchive/test/test_archive_cmdline.c \
@@ -376,7 +377,7 @@ libarchive_test_SOURCES= \
libarchive/test/test_compat_plexus_archiver_tar.c \
libarchive/test/test_compat_solaris_tar_acl.c \
libarchive/test/test_compat_solaris_pax_sparse.c \
- libarchive/test/test_compat_star_acl_posix1e.c \
+ libarchive/test/test_compat_star_acl.c \
libarchive/test/test_compat_tar_hardlink.c \
libarchive/test/test_compat_uudecode.c \
libarchive/test/test_compat_uudecode_large.c \
@@ -598,7 +599,8 @@ libarchive_TESTS_ENVIRONMENT= LIBARCHIVE_TEST_FILES=`cd $(top_srcdir);/bin/pwd`/
libarchive_test_EXTRA_DIST=\
libarchive/test/list.h \
- libarchive/test/test_acl_pax.tar.uu \
+ libarchive/test/test_acl_pax_posix1e.tar.uu \
+ libarchive/test/test_acl_pax_nfs4.tar.uu \
libarchive/test/test_archive_string_conversion.txt.Z.uu \
libarchive/test/test_compat_bzip2_1.tbz.uu \
libarchive/test/test_compat_bzip2_2.tbz.uu \
@@ -635,6 +637,7 @@ libarchive_test_EXTRA_DIST=\
libarchive/test/test_compat_solaris_pax_sparse_1.pax.Z.uu \
libarchive/test/test_compat_solaris_pax_sparse_2.pax.Z.uu \
libarchive/test/test_compat_solaris_tar_acl.tar.uu \
+ libarchive/test/test_compat_star_acl_nfs4.tar.uu \
libarchive/test/test_compat_star_acl_posix1e.tar.uu \
libarchive/test/test_compat_tar_hardlink_1.tar.uu \
libarchive/test/test_compat_uudecode_large.tar.Z.uu \
diff --git a/NEWS b/NEWS
index 6f16b889ac86..4d875b2a9df5 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,6 @@
+Dec 27, 2016: NFSv4 ACL read and write support for pax
+ Deprecated functions: archive_entry_acl_text(), archive_entry_acl_text_w()
+
Oct 26, 2016: Remove liblzmadec support
Oct 23, 2016: libarchive 3.2.2 released
diff --git a/libarchive/archive_acl.c b/libarchive/archive_acl.c
index 3653d6fc7b4a..b8e8ba40d2ec 100644
--- a/libarchive/archive_acl.c
+++ b/libarchive/archive_acl.c
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2003-2010 Tim Kientzle
+ * Copyright (c) 2016 Martin Matuska
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -55,23 +56,31 @@ static struct archive_acl_entry *acl_new_entry(struct archive_acl *acl,
static int archive_acl_add_entry_len_l(struct archive_acl *acl,
int type, int permset, int tag, int id, const char *name,
size_t len, struct archive_string_conv *sc);
+static int archive_acl_text_want_type(struct archive_acl *acl, int flags);
+static ssize_t archive_acl_text_len(struct archive_acl *acl, int want_type,
+ int flags, int wide, struct archive *a,
+ struct archive_string_conv *sc);
static int isint_w(const wchar_t *start, const wchar_t *end, int *result);
static int ismode_w(const wchar_t *start, const wchar_t *end, int *result);
+static int is_nfs4_flags_w(const wchar_t *start, const wchar_t *end,
+ int *result);
+static int is_nfs4_perms_w(const wchar_t *start, const wchar_t *end,
+ int *result);
static void next_field_w(const wchar_t **wp, const wchar_t **start,
const wchar_t **end, wchar_t *sep);
-static int prefix_w(const wchar_t *start, const wchar_t *end,
- const wchar_t *test);
-static void append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
- const wchar_t *wname, int perm, int id);
+static void append_entry_w(wchar_t **wp, const wchar_t *prefix, int type,
+ int tag, int flags, const wchar_t *wname, int perm, int id);
static void append_id_w(wchar_t **wp, int id);
static int isint(const char *start, const char *end, int *result);
static int ismode(const char *start, const char *end, int *result);
+static int is_nfs4_flags(const char *start, const char *end,
+ int *result);
+static int is_nfs4_perms(const char *start, const char *end,
+ int *result);
static void next_field(const char **p, const char **start,
const char **end, char *sep);
-static int prefix_c(const char *start, const char *end,
- const char *test);
-static void append_entry(char **p, const char *prefix, int tag,
- const char *name, int perm, int id);
+static void append_entry(char **p, const char *prefix, int type,
+ int tag, int flags, const char *name, int perm, int id);
static void append_id(char **p, int id);
void
@@ -375,8 +384,8 @@ archive_acl_reset(struct archive_acl *acl, int want_type)
* standard permissions and include them in the returned list.
*/
int
-archive_acl_next(struct archive *a, struct archive_acl *acl, int want_type, int *type,
- int *permset, int *tag, int *id, const char **name)
+archive_acl_next(struct archive *a, struct archive_acl *acl, int want_type,
+ int *type, int *permset, int *tag, int *id, const char **name)
{
*name = NULL;
*id = -1;
@@ -441,130 +450,273 @@ archive_acl_next(struct archive *a, struct archive_acl *acl, int want_type, int
}
/*
- * Generate a text version of the ACL. The flags parameter controls
- * the style of the generated ACL.
+ * Determine what type of ACL do we want
*/
-const wchar_t *
-archive_acl_text_w(struct archive *a, struct archive_acl *acl, int flags)
+static int
+archive_acl_text_want_type(struct archive_acl *acl, int flags)
{
- int count;
- size_t length;
- const wchar_t *wname;
- const wchar_t *prefix;
- wchar_t separator;
- struct archive_acl_entry *ap;
- int id, r;
- wchar_t *wp;
+ int want_type;
- if (acl->acl_text_w != NULL) {
- free (acl->acl_text_w);
- acl->acl_text_w = NULL;
+ /* Check if ACL is NFSv4 */
+ if ((acl->acl_types & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
+ /* NFSv4 should never mix with POSIX.1e */
+ if ((acl->acl_types & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0)
+ return (0);
+ else
+ return (ARCHIVE_ENTRY_ACL_TYPE_NFS4);
}
- separator = L',';
+ /* Now deal with POSIX.1e ACLs */
+
+ want_type = 0;
+ if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)
+ want_type |= ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
+ if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)
+ want_type |= ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
+
+ /* By default we want both access and default ACLs */
+ if (want_type == 0)
+ return (ARCHIVE_ENTRY_ACL_TYPE_POSIX1E);
+
+ return (want_type);
+}
+
+/*
+ * Calculate ACL text string length
+ */
+static ssize_t
+archive_acl_text_len(struct archive_acl *acl, int want_type, int flags,
+ int wide, struct archive *a, struct archive_string_conv *sc) {
+ struct archive_acl_entry *ap;
+ const char *name;
+ const wchar_t *wname;
+ int count, idlen, tmp, r;
+ ssize_t length;
+ size_t len;
+
count = 0;
length = 0;
- ap = acl->acl_head;
- while (ap != NULL) {
- if ((ap->type & flags) != 0) {
- count++;
- if ((flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) &&
- (ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT))
- length += 8; /* "default:" */
- length += 5; /* tag name */
- length += 1; /* colon */
- r = archive_mstring_get_wcs(a, &ap->name, &wname);
- if (r == 0 && wname != NULL)
- length += wcslen(wname);
- else if (r < 0 && errno == ENOMEM)
- return (NULL);
- else
- length += sizeof(uid_t) * 3 + 1;
- length ++; /* colon */
+ for (ap = acl->acl_head; ap != NULL; ap = ap->next) {
+ if ((ap->type & want_type) == 0)
+ continue;
+ /*
+ * Filemode-mapping ACL entries are stored exclusively in
+ * ap->mode so they should not be in the list
+ */
+ if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS)
+ && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ
+ || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ
+ || ap->tag == ARCHIVE_ENTRY_ACL_OTHER))
+ continue;
+ count++;
+ if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0
+ && (ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)
+ length += 8; /* "default:" */
+ switch (ap->tag) {
+ case ARCHIVE_ENTRY_ACL_USER_OBJ:
+ if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
+ length += 6; /* "owner@" */
+ break;
+ }
+ /* FALLTHROUGH */
+ case ARCHIVE_ENTRY_ACL_USER:
+ case ARCHIVE_ENTRY_ACL_MASK:
+ length += 4; /* "user", "mask" */
+ break;
+ case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+ if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
+ length += 6; /* "group@" */
+ break;
+ }
+ /* FALLTHROUGH */
+ case ARCHIVE_ENTRY_ACL_GROUP:
+ case ARCHIVE_ENTRY_ACL_OTHER:
+ length += 5; /* "group", "other" */
+ break;
+ case ARCHIVE_ENTRY_ACL_EVERYONE:
+ length += 9; /* "everyone@" */
+ break;
+ }
+ length += 1; /* colon after tag */
+ if (ap->tag == ARCHIVE_ENTRY_ACL_USER ||
+ ap->tag == ARCHIVE_ENTRY_ACL_GROUP) {
+ if (wide) {
+ r = archive_mstring_get_wcs(a, &ap->name,
+ &wname);
+ if (r == 0 && wname != NULL)
+ length += wcslen(wname);
+ else if (r < 0 && errno == ENOMEM)
+ return (0);
+ else
+ length += sizeof(uid_t) * 3 + 1;
+ } else {
+ r = archive_mstring_get_mbs_l(&ap->name, &name,
+ &len, sc);
+ if (r != 0)
+ return (0);
+ if (len > 0 && name != NULL)
+ length += len;
+ else
+ length += sizeof(uid_t) * 3 + 1;
+ }
+ length += 1; /* colon after user or group name */
+ } else if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4)
+ length += 1; /* 2nd colon empty user,group or other */
+
+ if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) != 0)
+ && ((want_type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0)
+ && (ap->tag == ARCHIVE_ENTRY_ACL_OTHER
+ || ap->tag == ARCHIVE_ENTRY_ACL_MASK)) {
+ /* Solaris has no colon after other: and mask: */
+ length = length - 1;
+ }
+
+ if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
+ /* rwxpdDaARWcCos:fdinSFI:deny */
+ length += 27;
+ if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DENY) == 0)
+ length += 1; /* allow, alarm, audit */
+ } else
length += 3; /* rwx */
+
+ if ((ap->tag == ARCHIVE_ENTRY_ACL_USER ||
+ ap->tag == ARCHIVE_ENTRY_ACL_GROUP) &&
+ (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) != 0) {
length += 1; /* colon */
- length += max(sizeof(uid_t), sizeof(gid_t)) * 3 + 1;
- length ++; /* newline */
+ /* ID digit count */
+ idlen = 1;
+ tmp = ap->id;
+ while (tmp > 9) {
+ tmp = tmp / 10;
+ idlen++;
+ }
+ length += idlen;
}
- ap = ap->next;
+ length ++; /* entry separator */
}
- if (count > 0 && ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)) {
- length += 10; /* "user::rwx\n" */
- length += 11; /* "group::rwx\n" */
- length += 11; /* "other::rwx\n" */
- }
+ /* Add filemode-mapping access entries to the length */
+ if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
+ if ((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) != 0) {
+ /* "user::rwx\ngroup::rwx\nother:rwx\n" */
+ length += 31;
+ } else {
+ /* "user::rwx\ngroup::rwx\nother::rwx\n" */
+ length += 32;
+ }
+ } else if (count == 0)
+ return (0);
+
+ /* The terminating character is included in count */
+ return (length);
+}
- if (count == 0)
+/*
+ * Generate a wide text version of the ACL. The flags parameter controls
+ * the type and style of the generated ACL.
+ */
+wchar_t *
+archive_acl_to_text_w(struct archive_acl *acl, ssize_t *text_len, int flags,
+ struct archive *a)
+{
+ int count;
+ ssize_t length;
+ size_t len;
+ const wchar_t *wname;
+ const wchar_t *prefix;
+ wchar_t separator;
+ struct archive_acl_entry *ap;
+ int id, r, want_type;
+ wchar_t *wp, *ws;
+
+ want_type = archive_acl_text_want_type(acl, flags);
+
+ /* Both NFSv4 and POSIX.1 types found */
+ if (want_type == 0)
return (NULL);
+ if (want_type == ARCHIVE_ENTRY_ACL_TYPE_POSIX1E)
+ flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT;
+
+ length = archive_acl_text_len(acl, want_type, flags, 1, a, NULL);
+
+ if (length == 0)
+ return (NULL);
+
+ if (flags & ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA)
+ separator = L',';
+ else
+ separator = L'\n';
+
/* Now, allocate the string and actually populate it. */
- wp = acl->acl_text_w = (wchar_t *)malloc(length * sizeof(wchar_t));
- if (wp == NULL)
+ wp = ws = (wchar_t *)malloc(length * sizeof(wchar_t));
+ if (wp == NULL) {
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
return (NULL);
+ }
count = 0;
- if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
- append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL,
+
+ if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
+ append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ ARCHIVE_ENTRY_ACL_USER_OBJ, flags, NULL,
acl->mode & 0700, -1);
- *wp++ = ',';
- append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_GROUP_OBJ, NULL,
+ *wp++ = separator;
+ append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ ARCHIVE_ENTRY_ACL_GROUP_OBJ, flags, NULL,
acl->mode & 0070, -1);
- *wp++ = ',';
- append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_OTHER, NULL,
+ *wp++ = separator;
+ append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ ARCHIVE_ENTRY_ACL_OTHER, flags, NULL,
acl->mode & 0007, -1);
count += 3;
-
- ap = acl->acl_head;
- while (ap != NULL) {
- if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
- r = archive_mstring_get_wcs(a, &ap->name, &wname);
- if (r == 0) {
- *wp++ = separator;
- if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
- id = ap->id;
- else
- id = -1;
- append_entry_w(&wp, NULL, ap->tag, wname,
- ap->permset, id);
- count++;
- } else if (r < 0 && errno == ENOMEM)
- return (NULL);
- }
- ap = ap->next;
- }
}
-
- if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) {
- if (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT)
+ for (ap = acl->acl_head; ap != NULL; ap = ap->next) {
+ if ((ap->type & want_type) == 0)
+ continue;
+ /*
+ * Filemode-mapping ACL entries are stored exclusively in
+ * ap->mode so they should not be in the list
+ */
+ if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS)
+ && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ
+ || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ
+ || ap->tag == ARCHIVE_ENTRY_ACL_OTHER))
+ continue;
+ if (ap->type == ARCHIVE_ENTRY_ACL_TYPE_DEFAULT &&
+ (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0)
prefix = L"default:";
else
prefix = NULL;
- ap = acl->acl_head;
- count = 0;
- while (ap != NULL) {
- if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) {
- r = archive_mstring_get_wcs(a, &ap->name, &wname);
- if (r == 0) {
- if (count > 0)
- *wp++ = separator;
- if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
- id = ap->id;
- else
- id = -1;
- append_entry_w(&wp, prefix, ap->tag,
- wname, ap->permset, id);
- count ++;
- } else if (r < 0 && errno == ENOMEM)
- return (NULL);
- }
- ap = ap->next;
- }
+ r = archive_mstring_get_wcs(a, &ap->name, &wname);
+ if (r == 0) {
+ if (count > 0)
+ *wp++ = separator;
+ if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
+ id = ap->id;
+ else
+ id = -1;
+ append_entry_w(&wp, prefix, ap->type, ap->tag, flags,
+ wname, ap->permset, id);
+ count++;
+ } else if (r < 0 && errno == ENOMEM)
+ return (NULL);
}
- return (acl->acl_text_w);
-}
+ /* Add terminating character */
+ *wp++ = L'\0';
+
+ len = wcslen(ws);
+ if ((ssize_t)len > (length - 1))
+ __archive_errx(1, "Buffer overrun");
+
+ if (text_len != NULL)
+ *text_len = len;
+
+ return (ws);
+}
static void
append_id_w(wchar_t **wp, int id)
@@ -577,8 +729,8 @@ append_id_w(wchar_t **wp, int id)
}
static void
-append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
- const wchar_t *wname, int perm, int id)
+append_entry_w(wchar_t **wp, const wchar_t *prefix, int type,
+ int tag, int flags, const wchar_t *wname, int perm, int id)
{
if (prefix != NULL) {
wcscpy(*wp, prefix);
@@ -588,6 +740,10 @@ append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
case ARCHIVE_ENTRY_ACL_USER_OBJ:
wname = NULL;
id = -1;
+ if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
+ wcscpy(*wp, L"owner@");
+ break;
+ }
/* FALLTHROUGH */
case ARCHIVE_ENTRY_ACL_USER:
wcscpy(*wp, L"user");
@@ -595,6 +751,10 @@ append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
wname = NULL;
id = -1;
+ if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
+ wcscpy(*wp, L"group@");
+ break;
+ }
/* FALLTHROUGH */
case ARCHIVE_ENTRY_ACL_GROUP:
wcscpy(*wp, L"group");
@@ -609,154 +769,209 @@ append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
wname = NULL;
id = -1;
break;
+ case ARCHIVE_ENTRY_ACL_EVERYONE:
+ wcscpy(*wp, L"everyone@");
+ wname = NULL;
+ id = -1;
+ break;
}
*wp += wcslen(*wp);
*(*wp)++ = L':';
- if (wname != NULL) {
- wcscpy(*wp, wname);
+ if (((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) ||
+ tag == ARCHIVE_ENTRY_ACL_USER ||
+ tag == ARCHIVE_ENTRY_ACL_GROUP) {
+ if (wname != NULL) {
+ wcscpy(*wp, wname);
+ *wp += wcslen(*wp);
+ } else if (tag == ARCHIVE_ENTRY_ACL_USER
+ || tag == ARCHIVE_ENTRY_ACL_GROUP) {
+ append_id_w(wp, id);
+ id = -1;
+ }
+ /* Solaris style has no second colon after other and mask */
+ if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) == 0)
+ || (tag != ARCHIVE_ENTRY_ACL_OTHER
+ && tag != ARCHIVE_ENTRY_ACL_MASK))
+ *(*wp)++ = L':';
+ }
+ if ((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
+ /* POSIX.1e ACL perms */
+ *(*wp)++ = (perm & 0444) ? L'r' : L'-';
+ *(*wp)++ = (perm & 0222) ? L'w' : L'-';
+ *(*wp)++ = (perm & 0111) ? L'x' : L'-';
+ } else {
+ /* NFS4 ACL perms */
+ *(*wp)++ = (perm & (ARCHIVE_ENTRY_ACL_READ_DATA |
+ ARCHIVE_ENTRY_ACL_LIST_DIRECTORY)) ? L'r' : L'-';
+ *(*wp)++ = (perm & (ARCHIVE_ENTRY_ACL_WRITE_DATA |
+ ARCHIVE_ENTRY_ACL_ADD_FILE)) ? L'w' : L'-';
+ *(*wp)++ = (perm & ARCHIVE_ENTRY_ACL_EXECUTE) ? L'x' : L'-';
+ *(*wp)++ = (perm & (ARCHIVE_ENTRY_ACL_APPEND_DATA |
+ ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY)) ? L'p' : L'-';
+ *(*wp)++ = (perm & ARCHIVE_ENTRY_ACL_DELETE) ? L'd' : L'-';
+ *(*wp)++ = (perm &
+ ARCHIVE_ENTRY_ACL_DELETE_CHILD) ? L'D' : L'-';
+ *(*wp)++ = (perm &
+ ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES) ? L'a' : L'-';
+ *(*wp)++ = (perm &
+ ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES) ? L'A' : L'-';
+ *(*wp)++ = (perm &
+ ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS) ? L'R' : L'-';
+ *(*wp)++ = (perm &
+ ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS) ? L'W' : L'-';
+ *(*wp)++ = (perm & ARCHIVE_ENTRY_ACL_READ_ACL) ? L'c' : L'-';
+ *(*wp)++ = (perm & ARCHIVE_ENTRY_ACL_WRITE_ACL) ? L'C' : L'-';
+ *(*wp)++ = (perm &
+ ARCHIVE_ENTRY_ACL_WRITE_OWNER) ? L'o' : L'-';
+ *(*wp)++ = (perm &
+ ARCHIVE_ENTRY_ACL_SYNCHRONIZE) ? L's' : L'-';
+ *(*wp)++ = L':';
+ *(*wp)++ = (perm &
+ ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT) ? L'f' : L'-';
+ *(*wp)++ = (perm &
+ ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT) ? L'd' : L'-';
+ *(*wp)++ = (perm &
+ ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY) ? L'i' : L'-';
+ *(*wp)++ = (perm &
+ ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT) ? L'n' : L'-';
+ *(*wp)++ = (perm &
+ ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS) ? L'S' : L'-';
+ *(*wp)++ = (perm &
+ ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS) ? L'F' : L'-';
+ *(*wp)++ = (perm &
+ ARCHIVE_ENTRY_ACL_ENTRY_INHERITED) ? L'I' : L'-';
+ *(*wp)++ = L':';
+ switch (type) {
+ case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
+ wcscpy(*wp, L"allow");
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_DENY:
+ wcscpy(*wp, L"deny");
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
+ wcscpy(*wp, L"audit");
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
+ wcscpy(*wp, L"alarm");
+ break;
+ default:
+ break;
+ }
*wp += wcslen(*wp);
- } else if (tag == ARCHIVE_ENTRY_ACL_USER
- || tag == ARCHIVE_ENTRY_ACL_GROUP) {
- append_id_w(wp, id);
- id = -1;
}
- *(*wp)++ = L':';
- *(*wp)++ = (perm & 0444) ? L'r' : L'-';
- *(*wp)++ = (perm & 0222) ? L'w' : L'-';
- *(*wp)++ = (perm & 0111) ? L'x' : L'-';
if (id != -1) {
*(*wp)++ = L':';
append_id_w(wp, id);
}
- **wp = L'\0';
}
-int
-archive_acl_text_l(struct archive_acl *acl, int flags,
- const char **acl_text, size_t *acl_text_len,
+/*
+ * Generate a text version of the ACL. The flags parameter controls
+ * the type and style of the generated ACL.
+ */
+char *
+archive_acl_to_text_l(struct archive_acl *acl, ssize_t *text_len, int flags,
struct archive_string_conv *sc)
{
int count;
- size_t length;
+ ssize_t length;
+ size_t len;
const char *name;
const char *prefix;
char separator;
struct archive_acl_entry *ap;
- size_t len;
- int id, r;
- char *p;
+ int id, r, want_type;
+ char *p, *s;
- if (acl->acl_text != NULL) {
- free (acl->acl_text);
- acl->acl_text = NULL;
- }
+ want_type = archive_acl_text_want_type(acl, flags);
- *acl_text = NULL;
- if (acl_text_len != NULL)
- *acl_text_len = 0;
- separator = ',';
- count = 0;
- length = 0;
- ap = acl->acl_head;
- while (ap != NULL) {
- if ((ap->type & flags) != 0) {
- count++;
- if ((flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) &&
- (ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT))
- length += 8; /* "default:" */
- length += 5; /* tag name */
- length += 1; /* colon */
- r = archive_mstring_get_mbs_l(
- &ap->name, &name, &len, sc);
- if (r != 0)
- return (-1);
- if (len > 0 && name != NULL)
- length += len;
- else
- length += sizeof(uid_t) * 3 + 1;
- length ++; /* colon */
- length += 3; /* rwx */
- length += 1; /* colon */
- length += max(sizeof(uid_t), sizeof(gid_t)) * 3 + 1;
- length ++; /* newline */
- }
- ap = ap->next;
- }
+ /* Both NFSv4 and POSIX.1 types found */
+ if (want_type == 0)
+ return (NULL);
- if (count > 0 && ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)) {
- length += 10; /* "user::rwx\n" */
- length += 11; /* "group::rwx\n" */
- length += 11; /* "other::rwx\n" */
- }
+ if (want_type == ARCHIVE_ENTRY_ACL_TYPE_POSIX1E)
+ flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT;
- if (count == 0)
- return (0);
+ length = archive_acl_text_len(acl, want_type, flags, 0, NULL, sc);
+
+ if (length == 0)
+ return (NULL);
+
+ if (flags & ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA)
+ separator = ',';
+ else
+ separator = '\n';
/* Now, allocate the string and actually populate it. */
- p = acl->acl_text = (char *)malloc(length);
- if (p == NULL)
- return (-1);
+ p = s = (char *)malloc(length * sizeof(char));
+ if (p == NULL) {
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
+ return (NULL);
+ }
count = 0;
- if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
- append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL,
+
+ if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
+ append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ ARCHIVE_ENTRY_ACL_USER_OBJ, flags, NULL,
acl->mode & 0700, -1);
- *p++ = ',';
- append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_GROUP_OBJ, NULL,
+ *p++ = separator;
+ append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ ARCHIVE_ENTRY_ACL_GROUP_OBJ, flags, NULL,
acl->mode & 0070, -1);
- *p++ = ',';
- append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_OTHER, NULL,
+ *p++ = separator;
+ append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ ARCHIVE_ENTRY_ACL_OTHER, flags, NULL,
acl->mode & 0007, -1);
count += 3;
-
- for (ap = acl->acl_head; ap != NULL; ap = ap->next) {
- if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) == 0)
- continue;
- r = archive_mstring_get_mbs_l(
- &ap->name, &name, &len, sc);
- if (r != 0)
- return (-1);
- *p++ = separator;
- if (name == NULL || (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)) {
- id = ap->id;
- } else {
- id = -1;
- }
- append_entry(&p, NULL, ap->tag, name,
- ap->permset, id);
- count++;
- }
}
-
- if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) {
- if (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT)
+ for (ap = acl->acl_head; ap != NULL; ap = ap->next) {
+ if ((ap->type & want_type) == 0)
+ continue;
+ /*
+ * Filemode-mapping ACL entries are stored exclusively in
+ * ap->mode so they should not be in the list
+ */
+ if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS)
+ && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ
+ || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ
+ || ap->tag == ARCHIVE_ENTRY_ACL_OTHER))
+ continue;
+ if (ap->type == ARCHIVE_ENTRY_ACL_TYPE_DEFAULT &&
+ (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0)
prefix = "default:";
else
prefix = NULL;
- count = 0;
- for (ap = acl->acl_head; ap != NULL; ap = ap->next) {
- if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) == 0)
- continue;
- r = archive_mstring_get_mbs_l(
- &ap->name, &name, &len, sc);
- if (r != 0)
- return (-1);
- if (count > 0)
- *p++ = separator;
- if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
- id = ap->id;
- else
- id = -1;
- append_entry(&p, prefix, ap->tag,
- name, ap->permset, id);
- count ++;
+ r = archive_mstring_get_mbs_l(
+ &ap->name, &name, &len, sc);
+ if (r != 0)
+ return (NULL);
+ if (count > 0)
+ *p++ = separator;
+ if (name == NULL ||
+ (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)) {
+ id = ap->id;
+ } else {
+ id = -1;
}
+ append_entry(&p, prefix, ap->type, ap->tag, flags, name,
+ ap->permset, id);
+ count++;
}
- *acl_text = acl->acl_text;
- if (acl_text_len != NULL)
- *acl_text_len = strlen(acl->acl_text);
- return (0);
+ /* Add terminating character */
+ *p++ = '\0';
+
+ len = strlen(s);
+
+ if ((ssize_t)len > (length - 1))
+ __archive_errx(1, "Buffer overrun");
+
+ if (text_len != NULL)
+ *text_len = len;
+
+ return (s);
}
static void
@@ -770,8 +985,8 @@ append_id(char **p, int id)
}
static void
-append_entry(char **p, const char *prefix, int tag,
- const char *name, int perm, int id)
+append_entry(char **p, const char *prefix, int type,
+ int tag, int flags, const char *name, int perm, int id)
{
if (prefix != NULL) {
strcpy(*p, prefix);
@@ -781,6 +996,10 @@ append_entry(char **p, const char *prefix, int tag,
case ARCHIVE_ENTRY_ACL_USER_OBJ:
name = NULL;
id = -1;
+ if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
+ strcpy(*p, "owner@");
+ break;
+ }
/* FALLTHROUGH */
case ARCHIVE_ENTRY_ACL_USER:
strcpy(*p, "user");
@@ -788,6 +1007,10 @@ append_entry(char **p, const char *prefix, int tag,
case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
name = NULL;
id = -1;
+ if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
+ strcpy(*p, "group@");
+ break;
+ }
/* FALLTHROUGH */
case ARCHIVE_ENTRY_ACL_GROUP:
strcpy(*p, "group");
@@ -802,48 +1025,146 @@ append_entry(char **p, const char *prefix, int tag,
name = NULL;
id = -1;
break;
+ case ARCHIVE_ENTRY_ACL_EVERYONE:
+ strcpy(*p, "everyone@");
+ name = NULL;
+ id = -1;
+ break;
}
*p += strlen(*p);
*(*p)++ = ':';
- if (name != NULL) {
- strcpy(*p, name);
+ if (((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) ||
+ tag == ARCHIVE_ENTRY_ACL_USER ||
+ tag == ARCHIVE_ENTRY_ACL_GROUP) {
+ if (name != NULL) {
+ strcpy(*p, name);
+ *p += strlen(*p);
+ } else if (tag == ARCHIVE_ENTRY_ACL_USER
+ || tag == ARCHIVE_ENTRY_ACL_GROUP) {
+ append_id(p, id);
+ id = -1;
+ }
+ /* Solaris style has no second colon after other and mask */
+ if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) == 0)
+ || (tag != ARCHIVE_ENTRY_ACL_OTHER
+ && tag != ARCHIVE_ENTRY_ACL_MASK))
+ *(*p)++ = ':';
+ }
+ if ((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) {
+ /* POSIX.1e ACL perms */
+ *(*p)++ = (perm & 0444) ? 'r' : '-';
+ *(*p)++ = (perm & 0222) ? 'w' : '-';
+ *(*p)++ = (perm & 0111) ? 'x' : '-';
+ } else {
+ /* NFS4 ACL perms */
+ *(*p)++ = (perm & (ARCHIVE_ENTRY_ACL_READ_DATA |
+ ARCHIVE_ENTRY_ACL_LIST_DIRECTORY)) ? 'r' : '-';
+ *(*p)++ = (perm & (ARCHIVE_ENTRY_ACL_WRITE_DATA |
+ ARCHIVE_ENTRY_ACL_ADD_FILE)) ? 'w' : '-';
+ *(*p)++ = (perm & (ARCHIVE_ENTRY_ACL_EXECUTE)) ? 'x' : '-';
+ *(*p)++ = (perm & (ARCHIVE_ENTRY_ACL_APPEND_DATA |
+ ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY)) ? 'p' : '-';
+ *(*p)++ = (perm & ARCHIVE_ENTRY_ACL_DELETE) ? 'd' : '-';
+ *(*p)++ = (perm & ARCHIVE_ENTRY_ACL_DELETE_CHILD) ? 'D' : '-';
+ *(*p)++ = (perm &
+ ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES) ? 'a' : '-';
+ *(*p)++ = (perm &
+ ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES) ? 'A' : '-';
+ *(*p)++ = (perm &
+ ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS) ? 'R' : '-';
+ *(*p)++ = (perm &
+ ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS) ? 'W' : '-';
+ *(*p)++ = (perm &
+ ARCHIVE_ENTRY_ACL_READ_ACL) ? 'c' : '-';
+ *(*p)++ = (perm &
+ ARCHIVE_ENTRY_ACL_WRITE_ACL) ? 'C' : '-';
+ *(*p)++ = (perm &
+ ARCHIVE_ENTRY_ACL_WRITE_OWNER) ? 'o' : '-';
+ *(*p)++ = (perm &
+ ARCHIVE_ENTRY_ACL_SYNCHRONIZE) ? 's' : '-';
+ *(*p)++ = ':';
+ *(*p)++ = (perm &
+ ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT) ? 'f' : '-';
+ *(*p)++ = (perm &
+ ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT) ? 'd' : '-';
+ *(*p)++ = (perm &
+ ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY) ? 'i' : '-';
+ *(*p)++ = (perm &
+ ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT) ? 'n' : '-';
+ *(*p)++ = (perm &
+ ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS) ? 'S' : '-';
+ *(*p)++ = (perm &
+ ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS) ? 'F' : '-';
+ *(*p)++ = (perm &
+ ARCHIVE_ENTRY_ACL_ENTRY_INHERITED) ? 'I' : '-';
+ *(*p)++ = ':';
+ switch (type) {
+ case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
+ strcpy(*p, "allow");
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_DENY:
+ strcpy(*p, "deny");
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
+ strcpy(*p, "audit");
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
+ strcpy(*p, "alarm");
+ break;
+ }
*p += strlen(*p);
- } else if (tag == ARCHIVE_ENTRY_ACL_USER
- || tag == ARCHIVE_ENTRY_ACL_GROUP) {
- append_id(p, id);
- id = -1;
}
- *(*p)++ = ':';
- *(*p)++ = (perm & 0444) ? 'r' : '-';
- *(*p)++ = (perm & 0222) ? 'w' : '-';
- *(*p)++ = (perm & 0111) ? 'x' : '-';
if (id != -1) {
*(*p)++ = ':';
append_id(p, id);
}
- **p = '\0';
}
/*
- * Parse a textual ACL. This automatically recognizes and supports
- * extensions described above. The 'type' argument is used to
- * indicate the type that should be used for any entries not
- * explicitly marked as "default:".
+ * Parse a wide ACL text string.
+ *
+ * The want_type argument may be one of the following:
+ * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - text is a POSIX.1e ACL of type ACCESS
+ * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - text is a POSIX.1e ACL of type DEFAULT
+ * ARCHIVE_ENTRY_ACL_TYPE_NFS4 - text is as a NFSv4 ACL
+ *
+ * POSIX.1e ACL entries prefixed with "default:" are treated as
+ * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT unless type is ARCHIVE_ENTRY_ACL_TYPE_NFS4
*/
int
-archive_acl_parse_w(struct archive_acl *acl,
- const wchar_t *text, int default_type)
+archive_acl_from_text_w(struct archive_acl *acl, const wchar_t *text,
+ int want_type)
{
struct {
const wchar_t *start;
const wchar_t *end;
- } field[4], name;
+ } field[6], name;
- int fields, n;
- int type, tag, permset, id;
+ const wchar_t *s, *st;
+
+ int numfields, fields, n, r, ret;
+ int type, types, tag, permset, id;
+ size_t len;
wchar_t sep;
- while (text != NULL && *text != L'\0') {
+ ret = ARCHIVE_OK;
+ types = 0;
+
+ switch (want_type) {
+ case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E:
+ want_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
+ case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
+ case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
+ numfields = 5;
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_NFS4:
+ numfields = 6;
+ break;
+ default:
+ return (ARCHIVE_FATAL);
+ }
+
+ while (text != NULL && *text != L'\0') {
/*
* Parse the fields out of the next entry,
* advance 'text' to start of next entry.
@@ -852,7 +1173,7 @@ archive_acl_parse_w(struct archive_acl *acl,
do {
const wchar_t *start, *end;
next_field_w(&text, &start, &end, &sep);
- if (fields < 4) {
+ if (fields < numfields) {
field[fields].start = start;
field[fields].end = end;
}
@@ -860,78 +1181,204 @@ archive_acl_parse_w(struct archive_acl *acl,
} while (sep == L':');
/* Set remaining fields to blank. */
- for (n = fields; n < 4; ++n)
+ for (n = fields; n < numfields; ++n)
field[n].start = field[n].end = NULL;
- /* Check for a numeric ID in field 1 or 3. */
- id = -1;
- isint_w(field[1].start, field[1].end, &id);
- /* Field 3 is optional. */
- if (id == -1 && fields > 3)
- isint_w(field[3].start, field[3].end, &id);
-
- /*
- * Solaris extension: "defaultuser::rwx" is the
- * default ACL corresponding to "user::rwx", etc.
- */
- if (field[0].end - field[0].start > 7
- && wmemcmp(field[0].start, L"default", 7) == 0) {
- type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
- field[0].start += 7;
- } else
- type = default_type;
+ if (field[0].start != NULL && *(field[0].start) == L'#') {
+ /* Comment, skip entry */
+ continue;
+ }
+ n = 0;
+ id = -1;
+ permset = 0;
name.start = name.end = NULL;
- if (prefix_w(field[0].start, field[0].end, L"user")) {
- if (!ismode_w(field[2].start, field[2].end, &permset))
- return (ARCHIVE_WARN);
- if (id != -1 || field[1].start < field[1].end) {
- tag = ARCHIVE_ENTRY_ACL_USER;
- name = field[1];
+
+ if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
+ /* POSIX.1e ACLs */
+ /*
+ * Default keyword "default:user::rwx"
+ * if found, we have one more field
+ *
+ * We also support old Solaris extension:
+ * "defaultuser::rwx" is the default ACL corresponding
+ * to "user::rwx", etc. valid only for first field
+ */
+ s = field[0].start;
+ len = field[0].end - field[0].start;
+ if (*s == L'd' && (len == 1 || (len >= 7
+ && wmemcmp((s + 1), L"efault", 6) == 0))) {
+ type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
+ if (len > 7)
+ field[0].start += 7;
+ else
+ n = 1;
} else
- tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
- } else if (prefix_w(field[0].start, field[0].end, L"group")) {
- if (!ismode_w(field[2].start, field[2].end, &permset))
- return (ARCHIVE_WARN);
- if (id != -1 || field[1].start < field[1].end) {
- tag = ARCHIVE_ENTRY_ACL_GROUP;
+ type = want_type;
+
+ /* Check for a numeric ID in field n+1 or n+3. */
+ isint_w(field[n + 1].start, field[n + 1].end, &id);
+ /* Field n+3 is optional. */
+ if (id == -1 && fields > n+3)
+ isint_w(field[n + 3].start, field[n + 3].end,
+ &id);
+
+ tag = 0;
+ s = field[n].start;
+ st = field[n].start + 1;
+ len = field[n].end - field[n].start;
+
+ switch (*s) {
+ case L'u':
+ if (len == 1 || (len == 4
+ && wmemcmp(st, L"ser", 3) == 0))
+ tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
+ break;
+ case L'g':
+ if (len == 1 || (len == 5
+ && wmemcmp(st, L"roup", 4) == 0))
+ tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+ break;
+ case L'o':
+ if (len == 1 || (len == 5
+ && wmemcmp(st, L"ther", 4) == 0))
+ tag = ARCHIVE_ENTRY_ACL_OTHER;
+ break;
+ case L'm':
+ if (len == 1 || (len == 4
+ && wmemcmp(st, L"ask", 3) == 0))
+ tag = ARCHIVE_ENTRY_ACL_MASK;
+ break;
+ default:
+ break;
+ }
+
+ switch (tag) {
+ case ARCHIVE_ENTRY_ACL_OTHER:
+ case ARCHIVE_ENTRY_ACL_MASK:
+ if (fields == (n + 2)
+ && field[n + 1].start < field[n + 1].end
+ && ismode_w(field[n + 1].start,
+ field[n + 1].end, &permset)) {
+ /* This is Solaris-style "other:rwx" */
+ } else if (fields == (n + 3) &&
+ field[n + 1].start < field[n + 1].end) {
+ /* Invalid mask or other field */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ break;
+ case ARCHIVE_ENTRY_ACL_USER_OBJ:
+ case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+ if (id != -1 ||
+ field[n + 1].start < field[n + 1].end) {
+ name = field[n + 1];
+ if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ)
+ tag = ARCHIVE_ENTRY_ACL_USER;
+ else
+ tag = ARCHIVE_ENTRY_ACL_GROUP;
+ }
+ break;
+ default:
+ /* Invalid tag, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+
+ /* Without "default:" we expect mode in field 2 */
+ if (permset == 0 && !ismode_w(field[n + 2].start,
+ field[n + 2].end, &permset)) {
+ /* Invalid mode, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ } else {
+ /* NFS4 ACLs */
+ s = field[0].start;
+ len = field[0].end - field[0].start;
+ tag = 0;
+
+ switch (len) {
+ case 4:
+ if (wmemcmp(s, L"user", 4) == 0)
+ tag = ARCHIVE_ENTRY_ACL_USER;
+ break;
+ case 5:
+ if (wmemcmp(s, L"group", 5) == 0)
+ tag = ARCHIVE_ENTRY_ACL_GROUP;
+ break;
+ case 6:
+ if (wmemcmp(s, L"owner@", 6) == 0)
+ tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
+ else if (wmemcmp(s, L"group@", len) == 0)
+ tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+ break;
+ case 9:
+ if (wmemcmp(s, L"everyone@", 9) == 0)
+ tag = ARCHIVE_ENTRY_ACL_EVERYONE;
+ default:
+ break;
+ }
+
+ if (tag == 0) {
+ /* Invalid tag, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ } else if (tag == ARCHIVE_ENTRY_ACL_USER ||
+ tag == ARCHIVE_ENTRY_ACL_GROUP) {
+ n = 1;
name = field[1];
} else
- tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
- } else if (prefix_w(field[0].start, field[0].end, L"other")) {
- if (fields == 2
- && field[1].start < field[1].end
- && ismode_w(field[1].start, field[1].end, &permset)) {
- /* This is Solaris-style "other:rwx" */
- } else if (fields == 3
- && field[1].start == field[1].end
- && field[2].start < field[2].end
- && ismode_w(field[2].start, field[2].end, &permset)) {
- /* This is FreeBSD-style "other::rwx" */
- } else
- return (ARCHIVE_WARN);
- tag = ARCHIVE_ENTRY_ACL_OTHER;
- } else if (prefix_w(field[0].start, field[0].end, L"mask")) {
- if (fields == 2
- && field[1].start < field[1].end
- && ismode_w(field[1].start, field[1].end, &permset)) {
- /* This is Solaris-style "mask:rwx" */
- } else if (fields == 3
- && field[1].start == field[1].end
- && field[2].start < field[2].end
- && ismode_w(field[2].start, field[2].end, &permset)) {
- /* This is FreeBSD-style "mask::rwx" */
- } else
- return (ARCHIVE_WARN);
- tag = ARCHIVE_ENTRY_ACL_MASK;
- } else
- return (ARCHIVE_WARN);
+ n = 0;
+
+ if (!is_nfs4_perms_w(field[1 + n].start,
+ field[1 + n].end, &permset)) {
+ /* Invalid NFSv4 perms, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ if (!is_nfs4_flags_w(field[2 + n].start,
+ field[2 + n].end, &permset)) {
+ /* Invalid NFSv4 flags, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ s = field[3 + n].start;
+ len = field[3 + n].end - field[3 + n].start;
+ type = 0;
+ if (len == 4) {
+ if (wmemcmp(s, L"deny", 4) == 0)
+ type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
+ } else if (len == 5) {
+ if (wmemcmp(s, L"allow", 5) == 0)
+ type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
+ else if (wmemcmp(s, L"audit", 5) == 0)
+ type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT;
+ else if (wmemcmp(s, L"alarm", 5) == 0)
+ type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
+ }
+ if (type == 0) {
+ /* Invalid entry type, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ isint_w(field[4 + n].start, field[4 + n].end, &id);
+ }
/* Add entry to the internal list. */
- archive_acl_add_entry_w_len(acl, type, permset,
+ r = archive_acl_add_entry_w_len(acl, type, permset,
tag, id, name.start, name.end - name.start);
+ if (r < ARCHIVE_WARN)
+ return (r);
+ if (r != ARCHIVE_OK)
+ ret = ARCHIVE_WARN;
+ types |= type;
}
- return (ARCHIVE_OK);
+
+ /* Reset ACL */
+ archive_acl_reset(acl, types);
+
+ return (ret);
}
/*
@@ -977,16 +1424,128 @@ ismode_w(const wchar_t *start, const wchar_t *end, int *permset)
*permset = 0;
while (p < end) {
switch (*p++) {
- case 'r': case 'R':
+ case L'r': case L'R':
*permset |= ARCHIVE_ENTRY_ACL_READ;
break;
- case 'w': case 'W':
+ case L'w': case L'W':
*permset |= ARCHIVE_ENTRY_ACL_WRITE;
break;
- case 'x': case 'X':
+ case L'x': case L'X':
*permset |= ARCHIVE_ENTRY_ACL_EXECUTE;
break;
- case '-':
+ case L'-':
+ break;
+ default:
+ return (0);
+ }
+ }
+ return (1);
+}
+
+/*
+ * Parse a string as a NFS4 ACL permission field.
+ * Returns true if the string is non-empty and consists only of NFS4 ACL
+ * permission characters, false otherwise
+ */
+static int
+is_nfs4_perms_w(const wchar_t *start, const wchar_t *end, int *permset)
+{
+ const wchar_t *p;
+
+ if (start >= end)
+ return (0);
+ p = start;
+ while (p < end) {
+ switch (*p++) {
+ case L'r':
+ *permset |= ARCHIVE_ENTRY_ACL_READ_DATA;
+ break;
+ case L'w':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_DATA;
+ break;
+ case L'x':
+ *permset |= ARCHIVE_ENTRY_ACL_EXECUTE;
+ break;
+ case L'p':
+ *permset |= ARCHIVE_ENTRY_ACL_APPEND_DATA;
+ break;
+ case L'D':
+ *permset |= ARCHIVE_ENTRY_ACL_DELETE_CHILD;
+ break;
+ case L'd':
+ *permset |= ARCHIVE_ENTRY_ACL_DELETE;
+ break;
+ case L'a':
+ *permset |= ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES;
+ break;
+ case L'A':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES;
+ break;
+ case L'R':
+ *permset |= ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS;
+ break;
+ case L'W':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS;
+ break;
+ case L'c':
+ *permset |= ARCHIVE_ENTRY_ACL_READ_ACL;
+ break;
+ case L'C':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_ACL;
+ break;
+ case L'o':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_OWNER;
+ break;
+ case L's':
+ *permset |= ARCHIVE_ENTRY_ACL_SYNCHRONIZE;
+ break;
+ case L'-':
+ break;
+ default:
+ return(0);
+ }
+ }
+ return (1);
+}
+
+/*
+ * Parse a string as a NFS4 ACL flags field.
+ * Returns true if the string is non-empty and consists only of NFS4 ACL
+ * flag characters, false otherwise
+ */
+static int
+is_nfs4_flags_w(const wchar_t *start, const wchar_t *end, int *permset)
+{
+ const wchar_t *p;
+
+ if (start >= end)
+ return (0);
+ p = start;
+ while (p < end) {
+ switch(*p++) {
+ case L'f':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT;
+ break;
+ case L'd':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT;
+ break;
+ case L'i':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY;
+ break;
+ case L'n':
+ *permset |=
+ ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT;
+ break;
+ case L'S':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS;
+ break;
+ case L'F':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS;
+ break;
+ case L'I':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERITED;
+ break;
+ case L'-':
break;
default:
return (0);
@@ -1033,46 +1592,48 @@ next_field_w(const wchar_t **wp, const wchar_t **start,
}
/*
- * Return true if the characters [start...end) are a prefix of 'test'.
- * This makes it easy to handle the obvious abbreviations: 'u' for 'user', etc.
- */
-static int
-prefix_w(const wchar_t *start, const wchar_t *end, const wchar_t *test)
-{
- if (start == end)
- return (0);
-
- if (*start++ != *test++)
- return (0);
-
- while (start < end && *start++ == *test++)
- ;
-
- if (start < end)
- return (0);
-
- return (1);
-}
-
-/*
- * Parse a textual ACL. This automatically recognizes and supports
- * extensions described above. The 'type' argument is used to
- * indicate the type that should be used for any entries not
- * explicitly marked as "default:".
+ * Parse an ACL text string.
+ *
+ * The want_type argument may be one of the following:
+ * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - text is a POSIX.1e ACL of type ACCESS
+ * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - text is a POSIX.1e ACL of type DEFAULT
+ * ARCHIVE_ENTRY_ACL_TYPE_NFS4 - text is as a NFSv4 ACL
+ *
+ * POSIX.1e ACL entries prefixed with "default:" are treated as
+ * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT unless type is ARCHIVE_ENTRY_ACL_TYPE_NFS4
*/
int
-archive_acl_parse_l(struct archive_acl *acl,
- const char *text, int default_type, struct archive_string_conv *sc)
+archive_acl_from_text_l(struct archive_acl *acl, const char *text,
+ int want_type, struct archive_string_conv *sc)
{
struct {
const char *start;
const char *end;
- } field[4], name;
+ } field[6], name;
- int fields, n, r, ret = ARCHIVE_OK;
- int type, tag, permset, id;
+ const char *s, *st;
+ int numfields, fields, n, r, ret;
+ int type, types, tag, permset, id;
+ size_t len;
char sep;
+ switch (want_type) {
+ case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E:
+ want_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
+ case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
+ case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
+ numfields = 5;
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_NFS4:
+ numfields = 6;
+ break;
+ default:
+ return (ARCHIVE_FATAL);
+ }
+
+ ret = ARCHIVE_OK;
+ types = 0;
+
while (text != NULL && *text != '\0') {
/*
* Parse the fields out of the next entry,
@@ -1082,7 +1643,7 @@ archive_acl_parse_l(struct archive_acl *acl,
do {
const char *start, *end;
next_field(&text, &start, &end, &sep);
- if (fields < 4) {
+ if (fields < numfields) {
field[fields].start = start;
field[fields].end = end;
}
@@ -1090,72 +1651,191 @@ archive_acl_parse_l(struct archive_acl *acl,
} while (sep == ':');
/* Set remaining fields to blank. */
- for (n = fields; n < 4; ++n)
+ for (n = fields; n < numfields; ++n)
field[n].start = field[n].end = NULL;
- /* Check for a numeric ID in field 1 or 3. */
- id = -1;
- isint(field[1].start, field[1].end, &id);
- /* Field 3 is optional. */
- if (id == -1 && fields > 3)
- isint(field[3].start, field[3].end, &id);
-
- /*
- * Solaris extension: "defaultuser::rwx" is the
- * default ACL corresponding to "user::rwx", etc.
- */
- if (field[0].end - field[0].start > 7
- && memcmp(field[0].start, "default", 7) == 0) {
- type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
- field[0].start += 7;
- } else
- type = default_type;
+ if (field[0].start != NULL && *(field[0].start) == '#') {
+ /* Comment, skip entry */
+ continue;
+ }
+ n = 0;
+ id = -1;
+ permset = 0;
name.start = name.end = NULL;
- if (prefix_c(field[0].start, field[0].end, "user")) {
- if (!ismode(field[2].start, field[2].end, &permset))
- return (ARCHIVE_WARN);
- if (id != -1 || field[1].start < field[1].end) {
- tag = ARCHIVE_ENTRY_ACL_USER;
- name = field[1];
+
+ if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
+ /* POSIX.1e ACLs */
+ /*
+ * Default keyword "default:user::rwx"
+ * if found, we have one more field
+ *
+ * We also support old Solaris extension:
+ * "defaultuser::rwx" is the default ACL corresponding
+ * to "user::rwx", etc. valid only for first field
+ */
+ s = field[0].start;
+ len = field[0].end - field[0].start;
+ if (*s == 'd' && (len == 1 || (len >= 7
+ && memcmp((s + 1), "efault", 6) == 0))) {
+ type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
+ if (len > 7)
+ field[0].start += 7;
+ else
+ n = 1;
} else
- tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
- } else if (prefix_c(field[0].start, field[0].end, "group")) {
- if (!ismode(field[2].start, field[2].end, &permset))
- return (ARCHIVE_WARN);
- if (id != -1 || field[1].start < field[1].end) {
- tag = ARCHIVE_ENTRY_ACL_GROUP;
+ type = want_type;
+
+ /* Check for a numeric ID in field n+1 or n+3. */
+ isint(field[n + 1].start, field[n + 1].end, &id);
+ /* Field n+3 is optional. */
+ if (id == -1 && fields > (n + 3))
+ isint(field[n + 3].start, field[n + 3].end,
+ &id);
+
+ tag = 0;
+ s = field[n].start;
+ st = field[n].start + 1;
+ len = field[n].end - field[n].start;
+
+ switch (*s) {
+ case 'u':
+ if (len == 1 || (len == 4
+ && memcmp(st, "ser", 3) == 0))
+ tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
+ break;
+ case 'g':
+ if (len == 1 || (len == 5
+ && memcmp(st, "roup", 4) == 0))
+ tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+ break;
+ case 'o':
+ if (len == 1 || (len == 5
+ && memcmp(st, "ther", 4) == 0))
+ tag = ARCHIVE_ENTRY_ACL_OTHER;
+ break;
+ case 'm':
+ if (len == 1 || (len == 4
+ && memcmp(st, "ask", 3) == 0))
+ tag = ARCHIVE_ENTRY_ACL_MASK;
+ break;
+ default:
+ break;
+ }
+
+ switch (tag) {
+ case ARCHIVE_ENTRY_ACL_OTHER:
+ case ARCHIVE_ENTRY_ACL_MASK:
+ if (fields == (n + 2)
+ && field[n + 1].start < field[n + 1].end
+ && ismode(field[n + 1].start,
+ field[n + 1].end, &permset)) {
+ /* This is Solaris-style "other:rwx" */
+ } else if (fields == (n + 3) &&
+ field[n + 1].start < field[n + 1].end) {
+ /* Invalid mask or other field */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ break;
+ case ARCHIVE_ENTRY_ACL_USER_OBJ:
+ case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+ if (id != -1 ||
+ field[n + 1].start < field[n + 1].end) {
+ name = field[n + 1];
+ if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ)
+ tag = ARCHIVE_ENTRY_ACL_USER;
+ else
+ tag = ARCHIVE_ENTRY_ACL_GROUP;
+ }
+ break;
+ default:
+ /* Invalid tag, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+
+ /* Without "default:" we expect mode in field 2 */
+ if (permset == 0 && !ismode(field[n + 2].start,
+ field[n + 2].end, &permset)) {
+ /* Invalid mode, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ } else {
+ /* NFS4 ACLs */
+ s = field[0].start;
+ len = field[0].end - field[0].start;
+ tag = 0;
+
+ switch (len) {
+ case 4:
+ if (memcmp(s, "user", 4) == 0)
+ tag = ARCHIVE_ENTRY_ACL_USER;
+ break;
+ case 5:
+ if (memcmp(s, "group", 5) == 0)
+ tag = ARCHIVE_ENTRY_ACL_GROUP;
+ break;
+ case 6:
+ if (memcmp(s, "owner@", 6) == 0)
+ tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
+ else if (memcmp(s, "group@", 6) == 0)
+ tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+ break;
+ case 9:
+ if (memcmp(s, "everyone@", 9) == 0)
+ tag = ARCHIVE_ENTRY_ACL_EVERYONE;
+ break;
+ default:
+ break;
+ }
+
+ if (tag == 0) {
+ /* Invalid tag, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ } else if (tag == ARCHIVE_ENTRY_ACL_USER ||
+ tag == ARCHIVE_ENTRY_ACL_GROUP) {
+ n = 1;
name = field[1];
} else
- tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
- } else if (prefix_c(field[0].start, field[0].end, "other")) {
- if (fields == 2
- && field[1].start < field[1].end
- && ismode(field[1].start, field[1].end, &permset)) {
- /* This is Solaris-style "other:rwx" */
- } else if (fields == 3
- && field[1].start == field[1].end
- && field[2].start < field[2].end
- && ismode(field[2].start, field[2].end, &permset)) {
- /* This is FreeBSD-style "other::rwx" */
- } else
- return (ARCHIVE_WARN);
- tag = ARCHIVE_ENTRY_ACL_OTHER;
- } else if (prefix_c(field[0].start, field[0].end, "mask")) {
- if (fields == 2
- && field[1].start < field[1].end
- && ismode(field[1].start, field[1].end, &permset)) {
- /* This is Solaris-style "mask:rwx" */
- } else if (fields == 3
- && field[1].start == field[1].end
- && field[2].start < field[2].end
- && ismode(field[2].start, field[2].end, &permset)) {
- /* This is FreeBSD-style "mask::rwx" */
- } else
- return (ARCHIVE_WARN);
- tag = ARCHIVE_ENTRY_ACL_MASK;
- } else
- return (ARCHIVE_WARN);
+ n = 0;
+
+ if (!is_nfs4_perms(field[1 + n].start,
+ field[1 + n].end, &permset)) {
+ /* Invalid NFSv4 perms, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ if (!is_nfs4_flags(field[2 + n].start,
+ field[2 + n].end, &permset)) {
+ /* Invalid NFSv4 flags, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ s = field[3 + n].start;
+ len = field[3 + n].end - field[3 + n].start;
+ type = 0;
+ if (len == 4) {
+ if (memcmp(s, "deny", 4) == 0)
+ type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
+ } else if (len == 5) {
+ if (memcmp(s, "allow", 5) == 0)
+ type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
+ else if (memcmp(s, "audit", 5) == 0)
+ type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT;
+ else if (memcmp(s, "alarm", 5) == 0)
+ type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
+ }
+ if (type == 0) {
+ /* Invalid entry type, skip entry */
+ ret = ARCHIVE_WARN;
+ continue;
+ }
+ isint(field[4 + n].start, field[4 + n].end,
+ &id);
+ }
/* Add entry to the internal list. */
r = archive_acl_add_entry_len_l(acl, type, permset,
@@ -1164,7 +1844,12 @@ archive_acl_parse_l(struct archive_acl *acl,
return (r);
if (r != ARCHIVE_OK)
ret = ARCHIVE_WARN;
+ types |= type;
}
+
+ /* Reset ACL */
+ archive_acl_reset(acl, types);
+
return (ret);
}
@@ -1230,6 +1915,118 @@ ismode(const char *start, const char *end, int *permset)
}
/*
+ * Parse a string as a NFS4 ACL permission field.
+ * Returns true if the string is non-empty and consists only of NFS4 ACL
+ * permission characters, false otherwise
+ */
+static int
+is_nfs4_perms(const char *start, const char *end, int *permset)
+{
+ const char *p;
+
+ if (start >= end)
+ return (0);
+ p = start;
+ while (p < end) {
+ switch (*p++) {
+ case 'r':
+ *permset |= ARCHIVE_ENTRY_ACL_READ_DATA;
+ break;
+ case 'w':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_DATA;
+ break;
+ case 'x':
+ *permset |= ARCHIVE_ENTRY_ACL_EXECUTE;
+ break;
+ case 'p':
+ *permset |= ARCHIVE_ENTRY_ACL_APPEND_DATA;
+ break;
+ case 'D':
+ *permset |= ARCHIVE_ENTRY_ACL_DELETE_CHILD;
+ break;
+ case 'd':
+ *permset |= ARCHIVE_ENTRY_ACL_DELETE;
+ break;
+ case 'a':
+ *permset |= ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES;
+ break;
+ case 'A':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES;
+ break;
+ case 'R':
+ *permset |= ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS;
+ break;
+ case 'W':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS;
+ break;
+ case 'c':
+ *permset |= ARCHIVE_ENTRY_ACL_READ_ACL;
+ break;
+ case 'C':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_ACL;
+ break;
+ case 'o':
+ *permset |= ARCHIVE_ENTRY_ACL_WRITE_OWNER;
+ break;
+ case 's':
+ *permset |= ARCHIVE_ENTRY_ACL_SYNCHRONIZE;
+ break;
+ case '-':
+ break;
+ default:
+ return(0);
+ }
+ }
+ return (1);
+}
+
+/*
+ * Parse a string as a NFS4 ACL flags field.
+ * Returns true if the string is non-empty and consists only of NFS4 ACL
+ * flag characters, false otherwise
+ */
+static int
+is_nfs4_flags(const char *start, const char *end, int *permset)
+{
+ const char *p;
+
+ if (start >= end)
+ return (0);
+ p = start;
+ while (p < end) {
+ switch(*p++) {
+ case 'f':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT;
+ break;
+ case 'd':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT;
+ break;
+ case 'i':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY;
+ break;
+ case 'n':
+ *permset |=
+ ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT;
+ break;
+ case 'S':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS;
+ break;
+ case 'F':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS;
+ break;
+ case 'I':
+ *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERITED;
+ break;
+ case '-':
+ break;
+ default:
+ return (0);
+ }
+ }
+ return (1);
+}
+
+/*
* Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]". *wp is updated
* to point to just after the separator. *start points to the first
* character of the matched text and *end just after the last
@@ -1264,25 +2061,3 @@ next_field(const char **p, const char **start,
if (**p != '\0')
(*p)++;
}
-
-/*
- * Return true if the characters [start...end) are a prefix of 'test'.
- * This makes it easy to handle the obvious abbreviations: 'u' for 'user', etc.
- */
-static int
-prefix_c(const char *start, const char *end, const char *test)
-{
- if (start == end)
- return (0);
-
- if (*start++ != *test++)
- return (0);
-
- while (start < end && *start++ == *test++)
- ;
-
- if (start < end)
- return (0);
-
- return (1);
-}
diff --git a/libarchive/archive_acl_private.h b/libarchive/archive_acl_private.h
index 1421adbf8a23..0aac6fff2d9d 100644
--- a/libarchive/archive_acl_private.h
+++ b/libarchive/archive_acl_private.h
@@ -66,22 +66,17 @@ int archive_acl_add_entry_w_len(struct archive_acl *,
int archive_acl_add_entry_len(struct archive_acl *,
int, int, int, int, const char *, size_t);
-const wchar_t *archive_acl_text_w(struct archive *, struct archive_acl *, int);
-int archive_acl_text_l(struct archive_acl *, int, const char **, size_t *,
+wchar_t *archive_acl_to_text_w(struct archive_acl *, ssize_t *, int,
+ struct archive *);
+char *archive_acl_to_text_l(struct archive_acl *, ssize_t *, int,
struct archive_string_conv *);
/*
- * Private ACL parser. This is private because it handles some
- * very weird formats that clients should not be messing with.
- * Clients should only deal with their platform-native formats.
- * Because of the need to support many formats cleanly, new arguments
- * are likely to get added on a regular basis. Clients who try to use
- * this interface are likely to be surprised when it changes.
+ * ACL text parser.
*/
-int archive_acl_parse_w(struct archive_acl *,
- const wchar_t *, int /* type */);
-int archive_acl_parse_l(struct archive_acl *,
- const char *, int /* type */,
- struct archive_string_conv *);
+int archive_acl_from_text_w(struct archive_acl *, const wchar_t * /* wtext */,
+ int /* type */);
+int archive_acl_from_text_l(struct archive_acl *, const char * /* text */,
+ int /* type */, struct archive_string_conv *);
#endif /* ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */
diff --git a/libarchive/archive_entry.c b/libarchive/archive_entry.c
index b05eb4d22477..5af030729895 100644
--- a/libarchive/archive_entry.c
+++ b/libarchive/archive_entry.c
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2016 Martin Matuska
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -1486,34 +1487,121 @@ archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type,
}
/*
- * Generate a text version of the ACL. The flags parameter controls
+ * Generate a text version of the ACL. The flags parameter controls
* the style of the generated ACL.
*/
+wchar_t *
+archive_entry_acl_to_text_w(struct archive_entry *entry, ssize_t *len,
+ int flags)
+{
+ return (archive_acl_to_text_w(&entry->acl, len, flags,
+ entry->archive));
+}
+
+char *
+archive_entry_acl_to_text(struct archive_entry *entry, ssize_t *len,
+ int flags)
+{
+ return (archive_acl_to_text_l(&entry->acl, len, flags, NULL));
+}
+
+char *
+_archive_entry_acl_to_text_l(struct archive_entry *entry, ssize_t *len,
+ int flags, struct archive_string_conv *sc)
+{
+ return (archive_acl_to_text_l(&entry->acl, len, flags, sc));
+}
+
+/*
+ * ACL text parser.
+ */
+int
+archive_entry_acl_from_text_w(struct archive_entry *entry,
+ const wchar_t *wtext, int type)
+{
+ return (archive_acl_from_text_w(&entry->acl, wtext, type));
+}
+
+int
+archive_entry_acl_from_text(struct archive_entry *entry,
+ const char *text, int type)
+{
+ return (archive_acl_from_text_l(&entry->acl, text, type, NULL));
+}
+
+int
+_archive_entry_acl_from_text_l(struct archive_entry *entry, const char *text,
+ int type, struct archive_string_conv *sc)
+{
+ return (archive_acl_from_text_l(&entry->acl, text, type, sc));
+}
+
+/* Deprecated */
+static int
+archive_entry_acl_text_compat(int *flags)
+{
+ if ((*flags & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) == 0)
+ return (1);
+
+ /* ABI compat with old ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID */
+ if ((*flags & OLD_ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) != 0)
+ *flags |= ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID;
+
+ /* ABI compat with old ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT */
+ if ((*flags & OLD_ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0)
+ *flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT;
+
+ *flags |= ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA;
+
+ return (0);
+}
+
+/* Deprecated */
const wchar_t *
archive_entry_acl_text_w(struct archive_entry *entry, int flags)
{
- const wchar_t *r;
- r = archive_acl_text_w(entry->archive, &entry->acl, flags);
- if (r == NULL && errno == ENOMEM)
- __archive_errx(1, "No memory");
- return (r);
+ if (entry->acl.acl_text_w != NULL) {
+ free(entry->acl.acl_text_w);
+ entry->acl.acl_text_w = NULL;
+ }
+ if (archive_entry_acl_text_compat(&flags) == 0)
+ entry->acl.acl_text_w = archive_acl_to_text_w(&entry->acl,
+ NULL, flags, entry->archive);
+ return (entry->acl.acl_text_w);
}
+/* Deprecated */
const char *
archive_entry_acl_text(struct archive_entry *entry, int flags)
{
- const char *p;
- if (archive_acl_text_l(&entry->acl, flags, &p, NULL, NULL) != 0
- && errno == ENOMEM)
- __archive_errx(1, "No memory");
- return (p);
+ if (entry->acl.acl_text != NULL) {
+ free(entry->acl.acl_text);
+ entry->acl.acl_text = NULL;
+ }
+ if (archive_entry_acl_text_compat(&flags) == 0)
+ entry->acl.acl_text = archive_acl_to_text_l(&entry->acl, NULL,
+ flags, NULL);
+
+ return (entry->acl.acl_text);
}
+/* Deprecated */
int
_archive_entry_acl_text_l(struct archive_entry *entry, int flags,
const char **acl_text, size_t *len, struct archive_string_conv *sc)
{
- return (archive_acl_text_l(&entry->acl, flags, acl_text, len, sc));
+ if (entry->acl.acl_text != NULL) {
+ free(entry->acl.acl_text);
+ entry->acl.acl_text = NULL;
+ }
+
+ if (archive_entry_acl_text_compat(&flags) == 0)
+ entry->acl.acl_text = archive_acl_to_text_l(&entry->acl,
+ (ssize_t *)len, flags, sc);
+
+ *acl_text = entry->acl.acl_text;
+
+ return (0);
}
/*
diff --git a/libarchive/archive_entry.h b/libarchive/archive_entry.h
index b6a5d89c5d6f..0f09b985029b 100644
--- a/libarchive/archive_entry.h
+++ b/libarchive/archive_entry.h
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2003-2008 Tim Kientzle
+ * Copyright (c) 2016 Martin Matuska
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -420,6 +421,7 @@ __LA_DECL void archive_entry_copy_mac_metadata(struct archive_entry *, const voi
/*
* Inheritance values (NFS4 ACLs only); included in permset.
*/
+#define ARCHIVE_ENTRY_ACL_ENTRY_INHERITED 0x01000000
#define ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT 0x02000000
#define ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT 0x04000000
#define ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT 0x08000000
@@ -433,15 +435,16 @@ __LA_DECL void archive_entry_copy_mac_metadata(struct archive_entry *, const voi
| ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT \
| ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY \
| ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS \
- | ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS)
+ | ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS \
+ | ARCHIVE_ENTRY_ACL_ENTRY_INHERITED)
/* We need to be able to specify combinations of these. */
-#define ARCHIVE_ENTRY_ACL_TYPE_ACCESS 256 /* POSIX.1e only */
-#define ARCHIVE_ENTRY_ACL_TYPE_DEFAULT 512 /* POSIX.1e only */
-#define ARCHIVE_ENTRY_ACL_TYPE_ALLOW 1024 /* NFS4 only */
-#define ARCHIVE_ENTRY_ACL_TYPE_DENY 2048 /* NFS4 only */
-#define ARCHIVE_ENTRY_ACL_TYPE_AUDIT 4096 /* NFS4 only */
-#define ARCHIVE_ENTRY_ACL_TYPE_ALARM 8192 /* NFS4 only */
+#define ARCHIVE_ENTRY_ACL_TYPE_ACCESS 0x00000100 /* POSIX.1e only */
+#define ARCHIVE_ENTRY_ACL_TYPE_DEFAULT 0x00000200 /* POSIX.1e only */
+#define ARCHIVE_ENTRY_ACL_TYPE_ALLOW 0x00000400 /* NFS4 only */
+#define ARCHIVE_ENTRY_ACL_TYPE_DENY 0x00000800 /* NFS4 only */
+#define ARCHIVE_ENTRY_ACL_TYPE_AUDIT 0x00001000 /* NFS4 only */
+#define ARCHIVE_ENTRY_ACL_TYPE_ALARM 0x00002000 /* NFS4 only */
#define ARCHIVE_ENTRY_ACL_TYPE_POSIX1E (ARCHIVE_ENTRY_ACL_TYPE_ACCESS \
| ARCHIVE_ENTRY_ACL_TYPE_DEFAULT)
#define ARCHIVE_ENTRY_ACL_TYPE_NFS4 (ARCHIVE_ENTRY_ACL_TYPE_ALLOW \
@@ -492,21 +495,43 @@ __LA_DECL int archive_entry_acl_next_w(struct archive_entry *, int /* want_type
* Construct a text-format ACL. The flags argument is a bitmask that
* can include any of the following:
*
+ * Flags only for archive entries with POSIX.1e ACL:
* ARCHIVE_ENTRY_ACL_TYPE_ACCESS - Include POSIX.1e "access" entries.
* ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - Include POSIX.1e "default" entries.
- * ARCHIVE_ENTRY_ACL_TYPE_NFS4 - Include NFS4 entries.
- * ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID - Include extra numeric ID field in
- * each ACL entry. ('star' introduced this for POSIX.1e, this flag
- * also applies to NFS4.)
* ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT - Include "default:" before each
- * default ACL entry, as used in old Solaris ACLs.
+ * default ACL entry.
+ * ARCHIVE_ENTRY_ACL_STYLE_SOLARIS - Output only one colon after "other" and
+ * "mask" entries.
+ *
+ * Flags for for archive entries with POSIX.1e ACL or NFSv4 ACL:
+ * ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID - Include extra numeric ID field in
+ * each ACL entry.
+ * ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA - Separate entries with comma
+ * instead of newline.
*/
-#define ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 1024
-#define ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 2048
+#define ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 0x00000001
+#define ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 0x00000002
+#define ARCHIVE_ENTRY_ACL_STYLE_SOLARIS 0x00000004
+#define ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA 0x00000008
+
+__LA_DECL wchar_t *archive_entry_acl_to_text_w(struct archive_entry *,
+ ssize_t * /* len */, int /* flags */);
+__LA_DECL char *archive_entry_acl_to_text(struct archive_entry *,
+ ssize_t * /* len */, int /* flags */);
+__LA_DECL int archive_entry_acl_from_text_w(struct archive_entry *,
+ const wchar_t * /* wtext */, int /* type */);
+__LA_DECL int archive_entry_acl_from_text(struct archive_entry *,
+ const char * /* text */, int /* type */);
+
+/* Deprecated constants */
+#define OLD_ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 1024
+#define OLD_ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 2048
+
+/* Deprecated functions */
__LA_DECL const wchar_t *archive_entry_acl_text_w(struct archive_entry *,
- int /* flags */);
+ int /* flags */) __attribute__ ((deprecated));
__LA_DECL const char *archive_entry_acl_text(struct archive_entry *,
- int /* flags */);
+ int /* flags */) __attribute__ ((deprecated));
/* Return bitmask of ACL types in an archive entry */
__LA_DECL int archive_entry_acl_types(struct archive_entry *);
diff --git a/libarchive/archive_entry_acl.3 b/libarchive/archive_entry_acl.3
index e85c4ded1627..93707d1ff054 100644
--- a/libarchive/archive_entry_acl.3
+++ b/libarchive/archive_entry_acl.3
@@ -1,4 +1,5 @@
.\" Copyright (c) 2010 Joerg Sonnenberger
+.\" Copyright (c) 2016 Martin Matuska
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
@@ -22,7 +23,7 @@
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd February 2, 2012
+.Dd December 27, 2016
.Dt ARCHIVE_ENTRY_ACL 3
.Os
.Sh NAME
@@ -30,10 +31,13 @@
.Nm archive_entry_acl_add_entry_w ,
.Nm archive_entry_acl_clear ,
.Nm archive_entry_acl_count ,
+.Nm archive_entry_acl_from_text ,
+.Nm archive_entry_acl_from_text_w,
.Nm archive_entry_acl_next ,
.Nm archive_entry_acl_next_w ,
.Nm archive_entry_acl_reset ,
-.Nm archive_entry_acl_text_w ,
+.Nm archive_entry_acl_to_text ,
+.Nm archive_entry_acl_to_text_w ,
.Nm archive_entry_acl_types
.Nd functions for manipulating Access Control Lists in archive entry descriptions
.Sh LIBRARY
@@ -63,6 +67,18 @@ Streaming Archive Library (libarchive, -larchive)
.Ft int
.Fn archive_entry_acl_count "struct archive_entry *a" "int type"
.Ft int
+.Fo archive_entry_acl_from_text
+.Fa "struct archive_entry *a"
+.Fa "const char *text"
+.Fa "int type"
+.Fc
+.Ft int
+.Fo archive_entry_acl_from_text_w
+.Fa "struct archive_entry *a"
+.Fa "const wchar_t *text"
+.Fa "int type"
+.Fc
+.Ft int
.Fo archive_entry_acl_next
.Fa "struct archive_entry *a"
.Fa "int type"
@@ -84,33 +100,48 @@ Streaming Archive Library (libarchive, -larchive)
.Fc
.Ft int
.Fn archive_entry_acl_reset "struct archive_entry *a" "int type"
-.Ft const wchar_t *
-.Fn archive_entry_acl_text_w "struct archive_entry *a" "int flags"
+.Ft char *
+.Fo archive_entry_acl_to_text
+.Fa "struct archive_entry *a"
+.Fa "ssize_t *len_p"
+.Fa "int flags"
+.Fc
+.Ft wchar_t *
+.Fo archive_entry_acl_to_text_w
+.Fa "struct archive_entry *a"
+.Fa "ssize_t *len_p"
+.Fa "int flags"
+.Fc
.Ft int
.Fn archive_entry_acl_types "struct archive_entry *a"
.\" enum?
.Sh DESCRIPTION
-An
-.Dq Access Control List
-is a generalisation of the classic Unix permission system.
+The
+.Dq Access Control Lists (ACLs)
+extend the standard Unix perssion model.
The ACL interface of
.Nm libarchive
-is derived from the POSIX.1e draft, but restricted to simplify dealing
-with practical implementations in various Operating Systems and archive formats.
-.Pp
-An ACL consists of a number of independent entries.
+supports both POSIX.1e and NFSv4 style ACLs. Use of ACLs is restricted by
+various levels of ACL support in operating systems, file systems and archive
+formats.
+.Ss POSIX.1e Access Control Lists
+A POSIX.1e ACL consists of a number of independent entries.
Each entry specifies the permission set as bitmask of basic permissions.
-Valid permissions are:
+Valid permissions in the
+.Fa permset
+are:
.Bl -tag -offset indent -compact -width "ARCHIVE_ENTRY_ACL_EXECUTE"
-.It Dv ARCHIVE_ENTRY_ACL_EXECUTE
-.It Dv ARCHIVE_ENTRY_ACL_WRITE
-.It Dv ARCHIVE_ENTRY_ACL_READ
+.It Dv ARCHIVE_ENTRY_ACL_READ ( Sy r )
+.It Dv ARCHIVE_ENTRY_ACL_WRITE ( Sy w )
+.It Dv ARCHIVE_ENTRY_ACL_EXECUTE ( Sy x )
.El
The permissions correspond to the normal Unix permissions.
.Pp
-The tag specifies the principal to which the permission applies.
+The
+.Fa tag
+specifies the principal to which the permission applies.
Valid values are:
-.Bl -tag -offset indent -compact -width "ARCHIVE_ENTRY_ACL_GROUP_OBJ"
+.Bl -hang -offset indent -compact -width "ARCHIVE_ENTRY_ACL_GROUP_OBJ"
.It Dv ARCHIVE_ENTRY_ACL_USER
The user specified by the name field.
.It Dv ARCHIVE_ENTRY_ACL_USER_OBJ
@@ -122,8 +153,9 @@ The group who owns the file.
.It Dv ARCHIVE_ENTRY_ACL_MASK
The maximum permissions to be obtained via group permissions.
.It Dv ARCHIVE_ENTRY_ACL_OTHER
-Any principal who doesn't have a user or group entry.
+Any principal who is not file owner or a member of the owning group.
.El
+.Pp
The principals
.Dv ARCHIVE_ENTRY_ACL_USER_OBJ ,
.Dv ARCHIVE_ENTRY_ACL_GROUP_OBJ
@@ -132,19 +164,123 @@ and
are equivalent to user, group and other in the classic Unix permission
model and specify non-extended ACL entries.
.Pp
-All files have an access ACL
+All files with have an access ACL
.Pq Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS .
This specifies the permissions required for access to the file itself.
Directories have an additional ACL
.Pq Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT ,
which controls the initial access ACL for newly created directory entries.
+.Ss NFSv4 Access Control Lists
+A NFSv4 ACL consists of multiple individual entries called Access Control
+Entries (ACEs).
+.Pp
+There are four possible types of a NFSv4 ACE:
+.Bl -hang -offset indent -compact -width "ARCHIVE_ENTRY_ACL_TYE_ALLOW"
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_ALLOW
+Allow principal to perform actions requiring given permissions.
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_DENY
+Prevent principal from performing actions requiring given permissions.
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_AUDIT
+Log access attempts by principal which require given permissions.
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_ALARM
+Trigger a system alarm on access attempts by principal which require given
+permissions.
+.El
+.Pp
+The
+.Fa tag
+specifies the principal to which the permission applies.
+Valid values are:
+.Bl -hang -offset indent -compact -width "ARCHIVE_ENTRY_ACL_GROUP_OBJ"
+.It Dv ARCHIVE_ENTRY_ACL_USER
+The user specified by the name field.
+.It Dv ARCHIVE_ENTRY_ACL_USER_OBJ
+The owner of the file.
+.It Dv ARCHIVE_ENTRY_ACL_GROUP
+The group specied by the name field.
+.It Dv ARCHIVE_ENTRY_ACL_GROUP_OBJ
+The group who owns the file.
+.It Dv ARCHIVE_ENTRY_ACL_EVERYONE
+Any principal who is not file owner or a member of the owning group.
+.El
+.Pp
+Entries with the
+.Dv ARCHIVE_ENTRY_ACL_USER
+or
+.Dv ARCHIVE_ENTRY_ACL_GROUP
+tag store the user and group name in the
+.Fa name
+string and optionally the user or group ID in the
+.Fa qualifier
+integer.
.Pp
+NFSv4 ACE permissions and flags are stored in the same
+.Fa permset
+bitfield. Some permissions share the same constant and permission character but
+have different effect on directories than on files. The following ACE
+permissions are supported:
+.Bl -tag -offset indent -compact -width ARCHIV
+.It Dv ARCHIVE_ENTRY_ACL_READ_DATA ( Sy r )
+Read data (file).
+.It Dv ARCHIVE_ENTRY_ACL_LIST_DIRECTORY ( Sy r )
+List entries (directory).
+.It ARCHIVE_ENTRY_ACL_WRITE_DATA ( Sy w )
+Write data (file).
+.It ARCHIVE_ENTRY_ACL_ADD_FILE ( Sy w )
+Create files (directory).
+.It Dv ARCHIVE_ENTRY_ACL_EXECUTE ( Sy x )
+Execute file or change into a directory.
+.It Dv ARCHIVE_ENTRY_ACL_APPEND_DATA ( Sy p )
+Append data (file).
+.It Dv ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY ( Sy p )
+Create subdirectories (directory).
+.It Dv ARCHIVE_ENTRY_ACL_DELETE_CHILD ( Sy D )
+Remove files and subdirectories inside a directory.
+.It Dv ARCHIVE_ENTRY_ACL_DELETE ( Sy d )
+Remove file or directory.
+.It Dv ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES ( Sy a )
+Read file or directory attributes.
+.It Dv ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES ( Sy A )
+Write file or directory attributes.
+.It Dv ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS ( Sy R )
+Read named file or directory attributes.
+.It Dv ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS ( Sy W )
+Write named file or directory attributes.
+.It Dv ARCHIVE_ENTRY_ACL_READ_ACL ( Sy c )
+Read file or directory ACL.
+.It Dv ARCHIVE_ENTRY_ACL_WRITE_ACL ( Sy C )
+Write file or directory ACL.
+.It Dv ARCHIVE_ENTRY_ACL_WRITE_OWNER ( Sy o )
+Change owner of a file or directory.
+.It Dv ARCHIVE_ENTRY_ACL_SYNCHRONIZE ( Sy s )
+Use synchronous I/O.
+.El
+.Pp
+The following NFSv4 ACL inheritance flags are supported:
+.Bl -tag -offset indent -compact -width ARCHIV
+.It Dv ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT ( Sy f )
+Inherit parent directory ACE to files.
+.It Dv ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT ( Sy d )
+Inherit parent directory ACE to subdirectories.
+.It Dv ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY ( Sy i )
+Only inherit, do not apply the permission on the directory itself.
+.It Dv ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT ( Sy n )
+Do not propagate inherit flags. Only first-level entries inherit ACLs.
+.It Dv ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS ( Sy S )
+Trigger alarm or audit on succesful access.
+.It Dv ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS ( Sy F )
+Trigger alarm or audit on failed access.
+.It Dv ARCHIVE_ENTRY_ACL_ENTRY_INHERITED ( Sy I )
+Mark that ACE was inherited.
+.El
+.Ss Functions
.Fn archive_entry_acl_add_entry
and
.Fn archive_entry_acl_add_entry_w
add a single ACL entry.
For the access ACL and non-extended principals, the classic Unix permissions
-are updated.
+are updated. An archive enry cannot contain both POSIX.1e and NFSv4 ACL
+entries.
.Pp
.Fn archive_entry_acl_clear
removes all ACL entries and resets the enumeration pointer.
@@ -153,14 +289,58 @@ removes all ACL entries and resets the enumeration pointer.
counts the ACL entries that have the given type mask.
.Fa type
can be the bitwise-or of
-.Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS
-and
-.Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT .
-If
+.Bl -tag -offset indent -compact -width "ARCHIVE_ENTRY_ACL_TYPE_DEFAULT"
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT
+.El
+for POSIX.1e ACLs and
+.Bl -tag -offset indent -compact -width "ARCHIVE_ENTRY_ACL_TYPE_ALLOW"
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_ALLOW
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_DENY
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_AUDIT
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_ALARM
+.El
+for NFSv4 ACLs. For POSIX.1e ACLs if
.Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS
is included and at least one extended ACL entry is found,
the three non-extened ACLs are added.
.Pp
+.Fn archive_entry_acl_from_text
+and
+.Fn archive_entry_acl_from_text_w
+add new
+.Pq or merge with existing
+ACL entries from
+.Pq wide
+text. The argument
+.Fa type
+may take one of the following values:
+.Bl -tag -offset indent -compact -width "ARCHIVE_ENTRY_ACL_TYPE_DEFAULT"
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_NFS4
+.El
+Supports all formats that can be created with
+.Fn archive_entry_acl_to_text
+or respective
+.Fn archive_entry_acl_to_text_w .
+Existing ACL entries are preserved. To get a clean new ACL from text
+.Fn archive_entry_acl_clear
+must be called first. Entries prefixed with
+.Dq default:
+are treated as
+.Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT
+unless
+.Fa type
+is
+.Dv ARCHIVE_ENTRY_ACL_TYPE_NFS4 .
+Invalid entries, non-parseable ACL entries and entries beginning with
+the
+.Sq #
+character
+.Pq comments
+are skipped.
+.Pp
.Fn archive_entry_acl_next
and
.Fn archive_entry_acl_next_w
@@ -182,19 +362,50 @@ or set using
Otherwise, the function returns the same value as
.Fn archive_entry_acl_count .
.Pp
-.Fn archive_entry_acl_text_w
-converts the ACL entries for the given type mask into a wide string.
-In addition to the normal type flags,
-.Dv ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID
+.Fn archive_entry_acl_to_text
and
-.Dv ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT
-can be specified to further customize the result.
-The returned long string is valid until the next call to
-.Fn archive_entry_acl_clear ,
-.Fn archive_entry_acl_add_entry ,
-.Fn archive_entry_acl_add_entry_w
+.Fn archive_entry_acl_to_text_w
+convert the ACL entries for the given type into a
+.Pq wide
+string of ACL entries separated by newline. If the the pointer
+.Fa len_p
+is not NULL, then the function shall return the length of the string
+.Pq not including the NULL terminator
+in the location pointed to by
+.Fa len_p .
+The
+.Fa flag
+argument is a bitwise-or.
+.Pp
+The following flags are effective only on POSIX.1e ACL:
+.Bl -tag -offset indent -compact -width ARCHIV
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS
+Output access ACLs.
+.It Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT
+Output POSIX.1e default ACLs.
+.It Dv ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT
+Prefix each default ACL entry with the word
+.Dq default: .
+.It Dv ARCHIVE_ENTRY_ACL_STYLE_SOLARIS
+The mask and other ACLs don not contain a double colon.
+.El
+.Pp
+The following flags are effective on both POSIX.1e and NFSv4 ACL:
+.Bl -tag -offset indent -compact -width ARCHIV
+.It Dv ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID
+Add an additional colon-separated field containing the user or group id.
+.It Dv ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA
+Separate ACL entries with comma instead of newline.
+.El
+.Pp
+If the archive entry contains NFSv4 ACLs, all types of NFSv4 ACLs are returned.
+It the entry contains POSIX.1e ACLs and none of the flags
+.Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS
or
-.Fn archive_entry_acl_text_w .
+.Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT
+are specified, both access and default entries are returned and default entries
+are prefixed with
+.Dq default: .
.Pp
.Fn archive_entry_acl_types
get ACL entry types contained in an archive entry's ACL. As POSIX.1e and NFSv4
@@ -205,11 +416,20 @@ an ACL already contains POSIX.1e or NFSv4 ACL entries.
and
.Fn archive_entry_acl_reset
returns the number of ACL entries that match the given type mask.
-If the type mask includes
+For POSIX.1e ACLS if the type mask includes
.Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS
and at least one extended ACL entry exists, the three classic Unix
permissions are counted.
.Pp
+.Fn archive_entry_acl_from_text
+and
+.Fn archive_entry_acl_from_text_w
+return
+.Dv ARCHIVE_OK
+if all entries were successfully parsed and
+.Dv ARCHIVE_WARN
+if one or more entries were invalid or non-parseable.
+.Pp
.Fn archive_entry_acl_next
and
.Fn archive_entry_acl_next_w
@@ -224,23 +444,16 @@ if
.Fn archive_entry_acl_reset
has not been called first.
.Pp
-.Fn archive_entry_text_w
-returns a wide string representation of the ACL entrise matching the
-given type mask.
-The returned long string is valid until the next call to
-.Fn archive_entry_acl_clear ,
-.Fn archive_entry_acl_add_entry ,
-.Fn archive_entry_acl_add_entry_w
-or
-.Fn archive_entry_acl_text_w .
+.Fn archive_entry_acl_to_text
+returns a string representing the ACL entries matching the given type and
+flags on success or NULL on error.
+.Pp
+.Fn archive_entry_acl_to_text_w
+returns a wide string representing the ACL entries matching the given type
+and flags on success or NULL on error.
.Pp
.Fn archive_entry_acl_types
returns a bitmask of ACL entry types or 0 if archive entry has no ACL entries.
.Sh SEE ALSO
-.Xr archive_entry 3
-.Xr libarchive 3 ,
-.Sh BUGS
-.Dv ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID
-and
-.Dv ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT
-are not documented.
+.Xr archive_entry 3 ,
+.Xr libarchive 3
diff --git a/libarchive/archive_entry_locale.h b/libarchive/archive_entry_locale.h
index 02e024ae20c1..c7c90088822d 100644
--- a/libarchive/archive_entry_locale.h
+++ b/libarchive/archive_entry_locale.h
@@ -63,9 +63,14 @@ int _archive_entry_uname_l(struct archive_entry *,
const char **, size_t *, struct archive_string_conv *);
#define archive_entry_acl_text_l _archive_entry_acl_text_l
int _archive_entry_acl_text_l(struct archive_entry *, int,
- const char **, size_t *, struct archive_string_conv *);
-
-
+const char **, size_t *, struct archive_string_conv *)
+__attribute__ ((deprecated));
+#define archive_entry_acl_to_text_l _archive_entry_acl_to_text_l
+char *_archive_entry_acl_to_text_l(struct archive_entry *, ssize_t *, int,
+ struct archive_string_conv *);
+#define archive_entry_acl_from_text_l _archive_entry_acl_from_text_l
+int _archive_entry_acl_from_text_l(struct archive_entry *, const char* text,
+ int type, struct archive_string_conv *);
#define archive_entry_copy_gname_l _archive_entry_copy_gname_l
int _archive_entry_copy_gname_l(struct archive_entry *,
const char *, size_t, struct archive_string_conv *);
diff --git a/libarchive/archive_read_disk_entry_from_file.c b/libarchive/archive_read_disk_entry_from_file.c
index f37bb162a0f0..0a5453c640ba 100644
--- a/libarchive/archive_read_disk_entry_from_file.c
+++ b/libarchive/archive_read_disk_entry_from_file.c
@@ -1,6 +1,7 @@
/*-
* Copyright (c) 2003-2009 Tim Kientzle
* Copyright (c) 2010-2012 Michihiro NAKAJIMA
+ * Copyright (c) 2016 Martin Matuska
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -440,7 +441,7 @@ setup_acls(struct archive_read_disk *a,
acl = NULL;
#ifdef ACL_TYPE_NFS4
- /* Try NFS4 ACL first. */
+ /* Try NFSv4 ACL first. */
if (*fd >= 0)
#if HAVE_ACL_GET_FD_NP
acl = acl_get_fd_np(*fd, ACL_TYPE_NFS4);
diff --git a/libarchive/archive_read_support_format_tar.c b/libarchive/archive_read_support_format_tar.c
index 948929a3d817..b18edcc12029 100644
--- a/libarchive/archive_read_support_format_tar.c
+++ b/libarchive/archive_read_support_format_tar.c
@@ -1,6 +1,7 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* Copyright (c) 2011-2012 Michihiro NAKAJIMA
+ * Copyright (c) 2016 Martin Matuska
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -204,6 +205,10 @@ static int archive_read_format_tar_read_header(struct archive_read *,
static int checksum(struct archive_read *, const void *);
static int pax_attribute(struct archive_read *, struct tar *,
struct archive_entry *, const char *key, const char *value);
+static int pax_attribute_acl(struct archive_read *, struct tar *,
+ struct archive_entry *, const char *, int);
+static int pax_attribute_xattr(struct archive_entry *, const char *,
+ const char *);
static int pax_header(struct archive_read *, struct tar *,
struct archive_entry *, char *attr);
static void pax_time(const char *, int64_t *sec, long *nanos);
@@ -1016,7 +1021,7 @@ header_Solaris_ACL(struct archive_read *a, struct tar *tar,
return (ARCHIVE_FATAL);
}
archive_strncpy(&(tar->localname), acl, p - acl);
- err = archive_acl_parse_l(archive_entry_acl(entry),
+ err = archive_acl_from_text_l(archive_entry_acl(entry),
tar->localname.s, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, tar->sconv_acl);
if (err != ARCHIVE_OK) {
if (errno == ENOMEM) {
@@ -1758,6 +1763,52 @@ pax_attribute_xattr(struct archive_entry *entry,
return 0;
}
+static int
+pax_attribute_acl(struct archive_read *a, struct tar *tar,
+ struct archive_entry *entry, const char *value, int type)
+{
+ int r;
+ const char* errstr;
+
+ switch (type) {
+ case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
+ errstr = "SCHILY.acl.access";
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
+ errstr = "SCHILY.acl.default";
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_NFS4:
+ errstr = "SCHILY.acl.ace";
+ break;
+ default:
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Unknown ACL type: %d", type);
+ return(ARCHIVE_FATAL);
+ }
+
+ if (tar->sconv_acl == NULL) {
+ tar->sconv_acl =
+ archive_string_conversion_from_charset(
+ &(a->archive), "UTF-8", 1);
+ if (tar->sconv_acl == NULL)
+ return (ARCHIVE_FATAL);
+ }
+
+ r = archive_acl_from_text_l(archive_entry_acl(entry), value, type,
+ tar->sconv_acl);
+ if (r != ARCHIVE_OK) {
+ if (r == ARCHIVE_FATAL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "%s %s", "Can't allocate memory for ",
+ errstr);
+ return (r);
+ }
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC, "%s %s", "Parse error: ", errstr);
+ }
+ return (r);
+}
+
/*
* Parse a single key=value attribute. key/value pointers are
* assumed to point into reasonably long-lived storage.
@@ -1874,53 +1925,20 @@ pax_attribute(struct archive_read *a, struct tar *tar,
case 'S':
/* We support some keys used by the "star" archiver */
if (strcmp(key, "SCHILY.acl.access") == 0) {
- if (tar->sconv_acl == NULL) {
- tar->sconv_acl =
- archive_string_conversion_from_charset(
- &(a->archive), "UTF-8", 1);
- if (tar->sconv_acl == NULL)
- return (ARCHIVE_FATAL);
- }
-
- r = archive_acl_parse_l(archive_entry_acl(entry),
- value, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
- tar->sconv_acl);
- if (r != ARCHIVE_OK) {
- err = r;
- if (err == ARCHIVE_FATAL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for "
- "SCHILY.acl.access");
- return (err);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Parse error: SCHILY.acl.access");
- }
+ r = pax_attribute_acl(a, tar, entry, value,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
+ if (r == ARCHIVE_FATAL)
+ return (r);
} else if (strcmp(key, "SCHILY.acl.default") == 0) {
- if (tar->sconv_acl == NULL) {
- tar->sconv_acl =
- archive_string_conversion_from_charset(
- &(a->archive), "UTF-8", 1);
- if (tar->sconv_acl == NULL)
- return (ARCHIVE_FATAL);
- }
-
- r = archive_acl_parse_l(archive_entry_acl(entry),
- value, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT,
- tar->sconv_acl);
- if (r != ARCHIVE_OK) {
- err = r;
- if (err == ARCHIVE_FATAL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for "
- "SCHILY.acl.default");
- return (err);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_MISC,
- "Parse error: SCHILY.acl.default");
- }
+ r = pax_attribute_acl(a, tar, entry, value,
+ ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
+ if (r == ARCHIVE_FATAL)
+ return (r);
+ } else if (strcmp(key, "SCHILY.acl.ace") == 0) {
+ r = pax_attribute_acl(a, tar, entry, value,
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4);
+ if (r == ARCHIVE_FATAL)
+ return (r);
} else if (strcmp(key, "SCHILY.devmajor") == 0) {
archive_entry_set_rdevmajor(entry,
(dev_t)tar_atol10(value, strlen(value)));
diff --git a/libarchive/archive_write_set_format_pax.c b/libarchive/archive_write_set_format_pax.c
index 386d7451d91d..0063d23e1d2a 100644
--- a/libarchive/archive_write_set_format_pax.c
+++ b/libarchive/archive_write_set_format_pax.c
@@ -1,6 +1,7 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
* Copyright (c) 2010-2012 Michihiro NAKAJIMA
+ * Copyright (c) 2016 Martin Matuska
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -70,6 +71,8 @@ static void add_pax_attr_int(struct archive_string *,
static void add_pax_attr_time(struct archive_string *,
const char *key, int64_t sec,
unsigned long nanos);
+static int add_pax_acl(struct archive_write *,
+ struct archive_entry *, struct pax *, int);
static ssize_t archive_write_pax_data(struct archive_write *,
const void *, size_t);
static int archive_write_pax_close(struct archive_write *);
@@ -449,6 +452,45 @@ get_entry_symlink(struct archive_write *a, struct archive_entry *entry,
return (ARCHIVE_OK);
}
+/* Add ACL to pax header */
+static int
+add_pax_acl(struct archive_write *a,
+ struct archive_entry *entry, struct pax *pax, int flags)
+{
+ char *p;
+ const char *attr;
+ int acl_types;
+
+ acl_types = archive_entry_acl_types(entry);
+
+ if ((acl_types & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0)
+ attr = "SCHILY.acl.ace";
+ else if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)
+ attr = "SCHILY.acl.access";
+ else if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0)
+ attr = "SCHILY.acl.default";
+ else
+ return (ARCHIVE_FATAL);
+
+ p = archive_entry_acl_to_text_l(entry, NULL, flags, pax->sconv_utf8);
+ if (p == NULL) {
+ if (errno == ENOMEM) {
+ archive_set_error(&a->archive, ENOMEM, "%s %s",
+ "Can't allocate memory for ", attr);
+ return (ARCHIVE_FATAL);
+ }
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT, "%s %s %s",
+ "Can't translate ", attr, " to UTF-8");
+ return(ARCHIVE_WARN);
+ } else if (*p != '\0') {
+ add_pax_attr(&(pax->pax_header),
+ attr, p);
+ free(p);
+ }
+ return(ARCHIVE_OK);
+}
+
/*
* TODO: Consider adding 'comment' and 'charset' fields to
* archive_entry so that clients can specify them. Also, consider
@@ -465,6 +507,7 @@ archive_write_pax_header(struct archive_write *a,
const char *p;
const char *suffix;
int need_extension, r, ret;
+ int acl_types;
int sparse_count;
uint64_t sparse_total, real_size;
struct pax *pax;
@@ -1016,16 +1059,6 @@ archive_write_pax_header(struct archive_write *a,
if (!need_extension && p != NULL && *p != '\0')
need_extension = 1;
- /* If there are non-trivial ACL entries, we need an extension. */
- if (!need_extension && archive_entry_acl_count(entry_original,
- ARCHIVE_ENTRY_ACL_TYPE_ACCESS) > 0)
- need_extension = 1;
-
- /* If there are non-trivial ACL entries, we need an extension. */
- if (!need_extension && archive_entry_acl_count(entry_original,
- ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) > 0)
- need_extension = 1;
-
/* If there are extended attributes, we need an extension */
if (!need_extension && archive_entry_xattr_count(entry_original) > 0)
need_extension = 1;
@@ -1034,6 +1067,12 @@ archive_write_pax_header(struct archive_write *a,
if (!need_extension && sparse_count > 0)
need_extension = 1;
+ acl_types = archive_entry_acl_types(entry_original);
+
+ /* If there are any ACL entries, we need an extension */
+ if (!need_extension && acl_types != 0)
+ need_extension = 1;
+
/*
* Libarchive used to include these in extended headers for
* restricted pax format, but that confused people who
@@ -1085,43 +1124,28 @@ archive_write_pax_header(struct archive_write *a,
add_pax_attr(&(pax->pax_header), "SCHILY.fflags", p);
/* I use star-compatible ACL attributes. */
- r = archive_entry_acl_text_l(entry_original,
- ARCHIVE_ENTRY_ACL_TYPE_ACCESS |
- ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID,
- &p, NULL, pax->sconv_utf8);
- if (r != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for "
- "ACL.access");
+ if ((acl_types & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) {
+ ret = add_pax_acl(a, entry_original, pax,
+ ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID |
+ ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA);
+ if (ret == ARCHIVE_FATAL)
return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Can't translate ACL.access to UTF-8");
- ret = ARCHIVE_WARN;
- } else if (p != NULL && *p != '\0') {
- add_pax_attr(&(pax->pax_header),
- "SCHILY.acl.access", p);
}
- r = archive_entry_acl_text_l(entry_original,
- ARCHIVE_ENTRY_ACL_TYPE_DEFAULT |
- ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID,
- &p, NULL, pax->sconv_utf8);
- if (r != 0) {
- if (errno == ENOMEM) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate memory for "
- "ACL.default");
+ if (acl_types & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) {
+ ret = add_pax_acl(a, entry_original, pax,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS |
+ ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID |
+ ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA);
+ if (ret == ARCHIVE_FATAL)
+ return (ARCHIVE_FATAL);
+ }
+ if (acl_types & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) {
+ ret = add_pax_acl(a, entry_original, pax,
+ ARCHIVE_ENTRY_ACL_TYPE_DEFAULT |
+ ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID |
+ ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA);
+ if (ret == ARCHIVE_FATAL)
return (ARCHIVE_FATAL);
- }
- archive_set_error(&a->archive,
- ARCHIVE_ERRNO_FILE_FORMAT,
- "Can't translate ACL.default to UTF-8");
- ret = ARCHIVE_WARN;
- } else if (p != NULL && *p != '\0') {
- add_pax_attr(&(pax->pax_header),
- "SCHILY.acl.default", p);
}
/* We use GNU-tar-compatible sparse attributes. */
diff --git a/libarchive/libarchive-formats.5 b/libarchive/libarchive-formats.5
index 9cec760052ee..62359ddc20b0 100644
--- a/libarchive/libarchive-formats.5
+++ b/libarchive/libarchive-formats.5
@@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd March 18, 2012
+.Dd December 27, 2016
.Dt LIBARCHIVE-FORMATS 5
.Os
.Sh NAME
@@ -191,8 +191,6 @@ and device numbers.
.It Solaris extensions
Libarchive recognizes ACL and extended attribute records written
by Solaris tar.
-Currently, libarchive only has support for old-style ACLs; the
-newer NFSv4 ACLs are recognized but discarded.
.El
.Pp
The first tar program appeared in Seventh Edition Unix in 1979.
diff --git a/libarchive/tar.5 b/libarchive/tar.5
index 6e6f0c096c90..c8911a06d5b0 100644
--- a/libarchive/tar.5
+++ b/libarchive/tar.5
@@ -1,4 +1,5 @@
.\" Copyright (c) 2003-2009 Tim Kientzle
+.\" Copyright (c) 2016 Martin Matuska
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
@@ -24,7 +25,7 @@
.\"
.\" $FreeBSD$
.\"
-.Dd December 23, 2011
+.Dd December 27, 2016
.Dt TAR 5
.Os
.Sh NAME
@@ -440,11 +441,11 @@ archives to store files much larger than the historic 8GB limit.
Vendor-specific attributes used by Joerg Schilling's
.Nm star
implementation.
-.It Cm SCHILY.acl.access , Cm SCHILY.acl.default
-Stores the access and default ACLs as textual strings in a format
+.It Cm SCHILY.acl.access , Cm SCHILY.acl.default, .Cm SCHILY.acl.ace
+Stores the access, default and NFSv4 ACLs as textual strings in a format
that is an extension of the format specified by POSIX.1e draft 17.
-In particular, each user or group access specification can include a fourth
-colon-separated field with the numeric UID or GID.
+In particular, each user or group access specification can include
+an additional colon-separated field with the numeric UID or GID.
This allows ACLs to be restored on systems that may not have complete
user or group information available (such as when NIS/YP or LDAP services
are temporarily unavailable).
diff --git a/libarchive/test/CMakeLists.txt b/libarchive/test/CMakeLists.txt
index 3c2671dd08fc..2f0e9e7b3d23 100644
--- a/libarchive/test/CMakeLists.txt
+++ b/libarchive/test/CMakeLists.txt
@@ -14,6 +14,7 @@ IF(ENABLE_TEST)
test_acl_nfs4.c
test_acl_pax.c
test_acl_posix1e.c
+ test_acl_text.c
test_archive_api_feature.c
test_archive_clear_error.c
test_archive_cmdline.c
@@ -62,7 +63,7 @@ IF(ENABLE_TEST)
test_compat_plexus_archiver_tar.c
test_compat_solaris_pax_sparse.c
test_compat_solaris_tar_acl.c
- test_compat_star_acl_posix1e.c
+ test_compat_star_acl.c
test_compat_tar_hardlink.c
test_compat_uudecode.c
test_compat_uudecode_large.c
diff --git a/libarchive/test/main.c b/libarchive/test/main.c
index 3553be6a9926..d59f1552e70d 100644
--- a/libarchive/test/main.c
+++ b/libarchive/test/main.c
@@ -2421,6 +2421,132 @@ extract_reference_files(const char **names)
extract_reference_file(*names++);
}
+/* Set ACLs */
+void
+archive_test_set_acls(struct archive_entry *ae,
+ struct archive_test_acl_t *acls, int n)
+{
+ int i;
+
+ archive_entry_acl_clear(ae);
+ for (i = 0; i < n; i++) {
+ failure("type=%#010x, permset=%#010x, tag=%d, qual=%d name=%s",
+ acls[i].type, acls[i].permset, acls[i].tag,
+ acls[i].qual, acls[i].name);
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_add_entry(ae,
+ acls[i].type, acls[i].permset, acls[i].tag,
+ acls[i].qual, acls[i].name));
+ }
+}
+
+static int
+archive_test_acl_match(struct archive_test_acl_t *acl, int type, int permset,
+ int tag, int qual, const char *name)
+{
+ if (type != acl->type)
+ return (0);
+ if (permset != acl->permset)
+ return (0);
+ if (tag != acl->tag)
+ return (0);
+ if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ)
+ return (1);
+ if (tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ)
+ return (1);
+ if (tag == ARCHIVE_ENTRY_ACL_EVERYONE)
+ return (1);
+ if (tag == ARCHIVE_ENTRY_ACL_OTHER)
+ return (1);
+ if (qual != acl->qual)
+ return (0);
+ if (name == NULL) {
+ if (acl->name == NULL || acl->name[0] == '\0')
+ return (1);
+ return (0);
+ }
+ if (acl->name == NULL) {
+ if (name[0] == '\0')
+ return (1);
+ return (0);
+ }
+ return (0 == strcmp(name, acl->name));
+}
+
+/* Compare ACLs */
+void
+archive_test_compare_acls(struct archive_entry *ae,
+ struct archive_test_acl_t *acls, int cnt, int want_type, int mode)
+{
+ int *marker;
+ int i, r, n;
+ int type, permset, tag, qual;
+ int matched;
+ const char *name;
+
+ n = 0;
+ marker = malloc(sizeof(marker[0]) * cnt);
+
+ for (i = 0; i < cnt; i++) {
+ if ((acls[i].type & want_type) != 0) {
+ marker[n] = i;
+ n++;
+ }
+ }
+
+ failure("No ACL's to compare, type mask: %d", want_type);
+ assert(n > 0);
+ if (n == 0)
+ return;
+
+ while (0 == (r = archive_entry_acl_next(ae, want_type,
+ &type, &permset, &tag, &qual, &name))) {
+ for (i = 0, matched = 0; i < n && !matched; i++) {
+ if (archive_test_acl_match(&acls[marker[i]], type,
+ permset, tag, qual, name)) {
+ /* We found a match; remove it. */
+ marker[i] = marker[n - 1];
+ n--;
+ matched = 1;
+ }
+ }
+ if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS
+ && tag == ARCHIVE_ENTRY_ACL_USER_OBJ) {
+ if (!matched) printf("No match for user_obj perm\n");
+ failure("USER_OBJ permset (%02o) != user mode (%02o)",
+ permset, 07 & (mode >> 6));
+ assert((permset << 6) == (mode & 0700));
+ } else if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS
+ && tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ) {
+ if (!matched) printf("No match for group_obj perm\n");
+ failure("GROUP_OBJ permset %02o != group mode %02o",
+ permset, 07 & (mode >> 3));
+ assert((permset << 3) == (mode & 0070));
+ } else if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS
+ && tag == ARCHIVE_ENTRY_ACL_OTHER) {
+ if (!matched) printf("No match for other perm\n");
+ failure("OTHER permset (%02o) != other mode (%02o)",
+ permset, mode & 07);
+ assert((permset << 0) == (mode & 0007));
+ } else {
+ failure("Could not find match for ACL "
+ "(type=%#010x,permset=%#010x,tag=%d,qual=%d,"
+ "name=``%s'')", type, permset, tag, qual, name);
+ assert(matched == 1);
+ }
+ }
+ assertEqualInt(ARCHIVE_EOF, r);
+ if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)
+ assert((mode_t)(mode & 0777) == (archive_entry_mode(ae)
+ & 0777));
+ failure("Could not find match for ACL "
+ "(type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s'')",
+ acls[marker[0]].type, acls[marker[0]].permset,
+ acls[marker[0]].tag, acls[marker[0]].qual, acls[marker[0]].name);
+ assert(n == 0); /* Number of ACLs not matched should == 0 */
+ free(marker);
+}
+
/*
*
* TEST management
diff --git a/libarchive/test/test.h b/libarchive/test/test.h
index a48c42641e89..71ab1c6b3fe0 100644
--- a/libarchive/test/test.h
+++ b/libarchive/test/test.h
@@ -346,6 +346,23 @@ extern const char *testworkdir;
#include "archive.h"
#include "archive_entry.h"
+/* ACL structure */
+struct archive_test_acl_t {
+ int type; /* Type of ACL */
+ int permset; /* Permissions for this class of users. */
+ int tag; /* Owner, User, Owning group, group, other, etc. */
+ int qual; /* GID or UID of user/group, depending on tag. */
+ const char *name; /* Name of user/group, depending on tag. */
+};
+
+/* Set ACLs */
+void archive_test_set_acls(struct archive_entry *, struct archive_test_acl_t *,
+ int);
+
+/* Compare ACLs */
+void archive_test_compare_acls(struct archive_entry *,
+ struct archive_test_acl_t *, int, int, int);
+
/* Special customized read-from-memory interface. */
int read_open_memory(struct archive *, const void *, size_t, size_t);
/* _minimal version exercises a slightly different set of libarchive APIs. */
diff --git a/libarchive/test/test_acl_freebsd_nfs4.c b/libarchive/test/test_acl_freebsd_nfs4.c
index 89861d6eadf9..4e68623c1722 100644
--- a/libarchive/test/test_acl_freebsd_nfs4.c
+++ b/libarchive/test/test_acl_freebsd_nfs4.c
@@ -334,7 +334,7 @@ compare_acls(acl_t acl, struct myacl_t *myacls, const char *filename, int start,
/* Dump entries in the myacls array that weren't in the system acl. */
for (i = 0; i < n; ++i) {
failure(" ACL entry %d missing from %s: "
- "type=%d,permset=%x,tag=%d,qual=%d,name=``%s''\n",
+ "type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s''\n",
marker[i], filename,
myacls[marker[i]].type, myacls[marker[i]].permset,
myacls[marker[i]].tag, myacls[marker[i]].qual,
@@ -386,7 +386,7 @@ compare_entry_acls(struct archive_entry *ae, struct myacl_t *myacls, const char
}
failure("ACL entry on file that shouldn't be there: "
- "type=%d,permset=%x,tag=%d,qual=%d",
+ "type=%#010x,permset=%#010x,tag=%d,qual=%d",
type,permset,tag,qual);
assert(matched == 1);
}
@@ -394,7 +394,7 @@ compare_entry_acls(struct archive_entry *ae, struct myacl_t *myacls, const char
/* Dump entries in the myacls array that weren't in the system acl. */
for (i = 0; i < n; ++i) {
failure(" ACL entry %d missing from %s: "
- "type=%d,permset=%x,tag=%d,qual=%d,name=``%s''\n",
+ "type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s''\n",
marker[i], filename,
myacls[marker[i]].type, myacls[marker[i]].permset,
myacls[marker[i]].tag, myacls[marker[i]].qual,
diff --git a/libarchive/test/test_acl_freebsd_posix1e.c b/libarchive/test/test_acl_freebsd_posix1e.c
index 2eb0a001cb4f..9d256a9f8790 100644
--- a/libarchive/test/test_acl_freebsd_posix1e.c
+++ b/libarchive/test/test_acl_freebsd_posix1e.c
@@ -28,15 +28,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/test/test_acl_freebsd.c 189427 2009-03-0
#if defined(__FreeBSD__) && __FreeBSD__ > 4
#include <sys/acl.h>
-struct myacl_t {
- int type; /* Type of ACL: "access" or "default" */
- int permset; /* Permissions for this class of users. */
- int tag; /* Owner, User, Owning group, group, other, etc. */
- int qual; /* GID or UID of user/group, depending on tag. */
- const char *name; /* Name of user/group, depending on tag. */
-};
-
-static struct myacl_t acls2[] = {
+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, "" },
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ,
@@ -53,22 +45,8 @@ static struct myacl_t acls2[] = {
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
ARCHIVE_ENTRY_ACL_WRITE | ARCHIVE_ENTRY_ACL_READ | ARCHIVE_ENTRY_ACL_EXECUTE,
ARCHIVE_ENTRY_ACL_MASK, -1, "" },
- { 0, 0, 0, 0, NULL }
};
-static void
-set_acls(struct archive_entry *ae, struct myacl_t *acls)
-{
- int i;
-
- archive_entry_acl_clear(ae);
- for (i = 0; acls[i].name != NULL; i++) {
- archive_entry_acl_add_entry(ae,
- acls[i].type, acls[i].permset, acls[i].tag, acls[i].qual,
- acls[i].name);
- }
-}
-
static int
acl_entry_get_perm(acl_entry_t aclent) {
int permset = 0;
@@ -127,7 +105,7 @@ acl_get_specific_entry(acl_t acl, acl_tag_t requested_tag_type, int requested_ta
#endif
static int
-acl_match(acl_entry_t aclent, struct myacl_t *myacl)
+acl_match(acl_entry_t aclent, struct archive_test_acl_t *myacl)
{
gid_t g, *gp;
uid_t u, *up;
@@ -173,25 +151,20 @@ acl_match(acl_entry_t aclent, struct myacl_t *myacl)
}
static void
-compare_acls(acl_t acl, struct myacl_t *myacls)
+compare_acls(acl_t acl, struct archive_test_acl_t *myacls, int n)
{
int *marker;
int entry_id = ACL_FIRST_ENTRY;
int matched;
- int i, n;
+ int i;
acl_entry_t acl_entry;
/* Count ACL entries in myacls array and allocate an indirect array. */
- for (n = 0; myacls[n].name != NULL; ++n)
- continue;
- if (n) {
- marker = malloc(sizeof(marker[0]) * n);
- if (marker == NULL)
- return;
- for (i = 0; i < n; i++)
- marker[i] = i;
- } else
- marker = NULL;
+ marker = malloc(sizeof(marker[0]) * n);
+ if (marker == NULL)
+ return;
+ for (i = 0; i < n; i++)
+ marker[i] = i;
/*
* Iterate over acls in system acl object, try to match each
@@ -219,7 +192,7 @@ compare_acls(acl_t acl, struct myacl_t *myacls)
/* Dump entries in the myacls array that weren't in the system acl. */
for (i = 0; i < n; ++i) {
failure(" ACL entry missing from file: "
- "type=%d,permset=%d,tag=%d,qual=%d,name=``%s''\n",
+ "type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s''\n",
myacls[marker[i]].type, myacls[marker[i]].permset,
myacls[marker[i]].tag, myacls[marker[i]].qual,
myacls[marker[i]].name);
@@ -291,7 +264,7 @@ DEFINE_TEST(test_acl_freebsd_posix1e_restore)
archive_entry_set_pathname(ae, "test0");
archive_entry_set_mtime(ae, 123456, 7890);
archive_entry_set_size(ae, 0);
- set_acls(ae, acls2);
+ archive_test_set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]));
assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
archive_entry_free(ae);
@@ -304,7 +277,7 @@ DEFINE_TEST(test_acl_freebsd_posix1e_restore)
assertEqualInt(st.st_mtime, 123456);
acl = acl_get_file("test0", ACL_TYPE_ACCESS);
assert(acl != (acl_t)NULL);
- compare_acls(acl, acls2);
+ compare_acls(acl, acls2, sizeof(acls2)/sizeof(acls2[0]));
acl_free(acl);
#endif
}
@@ -332,7 +305,12 @@ DEFINE_TEST(test_acl_freebsd_posix1e_read)
*/
/* Create a test file f1 with acl1 */
- acl1_text = "user::rwx,group::rwx,other::rwx,user:1:rw-,group:15:r-x,mask::rwx";
+ acl1_text = "user::rwx\n"
+ "group::rwx\n"
+ "other::rwx\n"
+ "user:1:rw-\n"
+ "group:15:r-x\n"
+ "mask::rwx";
acl1 = acl_from_text(acl1_text);
assert((void *)acl1 != NULL);
fd = open("f1", O_WRONLY | O_CREAT | O_EXCL, 0777);
@@ -371,7 +349,12 @@ DEFINE_TEST(test_acl_freebsd_posix1e_read)
* to read ACLs, resulting in reading the ACL from a like-named
* file in the wrong directory.
*/
- acl2_text = "user::rwx,group::rwx,other::---,user:1:r--,group:15:r--,mask::rwx";
+ acl2_text = "user::rwx\n"
+ "group::rwx\n"
+ "other::---\n"
+ "user:1:r--\n"
+ "group:15:r--\n"
+ "mask::rwx";
acl2 = acl_from_text(acl2_text);
assert((void *)acl2 != NULL);
fd = open("d/f1", O_WRONLY | O_CREAT | O_EXCL, 0777);
@@ -406,10 +389,10 @@ DEFINE_TEST(test_acl_freebsd_posix1e_read)
while (ARCHIVE_OK == archive_read_next_header2(a, ae)) {
archive_read_disk_descend(a);
if (strcmp(archive_entry_pathname(ae), "./f1") == 0) {
- assertEqualString(archive_entry_acl_text(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS), acl1_text);
+ assertEqualString(archive_entry_acl_to_text(ae, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS), acl1_text);
} else if (strcmp(archive_entry_pathname(ae), "./d/f1") == 0) {
- assertEqualString(archive_entry_acl_text(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS), acl2_text);
+ assertEqualString(archive_entry_acl_to_text(ae, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS), acl2_text);
}
}
diff --git a/libarchive/test/test_acl_nfs4.c b/libarchive/test/test_acl_nfs4.c
index c8f59371a52b..f4e66f52294e 100644
--- a/libarchive/test/test_acl_nfs4.c
+++ b/libarchive/test/test_acl_nfs4.c
@@ -33,15 +33,7 @@ __FBSDID("$FreeBSD$");
* filesystems support ACLs or not.
*/
-struct acl_t {
- int type; /* Type of entry: "allow" or "deny" */
- int permset; /* Permissions for this class of users. */
- int tag; /* Owner, User, Owning group, group, everyone, etc. */
- int qual; /* GID or UID of user/group, depending on tag. */
- const char *name; /* Name of user/group, depending on tag. */
-};
-
-static struct acl_t acls1[] = {
+static struct archive_test_acl_t acls1[] = {
{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
{ ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_READ_DATA,
@@ -52,7 +44,7 @@ static struct acl_t acls1[] = {
ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" },
};
-static struct acl_t acls2[] = {
+static struct archive_test_acl_t acls2[] = {
/* An entry for each type. */
{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, 0,
ARCHIVE_ENTRY_ACL_USER, 108, "user108" },
@@ -136,7 +128,7 @@ static struct acl_t acls2[] = {
* Entries that should be rejected when we attempt to set them
* on an ACL that already has NFS4 entries.
*/
-static struct acl_t acls_bad[] = {
+static struct archive_test_acl_t acls_bad[] = {
/* POSIX.1e ACL types */
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE,
ARCHIVE_ENTRY_ACL_USER, 78, "" },
@@ -156,95 +148,6 @@ static struct acl_t acls_bad[] = {
ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" },
};
-static void
-set_acls(struct archive_entry *ae, struct acl_t *acls, int n)
-{
- int i;
-
- archive_entry_acl_clear(ae);
- for (i = 0; i < n; i++) {
- failure("type=%d, permset=%d, tag=%d, qual=%d name=%s",
- acls[i].type, acls[i].permset, acls[i].tag,
- acls[i].qual, acls[i].name);
- assertEqualInt(ARCHIVE_OK,
- archive_entry_acl_add_entry(ae,
- acls[i].type, acls[i].permset, acls[i].tag,
- acls[i].qual, acls[i].name));
- }
-}
-
-static int
-acl_match(struct acl_t *acl, int type, int permset, int tag, int qual,
- const char *name)
-{
- if (acl == NULL)
- return (0);
- if (type != acl->type)
- return (0);
- if (permset != acl->permset)
- return (0);
- if (tag != acl->tag)
- return (0);
- if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ)
- return (1);
- if (tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ)
- return (1);
- if (tag == ARCHIVE_ENTRY_ACL_EVERYONE)
- return (1);
- if (qual != acl->qual)
- return (0);
- if (name == NULL) {
- if (acl->name == NULL || acl->name[0] == '\0')
- return (1);
- return (0);
- }
- if (acl->name == NULL) {
- if (name[0] == '\0')
- return (1);
- return (0);
- }
- return (0 == strcmp(name, acl->name));
-}
-
-static void
-compare_acls(struct archive_entry *ae, struct acl_t *acls, int n)
-{
- int *marker = malloc(sizeof(marker[0]) * n);
- int i;
- int r;
- int type, permset, tag, qual;
- int matched;
- const char *name;
-
- for (i = 0; i < n; i++)
- marker[i] = i;
-
- while (0 == (r = archive_entry_acl_next(ae,
- ARCHIVE_ENTRY_ACL_TYPE_NFS4,
- &type, &permset, &tag, &qual, &name))) {
- for (i = 0, matched = 0; i < n && !matched; i++) {
- if (acl_match(&acls[marker[i]], type, permset,
- tag, qual, name)) {
- /* We found a match; remove it. */
- marker[i] = marker[n - 1];
- n--;
- matched = 1;
- }
- }
- failure("Could not find match for ACL "
- "(type=%d,permset=%d,tag=%d,qual=%d,name=``%s'')",
- type, permset, tag, qual, name);
- assertEqualInt(1, matched);
- }
- assertEqualInt(ARCHIVE_EOF, r);
- failure("Could not find match for ACL "
- "(type=%d,permset=%d,tag=%d,qual=%d,name=``%s'')",
- acls[marker[0]].type, acls[marker[0]].permset,
- acls[marker[0]].tag, acls[marker[0]].qual, acls[marker[0]].name);
- assertEqualInt(0, n); /* Number of ACLs not matched should == 0 */
- free(marker);
-}
-
DEFINE_TEST(test_acl_nfs4)
{
struct archive_entry *ae;
@@ -256,22 +159,31 @@ DEFINE_TEST(test_acl_nfs4)
archive_entry_set_mode(ae, S_IFREG | 0777);
/* Store and read back some basic ACL entries. */
- set_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]));
+ archive_test_set_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]));
+
+ /* Check that entry contains only NFSv4 types */
+ assert((archive_entry_acl_types(ae) &
+ ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) == 0);
+ assert((archive_entry_acl_types(ae) &
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0);
+
assertEqualInt(4,
archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4));
- compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]));
+ archive_test_compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]),
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4, 0);
/* A more extensive set of ACLs. */
- set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]));
+ archive_test_set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]));
assertEqualInt(32,
archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4));
- compare_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]));
+ archive_test_compare_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]),
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4, 0);
/*
* Check that clearing ACLs gets rid of them all by repeating
* the first test.
*/
- set_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]));
+ archive_test_set_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]));
failure("Basic ACLs shouldn't be stored as extended ACLs");
assertEqualInt(4,
archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4));
@@ -280,9 +192,9 @@ DEFINE_TEST(test_acl_nfs4)
* Different types of malformed ACL entries that should
* fail when added to existing NFS4 ACLs.
*/
- set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]));
+ archive_test_set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]));
for (i = 0; i < (int)(sizeof(acls_bad)/sizeof(acls_bad[0])); ++i) {
- struct acl_t *p = &acls_bad[i];
+ struct archive_test_acl_t *p = &acls_bad[i];
failure("Malformed ACL test #%d", i);
assertEqualInt(ARCHIVE_FAILED,
archive_entry_acl_add_entry(ae,
diff --git a/libarchive/test/test_acl_pax.c b/libarchive/test/test_acl_pax.c
index 5150b11d63b5..8dfa0e031312 100644
--- a/libarchive/test/test_acl_pax.c
+++ b/libarchive/test/test_acl_pax.c
@@ -1,5 +1,6 @@
/*-
* Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2016 Martin Matuska
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -23,11 +24,11 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "test.h"
-__FBSDID("$FreeBSD: head/lib/libarchive/test/test_acl_pax.c 201247 2009-12-30 05:59:21Z kientzle $");
+__FBSDID("$FreeBSD$");
/*
* Exercise the system-independent portion of the ACL support.
- * Check that pax archive can save and restore ACL data.
+ * Check that pax archive can save and restore POSIX.1e ACL data.
*
* This should work on all systems, regardless of whether local
* filesystems support ACLs or not.
@@ -35,15 +36,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/test/test_acl_pax.c 201247 2009-12-30 05
static unsigned char buff[16384];
-struct acl_t {
- int type; /* Type of ACL: "access" or "default" */
- int permset; /* Permissions for this class of users. */
- int tag; /* Owner, User, Owning group, group, other, etc. */
- int qual; /* GID or UID of user/group, depending on tag. */
- const char *name; /* Name of user/group, depending on tag. */
-};
-
-static struct acl_t acls0[] = {
+static struct archive_test_acl_t acls0[] = {
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE,
ARCHIVE_ENTRY_ACL_USER_OBJ, 0, "" },
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ,
@@ -52,7 +45,7 @@ static struct acl_t acls0[] = {
ARCHIVE_ENTRY_ACL_OTHER, 0, "" },
};
-static struct acl_t acls1[] = {
+static struct archive_test_acl_t acls1[] = {
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE,
ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ,
@@ -63,7 +56,7 @@ static struct acl_t acls1[] = {
ARCHIVE_ENTRY_ACL_OTHER, -1, "" },
};
-static struct acl_t acls2[] = {
+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, "" },
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ,
@@ -78,101 +71,149 @@ static struct acl_t acls2[] = {
ARCHIVE_ENTRY_ACL_OTHER, -1, "" },
};
-static void
-set_acls(struct archive_entry *ae, struct acl_t *acls, int n)
-{
- int i;
-
- archive_entry_acl_clear(ae);
- for (i = 0; i < n; i++) {
- archive_entry_acl_add_entry(ae,
- acls[i].type, acls[i].permset, acls[i].tag, acls[i].qual,
- acls[i].name);
- }
-}
+static struct archive_test_acl_t acls3[] = {
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
+ ARCHIVE_ENTRY_ACL_READ_DATA |
+ ARCHIVE_ENTRY_ACL_WRITE_DATA |
+ ARCHIVE_ENTRY_ACL_EXECUTE |
+ 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, 0, "" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
+ ARCHIVE_ENTRY_ACL_READ_DATA |
+ ARCHIVE_ENTRY_ACL_WRITE_DATA |
+ ARCHIVE_ENTRY_ACL_APPEND_DATA |
+ ARCHIVE_ENTRY_ACL_READ_ACL |
+ 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, 0, "" },
+ { 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, 0, "" },
+};
-static int
-acl_match(struct acl_t *acl, int type, int permset, int tag, int qual, const char *name)
-{
- if (type != acl->type)
- return (0);
- if (permset != acl->permset)
- return (0);
- if (tag != acl->tag)
- return (0);
- if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ)
- return (1);
- if (tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ)
- return (1);
- if (tag == ARCHIVE_ENTRY_ACL_OTHER)
- return (1);
- if (qual != acl->qual)
- return (0);
- if (name == NULL)
- return (acl->name == NULL || acl->name[0] == '\0');
- if (acl->name == NULL)
- return (name == NULL || name[0] == '\0');
- return (0 == strcmp(name, acl->name));
-}
+static struct archive_test_acl_t acls4[] = {
+ { 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, 0, "" },
+ { 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_ENTRY_INHERITED,
+ ARCHIVE_ENTRY_ACL_USER, 77, "user77" },
+ { ARCHIVE_ENTRY_ACL_TYPE_DENY,
+ ARCHIVE_ENTRY_ACL_READ_DATA |
+ ARCHIVE_ENTRY_ACL_WRITE_DATA |
+ ARCHIVE_ENTRY_ACL_EXECUTE,
+ ARCHIVE_ENTRY_ACL_USER, 78, "user78" },
+ { 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_READ_NAMED_ATTRS |
+ ARCHIVE_ENTRY_ACL_READ_ACL |
+ ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
+ ARCHIVE_ENTRY_ACL_GROUP_OBJ, 0, "" },
+ { ARCHIVE_ENTRY_ACL_TYPE_DENY,
+ ARCHIVE_ENTRY_ACL_WRITE_DATA |
+ ARCHIVE_ENTRY_ACL_APPEND_DATA |
+ ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES |
+ ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS |
+ ARCHIVE_ENTRY_ACL_WRITE_ACL |
+ ARCHIVE_ENTRY_ACL_WRITE_OWNER,
+ ARCHIVE_ENTRY_ACL_GROUP, 78, "group78" },
+ { 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, 0, "" },
+};
-static void
-compare_acls(struct archive_entry *ae, struct acl_t *acls, int n, int mode)
-{
- int *marker = malloc(sizeof(marker[0]) * n);
- int i;
- int r;
- int type, permset, tag, qual;
- int matched;
- const char *name;
-
- for (i = 0; i < n; i++)
- marker[i] = i;
-
- while (0 == (r = archive_entry_acl_next(ae,
- ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
- &type, &permset, &tag, &qual, &name))) {
- for (i = 0, matched = 0; i < n && !matched; i++) {
- if (acl_match(&acls[marker[i]], type, permset,
- tag, qual, name)) {
- /* We found a match; remove it. */
- marker[i] = marker[n - 1];
- n--;
- matched = 1;
- }
- }
- if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) {
- if (!matched) printf("No match for user_obj perm\n");
- failure("USER_OBJ permset (%02o) != user mode (%02o)",
- permset, 07 & (mode >> 6));
- assert((permset << 6) == (mode & 0700));
- } else if (tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ) {
- if (!matched) printf("No match for group_obj perm\n");
- failure("GROUP_OBJ permset %02o != group mode %02o",
- permset, 07 & (mode >> 3));
- assert((permset << 3) == (mode & 0070));
- } else if (tag == ARCHIVE_ENTRY_ACL_OTHER) {
- if (!matched) printf("No match for other perm\n");
- failure("OTHER permset (%02o) != other mode (%02o)",
- permset, mode & 07);
- assert((permset << 0) == (mode & 0007));
- } else {
- failure("Could not find match for ACL "
- "(type=%d,permset=%d,tag=%d,qual=%d,name=``%s'')",
- type, permset, tag, qual, name);
- assert(matched == 1);
- }
- }
- assertEqualInt(ARCHIVE_EOF, r);
- assert((mode_t)(mode & 0777) == (archive_entry_mode(ae) & 0777));
- failure("Could not find match for ACL "
- "(type=%d,permset=%d,tag=%d,qual=%d,name=``%s'')",
- acls[marker[0]].type, acls[marker[0]].permset,
- acls[marker[0]].tag, acls[marker[0]].qual, acls[marker[0]].name);
- assert(n == 0); /* Number of ACLs not matched should == 0 */
- free(marker);
-}
+static struct archive_test_acl_t acls5[] = {
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
+ ARCHIVE_ENTRY_ACL_READ_DATA |
+ ARCHIVE_ENTRY_ACL_WRITE_DATA |
+ ARCHIVE_ENTRY_ACL_EXECUTE |
+ 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, 0, "" },
+ { 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_READ_NAMED_ATTRS |
+ ARCHIVE_ENTRY_ACL_READ_ACL |
+ ARCHIVE_ENTRY_ACL_WRITE_OWNER |
+ ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
+ ARCHIVE_ENTRY_ACL_USER, 77, "user77" },
+ { ARCHIVE_ENTRY_ACL_TYPE_AUDIT,
+ ARCHIVE_ENTRY_ACL_WRITE_DATA |
+ ARCHIVE_ENTRY_ACL_APPEND_DATA |
+ ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS,
+ ARCHIVE_ENTRY_ACL_USER, 77, "user77" },
+ { 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_READ_NAMED_ATTRS |
+ ARCHIVE_ENTRY_ACL_READ_ACL |
+ ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
+ ARCHIVE_ENTRY_ACL_GROUP_OBJ, 0, "" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALARM,
+ ARCHIVE_ENTRY_ACL_READ_DATA |
+ ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES |
+ ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS |
+ ARCHIVE_ENTRY_ACL_READ_ACL |
+ ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS,
+ ARCHIVE_ENTRY_ACL_GROUP, 78, "group78" },
+ { 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, 0, "" },
+};
-DEFINE_TEST(test_acl_pax)
+DEFINE_TEST(test_acl_pax_posix1e)
{
struct archive *a;
struct archive_entry *ae;
@@ -197,23 +238,23 @@ DEFINE_TEST(test_acl_pax)
archive_entry_set_mode(ae, S_IFREG | 0777);
/* Basic owner/owning group should just update mode bits. */
- set_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]));
+ archive_test_set_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]));
assertA(0 == archive_write_header(a, ae));
/* With any extended ACL entry, we should read back a full set. */
- set_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]));
+ archive_test_set_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]));
assertA(0 == archive_write_header(a, ae));
/* A more extensive set of ACLs. */
- set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]));
+ archive_test_set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]));
assertA(0 == archive_write_header(a, ae));
/*
* Check that clearing ACLs gets rid of them all by repeating
* the first test.
*/
- set_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]));
+ archive_test_set_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]));
assertA(0 == archive_write_header(a, ae));
archive_entry_free(ae);
@@ -227,13 +268,13 @@ DEFINE_TEST(test_acl_pax)
fclose(f);
/* Write out the reference data to a file for manual inspection. */
- extract_reference_file("test_acl_pax.tar");
- reference = slurpfile(&reference_size, "test_acl_pax.tar");
+ extract_reference_file("test_acl_pax_posix1e.tar");
+ reference = slurpfile(&reference_size, "test_acl_pax_posix1e.tar");
/* Assert that the generated data matches the built-in reference data.*/
- failure("Generated pax archive does not match reference; compare 'testout' to 'test_acl_pax.tar' reference file.");
+ failure("Generated pax archive does not match reference; compare 'testout' to 'test_acl_pax_posix1e.tar' reference file.");
assertEqualMem(buff, reference, reference_size);
- failure("Generated pax archive does not match reference; compare 'testout' to 'test_acl_pax.tar' reference file.");
+ failure("Generated pax archive does not match reference; compare 'testout' to 'test_acl_pax_posix1e.tar' reference file.");
assertEqualInt((int)used, reference_size);
free(reference);
@@ -255,15 +296,18 @@ DEFINE_TEST(test_acl_pax)
assertA(0 == archive_read_next_header(a, &ae));
failure("One extended ACL should flag all ACLs to be returned.");
assert(4 == archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
- compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]), 0142);
+ archive_test_compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]),
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0142);
failure("Basic ACLs should set mode to 0142, not %04o",
archive_entry_mode(ae)&0777);
assert((archive_entry_mode(ae) & 0777) == 0142);
/* Third item has pretty extensive ACLs */
assertA(0 == archive_read_next_header(a, &ae));
- assertEqualInt(6, archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
- compare_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]), 0543);
+ assertEqualInt(6, archive_entry_acl_reset(ae,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ archive_test_compare_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]),
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0543);
failure("Basic ACLs should set mode to 0543, not %04o",
archive_entry_mode(ae)&0777);
assert((archive_entry_mode(ae) & 0777) == 0543);
@@ -280,3 +324,93 @@ DEFINE_TEST(test_acl_pax)
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
}
+
+DEFINE_TEST(test_acl_pax_nfs4)
+{
+ struct archive *a;
+ struct archive_entry *ae;
+ size_t used;
+ FILE *f;
+ void *reference;
+ size_t reference_size;
+
+ /* Write an archive to memory. */
+ assert(NULL != (a = archive_write_new()));
+ assertA(0 == archive_write_set_format_pax(a));
+ assertA(0 == archive_write_add_filter_none(a));
+ assertA(0 == archive_write_set_bytes_per_block(a, 1));
+ assertA(0 == archive_write_set_bytes_in_last_block(a, 1));
+ assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &used));
+
+ /* Write a series of files to the archive with different ACL info. */
+
+ /* Create a simple archive_entry. */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_set_pathname(ae, "file");
+ archive_entry_set_mode(ae, S_IFREG | 0777);
+
+ /* NFS4 ACLs mirroring 0754 file mode */
+ archive_test_set_acls(ae, acls3, sizeof(acls3)/sizeof(acls3[0]));
+ assertA(0 == archive_write_header(a, ae));
+
+ /* A more extensive set of NFS4 ACLs. */
+ archive_test_set_acls(ae, acls4, sizeof(acls4)/sizeof(acls4[0]));
+ assertA(0 == archive_write_header(a, ae));
+
+ /* Set with special (audit, alarm) NFS4 ACLs. */
+ archive_test_set_acls(ae, acls5, sizeof(acls5)/sizeof(acls5[0]));
+ assertA(0 == archive_write_header(a, ae));
+
+ archive_entry_free(ae);
+
+ /* Close out the archive. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_write_free(a));
+
+ /* Write out the data we generated to a file for manual inspection. */
+ assert(NULL != (f = fopen("testout", "wb")));
+ assertEqualInt(used, (size_t)fwrite(buff, 1, (unsigned int)used, f));
+ fclose(f);
+
+ /* Write out the reference data to a file for manual inspection. */
+ extract_reference_file("test_acl_pax_nfs4.tar");
+ reference = slurpfile(&reference_size, "test_acl_pax_nfs4.tar");
+
+ /* Assert that the generated data matches the built-in reference data.*/
+ failure("Generated pax archive does not match reference; compare 'testout' to 'test_acl_pax_nfs4.tar' reference file.");
+ assertEqualMem(buff, reference, reference_size);
+ failure("Generated pax archive does not match reference; compare 'testout' to 'test_acl_pax_nfs4.tar' reference file.");
+ assertEqualInt((int)used, reference_size);
+ free(reference);
+
+ /* Read back each entry and check that the ACL data is right. */
+ assert(NULL != (a = archive_read_new()));
+ assertA(0 == archive_read_support_format_all(a));
+ assertA(0 == archive_read_support_filter_all(a));
+ assertA(0 == archive_read_open_memory(a, buff, used));
+
+ /* First item has NFS4 ACLs mirroring file mode */
+ assertA(0 == archive_read_next_header(a, &ae));
+ assertEqualInt(3, archive_entry_acl_reset(ae,
+ ARCHIVE_ENTRY_ACL_TYPE_ALLOW));
+ archive_test_compare_acls(ae, acls3, sizeof(acls3)/sizeof(acls3[0]),
+ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, 0);
+
+ /* Second item has has more fine-grained NFS4 ACLs */
+ assertA(0 == archive_read_next_header(a, &ae));
+ assertEqualInt(6, archive_entry_acl_reset(ae,
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ archive_test_compare_acls(ae, acls4, sizeof(acls4)/sizeof(acls4[0]),
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4, 0);
+
+ /* Third item has has audit and alarm NFS4 ACLs */
+ assertA(0 == archive_read_next_header(a, &ae));
+ assertEqualInt(6, archive_entry_acl_reset(ae,
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ archive_test_compare_acls(ae, acls5, sizeof(acls5)/sizeof(acls5[0]),
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4, 0);
+
+ /* Close the archive. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
diff --git a/libarchive/test/test_acl_pax_nfs4.tar.uu b/libarchive/test/test_acl_pax_nfs4.tar.uu
new file mode 100644
index 000000000000..6a41557ff01a
--- /dev/null
+++ b/libarchive/test/test_acl_pax_nfs4.tar.uu
@@ -0,0 +1,129 @@
+begin 644 test_acl_pax_nfs4.tar
+M4&%X2&5A9&5R+V9I;&4`````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````#`P,#<W-R``,#`P,#`P(``P,#`P,#`@`#`P,#`P,#`P,C`R
+M(#`P,#`P,#`P,#`P(#`Q,C`P,0`@>```````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````!U<W1A<@`P,```````
+M````````````````````````````````````````````````````````````
+M```````````````````P,#`P,#`@`#`P,#`P,"``````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````Q,S`@4T-(24Q9+F%C;"YA8V4];W=N97)`.G)W
+M>'`M+6%!4E=C0V]S.BTM+2TM+2TZ86QL;W<L9W)O=7!`.G)W+7`M+6$M4BUC
+M+2US.BTM+2TM+2TZ86QL;W<L979E<GEO;F5`.G(M+2TM+6$M4BUC+2US.BTM
+M+2TM+2TZ86QL;W<*````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````&9I;&4`````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````````````````````````P
+M,#`W-S<@`#`P,#`P,"``,#`P,#`P(``P,#`P,#`P,#`P,"`P,#`P,#`P,#`P
+M,"`P,3`P,C0`(#``````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````=7-T87(`,#``````````````````````
+M````````````````````````````````````````````````````````````
+M````,#`P,#`P(``P,#`P,#`@````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````4&%X2&5A9&5R+V9I;&4`````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````#`P,#<W-R``,#`P,#`P(``P,#`P,#`@`#`P,#`P
+M,#`P-#`V(#`P,#`P,#`P,#`P(#`Q,C`P-P`@>```````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````````````!U<W1A<@`P
+M,```````````````````````````````````````````````````````````
+M```````````````````````````P,#`P,#`@`#`P,#`P,"``````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````R-C(@4T-(24Q9+F%C;"YA8V4];W=N
+M97)`.G)W+7`M+6%!4E=C0V]S.BTM+2TM+2TZ86QL;W<L=7-E<CIU<V5R-S<Z
+M<BTM+2TM82U2+6,M+7,Z+2TM+2TM23IA;&QO=SHW-RQU<V5R.G5S97(W.#IR
+M=W@M+2TM+2TM+2TM+3HM+2TM+2TM.F1E;GDZ-S@L9W)O=7!`.G)W+7`M+6$M
+M4BUC+2US.BTM+2TM+2TZ86QL;W<L9W)O=7`Z9W)O=7`W.#HM=RUP+2TM02U7
+M+4-O+3HM+2TM+2TM.F1E;GDZ-S@L979E<GEO;F5`.G(M+2TM+6$M4BUC+2US
+M.BTM+2TM+2TZ86QL;W<*````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````````````&9I;&4`
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````P,#`W-S<@`#`P,#`P,"``,#`P,#`P(``P,#`P,#`P,#`P,"`P,#`P
+M,#`P,#`P,"`P,3`P,C0`(#``````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````=7-T87(`,#``````````````
+M````````````````````````````````````````````````````````````
+M````````````,#`P,#`P(``P,#`P,#`@````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````4&%X2&5A9&5R+V9I;&4`````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````#`P,#<W-R``,#`P,#`P(``P,#`P,#`@
+M`#`P,#`P,#`P-#$P(#`P,#`P,#`P,#`P(#`Q,C`P,@`@>```````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````````````````````!U
+M<W1A<@`P,```````````````````````````````````````````````````
+M```````````````````````````````````P,#`P,#`@`#`P,#`P,"``````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````````R-C0@4T-(24Q9+F%C;"YA
+M8V4];W=N97)`.G)W>'`M+6%!4E=C0V]S.BTM+2TM+2TZ86QL;W<L=7-E<CIU
+M<V5R-S<Z<G<M<"TM82U2+6,M;W,Z+2TM+2TM+3IA;&QO=SHW-RQU<V5R.G5S
+M97(W-SHM=RUP+2TM+2TM+2TM+3HM+2TM4RTM.F%U9&ET.C<W+&=R;W5P0#IR
+M=RUP+2UA+5(M8RTM<SHM+2TM+2TM.F%L;&]W+&=R;W5P.F=R;W5P-S@Z<BTM
+M+2TM82U2+6,M+2TZ+2TM+2U&+3IA;&%R;3HW."QE=F5R>6]N94`Z<BTM+2TM
+M82U2+6,M+7,Z+2TM+2TM+3IA;&QO=PH`````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`&9I;&4`````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````P,#`W-S<@`#`P,#`P,"``,#`P,#`P(``P,#`P,#`P,#`P
+M,"`P,#`P,#`P,#`P,"`P,3`P,C0`(#``````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````=7-T87(`,#``````
+M````````````````````````````````````````````````````````````
+M````````````````````,#`P,#`P(``P,#`P,#`@````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+'````````````
+`
+end
diff --git a/libarchive/test/test_acl_pax.tar.uu b/libarchive/test/test_acl_pax_posix1e.tar.uu
index 58d7b62463d4..46cf97599d03 100644
--- a/libarchive/test/test_acl_pax.tar.uu
+++ b/libarchive/test/test_acl_pax_posix1e.tar.uu
@@ -1,4 +1,4 @@
-begin 644 test_acl_pax.tar
+begin 644 test_acl_pax_posix1e.tar
M9FEL90``````````````````````````````````````````````````````
M````````````````````````````````````````````````````````````
M`````````````#`P,#$T,B``,#`P,#`P(``P,#`P,#`@`#`P,#`P,#`P,#`P
diff --git a/libarchive/test/test_acl_posix1e.c b/libarchive/test/test_acl_posix1e.c
index 9984d44188ee..01167dae20b0 100644
--- a/libarchive/test/test_acl_posix1e.c
+++ b/libarchive/test/test_acl_posix1e.c
@@ -27,21 +27,14 @@ __FBSDID("$FreeBSD: src/lib/libarchive/test/test_acl_basic.c,v 1.6 2008/10/19 00
/*
* Exercise the system-independent portion of the ACL support.
- * Check that archive_entry objects can save and restore POSIX.1e-style ACL data.
+ * Check that archive_entry objects can save and restore POSIX.1e-style
+ * ACL data.
*
* This should work on all systems, regardless of whether local
* filesystems support ACLs or not.
*/
-struct acl_t {
- int type; /* Type of ACL: "access" or "default" */
- int permset; /* Permissions for this class of users. */
- int tag; /* Owner, User, Owning group, group, other, etc. */
- int qual; /* GID or UID of user/group, depending on tag. */
- const char *name; /* Name of user/group, depending on tag. */
-};
-
-static struct acl_t acls0[] = {
+static struct archive_test_acl_t acls0[] = {
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE,
ARCHIVE_ENTRY_ACL_USER_OBJ, 0, "" },
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ,
@@ -50,7 +43,7 @@ static struct acl_t acls0[] = {
ARCHIVE_ENTRY_ACL_OTHER, 0, "" },
};
-static struct acl_t acls1[] = {
+static struct archive_test_acl_t acls1[] = {
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE,
ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ,
@@ -61,7 +54,7 @@ static struct acl_t acls1[] = {
ARCHIVE_ENTRY_ACL_OTHER, -1, "" },
};
-static struct acl_t acls2[] = {
+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, "" },
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ,
@@ -80,7 +73,7 @@ static struct acl_t acls2[] = {
* NFS4 entry types; attempts to set these on top of POSIX.1e
* attributes should fail.
*/
-static struct acl_t acls_nfs4[] = {
+static struct archive_test_acl_t acls_nfs4[] = {
/* NFS4 types */
{ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ,
ARCHIVE_ENTRY_ACL_USER, 78, "" },
@@ -104,106 +97,6 @@ static struct acl_t acls_nfs4[] = {
ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
};
-static void
-set_acls(struct archive_entry *ae, struct acl_t *acls, int n)
-{
- int i;
-
- archive_entry_acl_clear(ae);
- for (i = 0; i < n; i++) {
- archive_entry_acl_add_entry(ae,
- acls[i].type, acls[i].permset, acls[i].tag, acls[i].qual,
- acls[i].name);
- }
-}
-
-static int
-acl_match(struct acl_t *acl, int type, int permset, int tag, int qual, const char *name)
-{
- if (type != acl->type)
- return (0);
- if (permset != acl->permset)
- return (0);
- if (tag != acl->tag)
- return (0);
- if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ)
- return (1);
- if (tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ)
- return (1);
- if (tag == ARCHIVE_ENTRY_ACL_OTHER)
- return (1);
- if (qual != acl->qual)
- return (0);
- if (name == NULL) {
- if (acl->name == NULL || acl->name[0] == '\0')
- return (1);
- return (0);
- }
- if (acl->name == NULL) {
- if (name[0] == '\0')
- return (1);
- return (0);
- }
- return (0 == strcmp(name, acl->name));
-}
-
-static void
-compare_acls(struct archive_entry *ae, struct acl_t *acls, int n, int mode)
-{
- int *marker = malloc(sizeof(marker[0]) * n);
- int i;
- int r;
- int type, permset, tag, qual;
- int matched;
- const char *name;
-
- for (i = 0; i < n; i++)
- marker[i] = i;
-
- while (0 == (r = archive_entry_acl_next(ae,
- ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
- &type, &permset, &tag, &qual, &name))) {
- for (i = 0, matched = 0; i < n && !matched; i++) {
- if (acl_match(&acls[marker[i]], type, permset,
- tag, qual, name)) {
- /* We found a match; remove it. */
- marker[i] = marker[n - 1];
- n--;
- matched = 1;
- }
- }
- if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) {
- if (!matched) printf("No match for user_obj perm\n");
- failure("USER_OBJ permset (%02o) != user mode (%02o)",
- permset, 07 & (mode >> 6));
- assert((permset << 6) == (mode & 0700));
- } else if (tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ) {
- if (!matched) printf("No match for group_obj perm\n");
- failure("GROUP_OBJ permset %02o != group mode %02o",
- permset, 07 & (mode >> 3));
- assert((permset << 3) == (mode & 0070));
- } else if (tag == ARCHIVE_ENTRY_ACL_OTHER) {
- if (!matched) printf("No match for other perm\n");
- failure("OTHER permset (%02o) != other mode (%02o)",
- permset, mode & 07);
- assert((permset << 0) == (mode & 0007));
- } else {
- failure("Could not find match for ACL "
- "(type=%d,permset=%d,tag=%d,qual=%d,name=``%s'')",
- type, permset, tag, qual, name);
- assert(matched == 1);
- }
- }
- assertEqualInt(ARCHIVE_EOF, r);
- assert((mode_t)(mode & 0777) == (archive_entry_mode(ae) & 0777));
- failure("Could not find match for ACL "
- "(type=%d,permset=%d,tag=%d,qual=%d,name=``%s'')",
- acls[marker[0]].type, acls[marker[0]].permset,
- acls[marker[0]].tag, acls[marker[0]].qual, acls[marker[0]].name);
- assert(n == 0); /* Number of ACLs not matched should == 0 */
- free(marker);
-}
-
DEFINE_TEST(test_acl_posix1e)
{
struct archive_entry *ae;
@@ -223,7 +116,7 @@ DEFINE_TEST(test_acl_posix1e)
* triggering unnecessary extensions. It's better to identify
* trivial ACLs at the point they are being read from disk.
*/
- set_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]));
+ archive_test_set_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]));
failure("Basic ACLs shouldn't be stored as extended ACLs");
assert(0 == archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
failure("Basic ACLs should set mode to 0142, not %04o",
@@ -232,19 +125,28 @@ DEFINE_TEST(test_acl_posix1e)
/* With any extended ACL entry, we should read back a full set. */
- set_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]));
+ archive_test_set_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]));
failure("One extended ACL should flag all ACLs to be returned.");
+
+ /* Check that entry contains only POSIX.1e types */
+ assert((archive_entry_acl_types(ae) &
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0);
+ assert((archive_entry_acl_types(ae) &
+ ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0);
+
assert(4 == archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
- compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]), 0142);
+ archive_test_compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]),
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0142);
failure("Basic ACLs should set mode to 0142, not %04o",
archive_entry_mode(ae)&0777);
assert((archive_entry_mode(ae) & 0777) == 0142);
/* A more extensive set of ACLs. */
- set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]));
+ archive_test_set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]));
assertEqualInt(6, archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
- compare_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]), 0543);
+ archive_test_compare_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]),
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0543);
failure("Basic ACLs should set mode to 0543, not %04o",
archive_entry_mode(ae)&0777);
assert((archive_entry_mode(ae) & 0777) == 0543);
@@ -253,7 +155,7 @@ DEFINE_TEST(test_acl_posix1e)
* Check that clearing ACLs gets rid of them all by repeating
* the first test.
*/
- set_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]));
+ archive_test_set_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]));
failure("Basic ACLs shouldn't be stored as extended ACLs");
assert(0 == archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
failure("Basic ACLs should set mode to 0142, not %04o",
@@ -264,9 +166,9 @@ DEFINE_TEST(test_acl_posix1e)
* Different types of malformed ACL entries that should
* fail when added to existing POSIX.1e ACLs.
*/
- set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]));
+ archive_test_set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]));
for (i = 0; i < (int)(sizeof(acls_nfs4)/sizeof(acls_nfs4[0])); ++i) {
- struct acl_t *p = &acls_nfs4[i];
+ struct archive_test_acl_t *p = &acls_nfs4[i];
failure("Malformed ACL test #%d", i);
assertEqualInt(ARCHIVE_FAILED,
archive_entry_acl_add_entry(ae,
diff --git a/libarchive/test/test_acl_text.c b/libarchive/test/test_acl_text.c
new file mode 100644
index 000000000000..2781e6ea5663
--- /dev/null
+++ b/libarchive/test/test_acl_text.c
@@ -0,0 +1,456 @@
+/*-
+ * Copyright (c) 2016 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$");
+
+/*
+ * Test converting ACLs to text, both wide and non-wide
+ *
+ * This should work on all systems, regardless of whether local
+ * filesystems support ACLs or not.
+ */
+
+static struct archive_test_acl_t acls0[] = {
+ { ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ ARCHIVE_ENTRY_ACL_EXECUTE |
+ ARCHIVE_ENTRY_ACL_READ |
+ ARCHIVE_ENTRY_ACL_WRITE,
+ ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ ARCHIVE_ENTRY_ACL_EXECUTE |
+ ARCHIVE_ENTRY_ACL_READ,
+ ARCHIVE_ENTRY_ACL_USER, 100, "user100" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0,
+ ARCHIVE_ENTRY_ACL_USER, 1000, "user1000" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ ARCHIVE_ENTRY_ACL_EXECUTE |
+ ARCHIVE_ENTRY_ACL_READ,
+ ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ ARCHIVE_ENTRY_ACL_EXECUTE |
+ ARCHIVE_ENTRY_ACL_READ |
+ ARCHIVE_ENTRY_ACL_WRITE,
+ ARCHIVE_ENTRY_ACL_GROUP, 78, "group78" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ ARCHIVE_ENTRY_ACL_READ |
+ ARCHIVE_ENTRY_ACL_EXECUTE,
+ ARCHIVE_ENTRY_ACL_OTHER, -1, "" },
+ { ARCHIVE_ENTRY_ACL_TYPE_DEFAULT,
+ ARCHIVE_ENTRY_ACL_EXECUTE |
+ ARCHIVE_ENTRY_ACL_READ,
+ ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
+ { ARCHIVE_ENTRY_ACL_TYPE_DEFAULT,
+ ARCHIVE_ENTRY_ACL_EXECUTE |
+ ARCHIVE_ENTRY_ACL_READ,
+ ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
+ { ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, 0,
+ ARCHIVE_ENTRY_ACL_OTHER, -1, "" },
+ { ARCHIVE_ENTRY_ACL_TYPE_DEFAULT,
+ ARCHIVE_ENTRY_ACL_EXECUTE |
+ ARCHIVE_ENTRY_ACL_READ,
+ ARCHIVE_ENTRY_ACL_USER, 101, "user101"},
+ { ARCHIVE_ENTRY_ACL_TYPE_DEFAULT,
+ ARCHIVE_ENTRY_ACL_EXECUTE,
+ ARCHIVE_ENTRY_ACL_GROUP, 79, "group79" },
+};
+
+static struct archive_test_acl_t acls1[] = {
+ { 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_READ_NAMED_ATTRS |
+ ARCHIVE_ENTRY_ACL_READ_ACL |
+ ARCHIVE_ENTRY_ACL_WRITE_OWNER,
+ ARCHIVE_ENTRY_ACL_USER, 77, "user77" },
+ { ARCHIVE_ENTRY_ACL_TYPE_DENY,
+ ARCHIVE_ENTRY_ACL_WRITE_DATA |
+ ARCHIVE_ENTRY_ACL_APPEND_DATA |
+ ARCHIVE_ENTRY_ACL_DELETE_CHILD |
+ ARCHIVE_ENTRY_ACL_DELETE |
+ ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT |
+ ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT |
+ ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY |
+ ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT,
+ ARCHIVE_ENTRY_ACL_USER, 101, "user101" },
+ { 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_ENTRY_INHERITED,
+ ARCHIVE_ENTRY_ACL_GROUP, 78, "group78" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
+ ARCHIVE_ENTRY_ACL_READ_DATA |
+ ARCHIVE_ENTRY_ACL_WRITE_DATA |
+ ARCHIVE_ENTRY_ACL_EXECUTE |
+ 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_USER_OBJ, 0, "" },
+ { 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_READ_NAMED_ATTRS |
+ ARCHIVE_ENTRY_ACL_READ_ACL,
+ ARCHIVE_ENTRY_ACL_GROUP_OBJ, 0, "" },
+ { 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, 0, "" },
+};
+
+const char* acltext[] = {
+ "user::rwx\n"
+ "group::r-x\n"
+ "other::r-x\n"
+ "user:user100:r-x\n"
+ "user:user1000:---\n"
+ "group:group78:rwx\n"
+ "default:user::r-x\n"
+ "default:group::r-x\n"
+ "default:other::---\n"
+ "default:user:user101:r-x\n"
+ "default:group:group79:--x",
+
+ "user::rwx\n"
+ "group::r-x\n"
+ "other::r-x\n"
+ "user:user100:r-x:100\n"
+ "user:user1000:---:1000\n"
+ "group:group78:rwx:78\n"
+ "default:user::r-x\n"
+ "default:group::r-x\n"
+ "default:other::---\n"
+ "default:user:user101:r-x:101\n"
+ "default:group:group79:--x:79",
+
+ "u::rwx\n"
+ "g::r-x\n"
+ "o::r-x\n"
+ "u:user100:r-x:100\n"
+ "u:user1000:---:1000\n"
+ "g:group78:rwx:78\n"
+ "d:user::r-x\n"
+ "d:group::r-x\n"
+ "d:other::---\n"
+ "d:user:user101:r-x:101\n"
+ "d:group:group79:--x:79",
+
+ "user::rwx\n"
+ "group::r-x\n"
+ "other::r-x\n"
+ "user:user100:r-x\n"
+ "user:user1000:---\n"
+ "group:group78:rwx",
+
+ "user::rwx,"
+ "group::r-x,"
+ "other::r-x,"
+ "user:user100:r-x,"
+ "user:user1000:---,"
+ "group:group78:rwx",
+
+ "user::rwx\n"
+ "group::r-x\n"
+ "other::r-x\n"
+ "user:user100:r-x:100\n"
+ "user:user1000:---:1000\n"
+ "group:group78:rwx:78",
+
+ "user::r-x\n"
+ "group::r-x\n"
+ "other::---\n"
+ "user:user101:r-x\n"
+ "group:group79:--x",
+
+ "user::r-x\n"
+ "group::r-x\n"
+ "other::---\n"
+ "user:user101:r-x:101\n"
+ "group:group79:--x:79",
+
+ "default:user::r-x\n"
+ "default:group::r-x\n"
+ "default:other::---\n"
+ "default:user:user101:r-x\n"
+ "default:group:group79:--x",
+
+ "user:user77:rw-p--a-R-c-o-:-------:allow\n"
+ "user:user101:-w-pdD--------:fdin---:deny\n"
+ "group:group78:r-----a-R-c---:------I:allow\n"
+ "owner@:rwxp--aARWcCo-:-------:allow\n"
+ "group@:rw-p--a-R-c---:-------:allow\n"
+ "everyone@:r-----a-R-c--s:-------:allow",
+
+ "user:user77:rw-p--a-R-c-o-:-------:allow:77\n"
+ "user:user101:-w-pdD--------:fdin---:deny:101\n"
+ "group:group78:r-----a-R-c---:------I:allow:78\n"
+ "owner@:rwxp--aARWcCo-:-------:allow\n"
+ "group@:rw-p--a-R-c---:-------:allow\n"
+ "everyone@:r-----a-R-c--s:-------:allow"
+};
+
+static wchar_t *
+convert_s_to_ws(const char *s)
+{
+ size_t len;
+ wchar_t *ws = NULL;
+
+ if (s != NULL) {
+ len = strlen(s) + 1;
+ ws = malloc(len * sizeof(wchar_t));
+ assert(mbstowcs(ws, s, len) != (size_t)-1);
+ }
+
+ return (ws);
+}
+
+static void
+compare_acl_text(struct archive_entry *ae, int flags, const char *s)
+{
+ const char *text;
+ const wchar_t *wtext;
+ wchar_t *ws;
+ ssize_t slen;
+
+ ws = convert_s_to_ws(s);
+
+ text = archive_entry_acl_to_text(ae, &slen, flags);
+ assertEqualString(text, s);
+ if (text != NULL)
+ assertEqualInt(strlen(text), slen);
+ wtext = archive_entry_acl_to_text_w(ae, &slen, flags);
+ assertEqualWString(wtext, ws);
+ if (wtext != NULL) {
+ assertEqualInt(wcslen(wtext), slen);
+ free(ws);
+ ws = NULL;
+ }
+}
+
+DEFINE_TEST(test_acl_from_text)
+{
+ struct archive_entry *ae;
+ wchar_t *ws = NULL;
+
+ /* Create an empty archive_entry. */
+ assert((ae = archive_entry_new()) != NULL);
+
+ /* 1a. Read POSIX.1e access ACLs from text */
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text(ae, acltext[5],
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0755);
+ assertEqualInt(6, archive_entry_acl_reset(ae,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+
+ /* 1b. Now read POSIX.1e default ACLs and append them */
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text(ae, acltext[7],
+ ARCHIVE_ENTRY_ACL_TYPE_DEFAULT));
+ archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
+ ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, 0755);
+ assertEqualInt(11, archive_entry_acl_reset(ae,
+ ARCHIVE_ENTRY_ACL_TYPE_POSIX1E));
+ archive_entry_acl_clear(ae);
+
+ /* 1a and 1b with wide strings */
+ ws = convert_s_to_ws(acltext[5]);
+
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text_w(ae, ws,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0755);
+ assertEqualInt(6, archive_entry_acl_reset(ae,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+
+ free(ws);
+ ws = convert_s_to_ws(acltext[7]);
+
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text_w(ae, ws,
+ ARCHIVE_ENTRY_ACL_TYPE_DEFAULT));
+ archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
+ ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, 0755);
+ assertEqualInt(11, archive_entry_acl_reset(ae,
+ ARCHIVE_ENTRY_ACL_TYPE_POSIX1E));
+ archive_entry_acl_clear(ae);
+
+ /* 2. Read POSIX.1e default ACLs from text */
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text(ae, acltext[7],
+ ARCHIVE_ENTRY_ACL_TYPE_DEFAULT));
+ archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
+ ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, 0);
+ assertEqualInt(5, archive_entry_acl_reset(ae,
+ ARCHIVE_ENTRY_ACL_TYPE_DEFAULT));
+ archive_entry_acl_clear(ae);
+
+ /* ws is still acltext[7] */
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text_w(ae, ws,
+ ARCHIVE_ENTRY_ACL_TYPE_DEFAULT));
+ archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
+ ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, 0);
+ assertEqualInt(5, archive_entry_acl_reset(ae,
+ ARCHIVE_ENTRY_ACL_TYPE_DEFAULT));
+ archive_entry_acl_clear(ae);
+
+ /* 3. Read POSIX.1e access and default ACLs from text */
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text(ae, acltext[1],
+ ARCHIVE_ENTRY_ACL_TYPE_POSIX1E));
+ archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
+ ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, 0755);
+ assertEqualInt(11, archive_entry_acl_reset(ae,
+ ARCHIVE_ENTRY_ACL_TYPE_POSIX1E));
+ archive_entry_acl_clear(ae);
+
+ free(ws);
+ ws = convert_s_to_ws(acltext[1]);
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text_w(ae, ws,
+ ARCHIVE_ENTRY_ACL_TYPE_POSIX1E));
+ archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
+ ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, 0755);
+ assertEqualInt(11, archive_entry_acl_reset(ae,
+ ARCHIVE_ENTRY_ACL_TYPE_POSIX1E));
+ archive_entry_acl_clear(ae);
+
+ /* 4. Read POSIX.1e access and default ACLs from text (short form) */
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text(ae, acltext[2],
+ ARCHIVE_ENTRY_ACL_TYPE_POSIX1E));
+ archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
+ ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, 0755);
+ assertEqualInt(11, archive_entry_acl_reset(ae,
+ ARCHIVE_ENTRY_ACL_TYPE_POSIX1E));
+ archive_entry_acl_clear(ae);
+
+ free(ws);
+ ws = convert_s_to_ws(acltext[2]);
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text_w(ae, ws,
+ ARCHIVE_ENTRY_ACL_TYPE_POSIX1E));
+ archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
+ ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, 0755);
+ assertEqualInt(11, archive_entry_acl_reset(ae,
+ ARCHIVE_ENTRY_ACL_TYPE_POSIX1E));
+ archive_entry_acl_clear(ae);
+
+ /* 5. Read NFSv4 ACLs from text */
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text(ae, acltext[10],
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ archive_test_compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]),
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4, 0);
+ assertEqualInt(6, archive_entry_acl_reset(ae,
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ archive_entry_acl_clear(ae);
+
+ free(ws);
+ ws = convert_s_to_ws(acltext[10]);
+
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_from_text_w(ae, ws,
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ archive_test_compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]),
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4, 0);
+ assertEqualInt(6, archive_entry_acl_reset(ae,
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ archive_entry_acl_clear(ae);
+}
+
+DEFINE_TEST(test_acl_to_text)
+{
+ struct archive_entry *ae;
+
+ /* Create an empty archive_entry. */
+ assert((ae = archive_entry_new()) != NULL);
+
+ /* Write POSIX.1e ACLs */
+ archive_test_set_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]));
+
+ /* No flags should give output like getfacl(1) on linux */
+ compare_acl_text(ae, 0, acltext[0]);
+
+ /* This should give the same output as previous test */
+ compare_acl_text(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS |
+ ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, acltext[0]);
+
+ /* This should give the same output as previous two tests */
+ compare_acl_text(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS |
+ ARCHIVE_ENTRY_ACL_TYPE_DEFAULT |
+ ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT, acltext[0]);
+
+ /* POSIX.1e access and default ACLs with appended ID */
+ compare_acl_text(ae, ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID, acltext[1]);
+
+ /* POSIX.1e access acls only, like getfacl(1) on FreeBSD */
+ compare_acl_text(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, acltext[3]);
+
+ /* POSIX.1e access acls separated with comma */
+ compare_acl_text(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS |
+ ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA,
+ acltext[4]);
+
+ /* POSIX.1e access acls with appended user or group ID */
+ compare_acl_text(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS |
+ ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID, acltext[5]);
+
+ /* POSIX.1e default acls */
+ compare_acl_text(ae, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, acltext[6]);
+
+ /* POSIX.1e default acls with appended user or group ID */
+ compare_acl_text(ae, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT |
+ ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID, acltext[7]);
+
+ /* POSIX.1e default acls prefixed with default: */
+ compare_acl_text(ae, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT |
+ ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT, acltext[8]);
+
+ /* Write NFSv4 ACLs */
+ archive_test_set_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]));
+
+ /* NFSv4 ACLs like getfacl(1) on FreeBSD */
+ compare_acl_text(ae, 0, acltext[9]);
+
+ /* NFSv4 ACLs like "getfacl -i" on FreeBSD */
+ compare_acl_text(ae, ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID, acltext[10]);
+}
diff --git a/libarchive/test/test_compat_star_acl.c b/libarchive/test/test_compat_star_acl.c
new file mode 100644
index 000000000000..f2a78b2d2ce4
--- /dev/null
+++ b/libarchive/test/test_compat_star_acl.c
@@ -0,0 +1,321 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2016 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$");
+
+/*
+ * Verify reading entries with POSIX.1e and NFSv4 ACLs from archives created
+ * by star.
+ *
+ * This should work on all systems, regardless of whether local filesystems
+ * support ACLs or not.
+ */
+
+static struct archive_test_acl_t acls0[] = {
+ { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE,
+ ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ,
+ ARCHIVE_ENTRY_ACL_USER, -1, "user77" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ,
+ ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ,
+ ARCHIVE_ENTRY_ACL_MASK, -1, ""},
+ { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_WRITE,
+ ARCHIVE_ENTRY_ACL_OTHER, -1, "" },
+};
+
+static struct archive_test_acl_t acls1[] = {
+ { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE | ARCHIVE_ENTRY_ACL_READ,
+ ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ,
+ ARCHIVE_ENTRY_ACL_USER, -1, "user77" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0,
+ ARCHIVE_ENTRY_ACL_USER, -1, "user78" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ,
+ ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0007,
+ ARCHIVE_ENTRY_ACL_GROUP, -1, "group78" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0007,
+ ARCHIVE_ENTRY_ACL_MASK, -1, ""},
+ { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_WRITE | ARCHIVE_ENTRY_ACL_EXECUTE,
+ ARCHIVE_ENTRY_ACL_OTHER, -1, "" },
+};
+
+static struct archive_test_acl_t acls2[] = {
+ { ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_EXECUTE,
+ ARCHIVE_ENTRY_ACL_USER_OBJ, -1 ,"" },
+ { ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_READ,
+ ARCHIVE_ENTRY_ACL_USER, -1, "user77" },
+ { ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_READ,
+ ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
+ { ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_EXECUTE,
+ ARCHIVE_ENTRY_ACL_GROUP, -1, "group78" },
+ { ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_READ | ARCHIVE_ENTRY_ACL_EXECUTE,
+ ARCHIVE_ENTRY_ACL_MASK, -1, ""},
+ { ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_WRITE,
+ ARCHIVE_ENTRY_ACL_OTHER, -1, "" },
+};
+
+static struct archive_test_acl_t acls3[] = {
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
+ ARCHIVE_ENTRY_ACL_READ_DATA |
+ ARCHIVE_ENTRY_ACL_WRITE_DATA |
+ ARCHIVE_ENTRY_ACL_EXECUTE |
+ 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, 0, "" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
+ ARCHIVE_ENTRY_ACL_READ_DATA |
+ ARCHIVE_ENTRY_ACL_WRITE_DATA |
+ ARCHIVE_ENTRY_ACL_APPEND_DATA |
+ ARCHIVE_ENTRY_ACL_READ_ACL |
+ 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, 0, "" },
+ { 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, 0, "" },
+};
+
+static struct archive_test_acl_t acls4[] = {
+ { 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, 0, "" },
+ { 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_ENTRY_INHERITED,
+ ARCHIVE_ENTRY_ACL_USER, 77, "user77" },
+ { ARCHIVE_ENTRY_ACL_TYPE_DENY,
+ ARCHIVE_ENTRY_ACL_READ_DATA |
+ ARCHIVE_ENTRY_ACL_WRITE_DATA |
+ ARCHIVE_ENTRY_ACL_EXECUTE,
+ ARCHIVE_ENTRY_ACL_USER, 78, "user78" },
+ { 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_READ_NAMED_ATTRS |
+ ARCHIVE_ENTRY_ACL_READ_ACL |
+ ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
+ ARCHIVE_ENTRY_ACL_GROUP_OBJ, 0, "" },
+ { ARCHIVE_ENTRY_ACL_TYPE_DENY,
+ ARCHIVE_ENTRY_ACL_WRITE_DATA |
+ ARCHIVE_ENTRY_ACL_APPEND_DATA |
+ ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES |
+ ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS |
+ ARCHIVE_ENTRY_ACL_WRITE_ACL |
+ ARCHIVE_ENTRY_ACL_WRITE_OWNER,
+ ARCHIVE_ENTRY_ACL_GROUP, 78, "group78" },
+ { 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, 0, "" },
+};
+
+static struct archive_test_acl_t acls5[] = {
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
+ ARCHIVE_ENTRY_ACL_READ_DATA |
+ ARCHIVE_ENTRY_ACL_WRITE_DATA |
+ ARCHIVE_ENTRY_ACL_EXECUTE |
+ 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, 0, "" },
+ { 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_ENTRY_FILE_INHERIT |
+ ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT,
+ ARCHIVE_ENTRY_ACL_USER, 77, "user77" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
+ ARCHIVE_ENTRY_ACL_READ_DATA |
+ ARCHIVE_ENTRY_ACL_WRITE_DATA |
+ ARCHIVE_ENTRY_ACL_EXECUTE |
+ 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_SYNCHRONIZE,
+ ARCHIVE_ENTRY_ACL_GROUP_OBJ, 0, "" },
+ { ARCHIVE_ENTRY_ACL_TYPE_DENY,
+ ARCHIVE_ENTRY_ACL_READ_DATA |
+ ARCHIVE_ENTRY_ACL_WRITE_DATA |
+ ARCHIVE_ENTRY_ACL_APPEND_DATA |
+ ARCHIVE_ENTRY_ACL_EXECUTE |
+ ARCHIVE_ENTRY_ACL_DELETE |
+ ARCHIVE_ENTRY_ACL_DELETE_CHILD |
+ 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_ENTRY_FILE_INHERIT |
+ ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT,
+ ARCHIVE_ENTRY_ACL_GROUP, 78, "group78" },
+ { 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_EVERYONE, 0, "" },
+};
+
+DEFINE_TEST(test_compat_star_acl_posix1e)
+{
+ char name[] = "test_compat_star_acl_posix1e.tar";
+ struct archive *a;
+ struct archive_entry *ae;
+
+ /* Read archive file */
+ assert(NULL != (a = archive_read_new()));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ extract_reference_file(name);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, name,
+ 10240));
+
+ /* First item has a few ACLs */
+ assertA(0 == archive_read_next_header(a, &ae));
+ failure("One extended ACL should flag all ACLs to be returned.");
+ assertEqualInt(5, archive_entry_acl_reset(ae,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]),
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0142);
+ failure("Basic ACLs should set mode to 0142, not %04o",
+ archive_entry_mode(ae)&0777);
+ assert((archive_entry_mode(ae) & 0777) == 0142);
+
+ /* Second item has pretty extensive ACLs */
+ assertA(0 == archive_read_next_header(a, &ae));
+ assertEqualInt(7, archive_entry_acl_reset(ae,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ archive_test_compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]),
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0543);
+ failure("Basic ACLs should set mode to 0543, not %04o",
+ archive_entry_mode(ae)&0777);
+ assert((archive_entry_mode(ae) & 0777) == 0543);
+
+ /* Third item has default ACLs */
+ assertA(0 == archive_read_next_header(a, &ae));
+ assertEqualInt(6, archive_entry_acl_reset(ae,
+ ARCHIVE_ENTRY_ACL_TYPE_DEFAULT));
+ archive_test_compare_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]),
+ ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, 0142);
+ failure("Basic ACLs should set mode to 0142, not %04o",
+ archive_entry_mode(ae)&0777);
+ assert((archive_entry_mode(ae) & 0777) == 0142);
+
+ /* Close the archive. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
+
+DEFINE_TEST(test_compat_star_acl_nfs4)
+{
+ char name[] = "test_compat_star_acl_nfs4.tar";
+ struct archive *a;
+ struct archive_entry *ae;
+
+ /* Read archive file */
+ assert(NULL != (a = archive_read_new()));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+ extract_reference_file(name);
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, name, 10240
+));
+
+ /* First item has NFS4 ACLs mirroring file mode */
+ assertA(0 == archive_read_next_header(a, &ae));
+ assertEqualInt(3, archive_entry_acl_reset(ae,
+ ARCHIVE_ENTRY_ACL_TYPE_ALLOW));
+ archive_test_compare_acls(ae, acls3, sizeof(acls3)/sizeof(acls3[0]),
+ ARCHIVE_ENTRY_ACL_TYPE_ALLOW, 0);
+
+ /* Second item has has fine-grained NFS4 ACLs */
+ assertA(0 == archive_read_next_header(a, &ae));
+ assertEqualInt(6, archive_entry_acl_reset(ae,
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ archive_test_compare_acls(ae, acls4, sizeof(acls4)/sizeof(acls0[4]),
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4, 0);
+
+ /* Third item has file and directory inheritance NFS4 ACLs */
+ assertA(0 == archive_read_next_header(a, &ae));
+ assertEqualInt(5, archive_entry_acl_reset(ae,
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ archive_test_compare_acls(ae, acls5, sizeof(acls5)/sizeof(acls5[0]),
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4, 0);
+
+ /* Close the archive. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
diff --git a/libarchive/test/test_compat_star_acl_nfs4.tar.uu b/libarchive/test/test_compat_star_acl_nfs4.tar.uu
new file mode 100644
index 000000000000..79b228e4dd33
--- /dev/null
+++ b/libarchive/test/test_compat_star_acl_nfs4.tar.uu
@@ -0,0 +1,231 @@
+begin 644 test_compat_star_acl_nfs4.tar
+M+B\N+T!087A(96%D97(`````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````#`P,#`V,#`@,#`P,#`P,"`P,#`P,#`P(#`P,#`P,#`P,C<R
+M(#`P,#`P,#`P,#`P(#`P,38P-S0@9P``````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````!U<W1A<@`P,')O;W0`
+M````````````````````````````````````=VAE96P`````````````````
+M```````````````````P,#`P,#`P(#`P,#`P,#`@````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````````````````P,#`P,#`P,#`P,"`P,#`P,#`P
+M,#`P,"`````````````````U-R!30TA)3%DN<F5L96%S93US=&%R(#$N-2XS
+M("AA;60V-"UU;FMN;W=N+69R965B<V0Q,2XP*0HR-R!30TA)3%DN87)C:'1Y
+M<&4]97AU<W1A<@HT-R!30TA)3%DN=F]L:&1R+F1U;7!D871E/3$T-SDQ-C<W
+M,C<N,38W,C(U,C@Q"C(U(%-#2$E,62YV;VQH9'(N=F]L;F\],0HS,"!30TA)
+M3%DN=F]L:&1R+F)L;V-K<VEZ93TR,`H`````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````````````````````"XO+B]`4&%X2&5A
+M9&5R````````````````````````````````````````````````````````
+M```````````````````````````````````````````````````````````P
+M,#`P-C`P(#`P,#`P,#`@,#`P,#`P,"`P,#`P,#`P,#,S-"`P,#`P,#`P,#`P
+M,"`P,#$V,3$T('@`````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````=7-T87(`,#!R;V]T````````````````
+M`````````````````````'=H965L````````````````````````````````
+M````,#`P,#`P,"`P,#`P,#`P(```````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````,#`P,#`P,#`P,#`@,#`P,#`P,#`P,#`@````````
+M````````,S`@871I;64],30W.3$Q.34U-"XP-#,U-#DP,#`*,S`@8W1I;64]
+M,30W.3$Q.3DQ,BXY,SDQ-C@P,#`*,S`@;71I;64],30W.3$Q.34U-"XP-#,U
+M-#DP,#`*,3,P(%-#2$E,62YA8VPN86-E/6]W;F5R0#IR=WAP+2UA05)78T-O
+M<SHM+2TM+2TM.F%L;&]W+&=R;W5P0#IR=RUP+2UA+5(M8RTM<SHM+2TM+2TM
+M.F%L;&]W+&5V97)Y;VYE0#IR+2TM+2UA+5(M8RTM<SHM+2TM+2TM.F%L;&]W
+M"@``````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````!F:6QE,0``````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````,#`P,#<V-"`P,#`P
+M,#`P(#`P,#`P,#`@,#`P,#`P,#`P,#`@,3,P,3(S,3$S,#(@,#`Q-#8S-B`P
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````'5S=&%R`#`P<F]O=```````````````````````````````
+M``````!W:&5E;````````````````````````````````````#`P,#`P,#`@
+M,#`P,#`P,"``````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````#$S,#$R,S$Q,S`R(#$S,#$R,S$R,#4P(````````````````"XO+B]`
+M4&%X2&5A9&5R````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````P,#`P-C`P(#`P,#`P,#`@,#`P,#`P,"`P,#`P,#`P,#4T,"`P,#`P
+M,#`P,#`P,"`P,#$V,3$S('@`````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````=7-T87(`,#!R;V]T````````
+M`````````````````````````````'=H965L````````````````````````
+M````````````,#`P,#`P,"`P,#`P,#`P(```````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````,#`P,#`P,#`P,#`@,#`P,#`P,#`P,#`@
+M````````````````,S`@871I;64],30W.3$Q.34U-2XR-C<P,3@P,#`*,S`@
+M8W1I;64],30W.3$V,34Y."XY,SDV-#8P,#`*,S`@;71I;64],30W.3$Q.34U
+M-2XR-C<P,3@P,#`*,C8R(%-#2$E,62YA8VPN86-E/75S97(Z=7-E<C<X.G)W
+M>"TM+2TM+2TM+2TM.BTM+2TM+2TZ9&5N>3HW."QG<F]U<#IG<F]U<#<X.BUW
+M+7`M+2U!+5<M0V\M.BTM+2TM+2TZ9&5N>3HW."QU<V5R.G5S97(W-SIR+2TM
+M+2UA+5(M8RTM<SHM+2TM+2U).F%L;&]W.C<W+&]W;F5R0#IR=RUP+2UA05)7
+M8T-O<SHM+2TM+2TM.F%L;&]W+&=R;W5P0#IR=RUP+2UA+5(M8RTM<SHM+2TM
+M+2TM.F%L;&]W+&5V97)Y;VYE0#IR+2TM+2UA+5(M8RTM<SHM+2TM+2TM.F%L
+M;&]W"@``````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````!F:6QE,@``````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````,#`P,#8V
+M-"`P,#`P,#`P(#`P,#`P,#`@,#`P,#`P,#`P,#`@,3,P,3(S,3$S,#,@,#`Q
+M-#8U-R`P````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````'5S=&%R`#`P<F]O=```````````````````````
+M``````````````!W:&5E;````````````````````````````````````#`P
+M,#`P,#`@,#`P,#`P,"``````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````#$S,#$R,S$Q,S`S(#$S,#$R-#,S,S<V(```````````````
+M`"XO+B]`4&%X2&5A9&5R````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````P,#`P-C`P(#`P,#`P,#`@,#`P,#`P,"`P,#`P,#`P,#0V
+M-2`P,#`P,#`P,#`P,"`P,#$V,3(Q('@`````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````=7-T87(`,#!R;V]T
+M`````````````````````````````````````'=H965L````````````````
+M````````````````````,#`P,#`P,"`P,#`P,#`P(```````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````,#`P,#`P,#`P,#`@,#`P,#`P
+M,#`P,#`@````````````````,S`@871I;64],30W.3$V-S0Y-2XV.#<X-C8P
+M,#`*,S`@8W1I;64],30W.3$V-S<R,RXT-#`X-C<P,#`*,S`@;71I;64],30W
+M.3$R,#8W."XT-#$U.#`P,#`*,C$Y(%-#2$E,62YA8VPN86-E/6=R;W5P.F=R
+M;W5P-S@Z<G=X<$1D84%25V-#;W,Z9F0M+2TM+3ID96YY.C<X+'5S97(Z=7-E
+M<C<W.G(M+2TM+6$M4BUC+2US.F9D+2TM+2TZ86QL;W<Z-S<L;W=N97)`.G)W
+M>'`M+6%!4E=C0V]S.BTM+2TM+2TZ86QL;W<L9W)O=7!`.G)W>'`M+6%!4E=C
+M+2US.BTM+2TM+2TZ86QL;W<L979E<GEO;F5`.G(M>"TM+6$M4BUC+2US.BTM
+M+2TM+2TZ86QL;W<*````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````````!D:7(Q+P``````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M,#`P,#<W-2`P,#`P,#`P(#`P,#`P,#`@,#`P,#`P,#`P,#`@,3,P,3(S,3,T
+M-#8@,#`Q-#8S,2`U````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````````````'5S=&%R`#`P<F]O=```````````````
+M``````````````````````!W:&5E;```````````````````````````````
+M`````#`P,#`P,#`@,#`P,#`P,"``````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````````````#$S,#$R-#0W,#`W(#$S,#$R-#0W,S4S(```````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+9````````````````````````````````````
+`
+end
diff --git a/libarchive/test/test_compat_star_acl_posix1e.c b/libarchive/test/test_compat_star_acl_posix1e.c
deleted file mode 100644
index 10bffd9cd1c6..000000000000
--- a/libarchive/test/test_compat_star_acl_posix1e.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/*-
- * Copyright (c) 2003-2007 Tim Kientzle
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-#include "test.h"
-__FBSDID("$FreeBSD$");
-
-/*
- * Verify reading entries with POSIX.1e ACLs from archives created by star
- *
- * This should work on all systems, regardless of whether local filesystems
- * support ACLs or not.
- */
-
-struct acl_t {
- int type; /* Type of ACL: "access" or "default" */
- int permset; /* Permissions for this class of users. */
- int tag; /* Owner, User, Owning group, group, other, etc. */
- const char *name; /* Name of user/group, depending on tag. */
-};
-
-static struct acl_t acls0[] = {
- { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE,
- ARCHIVE_ENTRY_ACL_USER_OBJ, "" },
- { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ,
- ARCHIVE_ENTRY_ACL_USER, "user77" },
- { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ,
- ARCHIVE_ENTRY_ACL_GROUP_OBJ, "" },
- { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ,
- ARCHIVE_ENTRY_ACL_MASK, ""},
- { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_WRITE,
- ARCHIVE_ENTRY_ACL_OTHER, "" },
-};
-
-static struct acl_t acls1[] = {
- { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE | ARCHIVE_ENTRY_ACL_READ,
- ARCHIVE_ENTRY_ACL_USER_OBJ, "" },
- { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ,
- ARCHIVE_ENTRY_ACL_USER, "user77" },
- { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0,
- ARCHIVE_ENTRY_ACL_USER, "user78" },
- { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ,
- ARCHIVE_ENTRY_ACL_GROUP_OBJ, "" },
- { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0007,
- ARCHIVE_ENTRY_ACL_GROUP, "group78" },
- { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0007,
- ARCHIVE_ENTRY_ACL_MASK, ""},
- { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_WRITE | ARCHIVE_ENTRY_ACL_EXECUTE,
- ARCHIVE_ENTRY_ACL_OTHER, "" },
-};
-
-static struct acl_t acls2[] = {
- { ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_EXECUTE,
- ARCHIVE_ENTRY_ACL_USER_OBJ, "" },
- { ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_READ,
- ARCHIVE_ENTRY_ACL_USER, "user77" },
- { ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_READ,
- ARCHIVE_ENTRY_ACL_GROUP_OBJ, "" },
- { ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_EXECUTE,
- ARCHIVE_ENTRY_ACL_GROUP, "group78" },
- { ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_READ | ARCHIVE_ENTRY_ACL_EXECUTE,
- ARCHIVE_ENTRY_ACL_MASK, ""},
- { ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_WRITE,
- ARCHIVE_ENTRY_ACL_OTHER, "" },
-};
-
-static int
-acl_match(struct acl_t *acl, int type, int permset, int tag, const char *name)
-{
- if (type != acl->type)
- return (0);
- if (permset != acl->permset)
- return (0);
- if (tag != acl->tag)
- return (0);
- if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ)
- return (1);
- if (tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ)
- return (1);
- if (tag == ARCHIVE_ENTRY_ACL_OTHER)
- return (1);
- if (tag == ARCHIVE_ENTRY_ACL_MASK)
- return (1);
- if (name == NULL)
- return (acl->name == NULL || acl->name[0] == '\0');
- if (acl->name == NULL)
- return (name == NULL || name[0] == '\0');
- return (0 == strcmp(name, acl->name));
-}
-
-static void
-compare_acls(struct archive_entry *ae, struct acl_t *acls, int n, int mode,
- int want_type)
-{
- int *marker = malloc(sizeof(marker[0]) * n);
- int i;
- int r;
- int type, permset, tag, qual;
- int matched;
- const char *name;
-
- for (i = 0; i < n; i++)
- marker[i] = i;
-
- while (0 == (r = archive_entry_acl_next(ae, want_type,
- &type, &permset, &tag, &qual, &name))) {
- for (i = 0, matched = 0; i < n && !matched; i++) {
- if (acl_match(&acls[marker[i]], type, permset,
- tag, name)) {
- /* We found a match; remove it. */
- marker[i] = marker[n - 1];
- n--;
- matched = 1;
- }
- }
- if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) {
- if (!matched) printf("No match for user_obj perm\n");
- if (want_type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) {
- failure("USER_OBJ permset (%02o) != user mode (%02o)",
- permset, 07 & (mode >> 6));
- assert((permset << 6) == (mode & 0700));
- }
- } else if (tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ) {
- if (!matched) printf("No match for group_obj perm\n");
- if (want_type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) {
- failure("GROUP_OBJ permset %02o != group mode %02o",
- permset, 07 & (mode >> 3));
- assert((permset << 3) == (mode & 0070));
- }
- } else if (tag == ARCHIVE_ENTRY_ACL_OTHER) {
- if (!matched) printf("No match for other perm\n");
- if (want_type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) {
- failure("OTHER permset (%02o) != other mode (%02o)",
- permset, mode & 07);
- assert((permset << 0) == (mode & 0007));
- }
- } else if (tag != ARCHIVE_ENTRY_ACL_MASK) {
- failure("Could not find match for ACL "
- "(type=%d,permset=%d,tag=%d,name=``%s'')",
- type, permset, tag, name);
- assert(matched == 1);
- }
- }
- assertEqualInt(ARCHIVE_EOF, r);
- assert((mode_t)(mode & 0777) == (archive_entry_mode(ae) & 0777));
- failure("Could not find match for ACL "
- "(type=%d,permset=%d,tag=%d,name=``%s'')",
- acls[marker[0]].type, acls[marker[0]].permset,
- acls[marker[0]].tag, acls[marker[0]].name);
- assert(n == 0); /* Number of ACLs not matched should == 0 */
- free(marker);
-}
-
-DEFINE_TEST(test_compat_star_acl_posix1e)
-{
- char name[] = "test_compat_star_acl_posix1e.tar";
- struct archive *a;
- struct archive_entry *ae;
-
- /* Read archive file */
- assert(NULL != (a = archive_read_new()));
- assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
- assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
- extract_reference_file(name);
- assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, name, 10240));
-
- /* First item has a few ACLs */
- assertA(0 == archive_read_next_header(a, &ae));
- failure("One extended ACL should flag all ACLs to be returned.");
- assertEqualInt(5, archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
- compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]), 0142, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
- failure("Basic ACLs should set mode to 0142, not %04o",
- archive_entry_mode(ae)&0777);
- assert((archive_entry_mode(ae) & 0777) == 0142);
-
- /* Second item has pretty extensive ACLs */
- assertA(0 == archive_read_next_header(a, &ae));
- assertEqualInt(7, archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
- compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]), 0543, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
- failure("Basic ACLs should set mode to 0543, not %04o",
- archive_entry_mode(ae)&0777);
- assert((archive_entry_mode(ae) & 0777) == 0543);
-
- /* Third item has default ACLs */
- assertA(0 == archive_read_next_header(a, &ae));
- assertEqualInt(6, archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT));
- compare_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]), 0142, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
- failure("Basic ACLs should set mode to 0142, not %04o",
- archive_entry_mode(ae)&0777);
- assert((archive_entry_mode(ae) & 0777) == 0142);
-
- /* Close the archive. */
- assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
- assertEqualInt(ARCHIVE_OK, archive_read_free(a));
-}