]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
Add an mbs version of ACL control functions in order to reduce
authorMichihiro NAKAJIMA <ggcueroad@gmail.com>
Fri, 25 Mar 2011 09:36:27 +0000 (05:36 -0400)
committerMichihiro NAKAJIMA <ggcueroad@gmail.com>
Fri, 25 Mar 2011 09:36:27 +0000 (05:36 -0400)
extra character conversion.
  previous:
    Create : Disk -> MBS -> WCS -> MBS -> UTF-8 -> Pax archive file.
    Extract: Pax archive file -> UTF-8 -> MBS -> WCS ->MBS -> Disk.

  after:
    Create : Disk -> MBS -> UTF-8 -> Pax archive file.
    Extract: Pax archive file -> UTF-8 -> MBS -> Disk.

SVN-Revision: 3073

libarchive/archive_acl.c
libarchive/archive_acl_private.h
libarchive/archive_entry.c
libarchive/archive_entry.h
libarchive/archive_read_support_format_tar.c
libarchive/archive_string.c
libarchive/archive_string.h
libarchive/archive_write_set_format_pax.c

index c01372182182b553b32bedc34a84ca5fcd4b02e9..57703964855fac6740b07fe319b5e00be1dd169a 100644 (file)
@@ -58,6 +58,15 @@ static int   prefix_w(const wchar_t *start, const wchar_t *end,
 static void    append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
                    const wchar_t *wname, int perm, int id);
 static void    append_id_w(wchar_t **wp, int id);
+static int     isint(const char *start, const char *end, int *result);
+static int     ismode(const char *start, const char *end, int *result);
+static void    next_field(const char **p, const char **start,
+                   const char **end, char *sep);
+static int     prefix(const char *start, const char *end,
+                   const char *test);
+static void    append_entry(char **p, const char *prefix, int tag,
+                   const char *name, int perm, int id);
+static void    append_id(char **p, int id);
 
 void
 archive_acl_clear(struct archive_acl *acl)
@@ -74,6 +83,10 @@ archive_acl_clear(struct archive_acl *acl)
                free(acl->acl_text_w);
                acl->acl_text_w = NULL;
        }
+       if (acl->acl_text != NULL) {
+               free(acl->acl_text);
+               acl->acl_text = NULL;
+       }
        acl->acl_p = NULL;
        acl->acl_state = 0; /* Not counting. */
 }
@@ -136,6 +149,26 @@ archive_acl_add_entry_w_len(struct archive_acl *acl,
        return ARCHIVE_OK;
 }
 
+int
+archive_acl_add_entry_len(struct archive_acl *acl,
+    int type, int permset, int tag, int id, const char *name, size_t len)
+{
+       struct archive_acl_entry *ap;
+
+       if (acl_special(acl, type, permset, tag) == 0)
+               return ARCHIVE_OK;
+       ap = acl_new_entry(acl, type, permset, tag, id);
+       if (ap == NULL) {
+               /* XXX Error XXX */
+               return ARCHIVE_FAILED;
+       }
+       if (name != NULL  &&  *name != '\0' && len > 0)
+               archive_mstring_copy_mbs_len(&ap->name, name, len);
+       else
+               archive_mstring_clean(&ap->name);
+       return ARCHIVE_OK;
+}
+
 /*
  * If this ACL entry is part of the standard POSIX permissions set,
  * store the permissions in the stat structure and return zero.
@@ -226,6 +259,10 @@ acl_new_entry(struct archive_acl *acl,
                free(acl->acl_text_w);
                acl->acl_text_w = NULL;
        }
+       if (acl->acl_text != NULL) {
+               free(acl->acl_text);
+               acl->acl_text = NULL;
+       }
 
        /* If there's a matching entry already in the list, overwrite it. */
        ap = acl->acl_head;
@@ -558,6 +595,184 @@ append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag,
        **wp = L'\0';
 }
 
