summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorkientzle <kientzle@FreeBSD.org>2004-04-06 23:16:50 +0000
committerkientzle <kientzle@FreeBSD.org>2004-04-06 23:16:50 +0000
commitf66baeffb4a34dc9ddefcb67483fe0eeb09f56b9 (patch)
tree90b995b3e74d4ca9b699ccd90f762138f10db7b4 /lib
parent3a3d909a8cb270706cd7840fed0e6a63f046e2b4 (diff)
downloadFreeBSD-src-f66baeffb4a34dc9ddefcb67483fe0eeb09f56b9.zip
FreeBSD-src-f66baeffb4a34dc9ddefcb67483fe0eeb09f56b9.tar.gz
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.
Diffstat (limited to 'lib')
-rw-r--r--lib/libarchive/archive_entry.c84
-rw-r--r--lib/libarchive/archive_entry.h15
-rw-r--r--lib/libarchive/archive_private.h1
-rw-r--r--lib/libarchive/archive_read_extract.c10
-rw-r--r--lib/libarchive/archive_write_set_format_pax.c32
5 files changed, 89 insertions, 53 deletions
diff --git a/lib/libarchive/archive_entry.c b/lib/libarchive/archive_entry.c
index 80e3da1..6ddbd95 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 0471f01..d749e9b 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 21655e7..7cb654e 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 f1e38cf..034e5b7 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 d0cec2c..ab060fd 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",
OpenPOWER on IntegriCloud