diff options
author | Brad King <brad.king@kitware.com> | 2017-02-20 13:04:00 (GMT) |
---|---|---|
committer | Brad King <brad.king@kitware.com> | 2017-02-20 13:04:00 (GMT) |
commit | a59a7ee95601f3496ec9ba9ae1283a8d980460bf (patch) | |
tree | d8279b1fe0a6ab19eaaf6c1490040663708e192d /Utilities/cmlibarchive/libarchive | |
parent | cdce7c619c58ec0947c036b93013445bb93e4be8 (diff) | |
parent | c206211af647dd1f7039da91c34c9c72e50aefdf (diff) | |
download | CMake-a59a7ee95601f3496ec9ba9ae1283a8d980460bf.zip CMake-a59a7ee95601f3496ec9ba9ae1283a8d980460bf.tar.gz CMake-a59a7ee95601f3496ec9ba9ae1283a8d980460bf.tar.bz2 |
Merge branch 'upstream-LibArchive' into update-libarchive
* upstream-LibArchive:
LibArchive 2017-02-19 (100ee75a)
Diffstat (limited to 'Utilities/cmlibarchive/libarchive')
81 files changed, 4577 insertions, 1831 deletions
diff --git a/Utilities/cmlibarchive/libarchive/CMakeLists.txt b/Utilities/cmlibarchive/libarchive/CMakeLists.txt index eaa7b20..d412c80 100644 --- a/Utilities/cmlibarchive/libarchive/CMakeLists.txt +++ b/Utilities/cmlibarchive/libarchive/CMakeLists.txt @@ -168,15 +168,33 @@ SET(libarchive_MANS archive_entry_time.3 archive_read.3 archive_read_add_passphrase.3 + archive_read_data.3 archive_read_disk.3 + archive_read_extract.3 + archive_read_filter.3 + archive_read_format.3 + archive_read_free.3 + archive_read_header.3 + archive_read_new.3 + archive_read_open.3 archive_read_set_options.3 archive_util.3 archive_write.3 + archive_write_blocksize.3 + archive_write_data.3 archive_write_disk.3 + archive_write_filter.3 + archive_write_finish_entry.3 + archive_write_format.3 + archive_write_free.3 + archive_write_header.3 + archive_write_new.3 + archive_write_open.3 archive_write_set_options.3 archive_write_set_passphrase.3 cpio.5 libarchive.3 + libarchive_changes.3 libarchive_internals.3 libarchive-formats.5 mtree.5 diff --git a/Utilities/cmlibarchive/libarchive/archive.h b/Utilities/cmlibarchive/libarchive/archive.h index 3b5104b..040f151 100644 --- a/Utilities/cmlibarchive/libarchive/archive.h +++ b/Utilities/cmlibarchive/libarchive/archive.h @@ -36,7 +36,7 @@ * assert that ARCHIVE_VERSION_NUMBER >= 2012108. */ /* Note: Compiler will complain if this does not match archive_entry.h! */ -#define ARCHIVE_VERSION_NUMBER 3002001 +#define ARCHIVE_VERSION_NUMBER 3003000 #include <sys/stat.h> #include <stddef.h> /* for wchar_t */ @@ -152,7 +152,7 @@ __LA_DECL int archive_version_number(void); /* * Textual name/version of the library, useful for version displays. */ -#define ARCHIVE_VERSION_ONLY_STRING "3.2.1" +#define ARCHIVE_VERSION_ONLY_STRING "3.3.0" #define ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING __LA_DECL const char * archive_version_string(void); @@ -370,7 +370,7 @@ typedef const char *archive_passphrase_callback(struct archive *, * 4) Repeatedly call archive_read_next_header to get information about * successive archive entries. Call archive_read_data to extract * data for entries of interest. - * 5) Call archive_read_finish to end processing. + * 5) Call archive_read_free to end processing. */ __LA_DECL struct archive *archive_read_new(void); @@ -559,7 +559,7 @@ __LA_DECL la_int64_t archive_read_header_position(struct archive *); * we cannot say whether there are encrypted entries, then * ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW is returned. * In general, this function will return values below zero when the - * reader is uncertain or totally uncapable of encryption support. + * reader is uncertain or totally incapable of encryption support. * When this function returns 0 you can be sure that the reader * supports encryption detection but no encrypted entries have * been found yet. @@ -981,12 +981,12 @@ __LA_DECL int archive_read_disk_can_descend(struct archive *); __LA_DECL int archive_read_disk_current_filesystem(struct archive *); __LA_DECL int archive_read_disk_current_filesystem_is_synthetic(struct archive *); __LA_DECL int archive_read_disk_current_filesystem_is_remote(struct archive *); -/* Request that the access time of the entry visited by travesal be restored. */ +/* Request that the access time of the entry visited by traversal be restored. */ __LA_DECL int archive_read_disk_set_atime_restored(struct archive *); /* * Set behavior. The "flags" argument selects optional behavior. */ -/* Request that the access time of the entry visited by travesal be restored. +/* Request that the access time of the entry visited by traversal be restored. * This is the same as archive_read_disk_set_atime_restored. */ #define ARCHIVE_READDISK_RESTORE_ATIME (0x0001) /* Default: Do not skip an entry which has nodump flags. */ @@ -1121,7 +1121,7 @@ __LA_DECL int archive_match_time_excluded(struct archive *, /* * Flags to tell a matching type of time stamps. These are used for - * following functinos. + * following functions. */ /* Time flag: mtime to be tested. */ #define ARCHIVE_MATCH_MTIME (0x0100) @@ -1141,7 +1141,7 @@ __LA_DECL int archive_match_include_date(struct archive *, int _flag, const char *_datestr); __LA_DECL int archive_match_include_date_w(struct archive *, int _flag, const wchar_t *_datestr); -/* Set inclusion time by a particluar file. */ +/* Set inclusion time by a particular file. */ __LA_DECL int archive_match_include_file_time(struct archive *, int _flag, const char *_pathname); __LA_DECL int archive_match_include_file_time_w(struct archive *, diff --git a/Utilities/cmlibarchive/libarchive/archive_acl.c b/Utilities/cmlibarchive/libarchive/archive_acl.c index bf4b610..b8b6b63 100644 --- a/Utilities/cmlibarchive/libarchive/archive_acl.c +++ b/Utilities/cmlibarchive/libarchive/archive_acl.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2003-2010 Tim Kientzle + * Copyright (c) 2016 Martin Matuska * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -55,25 +56,77 @@ static struct archive_acl_entry *acl_new_entry(struct archive_acl *acl, static int archive_acl_add_entry_len_l(struct archive_acl *acl, int type, int permset, int tag, int id, const char *name, size_t len, struct archive_string_conv *sc); +static int archive_acl_text_want_type(struct archive_acl *acl, int flags); +static ssize_t archive_acl_text_len(struct archive_acl *acl, int want_type, + int flags, int wide, struct archive *a, + struct archive_string_conv *sc); static int isint_w(const wchar_t *start, const wchar_t *end, int *result); static int ismode_w(const wchar_t *start, const wchar_t *end, int *result); +static int is_nfs4_flags_w(const wchar_t *start, const wchar_t *end, + int *result); +static int is_nfs4_perms_w(const wchar_t *start, const wchar_t *end, + int *result); static void next_field_w(const wchar_t **wp, const wchar_t **start, const wchar_t **end, wchar_t *sep); -static int prefix_w(const wchar_t *start, const wchar_t *end, - const wchar_t *test); -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_entry_w(wchar_t **wp, const wchar_t *prefix, int type, + int tag, int flags, 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 int is_nfs4_flags(const char *start, const char *end, + int *result); +static int is_nfs4_perms(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_c(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_entry(char **p, const char *prefix, int type, + int tag, int flags, const char *name, int perm, int id); static void append_id(char **p, int id); +static const struct { + const int perm; + const char c; + const wchar_t wc; +} nfsv4_acl_perm_map[] = { + { ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, 'r', + L'r' }, + { ARCHIVE_ENTRY_ACL_WRITE_DATA | ARCHIVE_ENTRY_ACL_ADD_FILE, 'w', + L'w' }, + { ARCHIVE_ENTRY_ACL_EXECUTE, 'x', L'x' }, + { ARCHIVE_ENTRY_ACL_APPEND_DATA | ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, + 'p', L'p' }, + { ARCHIVE_ENTRY_ACL_DELETE, 'd', L'd' }, + { ARCHIVE_ENTRY_ACL_DELETE_CHILD, 'D', L'D' }, + { ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, 'a', L'a' }, + { ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, 'A', L'A' }, + { ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, 'R', L'R' }, + { ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, 'W', L'W' }, + { ARCHIVE_ENTRY_ACL_READ_ACL, 'c', L'c' }, + { ARCHIVE_ENTRY_ACL_WRITE_ACL, 'C', L'C' }, + { ARCHIVE_ENTRY_ACL_WRITE_OWNER, 'o', L'o' }, + { ARCHIVE_ENTRY_ACL_SYNCHRONIZE, 's', L's' } +}; + +static const int nfsv4_acl_perm_map_size = (int)(sizeof(nfsv4_acl_perm_map) / + sizeof(nfsv4_acl_perm_map[0])); + +static const struct { + const int perm; + const char c; + const wchar_t wc; +} nfsv4_acl_flag_map[] = { + { ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, 'f', L'f' }, + { ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, 'd', L'd' }, + { ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, 'i', L'i' }, + { ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, 'n', L'n' }, + { ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, 'S', L'S' }, + { ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, 'F', L'F' }, + { ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, 'I', L'I' } +}; + +static const int nfsv4_acl_flag_map_size = (int)(sizeof(nfsv4_acl_flag_map) / + sizeof(nfsv4_acl_flag_map[0])); + void archive_acl_clear(struct archive_acl *acl) { @@ -94,6 +147,7 @@ archive_acl_clear(struct archive_acl *acl) acl->acl_text = NULL; } acl->acl_p = NULL; + acl->acl_types = 0; acl->acl_state = 0; /* Not counting. */ } @@ -279,23 +333,31 @@ acl_new_entry(struct archive_acl *acl, acl->acl_text = NULL; } - /* If there's a matching entry already in the list, overwrite it. */ + /* + * If there's a matching entry already in the list, overwrite it. + * NFSv4 entries may be repeated and are not overwritten. + * + * TODO: compare names of no id is provided (needs more rework) + */ ap = acl->acl_head; aq = NULL; while (ap != NULL) { - if (ap->type == type && ap->tag == tag && ap->id == id) { - ap->permset = permset; - return (ap); + if (((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0) && + ap->type == type && ap->tag == tag && ap->id == id) { + if (id != -1 || (tag != ARCHIVE_ENTRY_ACL_USER && + tag != ARCHIVE_ENTRY_ACL_GROUP)) { + ap->permset = permset; + return (ap); + } } aq = ap; ap = ap->next; } /* Add a new entry to the end of the list. */ - ap = (struct archive_acl_entry *)malloc(sizeof(*ap)); + ap = (struct archive_acl_entry *)calloc(1, sizeof(*ap)); if (ap == NULL) return (NULL); - memset(ap, 0, sizeof(*ap)); if (aq == NULL) acl->acl_head = ap; else @@ -331,6 +393,15 @@ archive_acl_count(struct archive_acl *acl, int want_type) } /* + * Return a bitmask of stored ACL types in an ACL list + */ +int +archive_acl_types(struct archive_acl *acl) +{ + return (acl->acl_types); +} + +/* * Prepare for reading entries from the ACL data. Returns a count * of entries matching "want_type", or zero if there are no * non-extended ACL entries of that type. @@ -366,8 +437,8 @@ archive_acl_reset(struct archive_acl *acl, int want_type) * standard permissions and include them in the returned list. */ int -archive_acl_next(struct archive *a, struct archive_acl *acl, int want_type, int *type, - int *permset, int *tag, int *id, const char **name) +archive_acl_next(struct archive *a, struct archive_acl *acl, int want_type, + int *type, int *permset, int *tag, int *id, const char **name) { *name = NULL; *id = -1; @@ -432,130 +503,273 @@ archive_acl_next(struct archive *a, struct archive_acl *acl, int want_type, int } /* - * Generate a text version of the ACL. The flags parameter controls - * the style of the generated ACL. + * Determine what type of ACL do we want */ -const wchar_t * -archive_acl_text_w(struct archive *a, struct archive_acl *acl, int flags) +static int +archive_acl_text_want_type(struct archive_acl *acl, int flags) { - int count; - size_t length; - const wchar_t *wname; - const wchar_t *prefix; - wchar_t separator; - struct archive_acl_entry *ap; - int id, r; - wchar_t *wp; + int want_type; - if (acl->acl_text_w != NULL) { - free (acl->acl_text_w); - acl->acl_text_w = NULL; + /* Check if ACL is NFSv4 */ + if ((acl->acl_types & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { + /* NFSv4 should never mix with POSIX.1e */ + if ((acl->acl_types & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) + return (0); + else + return (ARCHIVE_ENTRY_ACL_TYPE_NFS4); } - separator = L','; + /* Now deal with POSIX.1e ACLs */ + + want_type = 0; + if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) + want_type |= ARCHIVE_ENTRY_ACL_TYPE_ACCESS; + if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) + want_type |= ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; + + /* By default we want both access and default ACLs */ + if (want_type == 0) + return (ARCHIVE_ENTRY_ACL_TYPE_POSIX1E); + + return (want_type); +} + +/* + * Calculate ACL text string length + */ +static ssize_t +archive_acl_text_len(struct archive_acl *acl, int want_type, int flags, + int wide, struct archive *a, struct archive_string_conv *sc) { + struct archive_acl_entry *ap; + const char *name; + const wchar_t *wname; + int count, idlen, tmp, r; + ssize_t length; + size_t len; + 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 */ - r = archive_mstring_get_wcs(a, &ap->name, &wname); - if (r == 0 && wname != NULL) - length += wcslen(wname); - else if (r < 0 && errno == ENOMEM) - return (NULL); - else - length += sizeof(uid_t) * 3 + 1; - length ++; /* colon */ + for (ap = acl->acl_head; ap != NULL; ap = ap->next) { + if ((ap->type & want_type) == 0) + continue; + /* + * Filemode-mapping ACL entries are stored exclusively in + * ap->mode so they should not be in the list + */ + if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) + && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ + || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ + || ap->tag == ARCHIVE_ENTRY_ACL_OTHER)) + continue; + count++; + if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0 + && (ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) + length += 8; /* "default:" */ + switch (ap->tag) { + case ARCHIVE_ENTRY_ACL_USER_OBJ: + if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { + length += 6; /* "owner@" */ + break; + } + /* FALLTHROUGH */ + case ARCHIVE_ENTRY_ACL_USER: + case ARCHIVE_ENTRY_ACL_MASK: + length += 4; /* "user", "mask" */ + break; + case ARCHIVE_ENTRY_ACL_GROUP_OBJ: + if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { + length += 6; /* "group@" */ + break; + } + /* FALLTHROUGH */ + case ARCHIVE_ENTRY_ACL_GROUP: + case ARCHIVE_ENTRY_ACL_OTHER: + length += 5; /* "group", "other" */ + break; + case ARCHIVE_ENTRY_ACL_EVERYONE: + length += 9; /* "everyone@" */ + break; + } + length += 1; /* colon after tag */ + if (ap->tag == ARCHIVE_ENTRY_ACL_USER || + ap->tag == ARCHIVE_ENTRY_ACL_GROUP) { + if (wide) { + r = archive_mstring_get_wcs(a, &ap->name, + &wname); + if (r == 0 && wname != NULL) + length += wcslen(wname); + else if (r < 0 && errno == ENOMEM) + return (0); + else + length += sizeof(uid_t) * 3 + 1; + } else { + r = archive_mstring_get_mbs_l(&ap->name, &name, + &len, sc); + if (r != 0) + return (0); + if (len > 0 && name != NULL) + length += len; + else + length += sizeof(uid_t) * 3 + 1; + } + length += 1; /* colon after user or group name */ + } else if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) + length += 1; /* 2nd colon empty user,group or other */ + + if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) != 0) + && ((want_type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) + && (ap->tag == ARCHIVE_ENTRY_ACL_OTHER + || ap->tag == ARCHIVE_ENTRY_ACL_MASK)) { + /* Solaris has no colon after other: and mask: */ + length = length - 1; + } + + if (want_type == ARCHIVE_ENTRY_ACL_TYPE_NFS4) { + /* rwxpdDaARWcCos:fdinSFI:deny */ + length += 27; + if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DENY) == 0) + length += 1; /* allow, alarm, audit */ + } else length += 3; /* rwx */ + + if ((ap->tag == ARCHIVE_ENTRY_ACL_USER || + ap->tag == ARCHIVE_ENTRY_ACL_GROUP) && + (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) != 0) { length += 1; /* colon */ - length += max(sizeof(uid_t), sizeof(gid_t)) * 3 + 1; - length ++; /* newline */ + /* ID digit count */ + idlen = 1; + tmp = ap->id; + while (tmp > 9) { + tmp = tmp / 10; + idlen++; + } + length += idlen; } - ap = ap->next; + length ++; /* entry separator */ } - 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" */ - } + /* Add filemode-mapping access entries to the length */ + if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { + if ((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) != 0) { + /* "user::rwx\ngroup::rwx\nother:rwx\n" */ + length += 31; + } else { + /* "user::rwx\ngroup::rwx\nother::rwx\n" */ + length += 32; + } + } else if (count == 0) + return (0); + + /* The terminating character is included in count */ + return (length); +} + +/* + * Generate a wide text version of the ACL. The flags parameter controls + * the type and style of the generated ACL. + */ +wchar_t * +archive_acl_to_text_w(struct archive_acl *acl, ssize_t *text_len, int flags, + struct archive *a) +{ + int count; + ssize_t length; + size_t len; + const wchar_t *wname; + const wchar_t *prefix; + wchar_t separator; + struct archive_acl_entry *ap; + int id, r, want_type; + wchar_t *wp, *ws; + + want_type = archive_acl_text_want_type(acl, flags); + + /* Both NFSv4 and POSIX.1 types found */ + if (want_type == 0) + return (NULL); + + if (want_type == ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) + flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT; + + length = archive_acl_text_len(acl, want_type, flags, 1, a, NULL); - if (count == 0) + if (length == 0) return (NULL); + if (flags & ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA) + separator = L','; + else + separator = L'\n'; + /* Now, allocate the string and actually populate it. */ - wp = acl->acl_text_w = (wchar_t *)malloc(length * sizeof(wchar_t)); - if (wp == NULL) + wp = ws = (wchar_t *)malloc(length * sizeof(wchar_t)); + if (wp == NULL) { + if (errno == ENOMEM) + __archive_errx(1, "No memory"); return (NULL); + } count = 0; - if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { - append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL, + + if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { + append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, + ARCHIVE_ENTRY_ACL_USER_OBJ, flags, NULL, acl->mode & 0700, -1); - *wp++ = ','; - append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_GROUP_OBJ, NULL, + *wp++ = separator; + append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, + ARCHIVE_ENTRY_ACL_GROUP_OBJ, flags, NULL, acl->mode & 0070, -1); - *wp++ = ','; - append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_OTHER, NULL, + *wp++ = separator; + append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, + ARCHIVE_ENTRY_ACL_OTHER, flags, NULL, acl->mode & 0007, -1); count += 3; - - ap = acl->acl_head; - while (ap != NULL) { - if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { - r = archive_mstring_get_wcs(a, &ap->name, &wname); - if (r == 0) { - *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, id); - count++; - } else if (r < 0 && errno == ENOMEM) - return (NULL); - } - ap = ap->next; - } } - - if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) { - if (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) + for (ap = acl->acl_head; ap != NULL; ap = ap->next) { + if ((ap->type & want_type) == 0) + continue; + /* + * Filemode-mapping ACL entries are stored exclusively in + * ap->mode so they should not be in the list + */ + if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) + && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ + || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ + || ap->tag == ARCHIVE_ENTRY_ACL_OTHER)) + continue; + if (ap->type == ARCHIVE_ENTRY_ACL_TYPE_DEFAULT && + (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0) prefix = L"default:"; else prefix = NULL; - ap = acl->acl_head; - count = 0; - while (ap != NULL) { - if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) { - r = archive_mstring_get_wcs(a, &ap->name, &wname); - if (r == 0) { - if (count > 0) - *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 ++; - } else if (r < 0 && errno == ENOMEM) - return (NULL); - } - ap = ap->next; - } + r = archive_mstring_get_wcs(a, &ap->name, &wname); + if (r == 0) { + if (count > 0) + *wp++ = separator; + if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) + id = ap->id; + else + id = -1; + append_entry_w(&wp, prefix, ap->type, ap->tag, flags, + wname, ap->permset, id); + count++; + } else if (r < 0 && errno == ENOMEM) + return (NULL); } - return (acl->acl_text_w); -} + /* Add terminating character */ + *wp++ = L'\0'; + + len = wcslen(ws); + if ((ssize_t)len > (length - 1)) + __archive_errx(1, "Buffer overrun"); + + if (text_len != NULL) + *text_len = len; + + return (ws); +} static void append_id_w(wchar_t **wp, int id) @@ -568,9 +782,11 @@ append_id_w(wchar_t **wp, int id) } static void -append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag, - const wchar_t *wname, int perm, int id) +append_entry_w(wchar_t **wp, const wchar_t *prefix, int type, + int tag, int flags, const wchar_t *wname, int perm, int id) { + int i; + if (prefix != NULL) { wcscpy(*wp, prefix); *wp += wcslen(*wp); @@ -579,6 +795,10 @@ append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag, case ARCHIVE_ENTRY_ACL_USER_OBJ: wname = NULL; id = -1; + if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { + wcscpy(*wp, L"owner@"); + break; + } /* FALLTHROUGH */ case ARCHIVE_ENTRY_ACL_USER: wcscpy(*wp, L"user"); @@ -586,6 +806,10 @@ append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag, case ARCHIVE_ENTRY_ACL_GROUP_OBJ: wname = NULL; id = -1; + if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { + wcscpy(*wp, L"group@"); + break; + } /* FALLTHROUGH */ case ARCHIVE_ENTRY_ACL_GROUP: wcscpy(*wp, L"group"); @@ -600,153 +824,184 @@ append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag, wname = NULL; id = -1; break; + case ARCHIVE_ENTRY_ACL_EVERYONE: + wcscpy(*wp, L"everyone@"); + wname = NULL; + id = -1; + break; } *wp += wcslen(*wp); *(*wp)++ = L':'; - if (wname != NULL) { - wcscpy(*wp, wname); + if (((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) || + tag == ARCHIVE_ENTRY_ACL_USER || + tag == ARCHIVE_ENTRY_ACL_GROUP) { + if (wname != NULL) { + wcscpy(*wp, wname); + *wp += wcslen(*wp); + } else if (tag == ARCHIVE_ENTRY_ACL_USER + || tag == ARCHIVE_ENTRY_ACL_GROUP) { + append_id_w(wp, id); + if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0) + id = -1; + } + /* Solaris style has no second colon after other and mask */ + if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) == 0) + || (tag != ARCHIVE_ENTRY_ACL_OTHER + && tag != ARCHIVE_ENTRY_ACL_MASK)) + *(*wp)++ = L':'; + } + if ((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) { + /* POSIX.1e ACL perms */ + *(*wp)++ = (perm & 0444) ? L'r' : L'-'; + *(*wp)++ = (perm & 0222) ? L'w' : L'-'; + *(*wp)++ = (perm & 0111) ? L'x' : L'-'; + } else { + /* NFSv4 ACL perms */ + for (i = 0; i < nfsv4_acl_perm_map_size; i++) { + if (perm & nfsv4_acl_perm_map[i].perm) + *(*wp)++ = nfsv4_acl_perm_map[i].wc; + else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0) + *(*wp)++ = L'-'; + } + *(*wp)++ = L':'; + for (i = 0; i < nfsv4_acl_flag_map_size; i++) { + if (perm & nfsv4_acl_flag_map[i].perm) + *(*wp)++ = nfsv4_acl_flag_map[i].wc; + else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0) + *(*wp)++ = L'-'; + } + *(*wp)++ = L':'; + switch (type) { + case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: + wcscpy(*wp, L"allow"); + break; + case ARCHIVE_ENTRY_ACL_TYPE_DENY: + wcscpy(*wp, L"deny"); + break; + case ARCHIVE_ENTRY_ACL_TYPE_AUDIT: + wcscpy(*wp, L"audit"); + break; + case ARCHIVE_ENTRY_ACL_TYPE_ALARM: + wcscpy(*wp, L"alarm"); + break; + default: + break; + } *wp += wcslen(*wp); - } else if (tag == ARCHIVE_ENTRY_ACL_USER - || tag == ARCHIVE_ENTRY_ACL_GROUP) { - append_id_w(wp, id); - id = -1; } - *(*wp)++ = L':'; - *(*wp)++ = (perm & 0444) ? L'r' : L'-'; - *(*wp)++ = (perm & 0222) ? L'w' : L'-'; - *(*wp)++ = (perm & 0111) ? L'x' : L'-'; if (id != -1) { *(*wp)++ = L':'; append_id_w(wp, id); } - **wp = L'\0'; } -int -archive_acl_text_l(struct archive_acl *acl, int flags, - const char **acl_text, size_t *acl_text_len, +/* + * Generate a text version of the ACL. The flags parameter controls + * the type and style of the generated ACL. + */ +char * +archive_acl_to_text_l(struct archive_acl *acl, ssize_t *text_len, int flags, struct archive_string_conv *sc) { int count; - size_t length; + ssize_t length; + size_t len; const char *name; const char *prefix; char separator; struct archive_acl_entry *ap; - size_t len; - int id, r; - char *p; + int id, r, want_type; + char *p, *s; - if (acl->acl_text != NULL) { - free (acl->acl_text); - acl->acl_text = NULL; - } + want_type = archive_acl_text_want_type(acl, flags); - *acl_text = NULL; - if (acl_text_len != NULL) - *acl_text_len = 0; - 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 */ - r = archive_mstring_get_mbs_l( - &ap->name, &name, &len, sc); - if (r != 0) - return (-1); - if (len > 0 && name != NULL) - length += len; - 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; - } + /* Both NFSv4 and POSIX.1 types found */ + if (want_type == 0) + return (NULL); - 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 (want_type == ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) + flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT; - if (count == 0) - return (0); + length = archive_acl_text_len(acl, want_type, flags, 0, NULL, sc); + + if (length == 0) + return (NULL); + + if (flags & ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA) + separator = ','; + else + separator = '\n'; /* Now, allocate the string and actually populate it. */ - p = acl->acl_text = (char *)malloc(length); - if (p == NULL) - return (-1); + p = s = (char *)malloc(length * sizeof(char)); + if (p == NULL) { + if (errno == ENOMEM) + __archive_errx(1, "No memory"); + return (NULL); + } count = 0; - if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { - append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL, + + if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { + append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, + ARCHIVE_ENTRY_ACL_USER_OBJ, flags, NULL, acl->mode & 0700, -1); - *p++ = ','; - append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_GROUP_OBJ, NULL, + *p++ = separator; + append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, + ARCHIVE_ENTRY_ACL_GROUP_OBJ, flags, NULL, acl->mode & 0070, -1); - *p++ = ','; - append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_OTHER, NULL, + *p++ = separator; + append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, + ARCHIVE_ENTRY_ACL_OTHER, flags, NULL, acl->mode & 0007, -1); count += 3; - - for (ap = acl->acl_head; ap != NULL; ap = ap->next) { - if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) == 0) - continue; - r = archive_mstring_get_mbs_l( - &ap->name, &name, &len, sc); - if (r != 0) - return (-1); - *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++; - } } - - if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) { - if (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) + for (ap = acl->acl_head; ap != NULL; ap = ap->next) { + if ((ap->type & want_type) == 0) + continue; + /* + * Filemode-mapping ACL entries are stored exclusively in + * ap->mode so they should not be in the list + */ + if ((ap->type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) + && (ap->tag == ARCHIVE_ENTRY_ACL_USER_OBJ + || ap->tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ + || ap->tag == ARCHIVE_ENTRY_ACL_OTHER)) + continue; + if (ap->type == ARCHIVE_ENTRY_ACL_TYPE_DEFAULT && + (flags & ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0) prefix = "default:"; else prefix = NULL; - count = 0; - for (ap = acl->acl_head; ap != NULL; ap = ap->next) { - if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) == 0) - continue; - r = archive_mstring_get_mbs_l( - &ap->name, &name, &len, sc); - if (r != 0) - return (-1); - 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 ++; + r = archive_mstring_get_mbs_l( + &ap->name, &name, &len, sc); + if (r != 0) + return (NULL); + if (count > 0) + *p++ = separator; + if (name == NULL || + (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)) { + id = ap->id; + } else { + id = -1; } + append_entry(&p, prefix, ap->type, ap->tag, flags, name, + ap->permset, id); + count++; } - *acl_text = acl->acl_text; - if (acl_text_len != NULL) - *acl_text_len = strlen(acl->acl_text); - return (0); + /* Add terminating character */ + *p++ = '\0'; + + len = strlen(s); + + if ((ssize_t)len > (length - 1)) + __archive_errx(1, "Buffer overrun"); + + if (text_len != NULL) + *text_len = len; + + return (s); } static void @@ -760,9 +1015,11 @@ append_id(char **p, int id) } static void -append_entry(char **p, const char *prefix, int tag, - const char *name, int perm, int id) +append_entry(char **p, const char *prefix, int type, + int tag, int flags, const char *name, int perm, int id) { + int i; + if (prefix != NULL) { strcpy(*p, prefix); *p += strlen(*p); @@ -771,6 +1028,10 @@ append_entry(char **p, const char *prefix, int tag, case ARCHIVE_ENTRY_ACL_USER_OBJ: name = NULL; id = -1; + if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { + strcpy(*p, "owner@"); + break; + } /* FALLTHROUGH */ case ARCHIVE_ENTRY_ACL_USER: strcpy(*p, "user"); @@ -778,6 +1039,10 @@ append_entry(char **p, const char *prefix, int tag, case ARCHIVE_ENTRY_ACL_GROUP_OBJ: name = NULL; id = -1; + if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { + strcpy(*p, "group@"); + break; + } /* FALLTHROUGH */ case ARCHIVE_ENTRY_ACL_GROUP: strcpy(*p, "group"); @@ -792,48 +1057,120 @@ append_entry(char **p, const char *prefix, int tag, name = NULL; id = -1; break; + case ARCHIVE_ENTRY_ACL_EVERYONE: + strcpy(*p, "everyone@"); + name = NULL; + id = -1; + break; } *p += strlen(*p); *(*p)++ = ':'; - if (name != NULL) { - strcpy(*p, name); + if (((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) || + tag == ARCHIVE_ENTRY_ACL_USER || + tag == ARCHIVE_ENTRY_ACL_GROUP) { + 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); + if ((type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0) + id = -1; + } + /* Solaris style has no second colon after other and mask */ + if (((flags & ARCHIVE_ENTRY_ACL_STYLE_SOLARIS) == 0) + || (tag != ARCHIVE_ENTRY_ACL_OTHER + && tag != ARCHIVE_ENTRY_ACL_MASK)) + *(*p)++ = ':'; + } + if ((type & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) { + /* POSIX.1e ACL perms */ + *(*p)++ = (perm & 0444) ? 'r' : '-'; + *(*p)++ = (perm & 0222) ? 'w' : '-'; + *(*p)++ = (perm & 0111) ? 'x' : '-'; + } else { + /* NFSv4 ACL perms */ + for (i = 0; i < nfsv4_acl_perm_map_size; i++) { + if (perm & nfsv4_acl_perm_map[i].perm) + *(*p)++ = nfsv4_acl_perm_map[i].c; + else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0) + *(*p)++ = '-'; + } + *(*p)++ = ':'; + for (i = 0; i < nfsv4_acl_flag_map_size; i++) { + if (perm & nfsv4_acl_flag_map[i].perm) + *(*p)++ = nfsv4_acl_flag_map[i].c; + else if ((flags & ARCHIVE_ENTRY_ACL_STYLE_COMPACT) == 0) + *(*p)++ = '-'; + } + *(*p)++ = ':'; + switch (type) { + case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: + strcpy(*p, "allow"); + break; + case ARCHIVE_ENTRY_ACL_TYPE_DENY: + strcpy(*p, "deny"); + break; + case ARCHIVE_ENTRY_ACL_TYPE_AUDIT: + strcpy(*p, "audit"); + break; + case ARCHIVE_ENTRY_ACL_TYPE_ALARM: + strcpy(*p, "alarm"); + break; + } *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 - * indicate the type that should be used for any entries not - * explicitly marked as "default:". + * Parse a wide ACL text string. + * + * The want_type argument may be one of the following: + * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - text is a POSIX.1e ACL of type ACCESS + * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - text is a POSIX.1e ACL of type DEFAULT + * ARCHIVE_ENTRY_ACL_TYPE_NFS4 - text is as a NFSv4 ACL + * + * POSIX.1e ACL entries prefixed with "default:" are treated as + * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT unless type is ARCHIVE_ENTRY_ACL_TYPE_NFS4 */ int -archive_acl_parse_w(struct archive_acl *acl, - const wchar_t *text, int default_type) +archive_acl_from_text_w(struct archive_acl *acl, const wchar_t *text, + int want_type) { struct { const wchar_t *start; const wchar_t *end; - } field[4], name; + } field[6], name; + + const wchar_t *s, *st; - int fields, n; - int type, tag, permset, id; + int numfields, fields, n, r, sol, ret; + int type, types, tag, permset, id; + size_t len; wchar_t sep; - while (text != NULL && *text != L'\0') { + ret = ARCHIVE_OK; + types = 0; + + switch (want_type) { + case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E: + want_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; + case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: + case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: + numfields = 5; + break; + case ARCHIVE_ENTRY_ACL_TYPE_NFS4: + numfields = 6; + break; + default: + return (ARCHIVE_FATAL); + } + + while (text != NULL && *text != L'\0') { /* * Parse the fields out of the next entry, * advance 'text' to start of next entry. @@ -842,7 +1179,7 @@ archive_acl_parse_w(struct archive_acl *acl, do { const wchar_t *start, *end; next_field_w(&text, &start, &end, &sep); - if (fields < 4) { + if (fields < numfields) { field[fields].start = start; field[fields].end = end; } @@ -850,78 +1187,210 @@ archive_acl_parse_w(struct archive_acl *acl, } while (sep == L':'); /* Set remaining fields to blank. */ - for (n = fields; n < 4; ++n) + for (n = fields; n < numfields; ++n) field[n].start = field[n].end = NULL; - /* Check for a numeric ID in field 1 or 3. */ - id = -1; - isint_w(field[1].start, field[1].end, &id); - /* Field 3 is optional. */ - if (id == -1 && fields > 3) - isint_w(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 - && wmemcmp(field[0].start, L"default", 7) == 0) { - type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; - field[0].start += 7; - } else - type = default_type; + if (field[0].start != NULL && *(field[0].start) == L'#') { + /* Comment, skip entry */ + continue; + } + n = 0; + sol = 0; + id = -1; + permset = 0; name.start = name.end = NULL; - if (prefix_w(field[0].start, field[0].end, L"user")) { - if (!ismode_w(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]; + + if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) { + /* POSIX.1e ACLs */ + /* + * Default keyword "default:user::rwx" + * if found, we have one more field + * + * We also support old Solaris extension: + * "defaultuser::rwx" is the default ACL corresponding + * to "user::rwx", etc. valid only for first field + */ + s = field[0].start; + len = field[0].end - field[0].start; + if (*s == L'd' && (len == 1 || (len >= 7 + && wmemcmp((s + 1), L"efault", 6) == 0))) { + type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; + if (len > 7) + field[0].start += 7; + else + n = 1; } else - tag = ARCHIVE_ENTRY_ACL_USER_OBJ; - } else if (prefix_w(field[0].start, field[0].end, L"group")) { - if (!ismode_w(field[2].start, field[2].end, &permset)) - return (ARCHIVE_WARN); - if (id != -1 || field[1].start < field[1].end) { - tag = ARCHIVE_ENTRY_ACL_GROUP; + type = want_type; + + /* Check for a numeric ID in field n+1 or n+3. */ + isint_w(field[n + 1].start, field[n + 1].end, &id); + /* Field n+3 is optional. */ + if (id == -1 && fields > n+3) + isint_w(field[n + 3].start, field[n + 3].end, + &id); + + tag = 0; + s = field[n].start; + st = field[n].start + 1; + len = field[n].end - field[n].start; + + switch (*s) { + case L'u': + if (len == 1 || (len == 4 + && wmemcmp(st, L"ser", 3) == 0)) + tag = ARCHIVE_ENTRY_ACL_USER_OBJ; + break; + case L'g': + if (len == 1 || (len == 5 + && wmemcmp(st, L"roup", 4) == 0)) + tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; + break; + case L'o': + if (len == 1 || (len == 5 + && wmemcmp(st, L"ther", 4) == 0)) + tag = ARCHIVE_ENTRY_ACL_OTHER; + break; + case L'm': + if (len == 1 || (len == 4 + && wmemcmp(st, L"ask", 3) == 0)) + tag = ARCHIVE_ENTRY_ACL_MASK; + break; + default: + break; + } + + switch (tag) { + case ARCHIVE_ENTRY_ACL_OTHER: + case ARCHIVE_ENTRY_ACL_MASK: + if (fields == (n + 2) + && field[n + 1].start < field[n + 1].end + && ismode_w(field[n + 1].start, + field[n + 1].end, &permset)) { + /* This is Solaris-style "other:rwx" */ + sol = 1; + } else if (fields == (n + 3) && + field[n + 1].start < field[n + 1].end) { + /* Invalid mask or other field */ + ret = ARCHIVE_WARN; + continue; + } + break; + case ARCHIVE_ENTRY_ACL_USER_OBJ: + case ARCHIVE_ENTRY_ACL_GROUP_OBJ: + if (id != -1 || + field[n + 1].start < field[n + 1].end) { + name = field[n + 1]; + if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) + tag = ARCHIVE_ENTRY_ACL_USER; + else + tag = ARCHIVE_ENTRY_ACL_GROUP; + } + break; + default: + /* Invalid tag, skip entry */ + ret = ARCHIVE_WARN; + continue; + } + + /* + * Without "default:" we expect mode in field 2 + * Exception: Solaris other and mask fields + */ + if (permset == 0 && !ismode_w(field[n + 2 - sol].start, + field[n + 2 - sol].end, &permset)) { + /* Invalid mode, skip entry */ + ret = ARCHIVE_WARN; + continue; + } + } else { + /* NFS4 ACLs */ + s = field[0].start; + len = field[0].end - field[0].start; + tag = 0; + + switch (len) { + case 4: + if (wmemcmp(s, L"user", 4) == 0) + tag = ARCHIVE_ENTRY_ACL_USER; + break; + case 5: + if (wmemcmp(s, L"group", 5) == 0) + tag = ARCHIVE_ENTRY_ACL_GROUP; + break; + case 6: + if (wmemcmp(s, L"owner@", 6) == 0) + tag = ARCHIVE_ENTRY_ACL_USER_OBJ; + else if (wmemcmp(s, L"group@", len) == 0) + tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; + break; + case 9: + if (wmemcmp(s, L"everyone@", 9) == 0) + tag = ARCHIVE_ENTRY_ACL_EVERYONE; + default: + break; + } + + if (tag == 0) { + /* Invalid tag, skip entry */ + ret = ARCHIVE_WARN; + continue; + } else if (tag == ARCHIVE_ENTRY_ACL_USER || + tag == ARCHIVE_ENTRY_ACL_GROUP) { + n = 1; name = field[1]; + isint_w(name.start, name.end, &id); } else - tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; - } else if (prefix_w(field[0].start, field[0].end, L"other")) { - if (fields == 2 - && field[1].start < field[1].end - && ismode_w(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_w(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_w(field[0].start, field[0].end, L"mask")) { - if (fields == 2 - && field[1].start < field[1].end - && ismode_w(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_w(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); + n = 0; + + if (!is_nfs4_perms_w(field[1 + n].start, + field[1 + n].end, &permset)) { + /* Invalid NFSv4 perms, skip entry */ + ret = ARCHIVE_WARN; + continue; + } + if (!is_nfs4_flags_w(field[2 + n].start, + field[2 + n].end, &permset)) { + /* Invalid NFSv4 flags, skip entry */ + ret = ARCHIVE_WARN; + continue; + } + s = field[3 + n].start; + len = field[3 + n].end - field[3 + n].start; + type = 0; + if (len == 4) { + if (wmemcmp(s, L"deny", 4) == 0) + type = ARCHIVE_ENTRY_ACL_TYPE_DENY; + } else if (len == 5) { + if (wmemcmp(s, L"allow", 5) == 0) + type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW; + else if (wmemcmp(s, L"audit", 5) == 0) + type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT; + else if (wmemcmp(s, L"alarm", 5) == 0) + type = ARCHIVE_ENTRY_ACL_TYPE_ALARM; + } + if (type == 0) { + /* Invalid entry type, skip entry */ + ret = ARCHIVE_WARN; + continue; + } + isint_w(field[4 + n].start, field[4 + n].end, &id); + } /* Add entry to the internal list. */ - archive_acl_add_entry_w_len(acl, type, permset, + r = archive_acl_add_entry_w_len(acl, type, permset, tag, id, name.start, name.end - name.start); + if (r < ARCHIVE_WARN) + return (r); + if (r != ARCHIVE_OK) + ret = ARCHIVE_WARN; + types |= type; } - return (ARCHIVE_OK); + + /* Reset ACL */ + archive_acl_reset(acl, types); + + return (ret); } /* @@ -967,16 +1436,122 @@ ismode_w(const wchar_t *start, const wchar_t *end, int *permset) *permset = 0; while (p < end) { switch (*p++) { - case 'r': case 'R': + case L'r': case L'R': *permset |= ARCHIVE_ENTRY_ACL_READ; break; - case 'w': case 'W': + case L'w': case L'W': *permset |= ARCHIVE_ENTRY_ACL_WRITE; break; - case 'x': case 'X': + case L'x': case L'X': *permset |= ARCHIVE_ENTRY_ACL_EXECUTE; break; - case '-': + case L'-': + break; + default: + return (0); + } + } + return (1); +} + +/* + * Parse a string as a NFS4 ACL permission field. + * Returns true if the string is non-empty and consists only of NFS4 ACL + * permission characters, false otherwise + */ +static int +is_nfs4_perms_w(const wchar_t *start, const wchar_t *end, int *permset) +{ + const wchar_t *p = start; + + while (p < end) { + switch (*p++) { + case L'r': + *permset |= ARCHIVE_ENTRY_ACL_READ_DATA; + break; + case L'w': + *permset |= ARCHIVE_ENTRY_ACL_WRITE_DATA; + break; + case L'x': + *permset |= ARCHIVE_ENTRY_ACL_EXECUTE; + break; + case L'p': + *permset |= ARCHIVE_ENTRY_ACL_APPEND_DATA; + break; + case L'D': + *permset |= ARCHIVE_ENTRY_ACL_DELETE_CHILD; + break; + case L'd': + *permset |= ARCHIVE_ENTRY_ACL_DELETE; + break; + case L'a': + *permset |= ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES; + break; + case L'A': + *permset |= ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES; + break; + case L'R': + *permset |= ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS; + break; + case L'W': + *permset |= ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS; + break; + case L'c': + *permset |= ARCHIVE_ENTRY_ACL_READ_ACL; + break; + case L'C': + *permset |= ARCHIVE_ENTRY_ACL_WRITE_ACL; + break; + case L'o': + *permset |= ARCHIVE_ENTRY_ACL_WRITE_OWNER; + break; + case L's': + *permset |= ARCHIVE_ENTRY_ACL_SYNCHRONIZE; + break; + case L'-': + break; + default: + return(0); + } + } + return (1); +} + +/* + * Parse a string as a NFS4 ACL flags field. + * Returns true if the string is non-empty and consists only of NFS4 ACL + * flag characters, false otherwise + */ +static int +is_nfs4_flags_w(const wchar_t *start, const wchar_t *end, int *permset) +{ + const wchar_t *p = start; + + while (p < end) { + switch(*p++) { + case L'f': + *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT; + break; + case L'd': + *permset |= ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT; + break; + case L'i': + *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY; + break; + case L'n': + *permset |= + ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT; + break; + case L'S': + *permset |= ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS; + break; + case L'F': + *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS; + break; + case L'I': + *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERITED; + break; + case L'-': break; default: return (0); @@ -1023,46 +1598,48 @@ next_field_w(const wchar_t **wp, const wchar_t **start, } /* - * 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_w(const wchar_t *start, const wchar_t *end, const wchar_t *test) -{ - if (start == end) - return (0); - - if (*start++ != *test++) - return (0); - - while (start < end && *start++ == *test++) - ; - - if (start < end) - return (0); - - 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:". + * Parse an ACL text string. + * + * The want_type argument may be one of the following: + * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - text is a POSIX.1e ACL of type ACCESS + * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - text is a POSIX.1e ACL of type DEFAULT + * ARCHIVE_ENTRY_ACL_TYPE_NFS4 - text is as a NFSv4 ACL + * + * POSIX.1e ACL entries prefixed with "default:" are treated as + * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT unless type is ARCHIVE_ENTRY_ACL_TYPE_NFS4 */ int -archive_acl_parse_l(struct archive_acl *acl, - const char *text, int default_type, struct archive_string_conv *sc) +archive_acl_from_text_l(struct archive_acl *acl, const char *text, + int want_type, struct archive_string_conv *sc) { struct { const char *start; const char *end; - } field[4], name; + } field[6], name; - int fields, n, r, ret = ARCHIVE_OK; - int type, tag, permset, id; + const char *s, *st; + int numfields, fields, n, r, sol, ret; + int type, types, tag, permset, id; + size_t len; char sep; + switch (want_type) { + case ARCHIVE_ENTRY_ACL_TYPE_POSIX1E: + want_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; + case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: + case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: + numfields = 5; + break; + case ARCHIVE_ENTRY_ACL_TYPE_NFS4: + numfields = 6; + break; + default: + return (ARCHIVE_FATAL); + } + + ret = ARCHIVE_OK; + types = 0; + while (text != NULL && *text != '\0') { /* * Parse the fields out of the next entry, @@ -1072,7 +1649,7 @@ archive_acl_parse_l(struct archive_acl *acl, do { const char *start, *end; next_field(&text, &start, &end, &sep); - if (fields < 4) { + if (fields < numfields) { field[fields].start = start; field[fields].end = end; } @@ -1080,72 +1657,197 @@ archive_acl_parse_l(struct archive_acl *acl, } while (sep == ':'); /* Set remaining fields to blank. */ - for (n = fields; n < 4; ++n) + for (n = fields; n < numfields; ++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; + if (field[0].start != NULL && *(field[0].start) == '#') { + /* Comment, skip entry */ + continue; + } + n = 0; + sol = 0; + id = -1; + permset = 0; name.start = name.end = NULL; - if (prefix_c(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]; + + if (want_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4) { + /* POSIX.1e ACLs */ + /* + * Default keyword "default:user::rwx" + * if found, we have one more field + * + * We also support old Solaris extension: + * "defaultuser::rwx" is the default ACL corresponding + * to "user::rwx", etc. valid only for first field + */ + s = field[0].start; + len = field[0].end - field[0].start; + if (*s == 'd' && (len == 1 || (len >= 7 + && memcmp((s + 1), "efault", 6) == 0))) { + type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; + if (len > 7) + field[0].start += 7; + else + n = 1; } else - tag = ARCHIVE_ENTRY_ACL_USER_OBJ; - } else if (prefix_c(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; + type = want_type; + + /* Check for a numeric ID in field n+1 or n+3. */ + isint(field[n + 1].start, field[n + 1].end, &id); + /* Field n+3 is optional. */ + if (id == -1 && fields > (n + 3)) + isint(field[n + 3].start, field[n + 3].end, + &id); + + tag = 0; + s = field[n].start; + st = field[n].start + 1; + len = field[n].end - field[n].start; + + switch (*s) { + case 'u': + if (len == 1 || (len == 4 + && memcmp(st, "ser", 3) == 0)) + tag = ARCHIVE_ENTRY_ACL_USER_OBJ; + break; + case 'g': + if (len == 1 || (len == 5 + && memcmp(st, "roup", 4) == 0)) + tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; + break; + case 'o': + if (len == 1 || (len == 5 + && memcmp(st, "ther", 4) == 0)) + tag = ARCHIVE_ENTRY_ACL_OTHER; + break; + case 'm': + if (len == 1 || (len == 4 + && memcmp(st, "ask", 3) == 0)) + tag = ARCHIVE_ENTRY_ACL_MASK; + break; + default: + break; + } + + switch (tag) { + case ARCHIVE_ENTRY_ACL_OTHER: + case ARCHIVE_ENTRY_ACL_MASK: + if (fields == (n + 2) + && field[n + 1].start < field[n + 1].end + && ismode(field[n + 1].start, + field[n + 1].end, &permset)) { + /* This is Solaris-style "other:rwx" */ + sol = 1; + } else if (fields == (n + 3) && + field[n + 1].start < field[n + 1].end) { + /* Invalid mask or other field */ + ret = ARCHIVE_WARN; + continue; + } + break; + case ARCHIVE_ENTRY_ACL_USER_OBJ: + case ARCHIVE_ENTRY_ACL_GROUP_OBJ: + if (id != -1 || + field[n + 1].start < field[n + 1].end) { + name = field[n + 1]; + if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) + tag = ARCHIVE_ENTRY_ACL_USER; + else + tag = ARCHIVE_ENTRY_ACL_GROUP; + } + break; + default: + /* Invalid tag, skip entry */ + ret = ARCHIVE_WARN; + continue; + } + + /* + * Without "default:" we expect mode in field 3 + * Exception: Solaris other and mask fields + */ + if (permset == 0 && !ismode(field[n + 2 - sol].start, + field[n + 2 - sol].end, &permset)) { + /* Invalid mode, skip entry */ + ret = ARCHIVE_WARN; + continue; + } + } else { + /* NFS4 ACLs */ + s = field[0].start; + len = field[0].end - field[0].start; + tag = 0; + + switch (len) { + case 4: + if (memcmp(s, "user", 4) == 0) + tag = ARCHIVE_ENTRY_ACL_USER; + break; + case 5: + if (memcmp(s, "group", 5) == 0) + tag = ARCHIVE_ENTRY_ACL_GROUP; + break; + case 6: + if (memcmp(s, "owner@", 6) == 0) + tag = ARCHIVE_ENTRY_ACL_USER_OBJ; + else if (memcmp(s, "group@", 6) == 0) + tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; + break; + case 9: + if (memcmp(s, "everyone@", 9) == 0) + tag = ARCHIVE_ENTRY_ACL_EVERYONE; + break; + default: + break; + } + + if (tag == 0) { + /* Invalid tag, skip entry */ + ret = ARCHIVE_WARN; + continue; + } else if (tag == ARCHIVE_ENTRY_ACL_USER || + tag == ARCHIVE_ENTRY_ACL_GROUP) { + n = 1; name = field[1]; + isint(name.start, name.end, &id); } else - tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; - } else if (prefix_c(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_c(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); + n = 0; + + if (!is_nfs4_perms(field[1 + n].start, + field[1 + n].end, &permset)) { + /* Invalid NFSv4 perms, skip entry */ + ret = ARCHIVE_WARN; + continue; + } + if (!is_nfs4_flags(field[2 + n].start, + field[2 + n].end, &permset)) { + /* Invalid NFSv4 flags, skip entry */ + ret = ARCHIVE_WARN; + continue; + } + s = field[3 + n].start; + len = field[3 + n].end - field[3 + n].start; + type = 0; + if (len == 4) { + if (memcmp(s, "deny", 4) == 0) + type = ARCHIVE_ENTRY_ACL_TYPE_DENY; + } else if (len == 5) { + if (memcmp(s, "allow", 5) == 0) + type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW; + else if (memcmp(s, "audit", 5) == 0) + type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT; + else if (memcmp(s, "alarm", 5) == 0) + type = ARCHIVE_ENTRY_ACL_TYPE_ALARM; + } + if (type == 0) { + /* Invalid entry type, skip entry */ + ret = ARCHIVE_WARN; + continue; + } + isint(field[4 + n].start, field[4 + n].end, + &id); + } /* Add entry to the internal list. */ r = archive_acl_add_entry_len_l(acl, type, permset, @@ -1154,7 +1856,12 @@ archive_acl_parse_l(struct archive_acl *acl, return (r); if (r != ARCHIVE_OK) ret = ARCHIVE_WARN; + types |= type; } + + /* Reset ACL */ + archive_acl_reset(acl, types); + return (ret); } @@ -1220,6 +1927,112 @@ ismode(const char *start, const char *end, int *permset) } /* + * Parse a string as a NFS4 ACL permission field. + * Returns true if the string is non-empty and consists only of NFS4 ACL + * permission characters, false otherwise + */ +static int +is_nfs4_perms(const char *start, const char *end, int *permset) +{ + const char *p = start; + + while (p < end) { + switch (*p++) { + case 'r': + *permset |= ARCHIVE_ENTRY_ACL_READ_DATA; + break; + case 'w': + *permset |= ARCHIVE_ENTRY_ACL_WRITE_DATA; + break; + case 'x': + *permset |= ARCHIVE_ENTRY_ACL_EXECUTE; + break; + case 'p': + *permset |= ARCHIVE_ENTRY_ACL_APPEND_DATA; + break; + case 'D': + *permset |= ARCHIVE_ENTRY_ACL_DELETE_CHILD; + break; + case 'd': + *permset |= ARCHIVE_ENTRY_ACL_DELETE; + break; + case 'a': + *permset |= ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES; + break; + case 'A': + *permset |= ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES; + break; + case 'R': + *permset |= ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS; + break; + case 'W': + *permset |= ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS; + break; + case 'c': + *permset |= ARCHIVE_ENTRY_ACL_READ_ACL; + break; + case 'C': + *permset |= ARCHIVE_ENTRY_ACL_WRITE_ACL; + break; + case 'o': + *permset |= ARCHIVE_ENTRY_ACL_WRITE_OWNER; + break; + case 's': + *permset |= ARCHIVE_ENTRY_ACL_SYNCHRONIZE; + break; + case '-': + break; + default: + return(0); + } + } + return (1); +} + +/* + * Parse a string as a NFS4 ACL flags field. + * Returns true if the string is non-empty and consists only of NFS4 ACL + * flag characters, false otherwise + */ +static int +is_nfs4_flags(const char *start, const char *end, int *permset) +{ + const char *p = start; + + while (p < end) { + switch(*p++) { + case 'f': + *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT; + break; + case 'd': + *permset |= ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT; + break; + case 'i': + *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY; + break; + case 'n': + *permset |= + ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT; + break; + case 'S': + *permset |= ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS; + break; + case 'F': + *permset |= ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS; + break; + case 'I': + *permset |= ARCHIVE_ENTRY_ACL_ENTRY_INHERITED; + 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 @@ -1254,25 +2067,3 @@ next_field(const char **p, const char **start, 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_c(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); -} diff --git a/Utilities/cmlibarchive/libarchive/archive_acl_private.h b/Utilities/cmlibarchive/libarchive/archive_acl_private.h index 1421adb..ef0b023 100644 --- a/Utilities/cmlibarchive/libarchive/archive_acl_private.h +++ b/Utilities/cmlibarchive/libarchive/archive_acl_private.h @@ -56,6 +56,7 @@ struct archive_acl { void archive_acl_clear(struct archive_acl *); void archive_acl_copy(struct archive_acl *, struct archive_acl *); int archive_acl_count(struct archive_acl *, int); +int archive_acl_types(struct archive_acl *); int archive_acl_reset(struct archive_acl *, int); int archive_acl_next(struct archive *, struct archive_acl *, int, int *, int *, int *, int *, const char **); @@ -66,22 +67,17 @@ int archive_acl_add_entry_w_len(struct archive_acl *, 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); -int archive_acl_text_l(struct archive_acl *, int, const char **, size_t *, +wchar_t *archive_acl_to_text_w(struct archive_acl *, ssize_t *, int, + struct archive *); +char *archive_acl_to_text_l(struct archive_acl *, ssize_t *, int, struct archive_string_conv *); /* - * Private ACL parser. This is private because it handles some - * very weird formats that clients should not be messing with. - * Clients should only deal with their platform-native formats. - * Because of the need to support many formats cleanly, new arguments - * are likely to get added on a regular basis. Clients who try to use - * this interface are likely to be surprised when it changes. + * ACL text parser. */ -int archive_acl_parse_w(struct archive_acl *, - const wchar_t *, int /* type */); -int archive_acl_parse_l(struct archive_acl *, - const char *, int /* type */, - struct archive_string_conv *); +int archive_acl_from_text_w(struct archive_acl *, const wchar_t * /* wtext */, + int /* type */); +int archive_acl_from_text_l(struct archive_acl *, const char * /* text */, + int /* type */, struct archive_string_conv *); #endif /* ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */ diff --git a/Utilities/cmlibarchive/libarchive/archive_cryptor.c b/Utilities/cmlibarchive/libarchive/archive_cryptor.c index 2a51dfe..ced52fd 100644 --- a/Utilities/cmlibarchive/libarchive/archive_cryptor.c +++ b/Utilities/cmlibarchive/libarchive/archive_cryptor.c @@ -302,7 +302,8 @@ aes_ctr_release(archive_crypto_ctx *ctx) static int aes_ctr_init(archive_crypto_ctx *ctx, const uint8_t *key, size_t key_len) { - ctx->ctx = EVP_CIPHER_CTX_new(); + if ((ctx->ctx = EVP_CIPHER_CTX_new()) == NULL) + return -1; switch (key_len) { case 16: ctx->type = EVP_aes_128_ecb(); break; diff --git a/Utilities/cmlibarchive/libarchive/archive_entry.c b/Utilities/cmlibarchive/libarchive/archive_entry.c index 4ac1966..d4f061b 100644 --- a/Utilities/cmlibarchive/libarchive/archive_entry.c +++ b/Utilities/cmlibarchive/libarchive/archive_entry.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2003-2007 Tim Kientzle + * Copyright (c) 2016 Martin Matuska * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -248,10 +249,9 @@ archive_entry_new2(struct archive *a) { struct archive_entry *entry; - entry = (struct archive_entry *)malloc(sizeof(*entry)); + entry = (struct archive_entry *)calloc(1, sizeof(*entry)); if (entry == NULL) return (NULL); - memset(entry, 0, sizeof(*entry)); entry->archive = a; return (entry); } @@ -1442,6 +1442,15 @@ archive_entry_acl_add_entry_w(struct archive_entry *entry, } /* + * Return a bitmask of ACL types in an archive entry ACL list + */ +int +archive_entry_acl_types(struct archive_entry *entry) +{ + return (archive_acl_types(&entry->acl)); +} + +/* * Return a count of entries matching "want_type". */ int @@ -1478,34 +1487,121 @@ archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type, } /* - * Generate a text version of the ACL. The flags parameter controls + * Generate a text version of the ACL. The flags parameter controls * the style of the generated ACL. */ +wchar_t * +archive_entry_acl_to_text_w(struct archive_entry *entry, ssize_t *len, + int flags) +{ + return (archive_acl_to_text_w(&entry->acl, len, flags, + entry->archive)); +} + +char * +archive_entry_acl_to_text(struct archive_entry *entry, ssize_t *len, + int flags) +{ + return (archive_acl_to_text_l(&entry->acl, len, flags, NULL)); +} + +char * +_archive_entry_acl_to_text_l(struct archive_entry *entry, ssize_t *len, + int flags, struct archive_string_conv *sc) +{ + return (archive_acl_to_text_l(&entry->acl, len, flags, sc)); +} + +/* + * ACL text parser. + */ +int +archive_entry_acl_from_text_w(struct archive_entry *entry, + const wchar_t *wtext, int type) +{ + return (archive_acl_from_text_w(&entry->acl, wtext, type)); +} + +int +archive_entry_acl_from_text(struct archive_entry *entry, + const char *text, int type) +{ + return (archive_acl_from_text_l(&entry->acl, text, type, NULL)); +} + +int +_archive_entry_acl_from_text_l(struct archive_entry *entry, const char *text, + int type, struct archive_string_conv *sc) +{ + return (archive_acl_from_text_l(&entry->acl, text, type, sc)); +} + +/* Deprecated */ +static int +archive_entry_acl_text_compat(int *flags) +{ + if ((*flags & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) == 0) + return (1); + + /* ABI compat with old ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID */ + if ((*flags & OLD_ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID) != 0) + *flags |= ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID; + + /* ABI compat with old ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT */ + if ((*flags & OLD_ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT) != 0) + *flags |= ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT; + + *flags |= ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA; + + return (0); +} + +/* Deprecated */ const wchar_t * archive_entry_acl_text_w(struct archive_entry *entry, int flags) { - const wchar_t *r; - r = archive_acl_text_w(entry->archive, &entry->acl, flags); - if (r == NULL && errno == ENOMEM) - __archive_errx(1, "No memory"); - return (r); + if (entry->acl.acl_text_w != NULL) { + free(entry->acl.acl_text_w); + entry->acl.acl_text_w = NULL; + } + if (archive_entry_acl_text_compat(&flags) == 0) + entry->acl.acl_text_w = archive_acl_to_text_w(&entry->acl, + NULL, flags, entry->archive); + return (entry->acl.acl_text_w); } +/* Deprecated */ const char * archive_entry_acl_text(struct archive_entry *entry, int flags) { - const char *p; - if (archive_acl_text_l(&entry->acl, flags, &p, NULL, NULL) != 0 - && errno == ENOMEM) - __archive_errx(1, "No memory"); - return (p); + if (entry->acl.acl_text != NULL) { + free(entry->acl.acl_text); + entry->acl.acl_text = NULL; + } + if (archive_entry_acl_text_compat(&flags) == 0) + entry->acl.acl_text = archive_acl_to_text_l(&entry->acl, NULL, + flags, NULL); + + return (entry->acl.acl_text); } +/* Deprecated */ int _archive_entry_acl_text_l(struct archive_entry *entry, int flags, const char **acl_text, size_t *len, struct archive_string_conv *sc) { - return (archive_acl_text_l(&entry->acl, flags, acl_text, len, sc)); + if (entry->acl.acl_text != NULL) { + free(entry->acl.acl_text); + entry->acl.acl_text = NULL; + } + + if (archive_entry_acl_text_compat(&flags) == 0) + entry->acl.acl_text = archive_acl_to_text_l(&entry->acl, + (ssize_t *)len, flags, sc); + + *acl_text = entry->acl.acl_text; + + return (0); } /* diff --git a/Utilities/cmlibarchive/libarchive/archive_entry.h b/Utilities/cmlibarchive/libarchive/archive_entry.h index 81cd425..9427413 100644 --- a/Utilities/cmlibarchive/libarchive/archive_entry.h +++ b/Utilities/cmlibarchive/libarchive/archive_entry.h @@ -1,5 +1,6 @@ /*- * Copyright (c) 2003-2008 Tim Kientzle + * Copyright (c) 2016 Martin Matuska * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -29,7 +30,7 @@ #define ARCHIVE_ENTRY_H_INCLUDED /* Note: Compiler will complain if this does not match archive.h! */ -#define ARCHIVE_VERSION_NUMBER 3002001 +#define ARCHIVE_VERSION_NUMBER 3003000 /* * Note: archive_entry.h is for use outside of libarchive; the @@ -104,6 +105,12 @@ typedef int64_t la_int64_t; # define __LA_DECL #endif +#if defined(__GNUC__) && __GNUC__ >= 3 && __GNUC_MINOR__ >= 1 +# define __LA_DEPRECATED __attribute__((deprecated)) +#else +# define __LA_DEPRECATED +#endif + #ifdef __cplusplus extern "C" { #endif @@ -420,6 +427,7 @@ __LA_DECL void archive_entry_copy_mac_metadata(struct archive_entry *, const voi /* * Inheritance values (NFS4 ACLs only); included in permset. */ +#define ARCHIVE_ENTRY_ACL_ENTRY_INHERITED 0x01000000 #define ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT 0x02000000 #define ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT 0x04000000 #define ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT 0x08000000 @@ -433,15 +441,16 @@ __LA_DECL void archive_entry_copy_mac_metadata(struct archive_entry *, const voi | ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT \ | ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY \ | ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS \ - | ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS) + | ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS \ + | ARCHIVE_ENTRY_ACL_ENTRY_INHERITED) /* We need to be able to specify combinations of these. */ -#define ARCHIVE_ENTRY_ACL_TYPE_ACCESS 256 /* POSIX.1e only */ -#define ARCHIVE_ENTRY_ACL_TYPE_DEFAULT 512 /* POSIX.1e only */ -#define ARCHIVE_ENTRY_ACL_TYPE_ALLOW 1024 /* NFS4 only */ -#define ARCHIVE_ENTRY_ACL_TYPE_DENY 2048 /* NFS4 only */ -#define ARCHIVE_ENTRY_ACL_TYPE_AUDIT 4096 /* NFS4 only */ -#define ARCHIVE_ENTRY_ACL_TYPE_ALARM 8192 /* NFS4 only */ +#define ARCHIVE_ENTRY_ACL_TYPE_ACCESS 0x00000100 /* POSIX.1e only */ +#define ARCHIVE_ENTRY_ACL_TYPE_DEFAULT 0x00000200 /* POSIX.1e only */ +#define ARCHIVE_ENTRY_ACL_TYPE_ALLOW 0x00000400 /* NFS4 only */ +#define ARCHIVE_ENTRY_ACL_TYPE_DENY 0x00000800 /* NFS4 only */ +#define ARCHIVE_ENTRY_ACL_TYPE_AUDIT 0x00001000 /* NFS4 only */ +#define ARCHIVE_ENTRY_ACL_TYPE_ALARM 0x00002000 /* NFS4 only */ #define ARCHIVE_ENTRY_ACL_TYPE_POSIX1E (ARCHIVE_ENTRY_ACL_TYPE_ACCESS \ | ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) #define ARCHIVE_ENTRY_ACL_TYPE_NFS4 (ARCHIVE_ENTRY_ACL_TYPE_ALLOW \ @@ -492,21 +501,51 @@ __LA_DECL int archive_entry_acl_next_w(struct archive_entry *, int /* want_type * Construct a text-format ACL. The flags argument is a bitmask that * can include any of the following: * + * Flags only for archive entries with POSIX.1e ACL: * ARCHIVE_ENTRY_ACL_TYPE_ACCESS - Include POSIX.1e "access" entries. * ARCHIVE_ENTRY_ACL_TYPE_DEFAULT - Include POSIX.1e "default" entries. - * ARCHIVE_ENTRY_ACL_TYPE_NFS4 - Include NFS4 entries. - * ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID - Include extra numeric ID field in - * each ACL entry. ('star' introduced this for POSIX.1e, this flag - * also applies to NFS4.) * ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT - Include "default:" before each - * default ACL entry, as used in old Solaris ACLs. + * default ACL entry. + * ARCHIVE_ENTRY_ACL_STYLE_SOLARIS - Output only one colon after "other" and + * "mask" entries. + * + * Flags only for archive entries with NFSv4 ACL: + * ARCHIVE_ENTRY_ACL_STYLE_COMPACT - Do not output the minus character for + * unset permissions and flags in NFSv4 ACL permission and flag fields + * + * Flags for for archive entries with POSIX.1e ACL or NFSv4 ACL: + * ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID - Include extra numeric ID field in + * each ACL entry. + * ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA - Separate entries with comma + * instead of newline. */ -#define ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 1024 -#define ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 2048 +#define ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 0x00000001 +#define ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 0x00000002 +#define ARCHIVE_ENTRY_ACL_STYLE_SOLARIS 0x00000004 +#define ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA 0x00000008 +#define ARCHIVE_ENTRY_ACL_STYLE_COMPACT 0x00000010 + +__LA_DECL wchar_t *archive_entry_acl_to_text_w(struct archive_entry *, + ssize_t * /* len */, int /* flags */); +__LA_DECL char *archive_entry_acl_to_text(struct archive_entry *, + ssize_t * /* len */, int /* flags */); +__LA_DECL int archive_entry_acl_from_text_w(struct archive_entry *, + const wchar_t * /* wtext */, int /* type */); +__LA_DECL int archive_entry_acl_from_text(struct archive_entry *, + const char * /* text */, int /* type */); + +/* Deprecated constants */ +#define OLD_ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 1024 +#define OLD_ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 2048 + +/* Deprecated functions */ __LA_DECL const wchar_t *archive_entry_acl_text_w(struct archive_entry *, - int /* flags */); + int /* flags */) __LA_DEPRECATED; __LA_DECL const char *archive_entry_acl_text(struct archive_entry *, - int /* flags */); + int /* flags */) __LA_DEPRECATED; + +/* Return bitmask of ACL types in an archive entry */ +__LA_DECL int archive_entry_acl_types(struct archive_entry *); /* Return a count of entries matching 'want_type' */ __LA_DECL int archive_entry_acl_count(struct archive_entry *, int /* want_type */); diff --git a/Utilities/cmlibarchive/libarchive/archive_entry_acl.3 b/Utilities/cmlibarchive/libarchive/archive_entry_acl.3 index 5aff996..c5115f7 100644 --- a/Utilities/cmlibarchive/libarchive/archive_entry_acl.3 +++ b/Utilities/cmlibarchive/libarchive/archive_entry_acl.3 @@ -1,4 +1,5 @@ .\" Copyright (c) 2010 Joerg Sonnenberger +.\" Copyright (c) 2016 Martin Matuska .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without @@ -22,7 +23,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd February 2, 2012 +.Dd February 15, 2017 .Dt ARCHIVE_ENTRY_ACL 3 .Os .Sh NAME @@ -30,10 +31,14 @@ .Nm archive_entry_acl_add_entry_w , .Nm archive_entry_acl_clear , .Nm archive_entry_acl_count , +.Nm archive_entry_acl_from_text , +.Nm archive_entry_acl_from_text_w, .Nm archive_entry_acl_next , .Nm archive_entry_acl_next_w , .Nm archive_entry_acl_reset , -.Nm archive_entry_acl_text_w +.Nm archive_entry_acl_to_text , +.Nm archive_entry_acl_to_text_w , +.Nm archive_entry_acl_types .Nd functions for manipulating Access Control Lists in archive entry descriptions .Sh LIBRARY Streaming Archive Library (libarchive, -larchive) @@ -62,6 +67,18 @@ Streaming Archive Library (libarchive, -larchive) .Ft int .Fn archive_entry_acl_count "struct archive_entry *a" "int type" .Ft int +.Fo archive_entry_acl_from_text +.Fa "struct archive_entry *a" +.Fa "const char *text" +.Fa "int type" +.Fc +.Ft int +.Fo archive_entry_acl_from_text_w +.Fa "struct archive_entry *a" +.Fa "const wchar_t *text" +.Fa "int type" +.Fc +.Ft int .Fo archive_entry_acl_next .Fa "struct archive_entry *a" .Fa "int type" @@ -83,31 +100,48 @@ Streaming Archive Library (libarchive, -larchive) .Fc .Ft int .Fn archive_entry_acl_reset "struct archive_entry *a" "int type" -.Ft const wchar_t * -.Fn archive_entry_acl_text_w "struct archive_entry *a" "int flags" +.Ft char * +.Fo archive_entry_acl_to_text +.Fa "struct archive_entry *a" +.Fa "ssize_t *len_p" +.Fa "int flags" +.Fc +.Ft wchar_t * +.Fo archive_entry_acl_to_text_w +.Fa "struct archive_entry *a" +.Fa "ssize_t *len_p" +.Fa "int flags" +.Fc +.Ft int +.Fn archive_entry_acl_types "struct archive_entry *a" .\" enum? .Sh DESCRIPTION -An -.Dq Access Control List -is a generalisation of the classic Unix permission system. +The +.Dq Access Control Lists (ACLs) +extend the standard Unix perssion model. The ACL interface of .Nm libarchive -is derived from the POSIX.1e draft, but restricted to simplify dealing -with practical implementations in various Operating Systems and archive formats. -.Pp -An ACL consists of a number of independent entries. +supports both POSIX.1e and NFSv4 style ACLs. Use of ACLs is restricted by +various levels of ACL support in operating systems, file systems and archive +formats. +.Ss POSIX.1e Access Control Lists +A POSIX.1e ACL consists of a number of independent entries. Each entry specifies the permission set as bitmask of basic permissions. -Valid permissions are: +Valid permissions in the +.Fa permset +are: .Bl -tag -offset indent -compact -width "ARCHIVE_ENTRY_ACL_EXECUTE" -.It Dv ARCHIVE_ENTRY_ACL_EXECUTE -.It Dv ARCHIVE_ENTRY_ACL_WRITE -.It Dv ARCHIVE_ENTRY_ACL_READ +.It Dv ARCHIVE_ENTRY_ACL_READ ( Sy r ) +.It Dv ARCHIVE_ENTRY_ACL_WRITE ( Sy w ) +.It Dv ARCHIVE_ENTRY_ACL_EXECUTE ( Sy x ) .El The permissions correspond to the normal Unix permissions. .Pp -The tag specifies the principal to which the permission applies. +The +.Fa tag +specifies the principal to which the permission applies. Valid values are: -.Bl -tag -offset indent -compact -width "ARCHIVE_ENTRY_ACL_GROUP_OBJ" +.Bl -hang -offset indent -compact -width "ARCHIVE_ENTRY_ACL_GROUP_OBJ" .It Dv ARCHIVE_ENTRY_ACL_USER The user specified by the name field. .It Dv ARCHIVE_ENTRY_ACL_USER_OBJ @@ -119,8 +153,9 @@ The group who owns the file. .It Dv ARCHIVE_ENTRY_ACL_MASK The maximum permissions to be obtained via group permissions. .It Dv ARCHIVE_ENTRY_ACL_OTHER -Any principal who doesn't have a user or group entry. +Any principal who is not file owner or a member of the owning group. .El +.Pp The principals .Dv ARCHIVE_ENTRY_ACL_USER_OBJ , .Dv ARCHIVE_ENTRY_ACL_GROUP_OBJ @@ -129,19 +164,123 @@ and are equivalent to user, group and other in the classic Unix permission model and specify non-extended ACL entries. .Pp -All files have an access ACL +All files with have an access ACL .Pq Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS . This specifies the permissions required for access to the file itself. Directories have an additional ACL .Pq Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT , which controls the initial access ACL for newly created directory entries. +.Ss NFSv4 Access Control Lists +A NFSv4 ACL consists of multiple individual entries called Access Control +Entries (ACEs). +.Pp +There are four possible types of a NFSv4 ACE: +.Bl -hang -offset indent -compact -width "ARCHIVE_ENTRY_ACL_TYE_ALLOW" +.It Dv ARCHIVE_ENTRY_ACL_TYPE_ALLOW +Allow principal to perform actions requiring given permissions. +.It Dv ARCHIVE_ENTRY_ACL_TYPE_DENY +Prevent principal from performing actions requiring given permissions. +.It Dv ARCHIVE_ENTRY_ACL_TYPE_AUDIT +Log access attempts by principal which require given permissions. +.It Dv ARCHIVE_ENTRY_ACL_TYPE_ALARM +Trigger a system alarm on access attempts by principal which require given +permissions. +.El +.Pp +The +.Fa tag +specifies the principal to which the permission applies. +Valid values are: +.Bl -hang -offset indent -compact -width "ARCHIVE_ENTRY_ACL_GROUP_OBJ" +.It Dv ARCHIVE_ENTRY_ACL_USER +The user specified by the name field. +.It Dv ARCHIVE_ENTRY_ACL_USER_OBJ +The owner of the file. +.It Dv ARCHIVE_ENTRY_ACL_GROUP +The group specied by the name field. +.It Dv ARCHIVE_ENTRY_ACL_GROUP_OBJ +The group who owns the file. +.It Dv ARCHIVE_ENTRY_ACL_EVERYONE +Any principal who is not file owner or a member of the owning group. +.El +.Pp +Entries with the +.Dv ARCHIVE_ENTRY_ACL_USER +or +.Dv ARCHIVE_ENTRY_ACL_GROUP +tag store the user and group name in the +.Fa name +string and optionally the user or group ID in the +.Fa qualifier +integer. +.Pp +NFSv4 ACE permissions and flags are stored in the same +.Fa permset +bitfield. Some permissions share the same constant and permission character but +have different effect on directories than on files. The following ACE +permissions are supported: +.Bl -tag -offset indent -compact -width ARCHIV +.It Dv ARCHIVE_ENTRY_ACL_READ_DATA ( Sy r ) +Read data (file). +.It Dv ARCHIVE_ENTRY_ACL_LIST_DIRECTORY ( Sy r ) +List entries (directory). +.It ARCHIVE_ENTRY_ACL_WRITE_DATA ( Sy w ) +Write data (file). +.It ARCHIVE_ENTRY_ACL_ADD_FILE ( Sy w ) +Create files (directory). +.It Dv ARCHIVE_ENTRY_ACL_EXECUTE ( Sy x ) +Execute file or change into a directory. +.It Dv ARCHIVE_ENTRY_ACL_APPEND_DATA ( Sy p ) +Append data (file). +.It Dv ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY ( Sy p ) +Create subdirectories (directory). +.It Dv ARCHIVE_ENTRY_ACL_DELETE_CHILD ( Sy D ) +Remove files and subdirectories inside a directory. +.It Dv ARCHIVE_ENTRY_ACL_DELETE ( Sy d ) +Remove file or directory. +.It Dv ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES ( Sy a ) +Read file or directory attributes. +.It Dv ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES ( Sy A ) +Write file or directory attributes. +.It Dv ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS ( Sy R ) +Read named file or directory attributes. +.It Dv ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS ( Sy W ) +Write named file or directory attributes. +.It Dv ARCHIVE_ENTRY_ACL_READ_ACL ( Sy c ) +Read file or directory ACL. +.It Dv ARCHIVE_ENTRY_ACL_WRITE_ACL ( Sy C ) +Write file or directory ACL. +.It Dv ARCHIVE_ENTRY_ACL_WRITE_OWNER ( Sy o ) +Change owner of a file or directory. +.It Dv ARCHIVE_ENTRY_ACL_SYNCHRONIZE ( Sy s ) +Use synchronous I/O. +.El .Pp +The following NFSv4 ACL inheritance flags are supported: +.Bl -tag -offset indent -compact -width ARCHIV +.It Dv ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT ( Sy f ) +Inherit parent directory ACE to files. +.It Dv ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT ( Sy d ) +Inherit parent directory ACE to subdirectories. +.It Dv ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY ( Sy i ) +Only inherit, do not apply the permission on the directory itself. +.It Dv ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT ( Sy n ) +Do not propagate inherit flags. Only first-level entries inherit ACLs. +.It Dv ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS ( Sy S ) +Trigger alarm or audit on succesful access. +.It Dv ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS ( Sy F ) +Trigger alarm or audit on failed access. +.It Dv ARCHIVE_ENTRY_ACL_ENTRY_INHERITED ( Sy I ) +Mark that ACE was inherited. +.El +.Ss Functions .Fn archive_entry_acl_add_entry and .Fn archive_entry_acl_add_entry_w add a single ACL entry. For the access ACL and non-extended principals, the classic Unix permissions -are updated. +are updated. An archive enry cannot contain both POSIX.1e and NFSv4 ACL +entries. .Pp .Fn archive_entry_acl_clear removes all ACL entries and resets the enumeration pointer. @@ -150,14 +289,58 @@ removes all ACL entries and resets the enumeration pointer. counts the ACL entries that have the given type mask. .Fa type can be the bitwise-or of -.Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS -and -.Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT . -If +.Bl -tag -offset indent -compact -width "ARCHIVE_ENTRY_ACL_TYPE_DEFAULT" +.It Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS +.It Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT +.El +for POSIX.1e ACLs and +.Bl -tag -offset indent -compact -width "ARCHIVE_ENTRY_ACL_TYPE_ALLOW" +.It Dv ARCHIVE_ENTRY_ACL_TYPE_ALLOW +.It Dv ARCHIVE_ENTRY_ACL_TYPE_DENY +.It Dv ARCHIVE_ENTRY_ACL_TYPE_AUDIT +.It Dv ARCHIVE_ENTRY_ACL_TYPE_ALARM +.El +for NFSv4 ACLs. For POSIX.1e ACLs if .Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS is included and at least one extended ACL entry is found, the three non-extened ACLs are added. .Pp +.Fn archive_entry_acl_from_text +and +.Fn archive_entry_acl_from_text_w +add new +.Pq or merge with existing +ACL entries from +.Pq wide +text. The argument +.Fa type +may take one of the following values: +.Bl -tag -offset indent -compact -width "ARCHIVE_ENTRY_ACL_TYPE_DEFAULT" +.It Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS +.It Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT +.It Dv ARCHIVE_ENTRY_ACL_TYPE_NFS4 +.El +Supports all formats that can be created with +.Fn archive_entry_acl_to_text +or respective +.Fn archive_entry_acl_to_text_w . +Existing ACL entries are preserved. To get a clean new ACL from text +.Fn archive_entry_acl_clear +must be called first. Entries prefixed with +.Dq default: +are treated as +.Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT +unless +.Fa type +is +.Dv ARCHIVE_ENTRY_ACL_TYPE_NFS4 . +Invalid entries, non-parseable ACL entries and entries beginning with +the +.Sq # +character +.Pq comments +are skipped. +.Pp .Fn archive_entry_acl_next and .Fn archive_entry_acl_next_w @@ -179,29 +362,81 @@ or set using Otherwise, the function returns the same value as .Fn archive_entry_acl_count . .Pp -.Fn archive_entry_acl_text_w -converts the ACL entries for the given type mask into a wide string. -In addition to the normal type flags, -.Dv ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID +.Fn archive_entry_acl_to_text and -.Dv ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT -can be specified to further customize the result. -The returned long string is valid until the next call to -.Fn archive_entry_acl_clear , -.Fn archive_entry_acl_add_entry , -.Fn archive_entry_acl_add_entry_w +.Fn archive_entry_acl_to_text_w +convert the ACL entries for the given type into a +.Pq wide +string of ACL entries separated by newline. If the the pointer +.Fa len_p +is not NULL, then the function shall return the length of the string +.Pq not including the NULL terminator +in the location pointed to by +.Fa len_p . +The +.Fa flag +argument is a bitwise-or. +.Pp +The following flags are effective only on POSIX.1e ACL: +.Bl -tag -offset indent -compact -width ARCHIV +.It Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS +Output access ACLs. +.It Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT +Output POSIX.1e default ACLs. +.It Dv ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT +Prefix each default ACL entry with the word +.Dq default: . +.It Dv ARCHIVE_ENTRY_ACL_STYLE_SOLARIS +The mask and other ACLs don not contain a double colon. +.El +.Pp +The following flags are effecive only on NFSv4 ACL: +.Bl -tag -offset indent -compact -width ARCHIV +.It Dv ARCHIVE_ENTRY_ACL_STYLE_COMPACT +Do not output minus characters for unset permissions and flags in NFSv4 ACL +permission and flag fields. +.El +.Pp +The following flags are effective on both POSIX.1e and NFSv4 ACL: +.Bl -tag -offset indent -compact -width ARCHIV +.It Dv ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID +Add an additional colon-separated field containing the user or group id. +.It Dv ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA +Separate ACL entries with comma instead of newline. +.El +.Pp +If the archive entry contains NFSv4 ACLs, all types of NFSv4 ACLs are returned. +It the entry contains POSIX.1e ACLs and none of the flags +.Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS or -.Fn archive_entry_acl_text_w . +.Dv ARCHIVE_ENTRY_ACL_TYPE_DEFAULT +are specified, both access and default entries are returned and default entries +are prefixed with +.Dq default: . +.Pp +.Fn archive_entry_acl_types +get ACL entry types contained in an archive entry's ACL. As POSIX.1e and NFSv4 +ACL entries cannot be mixed, this function is a very efficient way to detect if +an ACL already contains POSIX.1e or NFSv4 ACL entries. .Sh RETURN VALUES .Fn archive_entry_acl_count and .Fn archive_entry_acl_reset returns the number of ACL entries that match the given type mask. -If the type mask includes +For POSIX.1e ACLS if the type mask includes .Dv ARCHIVE_ENTRY_ACL_TYPE_ACCESS and at least one extended ACL entry exists, the three classic Unix permissions are counted. .Pp +.Fn archive_entry_acl_from_text +and +.Fn archive_entry_acl_from_text_w +return +.Dv ARCHIVE_OK +if all entries were successfully parsed and +.Dv ARCHIVE_WARN +if one or more entries were invalid or non-parseable. +.Pp .Fn archive_entry_acl_next and .Fn archive_entry_acl_next_w @@ -216,20 +451,16 @@ if .Fn archive_entry_acl_reset has not been called first. .Pp -.Fn archive_entry_text_w -returns a wide string representation of the ACL entrise matching the -given type mask. -The returned long string is valid until the next call to -.Fn archive_entry_acl_clear , -.Fn archive_entry_acl_add_entry , -.Fn archive_entry_acl_add_entry_w -or -.Fn archive_entry_acl_text_w . +.Fn archive_entry_acl_to_text +returns a string representing the ACL entries matching the given type and +flags on success or NULL on error. +.Pp +.Fn archive_entry_acl_to_text_w +returns a wide string representing the ACL entries matching the given type +and flags on success or NULL on error. +.Pp +.Fn archive_entry_acl_types +returns a bitmask of ACL entry types or 0 if archive entry has no ACL entries. .Sh SEE ALSO -.Xr archive_entry 3 -.Xr libarchive 3 , -.Sh BUGS -.Dv ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID -and -.Dv ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT -are not documented. +.Xr archive_entry 3 , +.Xr libarchive 3 diff --git a/Utilities/cmlibarchive/libarchive/archive_entry_locale.h b/Utilities/cmlibarchive/libarchive/archive_entry_locale.h index 02e024a..44550c5 100644 --- a/Utilities/cmlibarchive/libarchive/archive_entry_locale.h +++ b/Utilities/cmlibarchive/libarchive/archive_entry_locale.h @@ -63,9 +63,13 @@ int _archive_entry_uname_l(struct archive_entry *, const char **, size_t *, struct archive_string_conv *); #define archive_entry_acl_text_l _archive_entry_acl_text_l int _archive_entry_acl_text_l(struct archive_entry *, int, - const char **, size_t *, struct archive_string_conv *); - - +const char **, size_t *, struct archive_string_conv *) __LA_DEPRECATED; +#define archive_entry_acl_to_text_l _archive_entry_acl_to_text_l +char *_archive_entry_acl_to_text_l(struct archive_entry *, ssize_t *, int, + struct archive_string_conv *); +#define archive_entry_acl_from_text_l _archive_entry_acl_from_text_l +int _archive_entry_acl_from_text_l(struct archive_entry *, const char* text, + int type, struct archive_string_conv *); #define archive_entry_copy_gname_l _archive_entry_copy_gname_l int _archive_entry_copy_gname_l(struct archive_entry *, const char *, size_t, struct archive_string_conv *); diff --git a/Utilities/cmlibarchive/libarchive/archive_entry_strmode.c b/Utilities/cmlibarchive/libarchive/archive_entry_strmode.c index 16cb3f7..af2517a 100644 --- a/Utilities/cmlibarchive/libarchive/archive_entry_strmode.c +++ b/Utilities/cmlibarchive/libarchive/archive_entry_strmode.c @@ -80,7 +80,7 @@ archive_entry_strmode(struct archive_entry *entry) if (mode & 0001) bp[9] = 't'; else bp[9] = 'T'; } - if (archive_entry_acl_count(entry, ARCHIVE_ENTRY_ACL_TYPE_ACCESS)) + if (archive_entry_acl_types(entry) != 0) bp[10] = '+'; return (bp); diff --git a/Utilities/cmlibarchive/libarchive/archive_match.c b/Utilities/cmlibarchive/libarchive/archive_match.c index 4c41bad..be72066 100644 --- a/Utilities/cmlibarchive/libarchive/archive_match.c +++ b/Utilities/cmlibarchive/libarchive/archive_match.c @@ -471,7 +471,7 @@ archive_match_path_excluded(struct archive *_a, } /* - * Utilty functions to get statistic information for inclusion patterns. + * Utility functions to get statistic information for inclusion patterns. */ int archive_match_path_unmatched_inclusions(struct archive *_a) @@ -655,7 +655,7 @@ add_pattern_from_file(struct archive_match *a, struct match_list *mlist, } } - /* If something error happend, report it immediately. */ + /* If an error occurred, report it immediately. */ if (r < ARCHIVE_OK) { archive_copy_error(&(a->archive), ar); archive_read_free(ar); @@ -1270,7 +1270,7 @@ set_timefilter_pathname_wcs(struct archive_match *a, int timetype, #endif /* _WIN32 && !__CYGWIN__ */ /* - * Call back funtions for archive_rb. + * Call back functions for archive_rb. */ static int cmp_node_mbs(const struct archive_rb_node *n1, @@ -1405,7 +1405,7 @@ add_entry(struct archive_match *a, int flag, &(a->exclusion_tree), pathname); /* - * We always overwrite comparison condision. + * We always overwrite comparison condition. * If you do not want to overwrite it, you should not * call archive_match_exclude_entry(). We cannot know * what behavior you really expect since overwriting @@ -1481,7 +1481,7 @@ time_excluded(struct archive_match *a, struct archive_entry *entry) if (nsec == a->older_ctime_nsec && (a->older_ctime_filter & ARCHIVE_MATCH_EQUAL) == 0) - return (1); /* Eeual, skip it. */ + return (1); /* Equal, skip it. */ } } if (a->newer_mtime_filter) { @@ -1513,7 +1513,7 @@ time_excluded(struct archive_match *a, struct archive_entry *entry) } } - /* If there is no excluson list, include the file. */ + /* If there is no exclusion list, include the file. */ if (a->exclusion_entry_list.count == 0) return (0); @@ -1700,7 +1700,7 @@ add_owner_id(struct archive_match *a, struct id_array *ids, int64_t id) break; } - /* Add oowner id. */ + /* Add owner id. */ if (i == ids->count) ids->ids[ids->count++] = id; else if (ids->ids[i] != id) { diff --git a/Utilities/cmlibarchive/libarchive/archive_openssl_evp_private.h b/Utilities/cmlibarchive/libarchive/archive_openssl_evp_private.h index 0e97e27..43a3ccc 100644 --- a/Utilities/cmlibarchive/libarchive/archive_openssl_evp_private.h +++ b/Utilities/cmlibarchive/libarchive/archive_openssl_evp_private.h @@ -33,10 +33,7 @@ #include <string.h> /* memset */ static inline EVP_MD_CTX *EVP_MD_CTX_new(void) { - EVP_MD_CTX *ctx = (EVP_MD_CTX *)malloc(sizeof(EVP_MD_CTX)); - if (ctx != NULL) { - memset(ctx, 0, sizeof(*ctx)); - } + EVP_MD_CTX *ctx = (EVP_MD_CTX *)calloc(1, sizeof(EVP_MD_CTX)); return ctx; } diff --git a/Utilities/cmlibarchive/libarchive/archive_openssl_hmac_private.h b/Utilities/cmlibarchive/libarchive/archive_openssl_hmac_private.h index d4ae0d1..2deeb5f 100644 --- a/Utilities/cmlibarchive/libarchive/archive_openssl_hmac_private.h +++ b/Utilities/cmlibarchive/libarchive/archive_openssl_hmac_private.h @@ -33,11 +33,7 @@ #include <string.h> /* memset */ static inline HMAC_CTX *HMAC_CTX_new(void) { - HMAC_CTX *ctx = (HMAC_CTX *)malloc(sizeof(HMAC_CTX)); - if (ctx != NULL) { - memset(ctx, 0, sizeof(*ctx)); - HMAC_CTX_init(ctx); - } + HMAC_CTX *ctx = (HMAC_CTX *)calloc(1, sizeof(HMAC_CTX)); return ctx; } diff --git a/Utilities/cmlibarchive/libarchive/archive_options.c b/Utilities/cmlibarchive/libarchive/archive_options.c index dbf3e80..6496025 100644 --- a/Utilities/cmlibarchive/libarchive/archive_options.c +++ b/Utilities/cmlibarchive/libarchive/archive_options.c @@ -26,6 +26,10 @@ #include "archive_platform.h" __FBSDID("$FreeBSD$"); +#ifdef HAVE_ERRNO_H +#include <errno.h> +#endif + #include "archive_options_private.h" static const char * @@ -105,8 +109,11 @@ _archive_set_options(struct archive *a, const char *options, if (options == NULL || options[0] == '\0') return ARCHIVE_OK; - data = (char *)malloc(strlen(options) + 1); - strcpy(data, options); + if ((data = strdup(options)) == NULL) { + archive_set_error(a, + ENOMEM, "Out of memory adding file to list"); + return (ARCHIVE_FATAL); + } s = (const char *)data; do { diff --git a/Utilities/cmlibarchive/libarchive/archive_platform.h b/Utilities/cmlibarchive/libarchive/archive_platform.h index 08a384c..47d144b 100644 --- a/Utilities/cmlibarchive/libarchive/archive_platform.h +++ b/Utilities/cmlibarchive/libarchive/archive_platform.h @@ -152,8 +152,25 @@ * acl_set_file(), and ACL_USER, we assume it has the rest of the * POSIX.1e draft functions used in archive_read_extract.c. */ -#if HAVE_SYS_ACL_H && HAVE_ACL_CREATE_ENTRY && HAVE_ACL_INIT && HAVE_ACL_SET_FILE && HAVE_ACL_USER +#if HAVE_SYS_ACL_H && HAVE_ACL_CREATE_ENTRY && HAVE_ACL_INIT && HAVE_ACL_SET_FILE +#if HAVE_ACL_USER #define HAVE_POSIX_ACL 1 +#elif HAVE_ACL_TYPE_EXTENDED +#define HAVE_DARWIN_ACL 1 +#endif +#endif + +/* + * If this platform has <sys/acl.h>, acl_get(), facl_get(), acl_set(), + * facl_set() and types aclent_t and ace_t it uses Solaris-style ACL functions + */ +#if HAVE_SYS_ACL_H && HAVE_ACL_GET && HAVE_FACL_GET && HAVE_ACL_SET && HAVE_FACL_SET && HAVE_ACLENT_T && HAVE_ACE_T +#define HAVE_SUN_ACL 1 +#endif + +/* Define if platform supports NFSv4 ACLs */ +#if (HAVE_POSIX_ACL && HAVE_ACL_TYPE_NFS4) || HAVE_SUN_ACL || HAVE_DARWIN_ACL +#define HAVE_NFS4_ACL 1 #endif /* @@ -164,6 +181,15 @@ #define CAN_RESTORE_METADATA_FD #endif +/* + * glibc 2.24 deprecates readdir_r + */ +#if defined(HAVE_READDIR_R) && (!defined(__GLIBC__) || !defined(__GLIBC_MINOR__) || __GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 24)) +#define USE_READDIR_R 1 +#else +#undef USE_READDIR_R +#endif + /* Set up defaults for internal error codes. */ #ifndef ARCHIVE_ERRNO_FILE_FORMAT #if HAVE_EFTYPE diff --git a/Utilities/cmlibarchive/libarchive/archive_ppmd7_private.h b/Utilities/cmlibarchive/libarchive/archive_ppmd7_private.h index 3a6b9eb..06c99e8 100644 --- a/Utilities/cmlibarchive/libarchive/archive_ppmd7_private.h +++ b/Utilities/cmlibarchive/libarchive/archive_ppmd7_private.h @@ -19,7 +19,7 @@ If you need the compatibility with original PPMd var.H, you can use external Ran #define PPMD7_MAX_ORDER 64 #define PPMD7_MIN_MEM_SIZE (1 << 11) -#define PPMD7_MAX_MEM_SIZE (0xFFFFFFFF - 12 * 3) +#define PPMD7_MAX_MEM_SIZE (0xFFFFFFFFu - 12 * 3) struct CPpmd7_Context_; diff --git a/Utilities/cmlibarchive/libarchive/archive_random.c b/Utilities/cmlibarchive/libarchive/archive_random.c index a20b9b1..357f973 100644 --- a/Utilities/cmlibarchive/libarchive/archive_random.c +++ b/Utilities/cmlibarchive/libarchive/archive_random.c @@ -80,7 +80,7 @@ archive_random(void *buf, size_t nbytes) success = CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT); - if (!success && GetLastError() == NTE_BAD_KEYSET) { + if (!success && GetLastError() == (DWORD)NTE_BAD_KEYSET) { success = CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET); } diff --git a/Utilities/cmlibarchive/libarchive/archive_rb.c b/Utilities/cmlibarchive/libarchive/archive_rb.c index 5b5da20..cf58ac3 100644 --- a/Utilities/cmlibarchive/libarchive/archive_rb.c +++ b/Utilities/cmlibarchive/libarchive/archive_rb.c @@ -312,7 +312,7 @@ __archive_rb_tree_insert_rebalance(struct archive_rb_tree *rbt, father = RB_FATHER(self); if (RB_BLACK_P(father)) { /* - * If our greatgrandpa is black, we're done. + * If our great-grandpa is black, we're done. */ return; } diff --git a/Utilities/cmlibarchive/libarchive/archive_read.c b/Utilities/cmlibarchive/libarchive/archive_read.c index 0bbacc8..d1feceb 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read.c +++ b/Utilities/cmlibarchive/libarchive/archive_read.c @@ -57,6 +57,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read.c 201157 2009-12-29 05:30:2 static int choose_filters(struct archive_read *); static int choose_format(struct archive_read *); +static int close_filters(struct archive_read *); static struct archive_vtable *archive_read_vtable(void); static int64_t _archive_filter_bytes(struct archive *, int); static int _archive_filter_code(struct archive *, int); @@ -528,7 +529,7 @@ archive_read_open1(struct archive *_a) { slot = choose_format(a); if (slot < 0) { - __archive_read_close_filters(a); + close_filters(a); a->archive.state = ARCHIVE_STATE_FATAL; return (ARCHIVE_FATAL); } @@ -582,7 +583,6 @@ choose_filters(struct archive_read *a) /* Verify the filter by asking it for some data. */ __archive_read_filter_ahead(a->filter, 1, &avail); if (avail < 0) { - __archive_read_close_filters(a); __archive_read_free_filters(a); return (ARCHIVE_FATAL); } @@ -601,7 +601,6 @@ choose_filters(struct archive_read *a) a->filter = filter; r = (best_bidder->init)(a->filter); if (r != ARCHIVE_OK) { - __archive_read_close_filters(a); __archive_read_free_filters(a); return (ARCHIVE_FATAL); } @@ -765,7 +764,7 @@ archive_read_header_position(struct archive *_a) * we cannot say whether there are encrypted entries, then * ARCHIVE_READ_FORMAT_ENCRYPTION_DONT_KNOW is returned. * In general, this function will return values below zero when the - * reader is uncertain or totally uncapable of encryption support. + * reader is uncertain or totally incapable of encryption support. * When this function returns 0 you can be sure that the reader * supports encryption detection but no encrypted entries have * been found yet. @@ -986,8 +985,8 @@ _archive_read_data_block(struct archive *_a, return (a->format->read_data)(a, buff, size, offset); } -int -__archive_read_close_filters(struct archive_read *a) +static int +close_filters(struct archive_read *a) { struct archive_read_filter *f = a->filter; int r = ARCHIVE_OK; @@ -1010,6 +1009,9 @@ __archive_read_close_filters(struct archive_read *a) void __archive_read_free_filters(struct archive_read *a) { + /* Make sure filters are closed and their buffers are freed */ + close_filters(a); + while (a->filter != NULL) { struct archive_read_filter *t = a->filter->upstream; free(a->filter); @@ -1052,7 +1054,7 @@ _archive_read_close(struct archive *_a) /* TODO: Clean up the formatters. */ /* Release the filter objects. */ - r1 = __archive_read_close_filters(a); + r1 = close_filters(a); if (r1 < r) r = r1; diff --git a/Utilities/cmlibarchive/libarchive/archive_read_add_passphrase.c b/Utilities/cmlibarchive/libarchive/archive_read_add_passphrase.c index f67f1eb..cf821b5 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_add_passphrase.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_add_passphrase.c @@ -125,7 +125,7 @@ void __archive_read_reset_passphrase(struct archive_read *a) { - a->passphrases.candiate = -1; + a->passphrases.candidate = -1; } /* @@ -137,31 +137,31 @@ __archive_read_next_passphrase(struct archive_read *a) struct archive_read_passphrase *p; const char *passphrase; - if (a->passphrases.candiate < 0) { + if (a->passphrases.candidate < 0) { /* Count out how many passphrases we have. */ int cnt = 0; for (p = a->passphrases.first; p != NULL; p = p->next) cnt++; - a->passphrases.candiate = cnt; + a->passphrases.candidate = cnt; p = a->passphrases.first; - } else if (a->passphrases.candiate > 1) { + } else if (a->passphrases.candidate > 1) { /* Rotate a passphrase list. */ - a->passphrases.candiate--; + a->passphrases.candidate--; p = remove_passphrases_from_head(a); add_passphrase_to_tail(a, p); - /* Pick a new passphrase candiate up. */ + /* Pick a new passphrase candidate up. */ p = a->passphrases.first; - } else if (a->passphrases.candiate == 1) { - /* This case is that all cadiates failed to decryption. */ - a->passphrases.candiate = 0; + } else if (a->passphrases.candidate == 1) { + /* This case is that all candidates failed to decrypt. */ + a->passphrases.candidate = 0; if (a->passphrases.first->next != NULL) { /* Rotate a passphrase list. */ p = remove_passphrases_from_head(a); add_passphrase_to_tail(a, p); } p = NULL; - } else /* There is no passphrase candaite. */ + } else /* There is no passphrase candidate. */ p = NULL; if (p != NULL) @@ -177,7 +177,7 @@ __archive_read_next_passphrase(struct archive_read *a) if (p == NULL) return (NULL); insert_passphrase_to_head(a, p); - a->passphrases.candiate = 1; + a->passphrases.candidate = 1; } } else passphrase = NULL; diff --git a/Utilities/cmlibarchive/libarchive/archive_read_append_filter.c b/Utilities/cmlibarchive/libarchive/archive_read_append_filter.c index 3a0d4d6..5e4d163 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_append_filter.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_append_filter.c @@ -133,7 +133,6 @@ archive_read_append_filter(struct archive *_a, int code) a->filter = filter; r2 = (bidder->init)(a->filter); if (r2 != ARCHIVE_OK) { - __archive_read_close_filters(a); __archive_read_free_filters(a); return (ARCHIVE_FATAL); } @@ -191,7 +190,6 @@ archive_read_append_filter_program_signature(struct archive *_a, a->filter = filter; r = (bidder->init)(a->filter); if (r != ARCHIVE_OK) { - __archive_read_close_filters(a); __archive_read_free_filters(a); return (ARCHIVE_FATAL); } diff --git a/Utilities/cmlibarchive/libarchive/archive_read_disk.3 b/Utilities/cmlibarchive/libarchive/archive_read_disk.3 index 525dc59..2a5c130 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_disk.3 +++ b/Utilities/cmlibarchive/libarchive/archive_read_disk.3 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd February 2, 2012 +.Dd December 30, 2016 .Dt ARCHIVE_READ_DISK 3 .Os .Sh NAME @@ -54,9 +54,9 @@ Streaming Archive Library (libarchive, -larchive) .Fn archive_read_disk_set_symlink_physical "struct archive *" .Ft int .Fn archive_read_disk_set_symlink_hybrid "struct archive *" -.Ft int +.Ft const char * .Fn archive_read_disk_gname "struct archive *" "gid_t" -.Ft int +.Ft const char * .Fn archive_read_disk_uname "struct archive *" "uid_t" .Ft int .Fo archive_read_disk_set_gname_lookup diff --git a/Utilities/cmlibarchive/libarchive/archive_read_disk_entry_from_file.c b/Utilities/cmlibarchive/libarchive/archive_read_disk_entry_from_file.c index 74fe353..591a212 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_disk_entry_from_file.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_disk_entry_from_file.c @@ -1,6 +1,7 @@ /*- * Copyright (c) 2003-2009 Tim Kientzle * Copyright (c) 2010-2012 Michihiro NAKAJIMA + * Copyright (c) 2016 Martin Matuska * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -37,6 +38,11 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 2010 #ifdef HAVE_SYS_ACL_H #include <sys/acl.h> #endif +#ifdef HAVE_DARWIN_ACL +#include <membership.h> +#include <grp.h> +#include <pwd.h> +#endif #ifdef HAVE_SYS_EXTATTR_H #include <sys/extattr.h> #endif @@ -117,6 +123,15 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 2010 #define ACL_GET_PERM acl_get_perm_np #endif +/* NFSv4 platform ACL type */ +#if HAVE_SUN_ACL +#define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACE_T +#elif HAVE_DARWIN_ACL +#define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACL_TYPE_EXTENDED +#elif HAVE_ACL_TYPE_NFS4 +#define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACL_TYPE_NFS4 +#endif + static int setup_acls(struct archive_read_disk *, struct archive_entry *, int *fd); static int setup_mac_metadata(struct archive_read_disk *, @@ -125,6 +140,10 @@ static int setup_xattrs(struct archive_read_disk *, struct archive_entry *, int *fd); static int setup_sparse(struct archive_read_disk *, struct archive_entry *, int *fd); +#if defined(HAVE_LINUX_FIEMAP_H) +static int setup_sparse_fiemap(struct archive_read_disk *, + struct archive_entry *, int *fd); +#endif int archive_read_disk_entry_from_file(struct archive *_a, @@ -302,20 +321,17 @@ setup_mac_metadata(struct archive_read_disk *a, name = archive_entry_sourcepath(entry); if (name == NULL) name = archive_entry_pathname(entry); + else if (a->tree != NULL && a->tree_enter_working_dir(a->tree) != 0) { + archive_set_error(&a->archive, errno, + "Can't change dir to read extended attributes"); + return (ARCHIVE_FAILED); + } if (name == NULL) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Can't open file to read extended attributes: No name"); return (ARCHIVE_WARN); } - if (a->tree != NULL) { - if (a->tree_enter_working_dir(a->tree) != 0) { - archive_set_error(&a->archive, errno, - "Couldn't change dir"); - return (ARCHIVE_FAILED); - } - } - /* Short-circuit if there's nothing to do. */ have_attrs = copyfile(name, NULL, 0, copyfile_flags | COPYFILE_CHECK); if (have_attrs == -1) { @@ -400,34 +416,87 @@ setup_mac_metadata(struct archive_read_disk *a, } #endif +#if HAVE_DARWIN_ACL +static int translate_guid(struct archive *, acl_entry_t, + int *, int *, const char **); + +static void add_trivial_nfs4_acl(struct archive_entry *); +#endif + +#if HAVE_SUN_ACL +static int +sun_acl_is_trivial(acl_t *, mode_t, int *trivialp); +#endif -#ifdef HAVE_POSIX_ACL +#if HAVE_POSIX_ACL || HAVE_NFS4_ACL static int translate_acl(struct archive_read_disk *a, - struct archive_entry *entry, acl_t acl, int archive_entry_acl_type); + struct archive_entry *entry, +#if HAVE_SUN_ACL + acl_t *acl, +#else + acl_t acl, +#endif + int archive_entry_acl_type); static int setup_acls(struct archive_read_disk *a, struct archive_entry *entry, int *fd) { const char *accpath; - acl_t acl; -#if HAVE_ACL_IS_TRIVIAL_NP - int r; +#if HAVE_SUN_ACL + acl_t *acl; +#else + acl_t acl; #endif + int r; - accpath = archive_entry_sourcepath(entry); - if (accpath == NULL) - accpath = archive_entry_pathname(entry); + accpath = NULL; + +#if HAVE_SUN_ACL || HAVE_DARWIN_ACL || HAVE_ACL_GET_FD_NP + if (*fd < 0) +#else + /* For default ACLs on Linux we need reachable accpath */ + if (*fd < 0 || S_ISDIR(archive_entry_mode(entry))) +#endif + { + accpath = archive_entry_sourcepath(entry); + if (accpath == NULL || (a->tree != NULL && + a->tree_enter_working_dir(a->tree) != 0)) + accpath = archive_entry_pathname(entry); + if (accpath == NULL) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Couldn't determine file path to read ACLs"); + return (ARCHIVE_WARN); + } + if (a->tree != NULL && +#if !HAVE_SUN_ACL && !HAVE_DARWIN_ACL && !HAVE_ACL_GET_FD_NP + *fd < 0 && +#endif + (a->follow_symlinks || + archive_entry_filetype(entry) != AE_IFLNK)) { + *fd = a->open_on_current_dir(a->tree, + accpath, O_RDONLY | O_NONBLOCK); + } + } archive_entry_acl_clear(entry); -#ifdef ACL_TYPE_NFS4 - /* Try NFS4 ACL first. */ + acl = NULL; + +#if HAVE_NFS4_ACL + /* Try NFSv4 ACL first. */ if (*fd >= 0) +#if HAVE_SUN_ACL + /* Solaris reads both POSIX.1e and NFSv4 ACL here */ + facl_get(*fd, 0, &acl); +#elif HAVE_ACL_GET_FD_NP + acl = acl_get_fd_np(*fd, ARCHIVE_PLATFORM_ACL_TYPE_NFS4); +#else acl = acl_get_fd(*fd); +#endif #if HAVE_ACL_GET_LINK_NP else if (!a->follow_symlinks) - acl = acl_get_link_np(accpath, ACL_TYPE_NFS4); + acl = acl_get_link_np(accpath, ARCHIVE_PLATFORM_ACL_TYPE_NFS4); #else else if ((!a->follow_symlinks) && (archive_entry_filetype(entry) == AE_IFLNK)) @@ -436,21 +505,62 @@ setup_acls(struct archive_read_disk *a, acl = NULL; #endif else - acl = acl_get_file(accpath, ACL_TYPE_NFS4); -#if HAVE_ACL_IS_TRIVIAL_NP +#if HAVE_SUN_ACL + /* Solaris reads both POSIX.1e and NFSv4 ACLs here */ + acl_get(accpath, 0, &acl); +#else + acl = acl_get_file(accpath, ARCHIVE_PLATFORM_ACL_TYPE_NFS4); +#endif + + +#if HAVE_ACL_IS_TRIVIAL_NP || HAVE_SUN_ACL /* Ignore "trivial" ACLs that just mirror the file mode. */ - acl_is_trivial_np(acl, &r); - if (r) { - acl_free(acl); - acl = NULL; - } + if (acl != NULL) { +#if HAVE_SUN_ACL + if (sun_acl_is_trivial(acl, archive_entry_mode(entry), + &r) == 0 && r == 1) +#elif HAVE_ACL_IS_TRIVIAL_NP + if (acl_is_trivial_np(acl, &r) == 0 && r == 1) #endif + { + acl_free(acl); + acl = NULL; + /* + * Simultaneous NFSv4 and POSIX.1e ACLs for the same + * entry are not allowed, so we should return here + */ + return (ARCHIVE_OK); + } + } +#endif /* HAVE_ACL_IS_TRIVIAL_NP || HAVE_SUN_ACL */ if (acl != NULL) { - translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4); + r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4); acl_free(acl); - return (ARCHIVE_OK); - } + if (r != ARCHIVE_OK) { + archive_set_error(&a->archive, errno, + "Couldn't translate " +#if !HAVE_SUN_ACL + "NFSv4 " +#endif + "ACLs"); + } +#if HAVE_DARWIN_ACL + /* + * Because Mac OS doesn't support owner@, group@ and everyone@ + * ACLs we need to add NFSv4 ACLs mirroring the file mode to + * the archive entry. Otherwise extraction on non-Mac platforms + * would lead to an invalid file mode. + */ + if ((archive_entry_acl_types(entry) & + ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) + add_trivial_nfs4_acl(entry); #endif + return (r); + } +#endif /* HAVE_NFS4_ACL */ + +#if HAVE_POSIX_ACL + /* This code path is skipped on MacOS and Solaris */ /* Retrieve access ACL from file. */ if (*fd >= 0) @@ -467,88 +577,609 @@ setup_acls(struct archive_read_disk *a, #endif else acl = acl_get_file(accpath, ACL_TYPE_ACCESS); + +#if HAVE_ACL_IS_TRIVIAL_NP + /* Ignore "trivial" ACLs that just mirror the file mode. */ + if (acl != NULL && acl_is_trivial_np(acl, &r) == 0) { + if (r) { + acl_free(acl); + acl = NULL; + } + } +#endif + if (acl != NULL) { - translate_acl(a, entry, acl, - ARCHIVE_ENTRY_ACL_TYPE_ACCESS); + r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_ACCESS); acl_free(acl); + acl = NULL; + if (r != ARCHIVE_OK) { + archive_set_error(&a->archive, errno, + "Couldn't translate access ACLs"); + return (r); + } } /* Only directories can have default ACLs. */ if (S_ISDIR(archive_entry_mode(entry))) { +#if HAVE_ACL_GET_FD_NP + if (*fd >= 0) + acl = acl_get_fd_np(*fd, ACL_TYPE_DEFAULT); + else +#endif acl = acl_get_file(accpath, ACL_TYPE_DEFAULT); if (acl != NULL) { - translate_acl(a, entry, acl, + r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT); acl_free(acl); + if (r != ARCHIVE_OK) { + archive_set_error(&a->archive, errno, + "Couldn't translate default ACLs"); + return (r); + } } } +#endif /* HAVE_POSIX_ACL */ return (ARCHIVE_OK); } /* - * Translate system ACL into libarchive internal structure. + * Translate system ACL permissions into libarchive internal structure */ - -static struct { - int archive_perm; - int platform_perm; +static const struct { + const int archive_perm; + const int platform_perm; } acl_perm_map[] = { - {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE}, - {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE}, - {ARCHIVE_ENTRY_ACL_READ, ACL_READ}, -#ifdef ACL_TYPE_NFS4 - {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA}, - {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY}, - {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA}, - {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE}, - {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA}, - {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY}, - {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS}, - {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS}, - {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD}, - {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES}, - {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES}, - {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE}, - {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL}, - {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL}, - {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER}, - {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE} +#if HAVE_SUN_ACL /* Solaris NFSv4 ACL permissions */ + {ARCHIVE_ENTRY_ACL_EXECUTE, ACE_EXECUTE}, + {ARCHIVE_ENTRY_ACL_READ_DATA, ACE_READ_DATA}, + {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACE_LIST_DIRECTORY}, + {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACE_WRITE_DATA}, + {ARCHIVE_ENTRY_ACL_ADD_FILE, ACE_ADD_FILE}, + {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACE_APPEND_DATA}, + {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACE_ADD_SUBDIRECTORY}, + {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACE_READ_NAMED_ATTRS}, + {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACE_WRITE_NAMED_ATTRS}, + {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACE_DELETE_CHILD}, + {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACE_READ_ATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACE_WRITE_ATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_DELETE, ACE_DELETE}, + {ARCHIVE_ENTRY_ACL_READ_ACL, ACE_READ_ACL}, + {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACE_WRITE_ACL}, + {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACE_WRITE_OWNER}, + {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACE_SYNCHRONIZE} +#elif HAVE_DARWIN_ACL /* MacOS ACL permissions */ + {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA}, + {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY}, + {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA}, + {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE}, + {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE}, + {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE}, + {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA}, + {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY}, + {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD}, + {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_EXTATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_EXTATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_SECURITY}, + {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_SECURITY}, + {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_CHANGE_OWNER}, + {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE} +#else /* POSIX.1e ACL permissions */ + {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE}, + {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE}, + {ARCHIVE_ENTRY_ACL_READ, ACL_READ}, +#if HAVE_ACL_TYPE_NFS4 /* FreeBSD NFSv4 ACL permissions */ + {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA}, + {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY}, + {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA}, + {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE}, + {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA}, + {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY}, + {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS}, + {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS}, + {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD}, + {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE}, + {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL}, + {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL}, + {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER}, + {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE} #endif +#endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */ }; -#ifdef ACL_TYPE_NFS4 -static struct { - int archive_inherit; - int platform_inherit; +#if HAVE_NFS4_ACL +/* + * Translate system NFSv4 inheritance flags into libarchive internal structure + */ +static const struct { + const int archive_inherit; + const int platform_inherit; } acl_inherit_map[] = { - {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT}, +#if HAVE_SUN_ACL /* Solaris ACL inheritance flags */ + {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACE_FILE_INHERIT_ACE}, + {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACE_DIRECTORY_INHERIT_ACE}, + {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACE_NO_PROPAGATE_INHERIT_ACE}, + {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACE_INHERIT_ONLY_ACE}, + {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACE_SUCCESSFUL_ACCESS_ACE_FLAG}, + {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACE_FAILED_ACCESS_ACE_FLAG}, + {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACE_INHERITED_ACE} +#elif HAVE_DARWIN_ACL /* MacOS NFSv4 inheritance flags */ + {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED}, + {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT}, + {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT}, + {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_LIMIT_INHERIT}, + {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_ONLY_INHERIT} +#else /* FreeBSD NFSv4 ACL inheritance flags */ + {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT}, {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT}, {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT}, - {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY} + {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY}, + {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACL_ENTRY_SUCCESSFUL_ACCESS}, + {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACL_ENTRY_FAILED_ACCESS}, + {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED} +#endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */ }; -#endif +#endif /* HAVE_NFS4_ACL */ + +#if HAVE_DARWIN_ACL +static int translate_guid(struct archive *a, acl_entry_t acl_entry, + int *ae_id, int *ae_tag, const char **ae_name) +{ + void *q; + uid_t ugid; + int r, idtype; + struct passwd *pwd; + struct group *grp; + + q = acl_get_qualifier(acl_entry); + if (q == NULL) + return (1); + r = mbr_uuid_to_id((const unsigned char *)q, &ugid, &idtype); + if (r != 0) { + acl_free(q); + return (1); + } + if (idtype == ID_TYPE_UID) { + *ae_tag = ARCHIVE_ENTRY_ACL_USER; + pwd = getpwuuid(q); + if (pwd == NULL) { + *ae_id = ugid; + *ae_name = NULL; + } else { + *ae_id = pwd->pw_uid; + *ae_name = archive_read_disk_uname(a, *ae_id); + } + } else if (idtype == ID_TYPE_GID) { + *ae_tag = ARCHIVE_ENTRY_ACL_GROUP; + grp = getgruuid(q); + if (grp == NULL) { + *ae_id = ugid; + *ae_name = NULL; + } else { + *ae_id = grp->gr_gid; + *ae_name = archive_read_disk_gname(a, *ae_id); + } + } else + r = 1; + + acl_free(q); + return (r); +} + +/* + * Add trivial NFSv4 ACL entries from mode + */ +static void +add_trivial_nfs4_acl(struct archive_entry *entry) +{ + mode_t mode; + int i; + const int rperm = ARCHIVE_ENTRY_ACL_READ_DATA; + const int wperm = ARCHIVE_ENTRY_ACL_WRITE_DATA | + ARCHIVE_ENTRY_ACL_APPEND_DATA; + const int eperm = ARCHIVE_ENTRY_ACL_EXECUTE; + const int pubset = ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE; + const int ownset = pubset | ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_WRITE_ACL | + ARCHIVE_ENTRY_ACL_WRITE_OWNER; + + struct { + const int type; + const int tag; + int permset; + } tacl_entry[] = { + {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_USER_OBJ, 0}, + {ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_USER_OBJ, 0}, + {ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_GROUP_OBJ, 0}, + {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_USER_OBJ, ownset}, + {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_GROUP_OBJ, pubset}, + {ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EVERYONE, pubset} + }; + + mode = archive_entry_mode(entry); + + /* Permissions for everyone@ */ + if (mode & 0004) + tacl_entry[5].permset |= rperm; + if (mode & 0002) + tacl_entry[5].permset |= wperm; + if (mode & 0001) + tacl_entry[5].permset |= eperm; + + /* Permissions for group@ */ + if (mode & 0040) + tacl_entry[4].permset |= rperm; + else if (mode & 0004) + tacl_entry[2].permset |= rperm; + if (mode & 0020) + tacl_entry[4].permset |= wperm; + else if (mode & 0002) + tacl_entry[2].permset |= wperm; + if (mode & 0010) + tacl_entry[4].permset |= eperm; + else if (mode & 0001) + tacl_entry[2].permset |= eperm; + + /* Permissions for owner@ */ + if (mode & 0400) { + tacl_entry[3].permset |= rperm; + if (!(mode & 0040) && (mode & 0004)) + tacl_entry[0].permset |= rperm; + } else if ((mode & 0040) || (mode & 0004)) + tacl_entry[1].permset |= rperm; + if (mode & 0200) { + tacl_entry[3].permset |= wperm; + if (!(mode & 0020) && (mode & 0002)) + tacl_entry[0].permset |= wperm; + } else if ((mode & 0020) || (mode & 0002)) + tacl_entry[1].permset |= wperm; + if (mode & 0100) { + tacl_entry[3].permset |= eperm; + if (!(mode & 0010) && (mode & 0001)) + tacl_entry[0].permset |= eperm; + } else if ((mode & 0010) || (mode & 0001)) + tacl_entry[1].permset |= eperm; + + for (i = 0; i < 6; i++) { + if (tacl_entry[i].permset != 0) { + archive_entry_acl_add_entry(entry, + tacl_entry[i].type, tacl_entry[i].permset, + tacl_entry[i].tag, -1, NULL); + } + } + + return; +} +#elif HAVE_SUN_ACL +/* + * Check if acl is trivial + * This is a FreeBSD acl_is_trivial_np() implementation for Solaris + */ +static int +sun_acl_is_trivial(acl_t *acl, mode_t mode, int *trivialp) +{ + int i, p; + const uint32_t rperm = ACE_READ_DATA; + const uint32_t wperm = ACE_WRITE_DATA | ACE_APPEND_DATA; + const uint32_t eperm = ACE_EXECUTE; + const uint32_t pubset = ACE_READ_ATTRIBUTES | ACE_READ_NAMED_ATTRS | + ACE_READ_ACL | ACE_SYNCHRONIZE; + const uint32_t ownset = pubset | ACE_WRITE_ATTRIBUTES | + ACE_WRITE_NAMED_ATTRS | ACE_WRITE_ACL | ACE_WRITE_OWNER; + + ace_t *ace; + ace_t tace[6]; + + if (acl == NULL || trivialp == NULL) + return (-1); + + *trivialp = 0; + + /* ACL_IS_TRIVIAL flag must be set for both POSIX.1e and NFSv4 ACLs */ + if ((acl->acl_flags & ACL_IS_TRIVIAL) == 0) + return (0); + + /* + * POSIX.1e ACLs marked with ACL_IS_TRIVIAL are compatible with + * FreeBSD acl_is_trivial_np(). On Solaris they have 4 entries, + * including mask. + */ + if (acl->acl_type == ACLENT_T) { + if (acl->acl_cnt == 4) + *trivialp = 1; + return (0); + } + + if (acl->acl_type != ACE_T || acl->acl_entry_size != sizeof(ace_t)) + return (-1); + + /* + * Continue with checking NFSv4 ACLs + * + * Create list of trivial ace's to be compared + */ + + /* owner@ allow pre */ + tace[0].a_flags = ACE_OWNER; + tace[0].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; + tace[0].a_access_mask = 0; + + /* owner@ deny */ + tace[1].a_flags = ACE_OWNER; + tace[1].a_type = ACE_ACCESS_DENIED_ACE_TYPE; + tace[1].a_access_mask = 0; + + /* group@ deny */ + tace[2].a_flags = ACE_GROUP | ACE_IDENTIFIER_GROUP; + tace[2].a_type = ACE_ACCESS_DENIED_ACE_TYPE; + tace[2].a_access_mask = 0; + + /* owner@ allow */ + tace[3].a_flags = ACE_OWNER; + tace[3].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; + tace[3].a_access_mask = ownset; + + /* group@ allow */ + tace[4].a_flags = ACE_GROUP | ACE_IDENTIFIER_GROUP; + tace[4].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; + tace[4].a_access_mask = pubset; + + /* everyone@ allow */ + tace[5].a_flags = ACE_EVERYONE; + tace[5].a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; + tace[5].a_access_mask = pubset; + + /* Permissions for everyone@ */ + if (mode & 0004) + tace[5].a_access_mask |= rperm; + if (mode & 0002) + tace[5].a_access_mask |= wperm; + if (mode & 0001) + tace[5].a_access_mask |= eperm; + + /* Permissions for group@ */ + if (mode & 0040) + tace[4].a_access_mask |= rperm; + else if (mode & 0004) + tace[2].a_access_mask |= rperm; + if (mode & 0020) + tace[4].a_access_mask |= wperm; + else if (mode & 0002) + tace[2].a_access_mask |= wperm; + if (mode & 0010) + tace[4].a_access_mask |= eperm; + else if (mode & 0001) + tace[2].a_access_mask |= eperm; + + /* Permissions for owner@ */ + if (mode & 0400) { + tace[3].a_access_mask |= rperm; + if (!(mode & 0040) && (mode & 0004)) + tace[0].a_access_mask |= rperm; + } else if ((mode & 0040) || (mode & 0004)) + tace[1].a_access_mask |= rperm; + if (mode & 0200) { + tace[3].a_access_mask |= wperm; + if (!(mode & 0020) && (mode & 0002)) + tace[0].a_access_mask |= wperm; + } else if ((mode & 0020) || (mode & 0002)) + tace[1].a_access_mask |= wperm; + if (mode & 0100) { + tace[3].a_access_mask |= eperm; + if (!(mode & 0010) && (mode & 0001)) + tace[0].a_access_mask |= eperm; + } else if ((mode & 0010) || (mode & 0001)) + tace[1].a_access_mask |= eperm; + + /* Check if the acl count matches */ + p = 3; + for (i = 0; i < 3; i++) { + if (tace[i].a_access_mask != 0) + p++; + } + if (acl->acl_cnt != p) + return (0); + + p = 0; + for (i = 0; i < 6; i++) { + if (tace[i].a_access_mask != 0) { + ace = &((ace_t *)acl->acl_aclp)[p]; + /* + * Illumos added ACE_DELETE_CHILD to write perms for + * directories. We have to check against that, too. + */ + if (ace->a_flags != tace[i].a_flags || + ace->a_type != tace[i].a_type || + (ace->a_access_mask != tace[i].a_access_mask && + ((acl->acl_flags & ACL_IS_DIR) == 0 || + (tace[i].a_access_mask & wperm) == 0 || + ace->a_access_mask != + (tace[i].a_access_mask | ACE_DELETE_CHILD)))) + return (0); + p++; + } + } + + *trivialp = 1; + return (0); +} +#endif /* HAVE_SUN_ACL */ + +#if HAVE_SUN_ACL +/* + * Translate Solaris POSIX.1e and NFSv4 ACLs into libarchive internal ACL + */ +static int +translate_acl(struct archive_read_disk *a, + struct archive_entry *entry, acl_t *acl, int default_entry_acl_type) +{ + int e, i; + int ae_id, ae_tag, ae_perm; + int entry_acl_type; + const char *ae_name; + aclent_t *aclent; + ace_t *ace; + + (void)default_entry_acl_type; + + if (acl->acl_cnt <= 0) + return (ARCHIVE_OK); + + for (e = 0; e < acl->acl_cnt; e++) { + ae_name = NULL; + ae_tag = 0; + ae_perm = 0; + + if (acl->acl_type == ACE_T) { + ace = &((ace_t *)acl->acl_aclp)[e]; + ae_id = ace->a_who; + + switch(ace->a_type) { + case ACE_ACCESS_ALLOWED_ACE_TYPE: + entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW; + break; + case ACE_ACCESS_DENIED_ACE_TYPE: + entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY; + break; + case ACE_SYSTEM_AUDIT_ACE_TYPE: + entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; + break; + case ACE_SYSTEM_ALARM_ACE_TYPE: + entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM; + break; + default: + /* Unknown entry type, skip */ + continue; + } + + if ((ace->a_flags & ACE_OWNER) != 0) + ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ; + else if ((ace->a_flags & ACE_GROUP) != 0) + ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; + else if ((ace->a_flags & ACE_EVERYONE) != 0) + ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE; + else if ((ace->a_flags & ACE_IDENTIFIER_GROUP) != 0) { + ae_tag = ARCHIVE_ENTRY_ACL_GROUP; + ae_name = archive_read_disk_gname(&a->archive, + ae_id); + } else { + ae_tag = ARCHIVE_ENTRY_ACL_USER; + ae_name = archive_read_disk_uname(&a->archive, + ae_id); + } + + for (i = 0; i < (int)(sizeof(acl_inherit_map) / + sizeof(acl_inherit_map[0])); ++i) { + if ((ace->a_flags & + acl_inherit_map[i].platform_inherit) != 0) + ae_perm |= + acl_inherit_map[i].archive_inherit; + } + + for (i = 0; i < (int)(sizeof(acl_perm_map) / + sizeof(acl_perm_map[0])); ++i) { + if ((ace->a_access_mask & + acl_perm_map[i].platform_perm) != 0) + ae_perm |= + acl_perm_map[i].archive_perm; + } + } else { + aclent = &((aclent_t *)acl->acl_aclp)[e]; + if ((aclent->a_type & ACL_DEFAULT) != 0) + entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; + else + entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; + ae_id = aclent->a_id; + + switch(aclent->a_type) { + case DEF_USER: + case USER: + ae_name = archive_read_disk_uname(&a->archive, + ae_id); + ae_tag = ARCHIVE_ENTRY_ACL_USER; + break; + case DEF_GROUP: + case GROUP: + ae_name = archive_read_disk_gname(&a->archive, + ae_id); + ae_tag = ARCHIVE_ENTRY_ACL_GROUP; + break; + case DEF_CLASS_OBJ: + case CLASS_OBJ: + ae_tag = ARCHIVE_ENTRY_ACL_MASK; + break; + case DEF_USER_OBJ: + case USER_OBJ: + ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ; + break; + case DEF_GROUP_OBJ: + case GROUP_OBJ: + ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ; + break; + case DEF_OTHER_OBJ: + case OTHER_OBJ: + ae_tag = ARCHIVE_ENTRY_ACL_OTHER; + break; + default: + /* Unknown tag type, skip */ + continue; + } + + if ((aclent->a_perm & 1) != 0) + ae_perm |= ARCHIVE_ENTRY_ACL_EXECUTE; + if ((aclent->a_perm & 2) != 0) + ae_perm |= ARCHIVE_ENTRY_ACL_WRITE; + if ((aclent->a_perm & 4) != 0) + ae_perm |= ARCHIVE_ENTRY_ACL_READ; + } /* default_entry_acl_type != ARCHIVE_ENTRY_ACL_TYPE_NFS4 */ + + archive_entry_acl_add_entry(entry, entry_acl_type, + ae_perm, ae_tag, ae_id, ae_name); + } + return (ARCHIVE_OK); +} +#else /* !HAVE_SUN_ACL */ +/* + * Translate POSIX.1e (Linux), FreeBSD (both POSIX.1e and NFSv4) and + * MacOS (NFSv4 only) ACLs into libarchive internal structure + */ static int translate_acl(struct archive_read_disk *a, struct archive_entry *entry, acl_t acl, int default_entry_acl_type) { acl_tag_t acl_tag; -#ifdef ACL_TYPE_NFS4 +#if HAVE_ACL_TYPE_NFS4 acl_entry_type_t acl_type; + int brand; +#endif +#if HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL acl_flagset_t acl_flagset; - int brand, r; #endif acl_entry_t acl_entry; acl_permset_t acl_permset; int i, entry_acl_type; - int s, ae_id, ae_tag, ae_perm; + int r, s, ae_id, ae_tag, ae_perm; +#if !HAVE_DARWIN_ACL + void *q; +#endif const char *ae_name; - -#ifdef ACL_TYPE_NFS4 +#if HAVE_ACL_TYPE_NFS4 // FreeBSD "brands" ACLs as POSIX.1e or NFSv4 // Make sure the "brand" on this ACL is consistent // with the default_entry_acl_type bits provided. - acl_get_brand_np(acl, &brand); + if (acl_get_brand_np(acl, &brand) != 0) { + archive_set_error(&a->archive, errno, + "Failed to read ACL brand"); + return (ARCHIVE_WARN); + } switch (brand) { case ACL_BRAND_POSIX: switch (default_entry_acl_type) { @@ -556,40 +1187,67 @@ translate_acl(struct archive_read_disk *a, case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: break; default: - // XXX set warning message? - return ARCHIVE_FAILED; + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Invalid ACL entry type for POSIX.1e ACL"); + return (ARCHIVE_WARN); } break; case ACL_BRAND_NFS4: if (default_entry_acl_type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) { - // XXX set warning message? - return ARCHIVE_FAILED; + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Invalid ACL entry type for NFSv4 ACL"); + return (ARCHIVE_WARN); } break; default: - // XXX set warning message? - return ARCHIVE_FAILED; - break; + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Unknown ACL brand"); + return (ARCHIVE_WARN); } #endif - s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry); - while (s == 1) { + if (s == -1) { + archive_set_error(&a->archive, errno, + "Failed to get first ACL entry"); + return (ARCHIVE_WARN); + } + +#if HAVE_DARWIN_ACL + while (s == 0) +#else /* FreeBSD, Linux */ + while (s == 1) +#endif + { ae_id = -1; ae_name = NULL; ae_perm = 0; - acl_get_tag_type(acl_entry, &acl_tag); + if (acl_get_tag_type(acl_entry, &acl_tag) != 0) { + archive_set_error(&a->archive, errno, + "Failed to get ACL tag type"); + return (ARCHIVE_WARN); + } switch (acl_tag) { +#if !HAVE_DARWIN_ACL /* FreeBSD, Linux */ case ACL_USER: - ae_id = (int)*(uid_t *)acl_get_qualifier(acl_entry); - ae_name = archive_read_disk_uname(&a->archive, ae_id); + q = acl_get_qualifier(acl_entry); + if (q != NULL) { + ae_id = (int)*(uid_t *)q; + acl_free(q); + ae_name = archive_read_disk_uname(&a->archive, + ae_id); + } ae_tag = ARCHIVE_ENTRY_ACL_USER; break; case ACL_GROUP: - ae_id = (int)*(gid_t *)acl_get_qualifier(acl_entry); - ae_name = archive_read_disk_gname(&a->archive, ae_id); + q = acl_get_qualifier(acl_entry); + if (q != NULL) { + ae_id = (int)*(gid_t *)q; + acl_free(q); + ae_name = archive_read_disk_gname(&a->archive, + ae_id); + } ae_tag = ARCHIVE_ENTRY_ACL_GROUP; break; case ACL_MASK: @@ -604,24 +1262,52 @@ translate_acl(struct archive_read_disk *a, case ACL_OTHER: ae_tag = ARCHIVE_ENTRY_ACL_OTHER; break; -#ifdef ACL_TYPE_NFS4 +#if HAVE_ACL_TYPE_NFS4 case ACL_EVERYONE: ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE; break; #endif +#else /* HAVE_DARWIN_ACL */ + case ACL_EXTENDED_ALLOW: + entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW; + r = translate_guid(&a->archive, acl_entry, &ae_id, + &ae_tag, &ae_name); + break; + case ACL_EXTENDED_DENY: + entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY; + r = translate_guid(&a->archive, acl_entry, &ae_id, + &ae_tag, &ae_name); + break; +#endif /* HAVE_DARWIN_ACL */ default: /* Skip types that libarchive can't support. */ s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry); continue; } - // XXX acl type maps to allow/deny/audit/YYYY bits - // XXX acl_get_entry_type_np on FreeBSD returns EINVAL for - // non-NFSv4 ACLs +#if HAVE_DARWIN_ACL + /* Skip if translate_guid() above failed */ + if (r != 0) { + s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry); + continue; + } +#endif + +#if !HAVE_DARWIN_ACL + // XXX acl_type maps to allow/deny/audit/YYYY bits entry_acl_type = default_entry_acl_type; -#ifdef ACL_TYPE_NFS4 - r = acl_get_entry_type_np(acl_entry, &acl_type); - if (r == 0) { +#endif +#if HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL + if (default_entry_acl_type & ARCHIVE_ENTRY_ACL_TYPE_NFS4) { +#if HAVE_ACL_TYPE_NFS4 + /* + * acl_get_entry_type_np() fails with non-NFSv4 ACLs + */ + if (acl_get_entry_type_np(acl_entry, &acl_type) != 0) { + archive_set_error(&a->archive, errno, "Failed " + "to get ACL type from a NFSv4 ACL entry"); + return (ARCHIVE_WARN); + } switch (acl_type) { case ACL_ENTRY_TYPE_ALLOW: entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW; @@ -635,29 +1321,54 @@ translate_acl(struct archive_read_disk *a, case ACL_ENTRY_TYPE_ALARM: entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM; break; + default: + archive_set_error(&a->archive, errno, + "Invalid NFSv4 ACL entry type"); + return (ARCHIVE_WARN); } - } - - /* - * Libarchive stores "flag" (NFSv4 inheritance bits) - * in the ae_perm bitmap. - */ - acl_get_flagset_np(acl_entry, &acl_flagset); - for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) { - if (acl_get_flag_np(acl_flagset, - acl_inherit_map[i].platform_inherit)) - ae_perm |= acl_inherit_map[i].archive_inherit; +#endif /* HAVE_ACL_TYPE_NFS4 */ - } -#endif + /* + * Libarchive stores "flag" (NFSv4 inheritance bits) + * in the ae_perm bitmap. + * + * acl_get_flagset_np() fails with non-NFSv4 ACLs + */ + if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) { + archive_set_error(&a->archive, errno, + "Failed to get flagset from a NFSv4 ACL entry"); + return (ARCHIVE_WARN); + } + for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) { + r = acl_get_flag_np(acl_flagset, + acl_inherit_map[i].platform_inherit); + if (r == -1) { + archive_set_error(&a->archive, errno, + "Failed to check flag in a NFSv4 " + "ACL flagset"); + return (ARCHIVE_WARN); + } else if (r) + ae_perm |= acl_inherit_map[i].archive_inherit; + } + } +#endif /* HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL */ - acl_get_permset(acl_entry, &acl_permset); + if (acl_get_permset(acl_entry, &acl_permset) != 0) { + archive_set_error(&a->archive, errno, + "Failed to get ACL permission set"); + return (ARCHIVE_WARN); + } for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) { /* * acl_get_perm() is spelled differently on different * platforms; see above. */ - if (ACL_GET_PERM(acl_permset, acl_perm_map[i].platform_perm)) + r = ACL_GET_PERM(acl_permset, acl_perm_map[i].platform_perm); + if (r == -1) { + archive_set_error(&a->archive, errno, + "Failed to check permission in an ACL permission set"); + return (ARCHIVE_WARN); + } else if (r) ae_perm |= acl_perm_map[i].archive_perm; } @@ -666,10 +1377,18 @@ translate_acl(struct archive_read_disk *a, ae_id, ae_name); s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry); +#if !HAVE_DARWIN_ACL + if (s == -1) { + archive_set_error(&a->archive, errno, + "Failed to get next ACL entry"); + return (ARCHIVE_WARN); + } +#endif } return (ARCHIVE_OK); } -#else +#endif /* !HAVE_SUN_ACL */ +#else /* !HAVE_POSIX_ACL && !HAVE_NFS4_ACL */ static int setup_acls(struct archive_read_disk *a, struct archive_entry *entry, int *fd) @@ -679,7 +1398,7 @@ setup_acls(struct archive_read_disk *a, (void)fd; /* UNUSED */ return (ARCHIVE_OK); } -#endif +#endif /* !HAVE_POSIX_ACL && !HAVE_NFS4_ACL */ #if (HAVE_FGETXATTR && HAVE_FLISTXATTR && HAVE_LISTXATTR && \ HAVE_LLISTXATTR && HAVE_GETXATTR && HAVE_LGETXATTR) || \ @@ -699,15 +1418,10 @@ setup_acls(struct archive_read_disk *a, static int setup_xattr(struct archive_read_disk *a, - struct archive_entry *entry, const char *name, int fd) + struct archive_entry *entry, const char *name, int fd, const char *accpath) { ssize_t size; void *value = NULL; - const char *accpath; - - accpath = archive_entry_sourcepath(entry); - if (accpath == NULL) - accpath = archive_entry_pathname(entry); #if HAVE_FGETXATTR if (fd >= 0) @@ -772,21 +1486,23 @@ setup_xattrs(struct archive_read_disk *a, const char *path; ssize_t list_size; - path = archive_entry_sourcepath(entry); - if (path == NULL) - path = archive_entry_pathname(entry); + path = NULL; - if (*fd < 0 && a->tree != NULL) { - if (a->follow_symlinks || - archive_entry_filetype(entry) != AE_IFLNK) - *fd = a->open_on_current_dir(a->tree, path, - O_RDONLY | O_NONBLOCK); - if (*fd < 0) { - if (a->tree_enter_working_dir(a->tree) != 0) { - archive_set_error(&a->archive, errno, - "Couldn't access %s", path); - return (ARCHIVE_FAILED); - } + if (*fd < 0) { + path = archive_entry_sourcepath(entry); + if (path == NULL || (a->tree != NULL && + a->tree_enter_working_dir(a->tree) != 0)) + path = archive_entry_pathname(entry); + if (path == NULL) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Couldn't determine file path to read " + "extended attributes"); + return (ARCHIVE_WARN); + } + if (a->tree != NULL && (a->follow_symlinks || + archive_entry_filetype(entry) != AE_IFLNK)) { + *fd = a->open_on_current_dir(a->tree, + path, O_RDONLY | O_NONBLOCK); } } @@ -849,7 +1565,7 @@ setup_xattrs(struct archive_read_disk *a, if (strncmp(p, "system.", 7) == 0 || strncmp(p, "xfsroot.", 8) == 0) continue; - setup_xattr(a, entry, p, *fd); + setup_xattr(a, entry, p, *fd, path); } free(list); @@ -870,19 +1586,16 @@ setup_xattrs(struct archive_read_disk *a, */ static int setup_xattr(struct archive_read_disk *a, struct archive_entry *entry, - int namespace, const char *name, const char *fullname, int fd); + int namespace, const char *name, const char *fullname, int fd, + const char *path); static int setup_xattr(struct archive_read_disk *a, struct archive_entry *entry, - int namespace, const char *name, const char *fullname, int fd) + int namespace, const char *name, const char *fullname, int fd, + const char *accpath) { ssize_t size; void *value = NULL; - const char *accpath; - - accpath = archive_entry_sourcepath(entry); - if (accpath == NULL) - accpath = archive_entry_pathname(entry); if (fd >= 0) size = extattr_get_fd(fd, namespace, name, NULL, 0); @@ -932,21 +1645,23 @@ setup_xattrs(struct archive_read_disk *a, const char *path; int namespace = EXTATTR_NAMESPACE_USER; - path = archive_entry_sourcepath(entry); - if (path == NULL) - path = archive_entry_pathname(entry); + path = NULL; - if (*fd < 0 && a->tree != NULL) { - if (a->follow_symlinks || - archive_entry_filetype(entry) != AE_IFLNK) - *fd = a->open_on_current_dir(a->tree, path, - O_RDONLY | O_NONBLOCK); - if (*fd < 0) { - if (a->tree_enter_working_dir(a->tree) != 0) { - archive_set_error(&a->archive, errno, - "Couldn't access %s", path); - return (ARCHIVE_FAILED); - } + if (*fd < 0) { + path = archive_entry_sourcepath(entry); + if (path == NULL || (a->tree != NULL && + a->tree_enter_working_dir(a->tree) != 0)) + path = archive_entry_pathname(entry); + if (path == NULL) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Couldn't determine file path to read " + "extended attributes"); + return (ARCHIVE_WARN); + } + if (a->tree != NULL && (a->follow_symlinks || + archive_entry_filetype(entry) != AE_IFLNK)) { + *fd = a->open_on_current_dir(a->tree, + path, O_RDONLY | O_NONBLOCK); } } @@ -996,7 +1711,7 @@ setup_xattrs(struct archive_read_disk *a, name = buff + strlen(buff); memcpy(name, p + 1, len); name[len] = '\0'; - setup_xattr(a, entry, namespace, name, buff, *fd); + setup_xattr(a, entry, namespace, name, buff, *fd, path); p += 1 + len; } @@ -1024,7 +1739,7 @@ setup_xattrs(struct archive_read_disk *a, #if defined(HAVE_LINUX_FIEMAP_H) /* - * Linux sparse interface. + * Linux FIEMAP sparse interface. * * The FIEMAP ioctl returns an "extent" for each physical allocation * on disk. We need to process those to generate a more compact list @@ -1039,7 +1754,7 @@ setup_xattrs(struct archive_read_disk *a, */ static int -setup_sparse(struct archive_read_disk *a, +setup_sparse_fiemap(struct archive_read_disk *a, struct archive_entry *entry, int *fd) { char buff[4096]; @@ -1090,8 +1805,8 @@ setup_sparse(struct archive_read_disk *a, if (r < 0) { /* When something error happens, it is better we * should return ARCHIVE_OK because an earlier - * version(<2.6.28) cannot perfom FS_IOC_FIEMAP. */ - goto exit_setup_sparse; + * version(<2.6.28) cannot perform FS_IOC_FIEMAP. */ + goto exit_setup_sparse_fiemap; } if (fm->fm_mapped_extents == 0) { if (iters == 0) { @@ -1126,14 +1841,24 @@ setup_sparse(struct archive_read_disk *a, } else break; } -exit_setup_sparse: +exit_setup_sparse_fiemap: return (exit_sts); } -#elif defined(SEEK_HOLE) && defined(SEEK_DATA) && defined(_PC_MIN_HOLE_SIZE) +#if !defined(SEEK_HOLE) || !defined(SEEK_DATA) +static int +setup_sparse(struct archive_read_disk *a, + struct archive_entry *entry, int *fd) +{ + return setup_sparse_fiemap(a, entry, fd); +} +#endif +#endif /* defined(HAVE_LINUX_FIEMAP_H) */ + +#if defined(SEEK_HOLE) && defined(SEEK_DATA) /* - * FreeBSD and Solaris sparse interface. + * SEEK_HOLE sparse interface (FreeBSD, Linux, Solaris) */ static int @@ -1141,8 +1866,8 @@ setup_sparse(struct archive_read_disk *a, struct archive_entry *entry, int *fd) { int64_t size; - off_t initial_off; /* FreeBSD/Solaris only, so off_t okay here */ - off_t off_s, off_e; /* FreeBSD/Solaris only, so off_t okay here */ + off_t initial_off; + off_t off_s, off_e; int exit_sts = ARCHIVE_OK; int check_fully_sparse = 0; @@ -1168,8 +1893,10 @@ setup_sparse(struct archive_read_disk *a, } if (*fd >= 0) { +#ifdef _PC_MIN_HOLE_SIZE if (fpathconf(*fd, _PC_MIN_HOLE_SIZE) <= 0) return (ARCHIVE_OK); +#endif initial_off = lseek(*fd, 0, SEEK_CUR); if (initial_off != 0) lseek(*fd, 0, SEEK_SET); @@ -1180,8 +1907,10 @@ setup_sparse(struct archive_read_disk *a, if (path == NULL) path = archive_entry_pathname(entry); +#ifdef _PC_MIN_HOLE_SIZE if (pathconf(path, _PC_MIN_HOLE_SIZE) <= 0) return (ARCHIVE_OK); +#endif *fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC); if (*fd < 0) { archive_set_error(&a->archive, errno, @@ -1192,6 +1921,19 @@ setup_sparse(struct archive_read_disk *a, initial_off = 0; } +#ifndef _PC_MIN_HOLE_SIZE + /* Check if the underlying filesystem supports seek hole */ + off_s = lseek(*fd, 0, SEEK_HOLE); + if (off_s < 0) +#if defined(HAVE_LINUX_FIEMAP_H) + return setup_sparse_fiemap(a, entry, fd); +#else + goto exit_setup_sparse; +#endif + else if (off_s > 0) + lseek(*fd, 0, SEEK_SET); +#endif + off_s = 0; size = archive_entry_size(entry); while (off_s < size) { @@ -1223,7 +1965,7 @@ setup_sparse(struct archive_read_disk *a, goto exit_setup_sparse; } if (off_s == 0 && off_e == size) - break;/* This is not spase. */ + break;/* This is not sparse. */ archive_entry_sparse_add_entry(entry, off_s, off_e - off_s); off_s = off_e; @@ -1241,7 +1983,7 @@ exit_setup_sparse: return (exit_sts); } -#else +#elif !defined(HAVE_LINUX_FIEMAP_H) /* * Generic (stub) sparse support. diff --git a/Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c b/Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c index 22a1f14..b893704 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_disk_posix.c @@ -165,7 +165,7 @@ struct filesystem { int synthetic; int remote; int noatime; -#if defined(HAVE_READDIR_R) +#if defined(USE_READDIR_R) size_t name_max; #endif long incr_xfer_size; @@ -200,7 +200,7 @@ struct tree { DIR *d; #define INVALID_DIR_HANDLE NULL struct dirent *de; -#if defined(HAVE_READDIR_R) +#if defined(USE_READDIR_R) struct dirent *dirent; size_t dirent_allocated; #endif @@ -244,7 +244,7 @@ struct tree { int initial_filesystem_id; int current_filesystem_id; int max_filesystem_id; - int allocated_filesytem; + int allocated_filesystem; int entry_fd; int entry_eof; @@ -675,7 +675,7 @@ setup_suitable_read_buffer(struct archive_read_disk *a) asize = cf->min_xfer_size; /* Increase a buffer size up to 64K bytes in - * a proper incremant size. */ + * a proper increment size. */ while (asize < 1024*64) asize += incr; /* Take a margin to adjust to the filesystem @@ -938,7 +938,7 @@ next_entry(struct archive_read_disk *a, struct tree *t, r = archive_match_path_excluded(a->matching, entry); if (r < 0) { archive_set_error(&(a->archive), errno, - "Faild : %s", archive_error_string(a->matching)); + "Failed : %s", archive_error_string(a->matching)); return (r); } if (r) { @@ -1026,7 +1026,7 @@ next_entry(struct archive_read_disk *a, struct tree *t, /* Save the times to be restored. This must be in before * calling archive_read_disk_descend() or any chance of it, - * especially, invokng a callback. */ + * especially, invoking a callback. */ t->restore_time.mtime = archive_entry_mtime(entry); t->restore_time.mtime_nsec = archive_entry_mtime_nsec(entry); t->restore_time.atime = archive_entry_atime(entry); @@ -1041,7 +1041,7 @@ next_entry(struct archive_read_disk *a, struct tree *t, r = archive_match_time_excluded(a->matching, entry); if (r < 0) { archive_set_error(&(a->archive), errno, - "Faild : %s", archive_error_string(a->matching)); + "Failed : %s", archive_error_string(a->matching)); return (r); } if (r) { @@ -1067,7 +1067,7 @@ next_entry(struct archive_read_disk *a, struct tree *t, r = archive_match_owner_excluded(a->matching, entry); if (r < 0) { archive_set_error(&(a->archive), errno, - "Faild : %s", archive_error_string(a->matching)); + "Failed : %s", archive_error_string(a->matching)); return (r); } if (r) { @@ -1382,7 +1382,7 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev) for (i = 0; i < t->max_filesystem_id; i++) { if (t->filesystem_table[i].dev == dev) { - /* There is the filesytem ID we've already generated. */ + /* There is the filesystem ID we've already generated. */ t->current_filesystem_id = i; t->current_filesystem = &(t->filesystem_table[i]); return (ARCHIVE_OK); @@ -1390,10 +1390,10 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev) } /* - * This is the new filesytem which we have to generate a new ID for. + * This is the new filesystem which we have to generate a new ID for. */ fid = t->max_filesystem_id++; - if (t->max_filesystem_id > t->allocated_filesytem) { + if (t->max_filesystem_id > t->allocated_filesystem) { size_t s; void *p; @@ -1406,7 +1406,7 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev) return (ARCHIVE_FATAL); } t->filesystem_table = (struct filesystem *)p; - t->allocated_filesytem = s; + t->allocated_filesystem = s; } t->current_filesystem_id = fid; t->current_filesystem = &(t->filesystem_table[fid]); @@ -1504,7 +1504,20 @@ setup_current_filesystem(struct archive_read_disk *a) struct tree *t = a->tree; struct statfs sfs; #if defined(HAVE_GETVFSBYNAME) && defined(VFCF_SYNTHETIC) +/* TODO: configure should set GETVFSBYNAME_ARG_TYPE to make + * this accurate; some platforms have both and we need the one that's + * used by getvfsbyname() + * + * Then the following would become: + * #if defined(GETVFSBYNAME_ARG_TYPE) + * GETVFSBYNAME_ARG_TYPE vfc; + * #endif + */ +# if defined(HAVE_STRUCT_XVFSCONF) struct xvfsconf vfc; +# else + struct vfsconf vfc; +# endif #endif int r, xr = 0; #if !defined(HAVE_STRUCT_STATFS_F_NAMEMAX) @@ -1579,7 +1592,7 @@ setup_current_filesystem(struct archive_read_disk *a) #endif t->current_filesystem->noatime = 0; -#if defined(HAVE_READDIR_R) +#if defined(USE_READDIR_R) /* Set maximum filename length. */ #if defined(HAVE_STRUCT_STATFS_F_NAMEMAX) t->current_filesystem->name_max = sfs.f_namemax; @@ -1602,7 +1615,7 @@ setup_current_filesystem(struct archive_read_disk *a) else t->current_filesystem->name_max = nm; #endif -#endif /* HAVE_READDIR_R */ +#endif /* USE_READDIR_R */ return (ARCHIVE_OK); } @@ -1643,7 +1656,7 @@ setup_current_filesystem(struct archive_read_disk *a) archive_set_error(&a->archive, errno, "statvfs failed"); return (ARCHIVE_FAILED); } else if (xr == 1) { - /* Usuall come here unless NetBSD supports _PC_REC_XFER_ALIGN + /* Usually come here unless NetBSD supports _PC_REC_XFER_ALIGN * for pathconf() function. */ t->current_filesystem->xfer_align = sfs.f_frsize; t->current_filesystem->max_xfer_size = -1; @@ -1804,7 +1817,7 @@ setup_current_filesystem(struct archive_read_disk *a) #endif t->current_filesystem->noatime = 0; -#if defined(HAVE_READDIR_R) +#if defined(USE_READDIR_R) /* Set maximum filename length. */ t->current_filesystem->name_max = sfs.f_namelen; #endif @@ -1888,7 +1901,7 @@ setup_current_filesystem(struct archive_read_disk *a) #endif t->current_filesystem->noatime = 0; -#if defined(HAVE_READDIR_R) +#if defined(USE_READDIR_R) /* Set maximum filename length. */ t->current_filesystem->name_max = sfs.f_namemax; #endif @@ -1905,7 +1918,7 @@ static int setup_current_filesystem(struct archive_read_disk *a) { struct tree *t = a->tree; -#if defined(_PC_NAME_MAX) && defined(HAVE_READDIR_R) +#if defined(_PC_NAME_MAX) && defined(USE_READDIR_R) long nm; #endif t->current_filesystem->synthetic = -1;/* Not supported */ @@ -1917,7 +1930,7 @@ setup_current_filesystem(struct archive_read_disk *a) t->current_filesystem->min_xfer_size = -1; t->current_filesystem->incr_xfer_size = -1; -#if defined(HAVE_READDIR_R) +#if defined(USE_READDIR_R) /* Set maximum filename length. */ # if defined(_PC_NAME_MAX) if (tree_current_is_symblic_link_target(t)) { @@ -1931,7 +1944,7 @@ setup_current_filesystem(struct archive_read_disk *a) if (nm == -1) # endif /* _PC_NAME_MAX */ /* - * Some sysmtes (HP-UX or others?) incorrectly defined + * Some systems (HP-UX or others?) incorrectly defined * NAME_MAX macro to be a smaller value. */ # if defined(NAME_MAX) && NAME_MAX >= 255 @@ -1945,7 +1958,7 @@ setup_current_filesystem(struct archive_read_disk *a) else t->current_filesystem->name_max = nm; # endif /* _PC_NAME_MAX */ -#endif /* HAVE_READDIR_R */ +#endif /* USE_READDIR_R */ return (ARCHIVE_OK); } @@ -2050,8 +2063,7 @@ tree_push(struct tree *t, const char *path, int filesystem_id, { struct tree_entry *te; - te = malloc(sizeof(*te)); - memset(te, 0, sizeof(*te)); + te = calloc(1, sizeof(*te)); te->next = t->stack; te->parent = t->current; if (te->parent) @@ -2109,9 +2121,8 @@ tree_open(const char *path, int symlink_mode, int restore_time) { struct tree *t; - if ((t = malloc(sizeof(*t))) == NULL) + if ((t = calloc(1, sizeof(*t))) == NULL) return (NULL); - memset(t, 0, sizeof(*t)); archive_string_init(&t->path); archive_string_ensure(&t->path, 31); t->initial_symlink_mode = symlink_mode; @@ -2353,7 +2364,7 @@ tree_dir_next_posix(struct tree *t) size_t namelen; if (t->d == NULL) { -#if defined(HAVE_READDIR_R) +#if defined(USE_READDIR_R) size_t dirent_size; #endif @@ -2374,7 +2385,7 @@ tree_dir_next_posix(struct tree *t) t->visit_type = r != 0 ? r : TREE_ERROR_DIR; return (t->visit_type); } -#if defined(HAVE_READDIR_R) +#if defined(USE_READDIR_R) dirent_size = offsetof(struct dirent, d_name) + t->filesystem_table[t->current->filesystem_id].name_max + 1; if (t->dirent == NULL || t->dirent_allocated < dirent_size) { @@ -2391,11 +2402,11 @@ tree_dir_next_posix(struct tree *t) } t->dirent_allocated = dirent_size; } -#endif /* HAVE_READDIR_R */ +#endif /* USE_READDIR_R */ } for (;;) { errno = 0; -#if defined(HAVE_READDIR_R) +#if defined(USE_READDIR_R) r = readdir_r(t->d, t->dirent, &t->de); #ifdef _AIX /* Note: According to the man page, return value 9 indicates @@ -2647,7 +2658,7 @@ tree_free(struct tree *t) if (t == NULL) return; archive_string_free(&t->path); -#if defined(HAVE_READDIR_R) +#if defined(USE_READDIR_R) free(t->dirent); #endif free(t->sparse_list); diff --git a/Utilities/cmlibarchive/libarchive/archive_read_disk_set_standard_lookup.c b/Utilities/cmlibarchive/libarchive/archive_read_disk_set_standard_lookup.c index d6b2d55..c7fd247 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_disk_set_standard_lookup.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_disk_set_standard_lookup.c @@ -232,6 +232,7 @@ static const char * lookup_uname_helper(struct name_cache *cache, id_t id) { struct passwd *result; + (void)cache; /* UNUSED */ result = getpwuid((uid_t)id); @@ -298,6 +299,7 @@ static const char * lookup_gname_helper(struct name_cache *cache, id_t id) { struct group *result; + (void)cache; /* UNUSED */ result = getgrgid((gid_t)id); diff --git a/Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c b/Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c index 566d264..27b75e3 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_disk_windows.c @@ -168,7 +168,7 @@ struct tree { int initial_filesystem_id; int current_filesystem_id; int max_filesystem_id; - int allocated_filesytem; + int allocated_filesystem; HANDLE entry_fh; int entry_eof; @@ -389,10 +389,9 @@ archive_read_disk_new(void) { struct archive_read_disk *a; - a = (struct archive_read_disk *)malloc(sizeof(*a)); + a = (struct archive_read_disk *)calloc(1, sizeof(*a)); if (a == NULL) return (NULL); - memset(a, 0, sizeof(*a)); a->archive.magic = ARCHIVE_READ_DISK_MAGIC; a->archive.state = ARCHIVE_STATE_NEW; a->archive.vtable = archive_read_disk_vtable(); @@ -803,7 +802,7 @@ next_entry(struct archive_read_disk *a, struct tree *t, r = archive_match_path_excluded(a->matching, entry); if (r < 0) { archive_set_error(&(a->archive), errno, - "Faild : %s", archive_error_string(a->matching)); + "Failed : %s", archive_error_string(a->matching)); return (r); } if (r) { @@ -863,7 +862,7 @@ next_entry(struct archive_read_disk *a, struct tree *t, /* Save the times to be restored. This must be in before * calling archive_read_disk_descend() or any chance of it, - * especially, invokng a callback. */ + * especially, invoking a callback. */ t->restore_time.lastWriteTime = st->ftLastWriteTime; t->restore_time.lastAccessTime = st->ftLastAccessTime; t->restore_time.filetype = archive_entry_filetype(entry); @@ -875,7 +874,7 @@ next_entry(struct archive_read_disk *a, struct tree *t, r = archive_match_time_excluded(a->matching, entry); if (r < 0) { archive_set_error(&(a->archive), errno, - "Faild : %s", archive_error_string(a->matching)); + "Failed : %s", archive_error_string(a->matching)); return (r); } if (r) { @@ -901,7 +900,7 @@ next_entry(struct archive_read_disk *a, struct tree *t, r = archive_match_owner_excluded(a->matching, entry); if (r < 0) { archive_set_error(&(a->archive), errno, - "Faild : %s", archive_error_string(a->matching)); + "Failed : %s", archive_error_string(a->matching)); return (r); } if (r) { @@ -1261,7 +1260,7 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev) for (i = 0; i < t->max_filesystem_id; i++) { if (t->filesystem_table[i].dev == dev) { - /* There is the filesytem ID we've already generated. */ + /* There is the filesystem ID we've already generated. */ t->current_filesystem_id = i; t->current_filesystem = &(t->filesystem_table[i]); return (ARCHIVE_OK); @@ -1269,10 +1268,10 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev) } /* - * There is a new filesytem, we generate a new ID for. + * There is a new filesystem, we generate a new ID for. */ fid = t->max_filesystem_id++; - if (t->max_filesystem_id > t->allocated_filesytem) { + if (t->max_filesystem_id > t->allocated_filesystem) { size_t s; void *p; @@ -1285,7 +1284,7 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev) return (ARCHIVE_FATAL); } t->filesystem_table = (struct filesystem *)p; - t->allocated_filesytem = (int)s; + t->allocated_filesystem = (int)s; } t->current_filesystem_id = fid; t->current_filesystem = &(t->filesystem_table[fid]); @@ -1402,7 +1401,7 @@ close_and_restore_time(HANDLE h, struct tree *t, struct restore_time *rt) if (h == INVALID_HANDLE_VALUE && AE_IFLNK == rt->filetype) return (0); - /* Close a file descritor. + /* Close a file descriptor. * It will not be used for SetFileTime() because it has been opened * by a read only mode. */ @@ -1437,8 +1436,7 @@ tree_push(struct tree *t, const wchar_t *path, const wchar_t *full_path, { struct tree_entry *te; - te = malloc(sizeof(*te)); - memset(te, 0, sizeof(*te)); + te = calloc(1, sizeof(*te)); te->next = t->stack; te->parent = t->current; if (te->parent) @@ -1507,8 +1505,7 @@ tree_open(const wchar_t *path, int symlink_mode, int restore_time) { struct tree *t; - t = malloc(sizeof(*t)); - memset(t, 0, sizeof(*t)); + t = calloc(1, sizeof(*t)); archive_string_init(&(t->full_path)); archive_string_init(&t->path); archive_wstring_ensure(&t->path, 15); diff --git a/Utilities/cmlibarchive/libarchive/archive_read_extract2.c b/Utilities/cmlibarchive/libarchive/archive_read_extract2.c index 7b2c126..4febd8c 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_extract2.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_extract2.c @@ -52,12 +52,11 @@ struct archive_read_extract * __archive_read_get_extract(struct archive_read *a) { if (a->extract == NULL) { - a->extract = (struct archive_read_extract *)malloc(sizeof(*a->extract)); + a->extract = (struct archive_read_extract *)calloc(1, sizeof(*a->extract)); if (a->extract == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't extract"); return (NULL); } - memset(a->extract, 0, sizeof(*a->extract)); a->cleanup_archive_extract = archive_read_extract_cleanup; } return (a->extract); diff --git a/Utilities/cmlibarchive/libarchive/archive_read_open_filename.c b/Utilities/cmlibarchive/libarchive/archive_read_open_filename.c index 5611aa8..86635e2 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_open_filename.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_open_filename.c @@ -222,7 +222,7 @@ file_open(struct archive *a, void *client_data) void *buffer; const char *filename = NULL; const wchar_t *wfilename = NULL; - int fd; + int fd = -1; int is_disk_like = 0; #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) off_t mediasize = 0; /* FreeBSD-specific, so off_t okay here. */ @@ -277,7 +277,7 @@ file_open(struct archive *a, void *client_data) #else archive_set_error(a, ARCHIVE_ERRNO_MISC, "Unexpedted operation in archive_read_open_filename"); - return (ARCHIVE_FATAL); + goto fail; #endif } if (fstat(fd, &st) != 0) { @@ -287,7 +287,7 @@ file_open(struct archive *a, void *client_data) else archive_set_error(a, errno, "Can't stat '%s'", filename); - return (ARCHIVE_FATAL); + goto fail; } /* @@ -356,11 +356,9 @@ file_open(struct archive *a, void *client_data) mine->block_size = new_block_size; } buffer = malloc(mine->block_size); - if (mine == NULL || buffer == NULL) { + if (buffer == NULL) { archive_set_error(a, ENOMEM, "No memory"); - free(mine); - free(buffer); - return (ARCHIVE_FATAL); + goto fail; } mine->buffer = buffer; mine->fd = fd; @@ -372,6 +370,14 @@ file_open(struct archive *a, void *client_data) mine->use_lseek = 1; return (ARCHIVE_OK); +fail: + /* + * Don't close file descriptors not opened or ones pointing referring + * to `FNT_STDIN`. + */ + if (fd != -1 && fd != 0) + close(fd); + return (ARCHIVE_FATAL); } static ssize_t diff --git a/Utilities/cmlibarchive/libarchive/archive_read_open_memory.c b/Utilities/cmlibarchive/libarchive/archive_read_open_memory.c index ff935a7..311be47 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_open_memory.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_open_memory.c @@ -70,12 +70,11 @@ archive_read_open_memory2(struct archive *a, const void *buff, { struct read_memory_data *mine; - mine = (struct read_memory_data *)malloc(sizeof(*mine)); + mine = (struct read_memory_data *)calloc(1, sizeof(*mine)); if (mine == NULL) { archive_set_error(a, ENOMEM, "No memory"); return (ARCHIVE_FATAL); } - memset(mine, 0, sizeof(*mine)); mine->start = mine->p = (const unsigned char *)buff; mine->end = mine->start + size; mine->read_size = read_size; diff --git a/Utilities/cmlibarchive/libarchive/archive_read_private.h b/Utilities/cmlibarchive/libarchive/archive_read_private.h index 9b61a53..78546dc 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_private.h +++ b/Utilities/cmlibarchive/libarchive/archive_read_private.h @@ -221,7 +221,7 @@ struct archive_read { struct { struct archive_read_passphrase *first; struct archive_read_passphrase **last; - int candiate; + int candidate; archive_passphrase_callback *callback; void *client_data; } passphrases; @@ -252,7 +252,6 @@ int64_t __archive_read_consume(struct archive_read *, int64_t); int64_t __archive_read_filter_consume(struct archive_read_filter *, int64_t); int __archive_read_program(struct archive_read_filter *, const char *); void __archive_read_free_filters(struct archive_read *); -int __archive_read_close_filters(struct archive_read *); struct archive_read_extract *__archive_read_get_extract(struct archive_read *); diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lz4.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lz4.c index e877917..663e2d3 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lz4.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lz4.c @@ -180,7 +180,7 @@ lz4_reader_bid(struct archive_read_filter_bidder *self, return (0); bits_checked += 8; BD = buffer[5]; - /* A block maximum size shuld be more than 3. */ + /* A block maximum size should be more than 3. */ if (((BD & 0x70) >> 4) < 4) return (0); /* Reserved bits must be "0". */ @@ -417,7 +417,7 @@ lz4_filter_read_descriptor(struct archive_read_filter *self) /* Reserved bits must be zero. */ if (bd & 0x8f) goto malformed_error; - /* Get a maxinum block size. */ + /* Get a maximum block size. */ switch (read_buf[1] >> 4) { case 4: /* 64 KB */ state->flags.block_maximum_size = 64 * 1024; @@ -595,7 +595,7 @@ lz4_filter_read_data_block(struct archive_read_filter *self, const void **p) #endif } - /* Check if an error happend in decompression process. */ + /* Check if an error occurred in the decompression process. */ if (uncompressed_size < 0) { archive_set_error(&(self->archive->archive), ARCHIVE_ERRNO_MISC, "lz4 decompression failed"); @@ -627,7 +627,7 @@ lz4_filter_read_default_stream(struct archive_read_filter *self, const void **p) if (state->stage == SELECT_STREAM) { state->stage = READ_DEFAULT_STREAM; - /* First, read a desciprtor. */ + /* First, read a descriptor. */ if((ret = lz4_filter_read_descriptor(self)) != ARCHIVE_OK) return (ret); state->stage = READ_DEFAULT_BLOCK; @@ -706,6 +706,11 @@ lz4_filter_read_legacy_stream(struct archive_read_filter *self, const void **p) /* Make sure we have a whole block. */ read_buf = __archive_read_filter_ahead(self->upstream, 4 + compressed, NULL); + if (read_buf == NULL) { + archive_set_error(&(self->archive->archive), + ARCHIVE_ERRNO_MISC, "truncated lz4 input"); + return (ARCHIVE_FATAL); + } ret = LZ4_decompress_safe(read_buf + 4, state->out_block, compressed, (int)state->out_block_size); if (ret < 0) { diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c index 23c18c7..4356b82 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_lzop.c @@ -436,7 +436,7 @@ lzop_filter_read(struct archive_read_filter *self, const void **p) } /* - * Drive lzo uncompresison. + * Drive lzo uncompression. */ out_size = (lzo_uint)state->uncompressed_size; r = lzo1x_decompress_safe(b, (lzo_uint)state->compressed_size, diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_program.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_program.c index 66dc2f4..b8bf128 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_program.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_program.c @@ -430,6 +430,7 @@ __archive_read_program(struct archive_read_filter *self, const char *cmd) &state->child_stdout); if (child == -1) { free(state->out_buf); + archive_string_free(&state->description); free(state); archive_set_error(&self->archive->archive, EINVAL, "Can't initialize filter; unable to run program \"%s\"", @@ -441,6 +442,7 @@ __archive_read_program(struct archive_read_filter *self, const char *cmd) if (state->child == NULL) { child_stop(self, state); free(state->out_buf); + archive_string_free(&state->description); free(state); archive_set_error(&self->archive->archive, EINVAL, "Can't initialize filter; unable to run program \"%s\"", diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_uu.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_uu.c index 787a619..6412979 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_uu.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_uu.c @@ -312,6 +312,7 @@ uudecode_bidder_bid(struct archive_read_filter_bidder *self, avail -= len; if (l == 6) { + /* "begin " */ if (!uuchar[*b]) return (0); /* Get a length of decoded bytes. */ @@ -319,30 +320,14 @@ uudecode_bidder_bid(struct archive_read_filter_bidder *self, if (l > 45) /* Normally, maximum length is 45(character 'M'). */ return (0); - while (l && len-nl > 0) { - if (l > 0) { - if (!uuchar[*b++]) - return (0); - if (!uuchar[*b++]) - return (0); - len -= 2; - --l; - } - if (l > 0) { - if (!uuchar[*b++]) - return (0); - --len; - --l; - } - if (l > 0) { - if (!uuchar[*b++]) - return (0); - --len; - --l; - } + if (l > len - nl) + return (0); /* Line too short. */ + while (l) { + if (!uuchar[*b++]) + return (0); + --len; + --l; } - if (len-nl < 0) - return (0); if (len-nl == 1 && (uuchar[*b] || /* Check sum. */ (*b >= 'a' && *b <= 'z'))) {/* Padding data(MINIX). */ @@ -352,8 +337,8 @@ uudecode_bidder_bid(struct archive_read_filter_bidder *self, b += nl; if (avail && uuchar[*b]) return (firstline+30); - } - if (l == 13) { + } else if (l == 13) { + /* "begin-base64 " */ while (len-nl > 0) { if (!base64[*b++]) return (0); @@ -510,6 +495,13 @@ read_more: } llen = len; if ((nl == 0) && (uudecode->state != ST_UUEND)) { + if (total == 0 && ravail <= 0) { + /* There is nothing more to read, fail */ + archive_set_error(&self->archive->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Missing format data"); + return (ARCHIVE_FATAL); + } /* * Save remaining data which does not contain * NL('\n','\r'). @@ -566,7 +558,7 @@ read_more: "Insufficient compressed data"); return (ARCHIVE_FATAL); } - /* Get length of undecoded bytes of curent line. */ + /* Get length of undecoded bytes of current line. */ l = UUDECODE(*b++); body--; if (l > body) { diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_xz.c b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_xz.c index 8f48273..a188186 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_filter_xz.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_filter_xz.c @@ -43,8 +43,6 @@ __FBSDID("$FreeBSD$"); #endif #if HAVE_LZMA_H #include <cm_lzma.h> -#elif HAVE_LZMADEC_H -#include <lzmadec.h> #endif #include "archive.h" @@ -82,19 +80,6 @@ static ssize_t xz_filter_read(struct archive_read_filter *, const void **); static int xz_filter_close(struct archive_read_filter *); static int xz_lzma_bidder_init(struct archive_read_filter *); -#elif HAVE_LZMADEC_H && HAVE_LIBLZMADEC - -struct private_data { - lzmadec_stream stream; - unsigned char *out_block; - size_t out_block_size; - int64_t total_out; - char eof; /* True = found end of compressed data. */ -}; - -/* Lzma-only filter */ -static ssize_t lzma_filter_read(struct archive_read_filter *, const void **); -static int lzma_filter_close(struct archive_read_filter *); #endif /* @@ -178,8 +163,6 @@ archive_read_support_filter_lzma(struct archive *_a) bidder->free = NULL; #if HAVE_LZMA_H && HAVE_LIBLZMA return (ARCHIVE_OK); -#elif HAVE_LZMADEC_H && HAVE_LIBLZMADEC - return (ARCHIVE_OK); #else archive_set_error(_a, ARCHIVE_ERRNO_MISC, "Using external lzma program for lzma decompression"); @@ -310,7 +293,7 @@ lzma_bidder_bid(struct archive_read_filter_bidder *self, /* Second through fifth bytes are dictionary size, stored in * little-endian order. The minimum dictionary size is * 1 << 12(4KiB) which the lzma of LZMA SDK uses with option - * -d12 and the maxinam dictionary size is 1 << 27(128MiB) + * -d12 and the maximum dictionary size is 1 << 27(128MiB) * which the one uses with option -d27. * NOTE: A comment of LZMA SDK source code says this dictionary * range is from 1 << 12 to 1 << 30. */ @@ -601,9 +584,7 @@ lzip_init(struct archive_read_filter *self) return (ARCHIVE_FATAL); } ret = lzma_raw_decoder(&(state->stream), filters); -#if LZMA_VERSION < 50010000 free(filters[0].options); -#endif if (ret != LZMA_OK) { set_error(self, ret); return (ARCHIVE_FATAL); @@ -763,175 +744,6 @@ xz_filter_close(struct archive_read_filter *self) #else -#if HAVE_LZMADEC_H && HAVE_LIBLZMADEC - -/* - * If we have the older liblzmadec library, then we can handle - * LZMA streams but not XZ streams. - */ - -/* - * Setup the callbacks. - */ -static int -lzma_bidder_init(struct archive_read_filter *self) -{ - static const size_t out_block_size = 64 * 1024; - void *out_block; - struct private_data *state; - ssize_t ret, avail_in; - - self->code = ARCHIVE_FILTER_LZMA; - self->name = "lzma"; - - state = (struct private_data *)calloc(sizeof(*state), 1); - out_block = (unsigned char *)malloc(out_block_size); - if (state == NULL || out_block == NULL) { - archive_set_error(&self->archive->archive, ENOMEM, - "Can't allocate data for lzma decompression"); - free(out_block); - free(state); - return (ARCHIVE_FATAL); - } - - self->data = state; - state->out_block_size = out_block_size; - state->out_block = out_block; - self->read = lzma_filter_read; - self->skip = NULL; /* not supported */ - self->close = lzma_filter_close; - - /* Prime the lzma library with 18 bytes of input. */ - state->stream.next_in = (unsigned char *)(uintptr_t) - __archive_read_filter_ahead(self->upstream, 18, &avail_in); - if (state->stream.next_in == NULL) - return (ARCHIVE_FATAL); - state->stream.avail_in = avail_in; - state->stream.next_out = state->out_block; - state->stream.avail_out = state->out_block_size; - - /* Initialize compression library. */ - ret = lzmadec_init(&(state->stream)); - __archive_read_filter_consume(self->upstream, - avail_in - state->stream.avail_in); - if (ret == LZMADEC_OK) - return (ARCHIVE_OK); - - /* Library setup failed: Clean up. */ - archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC, - "Internal error initializing lzma library"); - - /* Override the error message if we know what really went wrong. */ - switch (ret) { - case LZMADEC_HEADER_ERROR: - archive_set_error(&self->archive->archive, - ARCHIVE_ERRNO_MISC, - "Internal error initializing compression library: " - "invalid header"); - break; - case LZMADEC_MEM_ERROR: - archive_set_error(&self->archive->archive, ENOMEM, - "Internal error initializing compression library: " - "out of memory"); - break; - } - - free(state->out_block); - free(state); - self->data = NULL; - return (ARCHIVE_FATAL); -} - -/* - * Return the next block of decompressed data. - */ -static ssize_t -lzma_filter_read(struct archive_read_filter *self, const void **p) -{ - struct private_data *state; - size_t decompressed; - ssize_t avail_in, ret; - - state = (struct private_data *)self->data; - - /* Empty our output buffer. */ - state->stream.next_out = state->out_block; - state->stream.avail_out = state->out_block_size; - - /* Try to fill the output buffer. */ - while (state->stream.avail_out > 0 && !state->eof) { - state->stream.next_in = (unsigned char *)(uintptr_t) - __archive_read_filter_ahead(self->upstream, 1, &avail_in); - if (state->stream.next_in == NULL && avail_in < 0) { - archive_set_error(&self->archive->archive, - ARCHIVE_ERRNO_MISC, - "truncated lzma input"); - return (ARCHIVE_FATAL); - } - state->stream.avail_in = avail_in; - - /* Decompress as much as we can in one pass. */ - ret = lzmadec_decode(&(state->stream), avail_in == 0); - switch (ret) { - case LZMADEC_STREAM_END: /* Found end of stream. */ - state->eof = 1; - /* FALL THROUGH */ - case LZMADEC_OK: /* Decompressor made some progress. */ - __archive_read_filter_consume(self->upstream, - avail_in - state->stream.avail_in); - break; - case LZMADEC_BUF_ERROR: /* Insufficient input data? */ - archive_set_error(&self->archive->archive, - ARCHIVE_ERRNO_MISC, - "Insufficient compressed data"); - return (ARCHIVE_FATAL); - default: - /* Return an error. */ - archive_set_error(&self->archive->archive, - ARCHIVE_ERRNO_MISC, - "Lzma decompression failed"); - return (ARCHIVE_FATAL); - } - } - - decompressed = state->stream.next_out - state->out_block; - state->total_out += decompressed; - if (decompressed == 0) - *p = NULL; - else - *p = state->out_block; - return (decompressed); -} - -/* - * Clean up the decompressor. - */ -static int -lzma_filter_close(struct archive_read_filter *self) -{ - struct private_data *state; - int ret; - - state = (struct private_data *)self->data; - ret = ARCHIVE_OK; - switch (lzmadec_end(&(state->stream))) { - case LZMADEC_OK: - break; - default: - archive_set_error(&(self->archive->archive), - ARCHIVE_ERRNO_MISC, - "Failed to clean up %s compressor", - self->archive->archive.compression_name); - ret = ARCHIVE_FATAL; - } - - free(state->out_block); - free(state); - return (ret); -} - -#else - /* * * If we have no suitable library on this system, we can't actually do @@ -953,9 +765,6 @@ lzma_bidder_init(struct archive_read_filter *self) return (r); } -#endif /* HAVE_LZMADEC_H */ - - static int xz_bidder_init(struct archive_read_filter *self) { @@ -984,5 +793,4 @@ lzip_bidder_init(struct archive_read_filter *self) return (r); } - #endif /* HAVE_LZMA_H */ diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c index a33ea4f..96774f4 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_7zip.c @@ -213,7 +213,7 @@ struct _7zip { int header_is_encoded; uint64_t header_bytes_remaining; unsigned long header_crc32; - /* Header offset to check that reading pointes of the file contens + /* Header offset to check that reading points of the file contents * will not exceed the header. */ uint64_t header_offset; /* Base offset of the archive file for a seek in case reading SFX. */ @@ -263,22 +263,22 @@ struct _7zip { /* * Decompressor controllers. */ - /* Decording LZMA1 and LZMA2 data. */ + /* Decoding LZMA1 and LZMA2 data. */ #ifdef HAVE_LZMA_H lzma_stream lzstream; int lzstream_valid; #endif - /* Decording bzip2 data. */ + /* Decoding bzip2 data. */ #if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR) bz_stream bzstream; int bzstream_valid; #endif - /* Decording deflate data. */ + /* Decoding deflate data. */ #ifdef HAVE_ZLIB_H z_stream stream; int stream_valid; #endif - /* Decording PPMd data. */ + /* Decoding PPMd data. */ int ppmd7_stat; CPpmd7 ppmd7_context; CPpmd7z_RangeDec range_dec; @@ -552,7 +552,7 @@ skip_sfx(struct archive_read *a, ssize_t bytes_avail) /* * If bytes_avail > SFX_MIN_ADDR we do not have to call * __archive_read_seek() at this time since we have - * alredy had enough data. + * already had enough data. */ if (bytes_avail > SFX_MIN_ADDR) __archive_read_consume(a, SFX_MIN_ADDR); @@ -760,7 +760,7 @@ archive_read_format_7zip_read_header(struct archive_read *a, symsize += size; } if (symsize == 0) { - /* If there is no synname, handle it as a regular + /* If there is no symname, handle it as a regular * file. */ zip_entry->mode &= ~AE_IFMT; zip_entry->mode |= AE_IFREG; @@ -1056,10 +1056,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip, #endif { lzma_options_delta delta_opt; - lzma_filter filters[LZMA_FILTERS_MAX]; -#if LZMA_VERSION < 50010000 - lzma_filter *ff; -#endif + lzma_filter filters[LZMA_FILTERS_MAX], *ff; int fi = 0; if (zip->lzstream_valid) { @@ -1144,9 +1141,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip, else filters[fi].id = LZMA_FILTER_LZMA1; filters[fi].options = NULL; -#if LZMA_VERSION < 50010000 ff = &filters[fi]; -#endif r = lzma_properties_decode(&filters[fi], NULL, coder1->properties, (size_t)coder1->propertiesSize); if (r != LZMA_OK) { @@ -1158,9 +1153,7 @@ init_decompression(struct archive_read *a, struct _7zip *zip, filters[fi].id = LZMA_VLI_UNKNOWN; filters[fi].options = NULL; r = lzma_raw_decoder(&(zip->lzstream), filters); -#if LZMA_VERSION < 50010000 free(ff->options); -#endif if (r != LZMA_OK) { set_error(a, r); return (ARCHIVE_FAILED); @@ -2431,6 +2424,8 @@ read_Header(struct archive_read *a, struct _7z_header_info *h, switch (type) { case kEmptyStream: + if (h->emptyStreamBools != NULL) + return (-1); h->emptyStreamBools = calloc((size_t)zip->numFiles, sizeof(*h->emptyStreamBools)); if (h->emptyStreamBools == NULL) @@ -2451,6 +2446,8 @@ read_Header(struct archive_read *a, struct _7z_header_info *h, return (-1); break; } + if (h->emptyFileBools != NULL) + return (-1); h->emptyFileBools = calloc(empty_streams, sizeof(*h->emptyFileBools)); if (h->emptyFileBools == NULL) @@ -2465,6 +2462,8 @@ read_Header(struct archive_read *a, struct _7z_header_info *h, return (-1); break; } + if (h->antiBools != NULL) + return (-1); h->antiBools = calloc(empty_streams, sizeof(*h->antiBools)); if (h->antiBools == NULL) @@ -2491,6 +2490,8 @@ read_Header(struct archive_read *a, struct _7z_header_info *h, if ((ll & 1) || ll < zip->numFiles * 4) return (-1); + if (zip->entry_names != NULL) + return (-1); zip->entry_names = malloc(ll); if (zip->entry_names == NULL) return (-1); @@ -2543,6 +2544,8 @@ read_Header(struct archive_read *a, struct _7z_header_info *h, if ((p = header_bytes(a, 2)) == NULL) return (-1); allAreDefined = *p; + if (h->attrBools != NULL) + return (-1); h->attrBools = calloc((size_t)zip->numFiles, sizeof(*h->attrBools)); if (h->attrBools == NULL) @@ -3285,7 +3288,7 @@ read_stream(struct archive_read *a, const void **buff, size_t size, return (r); /* - * Skip the bytes we alrady has skipped in skip_stream(). + * Skip the bytes we already has skipped in skip_stream(). */ while (skip_bytes) { ssize_t skipped; @@ -3503,7 +3506,7 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder, return (ARCHIVE_FATAL); } - /* Allocate memory for the decorded data of a sub + /* Allocate memory for the decoded data of a sub * stream. */ b[i] = malloc((size_t)zip->folder_outbytes_remaining); if (b[i] == NULL) { @@ -3588,7 +3591,7 @@ skip_stream(struct archive_read *a, size_t skip_bytes) if (zip->folder_index == 0) { /* * Optimization for a list mode. - * Avoid unncecessary decoding operations. + * Avoid unnecessary decoding operations. */ zip->si.ci.folders[zip->entry->folderIndex].skipped_bytes += skip_bytes; diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_ar.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_ar.c index 4b5b66b..b6b9fc3 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_ar.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_ar.c @@ -104,13 +104,12 @@ archive_read_support_format_ar(struct archive *_a) archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_support_format_ar"); - ar = (struct ar *)malloc(sizeof(*ar)); + ar = (struct ar *)calloc(1, sizeof(*ar)); if (ar == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate ar data"); return (ARCHIVE_FATAL); } - memset(ar, 0, sizeof(*ar)); ar->strtab = NULL; r = __archive_read_register_format(a, @@ -260,7 +259,7 @@ _ar_read_header(struct archive_read *a, struct archive_entry *entry, archive_entry_set_filetype(entry, AE_IFREG); /* Get the size of the filename table. */ number = ar_atol10(h + AR_size_offset, AR_size_size); - if (number > SIZE_MAX) { + if (number > SIZE_MAX || number > 1024 * 1024 * 1024) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Filename table too large"); return (ARCHIVE_FATAL); @@ -316,7 +315,7 @@ _ar_read_header(struct archive_read *a, struct archive_entry *entry, * If we can't look up the real name, warn and return * the entry with the wrong name. */ - if (ar->strtab == NULL || number > ar->strtab_size) { + if (ar->strtab == NULL || number >= ar->strtab_size) { archive_set_error(&a->archive, EINVAL, "Can't find long filename for GNU/SVR4 archive entry"); archive_entry_copy_pathname(entry, filename); @@ -342,16 +341,19 @@ _ar_read_header(struct archive_read *a, struct archive_entry *entry, /* Parse the size of the name, adjust the file size. */ number = ar_atol10(h + AR_name_offset + 3, AR_name_size - 3); - bsd_name_length = (size_t)number; - /* Guard against the filename + trailing NUL - * overflowing a size_t and against the filename size - * being larger than the entire entry. */ - if (number > (uint64_t)(bsd_name_length + 1) - || (int64_t)bsd_name_length > ar->entry_bytes_remaining) { + /* Sanity check the filename length: + * = Must be <= SIZE_MAX - 1 + * = Must be <= 1MB + * = Cannot be bigger than the entire entry + */ + if (number > SIZE_MAX - 1 + || number > 1024 * 1024 + || (int64_t)number > ar->entry_bytes_remaining) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Bad input file size"); return (ARCHIVE_FATAL); } + bsd_name_length = (size_t)number; ar->entry_bytes_remaining -= bsd_name_length; /* Adjust file size reported to client. */ archive_entry_set_size(entry, ar->entry_bytes_remaining); diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_cab.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_cab.c index 6356963..20eb157 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_cab.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_cab.c @@ -67,7 +67,7 @@ struct lzx_dec { /* The length how many bytes we can copy decoded code from * the window. */ int copy_len; - /* Translation reversal for x86 proccessor CALL byte sequence(E8). + /* Translation reversal for x86 processor CALL byte sequence(E8). * This is used for LZX only. */ uint32_t translation_size; char translation; @@ -645,12 +645,13 @@ cab_read_header(struct archive_read *a) cab = (struct cab *)(a->format->data); if (cab->found_header == 0 && p[0] == 'M' && p[1] == 'Z') { - /* This is an executable? Must be self-extracting... */ + /* This is an executable? Must be self-extracting... */ err = cab_skip_sfx(a); if (err < ARCHIVE_WARN) return (err); - if ((p = __archive_read_ahead(a, sizeof(*p), NULL)) == NULL) + /* Re-read header after processing the SFX. */ + if ((p = __archive_read_ahead(a, 42, NULL)) == NULL) return (truncated_error(a)); } @@ -1494,6 +1495,8 @@ cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail) /* Cut out a tow-byte MSZIP signature(0x43, 0x4b). */ if (mszip > 0) { + if (bytes_avail <= 0) + goto nomszip; if (bytes_avail <= mszip) { if (mszip == 2) { if (cab->stream.next_in[0] != 0x43) @@ -1554,7 +1557,7 @@ cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail) /* * Note: I suspect there is a bug in makecab.exe because, in rare * case, compressed bytes are still remaining regardless we have - * gotten all uncompressed bytes, which size is recoded in CFDATA, + * gotten all uncompressed bytes, which size is recorded in CFDATA, * as much as we need, and we have to use the garbage so as to * correctly compute the sum of CFDATA accordingly. */ @@ -1741,7 +1744,7 @@ cab_read_ahead_cfdata_lzx(struct archive_read *a, ssize_t *avail) } /* - * Translation reversal of x86 proccessor CALL byte sequence(E8). + * Translation reversal of x86 processor CALL byte sequence(E8). */ lzx_translation(&cab->xstrm, cab->uncompressed_buffer, cfdata->uncompressed_size, @@ -2270,7 +2273,7 @@ static int lzx_br_fillup(struct lzx_stream *strm, struct lzx_br *br) { /* - * x86 proccessor family can read misaligned data without an access error. + * x86 processor family can read misaligned data without an access error. */ int n = CACHE_BITS - br->cache_avail; diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_cpio.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_cpio.c index b09db0e..ffd4a85 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_cpio.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_cpio.c @@ -326,7 +326,7 @@ archive_read_format_cpio_options(struct archive_read *a, cpio = (struct cpio *)(a->format->data); if (strcmp(key, "compat-2x") == 0) { - /* Handle filnames as libarchive 2.x */ + /* Handle filenames as libarchive 2.x */ cpio->init_default_conversion = (val != NULL)?1:0; return (ARCHIVE_OK); } else if (strcmp(key, "hdrcharset") == 0) { @@ -356,7 +356,7 @@ archive_read_format_cpio_read_header(struct archive_read *a, struct archive_entry *entry) { struct cpio *cpio; - const void *h; + const void *h, *hl; struct archive_string_conv *sconv; size_t namelength; size_t name_pad; @@ -406,11 +406,11 @@ archive_read_format_cpio_read_header(struct archive_read *a, "Rejecting malformed cpio archive: symlink contents exceed 1 megabyte"); return (ARCHIVE_FATAL); } - h = __archive_read_ahead(a, + hl = __archive_read_ahead(a, (size_t)cpio->entry_bytes_remaining, NULL); - if (h == NULL) + if (hl == NULL) return (ARCHIVE_FATAL); - if (archive_entry_copy_symlink_l(entry, (const char *)h, + if (archive_entry_copy_symlink_l(entry, (const char *)hl, (size_t)cpio->entry_bytes_remaining, sconv) != 0) { if (errno == ENOMEM) { archive_set_error(&a->archive, ENOMEM, @@ -434,7 +434,8 @@ archive_read_format_cpio_read_header(struct archive_read *a, * header. XXX */ /* Compare name to "TRAILER!!!" to test for end-of-archive. */ - if (namelength == 11 && strcmp((const char *)h, "TRAILER!!!") == 0) { + if (namelength == 11 && strncmp((const char *)h, "TRAILER!!!", + 11) == 0) { /* TODO: Store file location of start of block. */ archive_clear_error(&a->archive); return (ARCHIVE_EOF); @@ -814,8 +815,8 @@ header_odc(struct archive_read *a, struct cpio *cpio, * NOTE: if a filename suffix is ".z", it is the file gziped by afio. * it would be nice that we can show uncompressed file size and we can * uncompressed file contents automatically, unfortunately we have nothing - * to get a uncompressed file size while reading each header. it means - * we also cannot uncompressed file contens under the our framework. + * to get a uncompressed file size while reading each header. It means + * we also cannot uncompress file contents under our framework. */ static int header_afiol(struct archive_read *a, struct cpio *cpio, diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c index c19614a..3541330 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_iso9660.c @@ -322,7 +322,7 @@ struct iso9660 { struct archive_string pathname; char seenRockridge; /* Set true if RR extensions are used. */ - char seenSUSP; /* Set true if SUSP is beging used. */ + char seenSUSP; /* Set true if SUSP is being used. */ char seenJoliet; unsigned char suspOffset; @@ -374,7 +374,7 @@ struct iso9660 { size_t utf16be_path_len; unsigned char *utf16be_previous_path; size_t utf16be_previous_path_len; - /* Null buufer used in bidder to improve its performance. */ + /* Null buffer used in bidder to improve its performance. */ unsigned char null[2048]; }; @@ -1199,7 +1199,7 @@ archive_read_format_iso9660_read_header(struct archive_read *a, archive_string_conversion_from_charset( &(a->archive), "UTF-16BE", 1); if (iso9660->sconv_utf16be == NULL) - /* Coundn't allocate memory */ + /* Couldn't allocate memory */ return (ARCHIVE_FATAL); } if (iso9660->utf16be_path == NULL) { @@ -1864,7 +1864,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent, if ((file->utf16be_name = malloc(name_len)) == NULL) { archive_set_error(&a->archive, ENOMEM, "No memory for file name"); - return (NULL); + goto fail; } memcpy(file->utf16be_name, p, name_len); file->utf16be_bytes = name_len; @@ -1943,10 +1943,8 @@ parse_file_info(struct archive_read *a, struct file_info *parent, file->symlink_continues = 0; rr_start += iso9660->suspOffset; r = parse_rockridge(a, file, rr_start, rr_end); - if (r != ARCHIVE_OK) { - free(file); - return (NULL); - } + if (r != ARCHIVE_OK) + goto fail; /* * A file size of symbolic link files in ISO images * made by makefs is not zero and its location is @@ -1990,7 +1988,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent, archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Invalid Rockridge RE"); - return (NULL); + goto fail; } /* * Sanity check: file does not have "CL" extension. @@ -1999,7 +1997,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent, archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Invalid Rockridge RE and CL"); - return (NULL); + goto fail; } /* * Sanity check: The file type must be a directory. @@ -2008,7 +2006,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent, archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Invalid Rockridge RE"); - return (NULL); + goto fail; } } else if (parent != NULL && parent->rr_moved) file->rr_moved_has_re_only = 0; @@ -2022,7 +2020,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent, archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Invalid Rockridge CL"); - return (NULL); + goto fail; } /* * Sanity check: The file type must be a regular file. @@ -2031,7 +2029,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent, archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Invalid Rockridge CL"); - return (NULL); + goto fail; } parent->subdirs++; /* Overwrite an offset and a number of this "CL" entry @@ -2049,7 +2047,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent, archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Invalid Rockridge CL"); - return (NULL); + goto fail; } } if (file->cl_offset == file->offset || @@ -2057,7 +2055,7 @@ parse_file_info(struct archive_read *a, struct file_info *parent, archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Invalid Rockridge CL"); - return (NULL); + goto fail; } } } @@ -2088,6 +2086,10 @@ parse_file_info(struct archive_read *a, struct file_info *parent, #endif register_file(iso9660, file); return (file); +fail: + archive_string_free(&file->name); + free(file); + return (NULL); } static int @@ -2407,7 +2409,7 @@ read_CE(struct archive_read *a, struct iso9660 *iso9660) return (ARCHIVE_FATAL); } while (heap->cnt && heap->reqs[0].offset == iso9660->current_position); - /* NOTE: Do not move this consume's code to fron of + /* NOTE: Do not move this consume's code to front of * do-while loop. Registration of nested CE extension * might cause error because of current position. */ __archive_read_consume(a, step); @@ -2729,7 +2731,7 @@ next_cache_entry(struct archive_read *a, struct iso9660 *iso9660, if (file == NULL) { /* * If directory entries all which are descendant of - * rr_moved are stil remaning, expose their. + * rr_moved are still remaining, expose their. */ if (iso9660->re_files.first != NULL && iso9660->rr_moved != NULL && @@ -2852,7 +2854,7 @@ next_cache_entry(struct archive_read *a, struct iso9660 *iso9660, empty_files.last = &empty_files.first; /* Collect files which has the same file serial number. * Peek pending_files so that file which number is different - * is not put bak. */ + * is not put back. */ while (iso9660->pending_files.used > 0 && (iso9660->pending_files.files[0]->number == -1 || iso9660->pending_files.files[0]->number == number)) { @@ -2860,7 +2862,7 @@ next_cache_entry(struct archive_read *a, struct iso9660 *iso9660, /* This file has the same offset * but it's wrong offset which empty files * and symlink files have. - * NOTE: This wrong offse was recorded by + * NOTE: This wrong offset was recorded by * old mkisofs utility. If ISO images is * created by latest mkisofs, this does not * happen. diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_lha.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_lha.c index eff02d8..ebd7f2c 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_lha.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_lha.c @@ -924,6 +924,9 @@ lha_read_file_header_1(struct archive_read *a, struct lha *lha) /* Get a real compressed file size. */ lha->compsize -= extdsize - 2; + if (lha->compsize < 0) + goto invalid; /* Invalid compressed file size */ + if (sum_calculated != headersum) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "LHa header sum error"); @@ -1711,14 +1714,18 @@ lha_crc16(uint16_t crc, const void *pp, size_t len) */ for (;len >= 8; len -= 8) { /* This if statement expects compiler optimization will - * remove the stament which will not be executed. */ + * remove the statement which will not be executed. */ +#undef bswap16 #ifndef __has_builtin # define __has_builtin(x) 0 #endif #if defined(_MSC_VER) && _MSC_VER >= 1400 /* Visual Studio */ # define bswap16(x) _byteswap_ushort(x) -#elif (defined(__GNUC__) && __GNUC__ >= 4 && __GNUC_MINOR__ >= 8) \ - || (defined(__clang__) && __has_builtin(__builtin_bswap16)) +#elif defined(__GNUC__) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || __GNUC__ > 4) +/* GCC 4.8 and later has __builtin_bswap16() */ +# define bswap16(x) __builtin_bswap16(x) +#elif defined(__clang__) && __has_builtin(__builtin_bswap16) +/* All clang versions have __builtin_bswap16() */ # define bswap16(x) __builtin_bswap16(x) #else # define bswap16(x) ((((x) >> 8) & 0xff) | ((x) << 8)) diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c index 8c3be9a..4231ff5 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_mtree.c @@ -75,6 +75,8 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_support_format_mtree.c 2011 #define MTREE_HAS_OPTIONAL 0x0800 #define MTREE_HAS_NOCHANGE 0x1000 /* FreeBSD specific */ +#define MTREE_HASHTABLE_SIZE 1024 + struct mtree_option { struct mtree_option *next; char *value; @@ -86,6 +88,8 @@ struct mtree_entry { char *name; char full; char used; + unsigned int name_hash; + struct mtree_entry *hashtable_next; }; struct mtree { @@ -98,6 +102,7 @@ struct mtree { const char *archive_format_name; struct mtree_entry *entries; struct mtree_entry *this_entry; + struct mtree_entry *entry_hashtable[MTREE_HASHTABLE_SIZE]; struct archive_string current_dir; struct archive_string contents_name; @@ -110,6 +115,7 @@ struct mtree { static int bid_keycmp(const char *, const char *, ssize_t); static int cleanup(struct archive_read *); static int detect_form(struct archive_read *, int *); +static unsigned int hash(const char *); static int mtree_bid(struct archive_read *, int); static int parse_file(struct archive_read *, struct archive_entry *, struct mtree *, struct mtree_entry *, int *); @@ -223,13 +229,12 @@ archive_read_support_format_mtree(struct archive *_a) archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_support_format_mtree"); - mtree = (struct mtree *)malloc(sizeof(*mtree)); + mtree = (struct mtree *)calloc(1, sizeof(*mtree)); if (mtree == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate mtree data"); return (ARCHIVE_FATAL); } - memset(mtree, 0, sizeof(*mtree)); mtree->fd = -1; r = __archive_read_register_format(a, mtree, "mtree", @@ -301,6 +306,15 @@ get_line_size(const char *b, ssize_t avail, ssize_t *nlsize) return (avail); } +/* + * <---------------- ravail ---------------------> + * <-- diff ------> <--- avail -----------------> + * <---- len -----------> + * | Previous lines | line being parsed nl extra | + * ^ + * b + * + */ static ssize_t next_line(struct archive_read *a, const char **b, ssize_t *avail, ssize_t *ravail, ssize_t *nl) @@ -339,7 +353,7 @@ next_line(struct archive_read *a, *b += diff; *avail -= diff; tested = len;/* Skip some bytes we already determinated. */ - len = get_line_size(*b, *avail, nl); + len = get_line_size(*b + len, *avail - len, nl); if (len >= 0) len += tested; } @@ -701,13 +715,13 @@ detect_form(struct archive_read *a, int *is_form_d) } } else break; - } else if (strncmp(p, "/set", 4) == 0) { + } else if (len > 4 && strncmp(p, "/set", 4) == 0) { if (bid_keyword_list(p+4, len-4, 0, 0) <= 0) break; /* This line continues. */ if (p[len-nl-1] == '\\') multiline = 2; - } else if (strncmp(p, "/unset", 6) == 0) { + } else if (len > 6 && strncmp(p, "/unset", 6) == 0) { if (bid_keyword_list(p+6, len-6, 1, 0) <= 0) break; /* This line continues. */ @@ -853,11 +867,12 @@ process_add_entry(struct archive_read *a, struct mtree *mtree, struct mtree_option **global, const char *line, ssize_t line_len, struct mtree_entry **last_entry, int is_form_d) { - struct mtree_entry *entry; + struct mtree_entry *entry, *ht_iter; struct mtree_option *iter; const char *next, *eq, *name, *end; size_t name_len, len; int r, i; + unsigned int ht_idx; if ((entry = malloc(sizeof(*entry))) == NULL) { archive_set_error(&a->archive, errno, "Can't allocate memory"); @@ -868,6 +883,8 @@ process_add_entry(struct archive_read *a, struct mtree *mtree, entry->name = NULL; entry->used = 0; entry->full = 0; + entry->name_hash = 0; + entry->hashtable_next = NULL; /* Add this entry to list. */ if (*last_entry == NULL) @@ -920,6 +937,16 @@ process_add_entry(struct archive_read *a, struct mtree *mtree, memcpy(entry->name, name, name_len); entry->name[name_len] = '\0'; parse_escapes(entry->name, entry); + entry->name_hash = hash(entry->name); + + ht_idx = entry->name_hash % MTREE_HASHTABLE_SIZE; + if ((ht_iter = mtree->entry_hashtable[ht_idx]) != NULL) { + while (ht_iter->hashtable_next) + ht_iter = ht_iter->hashtable_next; + ht_iter->hashtable_next = entry; + } else { + mtree->entry_hashtable[ht_idx] = entry; + } for (iter = *global; iter != NULL; iter = iter->next) { r = add_option(a, &entry->options, iter->value, @@ -992,11 +1019,11 @@ read_mtree(struct archive_read *a, struct mtree *mtree) if (*p != '/') { r = process_add_entry(a, mtree, &global, p, len, &last_entry, is_form_d); - } else if (strncmp(p, "/set", 4) == 0) { + } else if (len > 4 && strncmp(p, "/set", 4) == 0) { if (p[4] != ' ' && p[4] != '\t') break; r = process_global_set(a, &global, p); - } else if (strncmp(p, "/unset", 6) == 0) { + } else if (len > 6 && strncmp(p, "/unset", 6) == 0) { if (p[6] != ' ' && p[6] != '\t') break; r = process_global_unset(a, &global, p); @@ -1113,9 +1140,10 @@ parse_file(struct archive_read *a, struct archive_entry *entry, * with pathname canonicalization, which is a very * tricky subject.) */ - for (mp = mentry->next; mp != NULL; mp = mp->next) { + for (mp = mentry->hashtable_next; mp != NULL; mp = mp->hashtable_next) { if (mp->full && !mp->used - && strcmp(mentry->name, mp->name) == 0) { + && mentry->name_hash == mp->name_hash + && strcmp(mentry->name, mp->name) == 0) { /* Later lines override earlier ones. */ mp->used = 1; r1 = parse_line(a, entry, mtree, mp, @@ -1580,8 +1608,11 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, if (*val == '.') { ++val; ns = (long)mtree_atol10(&val); - } else - ns = 0; + if (ns < 0) + ns = 0; + else if (ns > 999999999) + ns = 999999999; + } if (m > my_time_t_max) m = my_time_t_max; else if (m < my_time_t_min) @@ -1991,3 +2022,19 @@ readline(struct archive_read *a, struct mtree *mtree, char **start, find_off = u - mtree->line.s; } } + +static unsigned int +hash(const char *p) +{ + /* A 32-bit version of Peter Weinberger's (PJW) hash algorithm, + as used by ELF for hashing function names. */ + unsigned g, h = 0; + while (*p != '\0') { + h = (h << 4) + *p++; + if ((g = h & 0xF0000000) != 0) { + h ^= g >> 24; + h &= 0x0FFFFFFF; + } + } + return h; +} diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c index fc8153f..658d49d 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_rar.c @@ -647,13 +647,12 @@ archive_read_support_format_rar(struct archive *_a) archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_support_format_rar"); - rar = (struct rar *)malloc(sizeof(*rar)); + rar = (struct rar *)calloc(sizeof(*rar), 1); if (rar == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate rar data"); return (ARCHIVE_FATAL); } - memset(rar, 0, sizeof(*rar)); /* * Until enough data has been read, we cannot tell about @@ -907,7 +906,7 @@ archive_read_format_rar_read_header(struct archive_read *a, sizeof(rar->reserved2)); } - /* Main header is password encrytped, so we cannot read any + /* Main header is password encrypted, so we cannot read any file names or any other info about files from the header. */ if (rar->main_flags & MHD_PASSWORD) { diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c index b0521a6..bd7f13d 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_tar.c @@ -1,6 +1,7 @@ /*- * Copyright (c) 2003-2007 Tim Kientzle * Copyright (c) 2011-2012 Michihiro NAKAJIMA + * Copyright (c) 2016 Martin Matuska * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -136,6 +137,7 @@ struct tar { int64_t entry_padding; int64_t entry_bytes_unconsumed; int64_t realsize; + int sparse_allowed; struct sparse_block *sparse_list; struct sparse_block *sparse_last; int64_t sparse_offset; @@ -202,9 +204,14 @@ static int archive_read_format_tar_read_header(struct archive_read *, struct archive_entry *); static int checksum(struct archive_read *, const void *); static int pax_attribute(struct archive_read *, struct tar *, - struct archive_entry *, const char *key, const char *value); + struct archive_entry *, const char *key, const char *value, + size_t value_length); +static int pax_attribute_acl(struct archive_read *, struct tar *, + struct archive_entry *, const char *, int); +static int pax_attribute_xattr(struct archive_entry *, const char *, + const char *); static int pax_header(struct archive_read *, struct tar *, - struct archive_entry *, char *attr); + struct archive_entry *, struct archive_string *); static void pax_time(const char *, int64_t *sec, long *nanos); static ssize_t readline(struct archive_read *, struct tar *, const char **, ssize_t limit, size_t *); @@ -293,6 +300,57 @@ archive_read_format_tar_cleanup(struct archive_read *a) return (ARCHIVE_OK); } +/* + * Validate number field + * + * This has to be pretty lenient in order to accommodate the enormous + * variety of tar writers in the world: + * = POSIX (IEEE Std 1003.1-1988) ustar requires octal values with leading + * zeros and allows fields to be terminated with space or null characters + * = Many writers use different termination (in particular, libarchive + * omits terminator bytes to squeeze one or two more digits) + * = Many writers pad with space and omit leading zeros + * = GNU tar and star write base-256 values if numbers are too + * big to be represented in octal + * + * Examples of specific tar headers that we should support: + * = Perl Archive::Tar terminates uid, gid, devminor and devmajor with two + * null bytes, pads size with spaces and other numeric fields with zeroes + * = plexus-archiver prior to 2.6.3 (before switching to commons-compress) + * may have uid and gid fields filled with spaces without any octal digits + * at all and pads all numeric fields with spaces + * + * This should tolerate all variants in use. It will reject a field + * where the writer just left garbage after a trailing NUL. + */ +static int +validate_number_field(const char* p_field, size_t i_size) +{ + unsigned char marker = (unsigned char)p_field[0]; + if (marker == 128 || marker == 255 || marker == 0) { + /* Base-256 marker, there's nothing we can check. */ + return 1; + } else { + /* Must be octal */ + size_t i = 0; + /* Skip any leading spaces */ + while (i < i_size && p_field[i] == ' ') { + ++i; + } + /* Skip octal digits. */ + while (i < i_size && p_field[i] >= '0' && p_field[i] <= '7') { + ++i; + } + /* Any remaining characters must be space or NUL padding. */ + while (i < i_size) { + if (p_field[i] != ' ' && p_field[i] != 0) { + return 0; + } + ++i; + } + return 1; + } +} static int archive_read_format_tar_bid(struct archive_read *a, int best_bid) @@ -345,23 +403,19 @@ archive_read_format_tar_bid(struct archive_read *a, int best_bid) return (0); bid += 2; /* 6 bits of variation in an 8-bit field leaves 2 bits. */ - /* Sanity check: Look at first byte of mode field. */ - switch (255 & (unsigned)header->mode[0]) { - case 0: case 255: - /* Base-256 value: No further verification possible! */ - break; - case ' ': /* Not recommended, but not illegal, either. */ - break; - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - /* Octal Value. */ - /* TODO: Check format of remainder of this field. */ - break; - default: - /* Not a valid mode; bail out here. */ - return (0); + /* + * Check format of mode/uid/gid/mtime/size/rdevmajor/rdevminor fields. + */ + if (bid > 0 && ( + validate_number_field(header->mode, sizeof(header->mode)) == 0 + || validate_number_field(header->uid, sizeof(header->uid)) == 0 + || validate_number_field(header->gid, sizeof(header->gid)) == 0 + || validate_number_field(header->mtime, sizeof(header->mtime)) == 0 + || validate_number_field(header->size, sizeof(header->size)) == 0 + || validate_number_field(header->rdevmajor, sizeof(header->rdevmajor)) == 0 + || validate_number_field(header->rdevminor, sizeof(header->rdevminor)) == 0)) { + bid = 0; } - /* TODO: Sanity test uid/gid/size/mtime/rdevmajor/rdevminor fields. */ return (bid); } @@ -375,7 +429,7 @@ archive_read_format_tar_options(struct archive_read *a, tar = (struct tar *)(a->format->data); if (strcmp(key, "compat-2x") == 0) { - /* Handle UTF-8 filnames as libarchive 2.x */ + /* Handle UTF-8 filenames as libarchive 2.x */ tar->compat_2x = (val != NULL && val[0] != 0); tar->init_default_conversion = tar->compat_2x; return (ARCHIVE_OK); @@ -793,9 +847,9 @@ tar_read_header(struct archive_read *a, struct tar *tar, tar->sparse_gnu_pending = 0; /* Read initial sparse map. */ bytes_read = gnu_sparse_10_read(a, tar, unconsumed); - tar->entry_bytes_remaining -= bytes_read; if (bytes_read < 0) return ((int)bytes_read); + tar->entry_bytes_remaining -= bytes_read; } else { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, @@ -890,7 +944,7 @@ header_Solaris_ACL(struct archive_read *a, struct tar *tar, { const struct archive_entry_header_ustar *header; size_t size; - int err; + int err, acl_type; int64_t type; char *acl, *p; @@ -935,11 +989,12 @@ header_Solaris_ACL(struct archive_read *a, struct tar *tar, switch ((int)type & ~0777777) { case 01000000: /* POSIX.1e ACL */ + acl_type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; break; case 03000000: - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Solaris NFSv4 ACLs not supported"); - return (ARCHIVE_WARN); + /* NFSv4 ACL */ + acl_type = ARCHIVE_ENTRY_ACL_TYPE_NFS4; + break; default: archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Malformed Solaris ACL attribute (unsupported type %o)", @@ -968,8 +1023,8 @@ header_Solaris_ACL(struct archive_read *a, struct tar *tar, return (ARCHIVE_FATAL); } archive_strncpy(&(tar->localname), acl, p - acl); - err = archive_acl_parse_l(archive_entry_acl(entry), - tar->localname.s, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, tar->sconv_acl); + err = archive_acl_from_text_l(archive_entry_acl(entry), + tar->localname.s, acl_type, tar->sconv_acl); if (err != ARCHIVE_OK) { if (errno == ENOMEM) { archive_set_error(&a->archive, ENOMEM, @@ -1128,8 +1183,15 @@ header_common(struct archive_read *a, struct tar *tar, if (tar->entry_bytes_remaining < 0) { tar->entry_bytes_remaining = 0; archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Tar entry has negative size?"); - err = ARCHIVE_WARN; + "Tar entry has negative size"); + return (ARCHIVE_FATAL); + } + if (tar->entry_bytes_remaining == INT64_MAX) { + /* Note: tar_atol returns INT64_MAX on overflow */ + tar->entry_bytes_remaining = 0; + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Tar entry size overflow"); + return (ARCHIVE_FATAL); } tar->realsize = tar->entry_bytes_remaining; archive_entry_set_size(entry, tar->entry_bytes_remaining); @@ -1264,6 +1326,14 @@ header_common(struct archive_read *a, struct tar *tar, * sparse information in the extended area. */ /* FALLTHROUGH */ + case '0': + /* + * Enable sparse file "read" support only for regular + * files and explicit GNU sparse files. However, we + * don't allow non-standard file types to be sparse. + */ + tar->sparse_allowed = 1; + /* FALLTHROUGH */ default: /* Regular file and non-standard types */ /* * Per POSIX: non-recognized types should always be @@ -1415,7 +1485,7 @@ header_pax_extensions(struct archive_read *a, struct tar *tar, * and then skip any fields in the standard header that were * defined in the pax header. */ - err2 = pax_header(a, tar, entry, tar->pax_header.s); + err2 = pax_header(a, tar, entry, &tar->pax_header); err = err_combine(err, err2); tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining); return (err); @@ -1496,16 +1566,17 @@ header_ustar(struct archive_read *a, struct tar *tar, */ static int pax_header(struct archive_read *a, struct tar *tar, - struct archive_entry *entry, char *attr) + struct archive_entry *entry, struct archive_string *in_as) { - size_t attr_length, l, line_length; + size_t attr_length, l, line_length, value_length; char *p; char *key, *value; struct archive_string *as; struct archive_string_conv *sconv; int err, err2; + char *attr = in_as->s; - attr_length = strlen(attr); + attr_length = in_as->length; tar->pax_hdrcharset_binary = 0; archive_string_empty(&(tar->entry_gname)); archive_string_empty(&(tar->entry_linkpath)); @@ -1570,11 +1641,13 @@ pax_header(struct archive_read *a, struct tar *tar, } *p = '\0'; - /* Identify null-terminated 'value' portion. */ value = p + 1; + /* Some values may be binary data */ + value_length = attr + line_length - 1 - value; + /* Identify this attribute and set it in the entry. */ - err2 = pax_attribute(a, tar, entry, key, value); + err2 = pax_attribute(a, tar, entry, key, value, value_length); if (err2 == ARCHIVE_FATAL) return (err2); err = err_combine(err, err2); @@ -1695,6 +1768,66 @@ pax_attribute_xattr(struct archive_entry *entry, return 0; } +static int +pax_attribute_schily_xattr(struct archive_entry *entry, + const char *name, const char *value, size_t value_length) +{ + if (strlen(name) < 14 || (memcmp(name, "SCHILY.xattr.", 13)) != 0) + return 1; + + name += 13; + + archive_entry_xattr_add_entry(entry, name, value, value_length); + + return 0; +} + +static int +pax_attribute_acl(struct archive_read *a, struct tar *tar, + struct archive_entry *entry, const char *value, int type) +{ + int r; + const char* errstr; + + switch (type) { + case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: + errstr = "SCHILY.acl.access"; + break; + case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: + errstr = "SCHILY.acl.default"; + break; + case ARCHIVE_ENTRY_ACL_TYPE_NFS4: + errstr = "SCHILY.acl.ace"; + break; + default: + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Unknown ACL type: %d", type); + return(ARCHIVE_FATAL); + } + + if (tar->sconv_acl == NULL) { + tar->sconv_acl = + archive_string_conversion_from_charset( + &(a->archive), "UTF-8", 1); + if (tar->sconv_acl == NULL) + return (ARCHIVE_FATAL); + } + + r = archive_acl_from_text_l(archive_entry_acl(entry), value, type, + tar->sconv_acl); + if (r != ARCHIVE_OK) { + if (r == ARCHIVE_FATAL) { + archive_set_error(&a->archive, ENOMEM, + "%s %s", "Can't allocate memory for ", + errstr); + return (r); + } + archive_set_error(&a->archive, + ARCHIVE_ERRNO_MISC, "%s %s", "Parse error: ", errstr); + } + return (r); +} + /* * Parse a single key=value attribute. key/value pointers are * assumed to point into reasonably long-lived storage. @@ -1710,7 +1843,7 @@ pax_attribute_xattr(struct archive_entry *entry, */ static int pax_attribute(struct archive_read *a, struct tar *tar, - struct archive_entry *entry, const char *key, const char *value) + struct archive_entry *entry, const char *key, const char *value, size_t value_length) { int64_t s; long n; @@ -1721,6 +1854,14 @@ pax_attribute(struct archive_read *a, struct tar *tar, * NULL pointer to strlen(). */ switch (key[0]) { case 'G': + /* Reject GNU.sparse.* headers on non-regular files. */ + if (strncmp(key, "GNU.sparse", 10) == 0 && + !tar->sparse_allowed) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Non-regular file cannot be sparse"); + return (ARCHIVE_FATAL); + } + /* GNU "0.0" sparse pax format. */ if (strcmp(key, "GNU.sparse.numblocks") == 0) { tar->sparse_offset = -1; @@ -1803,53 +1944,20 @@ pax_attribute(struct archive_read *a, struct tar *tar, case 'S': /* We support some keys used by the "star" archiver */ if (strcmp(key, "SCHILY.acl.access") == 0) { - if (tar->sconv_acl == NULL) { - tar->sconv_acl = - archive_string_conversion_from_charset( - &(a->archive), "UTF-8", 1); - if (tar->sconv_acl == NULL) - return (ARCHIVE_FATAL); - } - - r = archive_acl_parse_l(archive_entry_acl(entry), - value, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, - tar->sconv_acl); - if (r != ARCHIVE_OK) { - err = r; - if (err == ARCHIVE_FATAL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory for " - "SCHILY.acl.access"); - return (err); - } - archive_set_error(&a->archive, - ARCHIVE_ERRNO_MISC, - "Parse error: SCHILY.acl.access"); - } + r = pax_attribute_acl(a, tar, entry, value, + ARCHIVE_ENTRY_ACL_TYPE_ACCESS); + if (r == ARCHIVE_FATAL) + return (r); } else if (strcmp(key, "SCHILY.acl.default") == 0) { - if (tar->sconv_acl == NULL) { - tar->sconv_acl = - archive_string_conversion_from_charset( - &(a->archive), "UTF-8", 1); - if (tar->sconv_acl == NULL) - return (ARCHIVE_FATAL); - } - - r = archive_acl_parse_l(archive_entry_acl(entry), - value, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, - tar->sconv_acl); - if (r != ARCHIVE_OK) { - err = r; - if (err == ARCHIVE_FATAL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory for " - "SCHILY.acl.default"); - return (err); - } - archive_set_error(&a->archive, - ARCHIVE_ERRNO_MISC, - "Parse error: SCHILY.acl.default"); - } + r = pax_attribute_acl(a, tar, entry, value, + ARCHIVE_ENTRY_ACL_TYPE_DEFAULT); + if (r == ARCHIVE_FATAL) + return (r); + } else if (strcmp(key, "SCHILY.acl.ace") == 0) { + r = pax_attribute_acl(a, tar, entry, value, + ARCHIVE_ENTRY_ACL_TYPE_NFS4); + if (r == ARCHIVE_FATAL) + return (r); } else if (strcmp(key, "SCHILY.devmajor") == 0) { archive_entry_set_rdevmajor(entry, (dev_t)tar_atol10(value, strlen(value))); @@ -1870,6 +1978,9 @@ pax_attribute(struct archive_read *a, struct tar *tar, } else if (strcmp(key, "SCHILY.realsize") == 0) { tar->realsize = tar_atol10(value, strlen(value)); archive_entry_set_size(entry, tar->realsize); + } else if (strncmp(key, "SCHILY.xattr.", 13) == 0) { + pax_attribute_schily_xattr(entry, key, value, + value_length); } else if (strcmp(key, "SUN.holesdata") == 0) { /* A Solaris extension for sparse. */ r = solaris_sparse_parse(a, tar, entry, value); @@ -2116,12 +2227,11 @@ gnu_add_sparse_entry(struct archive_read *a, struct tar *tar, { struct sparse_block *p; - p = (struct sparse_block *)malloc(sizeof(*p)); + p = (struct sparse_block *)calloc(1, sizeof(*p)); if (p == NULL) { archive_set_error(&a->archive, ENOMEM, "Out of memory"); return (ARCHIVE_FATAL); } - memset(p, 0, sizeof(*p)); if (tar->sparse_last != NULL) tar->sparse_last->next = p; else @@ -2377,6 +2487,9 @@ gnu_sparse_10_read(struct archive_read *a, struct tar *tar, size_t *unconsumed) tar_flush_unconsumed(a, unconsumed); bytes_read = (ssize_t)(tar->entry_bytes_remaining - remaining); to_skip = 0x1ff & -bytes_read; + /* Fail if tar->entry_bytes_remaing would get negative */ + if (to_skip > remaining) + return (ARCHIVE_FATAL); if (to_skip != __archive_read_consume(a, to_skip)) return (ARCHIVE_FATAL); return ((ssize_t)(bytes_read + to_skip)); @@ -2472,7 +2585,7 @@ tar_atol_base_n(const char *p, size_t char_cnt, int base) last_digit_limit = INT64_MAX % base; /* the pointer will not be dereferenced if char_cnt is zero - * due to the way the && operator is evaulated. + * due to the way the && operator is evaluated. */ while (char_cnt != 0 && (*p == ' ' || *p == '\t')) { p++; diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_warc.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_warc.c index 46a59ea..5e22438 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_warc.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_warc.c @@ -88,7 +88,7 @@ typedef enum { WT_RVIS, /* conversion, unsupported */ WT_CONV, - /* continutation, unsupported at the moment */ + /* continuation, unsupported at the moment */ WT_CONT, /* invalid type */ LAST_WT @@ -134,8 +134,8 @@ static ssize_t _warc_rdlen(const char *buf, size_t bsz); static time_t _warc_rdrtm(const char *buf, size_t bsz); static time_t _warc_rdmtm(const char *buf, size_t bsz); static const char *_warc_find_eoh(const char *buf, size_t bsz); +static const char *_warc_find_eol(const char *buf, size_t bsz); - int archive_read_support_format_warc(struct archive *_a) { @@ -146,12 +146,11 @@ archive_read_support_format_warc(struct archive *_a) archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_support_format_warc"); - if ((w = malloc(sizeof(*w))) == NULL) { + if ((w = calloc(1, sizeof(*w))) == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate warc data"); return (ARCHIVE_FATAL); } - memset(w, 0, sizeof(*w)); r = __archive_read_register_format( a, w, "warc", @@ -199,8 +198,8 @@ _warc_bid(struct archive_read *a, int best_bid) /* otherwise snarf the record's version number */ ver = _warc_rdver(hdr, nrd); - if (ver == 0U || ver > 10000U) { - /* oh oh oh, best not to wager ... */ + if (ver < 1200U || ver > 10000U) { + /* we only support WARC 0.12 to 1.0 */ return -1; } @@ -255,23 +254,32 @@ start_over: &a->archive, ARCHIVE_ERRNO_MISC, "Bad record header"); return (ARCHIVE_FATAL); - } else if ((ver = _warc_rdver(buf, eoh - buf)) > 10000U) { - /* nawww, I wish they promised backward compatibility - * anyhoo, in their infinite wisdom the 28500 guys might - * come up with something we can't possibly handle so - * best end things here */ + } + ver = _warc_rdver(buf, eoh - buf); + /* we currently support WARC 0.12 to 1.0 */ + if (ver == 0U) { archive_set_error( &a->archive, ARCHIVE_ERRNO_MISC, - "Unsupported record version"); + "Invalid record version"); return (ARCHIVE_FATAL); - } else if ((cntlen = _warc_rdlen(buf, eoh - buf)) < 0) { + } else if (ver < 1200U || ver > 10000U) { + archive_set_error( + &a->archive, ARCHIVE_ERRNO_MISC, + "Unsupported record version: %u.%u", + ver / 10000, (ver % 10000) / 100); + return (ARCHIVE_FATAL); + } + cntlen = _warc_rdlen(buf, eoh - buf); + if (cntlen < 0) { /* nightmare! the specs say content-length is mandatory * so I don't feel overly bad stopping the reader here */ archive_set_error( &a->archive, EINVAL, "Bad content length"); return (ARCHIVE_FATAL); - } else if ((rtime = _warc_rdrtm(buf, eoh - buf)) == (time_t)-1) { + } + rtime = _warc_rdrtm(buf, eoh - buf); + if (rtime == (time_t)-1) { /* record time is mandatory as per WARC/1.0, * so just barf here, fast and loud */ archive_set_error( @@ -285,7 +293,7 @@ start_over: if (ver != w->pver) { /* stringify this entry's version */ archive_string_sprintf(&w->sver, - "WARC/%u.%u", ver / 10000, ver % 10000); + "WARC/%u.%u", ver / 10000, (ver % 10000) / 100); /* remember the version */ w->pver = ver; } @@ -318,7 +326,7 @@ start_over: } memcpy(w->pool.str, fnam.str, fnam.len); w->pool.str[fnam.len] = '\0'; - /* let noone else know about the pool, it's a secret, shhh */ + /* let no one else know about the pool, it's a secret, shhh */ fnam.str = w->pool.str; /* snarf mtime or deduce from rtime @@ -535,7 +543,8 @@ xstrpisotime(const char *s, char **endptr) /* as a courtesy to our callers, and since this is a non-standard * routine, we skip leading whitespace */ - for (; isspace(*s); s++); + while (isblank((unsigned char)*s)) + ++s; /* read year */ if ((tm.tm_year = strtoi_lim(s, &s, 1583, 4095)) < 0 || *s++ != '-') { @@ -562,7 +571,7 @@ xstrpisotime(const char *s, char **endptr) goto out; } - /* massage TM to fulfill some of POSIX' contraints */ + /* massage TM to fulfill some of POSIX' constraints */ tm.tm_year -= 1900; tm.tm_mon--; @@ -577,51 +586,41 @@ out: } static unsigned int -_warc_rdver(const char buf[10], size_t bsz) +_warc_rdver(const char *buf, size_t bsz) { static const char magic[] = "WARC/"; - unsigned int ver; - - (void)bsz; /* UNUSED */ + unsigned int ver = 0U; + unsigned int end = 0U; - if (memcmp(buf, magic, sizeof(magic) - 1U) != 0) { - /* nope */ - return 99999U; + if (bsz < 12 || memcmp(buf, magic, sizeof(magic) - 1U) != 0) { + /* buffer too small or invalid magic */ + return ver; } /* looks good so far, read the version number for a laugh */ buf += sizeof(magic) - 1U; - /* most common case gets a quick-check here */ - if (memcmp(buf, "1.0\r\n", 5U) == 0) { - ver = 10000U; - } else { - switch (*buf) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - if (buf[1U] == '.') { - char *on; - - /* set up major version */ - ver = (buf[0U] - '0') * 10000U; - /* minor version, anyone? */ - ver += (strtol(buf + 2U, &on, 10)) * 100U; - /* don't parse anything else */ - if (on > buf + 2U) { - break; - } - } - /* FALLTHROUGH */ - case '9': - default: - /* just make the version ridiculously high */ - ver = 999999U; - break; + + if (isdigit(buf[0U]) && (buf[1U] == '.') && isdigit(buf[2U])) { + /* we support a maximum of 2 digits in the minor version */ + if (isdigit(buf[3U])) + end = 1U; + /* set up major version */ + ver = (buf[0U] - '0') * 10000U; + /* set up minor version */ + if (end == 1U) { + ver += (buf[2U] - '0') * 1000U; + ver += (buf[3U] - '0') * 100U; + } else + ver += (buf[2U] - '0') * 100U; + /* + * WARC below version 0.12 has a space-separated header + * WARC 0.12 and above terminates the version with a CRLF + */ + if (ver >= 1200U) { + if (memcmp(buf + 3U + end, "\r\n", 2U) != 0) + ver = 0U; + } else if (ver < 1200U) { + if (!isblank(*(buf + 3U + end))) + ver = 0U; } } return ver; @@ -631,32 +630,27 @@ static unsigned int _warc_rdtyp(const char *buf, size_t bsz) { static const char _key[] = "\r\nWARC-Type:"; - const char *const eob = buf + bsz; - const char *val; + const char *val, *eol; if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) { /* no bother */ return WT_NONE; } + val += sizeof(_key) - 1U; + if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL) { + /* no end of line */ + return WT_NONE; + } + /* overread whitespace */ - for (val += sizeof(_key) - 1U; val < eob && isspace(*val); val++); - - if (val + 8U > eob) { - ; - } else if (memcmp(val, "resource", 8U) == 0) { - return WT_RSRC; - } else if (memcmp(val, "warcinfo", 8U) == 0) { - return WT_INFO; - } else if (memcmp(val, "metadata", 8U) == 0) { - return WT_META; - } else if (memcmp(val, "request", 7U) == 0) { - return WT_REQ; - } else if (memcmp(val, "response", 8U) == 0) { - return WT_RSP; - } else if (memcmp(val, "conversi", 8U) == 0) { - return WT_CONV; - } else if (memcmp(val, "continua", 8U) == 0) { - return WT_CONT; + while (val < eol && isblank((unsigned char)*val)) + ++val; + + if (val + 8U == eol) { + if (memcmp(val, "resource", 8U) == 0) + return WT_RSRC; + else if (memcmp(val, "response", 8U) == 0) + return WT_RSP; } return WT_NONE; } @@ -665,10 +659,7 @@ static warc_string_t _warc_rduri(const char *buf, size_t bsz) { static const char _key[] = "\r\nWARC-Target-URI:"; - const char *const eob = buf + bsz; - const char *val; - const char *uri; - const char *eol; + const char *val, *uri, *eol, *p; warc_string_t res = {0U, NULL}; if ((val = xmemmem(buf, bsz, _key, sizeof(_key) - 1U)) == NULL) { @@ -676,23 +667,33 @@ _warc_rduri(const char *buf, size_t bsz) return res; } /* overread whitespace */ - for (val += sizeof(_key) - 1U; val < eob && isspace(*val); val++); + val += sizeof(_key) - 1U; + if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL) { + /* no end of line */ + return res; + } + + while (val < eol && isblank((unsigned char)*val)) + ++val; /* overread URL designators */ - if ((uri = xmemmem(val, eob - val, "://", 3U)) == NULL) { + if ((uri = xmemmem(val, eol - val, "://", 3U)) == NULL) { /* not touching that! */ return res; - } else if ((eol = memchr(uri, '\n', eob - uri)) == NULL) { - /* no end of line? :O */ - return res; } - /* massage uri to point to after :// */ + /* spaces inside uri are not allowed, CRLF should follow */ + for (p = val; p < eol; p++) { + if (isspace(*p)) + return res; + } + + /* there must be at least space for ftp */ + if (uri < (val + 3U)) + return res; + + /* move uri to point to after :// */ uri += 3U; - /* also massage eol to point to the first whitespace - * after the last non-whitespace character before - * the end of the line */ - for (; eol > uri && isspace(eol[-1]); eol--); /* now then, inspect the URI */ if (memcmp(val, "file", 4U) == 0) { @@ -715,7 +716,7 @@ static ssize_t _warc_rdlen(const char *buf, size_t bsz) { static const char _key[] = "\r\nContent-Length:"; - const char *val; + const char *val, *eol; char *on = NULL; long int len; @@ -723,14 +724,24 @@ _warc_rdlen(const char *buf, size_t bsz) /* no bother */ return -1; } - - /* strtol kindly overreads whitespace for us, so use that */ val += sizeof(_key) - 1U; + if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL) { + /* no end of line */ + return -1; + } + + /* skip leading whitespace */ + while (val < eol && isblank(*val)) + val++; + /* there must be at least one digit */ + if (!isdigit(*val)) + return -1; len = strtol(val, &on, 10); - if (on == NULL || !isspace(*on)) { - /* hm, can we trust that number? Best not. */ + if (on != eol) { + /* line must end here */ return -1; } + return (size_t)len; } @@ -738,7 +749,7 @@ static time_t _warc_rdrtm(const char *buf, size_t bsz) { static const char _key[] = "\r\nWARC-Date:"; - const char *val; + const char *val, *eol; char *on = NULL; time_t res; @@ -746,13 +757,17 @@ _warc_rdrtm(const char *buf, size_t bsz) /* no bother */ return (time_t)-1; } + val += sizeof(_key) - 1U; + if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL ) { + /* no end of line */ + return -1; + } /* xstrpisotime() kindly overreads whitespace for us, so use that */ - val += sizeof(_key) - 1U; res = xstrpisotime(val, &on); - if (on == NULL || !isspace(*on)) { - /* hm, can we trust that number? Best not. */ - return (time_t)-1; + if (on != eol) { + /* line must end here */ + return -1; } return res; } @@ -761,7 +776,7 @@ static time_t _warc_rdmtm(const char *buf, size_t bsz) { static const char _key[] = "\r\nLast-Modified:"; - const char *val; + const char *val, *eol; char *on = NULL; time_t res; @@ -769,13 +784,17 @@ _warc_rdmtm(const char *buf, size_t bsz) /* no bother */ return (time_t)-1; } + val += sizeof(_key) - 1U; + if ((eol = _warc_find_eol(val, buf + bsz - val)) == NULL ) { + /* no end of line */ + return -1; + } /* xstrpisotime() kindly overreads whitespace for us, so use that */ - val += sizeof(_key) - 1U; res = xstrpisotime(val, &on); - if (on == NULL || !isspace(*on)) { - /* hm, can we trust that number? Best not. */ - return (time_t)-1; + if (on != eol) { + /* line must end here */ + return -1; } return res; } @@ -792,4 +811,12 @@ _warc_find_eoh(const char *buf, size_t bsz) return hit; } +static const char* +_warc_find_eol(const char *buf, size_t bsz) +{ + static const char _marker[] = "\r\n"; + const char *hit = xmemmem(buf, bsz, _marker, sizeof(_marker) - 1U); + + return hit; +} /* archive_read_support_format_warc.c ends here */ diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_xar.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_xar.c index ec623c6..eeac1c8 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_xar.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_xar.c @@ -43,8 +43,6 @@ __FBSDID("$FreeBSD$"); #endif #if HAVE_LZMA_H #include <cm_lzma.h> -#elif HAVE_LZMADEC_H -#include <lzmadec.h> #endif #ifdef HAVE_ZLIB_H #include <cm_zlib.h> @@ -334,9 +332,6 @@ struct xar { #if HAVE_LZMA_H && HAVE_LIBLZMA lzma_stream lzstream; int lzstream_valid; -#elif HAVE_LZMADEC_H && HAVE_LIBLZMADEC - lzmadec_stream lzstream; - int lzstream_valid; #endif /* * For Checksum data. @@ -399,6 +394,7 @@ static void checksum_update(struct archive_read *, const void *, size_t, const void *, size_t); static int checksum_final(struct archive_read *, const void *, size_t, const void *, size_t); +static void checksum_cleanup(struct archive_read *); static int decompression_init(struct archive_read *, enum enctype); static int decompress(struct archive_read *, const void **, size_t *, const void *, size_t *); @@ -928,6 +924,7 @@ xar_cleanup(struct archive_read *a) int r; xar = (struct xar *)(a->format->data); + checksum_cleanup(a); r = decompression_cleanup(a); hdlink = xar->hdlink_list; while (hdlink != NULL) { @@ -938,6 +935,7 @@ xar_cleanup(struct archive_read *a) } for (i = 0; i < xar->file_queue.used; i++) file_free(xar->file_queue.files[i]); + free(xar->file_queue.files); while (xar->unknowntags != NULL) { struct unknown_tag *tag; @@ -1526,34 +1524,6 @@ decompression_init(struct archive_read *a, enum enctype encoding) xar->lzstream.total_in = 0; xar->lzstream.total_out = 0; break; -#elif defined(HAVE_LZMADEC_H) && defined(HAVE_LIBLZMADEC) - case LZMA: - if (xar->lzstream_valid) - lzmadec_end(&(xar->lzstream)); - r = lzmadec_init(&(xar->lzstream)); - if (r != LZMADEC_OK) { - switch (r) { - case LZMADEC_HEADER_ERROR: - archive_set_error(&a->archive, - ARCHIVE_ERRNO_MISC, - "Internal error initializing " - "compression library: " - "invalid header"); - break; - case LZMADEC_MEM_ERROR: - archive_set_error(&a->archive, - ENOMEM, - "Internal error initializing " - "compression library: " - "out of memory"); - break; - } - return (ARCHIVE_FATAL); - } - xar->lzstream_valid = 1; - xar->lzstream.total_in = 0; - xar->lzstream.total_out = 0; - break; #endif /* * Unsupported compression. @@ -1563,9 +1533,7 @@ decompression_init(struct archive_read *a, enum enctype encoding) case BZIP2: #endif #if !defined(HAVE_LZMA_H) || !defined(HAVE_LIBLZMA) -#if !defined(HAVE_LZMADEC_H) || !defined(HAVE_LIBLZMADEC) case LZMA: -#endif case XZ: #endif switch (xar->entry_encoding) { @@ -1685,46 +1653,12 @@ decompress(struct archive_read *a, const void **buff, size_t *outbytes, *used = avail_in - xar->lzstream.avail_in; *outbytes = avail_out - xar->lzstream.avail_out; break; -#elif defined(HAVE_LZMADEC_H) && defined(HAVE_LIBLZMADEC) - case LZMA: - xar->lzstream.next_in = (unsigned char *)(uintptr_t)b; - xar->lzstream.avail_in = avail_in; - xar->lzstream.next_out = (unsigned char *)outbuff; - xar->lzstream.avail_out = avail_out; - r = lzmadec_decode(&(xar->lzstream), 0); - switch (r) { - case LZMADEC_STREAM_END: /* Found end of stream. */ - switch (lzmadec_end(&(xar->lzstream))) { - case LZMADEC_OK: - break; - default: - archive_set_error(&(a->archive), - ARCHIVE_ERRNO_MISC, - "Failed to clean up lzmadec decompressor"); - return (ARCHIVE_FATAL); - } - xar->lzstream_valid = 0; - /* FALLTHROUGH */ - case LZMADEC_OK: /* Decompressor made some progress. */ - break; - default: - archive_set_error(&(a->archive), - ARCHIVE_ERRNO_MISC, - "lzmadec decompression failed(%d)", - r); - return (ARCHIVE_FATAL); - } - *used = avail_in - xar->lzstream.avail_in; - *outbytes = avail_out - xar->lzstream.avail_out; - break; #endif #if !defined(HAVE_BZLIB_H) || !defined(BZ_CONFIG_ERROR) case BZIP2: #endif #if !defined(HAVE_LZMA_H) || !defined(HAVE_LIBLZMA) -#if !defined(HAVE_LZMADEC_H) || !defined(HAVE_LIBLZMADEC) case LZMA: -#endif case XZ: #endif case NONE: @@ -1788,6 +1722,16 @@ decompression_cleanup(struct archive_read *a) } static void +checksum_cleanup(struct archive_read *a) { + struct xar *xar; + + xar = (struct xar *)(a->format->data); + + _checksum_final(&(xar->a_sumwrk), NULL, 0); + _checksum_final(&(xar->e_sumwrk), NULL, 0); +} + +static void xmlattr_cleanup(struct xmlattr_list *list) { struct xmlattr *attr, *next; @@ -3116,7 +3060,7 @@ xml2_read_cb(void *context, char *buffer, int len) struct xar *xar; const void *d; size_t outbytes; - size_t used; + size_t used = 0; int r; a = (struct archive_read *)context; @@ -3240,6 +3184,9 @@ expat_xmlattr_setup(struct archive_read *a, value = strdup(atts[1]); if (attr == NULL || name == NULL || value == NULL) { archive_set_error(&a->archive, ENOMEM, "Out of memory"); + free(attr); + free(name); + free(value); return (ARCHIVE_FATAL); } attr->name = name; diff --git a/Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c b/Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c index c50ba84..e56bd63 100644 --- a/Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c +++ b/Utilities/cmlibarchive/libarchive/archive_read_support_format_zip.c @@ -199,7 +199,7 @@ struct zip { struct trad_enc_ctx tctx; char tctx_valid; - /* WinZip AES decyption. */ + /* WinZip AES decryption. */ /* Contexts used for AES decryption. */ archive_crypto_ctx cctx; char cctx_valid; @@ -242,7 +242,7 @@ trad_enc_update_keys(struct trad_enc_ctx *ctx, uint8_t c) } static uint8_t -trad_enc_decypt_byte(struct trad_enc_ctx *ctx) +trad_enc_decrypt_byte(struct trad_enc_ctx *ctx) { unsigned temp = ctx->keys[2] | 2; return (uint8_t)((temp * (temp ^ 1)) >> 8) & 0xff; @@ -257,7 +257,7 @@ trad_enc_decrypt_update(struct trad_enc_ctx *ctx, const uint8_t *in, max = (unsigned)((in_len < out_len)? in_len: out_len); for (i = 0; i < max; i++) { - uint8_t t = in[i] ^ trad_enc_decypt_byte(ctx); + uint8_t t = in[i] ^ trad_enc_decrypt_byte(ctx); out[i] = t; trad_enc_update_keys(ctx, t); } @@ -418,18 +418,30 @@ zip_time(const char *p) * id1+size1+data1 + id2+size2+data2 ... * triplets. id and size are 2 bytes each. */ -static void -process_extra(const char *p, size_t extra_length, struct zip_entry* zip_entry) +static int +process_extra(struct archive_read *a, const char *p, size_t extra_length, struct zip_entry* zip_entry) { unsigned offset = 0; - while (offset < extra_length - 4) { + if (extra_length == 0) { + return ARCHIVE_OK; + } + + if (extra_length < 4) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Too-small extra data: Need at least 4 bytes, but only found %d bytes", (int)extra_length); + return ARCHIVE_FAILED; + } + while (offset <= extra_length - 4) { unsigned short headerid = archive_le16dec(p + offset); unsigned short datasize = archive_le16dec(p + offset + 2); offset += 4; if (offset + datasize > extra_length) { - break; + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Extra data overflow: Need %d bytes but only found %d bytes", + (int)datasize, (int)(extra_length - offset)); + return ARCHIVE_FAILED; } #ifdef DEBUG fprintf(stderr, "Header id 0x%04x, length %d\n", @@ -440,26 +452,38 @@ process_extra(const char *p, size_t extra_length, struct zip_entry* zip_entry) /* Zip64 extended information extra field. */ zip_entry->flags |= LA_USED_ZIP64; if (zip_entry->uncompressed_size == 0xffffffff) { - if (datasize < 8) - break; - zip_entry->uncompressed_size = - archive_le64dec(p + offset); + uint64_t t = 0; + if (datasize < 8 + || (t = archive_le64dec(p + offset)) > INT64_MAX) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Malformed 64-bit uncompressed size"); + return ARCHIVE_FAILED; + } + zip_entry->uncompressed_size = t; offset += 8; datasize -= 8; } if (zip_entry->compressed_size == 0xffffffff) { - if (datasize < 8) - break; - zip_entry->compressed_size = - archive_le64dec(p + offset); + uint64_t t = 0; + if (datasize < 8 + || (t = archive_le64dec(p + offset)) > INT64_MAX) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Malformed 64-bit compressed size"); + return ARCHIVE_FAILED; + } + zip_entry->compressed_size = t; offset += 8; datasize -= 8; } if (zip_entry->local_header_offset == 0xffffffff) { - if (datasize < 8) - break; - zip_entry->local_header_offset = - archive_le64dec(p + offset); + uint64_t t = 0; + if (datasize < 8 + || (t = archive_le64dec(p + offset)) > INT64_MAX) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Malformed 64-bit local header offset"); + return ARCHIVE_FAILED; + } + zip_entry->local_header_offset = t; offset += 8; datasize -= 8; } @@ -698,7 +722,7 @@ process_extra(const char *p, size_t extra_length, struct zip_entry* zip_entry) break; } case 0x9901: - /* WinZIp AES extra data field. */ + /* WinZip AES extra data field. */ if (p[offset + 2] == 'A' && p[offset + 3] == 'E') { /* Vendor version. */ zip_entry->aes_extra.vendor = @@ -715,13 +739,13 @@ process_extra(const char *p, size_t extra_length, struct zip_entry* zip_entry) } offset += datasize; } -#ifdef DEBUG - if (offset != extra_length) - { - fprintf(stderr, - "Extra data field contents do not match reported size!\n"); + if (offset != extra_length) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Malformed extra data: Consumed %d bytes of %d bytes", + (int)offset, (int)extra_length); + return ARCHIVE_FAILED; } -#endif + return ARCHIVE_OK; } /* @@ -840,7 +864,9 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry, return (ARCHIVE_FATAL); } - process_extra(h, extra_length, zip_entry); + if (ARCHIVE_OK != process_extra(a, h, extra_length, zip_entry)) { + return ARCHIVE_FATAL; + } __archive_read_consume(a, extra_length); /* Work around a bug in Info-Zip: When reading from a pipe, it @@ -850,29 +876,33 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry, zip_entry->mode |= AE_IFREG; } - if ((zip_entry->mode & AE_IFMT) == 0) { - /* Especially in streaming mode, we can end up - here without having seen proper mode information. - Guess from the filename. */ + /* If the mode is totally empty, set some sane default. */ + if (zip_entry->mode == 0) { + zip_entry->mode |= 0664; + } + + /* Make sure that entries with a trailing '/' are marked as directories + * even if the External File Attributes contains bogus values. If this + * is not a directory and there is no type, assume regularfile. */ + if ((zip_entry->mode & AE_IFMT) != AE_IFDIR) { + int has_slash; + wp = archive_entry_pathname_w(entry); if (wp != NULL) { len = wcslen(wp); - if (len > 0 && wp[len - 1] == L'/') - zip_entry->mode |= AE_IFDIR; - else - zip_entry->mode |= AE_IFREG; + has_slash = len > 0 && wp[len - 1] == L'/'; } else { cp = archive_entry_pathname(entry); len = (cp != NULL)?strlen(cp):0; - if (len > 0 && cp[len - 1] == '/') - zip_entry->mode |= AE_IFDIR; - else - zip_entry->mode |= AE_IFREG; + has_slash = len > 0 && cp[len - 1] == '/'; } - if (zip_entry->mode == AE_IFDIR) { - zip_entry->mode |= 0775; - } else if (zip_entry->mode == AE_IFREG) { - zip_entry->mode |= 0664; + /* Correct file type as needed. */ + if (has_slash) { + zip_entry->mode &= ~AE_IFMT; + zip_entry->mode |= AE_IFDIR; + zip_entry->mode |= 0111; + } else if ((zip_entry->mode & AE_IFMT) == 0) { + zip_entry->mode |= AE_IFREG; } } @@ -887,6 +917,7 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry, archive_wstrcat(&s, wp); archive_wstrappend_wchar(&s, L'/'); archive_entry_copy_pathname_w(entry, s.s); + archive_wstring_free(&s); } } else { cp = archive_entry_pathname(entry); @@ -897,6 +928,7 @@ zip_read_local_file_header(struct archive_read *a, struct archive_entry *entry, archive_strcat(&s, cp); archive_strappend_char(&s, '/'); archive_entry_set_pathname(entry, s.s); + archive_string_free(&s); } } } @@ -1136,11 +1168,18 @@ zip_read_data_none(struct archive_read *a, const void **_buff, || (zip->hctx_valid && zip->entry->aes_extra.vendor == AES_VENDOR_AE_2))) { if (zip->entry->flags & LA_USED_ZIP64) { + uint64_t compressed, uncompressed; zip->entry->crc32 = archive_le32dec(p + 4); - zip->entry->compressed_size = - archive_le64dec(p + 8); - zip->entry->uncompressed_size = - archive_le64dec(p + 16); + compressed = archive_le64dec(p + 8); + uncompressed = archive_le64dec(p + 16); + if (compressed > INT64_MAX || uncompressed > INT64_MAX) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Overflow of 64-bit file sizes"); + return ARCHIVE_FAILED; + } + zip->entry->compressed_size = compressed; + zip->entry->uncompressed_size = uncompressed; zip->unconsumed = 24; } else { zip->entry->crc32 = archive_le32dec(p + 4); @@ -1293,7 +1332,7 @@ zip_read_data_deflate(struct archive_read *a, const void **buff, && bytes_avail > zip->entry_bytes_remaining) { bytes_avail = (ssize_t)zip->entry_bytes_remaining; } - if (bytes_avail <= 0) { + if (bytes_avail < 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Truncated ZIP file body"); return (ARCHIVE_FATAL); @@ -1417,9 +1456,18 @@ zip_read_data_deflate(struct archive_read *a, const void **buff, zip->unconsumed = 4; } if (zip->entry->flags & LA_USED_ZIP64) { + uint64_t compressed, uncompressed; zip->entry->crc32 = archive_le32dec(p); - zip->entry->compressed_size = archive_le64dec(p + 4); - zip->entry->uncompressed_size = archive_le64dec(p + 12); + compressed = archive_le64dec(p + 4); + uncompressed = archive_le64dec(p + 12); + if (compressed > INT64_MAX || uncompressed > INT64_MAX) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Overflow of 64-bit file sizes"); + return ARCHIVE_FAILED; + } + zip->entry->compressed_size = compressed; + zip->entry->uncompressed_size = uncompressed; zip->unconsumed += 20; } else { zip->entry->crc32 = archive_le32dec(p); @@ -1500,7 +1548,7 @@ read_decryption_header(struct archive_read *a) case 0x6720:/* Blowfish */ case 0x6721:/* Twofish */ case 0x6801:/* RC4 */ - /* Suuported encryption algorithm. */ + /* Supported encryption algorithm. */ break; default: archive_set_error(&a->archive, @@ -1609,7 +1657,7 @@ read_decryption_header(struct archive_read *a) __archive_read_consume(a, 4); /*return (ARCHIVE_OK); - * This is not fully implemnted yet.*/ + * This is not fully implemented yet.*/ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Encrypted file is unsupported"); return (ARCHIVE_FAILED); @@ -1691,7 +1739,7 @@ init_traditional_PKWARE_decryption(struct archive_read *a) } /* - * Initialize ctx for Traditional PKWARE Decyption. + * Initialize ctx for Traditional PKWARE Decryption. */ r = trad_enc_init(&zip->tctx, passphrase, strlen(passphrase), p, ENC_HEADER_SIZE, &crcchk); @@ -2691,7 +2739,9 @@ slurp_central_directory(struct archive_read *a, struct zip *zip) "Truncated ZIP file header"); return ARCHIVE_FATAL; } - process_extra(p + filename_length, extra_length, zip_entry); + if (ARCHIVE_OK != process_extra(a, p + filename_length, extra_length, zip_entry)) { + return ARCHIVE_FATAL; + } /* * Mac resource fork files are stored under the diff --git a/Utilities/cmlibarchive/libarchive/archive_string.c b/Utilities/cmlibarchive/libarchive/archive_string.c index 282c58e..592ead2 100644 --- a/Utilities/cmlibarchive/libarchive/archive_string.c +++ b/Utilities/cmlibarchive/libarchive/archive_string.c @@ -219,6 +219,12 @@ archive_wstring_append(struct archive_wstring *as, const wchar_t *p, size_t s) return (as); } +struct archive_string * +archive_array_append(struct archive_string *as, const char *p, size_t s) +{ + return archive_string_append(as, p, s); +} + void archive_string_concat(struct archive_string *dest, struct archive_string *src) { @@ -559,7 +565,8 @@ archive_wstring_append_from_mbs_in_codepage(struct archive_wstring *dest, } if (count == 0 && length != 0) ret = -1; - } while (0); + break; + } while (1); } dest->length += count; dest->s[dest->length] = L'\0'; @@ -596,7 +603,7 @@ archive_wstring_append_from_mbs(struct archive_wstring *dest, wcs = dest->s + dest->length; /* * We cannot use mbsrtowcs/mbstowcs here because those may convert - * extra MBS when strlen(p) > len and one wide character consis of + * extra MBS when strlen(p) > len and one wide character consists of * multi bytes. */ while (*mbs && mbs_length > 0) { @@ -1247,7 +1254,7 @@ create_sconv_object(const char *fc, const char *tc, sc->cd = iconv_open(tc, fc); if (sc->cd == (iconv_t)-1 && (sc->flag & SCONV_BEST_EFFORT)) { /* - * Unfortunaly, all of iconv implements do support + * Unfortunately, all of iconv implements do support * "CP932" character-set, so we should use "SJIS" * instead if iconv_open failed. */ @@ -1260,7 +1267,7 @@ create_sconv_object(const char *fc, const char *tc, /* * archive_mstring on Windows directly convert multi-bytes * into archive_wstring in order not to depend on locale - * so that you can do a I18N programing. This will be + * so that you can do a I18N programming. This will be * used only in archive_mstring_copy_mbs_len_l so far. */ if (flag & SCONV_FROM_CHARSET) { @@ -1725,7 +1732,7 @@ archive_string_conversion_from_charset(struct archive *a, const char *charset, * in tar or zip files. But mbstowcs/wcstombs(CRT) usually use CP_ACP * unless you use setlocale(LC_ALL, ".OCP")(specify CP_OEMCP). * So we should make a string conversion between CP_ACP and CP_OEMCP - * for compatibillty. + * for compatibility. */ #if defined(_WIN32) && !defined(__CYGWIN__) struct archive_string_conv * @@ -1826,7 +1833,7 @@ archive_string_conversion_set_opt(struct archive_string_conv *sc, int opt) * A filename in UTF-8 was made with libarchive 2.x in a wrong * assumption that wchar_t was Unicode. * This option enables simulating the assumption in order to read - * that filname correctly. + * that filename correctly. */ case SCONV_SET_OPT_UTF8_LIBARCHIVE2X: #if (defined(_WIN32) && !defined(__CYGWIN__)) \ @@ -1938,12 +1945,19 @@ archive_strncat_l(struct archive_string *as, const void *_p, size_t n, struct archive_string_conv *sc) { const void *s; - size_t length; + size_t length = 0; int i, r = 0, r2; + if (_p != NULL && n > 0) { + if (sc != NULL && (sc->flag & SCONV_FROM_UTF16)) + length = utf16nbytes(_p, n); + else + length = mbsnbytes(_p, n); + } + /* We must allocate memory even if there is no data for conversion * or copy. This simulates archive_string_append behavior. */ - if (_p == NULL || n == 0) { + if (length == 0) { int tn = 1; if (sc != NULL && (sc->flag & SCONV_TO_UTF16)) tn = 2; @@ -1959,16 +1973,11 @@ archive_strncat_l(struct archive_string *as, const void *_p, size_t n, * If sc is NULL, we just make a copy. */ if (sc == NULL) { - length = mbsnbytes(_p, n); if (archive_string_append(as, _p, length) == NULL) return (-1);/* No memory */ return (0); } - if (sc->flag & SCONV_FROM_UTF16) - length = utf16nbytes(_p, n); - else - length = mbsnbytes(_p, n); s = _p; i = 0; if (sc->nconverter > 1) { @@ -1991,7 +2000,7 @@ archive_strncat_l(struct archive_string *as, const void *_p, size_t n, #if HAVE_ICONV /* - * Return -1 if conversion failes. + * Return -1 if conversion fails. */ static int iconv_strncat_in_locale(struct archive_string *as, const void *_p, @@ -2093,7 +2102,7 @@ iconv_strncat_in_locale(struct archive_string *as, const void *_p, /* * Translate a string from a some CodePage to an another CodePage by - * Windows APIs, and copy the result. Return -1 if conversion failes. + * Windows APIs, and copy the result. Return -1 if conversion fails. */ static int strncat_in_codepage(struct archive_string *as, @@ -2217,7 +2226,7 @@ best_effort_strncat_in_locale(struct archive_string *as, const void *_p, /* * If a character is ASCII, this just copies it. If not, this - * assigns '?' charater instead but in UTF-8 locale this assigns + * assigns '?' character instead but in UTF-8 locale this assigns * byte sequence 0xEF 0xBD 0xBD, which are code point U+FFFD, * a Replacement Character in Unicode. */ @@ -2297,7 +2306,7 @@ _utf8_to_unicode(uint32_t *pwc, const char *s, size_t n) return (0); /* Standard: return 0 for end-of-string. */ cnt = utf8_count[ch]; - /* Invalide sequence or there are not plenty bytes. */ + /* Invalid sequence or there are not plenty bytes. */ if ((int)n < cnt) { cnt = (int)n; for (i = 1; i < cnt; i++) { @@ -2378,7 +2387,7 @@ _utf8_to_unicode(uint32_t *pwc, const char *s, size_t n) goto invalid_sequence; } - /* The code point larger than 0x10FFFF is not leagal + /* The code point larger than 0x10FFFF is not legal * Unicode values. */ if (wc > UNICODE_MAX) goto invalid_sequence; @@ -2396,7 +2405,7 @@ utf8_to_unicode(uint32_t *pwc, const char *s, size_t n) int cnt; cnt = _utf8_to_unicode(pwc, s, n); - /* Any of Surrogate pair is not leagal Unicode values. */ + /* Any of Surrogate pair is not legal Unicode values. */ if (cnt == 3 && IS_SURROGATE_PAIR_LA(*pwc)) return (-3); return (cnt); @@ -2457,7 +2466,7 @@ invalid_sequence: /* * Convert a Unicode code point to a single UTF-8 sequence. * - * NOTE:This function does not check if the Unicode is leagal or not. + * NOTE:This function does not check if the Unicode is legal or not. * Please you definitely check it before calling this. */ static size_t @@ -2551,9 +2560,9 @@ utf16_to_unicode(uint32_t *pwc, const char *s, size_t n, int be) /* * Surrogate pair values(0xd800 through 0xdfff) are only - * used by UTF-16, so, after above culculation, the code + * used by UTF-16, so, after above calculation, the code * must not be surrogate values, and Unicode has no codes - * larger than 0x10ffff. Thus, those are not leagal Unicode + * larger than 0x10ffff. Thus, those are not legal Unicode * values. */ if (IS_SURROGATE_PAIR_LA(uc) || uc > UNICODE_MAX) { @@ -2900,7 +2909,7 @@ get_nfc(uint32_t uc, uint32_t uc2) /* * Normalize UTF-8/UTF-16BE characters to Form C and copy the result. * - * TODO: Convert composition exclusions,which are never converted + * TODO: Convert composition exclusions, which are never converted * from NFC,NFD,NFKC and NFKD, to Form C. */ static int @@ -3434,7 +3443,7 @@ strncat_from_utf8_libarchive2(struct archive_string *as, } /* - * As libarchie 2.x, translates the UTF-8 characters into + * As libarchive 2.x, translates the UTF-8 characters into * wide-characters in the assumption that WCS is Unicode. */ if (n < 0) { @@ -3473,7 +3482,7 @@ strncat_from_utf8_libarchive2(struct archive_string *as, /* * Convert a UTF-16BE/LE string to current locale and copy the result. - * Return -1 if conversion failes. + * Return -1 if conversion fails. */ static int win_strncat_from_utf16(struct archive_string *as, const void *_p, size_t bytes, @@ -3552,18 +3561,19 @@ win_strncat_from_utf16(struct archive_string *as, const void *_p, size_t bytes, ll = WideCharToMultiByte(sc->to_cp, 0, (LPCWSTR)u16, (int)bytes>>1, mbs, (int)mbs_size, NULL, &defchar); - if (ll == 0 && - GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - /* Need more buffer for MBS. */ - ll = WideCharToMultiByte(sc->to_cp, 0, - (LPCWSTR)u16, (int)bytes, NULL, 0, NULL, NULL); - if (archive_string_ensure(as, ll +1) == NULL) - return (-1); - mbs = as->s + as->length; - mbs_size = as->buffer_length - as->length -1; - continue; + /* Exit loop if we succeeded */ + if (ll != 0 || + GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + break; } - } while (0); + /* Else expand buffer and loop to try again. */ + ll = WideCharToMultiByte(sc->to_cp, 0, + (LPCWSTR)u16, (int)bytes, NULL, 0, NULL, NULL); + if (archive_string_ensure(as, ll +1) == NULL) + return (-1); + mbs = as->s + as->length; + mbs_size = as->buffer_length - as->length -1; + } while (1); archive_string_free(&tmp); as->length += ll; as->s[as->length] = '\0'; @@ -3596,7 +3606,7 @@ is_big_endian(void) /* * Convert a current locale string to UTF-16BE/LE and copy the result. - * Return -1 if conversion failes. + * Return -1 if conversion fails. */ static int win_strncat_to_utf16(struct archive_string *as16, const void *_p, @@ -3634,19 +3644,20 @@ win_strncat_to_utf16(struct archive_string *as16, const void *_p, do { count = MultiByteToWideChar(sc->from_cp, MB_PRECOMPOSED, s, (int)length, (LPWSTR)u16, (int)avail>>1); - if (count == 0 && - GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - /* Need more buffer for UTF-16 string */ - count = MultiByteToWideChar(sc->from_cp, - MB_PRECOMPOSED, s, (int)length, NULL, 0); - if (archive_string_ensure(as16, (count +1) * 2) - == NULL) - return (-1); - u16 = as16->s + as16->length; - avail = as16->buffer_length - 2; - continue; + /* Exit loop if we succeeded */ + if (count != 0 || + GetLastError() != ERROR_INSUFFICIENT_BUFFER) { + break; } - } while (0); + /* Expand buffer and try again */ + count = MultiByteToWideChar(sc->from_cp, + MB_PRECOMPOSED, s, (int)length, NULL, 0); + if (archive_string_ensure(as16, (count +1) * 2) + == NULL) + return (-1); + u16 = as16->s + as16->length; + avail = as16->buffer_length - 2; + } while (1); as16->length += count * 2; as16->s[as16->length] = 0; as16->s[as16->length+1] = 0; @@ -3700,7 +3711,7 @@ win_strncat_to_utf16le(struct archive_string *as16, const void *_p, /* * Convert a UTF-16BE string to current locale and copy the result. - * Return -1 if conversion failes. + * Return -1 if conversion fails. */ static int best_effort_strncat_from_utf16(struct archive_string *as, const void *_p, @@ -3758,7 +3769,7 @@ best_effort_strncat_from_utf16le(struct archive_string *as, const void *_p, /* * Convert a current locale string to UTF-16BE/LE and copy the result. - * Return -1 if conversion failes. + * Return -1 if conversion fails. */ static int best_effort_strncat_to_utf16(struct archive_string *as16, const void *_p, @@ -3942,7 +3953,7 @@ archive_mstring_get_mbs_l(struct archive_mstring *aes, #if defined(_WIN32) && !defined(__CYGWIN__) /* - * Internationalization programing on Windows must use Wide + * Internationalization programming on Windows must use Wide * characters because Windows platform cannot make locale UTF-8. */ if (sc != NULL && (aes->aes_set & AES_SET_WCS) != 0) { @@ -4074,7 +4085,7 @@ archive_mstring_copy_mbs_len_l(struct archive_mstring *aes, archive_string_empty(&(aes->aes_utf8)); #if defined(_WIN32) && !defined(__CYGWIN__) /* - * Internationalization programing on Windows must use Wide + * Internationalization programming on Windows must use Wide * characters because Windows platform cannot make locale UTF-8. */ if (sc == NULL) { diff --git a/Utilities/cmlibarchive/libarchive/archive_string.h b/Utilities/cmlibarchive/libarchive/archive_string.h index 23f4916..56dfbb2 100644 --- a/Utilities/cmlibarchive/libarchive/archive_string.h +++ b/Utilities/cmlibarchive/libarchive/archive_string.h @@ -81,6 +81,10 @@ archive_strappend_char(struct archive_string *, char); struct archive_wstring * archive_wstrappend_wchar(struct archive_wstring *, wchar_t); +/* Append a raw array to an archive_string, resizing as necessary */ +struct archive_string * +archive_array_append(struct archive_string *, const char *, size_t); + /* Convert a Unicode string to current locale and append the result. */ /* Returns -1 if conversion fails. */ int @@ -115,13 +119,13 @@ archive_string_conversion_set_opt(struct archive_string_conv *, int); /* Copy one archive_string to another in locale conversion. - * Return -1 if conversion failes. */ + * Return -1 if conversion fails. */ int archive_strncpy_l(struct archive_string *, const void *, size_t, struct archive_string_conv *); /* Copy one archive_string to another in locale conversion. - * Return -1 if conversion failes. */ + * Return -1 if conversion fails. */ int archive_strncat_l(struct archive_string *, const void *, size_t, struct archive_string_conv *); diff --git a/Utilities/cmlibarchive/libarchive/archive_string_composition.h b/Utilities/cmlibarchive/libarchive/archive_string_composition.h index be41e33..8902ac1 100644 --- a/Utilities/cmlibarchive/libarchive/archive_string_composition.h +++ b/Utilities/cmlibarchive/libarchive/archive_string_composition.h @@ -1009,7 +1009,7 @@ static const char u_decomposable_blocks[0x1D2+1] = { (((uc) > 0x1D244)?0:\ ccc_val[ccc_val_index[ccc_index[(uc)>>8]][((uc)>>4)&0x0F]][(uc)&0x0F]) -/* The table of the value of Canonical Cimbining Class */ +/* The table of the value of Canonical Combining Class */ static const unsigned char ccc_val[][16] = { /* idx=0: XXXX0 - XXXXF */ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, diff --git a/Utilities/cmlibarchive/libarchive/archive_util.c b/Utilities/cmlibarchive/libarchive/archive_util.c index f89df1d..f56ca33 100644 --- a/Utilities/cmlibarchive/libarchive/archive_util.c +++ b/Utilities/cmlibarchive/libarchive/archive_util.c @@ -580,7 +580,7 @@ void __archive_ensure_cloexec_flag(int fd) { #if defined(_WIN32) && !defined(__CYGWIN__) - (void)fd; /* UNSED */ + (void)fd; /* UNUSED */ #else int flags; diff --git a/Utilities/cmlibarchive/libarchive/archive_windows.c b/Utilities/cmlibarchive/libarchive/archive_windows.c index d4e93fe..6ff8749 100644 --- a/Utilities/cmlibarchive/libarchive/archive_windows.c +++ b/Utilities/cmlibarchive/libarchive/archive_windows.c @@ -766,7 +766,7 @@ __la_win_entry_in_posix_pathseparator(struct archive_entry *entry) has_backslash = 1; } /* - * If there is no backslach chars, return the original. + * If there is no backslash chars, return the original. */ if (!has_backslash) return (entry); @@ -891,7 +891,7 @@ __la_dosmaperr(unsigned long e) return; } - for (i = 0; i < (int)sizeof(doserrors); i++) + for (i = 0; i < (int)(sizeof(doserrors)/sizeof(doserrors[0])); i++) { if (doserrors[i].winerr == e) { diff --git a/Utilities/cmlibarchive/libarchive/archive_windows.h b/Utilities/cmlibarchive/libarchive/archive_windows.h index 7c31a16..c3aed0c 100644 --- a/Utilities/cmlibarchive/libarchive/archive_windows.h +++ b/Utilities/cmlibarchive/libarchive/archive_windows.h @@ -224,16 +224,20 @@ #define S_IWUSR _S_IWUSR #define S_IRUSR _S_IRUSR #endif +#ifndef S_IRWXG #define S_IRWXG _S_IRWXG #define S_IXGRP _S_IXGRP #define S_IWGRP _S_IWGRP +#endif #ifndef S_IRGRP #define S_IRGRP _S_IRGRP #endif +#ifndef S_IRWXO #define S_IRWXO _S_IRWXO #define S_IXOTH _S_IXOTH #define S_IWOTH _S_IWOTH #define S_IROTH _S_IROTH +#endif #endif diff --git a/Utilities/cmlibarchive/libarchive/archive_write.c b/Utilities/cmlibarchive/libarchive/archive_write.c index e3fa335..0634a22 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write.c +++ b/Utilities/cmlibarchive/libarchive/archive_write.c @@ -109,10 +109,9 @@ archive_write_new(void) struct archive_write *a; unsigned char *nulls; - a = (struct archive_write *)malloc(sizeof(*a)); + a = (struct archive_write *)calloc(1, sizeof(*a)); if (a == NULL) return (NULL); - memset(a, 0, sizeof(*a)); a->archive.magic = ARCHIVE_WRITE_MAGIC; a->archive.state = ARCHIVE_STATE_NEW; a->archive.vtable = archive_write_vtable(); @@ -126,12 +125,11 @@ archive_write_new(void) /* Initialize a block of nulls for padding purposes. */ a->null_length = 1024; - nulls = (unsigned char *)malloc(a->null_length); + nulls = (unsigned char *)calloc(1, a->null_length); if (nulls == NULL) { free(a); return (NULL); } - memset(nulls, 0, a->null_length); a->nulls = nulls; return (&a->archive); } @@ -233,7 +231,7 @@ __archive_write_filter(struct archive_write_filter *f, if (length == 0) return(ARCHIVE_OK); if (f->write == NULL) - /* If unset, a fatal error has already ocuured, so this filter + /* If unset, a fatal error has already occurred, so this filter * didn't open. We cannot write anything. */ return(ARCHIVE_FATAL); r = (f->write)(f, buff, length); diff --git a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_lz4.c b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_lz4.c index 1d0ab8c..e655185 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_lz4.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_lz4.c @@ -523,7 +523,7 @@ drive_compressor_independence(struct archive_write_filter *f, const char *p, archive_le32enc(data->out, outsize); data->out += 4; } else { - /* The buffer is not compressed. The commpressed size was + /* The buffer is not compressed. The compressed size was * bigger than its uncompressed size. */ archive_le32enc(data->out, length | 0x80000000); data->out += 4; @@ -608,7 +608,7 @@ drive_compressor_dependence(struct archive_write_filter *f, const char *p, archive_le32enc(data->out, outsize); data->out += 4; } else { - /* The buffer is not compressed. The commpressed size was + /* The buffer is not compressed. The compressed size was * bigger than its uncompressed size. */ archive_le32enc(data->out, length | 0x80000000); data->out += 4; diff --git a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_program.c b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_program.c index 31a1b6f..55b5e8e 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_program.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_program.c @@ -200,6 +200,7 @@ __archive_write_program_free(struct archive_write_program_data *data) if (data->child) CloseHandle(data->child); #endif + free(data->program_name); free(data->child_buf); free(data); } diff --git a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_xz.c b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_xz.c index 4f849ce..e4a3535 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_add_filter_xz.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_add_filter_xz.c @@ -233,7 +233,7 @@ archive_compressor_xz_init_stream(struct archive_write_filter *f, if (f->code == ARCHIVE_FILTER_XZ) { #ifdef HAVE_LZMA_STREAM_ENCODER_MT if (data->threads != 1) { - bzero(&mt_options, sizeof(mt_options)); + memset(&mt_options, 0, sizeof(mt_options)); mt_options.threads = data->threads; mt_options.timeout = 300; mt_options.filters = data->lzmafilters; diff --git a/Utilities/cmlibarchive/libarchive/archive_write_disk_acl.c b/Utilities/cmlibarchive/libarchive/archive_write_disk_acl.c index 5cbba54..144ab7e 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_disk_acl.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_disk_acl.c @@ -34,6 +34,9 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_disk.c 201159 2009-12-29 0 #define _ACL_PRIVATE /* For debugging */ #include <sys/acl.h> #endif +#if HAVE_DARWIN_ACL +#include <membership.h> +#endif #ifdef HAVE_ERRNO_H #include <errno.h> #endif @@ -43,7 +46,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_write_disk.c 201159 2009-12-29 0 #include "archive_acl_private.h" #include "archive_write_disk_private.h" -#ifndef HAVE_POSIX_ACL +#if !HAVE_POSIX_ACL && !HAVE_NFS4_ACL /* Default empty function body to satisfy mainline code. */ int archive_write_disk_set_acls(struct archive *a, int fd, const char *name, @@ -56,47 +59,111 @@ archive_write_disk_set_acls(struct archive *a, int fd, const char *name, return (ARCHIVE_OK); } -#else +#else /* HAVE_POSIX_ACL || HAVE_NFS4_ACL */ + +#if HAVE_SUN_ACL +#define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACE_T +#elif HAVE_DARWIN_ACL +#define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACL_TYPE_EXTENDED +#elif HAVE_ACL_TYPE_NFS4 +#define ARCHIVE_PLATFORM_ACL_TYPE_NFS4 ACL_TYPE_NFS4 +#endif static int set_acl(struct archive *, int fd, const char *, struct archive_acl *, acl_type_t, int archive_entry_acl_type, const char *tn); -/* - * XXX TODO: What about ACL types other than ACCESS and DEFAULT? - */ int archive_write_disk_set_acls(struct archive *a, int fd, const char *name, struct archive_acl *abstract_acl) { - int ret; + int ret = ARCHIVE_OK; - if (archive_acl_count(abstract_acl, ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) > 0) { - ret = set_acl(a, fd, name, abstract_acl, ACL_TYPE_ACCESS, - ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access"); - if (ret != ARCHIVE_OK) - return (ret); - ret = set_acl(a, fd, name, abstract_acl, ACL_TYPE_DEFAULT, - ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default"); +#if !HAVE_DARWIN_ACL + if ((archive_acl_types(abstract_acl) + & ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0) { +#if HAVE_SUN_ACL + /* Solaris writes POSIX.1e access and default ACLs together */ + ret = set_acl(a, fd, name, abstract_acl, ACLENT_T, + ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, "posix1e"); +#else /* HAVE_POSIX_ACL */ + if ((archive_acl_types(abstract_acl) + & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) { + ret = set_acl(a, fd, name, abstract_acl, + ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, + "access"); + if (ret != ARCHIVE_OK) + return (ret); + } + if ((archive_acl_types(abstract_acl) + & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) + ret = set_acl(a, fd, name, abstract_acl, + ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, + "default"); +#endif /* !HAVE_SUN_ACL */ + /* Simultaneous POSIX.1e and NFSv4 is not supported */ return (ret); -#ifdef ACL_TYPE_NFS4 - } else if (archive_acl_count(abstract_acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4) > 0) { - ret = set_acl(a, fd, name, abstract_acl, ACL_TYPE_NFS4, + } +#endif /* !HAVE_DARWIN_ACL */ +#if HAVE_NFS4_ACL + if ((archive_acl_types(abstract_acl) & + ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { + ret = set_acl(a, fd, name, abstract_acl, + ARCHIVE_PLATFORM_ACL_TYPE_NFS4, ARCHIVE_ENTRY_ACL_TYPE_NFS4, "nfs4"); - return (ret); -#endif - } else - return ARCHIVE_OK; + } +#endif /* HAVE_NFS4_ACL */ + return (ret); } -static struct { - int archive_perm; - int platform_perm; +/* + * Translate system ACL permissions into libarchive internal structure + */ +static const struct { + const int archive_perm; + const int platform_perm; } acl_perm_map[] = { +#if HAVE_SUN_ACL /* Solaris NFSv4 ACL permissions */ + {ARCHIVE_ENTRY_ACL_EXECUTE, ACE_EXECUTE}, + {ARCHIVE_ENTRY_ACL_READ_DATA, ACE_READ_DATA}, + {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACE_LIST_DIRECTORY}, + {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACE_WRITE_DATA}, + {ARCHIVE_ENTRY_ACL_ADD_FILE, ACE_ADD_FILE}, + {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACE_APPEND_DATA}, + {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACE_ADD_SUBDIRECTORY}, + {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACE_READ_NAMED_ATTRS}, + {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACE_WRITE_NAMED_ATTRS}, + {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACE_DELETE_CHILD}, + {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACE_READ_ATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACE_WRITE_ATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_DELETE, ACE_DELETE}, + {ARCHIVE_ENTRY_ACL_READ_ACL, ACE_READ_ACL}, + {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACE_WRITE_ACL}, + {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACE_WRITE_OWNER}, + {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACE_SYNCHRONIZE} +#elif HAVE_DARWIN_ACL /* MacOS ACL permissions */ + {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA}, + {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY}, + {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA}, + {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE}, + {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE}, + {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE}, + {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA}, + {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY}, + {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD}, + {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_EXTATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_EXTATTRIBUTES}, + {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_SECURITY}, + {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_SECURITY}, + {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_CHANGE_OWNER}, + {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE} +#else /* POSIX.1e ACL permissions */ {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE}, {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE}, {ARCHIVE_ENTRY_ACL_READ, ACL_READ}, -#ifdef ACL_TYPE_NFS4 +#if HAVE_ACL_TYPE_NFS4 /* FreeBSD NFSv4 ACL permissions */ {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA}, {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY}, {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA}, @@ -114,33 +181,69 @@ static struct { {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER}, {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE} #endif +#endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */ }; -#ifdef ACL_TYPE_NFS4 -static struct { - int archive_inherit; - int platform_inherit; +#if HAVE_NFS4_ACL +/* + * Translate system NFSv4 inheritance flags into libarchive internal structure + */ +static const struct { + const int archive_inherit; + const int platform_inherit; } acl_inherit_map[] = { +#if HAVE_SUN_ACL /* Solaris NFSv4 inheritance flags */ + {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACE_FILE_INHERIT_ACE}, + {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACE_DIRECTORY_INHERIT_ACE}, + {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACE_NO_PROPAGATE_INHERIT_ACE}, + {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACE_INHERIT_ONLY_ACE}, + {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACE_SUCCESSFUL_ACCESS_ACE_FLAG}, + {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACE_FAILED_ACCESS_ACE_FLAG}, + {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACE_INHERITED_ACE} +#elif HAVE_DARWIN_ACL /* MacOS NFSv4 inheritance flags */ + {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED}, + {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT}, + {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT}, + {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_LIMIT_INHERIT}, + {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_ONLY_INHERIT} +#else /* FreeBSD NFSv4 ACL inheritance flags */ {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT}, {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT}, {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT}, - {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY} + {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY}, + {ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, ACL_ENTRY_SUCCESSFUL_ACCESS}, + {ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, ACL_ENTRY_FAILED_ACCESS}, + {ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, ACL_ENTRY_INHERITED} +#endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */ }; -#endif +#endif /* HAVE_NFS4_ACL */ static int set_acl(struct archive *a, int fd, const char *name, struct archive_acl *abstract_acl, acl_type_t acl_type, int ae_requested_type, const char *tname) { +#if HAVE_SUN_ACL + aclent_t *aclent; + ace_t *ace; + int e, r; + acl_t *acl; +#else acl_t acl; acl_entry_t acl_entry; acl_permset_t acl_permset; -#ifdef ACL_TYPE_NFS4 +#if HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL acl_flagset_t acl_flagset; #endif +#endif /* HAVE_SUN_ACL */ +#if HAVE_ACL_TYPE_NFS4 + int r; +#endif int ret; int ae_type, ae_permset, ae_tag, ae_id; +#if HAVE_DARWIN_ACL + uuid_t ae_uuid; +#endif uid_t ae_uid; gid_t ae_gid; const char *ae_name; @@ -151,22 +254,165 @@ set_acl(struct archive *a, int fd, const char *name, entries = archive_acl_reset(abstract_acl, ae_requested_type); if (entries == 0) return (ARCHIVE_OK); + +#if HAVE_SUN_ACL + acl = NULL; + acl = malloc(sizeof(acl_t)); + if (acl == NULL) { + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "Invalid ACL type"); + return (ARCHIVE_FAILED); + } + if (acl_type == ACE_T) + acl->acl_entry_size = sizeof(ace_t); + else if (acl_type == ACLENT_T) + acl->acl_entry_size = sizeof(aclent_t); + else { + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "Invalid ACL type"); + acl_free(acl); + return (ARCHIVE_FAILED); + } + acl->acl_type = acl_type; + acl->acl_cnt = entries; + + acl->acl_aclp = malloc(entries * acl->acl_entry_size); + if (acl->acl_aclp == NULL) { + archive_set_error(a, errno, + "Can't allocate memory for acl buffer"); + acl_free(acl); + return (ARCHIVE_FAILED); + } +#else /* !HAVE_SUN_ACL */ acl = acl_init(entries); + if (acl == (acl_t)NULL) { + archive_set_error(a, errno, + "Failed to initialize ACL working storage"); + return (ARCHIVE_FAILED); + } +#endif /* !HAVE_SUN_ACL */ +#if HAVE_SUN_ACL + e = 0; +#endif while (archive_acl_next(a, abstract_acl, ae_requested_type, &ae_type, &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) { - acl_create_entry(&acl, &acl_entry); - +#if HAVE_SUN_ACL + ace = NULL; + aclent = NULL; + if (acl->acl_type == ACE_T) { + ace = &((ace_t *)acl->acl_aclp)[e]; + ace->a_who = -1; + ace->a_access_mask = 0; + ace->a_flags = 0; + } else { + aclent = &((aclent_t *)acl->acl_aclp)[e]; + aclent->a_id = -1; + aclent->a_type = 0; + aclent->a_perm = 0; + } +#else /* !HAVE_SUN_ACL */ +#if HAVE_DARWIN_ACL + /* + * Mac OS doesn't support NFSv4 ACLs for + * owner@, group@ and everyone@. + * We skip any of these ACLs found. + */ + if (ae_tag == ARCHIVE_ENTRY_ACL_USER_OBJ || + ae_tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ || + ae_tag == ARCHIVE_ENTRY_ACL_EVERYONE) + continue; +#endif + if (acl_create_entry(&acl, &acl_entry) != 0) { + archive_set_error(a, errno, + "Failed to create a new ACL entry"); + ret = ARCHIVE_FAILED; + goto exit_free; + } +#endif /* !HAVE_SUN_ACL */ +#if HAVE_DARWIN_ACL + switch (ae_type) { + case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: + acl_set_tag_type(acl_entry, ACL_EXTENDED_ALLOW); + break; + case ARCHIVE_ENTRY_ACL_TYPE_DENY: + acl_set_tag_type(acl_entry, ACL_EXTENDED_DENY); + break; + default: + /* We don't support any other types on MacOS */ + continue; + } +#endif switch (ae_tag) { +#if HAVE_SUN_ACL + case ARCHIVE_ENTRY_ACL_USER: + ae_uid = archive_write_disk_uid(a, ae_name, ae_id); + if (acl->acl_type == ACE_T) + ace->a_who = ae_uid; + else { + aclent->a_id = ae_uid; + aclent->a_type |= USER; + } + break; + case ARCHIVE_ENTRY_ACL_GROUP: + ae_gid = archive_write_disk_gid(a, ae_name, ae_id); + if (acl->acl_type == ACE_T) { + ace->a_who = ae_gid; + ace->a_flags |= ACE_IDENTIFIER_GROUP; + } else { + aclent->a_id = ae_gid; + aclent->a_type |= GROUP; + } + break; + case ARCHIVE_ENTRY_ACL_USER_OBJ: + if (acl->acl_type == ACE_T) + ace->a_flags |= ACE_OWNER; + else + aclent->a_type |= USER_OBJ; + break; + case ARCHIVE_ENTRY_ACL_GROUP_OBJ: + if (acl->acl_type == ACE_T) { + ace->a_flags |= ACE_GROUP; + ace->a_flags |= ACE_IDENTIFIER_GROUP; + } else + aclent->a_type |= GROUP_OBJ; + break; + case ARCHIVE_ENTRY_ACL_MASK: + aclent->a_type |= CLASS_OBJ; + break; + case ARCHIVE_ENTRY_ACL_OTHER: + aclent->a_type |= OTHER_OBJ; + break; + case ARCHIVE_ENTRY_ACL_EVERYONE: + ace->a_flags |= ACE_EVERYONE; + break; +#else /* !HAVE_SUN_ACL */ case ARCHIVE_ENTRY_ACL_USER: - acl_set_tag_type(acl_entry, ACL_USER); ae_uid = archive_write_disk_uid(a, ae_name, ae_id); +#if !HAVE_DARWIN_ACL /* FreeBSD, Linux */ + acl_set_tag_type(acl_entry, ACL_USER); acl_set_qualifier(acl_entry, &ae_uid); +#else /* MacOS */ + if (mbr_identifier_to_uuid(ID_TYPE_UID, &ae_uid, + sizeof(uid_t), ae_uuid) != 0) + continue; + if (acl_set_qualifier(acl_entry, &ae_uuid) != 0) + continue; +#endif /* HAVE_DARWIN_ACL */ break; case ARCHIVE_ENTRY_ACL_GROUP: - acl_set_tag_type(acl_entry, ACL_GROUP); ae_gid = archive_write_disk_gid(a, ae_name, ae_id); +#if !HAVE_DARWIN_ACL /* FreeBSD, Linux */ + acl_set_tag_type(acl_entry, ACL_GROUP); acl_set_qualifier(acl_entry, &ae_gid); +#else /* MacOS */ + if (mbr_identifier_to_uuid(ID_TYPE_GID, &ae_gid, + sizeof(gid_t), ae_uuid) != 0) + continue; + if (acl_set_qualifier(acl_entry, &ae_uuid) != 0) + continue; +#endif /* HAVE_DARWIN_ACL */ break; +#if !HAVE_DARWIN_ACL /* FreeBSD, Linux */ case ARCHIVE_ENTRY_ACL_USER_OBJ: acl_set_tag_type(acl_entry, ACL_USER_OBJ); break; @@ -179,85 +425,230 @@ set_acl(struct archive *a, int fd, const char *name, case ARCHIVE_ENTRY_ACL_OTHER: acl_set_tag_type(acl_entry, ACL_OTHER); break; -#ifdef ACL_TYPE_NFS4 +#if HAVE_ACL_TYPE_NFS4 /* FreeBSD only */ case ARCHIVE_ENTRY_ACL_EVERYONE: acl_set_tag_type(acl_entry, ACL_EVERYONE); break; #endif +#endif /* !HAVE_DARWIN_ACL */ +#endif /* !HAVE_SUN_ACL */ default: - /* XXX */ - break; + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "Unknown ACL tag"); + ret = ARCHIVE_FAILED; + goto exit_free; } -#ifdef ACL_TYPE_NFS4 +#if HAVE_ACL_TYPE_NFS4 || HAVE_SUN_ACL + r = 0; switch (ae_type) { +#if HAVE_SUN_ACL + case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: + if (ace != NULL) + ace->a_type = ACE_ACCESS_ALLOWED_ACE_TYPE; + else + r = -1; + break; + case ARCHIVE_ENTRY_ACL_TYPE_DENY: + if (ace != NULL) + ace->a_type = ACE_ACCESS_DENIED_ACE_TYPE; + else + r = -1; + break; + case ARCHIVE_ENTRY_ACL_TYPE_AUDIT: + if (ace != NULL) + ace->a_type = ACE_SYSTEM_AUDIT_ACE_TYPE; + else + r = -1; + break; + case ARCHIVE_ENTRY_ACL_TYPE_ALARM: + if (ace != NULL) + ace->a_type = ACE_SYSTEM_ALARM_ACE_TYPE; + else + r = -1; + break; + case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: + if (aclent == NULL) + r = -1; + break; + case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: + if (aclent != NULL) + aclent->a_type |= ACL_DEFAULT; + else + r = -1; + break; +#else /* !HAVE_SUN_ACL */ case ARCHIVE_ENTRY_ACL_TYPE_ALLOW: - acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALLOW); + r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALLOW); break; case ARCHIVE_ENTRY_ACL_TYPE_DENY: - acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_DENY); + r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_DENY); break; case ARCHIVE_ENTRY_ACL_TYPE_AUDIT: - acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_AUDIT); + r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_AUDIT); break; case ARCHIVE_ENTRY_ACL_TYPE_ALARM: - acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALARM); + r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALARM); break; case ARCHIVE_ENTRY_ACL_TYPE_ACCESS: case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: // These don't translate directly into the system ACL. break; +#endif /* !HAVE_SUN_ACL */ default: - // XXX error handling here. - break; + archive_set_error(a, ARCHIVE_ERRNO_MISC, + "Unknown ACL entry type"); + ret = ARCHIVE_FAILED; + goto exit_free; } -#endif - acl_get_permset(acl_entry, &acl_permset); - acl_clear_perms(acl_permset); + if (r != 0) { +#if HAVE_SUN_ACL + errno = EINVAL; +#endif + archive_set_error(a, errno, + "Failed to set ACL entry type"); + ret = ARCHIVE_FAILED; + goto exit_free; + } +#endif /* HAVE_ACL_TYPE_NFS4 || HAVE_SUN_ACL */ +#if HAVE_SUN_ACL + if (acl->acl_type == ACLENT_T) { + if (ae_permset & ARCHIVE_ENTRY_ACL_EXECUTE) + aclent->a_perm |= 1; + if (ae_permset & ARCHIVE_ENTRY_ACL_WRITE) + aclent->a_perm |= 2; + if (ae_permset & ARCHIVE_ENTRY_ACL_READ) + aclent->a_perm |= 4; + } else +#else + if (acl_get_permset(acl_entry, &acl_permset) != 0) { + archive_set_error(a, errno, + "Failed to get ACL permission set"); + ret = ARCHIVE_FAILED; + goto exit_free; + } + if (acl_clear_perms(acl_permset) != 0) { + archive_set_error(a, errno, + "Failed to clear ACL permissions"); + ret = ARCHIVE_FAILED; + goto exit_free; + } +#endif /* !HAVE_SUN_ACL */ for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) { - if (ae_permset & acl_perm_map[i].archive_perm) - acl_add_perm(acl_permset, - acl_perm_map[i].platform_perm); + if (ae_permset & acl_perm_map[i].archive_perm) { +#if HAVE_SUN_ACL + ace->a_access_mask |= + acl_perm_map[i].platform_perm; +#else + if (acl_add_perm(acl_permset, + acl_perm_map[i].platform_perm) != 0) { + archive_set_error(a, errno, + "Failed to add ACL permission"); + ret = ARCHIVE_FAILED; + goto exit_free; + } +#endif + } } -#ifdef ACL_TYPE_NFS4 - acl_get_flagset_np(acl_entry, &acl_flagset); - acl_clear_flags_np(acl_flagset); - for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) { - if (ae_permset & acl_inherit_map[i].archive_inherit) - acl_add_flag_np(acl_flagset, - acl_inherit_map[i].platform_inherit); +#if HAVE_NFS4_ACL +#if HAVE_SUN_ACL + if (acl_type == ACE_T) +#elif HAVE_DARWIN_ACL + if (acl_type == ACL_TYPE_EXTENDED) +#else /* FreeBSD */ + if (acl_type == ACL_TYPE_NFS4) +#endif + { +#if HAVE_POSIX_ACL || HAVE_DARWIN_ACL + /* + * acl_get_flagset_np() fails with non-NFSv4 ACLs + */ + if (acl_get_flagset_np(acl_entry, &acl_flagset) != 0) { + archive_set_error(a, errno, + "Failed to get flagset from an NFSv4 ACL entry"); + ret = ARCHIVE_FAILED; + goto exit_free; + } + if (acl_clear_flags_np(acl_flagset) != 0) { + archive_set_error(a, errno, + "Failed to clear flags from an NFSv4 ACL flagset"); + ret = ARCHIVE_FAILED; + goto exit_free; + } +#endif /* HAVE_POSIX_ACL || HAVE_DARWIN_ACL */ + for (i = 0; i < (int)(sizeof(acl_inherit_map) /sizeof(acl_inherit_map[0])); ++i) { + if (ae_permset & acl_inherit_map[i].archive_inherit) { +#if HAVE_SUN_ACL + ace->a_flags |= + acl_inherit_map[i].platform_inherit; +#else /* !HAVE_SUN_ACL */ + if (acl_add_flag_np(acl_flagset, + acl_inherit_map[i].platform_inherit) != 0) { + archive_set_error(a, errno, + "Failed to add flag to NFSv4 ACL flagset"); + ret = ARCHIVE_FAILED; + goto exit_free; + } +#endif /* HAVE_SUN_ACL */ + } + } } +#endif /* HAVE_NFS4_ACL */ +#if HAVE_SUN_ACL + e++; #endif } +#if HAVE_ACL_SET_FD_NP || HAVE_ACL_SET_FD || HAVE_SUN_ACL /* Try restoring the ACL through 'fd' if we can. */ -#if HAVE_ACL_SET_FD - if (fd >= 0 && acl_type == ACL_TYPE_ACCESS && acl_set_fd(fd, acl) == 0) - ret = ARCHIVE_OK; - else -#else -#if HAVE_ACL_SET_FD_NP - if (fd >= 0 && acl_set_fd_np(fd, acl, acl_type) == 0) - ret = ARCHIVE_OK; - else +#if HAVE_SUN_ACL || HAVE_ACL_SET_FD_NP + if (fd >= 0) +#else /* !HAVE_SUN_ACL && !HAVE_ACL_SET_FD_NP */ + if (fd >= 0 && acl_type == ACL_TYPE_ACCESS) #endif + { +#if HAVE_SUN_ACL + if (facl_set(fd, acl) == 0) +#elif HAVE_ACL_SET_FD_NP + if (acl_set_fd_np(fd, acl, acl_type) == 0) +#else /* !HAVE_SUN_ACL && !HAVE_ACL_SET_FD_NP */ + if (acl_set_fd(fd, acl) == 0) #endif -#if HAVE_ACL_SET_LINK_NP - if (acl_set_link_np(name, acl_type, acl) != 0) { - archive_set_error(a, errno, "Failed to set %s acl", tname); - ret = ARCHIVE_WARN; - } + ret = ARCHIVE_OK; + else { + if (errno == EOPNOTSUPP) { + /* Filesystem doesn't support ACLs */ + ret = ARCHIVE_OK; + } else { + archive_set_error(a, errno, + "Failed to set %s acl on fd", tname); + } + } + } else +#endif /* HAVE_ACL_SET_FD_NP || HAVE_ACL_SET_FD || HAVE_SUN_ACL */ +#if HAVE_SUN_ACL + if (acl_set(name, acl) != 0) +#elif HAVE_ACL_SET_LINK_NP + if (acl_set_link_np(name, acl_type, acl) != 0) #else /* TODO: Skip this if 'name' is a symlink. */ - if (acl_set_file(name, acl_type, acl) != 0) { - archive_set_error(a, errno, "Failed to set %s acl", tname); - ret = ARCHIVE_WARN; - } + if (acl_set_file(name, acl_type, acl) != 0) #endif + { + if (errno == EOPNOTSUPP) { + /* Filesystem doesn't support ACLs */ + ret = ARCHIVE_OK; + } else { + archive_set_error(a, errno, "Failed to set %s acl", + tname); + ret = ARCHIVE_WARN; + } + } +exit_free: acl_free(acl); return (ret); } -#endif +#endif /* HAVE_POSIX_ACL || HAVE_NFS4_ACL */ diff --git a/Utilities/cmlibarchive/libarchive/archive_write_disk_posix.c b/Utilities/cmlibarchive/libarchive/archive_write_disk_posix.c index 5946683..53629ac 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_disk_posix.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_disk_posix.c @@ -110,6 +110,18 @@ __FBSDID("$FreeBSD$"); #include <sys/fcntl1.h> #endif +/* + * Macro to cast st_mtime and time_t to an int64 so that 2 numbers can reliably be compared. + * + * It assumes that the input is an integer type of no more than 64 bits. + * If the number is less than zero, t must be a signed type, so it fits in + * int64_t. Otherwise, it's a nonnegative value so we can cast it to uint64_t + * without loss. But it could be a large unsigned value, so we have to clip it + * to INT64_MAX.* + */ +#define to_int64_time(t) \ + ((t) < 0 ? (int64_t)(t) : (uint64_t)(t) > (uint64_t)INT64_MAX ? INT64_MAX : (int64_t)(t)) + #if __APPLE__ #include <TargetConditionals.h> #if TARGET_OS_MAC && !TARGET_OS_EMBEDDED && HAVE_QUARANTINE_H @@ -140,7 +152,17 @@ __FBSDID("$FreeBSD$"); #define O_BINARY 0 #endif #ifndef O_CLOEXEC -#define O_CLOEXEC 0 +#define O_CLOEXEC 0 +#endif + +/* Ignore non-int O_NOFOLLOW constant. */ +/* gnulib's fcntl.h does this on AIX, but it seems practical everywhere */ +#if defined O_NOFOLLOW && !(INT_MIN <= O_NOFOLLOW && O_NOFOLLOW <= INT_MAX) +#undef O_NOFOLLOW +#endif + +#ifndef O_NOFOLLOW +#define O_NOFOLLOW 0 #endif struct fixup_entry { @@ -298,7 +320,7 @@ struct archive_write_disk { #define MAXIMUM_DIR_MODE 0775 /* - * Maxinum uncompressed size of a decmpfs block. + * Maximum uncompressed size of a decmpfs block. */ #define MAX_DECMPFS_BLOCK_SIZE (64 * 1024) /* @@ -313,7 +335,7 @@ struct archive_write_disk { #define RSRC_F_SIZE 50 /* Size of Resource fork footer. */ /* Size to write compressed data to resource fork. */ #define COMPRESSED_W_SIZE (64 * 1024) -/* decmpfs difinitions. */ +/* decmpfs definitions. */ #define MAX_DECMPFS_XATTR_SIZE 3802 #ifndef DECMPFS_XATTR_NAME #define DECMPFS_XATTR_NAME "com.apple.decmpfs" @@ -326,12 +348,19 @@ struct archive_write_disk { #define HFS_BLOCKS(s) ((s) >> 12) +static void fsobj_error(int *, struct archive_string *, int, const char *, + const char *); +static int check_symlinks_fsobj(char *, int *, struct archive_string *, + int); static int check_symlinks(struct archive_write_disk *); static int create_filesystem_object(struct archive_write_disk *); -static struct fixup_entry *current_fixup(struct archive_write_disk *, const char *pathname); +static struct fixup_entry *current_fixup(struct archive_write_disk *, + const char *pathname); #if defined(HAVE_FCHDIR) && defined(PATH_MAX) static void edit_deep_directories(struct archive_write_disk *ad); #endif +static int cleanup_pathname_fsobj(char *, int *, struct archive_string *, + int); static int cleanup_pathname(struct archive_write_disk *); static int create_dir(struct archive_write_disk *, char *); static int create_parent_dir(struct archive_write_disk *, char *); @@ -362,11 +391,14 @@ static struct archive_vtable *archive_write_disk_vtable(void); static int _archive_write_disk_close(struct archive *); static int _archive_write_disk_free(struct archive *); -static int _archive_write_disk_header(struct archive *, struct archive_entry *); +static int _archive_write_disk_header(struct archive *, + struct archive_entry *); static int64_t _archive_write_disk_filter_bytes(struct archive *, int); static int _archive_write_disk_finish_entry(struct archive *); -static ssize_t _archive_write_disk_data(struct archive *, const void *, size_t); -static ssize_t _archive_write_disk_data_block(struct archive *, const void *, size_t, int64_t); +static ssize_t _archive_write_disk_data(struct archive *, const void *, + size_t); +static ssize_t _archive_write_disk_data_block(struct archive *, const void *, + size_t, int64_t); static int lazy_stat(struct archive_write_disk *a) @@ -612,9 +644,9 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry) /* * NOTE: UF_COMPRESSED is ignored even if the filesystem * supports HFS+ Compression because the file should - * have at least an extended attriute "com.apple.decmpfs" + * have at least an extended attribute "com.apple.decmpfs" * before the flag is set to indicate that the file have - * been compressed. If hte filesystem does not support + * been compressed. If the filesystem does not support * HFS+ Compression the system call will fail. */ if (a->fd < 0 || fchflags(a->fd, UF_COMPRESSED) != 0) @@ -637,7 +669,8 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry) if (a->restore_pwd >= 0) { r = fchdir(a->restore_pwd); if (r != 0) { - archive_set_error(&a->archive, errno, "chdir() failure"); + archive_set_error(&a->archive, errno, + "chdir() failure"); ret = ARCHIVE_FATAL; } close(a->restore_pwd); @@ -685,7 +718,8 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry) } if (archive_entry_birthtime_is_set(entry)) { fe->birthtime = archive_entry_birthtime(entry); - fe->birthtime_nanos = archive_entry_birthtime_nsec(entry); + fe->birthtime_nanos = archive_entry_birthtime_nsec( + entry); } else { /* If birthtime is unset, use mtime. */ fe->birthtime = fe->mtime; @@ -711,7 +745,8 @@ _archive_write_disk_header(struct archive *_a, struct archive_entry *entry) return (ARCHIVE_FATAL); fe->mac_metadata = malloc(metadata_size); if (fe->mac_metadata != NULL) { - memcpy(fe->mac_metadata, metadata, metadata_size); + memcpy(fe->mac_metadata, metadata, + metadata_size); fe->mac_metadata_size = metadata_size; fe->fixup |= TODO_MAC_METADATA; } @@ -1224,7 +1259,7 @@ hfs_drive_compressor(struct archive_write_disk *a, const char *buff, ret = hfs_write_compressed_data(a, bytes_used + rsrc_size); a->compressed_buffer_remaining = a->compressed_buffer_size; - /* If the compressed size is not enouph smaller than + /* If the compressed size is not enough smaller than * the uncompressed size. cancel HFS+ compression. * TODO: study a behavior of ditto utility and improve * the condition to fall back into no HFS+ compression. */ @@ -1329,7 +1364,7 @@ hfs_write_decmpfs_block(struct archive_write_disk *a, const char *buff, (uint32_t *)(a->resource_fork + RSRC_H_SIZE); /* Set the block count to the resource fork. */ archive_le32enc(a->decmpfs_block_info++, block_count); - /* Get the position where we are goint to set compressed + /* Get the position where we are going to set compressed * data. */ a->compressed_rsrc_position = RSRC_H_SIZE + 4 + (block_count * 8); @@ -1402,7 +1437,7 @@ hfs_write_data_block(struct archive_write_disk *a, const char *buff, bytes_to_write = size; /* Seek if necessary to the specified offset. */ if (a->offset < a->fd_offset) { - /* Can't support backword move. */ + /* Can't support backward move. */ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Seek failed"); return (ARCHIVE_FATAL); @@ -1468,7 +1503,8 @@ _archive_write_disk_data_block(struct archive *_a, return (r); if ((size_t)r < size) { archive_set_error(&a->archive, 0, - "Too much data: Truncating file at %ju bytes", (uintmax_t)a->filesize); + "Too much data: Truncating file at %ju bytes", + (uintmax_t)a->filesize); return (ARCHIVE_WARN); } #if ARCHIVE_VERSION_NUMBER < 3999000 @@ -1666,10 +1702,25 @@ _archive_write_disk_finish_entry(struct archive *_a) * ACLs that prevent attribute changes (including time). */ if (a->todo & TODO_ACLS) { - int r2 = archive_write_disk_set_acls(&a->archive, a->fd, - archive_entry_pathname(a->entry), - archive_entry_acl(a->entry)); + int r2; +#ifdef HAVE_DARWIN_ACL + /* + * On Mac OS, platform ACLs are stored also in mac_metadata by + * the operating system. If mac_metadata is present it takes + * precedence and we skip extracting libarchive NFSv4 ACLs + */ + const void *metadata; + size_t metadata_size; + metadata = archive_entry_mac_metadata(a->entry, &metadata_size); + if (metadata == NULL || metadata_size == 0) { +#endif + r2 = archive_write_disk_set_acls(&a->archive, a->fd, + archive_entry_pathname(a->entry), + archive_entry_acl(a->entry)); if (r2 < ret) ret = r2; +#ifdef HAVE_DARWIN_ACL + } +#endif } finish_metadata: @@ -1755,10 +1806,9 @@ archive_write_disk_new(void) { struct archive_write_disk *a; - a = (struct archive_write_disk *)malloc(sizeof(*a)); + a = (struct archive_write_disk *)calloc(1, sizeof(*a)); if (a == NULL) return (NULL); - memset(a, 0, sizeof(*a)); a->archive.magic = ARCHIVE_WRITE_DISK_MAGIC; /* We're ready to write a header immediately. */ a->archive.state = ARCHIVE_STATE_HEADER; @@ -1796,7 +1846,7 @@ edit_deep_directories(struct archive_write_disk *a) char *tail = a->name; /* If path is short, avoid the open() below. */ - if (strlen(tail) <= PATH_MAX) + if (strlen(tail) < PATH_MAX) return; /* Try to record our starting dir. */ @@ -1806,7 +1856,7 @@ edit_deep_directories(struct archive_write_disk *a) return; /* As long as the path is too long... */ - while (strlen(tail) > PATH_MAX) { + while (strlen(tail) >= PATH_MAX) { /* Locate a dir prefix shorter than PATH_MAX. */ tail += PATH_MAX - 8; while (tail > a->name && *tail != '/') @@ -1993,8 +2043,9 @@ restore_entry(struct archive_write_disk *a) if (en) { /* Everything failed; give up here. */ - archive_set_error(&a->archive, en, "Can't create '%s'", - a->name); + if ((&a->archive)->error == NULL) + archive_set_error(&a->archive, en, "Can't create '%s'", + a->name); return (ARCHIVE_FAILED); } @@ -2014,6 +2065,11 @@ create_filesystem_object(struct archive_write_disk *a) const char *linkname; mode_t final_mode, mode; int r; + /* these for check_symlinks_fsobj */ + char *linkname_copy; /* non-const copy of linkname */ + struct stat st; + struct archive_string error_string; + int error_number; /* We identify hard/symlinks according to the link names. */ /* Since link(2) and symlink(2) don't handle modes, we're done here. */ @@ -2022,6 +2078,43 @@ create_filesystem_object(struct archive_write_disk *a) #if !HAVE_LINK return (EPERM); #else + archive_string_init(&error_string); + linkname_copy = strdup(linkname); + if (linkname_copy == NULL) { + return (EPERM); + } + /* + * TODO: consider using the cleaned-up path as the link + * target? + */ + r = cleanup_pathname_fsobj(linkname_copy, &error_number, + &error_string, a->flags); + if (r != ARCHIVE_OK) { + archive_set_error(&a->archive, error_number, "%s", + error_string.s); + free(linkname_copy); + archive_string_free(&error_string); + /* + * EPERM is more appropriate than error_number for our + * callers + */ + return (EPERM); + } + r = check_symlinks_fsobj(linkname_copy, &error_number, + &error_string, a->flags); + if (r != ARCHIVE_OK) { + archive_set_error(&a->archive, error_number, "%s", + error_string.s); + free(linkname_copy); + archive_string_free(&error_string); + /* + * EPERM is more appropriate than error_number for our + * callers + */ + return (EPERM); + } + free(linkname_copy); + archive_string_free(&error_string); r = link(linkname, a->name) ? errno : 0; /* * New cpio and pax formats allow hardlink entries @@ -2039,11 +2132,20 @@ create_filesystem_object(struct archive_write_disk *a) a->todo = 0; a->deferred = 0; } else if (r == 0 && a->filesize > 0) { - a->fd = open(a->name, - O_WRONLY | O_TRUNC | O_BINARY | O_CLOEXEC); - __archive_ensure_cloexec_flag(a->fd); - if (a->fd < 0) +#ifdef HAVE_LSTAT + r = lstat(a->name, &st); +#else + r = stat(a->name, &st); +#endif + if (r != 0) r = errno; + else if ((st.st_mode & AE_IFMT) == AE_IFREG) { + a->fd = open(a->name, O_WRONLY | O_TRUNC | + O_BINARY | O_CLOEXEC | O_NOFOLLOW); + __archive_ensure_cloexec_flag(a->fd); + if (a->fd < 0) + r = errno; + } } return (r); #endif @@ -2190,8 +2292,12 @@ _archive_write_disk_close(struct archive *_a) if (p->fixup & TODO_MODE_BASE) chmod(p->name, p->mode); if (p->fixup & TODO_ACLS) - archive_write_disk_set_acls(&a->archive, - -1, p->name, &p->acl); +#ifdef HAVE_DARWIN_ACL + if (p->mac_metadata == NULL || + p->mac_metadata_size == 0) +#endif + archive_write_disk_set_acls(&a->archive, + -1, p->name, &p->acl); if (p->fixup & TODO_FFLAGS) set_fflags_platform(a, -1, p->name, p->mode, p->fflags_set, 0); @@ -2351,116 +2457,283 @@ current_fixup(struct archive_write_disk *a, const char *pathname) return (a->current_fixup); } -/* TODO: Make this work. */ -/* - * TODO: The deep-directory support bypasses this; disable deep directory - * support if we're doing symlink checks. - */ +/* Error helper for new *_fsobj functions */ +static void +fsobj_error(int *a_eno, struct archive_string *a_estr, + int err, const char *errstr, const char *path) +{ + if (a_eno) + *a_eno = err; + if (a_estr) + archive_string_sprintf(a_estr, errstr, path); +} + /* * TODO: Someday, integrate this with the deep dir support; they both * scan the path and both can be optimized by comparing against other * recent paths. */ /* TODO: Extend this to support symlinks on Windows Vista and later. */ + +/* + * Checks the given path to see if any elements along it are symlinks. Returns + * ARCHIVE_OK if there are none, otherwise puts an error in errmsg. + */ static int -check_symlinks(struct archive_write_disk *a) +check_symlinks_fsobj(char *path, int *a_eno, struct archive_string *a_estr, + int flags) { #if !defined(HAVE_LSTAT) /* Platform doesn't have lstat, so we can't look for symlinks. */ - (void)a; /* UNUSED */ + (void)path; /* UNUSED */ + (void)error_number; /* UNUSED */ + (void)error_string; /* UNUSED */ + (void)flags; /* UNUSED */ return (ARCHIVE_OK); #else - char *pn; + int res = ARCHIVE_OK; + char *tail; + char *head; + int last; char c; int r; struct stat st; + int restore_pwd; + + /* Nothing to do here if name is empty */ + if(path[0] == '\0') + return (ARCHIVE_OK); /* * Guard against symlink tricks. Reject any archive entry whose * destination would be altered by a symlink. + * + * Walk the filename in chunks separated by '/'. For each segment: + * - if it doesn't exist, continue + * - if it's symlink, abort or remove it + * - if it's a directory and it's not the last chunk, cd into it + * As we go: + * head points to the current (relative) path + * tail points to the temporary \0 terminating the segment we're + * currently examining + * c holds what used to be in *tail + * last is 1 if this is the last tail */ - /* Whatever we checked last time doesn't need to be re-checked. */ - pn = a->name; - if (archive_strlen(&(a->path_safe)) > 0) { - char *p = a->path_safe.s; - while ((*pn != '\0') && (*p == *pn)) - ++p, ++pn; - } + restore_pwd = open(".", O_RDONLY | O_BINARY | O_CLOEXEC); + __archive_ensure_cloexec_flag(restore_pwd); + if (restore_pwd < 0) + return (ARCHIVE_FATAL); + head = path; + tail = path; + last = 0; + /* TODO: reintroduce a safe cache here? */ /* Skip the root directory if the path is absolute. */ - if(pn == a->name && pn[0] == '/') - ++pn; - c = pn[0]; - /* Keep going until we've checked the entire name. */ - while (pn[0] != '\0' && (pn[0] != '/' || pn[1] != '\0')) { + if(tail == path && tail[0] == '/') + ++tail; + /* Keep going until we've checked the entire name. + * head, tail, path all alias the same string, which is + * temporarily zeroed at tail, so be careful restoring the + * stashed (c=tail[0]) for error messages. + * Exiting the loop with break is okay; continue is not. + */ + while (!last) { + /* + * Skip the separator we just consumed, plus any adjacent ones + */ + while (*tail == '/') + ++tail; /* Skip the next path element. */ - while (*pn != '\0' && *pn != '/') - ++pn; - c = pn[0]; - pn[0] = '\0'; + while (*tail != '\0' && *tail != '/') + ++tail; + /* is this the last path component? */ + last = (tail[0] == '\0') || (tail[0] == '/' && tail[1] == '\0'); + /* temporarily truncate the string here */ + c = tail[0]; + tail[0] = '\0'; /* Check that we haven't hit a symlink. */ - r = lstat(a->name, &st); + r = lstat(head, &st); if (r != 0) { + tail[0] = c; /* We've hit a dir that doesn't exist; stop now. */ - if (errno == ENOENT) + if (errno == ENOENT) { + break; + } else { + /* + * Treat any other error as fatal - best to be + * paranoid here. + * Note: This effectively disables deep + * directory support when security checks are + * enabled. Otherwise, very long pathnames that + * trigger an error here could evade the + * sandbox. + * TODO: We could do better, but it would + * probably require merging the symlink checks + * with the deep-directory editing. + */ + fsobj_error(a_eno, a_estr, errno, + "Could not stat %s", path); + res = ARCHIVE_FAILED; break; + } + } else if (S_ISDIR(st.st_mode)) { + if (!last) { + if (chdir(head) != 0) { + tail[0] = c; + fsobj_error(a_eno, a_estr, errno, + "Could not chdir %s", path); + res = (ARCHIVE_FATAL); + break; + } + /* Our view is now from inside this dir: */ + head = tail + 1; + } } else if (S_ISLNK(st.st_mode)) { - if (c == '\0') { + if (last) { /* * Last element is symlink; remove it * so we can overwrite it with the * item being extracted. */ - if (unlink(a->name)) { - archive_set_error(&a->archive, errno, + if (unlink(head)) { + tail[0] = c; + fsobj_error(a_eno, a_estr, errno, "Could not remove symlink %s", - a->name); - pn[0] = c; - return (ARCHIVE_FAILED); + path); + res = ARCHIVE_FAILED; + break; } - a->pst = NULL; /* * Even if we did remove it, a warning * is in order. The warning is silly, * though, if we're just replacing one * symlink with another symlink. */ - if (!S_ISLNK(a->mode)) { - archive_set_error(&a->archive, 0, - "Removing symlink %s", - a->name); + tail[0] = c; + /* + * FIXME: not sure how important this is to + * restore + */ + /* + if (!S_ISLNK(path)) { + fsobj_error(a_eno, a_estr, 0, + "Removing symlink %s", path); } + */ /* Symlink gone. No more problem! */ - pn[0] = c; - return (0); - } else if (a->flags & ARCHIVE_EXTRACT_UNLINK) { + res = ARCHIVE_OK; + break; + } else if (flags & ARCHIVE_EXTRACT_UNLINK) { /* User asked us to remove problems. */ - if (unlink(a->name) != 0) { - archive_set_error(&a->archive, 0, - "Cannot remove intervening symlink %s", - a->name); - pn[0] = c; - return (ARCHIVE_FAILED); + if (unlink(head) != 0) { + tail[0] = c; + fsobj_error(a_eno, a_estr, 0, + "Cannot remove intervening " + "symlink %s", path); + res = ARCHIVE_FAILED; + break; + } + tail[0] = c; + } else if ((flags & + ARCHIVE_EXTRACT_SECURE_SYMLINKS) == 0) { + /* + * We are not the last element and we want to + * follow symlinks if they are a directory. + * + * This is needed to extract hardlinks over + * symlinks. + */ + r = stat(head, &st); + if (r != 0) { + tail[0] = c; + if (errno == ENOENT) { + break; + } else { + fsobj_error(a_eno, a_estr, + errno, + "Could not stat %s", path); + res = (ARCHIVE_FAILED); + break; + } + } else if (S_ISDIR(st.st_mode)) { + if (chdir(head) != 0) { + tail[0] = c; + fsobj_error(a_eno, a_estr, + errno, + "Could not chdir %s", path); + res = (ARCHIVE_FATAL); + break; + } + /* + * Our view is now from inside + * this dir: + */ + head = tail + 1; + } else { + tail[0] = c; + fsobj_error(a_eno, a_estr, 0, + "Cannot extract through " + "symlink %s", path); + res = ARCHIVE_FAILED; + break; } - a->pst = NULL; } else { - archive_set_error(&a->archive, 0, - "Cannot extract through symlink %s", - a->name); - pn[0] = c; - return (ARCHIVE_FAILED); + tail[0] = c; + fsobj_error(a_eno, a_estr, 0, + "Cannot extract through symlink %s", path); + res = ARCHIVE_FAILED; + break; } } - pn[0] = c; - if (pn[0] != '\0') - pn++; /* Advance to the next segment. */ + /* be sure to always maintain this */ + tail[0] = c; + if (tail[0] != '\0') + tail++; /* Advance to the next segment. */ + } + /* Catches loop exits via break */ + tail[0] = c; +#ifdef HAVE_FCHDIR + /* If we changed directory above, restore it here. */ + if (restore_pwd >= 0) { + r = fchdir(restore_pwd); + if (r != 0) { + fsobj_error(a_eno, a_estr, errno, + "chdir() failure", ""); + } + close(restore_pwd); + restore_pwd = -1; + if (r != 0) { + res = (ARCHIVE_FATAL); + } } - pn[0] = c; - /* We've checked and/or cleaned the whole path, so remember it. */ - archive_strcpy(&a->path_safe, a->name); - return (ARCHIVE_OK); +#endif + /* TODO: reintroduce a safe cache here? */ + return res; #endif } +/* + * Check a->name for symlinks, returning ARCHIVE_OK if its clean, otherwise + * calls archive_set_error and returns ARCHIVE_{FATAL,FAILED} + */ +static int +check_symlinks(struct archive_write_disk *a) +{ + struct archive_string error_string; + int error_number; + int rc; + archive_string_init(&error_string); + rc = check_symlinks_fsobj(a->name, &error_number, &error_string, + a->flags); + if (rc != ARCHIVE_OK) { + archive_set_error(&a->archive, error_number, "%s", + error_string.s); + } + archive_string_free(&error_string); + a->pst = NULL; /* to be safe */ + return rc; +} + + #if defined(__CYGWIN__) /* * 1. Convert a path separator from '\' to '/' . @@ -2471,7 +2744,7 @@ check_symlinks(struct archive_write_disk *a) * See also : http://msdn.microsoft.com/en-us/library/aa365247.aspx */ static void -cleanup_pathname_win(struct archive_write_disk *a) +cleanup_pathname_win(char *path) { wchar_t wc; char *p; @@ -2482,7 +2755,7 @@ cleanup_pathname_win(struct archive_write_disk *a) mb = 0; complete = 1; utf8 = (strcmp(nl_langinfo(CODESET), "UTF-8") == 0)? 1: 0; - for (p = a->name; *p != '\0'; p++) { + for (p = path; *p != '\0'; p++) { ++alen; if (*p == '\\') { /* If previous byte is smaller than 128, @@ -2507,7 +2780,7 @@ cleanup_pathname_win(struct archive_write_disk *a) /* * Convert path separator in wide-character. */ - p = a->name; + p = path; while (*p != '\0' && alen) { l = mbtowc(&wc, p, alen); if (l == (size_t)-1) { @@ -2534,26 +2807,27 @@ cleanup_pathname_win(struct archive_write_disk *a) * is set) if the path is absolute. */ static int -cleanup_pathname(struct archive_write_disk *a) +cleanup_pathname_fsobj(char *path, int *a_eno, struct archive_string *a_estr, + int flags) { char *dest, *src; char separator = '\0'; - dest = src = a->name; + dest = src = path; if (*src == '\0') { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Invalid empty pathname"); + fsobj_error(a_eno, a_estr, ARCHIVE_ERRNO_MISC, + "Invalid empty ", "pathname"); return (ARCHIVE_FAILED); } #if defined(__CYGWIN__) - cleanup_pathname_win(a); + cleanup_pathname_win(path); #endif /* Skip leading '/'. */ if (*src == '/') { - if (a->flags & ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Path is absolute"); + if (flags & ARCHIVE_EXTRACT_SECURE_NOABSOLUTEPATHS) { + fsobj_error(a_eno, a_estr, ARCHIVE_ERRNO_MISC, + "Path is ", "absolute"); return (ARCHIVE_FAILED); } @@ -2580,10 +2854,11 @@ cleanup_pathname(struct archive_write_disk *a) } else if (src[1] == '.') { if (src[2] == '/' || src[2] == '\0') { /* Conditionally warn about '..' */ - if (a->flags & ARCHIVE_EXTRACT_SECURE_NODOTDOT) { - archive_set_error(&a->archive, + if (flags + & ARCHIVE_EXTRACT_SECURE_NODOTDOT) { + fsobj_error(a_eno, a_estr, ARCHIVE_ERRNO_MISC, - "Path contains '..'"); + "Path contains ", "'..'"); return (ARCHIVE_FAILED); } } @@ -2614,7 +2889,7 @@ cleanup_pathname(struct archive_write_disk *a) * We've just copied zero or more path elements, not including the * final '/'. */ - if (dest == a->name) { + if (dest == path) { /* * Nothing got copied. The path must have been something * like '.' or '/' or './' or '/././././/./'. @@ -2629,6 +2904,23 @@ cleanup_pathname(struct archive_write_disk *a) return (ARCHIVE_OK); } +static int +cleanup_pathname(struct archive_write_disk *a) +{ + struct archive_string error_string; + int error_number; + int rc; + archive_string_init(&error_string); + rc = cleanup_pathname_fsobj(a->name, &error_number, &error_string, + a->flags); + if (rc != ARCHIVE_OK) { + archive_set_error(&a->archive, error_number, "%s", + error_string.s); + } + archive_string_free(&error_string); + return rc; +} + /* * Create the parent directory of the specified path, assuming path * is already in mutable storage. @@ -2707,7 +2999,8 @@ create_dir(struct archive_write_disk *a, char *path) } } else if (errno != ENOENT && errno != ENOTDIR) { /* Stat failed? */ - archive_set_error(&a->archive, errno, "Can't test directory '%s'", path); + archive_set_error(&a->archive, errno, + "Can't test directory '%s'", path); return (ARCHIVE_FAILED); } else if (slash != NULL) { *slash = '\0'; @@ -3232,7 +3525,8 @@ clear_nochange_fflags(struct archive_write_disk *a) nochange_flags |= EXT2_IMMUTABLE_FL; #endif - return (set_fflags_platform(a, a->fd, a->name, mode, 0, nochange_flags)); + return (set_fflags_platform(a, a->fd, a->name, mode, 0, + nochange_flags)); } @@ -3487,6 +3781,9 @@ exit_xattr: static int copy_acls(struct archive_write_disk *a, int tmpfd, int dffd) { +#ifndef HAVE_SYS_ACL_H + return 0; +#else acl_t acl, dfacl = NULL; int acl_r, ret = ARCHIVE_OK; @@ -3514,6 +3811,7 @@ exit_acl: if (dfacl) acl_free(dfacl); return (ret); +#endif } static int @@ -3753,7 +4051,8 @@ set_xattrs(struct archive_write_disk *a) if (errno == ENOTSUP || errno == ENOSYS) { if (!warning_done) { warning_done = 1; - archive_set_error(&a->archive, errno, + archive_set_error(&a->archive, + errno, "Cannot restore extended " "attributes on this file " "system"); @@ -3764,7 +4063,8 @@ set_xattrs(struct archive_write_disk *a) ret = ARCHIVE_WARN; } } else { - archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, "Invalid extended attribute encountered"); ret = ARCHIVE_WARN; } @@ -3808,19 +4108,22 @@ set_xattrs(struct archive_write_disk *a) errno = 0; #if HAVE_EXTATTR_SET_FD if (a->fd >= 0) - e = extattr_set_fd(a->fd, namespace, name, value, size); + e = extattr_set_fd(a->fd, namespace, name, + value, size); else #endif /* TODO: should we use extattr_set_link() instead? */ { - e = extattr_set_file(archive_entry_pathname(entry), - namespace, name, value, size); + e = extattr_set_file( + archive_entry_pathname(entry), namespace, + name, value, size); } if (e != (int)size) { if (errno == ENOTSUP || errno == ENOSYS) { if (!warning_done) { warning_done = 1; - archive_set_error(&a->archive, errno, + archive_set_error(&a->archive, + errno, "Cannot restore extended " "attributes on this file " "system"); @@ -3866,10 +4169,10 @@ older(struct stat *st, struct archive_entry *entry) { /* First, test the seconds and return if we have a definite answer. */ /* Definitely older. */ - if (st->st_mtime < archive_entry_mtime(entry)) + if (to_int64_time(st->st_mtime) < to_int64_time(archive_entry_mtime(entry))) return (1); /* Definitely younger. */ - if (st->st_mtime > archive_entry_mtime(entry)) + if (to_int64_time(st->st_mtime) > to_int64_time(archive_entry_mtime(entry))) return (0); /* If this platform supports fractional seconds, try those. */ #if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC diff --git a/Utilities/cmlibarchive/libarchive/archive_write_disk_set_standard_lookup.c b/Utilities/cmlibarchive/libarchive/archive_write_disk_set_standard_lookup.c index 3b868fb..5c766d7 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_disk_set_standard_lookup.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_disk_set_standard_lookup.c @@ -84,15 +84,13 @@ static void cleanup(void *); int archive_write_disk_set_standard_lookup(struct archive *a) { - struct bucket *ucache = malloc(cache_size * sizeof(struct bucket)); - struct bucket *gcache = malloc(cache_size * sizeof(struct bucket)); + struct bucket *ucache = calloc(cache_size, sizeof(struct bucket)); + struct bucket *gcache = calloc(cache_size, sizeof(struct bucket)); if (ucache == NULL || gcache == NULL) { free(ucache); free(gcache); return (ARCHIVE_FATAL); } - memset(ucache, 0, cache_size * sizeof(struct bucket)); - memset(gcache, 0, cache_size * sizeof(struct bucket)); archive_write_disk_set_group_lookup(a, gcache, lookup_gid, cleanup); archive_write_disk_set_user_lookup(a, ucache, lookup_uid, cleanup); return (ARCHIVE_OK); diff --git a/Utilities/cmlibarchive/libarchive/archive_write_disk_windows.c b/Utilities/cmlibarchive/libarchive/archive_write_disk_windows.c index da76c54..94b016e 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_disk_windows.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_disk_windows.c @@ -192,7 +192,7 @@ struct archive_write_disk { /* * Default mode for dirs created automatically (will be modified by umask). - * Note that POSIX specifies 0777 for implicity-created dirs, "modified + * Note that POSIX specifies 0777 for implicitly-created dirs, "modified * by the process' file creation mask." */ #define DEFAULT_DIR_MODE 0777 @@ -396,7 +396,7 @@ permissive_name_w(struct archive_write_disk *a) } /* - * A full-pathname pointig a network drive + * A full-pathname pointing to a network drive * like "\\<server-name>\<share-name>\file". */ if (wnp[0] == L'\\' && wnp[1] == L'\\' && wnp[2] != L'\\') { @@ -1221,10 +1221,9 @@ archive_write_disk_new(void) { struct archive_write_disk *a; - a = (struct archive_write_disk *)malloc(sizeof(*a)); + a = (struct archive_write_disk *)calloc(1, sizeof(*a)); if (a == NULL) return (NULL); - memset(a, 0, sizeof(*a)); a->archive.magic = ARCHIVE_WRITE_DISK_MAGIC; /* We're ready to write a header immediately. */ a->archive.state = ARCHIVE_STATE_HEADER; diff --git a/Utilities/cmlibarchive/libarchive/archive_write_open.3 b/Utilities/cmlibarchive/libarchive/archive_write_open.3 index a52959b..457873e 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_open.3 +++ b/Utilities/cmlibarchive/libarchive/archive_write_open.3 @@ -66,6 +66,7 @@ Freeze the settings, open the archive, and prepare for writing entries. This is the most generic form of this function, which accepts pointers to three callback functions which will be invoked by the compression layer to write the constructed archive. +This does not alter the default archive padding. .It Fn archive_write_open_fd A convenience form of .Fn archive_write_open @@ -123,12 +124,21 @@ is currently in use. You should be careful to ensure that this variable remains allocated until after the archive is closed. +This function will disable padding unless you +have specifically set the block size. .El More information about the .Va struct archive object and the overall design of the library can be found in the .Xr libarchive 3 overview. +.Pp +Note that the convenience forms above vary in how +they block the output. +See +.Xr archive_write_blocksize 3 +if you need to control the block size used for writes +or the end-of-file padding behavior. .\" .Sh CLIENT CALLBACKS To use this library, you will need to define and register @@ -226,6 +236,7 @@ functions. .Xr tar 1 , .Xr libarchive 3 , .Xr archive_write 3 , +.Xr archive_write_blocksize 3 , .Xr archive_write_filter 3 , .Xr archive_write_format 3 , .Xr archive_write_new 3 , diff --git a/Utilities/cmlibarchive/libarchive/archive_write_open_memory.c b/Utilities/cmlibarchive/libarchive/archive_write_open_memory.c index 4f8d679..ea6ae0a 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_open_memory.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_open_memory.c @@ -53,12 +53,11 @@ archive_write_open_memory(struct archive *a, void *buff, size_t buffSize, size_t { struct write_memory_data *mine; - mine = (struct write_memory_data *)malloc(sizeof(*mine)); + mine = (struct write_memory_data *)calloc(1, sizeof(*mine)); if (mine == NULL) { archive_set_error(a, ENOMEM, "No memory"); return (ARCHIVE_FATAL); } - memset(mine, 0, sizeof(*mine)); mine->buff = buff; mine->size = buffSize; mine->client_size = used; diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_7zip.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_7zip.c index 8718d25..3fc5a07 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_7zip.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_7zip.c @@ -205,7 +205,7 @@ struct _7zip { /* * The list of the file entries which has its contents is used to * manage struct file objects. - * We use 'next' a menber of struct file to chain. + * We use 'next' (a member of struct file) to chain. */ struct { struct file *first; @@ -1358,7 +1358,7 @@ make_header(struct archive_write *a, uint64_t offset, uint64_t pack_size, if (r < 0) return (r); - /* Write Nume size. */ + /* Write Name size. */ r = enc_uint64(a, zip->total_bytes_entry_name+1); if (r < 0) return (r); diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_ar.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_ar.c index 9f17564..c9771d8 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_ar.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_ar.c @@ -126,12 +126,11 @@ archive_write_set_format_ar(struct archive_write *a) if (a->format_free != NULL) (a->format_free)(a); - ar = (struct ar_w *)malloc(sizeof(*ar)); + ar = (struct ar_w *)calloc(1, sizeof(*ar)); if (ar == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate ar data"); return (ARCHIVE_FATAL); } - memset(ar, 0, sizeof(*ar)); a->format_data = ar; a->format_name = "ar"; diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio.c index 3526493..a4c9d1e 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio.c @@ -289,7 +289,7 @@ write_header(struct archive_write *a, struct archive_entry *entry) sconv = get_sconv(a); #if defined(_WIN32) && !defined(__CYGWIN__) - /* Make sure the path separators in pahtname, hardlink and symlink + /* Make sure the path separators in pathname, hardlink and symlink * are all slash '/', not the Windows path separator '\'. */ entry_main = __la_win_entry_in_posix_pathseparator(entry); if (entry_main == NULL) { diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio_newc.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio_newc.c index a9bfa80..957f1a3 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio_newc.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_cpio_newc.c @@ -116,12 +116,11 @@ archive_write_set_format_cpio_newc(struct archive *_a) if (a->format_free != NULL) (a->format_free)(a); - cpio = (struct cpio *)malloc(sizeof(*cpio)); + cpio = (struct cpio *)calloc(1, sizeof(*cpio)); if (cpio == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data"); return (ARCHIVE_FATAL); } - memset(cpio, 0, sizeof(*cpio)); a->format_data = cpio; a->format_name = "cpio"; a->format_options = archive_write_newc_options; @@ -232,7 +231,7 @@ write_header(struct archive_write *a, struct archive_entry *entry) sconv = get_sconv(a); #if defined(_WIN32) && !defined(__CYGWIN__) - /* Make sure the path separators in pahtname, hardlink and symlink + /* Make sure the path separators in pathname, hardlink and symlink * are all slash '/', not the Windows path separator '\'. */ entry_main = __la_win_entry_in_posix_pathseparator(entry); if (entry_main == NULL) { diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_gnutar.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_gnutar.c index 1d635d2..2d858c9 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_gnutar.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_gnutar.c @@ -119,9 +119,9 @@ static const char template_header[] = { '0','0','0','0','0','0', '0','\0', /* gid, null termination: 8 bytes */ '0','0','0','0','0','0', '0','\0', - /* size, space termation: 12 bytes */ + /* size, space termination: 12 bytes */ '0','0','0','0','0','0','0','0','0','0','0', '\0', - /* mtime, space termation: 12 bytes */ + /* mtime, space termination: 12 bytes */ '0','0','0','0','0','0','0','0','0','0','0', '\0', /* Initial checksum value: 8 spaces */ ' ',' ',' ',' ',' ',' ',' ',' ', @@ -368,7 +368,7 @@ archive_write_gnutar_header(struct archive_write *a, } #if defined(_WIN32) && !defined(__CYGWIN__) - /* Make sure the path separators in pahtname, hardlink and symlink + /* Make sure the path separators in pathname, hardlink and symlink * are all slash '/', not the Windows path separator '\'. */ entry_main = __la_win_entry_in_posix_pathseparator(entry); if (entry_main == NULL) { @@ -478,15 +478,15 @@ archive_write_gnutar_header(struct archive_write *a, archive_entry_set_pathname(temp, "././@LongLink"); archive_entry_set_size(temp, length); ret = archive_format_gnutar_header(a, buff, temp, 'K'); + archive_entry_free(temp); if (ret < ARCHIVE_WARN) goto exit_write_header; ret = __archive_write_output(a, buff, 512); - if(ret < ARCHIVE_WARN) + if (ret < ARCHIVE_WARN) goto exit_write_header; - archive_entry_free(temp); /* Write name and trailing null byte. */ ret = __archive_write_output(a, gnutar->linkname, length); - if(ret < ARCHIVE_WARN) + if (ret < ARCHIVE_WARN) goto exit_write_header; /* Pad to 512 bytes */ ret = __archive_write_nulls(a, 0x1ff & (-(ssize_t)length)); @@ -508,12 +508,12 @@ archive_write_gnutar_header(struct archive_write *a, archive_entry_set_pathname(temp, "././@LongLink"); archive_entry_set_size(temp, length); ret = archive_format_gnutar_header(a, buff, temp, 'L'); + archive_entry_free(temp); if (ret < ARCHIVE_WARN) goto exit_write_header; ret = __archive_write_output(a, buff, 512); if(ret < ARCHIVE_WARN) goto exit_write_header; - archive_entry_free(temp); /* Write pathname + trailing null byte. */ ret = __archive_write_output(a, pathname, length); if(ret < ARCHIVE_WARN) diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_iso9660.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_iso9660.c index 879a776..eb98491 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_iso9660.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_iso9660.c @@ -161,7 +161,7 @@ struct isofile { /* Used for managing struct isofile list. */ struct isofile *allnext; struct isofile *datanext; - /* Used for managing a hardlined struct isofile list. */ + /* Used for managing a hardlinked struct isofile list. */ struct isofile *hlnext; struct isofile *hardlink_target; @@ -436,7 +436,7 @@ struct iso_option { * Type : string * Default: Auto detect * : We check a size of boot image; - * : If ths size is just 1.22M/1.44M/2.88M, + * : If the size is just 1.22M/1.44M/2.88M, * : we assume boot_type is 'fd'; * : otherwise boot_type is 'no-emulation'. * COMPAT : @@ -528,7 +528,7 @@ struct iso_option { * - allow more then 8 depths of directory trees; * - disable a version number to a File Name; * - disable a forced period to the tail of a File Name; - * - the maxinum length of files and directories is raised to 193. + * - the maximum length of files and directories is raised to 193. * if rockridge option is disabled, raised to 207. */ unsigned int iso_level:3; @@ -626,7 +626,7 @@ struct iso_option { * : NOTE Our rockridge=useful option does not set a zero * : to uid and gid, you should use application * : option such as --gid,--gname,--uid and --uname - * : badtar options instead. + * : bsdtar options instead. * Type : boolean/string * Default: Enabled as rockridge=useful * COMPAT : mkisofs -r / -R @@ -660,7 +660,7 @@ struct iso_option { * : for making zisofs. * : When the file size is less than one Logical Block * : size, that file will not zisofs'ed since it does - * : reduece an ISO-image size. + * : reduce an ISO-image size. * : * : When you specify option 'boot=<boot-image>', that * : 'boot-image' file won't be converted to zisofs file. @@ -680,7 +680,7 @@ struct iso9660 { /* The creation time of ISO image. */ time_t birth_time; /* A file stream of a temporary file, which file contents - * save to until ISO iamge can be created. */ + * save to until ISO image can be created. */ int temp_fd; struct isofile *cur_file; @@ -703,7 +703,7 @@ struct iso9660 { } all_file_list; /* A list of struct isofile entries which have its - * contents and are not a directory, a hardlined file + * contents and are not a directory, a hardlinked file * and a symlink file. */ struct { struct isofile *first; @@ -1907,9 +1907,9 @@ iso9660_close(struct archive_write *a) iso9660->primary.rootent); if (ret < 0) return (ret); - /* Make sure we have UTF-16BE convertors. - * if there is no file entry, convertors are still - * uninitilized. */ + /* Make sure we have UTF-16BE converters. + * if there is no file entry, converters are still + * uninitialized. */ if (iso9660->sconv_to_utf16be == NULL) { iso9660->sconv_to_utf16be = archive_string_conversion_to_charset( @@ -1995,7 +1995,7 @@ iso9660_close(struct archive_write *a) * Write an ISO 9660 image. */ - /* Switc to start using wbuff as file buffer. */ + /* Switch to start using wbuff as file buffer. */ iso9660->wbuff_remaining = wb_buffmax(); iso9660->wbuff_type = WB_TO_STREAM; iso9660->wbuff_offset = 0; @@ -2524,7 +2524,8 @@ get_tmfromtime(struct tm *tm, time_t *t) tzset(); localtime_r(t, tm); #elif HAVE__LOCALTIME64_S - _localtime64_s(tm, t); + __time64_t tmp_t = (__time64_t) *t; //time_t may be shorter than 64 bits + _localtime64_s(tm, &tmp_t); #else memcpy(tm, localtime(t), sizeof(*tm)); #endif @@ -2553,7 +2554,7 @@ set_date_time(unsigned char *p, time_t t) static void set_date_time_null(unsigned char *p) { - memset(p, '0', 16); + memset(p, (int)'0', 16); p[16] = 0; } @@ -2959,7 +2960,7 @@ set_directory_record_rr(unsigned char *bp, int dr_len, gid = archive_entry_gid(file->entry); if (iso9660->opt.rr == OPT_RR_USEFUL) { /* - * This action is simular mkisofs -r option + * This action is similar to mkisofs -r option * but our rockridge=useful option does not * set a zero to uid and gid. */ @@ -3024,8 +3025,8 @@ set_directory_record_rr(unsigned char *bp, int dr_len, * +----+----+----+----+----+ * 10 11 12 13 14 15 * - * - cflg : flag of componet - * - clen : length of componet + * - cflg : flag of component + * - clen : length of component */ const char *sl; char sl_last; @@ -3108,7 +3109,7 @@ set_directory_record_rr(unsigned char *bp, int dr_len, /* * flg len * +----+----+ - * | 02 | 00 | CURREENT component. + * | 02 | 00 | CURRENT component. * +----+----+ (".") */ if (nc != NULL) { @@ -3947,7 +3948,7 @@ write_VD(struct archive_write *a, struct vdd *vdd) "Abstract File", 0, D_CHAR); if (r != ARCHIVE_OK) return (r); - /* Bibliongraphic File Identifier */ + /* Bibliographic File Identifier */ r = set_file_identifier(bp, 777, 813, vdc, a, vdd, &(iso9660->bibliographic_file_identifier), "Bibliongraphic File", 0, D_CHAR); @@ -4073,7 +4074,8 @@ write_information_block(struct archive_write *a) memset(info.s, 0, info_size); opt = 0; #if defined(HAVE__CTIME64_S) - _ctime64_s(buf, sizeof(buf), &(iso9660->birth_time)); + __time64_t iso9660_birth_time_tmp = (__time64_t) iso9660->birth_time; //time_t may be shorter than 64 bits + _ctime64_s(buf, sizeof(buf), &(iso9660_birth_time_tmp)); #elif defined(HAVE_CTIME_R) ctime_r(&(iso9660->birth_time), buf); #else @@ -4558,7 +4560,7 @@ write_file_descriptors(struct archive_write *a) file->cur_content = &(file->content); do { blocks += file->cur_content->blocks; - /* Next fragument */ + /* Next fragment */ file->cur_content = file->cur_content->next; } while (file->cur_content != NULL); } @@ -4748,7 +4750,7 @@ isofile_gen_utility_names(struct archive_write *a, struct isofile *file) } /* - * Converte a filename to UTF-16BE. + * Convert a filename to UTF-16BE. */ if (0 > archive_entry_pathname_l(file->entry, &u16, &u16len, iso9660->sconv_to_utf16be)) { @@ -5512,7 +5514,7 @@ isoent_setup_file_location(struct iso9660 *iso9660, int location) file->cur_content->location = location; location += file->cur_content->blocks; total_block += file->cur_content->blocks; - /* Next fragument */ + /* Next fragment */ file->cur_content = file->cur_content->next; } while (file->cur_content != NULL); } @@ -6135,7 +6137,7 @@ isoent_gen_iso9660_identifier(struct archive_write *a, struct isoent *isoent, off = ffmax - extlen; if (off == 0) { /* A dot('.') character - * does't place to the first + * doesn't place to the first * byte of identifier. */ off ++; extlen --; @@ -6164,7 +6166,7 @@ isoent_gen_iso9660_identifier(struct archive_write *a, struct isoent *isoent, np->id_len = l = ext_off + np->ext_len; /* Make an offset of the number which is used to be set - * hexadecimal number to avoid duplicate identififier. */ + * hexadecimal number to avoid duplicate identifier. */ if (iso9660->opt.iso_level == 1) { if (ext_off >= 5) noff = 5; @@ -6742,7 +6744,7 @@ isoent_rr_move(struct archive_write *a) int r; pt = &(iso9660->primary.pathtbl[MAX_DEPTH-1]); - /* Theare aren't level 8 directories reaching a deepr level. */ + /* There aren't level 8 directories reaching a deeper level. */ if (pt->cnt == 0) return (ARCHIVE_OK); @@ -6813,7 +6815,7 @@ _compare_path_table(const void *v1, const void *v2) if (cmp != 0) return (cmp); - /* Compare indetifier */ + /* Compare identifier */ s1 = p1->identifier; s2 = p2->identifier; l = p1->ext_off; @@ -6855,7 +6857,7 @@ _compare_path_table_joliet(const void *v1, const void *v2) if (cmp != 0) return (cmp); - /* Compare indetifier */ + /* Compare identifier */ s1 = (const unsigned char *)p1->identifier; s2 = (const unsigned char *)p2->identifier; l = p1->ext_off; @@ -7149,7 +7151,7 @@ isoent_create_boot_catalog(struct archive_write *a, struct isoent *rootent) iso9660->el_torito.catalog = isoent; /* - * Get a boot medai type. + * Get a boot media type. */ switch (iso9660->opt.boot_type) { default: diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_mtree.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_mtree.c index b686303..493d473 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_mtree.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_mtree.c @@ -1840,9 +1840,9 @@ mtree_entry_setup_filenames(struct archive_write *a, struct mtree_entry *file, len = strlen(p); /* - * Add "./" prefiex. + * Add "./" prefix. * NOTE: If the pathname does not have a path separator, we have - * to add "./" to the head of the pathename because mtree reader + * to add "./" to the head of the pathname because mtree reader * will suppose that it is v1(a.k.a classic) mtree format and * change the directory unexpectedly and so it will make a wrong * path. diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_pax.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_pax.c index 6f7fe78..6a301ac 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_pax.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_pax.c @@ -1,6 +1,7 @@ /*- * Copyright (c) 2003-2007 Tim Kientzle * Copyright (c) 2010-2012 Michihiro NAKAJIMA + * Copyright (c) 2016 Martin Matuska * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -61,15 +62,24 @@ struct pax { struct sparse_block *sparse_tail; struct archive_string_conv *sconv_utf8; int opt_binary; + + unsigned flags; +#define WRITE_SCHILY_XATTR (1 << 0) +#define WRITE_LIBARCHIVE_XATTR (1 << 1) }; static void add_pax_attr(struct archive_string *, const char *key, const char *value); +static void add_pax_attr_binary(struct archive_string *, + const char *key, + const char *value, size_t value_len); static void add_pax_attr_int(struct archive_string *, const char *key, int64_t value); static void add_pax_attr_time(struct archive_string *, const char *key, int64_t sec, unsigned long nanos); +static int add_pax_acl(struct archive_write *, + struct archive_entry *, struct pax *, int); static ssize_t archive_write_pax_data(struct archive_write *, const void *, size_t); static int archive_write_pax_close(struct archive_write *); @@ -127,13 +137,14 @@ archive_write_set_format_pax(struct archive *_a) if (a->format_free != NULL) (a->format_free)(a); - pax = (struct pax *)malloc(sizeof(*pax)); + pax = (struct pax *)calloc(1, sizeof(*pax)); if (pax == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate pax data"); return (ARCHIVE_FATAL); } - memset(pax, 0, sizeof(*pax)); + pax->flags = WRITE_LIBARCHIVE_XATTR | WRITE_SCHILY_XATTR; + a->format_data = pax; a->format_name = "pax"; a->format_options = archive_write_pax_options; @@ -273,6 +284,17 @@ add_pax_attr_int(struct archive_string *as, const char *key, int64_t value) static void add_pax_attr(struct archive_string *as, const char *key, const char *value) { + add_pax_attr_binary(as, key, value, strlen(value)); +} + +/* + * Add a key/value attribute to the pax header. This function handles + * binary values. + */ +static void +add_pax_attr_binary(struct archive_string *as, const char *key, + const char *value, size_t value_len) +{ int digits, i, len, next_ten; char tmp[1 + 3 * sizeof(int)]; /* < 3 base-10 digits per byte */ @@ -280,7 +302,7 @@ add_pax_attr(struct archive_string *as, const char *key, const char *value) * PAX attributes have the following layout: * <len> <space> <key> <=> <value> <nl> */ - len = 1 + (int)strlen(key) + 1 + (int)strlen(value) + 1; + len = 1 + (int)strlen(key) + 1 + (int)value_len + 1; /* * The <len> field includes the length of the <len> field, so @@ -311,21 +333,47 @@ add_pax_attr(struct archive_string *as, const char *key, const char *value) archive_strappend_char(as, ' '); archive_strcat(as, key); archive_strappend_char(as, '='); - archive_strcat(as, value); + archive_array_append(as, value, value_len); archive_strappend_char(as, '\n'); } +static void +archive_write_pax_header_xattr(struct pax *pax, const char *encoded_name, + const void *value, size_t value_len) +{ + struct archive_string s; + char *encoded_value; + + if (pax->flags & WRITE_LIBARCHIVE_XATTR) { + encoded_value = base64_encode((const char *)value, value_len); + + if (encoded_name != NULL && encoded_value != NULL) { + archive_string_init(&s); + archive_strcpy(&s, "LIBARCHIVE.xattr."); + archive_strcat(&s, encoded_name); + add_pax_attr(&(pax->pax_header), s.s, encoded_value); + archive_string_free(&s); + } + free(encoded_value); + } + if (pax->flags & WRITE_SCHILY_XATTR) { + archive_string_init(&s); + archive_strcpy(&s, "SCHILY.xattr."); + archive_strcat(&s, encoded_name); + add_pax_attr_binary(&(pax->pax_header), s.s, value, value_len); + archive_string_free(&s); + } +} + static int archive_write_pax_header_xattrs(struct archive_write *a, struct pax *pax, struct archive_entry *entry) { - struct archive_string s; int i = archive_entry_xattr_reset(entry); while (i--) { const char *name; const void *value; - char *encoded_value; char *url_encoded_name = NULL, *encoded_name = NULL; size_t size; int r; @@ -346,16 +394,9 @@ archive_write_pax_header_xattrs(struct archive_write *a, } } - encoded_value = base64_encode((const char *)value, size); + archive_write_pax_header_xattr(pax, encoded_name, + value, size); - if (encoded_name != NULL && encoded_value != NULL) { - archive_string_init(&s); - archive_strcpy(&s, "LIBARCHIVE.xattr."); - archive_strcat(&s, encoded_name); - add_pax_attr(&(pax->pax_header), s.s, encoded_value); - archive_string_free(&s); - } - free(encoded_value); } return (ARCHIVE_OK); } @@ -450,6 +491,45 @@ get_entry_symlink(struct archive_write *a, struct archive_entry *entry, return (ARCHIVE_OK); } +/* Add ACL to pax header */ +static int +add_pax_acl(struct archive_write *a, + struct archive_entry *entry, struct pax *pax, int flags) +{ + char *p; + const char *attr; + int acl_types; + + acl_types = archive_entry_acl_types(entry); + + if ((acl_types & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) + attr = "SCHILY.acl.ace"; + else if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) + attr = "SCHILY.acl.access"; + else if ((flags & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) + attr = "SCHILY.acl.default"; + else + return (ARCHIVE_FATAL); + + p = archive_entry_acl_to_text_l(entry, NULL, flags, pax->sconv_utf8); + if (p == NULL) { + if (errno == ENOMEM) { + archive_set_error(&a->archive, ENOMEM, "%s %s", + "Can't allocate memory for ", attr); + return (ARCHIVE_FATAL); + } + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, "%s %s %s", + "Can't translate ", attr, " to UTF-8"); + return(ARCHIVE_WARN); + } else if (*p != '\0') { + add_pax_attr(&(pax->pax_header), + attr, p); + free(p); + } + return(ARCHIVE_OK); +} + /* * TODO: Consider adding 'comment' and 'charset' fields to * archive_entry so that clients can specify them. Also, consider @@ -466,6 +546,7 @@ archive_write_pax_header(struct archive_write *a, const char *p; const char *suffix; int need_extension, r, ret; + int acl_types; int sparse_count; uint64_t sparse_total, real_size; struct pax *pax; @@ -709,7 +790,7 @@ archive_write_pax_header(struct archive_write *a, /* Copy entry so we can modify it as needed. */ #if defined(_WIN32) && !defined(__CYGWIN__) - /* Make sure the path separators in pahtname, hardlink and symlink + /* Make sure the path separators in pathname, hardlink and symlink * are all slash '/', not the Windows path separator '\'. */ entry_main = __la_win_entry_in_posix_pathseparator(entry_original); if (entry_main == entry_original) @@ -1017,16 +1098,6 @@ archive_write_pax_header(struct archive_write *a, if (!need_extension && p != NULL && *p != '\0') need_extension = 1; - /* If there are non-trivial ACL entries, we need an extension. */ - 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 (!need_extension && archive_entry_acl_count(entry_original, - ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) > 0) - need_extension = 1; - /* If there are extended attributes, we need an extension */ if (!need_extension && archive_entry_xattr_count(entry_original) > 0) need_extension = 1; @@ -1035,6 +1106,12 @@ archive_write_pax_header(struct archive_write *a, if (!need_extension && sparse_count > 0) need_extension = 1; + acl_types = archive_entry_acl_types(entry_original); + + /* If there are any ACL entries, we need an extension */ + if (!need_extension && acl_types != 0) + need_extension = 1; + /* * Libarchive used to include these in extended headers for * restricted pax format, but that confused people who @@ -1086,43 +1163,29 @@ archive_write_pax_header(struct archive_write *a, add_pax_attr(&(pax->pax_header), "SCHILY.fflags", p); /* I use star-compatible ACL attributes. */ - r = archive_entry_acl_text_l(entry_original, - ARCHIVE_ENTRY_ACL_TYPE_ACCESS | - ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID, - &p, NULL, pax->sconv_utf8); - if (r != 0) { - if (errno == ENOMEM) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory for " - "ACL.access"); + if ((acl_types & ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0) { + ret = add_pax_acl(a, entry_original, pax, + ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID | + ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA | + ARCHIVE_ENTRY_ACL_STYLE_COMPACT); + if (ret == ARCHIVE_FATAL) return (ARCHIVE_FATAL); - } - archive_set_error(&a->archive, - ARCHIVE_ERRNO_FILE_FORMAT, - "Can't translate ACL.access to UTF-8"); - ret = ARCHIVE_WARN; - } else if (p != NULL && *p != '\0') { - add_pax_attr(&(pax->pax_header), - "SCHILY.acl.access", p); } - r = archive_entry_acl_text_l(entry_original, - ARCHIVE_ENTRY_ACL_TYPE_DEFAULT | - ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID, - &p, NULL, pax->sconv_utf8); - if (r != 0) { - if (errno == ENOMEM) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory for " - "ACL.default"); + if (acl_types & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) { + ret = add_pax_acl(a, entry_original, pax, + ARCHIVE_ENTRY_ACL_TYPE_ACCESS | + ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID | + ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA); + if (ret == ARCHIVE_FATAL) + return (ARCHIVE_FATAL); + } + if (acl_types & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) { + ret = add_pax_acl(a, entry_original, pax, + ARCHIVE_ENTRY_ACL_TYPE_DEFAULT | + ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID | + ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA); + if (ret == ARCHIVE_FATAL) return (ARCHIVE_FATAL); - } - archive_set_error(&a->archive, - ARCHIVE_ERRNO_FILE_FORMAT, - "Can't translate ACL.default to UTF-8"); - ret = ARCHIVE_WARN; - } else if (p != NULL && *p != '\0') { - add_pax_attr(&(pax->pax_header), - "SCHILY.acl.default", p); } /* We use GNU-tar-compatible sparse attributes. */ diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_shar.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_shar.c index c033fb3..5be310a 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_shar.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_shar.c @@ -113,12 +113,11 @@ archive_write_set_format_shar(struct archive *_a) if (a->format_free != NULL) (a->format_free)(a); - shar = (struct shar *)malloc(sizeof(*shar)); + shar = (struct shar *)calloc(1, sizeof(*shar)); if (shar == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate shar data"); return (ARCHIVE_FATAL); } - memset(shar, 0, sizeof(*shar)); archive_string_init(&shar->work); archive_string_init(&shar->quoted_name); a->format_data = shar; diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_ustar.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_ustar.c index 484ab34..c54aeab 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_ustar.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_ustar.c @@ -114,9 +114,9 @@ static const char template_header[] = { '0','0','0','0','0','0', ' ','\0', /* gid, space-null termination: 8 bytes */ '0','0','0','0','0','0', ' ','\0', - /* size, space termation: 12 bytes */ + /* size, space termination: 12 bytes */ '0','0','0','0','0','0','0','0','0','0','0', ' ', - /* mtime, space termation: 12 bytes */ + /* mtime, space termination: 12 bytes */ '0','0','0','0','0','0','0','0','0','0','0', ' ', /* Initial checksum value: 8 spaces */ ' ',' ',' ',' ',' ',' ',' ',' ', @@ -184,13 +184,12 @@ archive_write_set_format_ustar(struct archive *_a) return (ARCHIVE_FATAL); } - ustar = (struct ustar *)malloc(sizeof(*ustar)); + ustar = (struct ustar *)calloc(1, sizeof(*ustar)); if (ustar == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate ustar data"); return (ARCHIVE_FATAL); } - memset(ustar, 0, sizeof(*ustar)); a->format_data = ustar; a->format_name = "ustar"; a->format_options = archive_write_ustar_options; @@ -307,7 +306,7 @@ archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry) * case getting WCS failed. On POSIX, this is a * normal operation. */ - if (p != NULL && p[strlen(p) - 1] != '/') { + if (p != NULL && p[0] != '\0' && p[strlen(p) - 1] != '/') { struct archive_string as; archive_string_init(&as); @@ -336,7 +335,7 @@ archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry) } #if defined(_WIN32) && !defined(__CYGWIN__) - /* Make sure the path separators in pahtname, hardlink and symlink + /* Make sure the path separators in pathname, hardlink and symlink * are all slash '/', not the Windows path separator '\'. */ entry_main = __la_win_entry_in_posix_pathseparator(entry); if (entry_main == NULL) { diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_v7tar.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_v7tar.c index 17efbaf..62b1522 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_v7tar.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_v7tar.c @@ -98,9 +98,9 @@ static const char template_header[] = { '0','0','0','0','0','0', ' ','\0', /* gid, space-null termination: 8 bytes */ '0','0','0','0','0','0', ' ','\0', - /* size, space termation: 12 bytes */ + /* size, space termination: 12 bytes */ '0','0','0','0','0','0','0','0','0','0','0', ' ', - /* mtime, space termation: 12 bytes */ + /* mtime, space termination: 12 bytes */ '0','0','0','0','0','0','0','0','0','0','0', ' ', /* Initial checksum value: 8 spaces */ ' ',' ',' ',' ',' ',' ',' ',' ', @@ -161,13 +161,12 @@ archive_write_set_format_v7tar(struct archive *_a) return (ARCHIVE_FATAL); } - v7tar = (struct v7tar *)malloc(sizeof(*v7tar)); + v7tar = (struct v7tar *)calloc(1, sizeof(*v7tar)); if (v7tar == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate v7tar data"); return (ARCHIVE_FATAL); } - memset(v7tar, 0, sizeof(*v7tar)); a->format_data = v7tar; a->format_name = "tar (non-POSIX)"; a->format_options = archive_write_v7tar_options; @@ -314,7 +313,7 @@ archive_write_v7tar_header(struct archive_write *a, struct archive_entry *entry) } #if defined(_WIN32) && !defined(__CYGWIN__) - /* Make sure the path separators in pahtname, hardlink and symlink + /* Make sure the path separators in pathname, hardlink and symlink * are all slash '/', not the Windows path separator '\'. */ entry_main = __la_win_entry_in_posix_pathseparator(entry); if (entry_main == NULL) { diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_warc.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_warc.c index ea66929..8b6daf9 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_warc.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_warc.c @@ -79,7 +79,7 @@ typedef enum { WT_RVIS, /* conversion, unsupported */ WT_CONV, - /* continutation, unsupported at the moment */ + /* continuation, unsupported at the moment */ WT_CONT, /* invalid type */ LAST_WT diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_xar.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_xar.c index 58ad9e0..3c617ec 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_xar.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_xar.c @@ -63,7 +63,7 @@ __FBSDID("$FreeBSD$"); * - When writing an XML element <link type="<file-type>">, <file-type> * which is a file type a symbolic link is referencing is always marked * as "broken". Xar utility uses stat(2) to get the file type, but, in - * libarcive format writer, we should not use it; if it is needed, we + * libarchive format writer, we should not use it; if it is needed, we * should get about it at archive_read_disk.c. * - It is possible to appear both <flags> and <ext2> elements. * Xar utility generates <flags> on BSD platform and <ext2> on Linux @@ -192,7 +192,7 @@ struct file { struct file *parent; /* parent directory entry */ /* * To manage sub directory files. - * We use 'chnext' a menber of struct file to chain. + * We use 'chnext' (a member of struct file) to chain. */ struct { struct file *first; @@ -258,7 +258,7 @@ struct xar { /* * The list of all file entries is used to manage struct file * objects. - * We use 'next' a menber of struct file to chain. + * We use 'next' (a member of struct file) to chain. */ struct { struct file *first; @@ -266,7 +266,7 @@ struct xar { } file_list; /* * The list of hard-linked file entries. - * We use 'hlnext' a menber of struct file to chain. + * We use 'hlnext' (a member of struct file) to chain. */ struct archive_rb_tree hardlink_rbtree; }; @@ -1227,7 +1227,7 @@ make_file_entry(struct archive_write *a, xmlTextWriterPtr writer, case AE_IFLNK: /* * xar utility has checked a file type, which - * a symblic-link file has referenced. + * a symbolic-link file has referenced. * For example: * <link type="directory">../ref/</link> * The symlink target file is "../ref/" and its @@ -1237,8 +1237,8 @@ make_file_entry(struct archive_write *a, xmlTextWriterPtr writer, * The symlink target file is "../f" and its * file type is a regular file. * - * But our implemention cannot do it, and then we - * always record that a attribute "type" is "borken", + * But our implementation cannot do it, and then we + * always record that a attribute "type" is "broken", * for example: * <link type="broken">foo/bar</link> * It means "foo/bar" is not reachable. @@ -1544,7 +1544,7 @@ make_toc(struct archive_write *a) } /* - * Start recoding TOC + * Start recording TOC */ r = xmlTextWriterStartElement(writer, BAD_CAST("xar")); if (r < 0) { @@ -1961,6 +1961,7 @@ file_free(struct file *file) archive_string_free(&(file->basename)); archive_string_free(&(file->symlink)); archive_string_free(&(file->script)); + archive_entry_free(file->entry); free(file); } @@ -2484,7 +2485,7 @@ file_connect_hardlink_files(struct xar *xar) archive_entry_set_nlink(target->entry, hl->nlink); if (hl->nlink > 1) /* It means this file is a hardlink - * targe itself. */ + * target itself. */ target->hardlink_target = target; for (nf = target->hlnext; nf != NULL; nf = nf->hlnext) { @@ -2913,7 +2914,7 @@ compression_init_encoder_xz(struct archive *a, *strm = lzma_init_data; #ifdef HAVE_LZMA_STREAM_ENCODER_MT if (threads > 1) { - bzero(&mt_options, sizeof(mt_options)); + memset(&mt_options, 0, sizeof(mt_options)); mt_options.threads = threads; mt_options.timeout = 300; mt_options.filters = lzmafilters; diff --git a/Utilities/cmlibarchive/libarchive/archive_write_set_format_zip.c b/Utilities/cmlibarchive/libarchive/archive_write_set_format_zip.c index 0b2c69b..a4ae229 100644 --- a/Utilities/cmlibarchive/libarchive/archive_write_set_format_zip.c +++ b/Utilities/cmlibarchive/libarchive/archive_write_set_format_zip.c @@ -592,7 +592,7 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) #if defined(_WIN32) && !defined(__CYGWIN__) - /* Make sure the path separators in pahtname, hardlink and symlink + /* Make sure the path separators in pathname, hardlink and symlink * are all slash '/', not the Windows path separator '\'. */ zip->entry = __la_win_entry_in_posix_pathseparator(entry); if (zip->entry == entry) @@ -878,7 +878,7 @@ archive_write_zip_header(struct archive_write *a, struct archive_entry *entry) || zip->entry_encryption == ENCRYPTION_WINZIP_AES256)) { memcpy(e, "\001\231\007\000\001\000AE", 8); - /* AES vendoer version AE-2 does not store a CRC. + /* AES vendor version AE-2 does not store a CRC. * WinZip 11 uses AE-1, which does store the CRC, * but it does not store the CRC when the file size * is less than 20 bytes. So we simulate what @@ -1013,7 +1013,7 @@ archive_write_zip_data(struct archive_write *a, const void *buff, size_t s) if (zip->entry_flags & ZIP_ENTRY_FLAG_ENCRYPTED) { switch (zip->entry_encryption) { case ENCRYPTION_TRADITIONAL: - /* Initialize traditoinal PKWARE encryption context. */ + /* Initialize traditional PKWARE encryption context. */ if (!zip->tctx_valid) { ret = init_traditional_pkware_encryption(a); if (ret != ARCHIVE_OK) @@ -1499,7 +1499,7 @@ trad_enc_update_keys(struct trad_enc_ctx *ctx, uint8_t c) } static uint8_t -trad_enc_decypt_byte(struct trad_enc_ctx *ctx) +trad_enc_decrypt_byte(struct trad_enc_ctx *ctx) { unsigned temp = ctx->keys[2] | 2; return (uint8_t)((temp * (temp ^ 1)) >> 8) & 0xff; @@ -1515,7 +1515,7 @@ trad_enc_encrypt_update(struct trad_enc_ctx *ctx, const uint8_t *in, for (i = 0; i < max; i++) { uint8_t t = in[i]; - out[i] = t ^ trad_enc_decypt_byte(ctx); + out[i] = t ^ trad_enc_decrypt_byte(ctx); trad_enc_update_keys(ctx, t); } return i; @@ -1626,7 +1626,7 @@ init_winzip_aes_encryption(struct archive_write *a) return (ARCHIVE_FAILED); } - /* Set a passowrd verification value after the 'salt'. */ + /* Set a password verification value after the 'salt'. */ salt[salt_len] = derived_key[key_len * 2]; salt[salt_len + 1] = derived_key[key_len * 2 + 1]; diff --git a/Utilities/cmlibarchive/libarchive/config_freebsd.h b/Utilities/cmlibarchive/libarchive/config_freebsd.h index 2073431..215e886 100644 --- a/Utilities/cmlibarchive/libarchive/config_freebsd.h +++ b/Utilities/cmlibarchive/libarchive/config_freebsd.h @@ -28,6 +28,7 @@ /* FreeBSD 5.0 and later have ACL and extattr support. */ #if __FreeBSD__ > 4 #define HAVE_ACL_CREATE_ENTRY 1 +#define HAVE_ACL_GET_FD_NP 1 #define HAVE_ACL_GET_LINK_NP 1 #define HAVE_ACL_GET_PERM_NP 1 #define HAVE_ACL_INIT 1 @@ -39,6 +40,7 @@ #define HAVE_EXTATTR_LIST_FILE 1 #define HAVE_EXTATTR_SET_FD 1 #define HAVE_EXTATTR_SET_FILE 1 +#define HAVE_STRUCT_XVFSCONF 1 #define HAVE_SYS_ACL_H 1 #define HAVE_SYS_EXTATTR_H 1 #endif diff --git a/Utilities/cmlibarchive/libarchive/libarchive-formats.5 b/Utilities/cmlibarchive/libarchive/libarchive-formats.5 index 9cec760..62359dd 100644 --- a/Utilities/cmlibarchive/libarchive/libarchive-formats.5 +++ b/Utilities/cmlibarchive/libarchive/libarchive-formats.5 @@ -24,7 +24,7 @@ .\" .\" $FreeBSD$ .\" -.Dd March 18, 2012 +.Dd December 27, 2016 .Dt LIBARCHIVE-FORMATS 5 .Os .Sh NAME @@ -191,8 +191,6 @@ and device numbers. .It Solaris extensions Libarchive recognizes ACL and extended attribute records written by Solaris tar. -Currently, libarchive only has support for old-style ACLs; the -newer NFSv4 ACLs are recognized but discarded. .El .Pp The first tar program appeared in Seventh Edition Unix in 1979. diff --git a/Utilities/cmlibarchive/libarchive/tar.5 b/Utilities/cmlibarchive/libarchive/tar.5 index 6e6f0c0..30b837d 100644 --- a/Utilities/cmlibarchive/libarchive/tar.5 +++ b/Utilities/cmlibarchive/libarchive/tar.5 @@ -1,4 +1,5 @@ .\" Copyright (c) 2003-2009 Tim Kientzle +.\" Copyright (c) 2016 Martin Matuska .\" All rights reserved. .\" .\" Redistribution and use in source and binary forms, with or without @@ -24,7 +25,7 @@ .\" .\" $FreeBSD$ .\" -.Dd December 23, 2011 +.Dd December 27, 2016 .Dt TAR 5 .Os .Sh NAME @@ -440,11 +441,11 @@ archives to store files much larger than the historic 8GB limit. Vendor-specific attributes used by Joerg Schilling's .Nm star implementation. -.It Cm SCHILY.acl.access , Cm SCHILY.acl.default -Stores the access and default ACLs as textual strings in a format +.It Cm SCHILY.acl.access , Cm SCHILY.acl.default, Cm SCHILY.acl.ace +Stores the access, default and NFSv4 ACLs as textual strings in a format that is an extension of the format specified by POSIX.1e draft 17. -In particular, each user or group access specification can include a fourth -colon-separated field with the numeric UID or GID. +In particular, each user or group access specification can include +an additional colon-separated field with the numeric UID or GID. This allows ACLs to be restored on systems that may not have complete user or group information available (such as when NIS/YP or LDAP services are temporarily unavailable). diff --git a/Utilities/cmlibarchive/libarchive/xxhash.c b/Utilities/cmlibarchive/libarchive/xxhash.c index 262fecb..6f5ba52 100644 --- a/Utilities/cmlibarchive/libarchive/xxhash.c +++ b/Utilities/cmlibarchive/libarchive/xxhash.c @@ -29,13 +29,13 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. You can contact the author at : - xxHash source repository : http://code.google.com/p/xxhash/ */ - #include "archive_platform.h" -#include "archive_xxhash.h" #include <stdlib.h> #include <string.h> +#include "archive_xxhash.h" + #ifdef HAVE_LIBLZ4 /*************************************** @@ -61,7 +61,7 @@ You can contact the author at : ** By default, xxHash library provides endian-independent Hash values, based on little-endian convention. ** Results are therefore identical for little-endian and big-endian CPU. ** This comes at a performance cost for big-endian CPU, since some swapping is required to emulate little-endian format. -** Should endian-independance be of no importance for your application, you may set the #define below to 1. +** Should endian-independence be of no importance for your application, you may set the #define below to 1. ** It will improve speed for Big-endian CPU. ** This option has no impact on Little_Endian CPU. */ |