+const char *
+archive_acl_text(struct archive *a, struct archive_acl *acl, int flags)
+{
+       int count;
+       size_t length;
+       const char *name;
+       const char *prefix;
+       char separator;
+       struct archive_acl_entry *ap;
+       int id;
+       char *p;
+
+       if (acl->acl_text != NULL) {
+               free (acl->acl_text);
+               acl->acl_text = NULL;
+       }
+
+       separator = ',';
+       count = 0;
+       length = 0;
+       ap = acl->acl_head;
+       while (ap != NULL) {
+               if ((ap->type & flags) != 0) {
+                       count++;
+                       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 */
+                       name = archive_mstring_get_mbs(a, &ap->name);
+                       if (name != NULL)
+                               length += strlen(name);
+                       else
+                               length += sizeof(uid_t) * 3 + 1;
+                       length ++; /* colon */
+                       length += 3; /* rwx */
+                       length += 1; /* colon */
+                       length += max(sizeof(uid_t), sizeof(gid_t)) * 3 + 1;
+                       length ++; /* newline */
+               }
+               ap = ap->next;
+       }
+
+       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" */
+       }
+
+       if (count == 0)
+               return (NULL);
+
+       /* Now, allocate the string and actually populate it. */
+       p = acl->acl_text = (char *)malloc(length);
+       if (p == NULL)
+               __archive_errx(1, "No memory to generate the text version of the ACL");
+       count = 0;
+       if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
+               append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL,
+                   acl->mode & 0700, -1);
+               *p++ = ',';
+               append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_GROUP_OBJ, NULL,
+                   acl->mode & 0070, -1);
+               *p++ = ',';
+               append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_OTHER, NULL,
+                   acl->mode & 0007, -1);
+               count += 3;
+
+               ap = acl->acl_head;
+               while (ap != NULL) {
+                       if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
+                               name = archive_mstring_get_mbs(a, &ap->name);
+                               *p++ = separator;
+                               if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
+                                       id = ap->id;
+                               else
+                                       id = -1;
+                               append_entry(&p, NULL, ap->tag, name,
+                                   ap->permset, id);
+                               count++;
+                       }
+                       ap = ap->next;
+               }
+       }
+
+
+       if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) {
+               if (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT)
+                       prefix = "default:";
+               else
+                       prefix = NULL;
+               ap = acl->acl_head;
+               count = 0;
+               while (ap != NULL) {
+                       if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) {
+                               name = archive_mstring_get_mbs(a, &ap->name);
+                               if (count > 0)
+                                       *p++ = separator;
+                               if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
+                                       id = ap->id;
+                               else
+                                       id = -1;
+                               append_entry(&p, prefix, ap->tag,
+                                   name, ap->permset, id);
+                               count ++;
+                       }
+                       ap = ap->next;
+               }
+       }
+
+       return (acl->acl_text);
+}
+
+static void
+append_id(char **p, int id)
+{
+       if (id < 0)
+               id = 0;
+       if (id > 9)
+               append_id(p, id / 10);
+       *(*p)++ = "0123456789"[id % 10];
+}
+
+static void
+append_entry(char **p, const char *prefix, int tag,
+    const char *name, int perm, int id)
+{
+       if (prefix != NULL) {
+               strcpy(*p, prefix);
+               *p += strlen(*p);
+       }
+       switch (tag) {
+       case ARCHIVE_ENTRY_ACL_USER_OBJ:
+               name = NULL;
+               id = -1;
+               /* FALLTHROUGH */
+       case ARCHIVE_ENTRY_ACL_USER:
+               strcpy(*p, "user");
+               break;
+       case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+               name = NULL;
+               id = -1;
+               /* FALLTHROUGH */
+       case ARCHIVE_ENTRY_ACL_GROUP:
+               strcpy(*p, "group");
+               break;
+       case ARCHIVE_ENTRY_ACL_MASK:
+               strcpy(*p, "mask");
+               name = NULL;
+               id = -1;
+               break;
+       case ARCHIVE_ENTRY_ACL_OTHER:
+               strcpy(*p, "other");
+               name = NULL;
+               id = -1;
+               break;
+       }
+       *p += strlen(*p);
+       *(*p)++ = ':';
+       if (name != NULL) {
+               strcpy(*p, name);
+               *p += strlen(*p);
+       } else if (tag == ARCHIVE_ENTRY_ACL_USER
+           || tag == ARCHIVE_ENTRY_ACL_GROUP) {
+               append_id(p, id);
+               id = -1;
+       }
+       *(*p)++ = ':';
+       *(*p)++ = (perm & 0444) ? 'r' : '-';
+       *(*p)++ = (perm & 0222) ? 'w' : '-';
+       *(*p)++ = (perm & 0111) ? 'x' : '-';
+       if (id != -1) {
+               *(*p)++ = ':';
+               append_id(p, id);
+       }
+       **p = '\0';
+}
+
 /*
  * Parse a textual ACL.  This automatically recognizes and supports
  * extensions described above.  The 'type' argument is used to
@@ -787,3 +1002,232 @@ prefix_w(const wchar_t *start, const wchar_t *end, const wchar_t *test)
 
        return (1);
 }
+
+/*
+ * Parse a textual ACL.  This automatically recognizes and supports
+ * extensions described above.  The 'type' argument is used to
+ * indicate the type that should be used for any entries not
+ * explicitly marked as "default:".
+ */
+int
+archive_acl_parse(struct archive_acl *acl,
+    const char *text, int default_type)
+{
+       struct {
+               const char *start;
+               const char *end;
+       } field[4], name;
+
+       int fields, n;
+       int type, tag, permset, id;
+       char sep;
+
+       while (text != NULL  &&  *text != '\0') {
+               /*
+                * Parse the fields out of the next entry,
+                * advance 'text' to start of next entry.
+                */
+               fields = 0;
+               do {
+                       const char *start, *end;
+                       next_field(&text, &start, &end, &sep);
+                       if (fields < 4) {
+                               field[fields].start = start;
+                               field[fields].end = end;
+                       }
+                       ++fields;
+               } while (sep == ':');
+
+               /* Set remaining fields to blank. */
+               for (n = fields; n < 4; ++n)
+                       field[n].start = field[n].end = NULL;
+
+               /* Check for a numeric ID in field 1 or 3. */
+               id = -1;
+               isint(field[1].start, field[1].end, &id);
+               /* Field 3 is optional. */
+               if (id == -1 && fields > 3)
+                       isint(field[3].start, field[3].end, &id);
+
+               /*
+                * Solaris extension:  "defaultuser::rwx" is the
+                * default ACL corresponding to "user::rwx", etc.
+                */
+               if (field[0].end - field[0].start > 7
+                   && memcmp(field[0].start, "default", 7) == 0) {
+                       type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT;
+                       field[0].start += 7;
+               } else
+                       type = default_type;
+
+               name.start = name.end = NULL;
+               if (prefix(field[0].start, field[0].end, "user")) {
+                       if (!ismode(field[2].start, field[2].end, &permset))
+                               return (ARCHIVE_WARN);
+                       if (id != -1 || field[1].start < field[1].end) {
+                               tag = ARCHIVE_ENTRY_ACL_USER;
+                               name = field[1];
+                       } else
+                               tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
+               } else if (prefix(field[0].start, field[0].end, "group")) {
+                       if (!ismode(field[2].start, field[2].end, &permset))
+                               return (ARCHIVE_WARN);
+                       if (id != -1 || field[1].start < field[1].end) {
+                               tag = ARCHIVE_ENTRY_ACL_GROUP;
+                               name = field[1];
+                       } else
+                               tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
+               } else if (prefix(field[0].start, field[0].end, "other")) {
+                       if (fields == 2
+                           && field[1].start < field[1].end
+                           && ismode(field[1].start, field[1].end, &permset)) {
+                               /* This is Solaris-style "other:rwx" */
+                       } else if (fields == 3
+                           && field[1].start == field[1].end
+                           && field[2].start < field[2].end
+                           && ismode(field[2].start, field[2].end, &permset)) {
+                               /* This is FreeBSD-style "other::rwx" */
+                       } else
+                               return (ARCHIVE_WARN);
+                       tag = ARCHIVE_ENTRY_ACL_OTHER;
+               } else if (prefix(field[0].start, field[0].end, "mask")) {
+                       if (fields == 2
+                           && field[1].start < field[1].end
+                           && ismode(field[1].start, field[1].end, &permset)) {
+                               /* This is Solaris-style "mask:rwx" */
+                       } else if (fields == 3
+                           && field[1].start == field[1].end
+                           && field[2].start < field[2].end
+                           && ismode(field[2].start, field[2].end, &permset)) {
+                               /* This is FreeBSD-style "mask::rwx" */
+                       } else
+                               return (ARCHIVE_WARN);
+                       tag = ARCHIVE_ENTRY_ACL_MASK;
+               } else
+                       return (ARCHIVE_WARN);
+
+               /* Add entry to the internal list. */
+               archive_acl_add_entry_len(acl, type, permset,
+                   tag, id, name.start, name.end - name.start);
+       }
+       return (ARCHIVE_OK);
+}
+
+/*
+ * Parse a string to a positive decimal integer.  Returns true if
+ * the string is non-empty and consists only of decimal digits,
+ * false otherwise.
+ */
+static int
+isint(const char *start, const char *end, int *result)
+{
+       int n = 0;
+       if (start >= end)
+               return (0);
+       while (start < end) {
+               if (*start < '0' || *start > '9')
+                       return (0);
+               if (n > (INT_MAX / 10) ||
+                   (n == INT_MAX / 10 && (*start - '0') > INT_MAX % 10)) {
+                       n = INT_MAX;
+               } else {
+                       n *= 10;
+                       n += *start - '0';
+               }
+               start++;
+       }
+       *result = n;
+       return (1);
+}
+
+/*
+ * Parse a string as a mode field.  Returns true if
+ * the string is non-empty and consists only of mode characters,
+ * false otherwise.
+ */
+static int
+ismode(const char *start, const char *end, int *permset)
+{
+       const char *p;
+
+       if (start >= end)
+               return (0);
+       p = start;
+       *permset = 0;
+       while (p < end) {
+               switch (*p++) {
+               case 'r': case 'R':
+                       *permset |= ARCHIVE_ENTRY_ACL_READ;
+                       break;
+               case 'w': case 'W':
+                       *permset |= ARCHIVE_ENTRY_ACL_WRITE;
+                       break;
+               case 'x': case 'X':
+                       *permset |= ARCHIVE_ENTRY_ACL_EXECUTE;
+                       break;
+               case '-':
+                       break;
+               default:
+                       return (0);
+               }
+       }
+       return (1);
+}
+
+/*
+ * Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]".  *wp is updated
+ * to point to just after the separator.  *start points to the first
+ * character of the matched text and *end just after the last
+ * character of the matched identifier.  In particular *end - *start
+ * is the length of the field body, not including leading or trailing
+ * whitespace.
+ */
+static void
+next_field(const char **p, const char **start,
+    const char **end, char *sep)
+{
+       /* Skip leading whitespace to find start of field. */
+       while (**p == ' ' || **p == '\t' || **p == '\n') {
+               (*p)++;
+       }
+       *start = *p;
+
+       /* Scan for the separator. */
+       while (**p != '\0' && **p != ',' && **p != ':' && **p != '\n') {
+               (*p)++;
+       }
+       *sep = **p;
+
+       /* Trim trailing whitespace to locate end of field. */
+       *end = *p - 1;
+       while (**end == ' ' || **end == '\t' || **end == '\n') {
+               (*end)--;
+       }
+       (*end)++;
+
+       /* Adjust scanner location. */
+       if (**p != '\0')
+               (*p)++;
+}
+
+/*
+ * Return true if the characters [start...end) are a prefix of 'test'.
+ * This makes it easy to handle the obvious abbreviations: 'u' for 'user', etc.
+ */
+static int
+prefix(const char *start, const char *end, const char *test)
+{
+       if (start == end)
+               return (0);
+
+       if (*start++ != *test++)
+               return (0);
+
+       while (start < end  &&  *start++ == *test++)
+               ;
+
+       if (start < end)
+               return (0);
+
+       return (1);
+}
index 4a967a8540ba82b58ec78199bc82f395a4a5014e..da78333f75d4c2ddc915d938b0459a79dd0e7550 100644 (file)
@@ -49,6 +49,7 @@ struct archive_acl {
        struct archive_acl_entry        *acl_p;
        int              acl_state;     /* See acl_next for details. */
        wchar_t         *acl_text_w;
+       char            *acl_text;
        int              acl_types;
 };
 
