Fix some issues with ACL handling:
* ACL storage is no longer erased before a group of entries are added. * ACL text creation no longer tries to skip over non-existent text. * UTF8 encoder no longer blows up on invalid wide characters. * Fixed ACL state management for default ACLs. Also, publicize function for obtaining text-format ACL in various formats. The interface is now extensible through a "flags" argument that allows you to select a variant format.
This commit is contained in:
parent
85d4d6aa5b
commit
08766bdf18
@ -747,7 +747,7 @@ archive_entry_acl_reset(struct archive_entry *entry, int want_type)
|
||||
entry->acl_state = ARCHIVE_ENTRY_ACL_USER_OBJ;
|
||||
else
|
||||
entry->acl_state = 0;
|
||||
entry->acl_p = NULL;
|
||||
entry->acl_p = entry->acl_head;
|
||||
return (count);
|
||||
}
|
||||
|
||||
@ -768,30 +768,34 @@ archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type,
|
||||
* (reading from list), or an entry type (retrieve that type
|
||||
* from ae_stat.st_mode).
|
||||
*/
|
||||
|
||||
if (entry->acl_state == 0)
|
||||
return (ARCHIVE_WARN);
|
||||
|
||||
if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0 &&
|
||||
entry->acl_state > 0) {
|
||||
*type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
|
||||
*tag = entry->acl_state;
|
||||
/* The first three access entries are special. */
|
||||
if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
|
||||
switch (entry->acl_state) {
|
||||
case ARCHIVE_ENTRY_ACL_USER_OBJ:
|
||||
*permset = (entry->ae_stat.st_mode >> 6) & 7;
|
||||
*type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
|
||||
*tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
|
||||
entry->acl_state = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
|
||||
break;
|
||||
return (ARCHIVE_OK);
|
||||
case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
|
||||
*permset = (entry->ae_stat.st_mode >> 3) & 7;
|
||||
*type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
|
||||
*tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
|
||||
entry->acl_state = ARCHIVE_ENTRY_ACL_OTHER;
|
||||
break;
|
||||
return (ARCHIVE_OK);
|
||||
case ARCHIVE_ENTRY_ACL_OTHER:
|
||||
*permset = entry->ae_stat.st_mode & 7;
|
||||
*type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
|
||||
*tag = ARCHIVE_ENTRY_ACL_OTHER;
|
||||
entry->acl_state = -1;
|
||||
entry->acl_p = entry->acl_head;
|
||||
return (ARCHIVE_OK);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return (ARCHIVE_OK);
|
||||
}
|
||||
|
||||
while (entry->acl_p != NULL && (entry->acl_p->type & want_type) == 0)
|
||||
@ -810,24 +814,19 @@ archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type,
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate a text version of the ACL. The format here varies
|
||||
* from POSIX.1e in a couple of useful ways:
|
||||
*
|
||||
* * An additional colon-delimited field holds the numeric uid
|
||||
* or gid. For proper archiving, it is essential to have both
|
||||
* the uname/gname and the uid/gid.
|
||||
*
|
||||
* * You can request a single text holding both access and default
|
||||
* entries. In this case, each default entry is prefixed with
|
||||
* "default:".
|
||||
* Generate a text version of the ACL. The flags parameter controls
|
||||
* the style of the generated ACL.
|
||||
*/
|
||||
const wchar_t *
|
||||
__archive_entry_acl_text_w(struct archive_entry *entry, int type)
|
||||
archive_entry_acl_text_w(struct archive_entry *entry, int flags)
|
||||
{
|
||||
int count;
|
||||
int length;
|
||||
const wchar_t *wname;
|
||||
const wchar_t *prefix;
|
||||
wchar_t separator;
|
||||
struct ae_acl *ap;
|
||||
int id;
|
||||
wchar_t *wp;
|
||||
|
||||
if (entry->acl_text_w != NULL) {
|
||||
@ -835,14 +834,15 @@ __archive_entry_acl_text_w(struct archive_entry *entry, int type)
|
||||
entry->acl_text_w = NULL;
|
||||
}
|
||||
|
||||
separator = L',';
|
||||
count = 0;
|
||||
length = 0;
|
||||
ap = entry->acl_head;
|
||||
while (ap != NULL) {
|
||||
if ((ap->type & type) != 0) {
|
||||
if ((ap->type & flags) != 0) {
|
||||
count++;
|
||||
if (type & (ARCHIVE_ENTRY_ACL_TYPE_ACCESS |
|
||||
ARCHIVE_ENTRY_ACL_TYPE_DEFAULT))
|
||||
if ((flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) &&
|
||||
(ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT))
|
||||
length += 8; /* "default:" */
|
||||
length += 5; /* tag name */
|
||||
length += 1; /* colon */
|
||||
@ -858,7 +858,7 @@ __archive_entry_acl_text_w(struct archive_entry *entry, int type)
|
||||
ap = ap->next;
|
||||
}
|
||||
|
||||
if (count > 0 && ((type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)) {
|
||||
if (count > 0 && ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0)) {
|
||||
length += 10; /* "user::rwx\n" */
|
||||
length += 11; /* "group::rwx\n" */
|
||||
length += 11; /* "other::rwx\n" */
|
||||
@ -870,7 +870,7 @@ __archive_entry_acl_text_w(struct archive_entry *entry, int type)
|
||||
/* Now, allocate the string and actually populate it. */
|
||||
wp = entry->acl_text_w = malloc(length * sizeof(wchar_t));
|
||||
count = 0;
|
||||
if ((type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
|
||||
if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
|
||||
append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL,
|
||||
entry->ae_stat.st_mode & 0700, -1);
|
||||
*wp++ = ',';
|
||||
@ -885,24 +885,39 @@ __archive_entry_acl_text_w(struct archive_entry *entry, int type)
|
||||
while (ap != NULL) {
|
||||
if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
|
||||
wname = aes_get_wcs(&ap->name);
|
||||
*wp++ = ',';
|
||||
*wp++ = separator;
|
||||
if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
|
||||
id = ap->id;
|
||||
else
|
||||
id = -1;
|
||||
append_entry_w(&wp, NULL, ap->tag, wname,
|
||||
ap->permset, ap->id);
|
||||
ap->permset, id);
|
||||
count++;
|
||||
}
|
||||
ap = ap->next;
|
||||
}
|
||||
}
|
||||
|
||||
if ((type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) {
|
||||
|
||||
if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) {
|
||||
if (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT)
|
||||
prefix = L"default:";
|
||||
else
|
||||
prefix = NULL;
|
||||
ap = entry->acl_head;
|
||||
count = 0;
|
||||
while (ap != NULL) {
|
||||
if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) {
|
||||
wname = aes_get_wcs(&ap->name);
|
||||
if (count > 0)
|
||||
*wp++ = ',';
|
||||
append_entry_w(&wp, L"default:", ap->tag,
|
||||
wname, ap->permset, ap->id);
|
||||
*wp++ = separator;
|
||||
if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
|
||||
id = ap->id;
|
||||
else
|
||||
id = -1;
|
||||
append_entry_w(&wp, prefix, ap->tag,
|
||||
wname, ap->permset, id);
|
||||
count ++;
|
||||
}
|
||||
ap = ap->next;
|
||||
}
|
||||
@ -955,9 +970,10 @@ append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
|
||||
}
|
||||
*wp += wcslen(*wp);
|
||||
*(*wp)++ = L':';
|
||||
if (wname != NULL)
|
||||
if (wname != NULL) {
|
||||
wcscpy(*wp, wname);
|
||||
*wp += wcslen(*wp);
|
||||
*wp += wcslen(*wp);
|
||||
}
|
||||
*(*wp)++ = L':';
|
||||
*(*wp)++ = (perm & 0444) ? L'r' : L'-';
|
||||
*(*wp)++ = (perm & 0222) ? L'w' : L'-';
|
||||
@ -990,8 +1006,6 @@ __archive_entry_acl_parse_w(struct archive_entry *entry,
|
||||
namebuff = NULL;
|
||||
namebuff_length = 0;
|
||||
|
||||
archive_entry_acl_clear(entry);
|
||||
|
||||
while (text != NULL && *text != L'\0') {
|
||||
next_field_w(&text, &start, &end, &sep);
|
||||
if (sep != L':')
|
||||
|
@ -167,6 +167,21 @@ int archive_entry_acl_next_w(struct archive_entry *, int want_type,
|
||||
int *type, int *permset, int *tag, int *qual,
|
||||
const wchar_t **name);
|
||||
|
||||
/*
|
||||
* Construct a text-format ACL. The flags argument is a bitmask that
|
||||
* can include any of the following:
|
||||
*
|
||||
* ARCHIVE_ENTRY_ACL_TYPE_ACCESS - Include access entries.
|
||||
* ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - Include default entries.
|
||||
* ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID - Include extra numeric ID field in
|
||||
* each ACL entry. (As used by 'star'.)
|
||||
* ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT - Include "default:" before each
|
||||
* default ACL entry.
|
||||
*/
|
||||
#define ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 1024
|
||||
#define ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 2048
|
||||
const wchar_t *archive_entry_acl_text_w(struct archive_entry *, int flags);
|
||||
|
||||
/* Return a count of entries matching 'want_type' */
|
||||
int archive_entry_acl_count(struct archive_entry *, int want_type);
|
||||
|
||||
|
@ -243,6 +243,5 @@ int __archive_read_register_compression(struct archive *a,
|
||||
*/
|
||||
int __archive_entry_acl_parse_w(struct archive_entry *,
|
||||
const wchar_t *, int type);
|
||||
const wchar_t *__archive_entry_acl_text_w(struct archive_entry *, int type);
|
||||
|
||||
#endif
|
||||
|
@ -81,7 +81,7 @@ static int mkdirpath_recursive(char *path);
|
||||
static int mksubdir(char *path);
|
||||
#ifdef HAVE_POSIX_ACL
|
||||
static int set_acl(struct archive *, struct archive_entry *,
|
||||
acl_type_t, int archive_entry_acl_type);
|
||||
acl_type_t, int archive_entry_acl_type, const char *tn);
|
||||
#endif
|
||||
static int set_acls(struct archive *, struct archive_entry *);
|
||||
static int set_extended_perm(struct archive *, struct archive_entry *,
|
||||
@ -845,18 +845,18 @@ set_acls(struct archive *a, struct archive_entry *entry)
|
||||
int ret;
|
||||
|
||||
ret = set_acl(a, entry, ACL_TYPE_ACCESS,
|
||||
ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
|
||||
ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access");
|
||||
if (ret != ARCHIVE_OK)
|
||||
return (ret);
|
||||
ret = set_acl(a, entry, ACL_TYPE_DEFAULT,
|
||||
ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
|
||||
ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default");
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
set_acl(struct archive *a, struct archive_entry *entry, acl_type_t acl_type,
|
||||
int ae_requested_type)
|
||||
int ae_requested_type, const char *typename)
|
||||
{
|
||||
acl_t acl;
|
||||
acl_entry_t acl_entry;
|
||||
@ -907,7 +907,7 @@ set_acl(struct archive *a, struct archive_entry *entry, acl_type_t acl_type,
|
||||
|
||||
name = archive_entry_pathname(entry);
|
||||
if (acl_set_file(name, acl_type, acl) != 0) {
|
||||
archive_set_error(a, errno, "Failed to set acl");
|
||||
archive_set_error(a, errno, "Failed to set %s acl", typename);
|
||||
ret = ARCHIVE_WARN;
|
||||
}
|
||||
acl_free(acl);
|
||||
|
@ -197,7 +197,9 @@ add_pax_attr_w(struct archive_string *as, const char *key, const wchar_t *wval)
|
||||
utf8len = 0;
|
||||
for (wp = wval; *wp != L'\0'; ) {
|
||||
wc = *wp++;
|
||||
if (wc <= 0x7f)
|
||||
if (wc <= 0) {
|
||||
/* Ignore negative values. */
|
||||
} else if (wc <= 0x7f)
|
||||
utf8len++;
|
||||
else if (wc <= 0x7ff)
|
||||
utf8len += 2;
|
||||
@ -214,7 +216,9 @@ add_pax_attr_w(struct archive_string *as, const char *key, const wchar_t *wval)
|
||||
utf8_value = malloc(utf8len + 1);
|
||||
for (wp = wval, p = utf8_value; *wp != L'\0'; ) {
|
||||
wc = *wp++;
|
||||
if (wc <= 0x7f) {
|
||||
if (wc <= 0) {
|
||||
/* Ignore negative values. */
|
||||
} else if (wc <= 0x7f) {
|
||||
*p++ = (char)wc;
|
||||
} else if (wc <= 0x7ff) {
|
||||
p[0] = 0xc0 | ((wc >> 6) & 0x1f);
|
||||
@ -485,16 +489,17 @@ archive_write_pax_header(struct archive *a,
|
||||
* avoid writing an mtime attribute just to handle a
|
||||
* high-resolution timestamp in "restricted pax" mode.
|
||||
*/
|
||||
if ((st_main->st_mtime < 0) || (st_main->st_mtime >= 0x7fffffff))
|
||||
if (!need_extension &&
|
||||
((st_main->st_mtime < 0) || (st_main->st_mtime >= 0x7fffffff)))
|
||||
need_extension = 1;
|
||||
|
||||
/* If there are non-trivial ACL entries, we need an extension. */
|
||||
if (archive_entry_acl_count(entry_original,
|
||||
if (!need_extension && archive_entry_acl_count(entry_original,
|
||||
ARCHIVE_ENTRY_ACL_TYPE_ACCESS) > 0)
|
||||
need_extension = 1;
|
||||
|
||||
/* If there are non-trivial ACL entries, we need an extension. */
|
||||
if (archive_entry_acl_count(entry_original,
|
||||
if (!need_extension && archive_entry_acl_count(entry_original,
|
||||
ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) > 0)
|
||||
need_extension = 1;
|
||||
|
||||
@ -530,15 +535,18 @@ archive_write_pax_header(struct archive *a,
|
||||
add_pax_attr(&(pax->pax_header), "SCHILY.fflags", p);
|
||||
|
||||
/* I use star-compatible ACL attributes. */
|
||||
wp = __archive_entry_acl_text_w(entry_original,
|
||||
ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
|
||||
wp = archive_entry_acl_text_w(entry_original,
|
||||
ARCHIVE_ENTRY_ACL_TYPE_ACCESS |
|
||||
ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID);
|
||||
if (wp != NULL && *wp != L'\0')
|
||||
add_pax_attr_w(&(pax->pax_header), "SCHILY.acl.access", wp);
|
||||
wp = __archive_entry_acl_text_w(entry_original,
|
||||
ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
|
||||
add_pax_attr_w(&(pax->pax_header),
|
||||
"SCHILY.acl.access", wp);
|
||||
wp = archive_entry_acl_text_w(entry_original,
|
||||
ARCHIVE_ENTRY_ACL_TYPE_DEFAULT |
|
||||
ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID);
|
||||
if (wp != NULL && *wp != L'\0')
|
||||
add_pax_attr_w(&(pax->pax_header), "SCHILY.acl.default",
|
||||
wp);
|
||||
add_pax_attr_w(&(pax->pax_header),
|
||||
"SCHILY.acl.default", wp);
|
||||
|
||||
/* Include star-compatible metadata info. */
|
||||
add_pax_attr_int(&(pax->pax_header), "SCHILY.dev",
|
||||
|
Loading…
Reference in New Issue
Block a user