Browse files

Resuscitate the old NFS4 support code and make it work on FreeBSD-CUR…

…RENT.

This includes a new test that archive_write_disk and archive_read_disk
consistently read/write ACL information to/from disk.
This new test currently passes on FreeBSD-CURRENT.
  • Loading branch information...
1 parent 7387569 commit f67370d5c33b336b103c43fe35984defe7e0e473 @kientzle kientzle committed Apr 9, 2012
View
2 CMakeLists.txt
@@ -1303,6 +1303,8 @@ IF(ENABLE_ACL)
CHECK_FUNCTION_EXISTS(acl_get_perm_np HAVE_ACL_GET_PERM_NP)
CHECK_FUNCTION_EXISTS(acl_get_link HAVE_ACL_GET_LINK)
CHECK_FUNCTION_EXISTS(acl_get_link_np HAVE_ACL_GET_LINK_NP)
+ CHECK_FUNCTION_EXISTS(acl_is_trivial_np HAVE_ACL_IS_TRIVIAL_NP)
+ CHECK_FUNCTION_EXISTS(acl_set_link_np HAVE_ACL_SET_LINK_NP)
# MacOS has an acl.h that isn't POSIX. It can be detected by
# checking for ACL_USER
View
1 libarchive/CMakeLists.txt
@@ -85,6 +85,7 @@ SET(libarchive_SOURCES
archive_util.c
archive_virtual.c
archive_write.c
+ archive_write_disk_acl.c
archive_write_disk_posix.c
archive_write_disk_private.h
archive_write_disk_set_standard_lookup.c
View
227 libarchive/archive_read_disk_entry_from_file.c
@@ -114,7 +114,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 2010
#define ACL_GET_PERM acl_get_perm_np
#endif
-static int setup_acls_posix1e(struct archive_read_disk *,
+static int setup_acls(struct archive_read_disk *,
struct archive_entry *, int *fd);
static int setup_mac_metadata(struct archive_read_disk *,
struct archive_entry *, int *fd);
@@ -168,15 +168,16 @@ archive_read_disk_entry_from_file(struct archive *_a,
st = &s;
}
archive_entry_copy_stat(entry, st);
- /* Lookup uname/gname */
- name = archive_read_disk_uname(_a, archive_entry_uid(entry));
- if (name != NULL)
- archive_entry_copy_uname(entry, name);
- name = archive_read_disk_gname(_a, archive_entry_gid(entry));
- if (name != NULL)
- archive_entry_copy_gname(entry, name);
}
+ /* Lookup uname/gname */
+ name = archive_read_disk_uname(_a, archive_entry_uid(entry));
+ if (name != NULL)
+ archive_entry_copy_uname(entry, name);
+ name = archive_read_disk_gname(_a, archive_entry_gid(entry));
+ if (name != NULL)
+ archive_entry_copy_gname(entry, name);
+
#ifdef HAVE_STRUCT_STAT_ST_FLAGS
/* On FreeBSD, we get flags for free with the stat. */
/* TODO: Does this belong in copy_stat()? */
@@ -244,7 +245,7 @@ archive_read_disk_entry_from_file(struct archive *_a,
}
#endif /* HAVE_READLINK || HAVE_READLINKAT */
- r = setup_acls_posix1e(a, entry, &fd);
+ r = setup_acls(a, entry, &fd);
r1 = setup_xattrs(a, entry, &fd);
if (r1 < r)
r = r1;
@@ -388,11 +389,11 @@ setup_mac_metadata(struct archive_read_disk *a,
#ifdef HAVE_POSIX_ACL
-static void setup_acl_posix1e(struct archive_read_disk *a,
+static int translate_acl(struct archive_read_disk *a,
struct archive_entry *entry, acl_t acl, int archive_entry_acl_type);
static int
-setup_acls_posix1e(struct archive_read_disk *a,
+setup_acls(struct archive_read_disk *a,
struct archive_entry *entry, int *fd)
{
const char *accpath;
@@ -404,15 +405,33 @@ setup_acls_posix1e(struct archive_read_disk *a,
archive_entry_acl_clear(entry);
- if (*fd < 0 && a->tree != NULL &&
- (a->follow_symlinks || archive_entry_filetype(entry) != AE_IFLNK)){
- *fd = a->open_on_current_dir(a->tree, accpath,
- O_RDONLY | O_NONBLOCK);
- if (*fd < 0) {
- archive_set_error(&a->archive, errno,
- "Couldn't access %s", accpath);
- return (ARCHIVE_FAILED);
- }
+ /* Try NFS4 ACL first. */
+ if (*fd >= 0)
+ acl = acl_get_fd(*fd);
+#if HAVE_ACL_GET_LINK_NP
+ else if (!a->follow_symlinks)
+ acl = acl_get_link_np(accpath, ACL_TYPE_NFS4);
+#else
+ else if ((!a->follow_symlinks)
+ && (archive_entry_filetype(entry) == AE_IFLNK))
+ /* We can't get the ACL of a symlink, so we assume it can't
+ have one. */
+ acl = NULL;
+#endif
+ else
+ acl = acl_get_file(accpath, ACL_TYPE_NFS4);
+#if HAVE_ACL_IS_TRIVIAL_NP
+ /* Ignore "trivial" ACLs that just mirror the file mode. */
+ acl_is_trivial_np(acl, &r);
+ if (r) {
+ acl_free(acl);
+ acl = NULL;
+ }
+#endif
+ if (acl != NULL) {
+ translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4);
+ acl_free(acl);
+ return (ARCHIVE_OK);
}
/* Retrieve access ACL from file. */
@@ -431,7 +450,7 @@ setup_acls_posix1e(struct archive_read_disk *a,
else
acl = acl_get_file(accpath, ACL_TYPE_ACCESS);
if (acl != NULL) {
- setup_acl_posix1e(a, entry, acl,
+ translate_acl(a, entry, acl,
ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
acl_free(acl);
}
@@ -440,7 +459,7 @@ setup_acls_posix1e(struct archive_read_disk *a,
if (S_ISDIR(archive_entry_mode(entry))) {
acl = acl_get_file(accpath, ACL_TYPE_DEFAULT);
if (acl != NULL) {
- setup_acl_posix1e(a, entry, acl,
+ translate_acl(a, entry, acl,
ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
acl_free(acl);
}
@@ -449,69 +468,181 @@ setup_acls_posix1e(struct archive_read_disk *a,
}
/*
- * Translate POSIX.1e ACL into libarchive internal structure.
+ * Translate system ACL into libarchive internal structure.
*/
-static void
-setup_acl_posix1e(struct archive_read_disk *a,
- struct archive_entry *entry, acl_t acl, int archive_entry_acl_type)
+
+static struct {
+ int archive_perm;
+ int platform_perm;
+} acl_perm_map[] = {
+ {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
+ {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE},
+ {ARCHIVE_ENTRY_ACL_READ, ACL_READ},
+ {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
+ {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
+ {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
+ {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
+ {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
+ {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
+ {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS},
+ {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS},
+ {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
+ {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
+ {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
+ {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
+ {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL},
+ {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL},
+ {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER},
+ {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
+};
+
+static struct {
+ int archive_inherit;
+ int platform_inherit;
+} acl_inherit_map[] = {
+ {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
+ {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
+ {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT},
+ {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY}
+};
+
+static int
+translate_acl(struct archive_read_disk *a,
+ struct archive_entry *entry, acl_t acl, int default_entry_acl_type)
{
acl_tag_t acl_tag;
+ acl_entry_type_t acl_type;
+ acl_flagset_t acl_flagset;
acl_entry_t acl_entry;
acl_permset_t acl_permset;
+ int brand, i, r, entry_acl_type;
int s, ae_id, ae_tag, ae_perm;
const char *ae_name;
+
+ // FreeBSD "brands" ACLs as POSIX.1e or NFSv4
+ // Make sure the "brand" on this ACL is consistent
+ // with the default_entry_acl_type bits provided.
+ acl_get_brand_np(acl, &brand);
+ switch (brand) {
+ case ACL_BRAND_POSIX:
+ switch (default_entry_acl_type) {
+ case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
+ case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
+ entry_acl_type = default_entry_acl_type;
+ break;
+ default:
+ // XXX set warning message?
+ return ARCHIVE_FAILED;
+ }
+ break;
+ case ACL_BRAND_NFS4:
+ if (default_entry_acl_type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
+ // XXX set warning message?
+ return ARCHIVE_FAILED;
+ }
+ break;
+ default:
+ // XXX set warning message?
+ return ARCHIVE_FAILED;
+ break;
+ }
+
+
s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry);
while (s == 1) {
ae_id = -1;
ae_name = NULL;
+ ae_perm = 0;
acl_get_tag_type(acl_entry, &acl_tag);
- if (acl_tag == ACL_USER) {
+ switch (acl_tag) {
+ case ACL_USER:
ae_id = (int)*(uid_t *)acl_get_qualifier(acl_entry);
ae_name = archive_read_disk_uname(&a->archive, ae_id);
ae_tag = ARCHIVE_ENTRY_ACL_USER;
- } else if (acl_tag == ACL_GROUP) {
+ break;
+ case ACL_GROUP:
ae_id = (int)*(gid_t *)acl_get_qualifier(acl_entry);
ae_name = archive_read_disk_gname(&a->archive, ae_id);
ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
- } else if (acl_tag == ACL_MASK) {
+ break;
+ case ACL_MASK:
ae_tag = ARCHIVE_ENTRY_ACL_MASK;
- } else if (acl_tag == ACL_USER_OBJ) {
+ break;
+ case ACL_USER_OBJ:
ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
- } else if (acl_tag == ACL_GROUP_OBJ) {
+ break;
+ case ACL_GROUP_OBJ:
ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
- } else if (acl_tag == ACL_OTHER) {
+ break;
+ case ACL_OTHER:
ae_tag = ARCHIVE_ENTRY_ACL_OTHER;
- } else {
+ break;
+ case ACL_EVERYONE:
+ ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE;
+ break;
+ default:
/* Skip types that libarchive can't support. */
continue;
}
- acl_get_permset(acl_entry, &acl_permset);
- ae_perm = 0;
+ // XXX acl type maps to allow/deny/audit/YYYY bits
+ // XXX acl_get_entry_type_np on FreeBSD returns EINVAL for
+ // non-NFSv4 ACLs
+ entry_acl_type = default_entry_acl_type;
+ r = acl_get_entry_type_np(acl_entry, &acl_type);
+ if (r == 0) {
+ switch (acl_type) {
+ case ACL_ENTRY_TYPE_ALLOW:
+ entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
+ break;
+ case ACL_ENTRY_TYPE_DENY:
+ entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
+ break;
+ case ACL_ENTRY_TYPE_AUDIT:
+ entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT;
+ break;
+ case ACL_ENTRY_TYPE_ALARM:
+ entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
+ break;
+ }
+ }
+
/*
- * acl_get_perm() is spelled differently on different
- * platforms; see above.
+ * Libarchive stores "flag" (NFSv4 inheritance bits)
+ * in the ae_perm bitmap.
*/
- if (ACL_GET_PERM(acl_permset, ACL_EXECUTE))
- ae_perm |= ARCHIVE_ENTRY_ACL_EXECUTE;
- if (ACL_GET_PERM(acl_permset, ACL_READ))
- ae_perm |= ARCHIVE_ENTRY_ACL_READ;
- if (ACL_GET_PERM(acl_permset, ACL_WRITE))
- ae_perm |= ARCHIVE_ENTRY_ACL_WRITE;
+ acl_get_flagset_np(acl_entry, &acl_flagset);
+ for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) {
+ if (acl_get_flag_np(acl_flagset,
+ acl_inherit_map[i].platform_inherit))
+ ae_perm |= acl_inherit_map[i].archive_inherit;
- archive_entry_acl_add_entry(entry,
- archive_entry_acl_type, ae_perm, ae_tag,
- ae_id, ae_name);
+ }
+
+ acl_get_permset(acl_entry, &acl_permset);
+ for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) {
+ /*
+ * acl_get_perm() is spelled differently on different
+ * platforms; see above.
+ */
+ if (ACL_GET_PERM(acl_permset, acl_perm_map[i].platform_perm))
+ ae_perm |= acl_perm_map[i].archive_perm;
+ }
+
+ archive_entry_acl_add_entry(entry, entry_acl_type,
+ ae_perm, ae_tag,
+ ae_id, ae_name);
s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
}
+ return (ARCHIVE_OK);
}
#else
static int
-setup_acls_posix1e(struct archive_read_disk *a,
- struct archive_entry *entry, int *fd)
+setup_acls(struct archive_read_disk *a,
+ struct archive_entry *entry, int fd)
{
(void)a; /* UNUSED */
(void)entry; /* UNUSED */
View
249 libarchive/archive_write_disk_acl.c
@@ -0,0 +1,249 @@
+/*-
+ * Copyright (c) 2003-2010 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
+ * in this position and unchanged.
+ * 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 "archive_platform.h"
+__FBSDID("$FreeBSD: head/lib/libarchive/archive_write_disk.c 201159 2009-12-29 05:35:40Z kientzle $");
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_ACL_H
+#define _ACL_PRIVATE /* For debugging */
+#include <sys/acl.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "archive.h"
+#include "archive_entry.h"
+#include "archive_acl_private.h"
+#include "archive_write_disk_private.h"
+
+#ifndef HAVE_POSIX_ACL
+/* Default empty function body to satisfy mainline code. */
+int
+archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
+ struct archive_acl *abstract_acl)
+{
+ (void)a; /* UNUSED */
+ (void)fd; /* UNUSED */
+ (void)name; /* UNUSED */
+ (void)abstract_acl; /* UNUSED */
+ return (ARCHIVE_OK);
+}
+
+#else
+
+static int set_acl(struct archive *, int fd, const char *,
+ struct archive_acl *,
+ acl_type_t, int archive_entry_acl_type, const char *tn);
+
+/*
+ * XXX TODO: What about ACL types other than ACCESS and DEFAULT?
+ */
+int
+archive_write_disk_set_acls(struct archive *a, int fd, const char *name,
+ struct archive_acl *abstract_acl)
+{
+ int ret;
+
+ if (archive_acl_count(abstract_acl, ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) > 0) {
+ ret = set_acl(a, fd, name, abstract_acl, ACL_TYPE_ACCESS,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access");
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ ret = set_acl(a, fd, name, abstract_acl, ACL_TYPE_DEFAULT,
+ ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default");
+ return (ret);
+ } else if (archive_acl_count(abstract_acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4) > 0) {
+ ret = set_acl(a, fd, name, abstract_acl, ACL_TYPE_NFS4,
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4");
+ return (ret);
+ } else
+ return ARCHIVE_OK;
+}
+
+static struct {
+ int archive_perm;
+ int platform_perm;
+} acl_perm_map[] = {
+ {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
+ {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE},
+ {ARCHIVE_ENTRY_ACL_READ, ACL_READ},
+ {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
+ {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
+ {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
+ {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
+ {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
+ {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
+ {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS},
+ {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS},
+ {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
+ {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
+ {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
+ {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
+ {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL},
+ {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL},
+ {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER},
+ {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
+};
+
+static struct {
+ int archive_inherit;
+ int platform_inherit;
+} acl_inherit_map[] = {
+ {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
+ {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
+ {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT},
+ {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY}
+};
+
+static int
+set_acl(struct archive *a, int fd, const char *name,
+ struct archive_acl *abstract_acl,
+ acl_type_t acl_type, int ae_requested_type, const char *tname)
+{
+ acl_t acl;
+ acl_entry_t acl_entry;
+ acl_permset_t acl_permset;
+ acl_flagset_t acl_flagset;
+ int ret;
+ int ae_type, ae_permset, ae_tag, ae_id;
+ uid_t ae_uid;
+ gid_t ae_gid;
+ const char *ae_name;
+ int entries;
+ int i;
+
+ ret = ARCHIVE_OK;
+ entries = archive_acl_reset(abstract_acl, ae_requested_type);
+ if (entries == 0)
+ return (ARCHIVE_OK);
+ acl = acl_init(entries);
+ while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type,
+ &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) {
+ acl_create_entry(&acl, &acl_entry);
+
+ switch (ae_tag) {
+ case ARCHIVE_ENTRY_ACL_USER:
+ acl_set_tag_type(acl_entry, ACL_USER);
+ ae_uid = archive_write_disk_uid(a, ae_name, ae_id);
+ acl_set_qualifier(acl_entry, &ae_uid);
+ break;
+ case ARCHIVE_ENTRY_ACL_GROUP:
+ acl_set_tag_type(acl_entry, ACL_GROUP);
+ ae_gid = archive_write_disk_gid(a, ae_name, ae_id);
+ acl_set_qualifier(acl_entry, &ae_gid);
+ break;
+ case ARCHIVE_ENTRY_ACL_USER_OBJ:
+ acl_set_tag_type(acl_entry, ACL_USER_OBJ);
+ break;
+ case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+ acl_set_tag_type(acl_entry, ACL_GROUP_OBJ);
+ break;
+ case ARCHIVE_ENTRY_ACL_MASK:
+ acl_set_tag_type(acl_entry, ACL_MASK);
+ break;
+ case ARCHIVE_ENTRY_ACL_OTHER:
+ acl_set_tag_type(acl_entry, ACL_OTHER);
+ break;
+ case ARCHIVE_ENTRY_ACL_EVERYONE:
+ acl_set_tag_type(acl_entry, ACL_EVERYONE);
+ break;
+ default:
+ /* XXX */
+ break;
+ }
+
+ switch (ae_type) {
+ case ARCHIVE_ENTRY_ACL_TYPE_ALLOW:
+ acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALLOW);
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_DENY:
+ acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_DENY);
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_AUDIT:
+ acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_AUDIT);
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_ALARM:
+ acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALARM);
+ break;
+ case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
+ case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
+ // These don't translate directly into the system ACL.
+ break;
+ default:
+ // XXX error handling here.
+ break;
+ }
+
+ acl_get_permset(acl_entry, &acl_permset);
+ acl_clear_perms(acl_permset);
+
+ for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) {
+ if (ae_permset & acl_perm_map[i].archive_perm)
+ acl_add_perm(acl_permset,
+ acl_perm_map[i].platform_perm);
+ }
+
+ acl_get_flagset_np(acl_entry, &acl_flagset);
+ acl_clear_flags_np(acl_flagset);
+ for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) {
+ if (ae_permset & acl_inherit_map[i].archive_inherit)
+ acl_add_flag_np(acl_flagset,
+ acl_inherit_map[i].platform_inherit);
+ }
+ }
+
+ /* Try restoring the ACL through 'fd' if we can. */
+#if HAVE_ACL_SET_FD
+ if (fd >= 0 && acl_type == ACL_TYPE_ACCESS && acl_set_fd(fd, acl) == 0)
+ ret = ARCHIVE_OK;
+ else
+#else
+#if HAVE_ACL_SET_FD_NP
+ if (fd >= 0 && acl_set_fd_np(fd, acl, acl_type) == 0)
+ ret = ARCHIVE_OK;
+ else
+#endif
+#endif
+#if HAVE_ACL_SET_LINK_NP
+ if (acl_set_link_np(name, acl_type, acl) != 0) {
+ archive_set_error(a, errno, "Failed to set %s acl", tname);
+ ret = ARCHIVE_WARN;
+ }
+#else
+ /* TODO: Skip this if 'name' is a symlink. */
+ if (acl_set_file(name, acl_type, acl) != 0) {
+ archive_set_error(a, errno, "Failed to set %s acl", tname);
+ ret = ARCHIVE_WARN;
+ }
+#endif
+ acl_free(acl);
+ return (ret);
+}
+#endif
View
152 libarchive/archive_write_disk_posix.c
@@ -32,9 +32,6 @@ __FBSDID("$FreeBSD$");
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
-#ifdef HAVE_SYS_ACL_H
-#include <sys/acl.h>
-#endif
#ifdef HAVE_SYS_EXTATTR_H
#include <sys/extattr.h>
#endif
@@ -129,6 +126,7 @@ __FBSDID("$FreeBSD$");
#include "archive_string.h"
#include "archive_entry.h"
#include "archive_private.h"
+#include "archive_write_disk_private.h"
#ifndef O_BINARY
#define O_BINARY 0
@@ -267,11 +265,6 @@ static int create_dir(struct archive_write_disk *, char *);
static int create_parent_dir(struct archive_write_disk *, char *);
static int older(struct stat *, struct archive_entry *);
static int restore_entry(struct archive_write_disk *);
-#ifdef HAVE_POSIX_ACL
-static int set_acl(struct archive_write_disk *, int fd, const char *, struct archive_acl *,
- acl_type_t, int archive_entry_acl_type, const char *tn);
-#endif
-static int set_acls(struct archive_write_disk *, int fd, const char *, struct archive_acl *);
static int set_mac_metadata(struct archive_write_disk *, const char *,
const void *, size_t);
static int set_xattrs(struct archive_write_disk *);
@@ -570,6 +563,7 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry)
if (a->deferred & TODO_ACLS) {
fe = current_fixup(a, archive_entry_pathname(entry));
+ fe->fixup |= TODO_ACLS;
archive_acl_copy(&fe->acl, archive_entry_acl(entry));
}
@@ -878,7 +872,7 @@ _archive_write_disk_finish_entry(struct archive *_a)
* ACLs that prevent attribute changes (including time).
*/
if (a->todo & TODO_ACLS) {
- int r2 = set_acls(a, a->fd,
+ int r2 = archive_write_disk_set_acls(&a->archive, a->fd,
archive_entry_pathname(a->entry),
archive_entry_acl(a->entry));
if (r2 < ret) ret = r2;
@@ -950,12 +944,12 @@ archive_write_disk_gid(struct archive *_a, const char *name, int64_t id)
int64_t
archive_write_disk_uid(struct archive *_a, const char *name, int64_t id)
{
- struct archive_write_disk *a = (struct archive_write_disk *)_a;
- archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
- ARCHIVE_STATE_ANY, "archive_write_disk_uid");
- if (a->lookup_uid)
- return (a->lookup_uid)(a->lookup_uid_data, name, id);
- return (id);
+ struct archive_write_disk *a = (struct archive_write_disk *)_a;
+ archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
+ ARCHIVE_STATE_ANY, "archive_write_disk_uid");
+ if (a->lookup_uid)
+ return (a->lookup_uid)(a->lookup_uid_data, name, id);
+ return (id);
}
/*
@@ -1381,7 +1375,8 @@ _archive_write_disk_close(struct archive *_a)
if (p->fixup & TODO_MODE_BASE)
chmod(p->name, p->mode);
if (p->fixup & TODO_ACLS)
- set_acls(a, -1, p->name, &p->acl);
+ archive_write_disk_set_acls(&a->archive,
+ -1, p->name, &p->acl);
if (p->fixup & TODO_FFLAGS)
set_fflags_platform(a, -1, p->name,
p->mode, p->fflags_set, 0);
@@ -2543,131 +2538,6 @@ set_mac_metadata(struct archive_write_disk *a, const char *pathname,
}
#endif
-#ifndef HAVE_POSIX_ACL
-/* Default empty function body to satisfy mainline code. */
-static int
-set_acls(struct archive_write_disk *a, int fd, const char *name,
- struct archive_acl *aacl)
-{
- (void)a; /* UNUSED */
- (void)fd; /* UNUSED */
- (void)name; /* UNUSED */
- (void)aacl; /* UNUSED */
- return (ARCHIVE_OK);
-}
-
-#else
-
-/*
- * XXX TODO: What about ACL types other than ACCESS and DEFAULT?
- */
-static int
-set_acls(struct archive_write_disk *a, int fd, const char *name,
- struct archive_acl *abstract_acl)
-{
- int ret;
-
- ret = set_acl(a, fd, name, abstract_acl, ACL_TYPE_ACCESS,
- ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access");
- if (ret != ARCHIVE_OK)
- return (ret);
- ret = set_acl(a, fd, name, abstract_acl, ACL_TYPE_DEFAULT,
- ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default");
- return (ret);
-}
-
-
-static int
-set_acl(struct archive_write_disk *a, int fd, const char *name,
- struct archive_acl *abstract_acl,
- acl_type_t acl_type, int ae_requested_type, const char *tname)
-{
- acl_t acl;
- acl_entry_t acl_entry;
- acl_permset_t acl_permset;
- int ret, r;
- int ae_type, ae_permset, ae_tag, ae_id;
- uid_t ae_uid;
- gid_t ae_gid;
- const char *ae_name;
- int entries;
-
- ret = ARCHIVE_OK;
- entries = archive_acl_reset(abstract_acl, ae_requested_type);
- if (entries == 0)
- return (ARCHIVE_OK);
- acl = acl_init(entries);
- while ((r = archive_acl_next(&a->archive, abstract_acl,
- ae_requested_type, &ae_type, &ae_permset, &ae_tag, &ae_id,
- &ae_name)) == ARCHIVE_OK) {
- acl_create_entry(&acl, &acl_entry);
-
- switch (ae_tag) {
- case ARCHIVE_ENTRY_ACL_USER:
- acl_set_tag_type(acl_entry, ACL_USER);
- ae_uid = archive_write_disk_uid(&a->archive,
- ae_name, ae_id);
- acl_set_qualifier(acl_entry, &ae_uid);
- break;
- case ARCHIVE_ENTRY_ACL_GROUP:
- acl_set_tag_type(acl_entry, ACL_GROUP);
- ae_gid = archive_write_disk_gid(&a->archive,
- ae_name, ae_id);
- acl_set_qualifier(acl_entry, &ae_gid);
- break;
- case ARCHIVE_ENTRY_ACL_USER_OBJ:
- acl_set_tag_type(acl_entry, ACL_USER_OBJ);
- break;
- case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
- acl_set_tag_type(acl_entry, ACL_GROUP_OBJ);
- break;
- case ARCHIVE_ENTRY_ACL_MASK:
- acl_set_tag_type(acl_entry, ACL_MASK);
- break;
- case ARCHIVE_ENTRY_ACL_OTHER:
- acl_set_tag_type(acl_entry, ACL_OTHER);
- break;
- default:
- /* XXX */
- break;
- }
-
- acl_get_permset(acl_entry, &acl_permset);
- acl_clear_perms(acl_permset);
- if (ae_permset & ARCHIVE_ENTRY_ACL_EXECUTE)
- acl_add_perm(acl_permset, ACL_EXECUTE);
- if (ae_permset & ARCHIVE_ENTRY_ACL_WRITE)
- acl_add_perm(acl_permset, ACL_WRITE);
- if (ae_permset & ARCHIVE_ENTRY_ACL_READ)
- acl_add_perm(acl_permset, ACL_READ);
- }
- if (r == ARCHIVE_FATAL) {
- acl_free(acl);
- archive_set_error(&a->archive, errno,
- "Failed to archive_acl_next");
- return (r);
- }
-
- /* Try restoring the ACL through 'fd' if we can. */
-#if HAVE_ACL_SET_FD
- if (fd >= 0 && acl_type == ACL_TYPE_ACCESS && acl_set_fd(fd, acl) == 0)
- ret = ARCHIVE_OK;
- else
-#else
-#if HAVE_ACL_SET_FD_NP
- if (fd >= 0 && acl_set_fd_np(fd, acl, acl_type) == 0)
- ret = ARCHIVE_OK;
- else
-#endif
-#endif
- if (acl_set_file(name, acl_type, acl) != 0) {
- archive_set_error(&a->archive, errno, "Failed to set %s acl", tname);
- ret = ARCHIVE_WARN;
- }
- acl_free(acl);
- return (ret);
-}
-#endif
#if HAVE_LSETXATTR || HAVE_LSETEA
/*
View
5 libarchive/archive_write_disk_private.h
@@ -33,6 +33,11 @@
#ifndef ARCHIVE_WRITE_DISK_PRIVATE_H_INCLUDED
#define ARCHIVE_WRITE_DISK_PRIVATE_H_INCLUDED
+#include "archive_acl_private.h"
+
struct archive_write_disk;
+int
+archive_write_disk_set_acls(struct archive *, int /* fd */, const char * /* pathname */, struct archive_acl *);
+
#endif
View
3 libarchive/test/CMakeLists.txt
@@ -8,7 +8,8 @@ IF(ENABLE_TEST)
main.c
read_open_memory.c
test.h
- test_acl_freebsd.c
+ test_acl_freebsd_posix1e.c
+ test_acl_freebsd_nfs4.c
test_acl_nfs4.c
test_acl_pax.c
test_acl_posix1e.c
View
547 libarchive/test/test_acl_freebsd_nfs4.c
@@ -0,0 +1,547 @@
+/*-
+ * Copyright (c) 2003-2010 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$");
+
+#if defined(__FreeBSD__) && __FreeBSD__ >= 8
+#define _ACL_PRIVATE
+#include <sys/acl.h>
+
+struct myacl_t {
+ int type;
+ int permset;
+ int tag;
+ 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 acls_reg[] = {
+ /* For this test, we need the file owner to be able to read and write the ACL. */
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
+ ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_READ_ACL | ARCHIVE_ENTRY_ACL_WRITE_ACL | ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES,
+ ARCHIVE_ENTRY_ACL_USER_OBJ, -1, ""},
+
+ /* An entry for each type. */
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
+ ARCHIVE_ENTRY_ACL_USER, 108, "user108" },
+ { ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_EXECUTE,
+ ARCHIVE_ENTRY_ACL_USER, 109, "user109" },
+
+ /* An entry for each permission. */
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
+ ARCHIVE_ENTRY_ACL_USER, 112, "user112" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_DATA,
+ ARCHIVE_ENTRY_ACL_USER, 113, "user113" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_DATA,
+ ARCHIVE_ENTRY_ACL_USER, 115, "user115" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_APPEND_DATA,
+ ARCHIVE_ENTRY_ACL_USER, 117, "user117" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS,
+ ARCHIVE_ENTRY_ACL_USER, 119, "user119" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS,
+ ARCHIVE_ENTRY_ACL_USER, 120, "user120" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES,
+ ARCHIVE_ENTRY_ACL_USER, 122, "user122" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES,
+ ARCHIVE_ENTRY_ACL_USER, 123, "user123" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_DELETE,
+ ARCHIVE_ENTRY_ACL_USER, 124, "user124" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ACL,
+ ARCHIVE_ENTRY_ACL_USER, 125, "user125" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ACL,
+ ARCHIVE_ENTRY_ACL_USER, 126, "user126" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_OWNER,
+ ARCHIVE_ENTRY_ACL_USER, 127, "user127" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
+ ARCHIVE_ENTRY_ACL_USER, 128, "user128" },
+
+ /* One entry for each qualifier. */
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
+ ARCHIVE_ENTRY_ACL_USER, 135, "user135" },
+// { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
+// ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
+ ARCHIVE_ENTRY_ACL_GROUP, 136, "group136" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
+ ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE,
+ ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }
+};
+
+
+static struct myacl_t acls_dir[] = {
+ /* For this test, we need to be able to read and write the ACL. */
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ACL,
+ ARCHIVE_ENTRY_ACL_USER_OBJ, -1, ""},
+
+ /* An entry for each type. */
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
+ ARCHIVE_ENTRY_ACL_USER, 101, "user101" },
+ { ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
+ ARCHIVE_ENTRY_ACL_USER, 102, "user102" },
+
+ /* An entry for each permission. */
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
+ ARCHIVE_ENTRY_ACL_USER, 201, "user201" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_ADD_FILE,
+ ARCHIVE_ENTRY_ACL_USER, 202, "user202" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY,
+ ARCHIVE_ENTRY_ACL_USER, 203, "user203" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS,
+ ARCHIVE_ENTRY_ACL_USER, 204, "user204" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS,
+ ARCHIVE_ENTRY_ACL_USER, 205, "user205" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_DELETE_CHILD,
+ ARCHIVE_ENTRY_ACL_USER, 206, "user206" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES,
+ ARCHIVE_ENTRY_ACL_USER, 207, "user207" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES,
+ ARCHIVE_ENTRY_ACL_USER, 208, "user208" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_DELETE,
+ ARCHIVE_ENTRY_ACL_USER, 209, "user209" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_ACL,
+ ARCHIVE_ENTRY_ACL_USER, 210, "user210" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_ACL,
+ ARCHIVE_ENTRY_ACL_USER, 211, "user211" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_WRITE_OWNER,
+ ARCHIVE_ENTRY_ACL_USER, 212, "user212" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_SYNCHRONIZE,
+ ARCHIVE_ENTRY_ACL_USER, 213, "user213" },
+
+ /* One entry with each inheritance value. */
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
+ ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT,
+ ARCHIVE_ENTRY_ACL_USER, 301, "user301" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
+ ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT,
+ ARCHIVE_ENTRY_ACL_USER, 302, "user302" },
+#if 0
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
+ ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT,
+ ARCHIVE_ENTRY_ACL_USER, 303, "user303" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW,
+ ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY,
+ ARCHIVE_ENTRY_ACL_USER, 304, "user304" },
+#endif
+
+#if 0
+ /* FreeBSD does not support audit entries. */
+ { ARCHIVE_ENTRY_ACL_TYPE_AUDIT,
+ ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS,
+ ARCHIVE_ENTRY_ACL_USER, 401, "user401" },
+ { ARCHIVE_ENTRY_ACL_TYPE_AUDIT,
+ ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS,
+ ARCHIVE_ENTRY_ACL_USER, 402, "user402" },
+#endif
+
+ /* One entry for each qualifier. */
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
+ ARCHIVE_ENTRY_ACL_USER, 501, "user501" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
+ ARCHIVE_ENTRY_ACL_GROUP, 502, "group502" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
+ ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" },
+ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY,
+ ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }
+};
+
+static void
+set_acls(struct archive_entry *ae, struct myacl_t *acls, int start, int end)
+{
+ int i;
+
+ archive_entry_acl_clear(ae);
+ if (start > 0) {
+ assertEqualInt(ARCHIVE_OK,
+ archive_entry_acl_add_entry(ae,
+ acls[0].type, acls[0].permset, acls[0].tag,
+ acls[0].qual, acls[0].name));
+ }
+ for (i = start; i < end; i++) {
+ 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_permset_to_bitmap(acl_permset_t opaque_ps)
+{
+ static struct { int machine; int portable; } perms[] = {
+ {ACL_EXECUTE, ARCHIVE_ENTRY_ACL_EXECUTE},
+ {ACL_WRITE, ARCHIVE_ENTRY_ACL_WRITE},
+ {ACL_READ, ARCHIVE_ENTRY_ACL_READ},
+ {ACL_READ_DATA, ARCHIVE_ENTRY_ACL_READ_DATA},
+ {ACL_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY},
+ {ACL_WRITE_DATA, ARCHIVE_ENTRY_ACL_WRITE_DATA},
+ {ACL_ADD_FILE, ARCHIVE_ENTRY_ACL_ADD_FILE},
+ {ACL_APPEND_DATA, ARCHIVE_ENTRY_ACL_APPEND_DATA},
+ {ACL_ADD_SUBDIRECTORY, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY},
+ {ACL_READ_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS},
+ {ACL_WRITE_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS},
+ {ACL_DELETE_CHILD, ARCHIVE_ENTRY_ACL_DELETE_CHILD},
+ {ACL_READ_ATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES},
+ {ACL_WRITE_ATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES},
+ {ACL_DELETE, ARCHIVE_ENTRY_ACL_DELETE},
+ {ACL_READ_ACL, ARCHIVE_ENTRY_ACL_READ_ACL},
+ {ACL_WRITE_ACL, ARCHIVE_ENTRY_ACL_WRITE_ACL},
+ {ACL_WRITE_OWNER, ARCHIVE_ENTRY_ACL_WRITE_OWNER},
+ {ACL_SYNCHRONIZE, ARCHIVE_ENTRY_ACL_SYNCHRONIZE}
+ };
+ int i, permset = 0;
+
+ for (i = 0; i < (int)(sizeof(perms)/sizeof(perms[0])); ++i)
+ if (acl_get_perm_np(opaque_ps, perms[i].machine))
+ permset |= perms[i].portable;
+ return permset;
+}
+
+static int
+acl_flagset_to_bitmap(acl_flagset_t opaque_fs)
+{
+ static struct { int machine; int portable; } flags[] = {
+ {ACL_ENTRY_FILE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT},
+ {ACL_ENTRY_DIRECTORY_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT},
+ {ACL_ENTRY_NO_PROPAGATE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT},
+ {ACL_ENTRY_INHERIT_ONLY, ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY},
+ };
+ int i, flagset = 0;
+
+ for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); ++i)
+ if (acl_get_flag_np(opaque_fs, flags[i].machine))
+ flagset |= flags[i].portable;
+ return flagset;
+}
+
+static int
+acl_match(acl_entry_t aclent, struct myacl_t *myacl)
+{
+ gid_t g, *gp;
+ uid_t u, *up;
+ acl_tag_t tag_type;
+ acl_permset_t opaque_ps;
+ acl_flagset_t opaque_fs;
+ int perms;
+
+ acl_get_tag_type(aclent, &tag_type);
+
+ /* translate the silly opaque permset to a bitmap */
+ acl_get_permset(aclent, &opaque_ps);
+ acl_get_flagset_np(aclent, &opaque_fs);
+ perms = acl_permset_to_bitmap(opaque_ps) | acl_flagset_to_bitmap(opaque_fs);
+ if (perms != myacl->permset)
+ return (0);
+
+ switch (tag_type) {
+ case ACL_USER_OBJ:
+ if (myacl->tag != ARCHIVE_ENTRY_ACL_USER_OBJ) return (0);
+ break;
+ case ACL_USER:
+ if (myacl->tag != ARCHIVE_ENTRY_ACL_USER)
+ return (0);
+ up = acl_get_qualifier(aclent);
+ u = *up;
+ acl_free(up);
+ if ((uid_t)myacl->qual != u)
+ return (0);
+ break;
+ case ACL_GROUP_OBJ:
+ if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP_OBJ) return (0);
+ break;
+ case ACL_GROUP:
+ if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP)
+ return (0);
+ gp = acl_get_qualifier(aclent);
+ g = *gp;
+ acl_free(gp);
+ if ((gid_t)myacl->qual != g)
+ return (0);
+ break;
+ case ACL_MASK:
+ if (myacl->tag != ARCHIVE_ENTRY_ACL_MASK) return (0);
+ break;
+ case ACL_EVERYONE:
+ if (myacl->tag != ARCHIVE_ENTRY_ACL_EVERYONE) return (0);
+ break;
+ }
+ return (1);
+}
+
+static void
+compare_acls(acl_t acl, struct myacl_t *myacls, const char *filename, int start, int end)
+{
+ int *marker;
+ int entry_id = ACL_FIRST_ENTRY;
+ int matched;
+ int i, n;
+ acl_entry_t acl_entry;
+
+ n = end - start;
+ marker = malloc(sizeof(marker[0]) * (n + 1));
+ for (i = 0; i < n; i++)
+ marker[i] = i + start;
+ /* Always include the first ACE. */
+ if (start > 0) {
+ marker[n] = 0;
+ ++n;
+ }
+
+ /*
+ * Iterate over acls in system acl object, try to match each
+ * one with an item in the myacls array.
+ */
+ while (1 == acl_get_entry(acl, entry_id, &acl_entry)) {
+ /* After the first time... */
+ entry_id = ACL_NEXT_ENTRY;
+
+ /* Search for a matching entry (tag and qualifier) */
+ for (i = 0, matched = 0; i < n && !matched; i++) {
+ if (acl_match(acl_entry, &myacls[marker[i]])) {
+ /* We found a match; remove it. */
+ marker[i] = marker[n - 1];
+ n--;
+ matched = 1;
+ }
+ }
+
+ failure("ACL entry on file %s that shouldn't be there", filename);
+ assert(matched == 1);
+ }
+
+ /* 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",
+ marker[i], filename,
+ myacls[marker[i]].type, myacls[marker[i]].permset,
+ myacls[marker[i]].tag, myacls[marker[i]].qual,
+ myacls[marker[i]].name);
+ assert(0); /* Record this as a failure. */
+ }
+ free(marker);
+}
+
+static void
+compare_entry_acls(struct archive_entry *ae, struct myacl_t *myacls, const char *filename, int start, int end)
+{
+ int *marker;
+ int matched;
+ int i, n;
+ int type, permset, tag, qual;
+ const char *name;
+
+ /* Count ACL entries in myacls array and allocate an indirect array. */
+ n = end - start;
+ marker = malloc(sizeof(marker[0]) * (n + 1));
+ for (i = 0; i < n; i++)
+ marker[i] = i + start;
+ /* Always include the first ACE. */
+ if (start > 0) {
+ marker[n] = 0;
+ ++n;
+ }
+
+ /*
+ * Iterate over acls in entry, try to match each
+ * one with an item in the myacls array.
+ */
+ assertEqualInt(n, archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4));
+ while (ARCHIVE_OK == archive_entry_acl_next(ae,
+ ARCHIVE_ENTRY_ACL_TYPE_NFS4, &type, &permset, &tag, &qual, &name)) {
+
+ /* Search for a matching entry (tag and qualifier) */
+ for (i = 0, matched = 0; i < n && !matched; i++) {
+ if (tag == myacls[marker[i]].tag
+ && qual == myacls[marker[i]].qual
+ && permset == myacls[marker[i]].permset
+ && type == myacls[marker[i]].type) {
+ /* We found a match; remove it. */
+ marker[i] = marker[n - 1];
+ n--;
+ matched = 1;
+ }
+ }
+
+ failure("ACL entry on file that shouldn't be there: "
+ "type=%d,permset=%x,tag=%d,qual=%d",
+ type,permset,tag,qual);
+ assert(matched == 1);
+ }
+
+ /* 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",
+ marker[i], filename,
+ myacls[marker[i]].type, myacls[marker[i]].permset,
+ myacls[marker[i]].tag, myacls[marker[i]].qual,
+ myacls[marker[i]].name);
+ assert(0); /* Record this as a failure. */
+ }
+ free(marker);
+}
+#endif
+
+/*
+ * Verify ACL restore-to-disk. This test is FreeBSD-specific.
+ */
+
+DEFINE_TEST(test_acl_freebsd_nfs4)
+{
+#if !defined(__FreeBSD__)
+ skipping("FreeBSD-specific NFS4 ACL restore test");
+#elif __FreeBSD__ < 8
+ skipping("NFS4 ACLs supported only on FreeBSD 8.0 and later");
+#else
+ char buff[64];
+ struct stat st;
+ struct archive *a;
+ struct archive_entry *ae;
+ int i, n;
+ acl_t acl;
+
+ /*
+ * First, do a quick manual set/read of ACL data to
+ * verify that the local filesystem does support ACLs.
+ * If it doesn't, we'll simply skip the remaining tests.
+ */
+ acl = acl_from_text("owner@:rwxp::allow,group@:rwp:f:allow");
+ assert((void *)acl != NULL);
+ /* Create a test dir and try to set an ACL on it. */
+ if (!assertMakeDir("pretest", 0755)) {
+ acl_free(acl);
+ return;
+ }
+
+ n = acl_set_file("pretest", ACL_TYPE_NFS4, acl);
+ acl_free(acl);
+ if (n != 0 && errno == EOPNOTSUPP) {
+ skipping("NFS4 ACL tests require that NFS4 ACLs"
+ " be enabled on the filesystem");
+ return;
+ }
+ if (n != 0 && errno == EINVAL) {
+ skipping("This filesystem does not support NFS4 ACLs");
+ return;
+ }
+ failure("acl_set_file(): errno = %d (%s)",
+ errno, strerror(errno));
+ assertEqualInt(0, n);
+
+ /* Create a write-to-disk object. */
+ assert(NULL != (a = archive_write_disk_new()));
+ archive_write_disk_set_options(a,
+ ARCHIVE_EXTRACT_TIME | ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_ACL);
+
+ /* Populate an archive entry with some metadata, including ACL info */
+ ae = archive_entry_new();
+ assert(ae != NULL);
+ archive_entry_set_pathname(ae, "testall");
+ archive_entry_set_filetype(ae, AE_IFREG);
+ archive_entry_set_perm(ae, 0654);
+ archive_entry_set_mtime(ae, 123456, 7890);
+ archive_entry_set_size(ae, 0);
+ set_acls(ae, acls_reg, 0, (int)(sizeof(acls_reg)/sizeof(acls_reg[0])));
+
+ /* Write the entry to disk, including ACLs. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
+
+ /* Likewise for a dir. */
+ archive_entry_set_pathname(ae, "dirall");
+ archive_entry_set_filetype(ae, AE_IFDIR);
+ archive_entry_set_perm(ae, 0654);
+ archive_entry_set_mtime(ae, 123456, 7890);
+ set_acls(ae, acls_dir, 0, (int)(sizeof(acls_dir)/sizeof(acls_dir[0])));
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
+
+ for (i = 0; i < (int)(sizeof(acls_dir)/sizeof(acls_dir[0])); ++i) {
+ sprintf(buff, "dir%d", i);
+ archive_entry_set_pathname(ae, buff);
+ archive_entry_set_filetype(ae, AE_IFDIR);
+ archive_entry_set_perm(ae, 0654);
+ archive_entry_set_mtime(ae, 123456 + i, 7891 + i);
+ set_acls(ae, acls_dir, i, i + 1);
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
+ }
+
+ archive_entry_free(ae);
+
+ /* Close the archive. */
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a));
+ assertEqualInt(ARCHIVE_OK, archive_write_free(a));
+
+ /* Verify the data on disk. */
+ assertEqualInt(0, stat("testall", &st));
+ assertEqualInt(st.st_mtime, 123456);
+ acl = acl_get_file("testall", ACL_TYPE_NFS4);
+ assert(acl != (acl_t)NULL);
+ compare_acls(acl, acls_reg, "testall", 0, (int)(sizeof(acls_reg)/sizeof(acls_reg[0])));
+ acl_free(acl);
+
+ /* Verify single-permission dirs on disk. */
+ for (i = 0; i < (int)(sizeof(acls_dir)/sizeof(acls_dir[0])); ++i) {
+ sprintf(buff, "dir%d", i);
+ assertEqualInt(0, stat(buff, &st));
+ assertEqualInt(st.st_mtime, 123456 + i);
+ acl = acl_get_file(buff, ACL_TYPE_NFS4);
+ assert(acl != (acl_t)NULL);
+ compare_acls(acl, acls_dir, buff, i, i + 1);
+ acl_free(acl);
+ }
+
+ /* Verify "dirall" on disk. */
+ assertEqualInt(0, stat("dirall", &st));
+ assertEqualInt(st.st_mtime, 123456);
+ acl = acl_get_file("dirall", ACL_TYPE_NFS4);
+ assert(acl != (acl_t)NULL);
+ compare_acls(acl, acls_dir, "dirall", 0, (int)(sizeof(acls_dir)/sizeof(acls_dir[0])));
+ acl_free(acl);
+
+ /* Read and compare ACL via archive_read_disk */
+ a = archive_read_disk_new();
+ assert(a != NULL);
+ ae = archive_entry_new();
+ assert(ae != NULL);
+ archive_entry_set_pathname(ae, "testall");
+ assertEqualInt(ARCHIVE_OK,
+ archive_read_disk_entry_from_file(a, ae, -1, NULL));
+ compare_entry_acls(ae, acls_reg, "testall", 0, (int)(sizeof(acls_reg)/sizeof(acls_reg[0])));
+ archive_entry_free(ae);
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+
+ /* Read and compare ACL via archive_read_disk */
+ a = archive_read_disk_new();
+ assert(a != NULL);
+ ae = archive_entry_new();
+ assert(ae != NULL);
+ archive_entry_set_pathname(ae, "dirall");
+ assertEqualInt(ARCHIVE_OK,
+ archive_read_disk_entry_from_file(a, ae, -1, NULL));
+ compare_entry_acls(ae, acls_dir, "dirall", 0, (int)(sizeof(acls_dir)/sizeof(acls_dir[0])));
+ archive_entry_free(ae);
+ assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+#endif
+}
View
2 libarchive/test/test_acl_freebsd.c → libarchive/test/test_acl_freebsd_posix1e.c
@@ -185,7 +185,7 @@ compare_acls(acl_t acl, struct myacl_t *myacls)
* Verify ACL restore-to-disk. This test is FreeBSD-specific.
*/
-DEFINE_TEST(test_acl_freebsd)
+DEFINE_TEST(test_acl_freebsd_posix1e)
{
#if !defined(__FreeBSD__)
skipping("FreeBSD-specific ACL restore test");
View
6 tar/test/test_basic.c
@@ -58,14 +58,19 @@ verify_files(const char *target)
assertChdir(target);
/* Regular file with 2 links. */
+ failure("%s", target);
assertIsReg("file", -1);
+ failure("%s", target);
assertFileSize("file", 10);
+ failure("%s", target);
assertFileContents("123456789", 10, "file");
failure("%s", target);
assertFileNLinks("file", 2);
/* Another name for the same file. */
+ failure("%s", target);
assertIsReg("linkfile", -1);
+ failure("%s", target);
assertFileSize("linkfile", 10);
assertFileContents("123456789", 10, "linkfile");
assertFileNLinks("linkfile", 2);
@@ -76,6 +81,7 @@ verify_files(const char *target)
assertIsSymlink("symlink", "file");
/* dir */
+ failure("%s", target);
assertIsDir("dir", 0775);
assertChdir("..");
}

0 comments on commit f67370d

Please sign in to comment.