@@ -62,8 +63,11 @@ int archive_acl_next(struct archive *, struct archive_acl *, int,
 int archive_acl_add_entry(struct archive_acl *, int, int, int, int, const char *);
 int archive_acl_add_entry_w_len(struct archive_acl *,
     int, int, int, int, const wchar_t *, size_t);
+int archive_acl_add_entry_len(struct archive_acl *,
+    int, int, int, int, const char *, size_t);
 
 const wchar_t *archive_acl_text_w(struct archive *, struct archive_acl *, int);
+const char *archive_acl_text(struct archive *, struct archive_acl *, int);
 
 /*
  * Private ACL parser.  This is private because it handles some
@@ -75,5 +79,7 @@ const wchar_t *archive_acl_text_w(struct archive *, struct archive_acl *, int);
  */
 int archive_acl_parse_w(struct archive_acl *,
                    const wchar_t *, int /* type */);
+int archive_acl_parse(struct archive_acl *,
+                   const char *, int /* type */);
 
 #endif /* ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */
index 17ba5b64874a566f41ceee7964fcb073f8d4924f..deb0abedc01ee9e6efd92f27dcdd55f795326a97 100644 (file)
@@ -1119,6 +1119,12 @@ archive_entry_acl_text_w(struct archive_entry *entry, int flags)
        return archive_acl_text_w(entry->archive, &entry->acl, flags);
 }
 
