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:
parent
a4a16855c3
commit
10ed66fdf8
@ -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 */
|
||||
|
249
contrib/libarchive/libarchive/archive_write_disk_acl.c
Normal file
249
contrib/libarchive/libarchive/archive_write_disk_acl.c
Normal 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
|
@ -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
|
||||
/*
|
||||
|
@ -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
|
||||
|
1094
contrib/libarchive/libarchive/test/test_acl_freebsd_nfs4.c
Normal file
1094
contrib/libarchive/libarchive/test/test_acl_freebsd_nfs4.c
Normal file
File diff suppressed because it is too large
Load Diff
520
contrib/libarchive/libarchive/test/test_acl_freebsd_posix1e.c
Normal file
520
contrib/libarchive/libarchive/test/test_acl_freebsd_posix1e.c
Normal 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
|
||||
}
|
@ -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("..");
|
||||
}
|
||||
|
@ -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 \
|
||||
|
@ -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
|
||||
|
@ -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 \
|
||||
|
Loading…
Reference in New Issue
Block a user