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:
Tim Kientzle 2004-04-06 23:16:50 +00:00
parent 85d4d6aa5b
commit 08766bdf18
5 changed files with 89 additions and 53 deletions

View File

@ -747,7 +747,7 @@ archive_entry_acl_reset(struct archive_entry *entry, int want_type)
entry->acl_state = ARCHIVE_ENTRY_ACL_USER_OBJ; entry->acl_state = ARCHIVE_ENTRY_ACL_USER_OBJ;
else else
entry->acl_state = 0; entry->acl_state = 0;
entry->acl_p = NULL; entry->acl_p = entry->acl_head;
return (count); 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 * (reading from list), or an entry type (retrieve that type
* from ae_stat.st_mode). * from ae_stat.st_mode).
*/ */
if (entry->acl_state == 0) if (entry->acl_state == 0)
return (ARCHIVE_WARN); return (ARCHIVE_WARN);
if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0 && /* The first three access entries are special. */
entry->acl_state > 0) { if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
*type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
*tag = entry->acl_state;
switch (entry->acl_state) { switch (entry->acl_state) {
case ARCHIVE_ENTRY_ACL_USER_OBJ: case ARCHIVE_ENTRY_ACL_USER_OBJ:
*permset = (entry->ae_stat.st_mode >> 6) & 7; *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; entry->acl_state = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
break; return (ARCHIVE_OK);
case ARCHIVE_ENTRY_ACL_GROUP_OBJ: case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
*permset = (entry->ae_stat.st_mode >> 3) & 7; *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; entry->acl_state = ARCHIVE_ENTRY_ACL_OTHER;
break; return (ARCHIVE_OK);
case ARCHIVE_ENTRY_ACL_OTHER: case ARCHIVE_ENTRY_ACL_OTHER:
*permset = entry->ae_stat.st_mode & 7; *permset = entry->ae_stat.st_mode & 7;
*type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
*tag = ARCHIVE_ENTRY_ACL_OTHER;
entry->acl_state = -1; entry->acl_state = -1;
entry->acl_p = entry->acl_head; entry->acl_p = entry->acl_head;
return (ARCHIVE_OK);
default:
break; break;
} }
return (ARCHIVE_OK);
} }
while (entry->acl_p != NULL && (entry->acl_p->type & want_type) == 0) 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 * Generate a text version of the ACL. The flags parameter controls
* from POSIX.1e in a couple of useful ways: * the style of the generated ACL.
*
* * 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:".
*/ */
const wchar_t * 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 count;
int length; int length;
const wchar_t *wname; const wchar_t *wname;
const wchar_t *prefix;
wchar_t separator;
struct ae_acl *ap; struct ae_acl *ap;
int id;
wchar_t *wp; wchar_t *wp;
if (entry->acl_text_w != NULL) { 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; entry->acl_text_w = NULL;
} }
separator = L',';
count = 0; count = 0;
length = 0; length = 0;
ap = entry->acl_head; ap = entry->acl_head;
while (ap != NULL) { while (ap != NULL) {
if ((ap->type & type) != 0) { if ((ap->type & flags) != 0) {
count++; count++;
if (type & (ARCHIVE_ENTRY_ACL_TYPE_ACCESS | if ((flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) &&
ARCHIVE_ENTRY_ACL_TYPE_DEFAULT)) (ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT))
length += 8; /* "default:" */ length += 8; /* "default:" */
length += 5; /* tag name */ length += 5; /* tag name */
length += 1; /* colon */ length += 1; /* colon */
@ -858,7 +858,7 @@ __archive_entry_acl_text_w(struct archive_entry *entry, int type)
ap = ap->next; 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 += 10; /* "user::rwx\n" */
length += 11; /* "group::rwx\n" */ length += 11; /* "group::rwx\n" */
length += 11; /* "other::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. */ /* Now, allocate the string and actually populate it. */
wp = entry->acl_text_w = malloc(length * sizeof(wchar_t)); wp = entry->acl_text_w = malloc(length * sizeof(wchar_t));
count = 0; 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, append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL,
entry->ae_stat.st_mode & 0700, -1); entry->ae_stat.st_mode & 0700, -1);
*wp++ = ','; *wp++ = ',';
@ -885,24 +885,39 @@ __archive_entry_acl_text_w(struct archive_entry *entry, int type)
while (ap != NULL) { while (ap != NULL) {
if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
wname = aes_get_wcs(&ap->name); 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, append_entry_w(&wp, NULL, ap->tag, wname,
ap->permset, ap->id); ap->permset, id);
count++; count++;
} }
ap = ap->next; 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; ap = entry->acl_head;
count = 0;
while (ap != NULL) { while (ap != NULL) {
if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) { if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) {
wname = aes_get_wcs(&ap->name); wname = aes_get_wcs(&ap->name);
if (count > 0) if (count > 0)
*wp++ = ','; *wp++ = separator;
append_entry_w(&wp, L"default:", ap->tag, if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
wname, ap->permset, ap->id); id = ap->id;
else
id = -1;
append_entry_w(&wp, prefix, ap->tag,
wname, ap->permset, id);
count ++;
} }
ap = ap->next; ap = ap->next;
} }
@ -955,9 +970,10 @@ append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
} }
*wp += wcslen(*wp); *wp += wcslen(*wp);
*(*wp)++ = L':'; *(*wp)++ = L':';
if (wname != NULL) if (wname != NULL) {
wcscpy(*wp, wname); wcscpy(*wp, wname);
*wp += wcslen(*wp); *wp += wcslen(*wp);
}
*(*wp)++ = L':'; *(*wp)++ = L':';
*(*wp)++ = (perm & 0444) ? L'r' : L'-'; *(*wp)++ = (perm & 0444) ? L'r' : L'-';
*(*wp)++ = (perm & 0222) ? L'w' : L'-'; *(*wp)++ = (perm & 0222) ? L'w' : L'-';
@ -990,8 +1006,6 @@ __archive_entry_acl_parse_w(struct archive_entry *entry,
namebuff = NULL; namebuff = NULL;
namebuff_length = 0; namebuff_length = 0;
archive_entry_acl_clear(entry);
while (text != NULL && *text != L'\0') { while (text != NULL && *text != L'\0') {
next_field_w(&text, &start, &end, &sep); next_field_w(&text, &start, &end, &sep);
if (sep != L':') if (sep != L':')

View File

@ -167,6 +167,21 @@ int archive_entry_acl_next_w(struct archive_entry *, int want_type,
int *type, int *permset, int *tag, int *qual, int *type, int *permset, int *tag, int *qual,
const wchar_t **name); 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' */ /* Return a count of entries matching 'want_type' */
int archive_entry_acl_count(struct archive_entry *, int want_type); int archive_entry_acl_count(struct archive_entry *, int want_type);

View File

@ -243,6 +243,5 @@ int __archive_read_register_compression(struct archive *a,
*/ */
int __archive_entry_acl_parse_w(struct archive_entry *, int __archive_entry_acl_parse_w(struct archive_entry *,
const wchar_t *, int type); const wchar_t *, int type);
const wchar_t *__archive_entry_acl_text_w(struct archive_entry *, int type);
#endif #endif

View File

@ -81,7 +81,7 @@ static int mkdirpath_recursive(char *path);
static int mksubdir(char *path); static int mksubdir(char *path);
#ifdef HAVE_POSIX_ACL #ifdef HAVE_POSIX_ACL
static int set_acl(struct archive *, struct archive_entry *, 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 #endif
static int set_acls(struct archive *, struct archive_entry *); static int set_acls(struct archive *, struct archive_entry *);
static int set_extended_perm(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; int ret;
ret = set_acl(a, entry, ACL_TYPE_ACCESS, ret = set_acl(a, entry, ACL_TYPE_ACCESS,
ARCHIVE_ENTRY_ACL_TYPE_ACCESS); ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access");
if (ret != ARCHIVE_OK) if (ret != ARCHIVE_OK)
return (ret); return (ret);
ret = set_acl(a, entry, ACL_TYPE_DEFAULT, ret = set_acl(a, entry, ACL_TYPE_DEFAULT,
ARCHIVE_ENTRY_ACL_TYPE_DEFAULT); ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default");
return (ret); return (ret);
} }
static int static int
set_acl(struct archive *a, struct archive_entry *entry, acl_type_t acl_type, 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_t acl;
acl_entry_t acl_entry; 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); name = archive_entry_pathname(entry);
if (acl_set_file(name, acl_type, acl) != 0) { 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; ret = ARCHIVE_WARN;
} }
acl_free(acl); acl_free(acl);

View File

@ -197,7 +197,9 @@ add_pax_attr_w(struct archive_string *as, const char *key, const wchar_t *wval)
utf8len = 0; utf8len = 0;
for (wp = wval; *wp != L'\0'; ) { for (wp = wval; *wp != L'\0'; ) {
wc = *wp++; wc = *wp++;
if (wc <= 0x7f) if (wc <= 0) {
/* Ignore negative values. */
} else if (wc <= 0x7f)
utf8len++; utf8len++;
else if (wc <= 0x7ff) else if (wc <= 0x7ff)
utf8len += 2; 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); utf8_value = malloc(utf8len + 1);
for (wp = wval, p = utf8_value; *wp != L'\0'; ) { for (wp = wval, p = utf8_value; *wp != L'\0'; ) {
wc = *wp++; wc = *wp++;
if (wc <= 0x7f) { if (wc <= 0) {
/* Ignore negative values. */
} else if (wc <= 0x7f) {
*p++ = (char)wc; *p++ = (char)wc;
} else if (wc <= 0x7ff) { } else if (wc <= 0x7ff) {
p[0] = 0xc0 | ((wc >> 6) & 0x1f); 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 * avoid writing an mtime attribute just to handle a
* high-resolution timestamp in "restricted pax" mode. * 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; need_extension = 1;
/* If there are non-trivial ACL entries, we need an extension. */ /* 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) ARCHIVE_ENTRY_ACL_TYPE_ACCESS) > 0)
need_extension = 1; need_extension = 1;
/* If there are non-trivial ACL entries, we need an extension. */ /* 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) ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) > 0)
need_extension = 1; need_extension = 1;
@ -530,15 +535,18 @@ archive_write_pax_header(struct archive *a,
add_pax_attr(&(pax->pax_header), "SCHILY.fflags", p); add_pax_attr(&(pax->pax_header), "SCHILY.fflags", p);
/* I use star-compatible ACL attributes. */ /* I use star-compatible ACL attributes. */
wp = __archive_entry_acl_text_w(entry_original, wp = archive_entry_acl_text_w(entry_original,
ARCHIVE_ENTRY_ACL_TYPE_ACCESS); ARCHIVE_ENTRY_ACL_TYPE_ACCESS |
ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID);
if (wp != NULL && *wp != L'\0') if (wp != NULL && *wp != L'\0')
add_pax_attr_w(&(pax->pax_header), "SCHILY.acl.access", wp); add_pax_attr_w(&(pax->pax_header),
wp = __archive_entry_acl_text_w(entry_original, "SCHILY.acl.access", wp);
ARCHIVE_ENTRY_ACL_TYPE_DEFAULT); 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') if (wp != NULL && *wp != L'\0')
add_pax_attr_w(&(pax->pax_header), "SCHILY.acl.default", add_pax_attr_w(&(pax->pax_header),
wp); "SCHILY.acl.default", wp);
/* Include star-compatible metadata info. */ /* Include star-compatible metadata info. */
add_pax_attr_int(&(pax->pax_header), "SCHILY.dev", add_pax_attr_int(&(pax->pax_header), "SCHILY.dev",