+const char *
+archive_entry_acl_text(struct archive_entry *entry, int flags)
+{
+       return archive_acl_text(entry->archive, &entry->acl, flags);
+}
+
 /*
  * Following code is modified from UC Berkeley sources, and
  * is subject to the following copyright notice.
index c2b9d6f6c079609d0b76257801e1d15d96310e3a..905598b784da4d58202d04a4fa4d994f37e765f3 100644 (file)
@@ -505,6 +505,8 @@ __LA_DECL int        archive_entry_acl_next_w(struct archive_entry *, int /* want_type
 #define        ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT    2048
 __LA_DECL const wchar_t        *archive_entry_acl_text_w(struct archive_entry *,
                    int /* flags */);
+__LA_DECL const char *archive_entry_acl_text(struct archive_entry *,
+                   int /* flags */);
 
 /* Return a count of entries matching 'want_type' */
 __LA_DECL int   archive_entry_acl_count(struct archive_entry *, int /* want_type */);
index 46c0beab5377d2c247ee8d5a4da5f216005ac107..33af3d4acc70cf3c8f4b71d3094f4701f23fedeb 100644 (file)
@@ -142,7 +142,6 @@ struct tar {
        int                      sparse_gnu_minor;
        char                     sparse_gnu_pending;
 
-       struct archive_wstring   wacl;
        struct archive_string    localname;
        struct archive_string    opt_charset;
        struct archive_string    hdr_charset;
@@ -273,7 +272,6 @@ archive_read_format_tar_cleanup(struct archive_read *a)
        archive_string_free(&tar->opt_charset);
        archive_string_free(&tar->hdr_charset);
        archive_string_free(&tar->localname);
-       archive_wstring_free(&tar->wacl);
        free(tar);
        (a->format->data) = NULL;
        return (ARCHIVE_OK);
@@ -888,15 +886,8 @@ header_Solaris_ACL(struct archive_read *a, struct tar *tar,
                    "Malformed Solaris ACL attribute (unconvertible)");
                return(ARCHIVE_WARN);
        }
