diff options
author | Tim Kientzle <kientzle@FreeBSD.org> | 2004-04-06 23:16:50 +0000 |
---|---|---|
committer | Tim Kientzle <kientzle@FreeBSD.org> | 2004-04-06 23:16:50 +0000 |
commit | 08766bdf1831e5befd0757e36557eb6fdffbc35d (patch) | |
tree | 90b995b3e74d4ca9b699ccd90f762138f10db7b4 | |
parent | 85d4d6aa5bd7ed0783191fb8c1a7b6a038b54e79 (diff) |
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.
Notes
Notes:
svn path=/head/; revision=127971
-rw-r--r-- | lib/libarchive/archive_entry.c | 84 | ||||
-rw-r--r-- | lib/libarchive/archive_entry.h | 15 | ||||
-rw-r--r-- | lib/libarchive/archive_private.h | 1 | ||||
-rw-r--r-- | lib/libarchive/archive_read_extract.c | 10 | ||||
-rw-r--r-- | lib/libarchive/archive_write_set_format_pax.c | 32 |
5 files changed, 89 insertions, 53 deletions
diff --git a/lib/libarchive/archive_entry.c b/lib/libarchive/archive_entry.c index 80e3da1c5afc..6ddbd959a97c 100644 --- a/lib/libarchive/archive_entry.c +++ b/lib/libarchive/archive_entry.c @@ -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':') diff --git a/lib/libarchive/archive_entry.h b/lib/libarchive/archive_entry.h index 0471f011fe1b..d749e9b7ac87 100644 --- a/lib/libarchive/archive_entry.h +++ b/lib/libarchive/archive_entry.h @@ -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); diff --git a/lib/libarchive/archive_private.h b/lib/libarchive/archive_private.h index 21655e7a2614..7cb654ed5e97 100644 --- a/lib/libarchive/archive_private.h +++ b/lib/libarchive/archive_private.h @@ -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 diff --git a/lib/libarchive/archive_read_extract.c b/lib/libarchive/archive_read_extract.c index f1e38cf7377c..034e5b7e0880 100644 --- a/lib/libarchive/archive_read_extract.c +++ b/lib/libarchive/archive_read_extract.c @@ -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); diff --git a/lib/libarchive/archive_write_set_format_pax.c b/lib/libarchive/archive_write_set_format_pax.c index d0cec2c16a0b..ab060fd50726 100644 --- a/lib/libarchive/archive_write_set_format_pax.c +++ b/lib/libarchive/archive_write_set_format_pax.c @@ -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", |