Backport NFSv4 ACL fix from libarchive master branch.

Source:
https://github.com/libarchive/libarchive/commit/f67370d5

Obtained from:	libarchive (master branch)
This commit is contained in:
Martin Matuska 2012-07-30 14:47:35 +00:00
parent a4a16855c3
commit 10ed66fdf8
10 changed files with 2072 additions and 192 deletions

View File

@ -114,7 +114,7 @@ __FBSDID("$FreeBSD$");
#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,15 +389,16 @@ 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;
acl_t acl;
int r;
accpath = archive_entry_sourcepath(entry);
if (accpath == NULL)
@ -404,15 +406,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 +451,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 +460,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,70 +469,182 @@ 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. */
s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
continue;
}
acl_get_permset(acl_entry, &acl_permset);
ae_perm = 0;
/*
* acl_get_perm() is spelled differently on different
* platforms; see above.
*/
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;
// 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;
}
}
archive_entry_acl_add_entry(entry,
archive_entry_acl_type, ae_perm, ae_tag,
ae_id, ae_name);
/*
* Libarchive stores "flag" (NFSv4 inheritance bits)
* in the ae_perm bitmap.
*/
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;
}
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 File

@ -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 File

@ -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 File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,520 @@
/*-
* Copyright (c) 2003-2008 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: head/lib/libarchive/test/test_acl_freebsd.c 189427 2009-03-06 04:21:23Z kientzle $");
#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[] = {
{ 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, 77, "user77" },
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0,
ARCHIVE_ENTRY_ACL_USER, 78, "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, 78, "group78" },
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
ARCHIVE_ENTRY_ACL_WRITE | ARCHIVE_ENTRY_ACL_EXECUTE,
ARCHIVE_ENTRY_ACL_OTHER, -1, "" },
{ 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_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;
int permset = 0;
acl_get_tag_type(aclent, &tag_type);
/* translate the silly opaque permset to a bitmap */
acl_get_permset(aclent, &opaque_ps);
if (acl_get_perm_np(opaque_ps, ACL_EXECUTE))
permset |= ARCHIVE_ENTRY_ACL_EXECUTE;
if (acl_get_perm_np(opaque_ps, ACL_WRITE))
permset |= ARCHIVE_ENTRY_ACL_WRITE;
if (acl_get_perm_np(opaque_ps, ACL_READ))
permset |= ARCHIVE_ENTRY_ACL_READ;
if (permset != 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_OTHER:
if (myacl->tag != ARCHIVE_ENTRY_ACL_OTHER) return (0);
break;
}
return (1);
}
static void
compare_acls(acl_t acl, struct myacl_t *myacls)
{
int *marker;
int entry_id = ACL_FIRST_ENTRY;
int matched;
int i, n;
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;
marker = malloc(sizeof(marker[0]) * n);
for (i = 0; i < n; i++)
marker[i] = i;
/*
* 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;
}
}
/* TODO: Print out more details in this case. */
failure("ACL entry on file that shouldn't be there");
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 missing from file: "
"type=%d,permset=%d,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);
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_posix1e)
{
#if !defined(__FreeBSD__)
skipping("FreeBSD-specific ACL restore test");
#elif __FreeBSD__ < 5
skipping("ACL restore supported only on FreeBSD 5.0 and later");
#else
struct stat st;
struct archive *a;
struct archive_entry *ae;
int n, fd;
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("u::rwx,u:1:rw,g::rwx,g:15:rx,o::rwx,m::rwx");
assert((void *)acl != NULL);
/* Create a test file and try to set an ACL on it. */
fd = open("pretest", O_WRONLY | O_CREAT | O_EXCL, 0777);
failure("Could not create test file?!");
if (!assert(fd >= 0)) {
acl_free(acl);
return;
}
n = acl_set_fd(fd, acl);
acl_free(acl);
if (n != 0 && errno == EOPNOTSUPP) {
close(fd);
skipping("ACL tests require that ACL support be enabled on the filesystem");
return;
}
if (n != 0 && errno == EINVAL) {
close(fd);
skipping("This filesystem does not support POSIX.1e ACLs");
return;
}
failure("acl_set_fd(): errno = %d (%s)",
errno, strerror(errno));
assertEqualInt(0, n);
close(fd);
/* 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, "test0");
archive_entry_set_mtime(ae, 123456, 7890);
archive_entry_set_size(ae, 0);
set_acls(ae, acls2);
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("test0", &st));
assertEqualInt(st.st_mtime, 123456);
acl = acl_get_file("test0", ACL_TYPE_ACCESS);
assert(acl != (acl_t)NULL);
compare_acls(acl, acls2);
acl_free(acl);
#endif
}
/*-
* Copyright (c) 2003-2008 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: head/lib/libarchive/test/test_acl_freebsd.c 189427 2009-03-06 04:21:23Z kientzle $");
#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[] = {
{ 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, 77, "user77" },
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0,
ARCHIVE_ENTRY_ACL_USER, 78, "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, 78, "group78" },
{ ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
ARCHIVE_ENTRY_ACL_WRITE | ARCHIVE_ENTRY_ACL_EXECUTE,
ARCHIVE_ENTRY_ACL_OTHER, -1, "" },
{ 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_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;
int permset = 0;
acl_get_tag_type(aclent, &tag_type);
/* translate the silly opaque permset to a bitmap */
acl_get_permset(aclent, &opaque_ps);
if (acl_get_perm_np(opaque_ps, ACL_EXECUTE))
permset |= ARCHIVE_ENTRY_ACL_EXECUTE;
if (acl_get_perm_np(opaque_ps, ACL_WRITE))
permset |= ARCHIVE_ENTRY_ACL_WRITE;
if (acl_get_perm_np(opaque_ps, ACL_READ))
permset |= ARCHIVE_ENTRY_ACL_READ;
if (permset != 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_OTHER:
if (myacl->tag != ARCHIVE_ENTRY_ACL_OTHER) return (0);
break;
}
return (1);
}
static void
compare_acls(acl_t acl, struct myacl_t *myacls)
{
int *marker;
int entry_id = ACL_FIRST_ENTRY;
int matched;
int i, n;
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;
marker = malloc(sizeof(marker[0]) * n);
for (i = 0; i < n; i++)
marker[i] = i;
/*
* 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;
}
}
/* TODO: Print out more details in this case. */
failure("ACL entry on file that shouldn't be there");
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 missing from file: "
"type=%d,permset=%d,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);
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_posix1e)
{
#if !defined(__FreeBSD__)
skipping("FreeBSD-specific ACL restore test");
#elif __FreeBSD__ < 5
skipping("ACL restore supported only on FreeBSD 5.0 and later");
#else
struct stat st;
struct archive *a;
struct archive_entry *ae;
int n, fd;
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("u::rwx,u:1:rw,g::rwx,g:15:rx,o::rwx,m::rwx");
assert((void *)acl != NULL);
/* Create a test file and try to set an ACL on it. */
fd = open("pretest", O_WRONLY | O_CREAT | O_EXCL, 0777);
failure("Could not create test file?!");
if (!assert(fd >= 0)) {
acl_free(acl);
return;
}
n = acl_set_fd(fd, acl);
acl_free(acl);
if (n != 0 && errno == EOPNOTSUPP) {
close(fd);
skipping("ACL tests require that ACL support be enabled on the filesystem");
return;
}
if (n != 0 && errno == EINVAL) {
close(fd);
skipping("This filesystem does not support POSIX.1e ACLs");
return;
}
failure("acl_set_fd(): errno = %d (%s)",
errno, strerror(errno));
assertEqualInt(0, n);
close(fd);
/* 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, "test0");
archive_entry_set_mtime(ae, 123456, 7890);
archive_entry_set_size(ae, 0);
set_acls(ae, acls2);
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("test0", &st));
assertEqualInt(st.st_mtime, 123456);
acl = acl_get_file("test0", ACL_TYPE_ACCESS);
assert(acl != (acl_t)NULL);
compare_acls(acl, acls2);
acl_free(acl);
#endif
}

View File

@ -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("..");
}

View File

@ -110,6 +110,7 @@ SRCS= archive_acl.c \
archive_virtual.c \
archive_write.c \
archive_write_add_filter.c \
archive_write_disk_acl.c \
archive_write_disk_set_standard_lookup.c \
archive_write_disk_posix.c \
archive_write_open_fd.c \

View File

@ -31,10 +31,12 @@
#define HAVE_ACL_GET_LINK_NP 1
#define HAVE_ACL_GET_PERM_NP 1
#define HAVE_ACL_INIT 1
#define HAVE_ACL_IS_TRIVIAL_NP 1
#define HAVE_ACL_PERMSET_T 1
#define HAVE_ACL_SET_FD 1
#define HAVE_ACL_SET_FD_NP 1
#define HAVE_ACL_SET_FILE 1
#define HAVE_ACL_SET_LINK_NP 1
#define HAVE_ACL_USER 1
#define HAVE_EXTATTR_GET_FILE 1
#define HAVE_EXTATTR_LIST_FILE 1

View File

@ -19,7 +19,8 @@ CFLAGS+= -DHAVE_LIBLZMA=1 -DHAVE_LZMA_H=1
.PATH: ${LIBARCHIVEDIR}/libarchive/test
TESTS= \
test_acl_freebsd.c \
test_acl_freebsd_nfs4.c \
test_acl_freebsd_posix1e.c \
test_acl_nfs4.c \
test_acl_pax.c \
test_acl_posix1e.c \