-       archive_wstring_empty(&(tar->wacl));
-       if (archive_wstring_append_from_mbs(&(a->archive), &(tar->wacl),
-           tar->localname.s, tar->localname.length) != 0) {
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-                   "Malformed Solaris ACL attribute (unconvertible)");
-               return(ARCHIVE_WARN);
-       }
-       err = archive_acl_parse_w(archive_entry_acl(entry), tar->wacl.s,
-           ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
+       err = archive_acl_parse(archive_entry_acl(entry),
+           tar->localname.s, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
        if (err != ARCHIVE_OK)
                archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
                    "Malformed Solaris ACL attribute (unparsable)");
@@ -1692,20 +1683,10 @@ pax_attribute(struct archive_read *a, struct tar *tar,
                                    ARCHIVE_ERRNO_FILE_FORMAT,
                                    "SCHILY.acl.access can't be converted "
                                    "from UTF-8 to current locale.");
-                       }
-                       archive_wstring_empty(&(tar->wacl));
-                       if (archive_wstring_append_from_mbs(
-                           &(a->archive), &(tar->wacl), tar->localname.s,
-                           tar->localname.length) != 0) {
-                               err = ARCHIVE_WARN;
-                               archive_set_error(&a->archive,
-                                    ARCHIVE_ERRNO_FILE_FORMAT,
-                                   "SCHILY.acl.access can't be converted"
-                                   " to wide-character.");
-                       } else {
-                               archive_acl_parse_w(archive_entry_acl(entry),
-                                   tar->wacl.s, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
-                       }
+                       } else
+                               archive_acl_parse(archive_entry_acl(entry),
+                                   tar->localname.s,
+                                   ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
                } else if (strcmp(key, "SCHILY.acl.default")==0) {
                        if (archive_strcpy_from_locale(&(a->archive),
                            &(tar->localname), value, "UTF-8") != 0) {
@@ -1714,20 +1695,10 @@ pax_attribute(struct archive_read *a, struct tar *tar,
                                    ARCHIVE_ERRNO_FILE_FORMAT,
                                    "SCHILY.acl.default can't be converted "
                                    "from UTF-8 to current locale.");
-                       }
-                       archive_wstring_empty(&(tar->wacl));
-                       if (archive_wstring_append_from_mbs(
-                           &(a->archive), &(tar->wacl), tar->localname.s,
-                           tar->localname.length) != 0) {
-                               err = ARCHIVE_WARN;
-                               archive_set_error(&a->archive,
-                                    ARCHIVE_ERRNO_FILE_FORMAT,
-                                   "SCHILY.acl.default can't be converted"
-                                   " to wide-character.");
-                       } else {
-                               archive_acl_parse_w(archive_entry_acl(entry),
-                                   tar->wacl.s, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
-                       }
+                       } else
+                               archive_acl_parse(archive_entry_acl(entry),
+                                   tar->localname.s,
+                                   ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
                } else if (strcmp(key, "SCHILY.devmajor")==0) {
                        archive_entry_set_rdevmajor(entry,
                            tar_atol10(value, strlen(value)));
index f8c011eae7af69fd4c42f7ce474e39f08ac66fb2..739990949a55c39bb47fafed2d92ee8b01ec9b85 100644 (file)
@@ -1812,13 +1812,24 @@ archive_mstring_get_wcs(struct archive *a, struct archive_mstring *aes)
 
 int
 archive_mstring_copy_mbs(struct archive_mstring *aes, const char *mbs)
+{
+       if (mbs == NULL) {
+               aes->aes_set = 0;
+               return (0);
+       }
+       return (archive_mstring_copy_mbs_len(aes, mbs, strlen(mbs)));
+}
+
+int
+archive_mstring_copy_mbs_len(struct archive_mstring *aes, const char *mbs,
+    size_t len)
 {
        if (mbs == NULL) {
                aes->aes_set = 0;
                return (0);
        }
        aes->aes_set = AES_SET_MBS; /* Only MBS form is set now. */
-       archive_strcpy(&(aes->aes_mbs), mbs);
+       archive_strncpy(&(aes->aes_mbs), mbs, len);
        archive_string_empty(&(aes->aes_utf8));
        archive_wstring_empty(&(aes->aes_wcs));
        return (0);
index 80307e528c39320c318a3b07fc377010bbae928c..4c778805f4410206cf076810932a332d3a9ceff0 100644 (file)
@@ -226,6 +226,8 @@ const char *        archive_mstring_get_mbs(struct archive *, struct archive_mstring *)
 const char *   archive_mstring_get_utf8(struct archive *, struct archive_mstring *);
 const wchar_t *        archive_mstring_get_wcs(struct archive *, struct archive_mstring *);
 int    archive_mstring_copy_mbs(struct archive_mstring *, const char *mbs);
+int    archive_mstring_copy_mbs_len(struct archive_mstring *, const char *mbs,
+           size_t);
 int    archive_mstring_copy_utf8(struct archive_mstring *, const char *utf8);
 int    archive_mstring_copy_wcs(struct archive_mstring *, const wchar_t *wcs);
 int    archive_mstring_copy_wcs_len(struct archive_mstring *, const wchar_t *wcs, size_t);
index 8507f6a8359b231f732f093ffd1b15d5779dcbe4..322223b400e73c6857cf4789d349c1d2ff6309a2 100644 (file)
@@ -57,7 +57,6 @@ struct pax {
        struct archive_string   l_gname;
        struct archive_string   l_linkpath;
        struct archive_string   l_url_encoded_name;
-       struct archive_string   l_acl_mbs;
        struct archive_string   l_acl_utf8;
        struct archive_string   pax_header;
        struct archive_string   sparse_map;
@@ -360,9 +359,8 @@ archive_write_pax_header(struct archive_write *a,
        struct archive_entry *entry_main;
        const char *p;
        char *t;
-       const wchar_t *wp;
        const char *suffix;
-       int binary, need_extension, r, r2, ret;
+       int binary, need_extension, r, ret;
        int sparse_count;
        uint64_t sparse_total, real_size;
        struct pax *pax;
@@ -882,22 +880,13 @@ archive_write_pax_header(struct archive_write *a,
                        add_pax_attr(&(pax->pax_header), "SCHILY.fflags", p);
 
                /* I use star-compatible ACL attributes. */
-               wp = archive_entry_acl_text_w(entry_original,
+               p = archive_entry_acl_text(entry_original,
                    ARCHIVE_ENTRY_ACL_TYPE_ACCESS |
                    ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID);
-               if (wp != NULL && *wp != L'\0') {
-                       archive_string_empty(&(pax->l_acl_mbs));
-                       r2 = archive_string_append_from_unicode_to_mbs(
-                           &(a->archive), &(pax->l_acl_mbs),
-                           wp, wcslen(wp));
-                       if (r2 == 0) {
-                               r = archive_strncpy_to_locale(
-                                   &(a->archive), &(pax->l_acl_utf8),
-                                   pax->l_acl_mbs.s, pax->l_acl_mbs.length,
-                                   "UTF-8");
-                       } else
-                               r = 0;
-                       if (r2 || r) {
+               if (p != NULL && *p != '\0') {
+                       r = archive_strcpy_to_locale(
+                           &(a->archive), &(pax->l_acl_utf8), p, "UTF-8");
+                       if (r != 0) {
                                archive_set_error(&a->archive,
                                    ARCHIVE_ERRNO_FILE_FORMAT,
                                    "Can't translate ACL.access to UTF-8");
@@ -907,22 +896,13 @@ archive_write_pax_header(struct archive_write *a,
                                    "SCHILY.acl.access", pax->l_acl_utf8.s);
                        }
                }
-               wp = archive_entry_acl_text_w(entry_original,
+               p = archive_entry_acl_text(entry_original,
                    ARCHIVE_ENTRY_ACL_TYPE_DEFAULT |
                    ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID);
-               if (wp != NULL && *wp != L'\0') {
-                       archive_string_empty(&(pax->l_acl_mbs));
-                       r2 = archive_string_append_from_unicode_to_mbs(
-                           &(a->archive), &(pax->l_acl_mbs),
-                           wp, wcslen(wp));
-                       if (r2 == 0) {
-                               r = archive_strncpy_to_locale(
-                                   &(a->archive), &(pax->l_acl_utf8),
-                                   pax->l_acl_mbs.s, pax->l_acl_mbs.length,
-                                   "UTF-8");
-                       } else
-                               r = 0;
-                       if (r2 || r) {
+               if (p != NULL && *p != '\0') {
+                       r = archive_strcpy_to_locale(
+                           &(a->archive), &(pax->l_acl_utf8), p, "UTF-8");
+                       if (r != 0) {
                                archive_set_error(&a->archive,
                                    ARCHIVE_ERRNO_FILE_FORMAT,
                                    "Can't translate ACL.default to UTF-8");
@@ -1455,7 +1435,6 @@ archive_write_pax_free(struct archive_write *a)
        archive_string_free(&pax->l_gname);
        archive_string_free(&pax->l_linkpath);
        archive_string_free(&pax->l_url_encoded_name);
-       archive_string_free(&pax->l_acl_mbs);
        archive_string_free(&pax->l_acl_utf8);
        free(pax->opt_charset);
        sparse_list_clear(pax);