From bedab702094c38a7aec2a44a7ba4adf886d100b0 Mon Sep 17 00:00:00 2001 From: mm Date: Sat, 11 Feb 2017 00:56:18 +0000 Subject: [PATCH] MFC r310866,310868,310870,311903,313074: Sync libarchive with vendor. MFC r310866: PR #771: Add NFSv4 ACL support to pax and restricted pax NFSv4 ACL information may now be stored to and restored from tar archives. ACL must be non-trivial and supported by the underlying filesystem, e.g. natively by ZFS or by UFS with the NFSv4 ACL enable flag set. MFC r310868: PR #843: Fix memory leak of struct archive_entry in cpio/cpio.c PR #851: Spelling fixes Fix two protoypes in manual page archive_read_disk.3 MFC r310870: Use __LA_DEPRECATED macro with functions deprecated in 379867e MFC r311903: #691: Support for SCHILY.xattr extended attributes #854: Spelling fixes Multiple fixes in ACL code: - prefer acl_set_fd_np() to acl_set_fd() - if acl_set_fd_np() fails, do no fallback to acl_set_file() - do not warn if trying to write ACLs to a filesystem without ACL support - fix id handling in archive_acl_(from_to)_text*() for NFSv4 ACLs MFC r313074: - support extracting NFSv4 ACLs from Solaris tar archives - bugfixes and optimizations in the ACL code - multiple fixes in the test suite - typo and other small bugfixes Security fixes: - cab reader: endless loop when parsing MSZIP signature (OSS-Fuzz 335) - LHA reader: heap-buffer-overflow in lha_read_file_header_1() (CVE-2017-5601) - LZ4 reader: null-pointer dereference in lz4_filter_read_legacy_stream() (OSS-Fuzz 453) - mtree reader: heap-buffer-overflow in detect_form() (OSS-Fuzz 421, 443) - WARC reader: heap-buffer-overflow in xstrpisotime() (OSS-Fuzz 382, 458) Memory leak fixes: - ACL support: free memory allocated by acl_get_qualifier() - disk writer: missing free in create_filesystem_object() - file reader: fd leak (Coverity 1016755) - gnutar writer: fix free in archive_write_gnutar_header() (Coverity 101675) - iso 9660 reader: missing free in parse_file_info() (partial Coverity 1016754) - program reader: missing free in __archive_read_program() - program writer: missing free in __archive_write_program_free() - xar reader: missing free in xar_cleanup() - xar reader: missing frees in expat_xmlattr_setup() (Coverity 1229979-1229981) - xar writer: missing free in file_free() - zip reader: missing free in zip_read_local_file_header() List of all libarchive issues at OSS-Fuzz: https://bugs.chromium.org/p/oss-fuzz/issues/list?can=1&q=libarchive Security: CVE-2017-5601 git-svn-id: svn://svn.freebsd.org/base/stable/10@313571 ccf9f872-aa2e-dd11-9fc8-001c23d0bc1f --- ObsoleteFiles.inc | 2 + contrib/libarchive/NEWS | 7 + contrib/libarchive/cpio/cpio.c | 1 + contrib/libarchive/libarchive/archive_acl.c | 1636 ++++++++++++----- .../libarchive/archive_acl_private.h | 22 +- contrib/libarchive/libarchive/archive_entry.c | 114 +- contrib/libarchive/libarchive/archive_entry.h | 63 +- .../libarchive/libarchive/archive_entry_acl.3 | 317 +++- .../libarchive/archive_entry_locale.h | 10 +- .../libarchive/archive_entry_strmode.c | 2 +- contrib/libarchive/libarchive/archive_match.c | 12 +- .../libarchive/libarchive/archive_platform.h | 19 +- .../libarchive/libarchive/archive_random.c | 2 +- contrib/libarchive/libarchive/archive_rb.c | 2 +- .../libarchive/libarchive/archive_read_disk.3 | 6 +- .../archive_read_disk_entry_from_file.c | 734 +++++++- .../libarchive/archive_read_disk_posix.c | 6 +- .../libarchive/archive_read_open_filename.c | 20 +- .../archive_read_support_filter_lz4.c | 11 +- .../archive_read_support_filter_lzop.c | 2 +- .../archive_read_support_filter_program.c | 2 + .../archive_read_support_format_7zip.c | 10 +- .../archive_read_support_format_cab.c | 2 + .../archive_read_support_format_cpio.c | 3 +- .../archive_read_support_format_iso9660.c | 40 +- .../archive_read_support_format_lha.c | 5 +- .../archive_read_support_format_mtree.c | 8 +- .../archive_read_support_format_rar.c | 2 +- .../archive_read_support_format_tar.c | 162 +- .../archive_read_support_format_warc.c | 6 +- .../archive_read_support_format_xar.c | 6 +- .../archive_read_support_format_zip.c | 16 +- .../libarchive/libarchive/archive_string.c | 26 +- .../libarchive/libarchive/archive_string.h | 4 + .../libarchive/archive_string_composition.h | 2 +- contrib/libarchive/libarchive/archive_write.c | 2 +- .../archive_write_add_filter_program.c | 1 + .../libarchive/archive_write_add_filter_xz.c | 2 +- .../libarchive/archive_write_disk_acl.c | 444 ++++- .../libarchive/archive_write_disk_posix.c | 62 +- .../libarchive/archive_write_open.3 | 11 + .../archive_write_set_format_7zip.c | 2 +- .../archive_write_set_format_gnutar.c | 8 +- .../archive_write_set_format_iso9660.c | 34 +- .../libarchive/archive_write_set_format_pax.c | 177 +- .../archive_write_set_format_warc.c | 2 +- .../libarchive/archive_write_set_format_xar.c | 15 +- .../libarchive/archive_write_set_format_zip.c | 10 +- .../libarchive/libarchive-formats.5 | 4 +- contrib/libarchive/libarchive/tar.5 | 11 +- contrib/libarchive/libarchive/test/main.c | 134 ++ contrib/libarchive/libarchive/test/test.h | 43 + .../libarchive/test/test_acl_nfs4.c | 126 +- .../libarchive/libarchive/test/test_acl_pax.c | 364 ++-- .../libarchive/test/test_acl_pax_nfs4.tar.uu | 129 ++ ...pax.tar.uu => test_acl_pax_posix1e.tar.uu} | 2 +- ...reebsd_nfs4.c => test_acl_platform_nfs4.c} | 474 ++++- ..._posix1e.c => test_acl_platform_posix1e.c} | 431 ++++- .../libarchive/test/test_acl_posix1e.c | 144 +- .../libarchive/test/test_acl_text.c | 462 +++++ .../test/test_archive_read_add_passphrase.c | 2 +- .../libarchive/test/test_archive_string.c | 24 + .../libarchive/test/test_compat_gtar.c | 2 + .../test/test_compat_solaris_tar_acl.c | 297 ++- .../test/test_compat_solaris_tar_acl.tar.uu | 220 ++- .../libarchive/test/test_compat_star_acl.c | 321 ++++ .../test/test_compat_star_acl_nfs4.tar.uu | 231 +++ .../test/test_compat_star_acl_posix1e.c | 215 --- .../libarchive/test/test_compat_uudecode.c | 2 +- .../libarchive/libarchive/test/test_fuzz.c | 4 + .../test_read_disk_directory_traversals.c | 12 +- .../libarchive/test/test_read_filter_lzop.c | 9 +- .../test_read_filter_lzop_multiple_parts.c | 8 +- .../libarchive/test/test_read_format_7zip.c | 2 +- .../test/test_read_format_cpio_afio.c | 2 +- .../test/test_read_format_isorr_bz2.c | 2 +- .../libarchive/test/test_read_format_zip.c | 5 + .../test_read_format_zip_comment_stored.c | 2 + .../test/test_read_format_zip_filename.c | 2 +- .../test/test_read_format_zip_mac_metadata.c | 2 + .../test/test_read_format_zip_malformed.c | 1 + .../test/test_read_format_zip_nested.c | 2 + .../test/test_read_format_zip_padded.c | 2 + .../test/test_read_format_zip_sfx.c | 2 + ...d_format_zip_traditional_encryption_data.c | 4 +- .../test/test_read_format_zip_winzip_aes.c | 2 +- .../test_read_format_zip_winzip_aes_large.c | 2 +- .../test/test_read_pax_schily_xattr.c | 70 + .../test/test_read_pax_schily_xattr.tar.uu | 231 +++ .../libarchive/test/test_sparse_basic.c | 2 +- .../test/test_write_disk_secure746.c | 3 + .../libarchive/test/test_write_filter_lz4.c | 2 + .../libarchive/test/test_write_filter_lzop.c | 6 +- .../test/test_write_format_iso9660.c | 2 +- .../test/test_write_format_iso9660_zisofs.c | 2 +- .../test/test_write_format_zip_large.c | 1 + .../test/test_write_format_zip_zip64.c | 2 + contrib/libarchive/libarchive/xxhash.c | 5 +- .../tar/test/test_option_uid_uname.c | 8 +- contrib/libarchive/tar/util.c | 1 + lib/libarchive/config_freebsd.h | 1 + lib/libarchive/tests/Makefile | 13 +- 102 files changed, 6338 insertions(+), 1766 deletions(-) create mode 100644 contrib/libarchive/libarchive/test/test_acl_pax_nfs4.tar.uu rename contrib/libarchive/libarchive/test/{test_acl_pax.tar.uu => test_acl_pax_posix1e.tar.uu} (99%) rename contrib/libarchive/libarchive/test/{test_acl_freebsd_nfs4.c => test_acl_platform_nfs4.c} (55%) rename contrib/libarchive/libarchive/test/{test_acl_freebsd_posix1e.c => test_acl_platform_posix1e.c} (52%) create mode 100644 contrib/libarchive/libarchive/test/test_acl_text.c create mode 100644 contrib/libarchive/libarchive/test/test_compat_star_acl.c create mode 100644 contrib/libarchive/libarchive/test/test_compat_star_acl_nfs4.tar.uu delete mode 100644 contrib/libarchive/libarchive/test/test_compat_star_acl_posix1e.c create mode 100644 contrib/libarchive/libarchive/test/test_read_pax_schily_xattr.c create mode 100644 contrib/libarchive/libarchive/test/test_read_pax_schily_xattr.tar.uu diff --git a/ObsoleteFiles.inc b/ObsoleteFiles.inc index 51b7ed252..cca3c71f4 100644 --- a/ObsoleteFiles.inc +++ b/ObsoleteFiles.inc @@ -38,6 +38,8 @@ # xargs -n1 | sort | uniq -d; # done +# 20170211: libarchive ACL pax test renamed to test_acl_pax_posix1e.tar.uu +OLD_FILES+=usr/tests/lib/libarchive/test_acl_pax.tar.uu # 20161229: Three files from gnop tests consolidated into one OLD_FILES+=usr/tests/sys/geom/class/nop/1_test OLD_FILES+=usr/tests/sys/geom/class/nop/2_test diff --git a/contrib/libarchive/NEWS b/contrib/libarchive/NEWS index 6f16b889a..7b5c31f75 100644 --- a/contrib/libarchive/NEWS +++ b/contrib/libarchive/NEWS @@ -1,3 +1,10 @@ +Jan 29, 2017: Limited NFSv4 ACL support for Mac OS (Darwin) + +Jan 10, 2017: POSIX.1e and NFSv4 ACL support for Solaris and derivates + +Dec 27, 2016: NFSv4 ACL read and write support for pax + Deprecated functions: archive_entry_acl_text(), archive_entry_acl_text_w() + Oct 26, 2016: Remove liblzmadec support Oct 23, 2016: libarchive 3.2.2 released diff --git a/contrib/libarchive/cpio/cpio.c b/contrib/libarchive/cpio/cpio.c index a7a747a6d..30c9ad348 100644 --- a/contrib/libarchive/cpio/cpio.c +++ b/contrib/libarchive/cpio/cpio.c @@ -703,6 +703,7 @@ file_to_archive(struct cpio *cpio, const char *srcpath) lafe_warnc(0, "%s", archive_error_string(cpio->archive_read_disk)); if (r <= ARCHIVE_FAILED) { + archive_entry_free(entry); cpio->return_value = 1; return (r); } diff --git a/contrib/libarchive/libarchive/archive_acl.c b/contrib/libarchive/libarchive/archive_acl.c index 3653d6fc7..1e9ddbb24 100644 --- a/contrib/libarchive/libarchive/archive_acl.c +++ b/contrib/libarchive/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,23 +56,31 @@ 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); void @@ -339,6 +348,15 @@ archive_acl_count(struct archive_acl *acl, int want_type) return (count); } +/* + * 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 @@ -375,8 +393,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; @@ -441,130 +459,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); - if (count == 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 (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) @@ -577,8 +738,8 @@ 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) { if (prefix != NULL) { wcscpy(*wp, prefix); @@ -588,6 +749,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"); @@ -595,6 +760,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"); @@ -609,154 +778,210 @@ 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 { + /* NFS4 ACL perms */ + *(*wp)++ = (perm & (ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_LIST_DIRECTORY)) ? L'r' : L'-'; + *(*wp)++ = (perm & (ARCHIVE_ENTRY_ACL_WRITE_DATA | + ARCHIVE_ENTRY_ACL_ADD_FILE)) ? L'w' : L'-'; + *(*wp)++ = (perm & ARCHIVE_ENTRY_ACL_EXECUTE) ? L'x' : L'-'; + *(*wp)++ = (perm & (ARCHIVE_ENTRY_ACL_APPEND_DATA | + ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY)) ? L'p' : L'-'; + *(*wp)++ = (perm & ARCHIVE_ENTRY_ACL_DELETE) ? L'd' : L'-'; + *(*wp)++ = (perm & + ARCHIVE_ENTRY_ACL_DELETE_CHILD) ? L'D' : L'-'; + *(*wp)++ = (perm & + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES) ? L'a' : L'-'; + *(*wp)++ = (perm & + ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES) ? L'A' : L'-'; + *(*wp)++ = (perm & + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS) ? L'R' : L'-'; + *(*wp)++ = (perm & + ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS) ? L'W' : L'-'; + *(*wp)++ = (perm & ARCHIVE_ENTRY_ACL_READ_ACL) ? L'c' : L'-'; + *(*wp)++ = (perm & ARCHIVE_ENTRY_ACL_WRITE_ACL) ? L'C' : L'-'; + *(*wp)++ = (perm & + ARCHIVE_ENTRY_ACL_WRITE_OWNER) ? L'o' : L'-'; + *(*wp)++ = (perm & + ARCHIVE_ENTRY_ACL_SYNCHRONIZE) ? L's' : L'-'; + *(*wp)++ = L':'; + *(*wp)++ = (perm & + ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT) ? L'f' : L'-'; + *(*wp)++ = (perm & + ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT) ? L'd' : L'-'; + *(*wp)++ = (perm & + ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY) ? L'i' : L'-'; + *(*wp)++ = (perm & + ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT) ? L'n' : L'-'; + *(*wp)++ = (perm & + ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS) ? L'S' : L'-'; + *(*wp)++ = (perm & + ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS) ? L'F' : L'-'; + *(*wp)++ = (perm & + ARCHIVE_ENTRY_ACL_ENTRY_INHERITED) ? L'I' : 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 (name == NULL || (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 @@ -770,8 +995,8 @@ 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) { if (prefix != NULL) { strcpy(*p, prefix); @@ -781,6 +1006,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"); @@ -788,6 +1017,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"); @@ -802,48 +1035,147 @@ 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 { + /* NFS4 ACL perms */ + *(*p)++ = (perm & (ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_LIST_DIRECTORY)) ? 'r' : '-'; + *(*p)++ = (perm & (ARCHIVE_ENTRY_ACL_WRITE_DATA | + ARCHIVE_ENTRY_ACL_ADD_FILE)) ? 'w' : '-'; + *(*p)++ = (perm & (ARCHIVE_ENTRY_ACL_EXECUTE)) ? 'x' : '-'; + *(*p)++ = (perm & (ARCHIVE_ENTRY_ACL_APPEND_DATA | + ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY)) ? 'p' : '-'; + *(*p)++ = (perm & ARCHIVE_ENTRY_ACL_DELETE) ? 'd' : '-'; + *(*p)++ = (perm & ARCHIVE_ENTRY_ACL_DELETE_CHILD) ? 'D' : '-'; + *(*p)++ = (perm & + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES) ? 'a' : '-'; + *(*p)++ = (perm & + ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES) ? 'A' : '-'; + *(*p)++ = (perm & + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS) ? 'R' : '-'; + *(*p)++ = (perm & + ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS) ? 'W' : '-'; + *(*p)++ = (perm & + ARCHIVE_ENTRY_ACL_READ_ACL) ? 'c' : '-'; + *(*p)++ = (perm & + ARCHIVE_ENTRY_ACL_WRITE_ACL) ? 'C' : '-'; + *(*p)++ = (perm & + ARCHIVE_ENTRY_ACL_WRITE_OWNER) ? 'o' : '-'; + *(*p)++ = (perm & + ARCHIVE_ENTRY_ACL_SYNCHRONIZE) ? 's' : '-'; + *(*p)++ = ':'; + *(*p)++ = (perm & + ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT) ? 'f' : '-'; + *(*p)++ = (perm & + ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT) ? 'd' : '-'; + *(*p)++ = (perm & + ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY) ? 'i' : '-'; + *(*p)++ = (perm & + ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT) ? 'n' : '-'; + *(*p)++ = (perm & + ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS) ? 'S' : '-'; + *(*p)++ = (perm & + ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS) ? 'F' : '-'; + *(*p)++ = (perm & + ARCHIVE_ENTRY_ACL_ENTRY_INHERITED) ? 'I' : '-'; + *(*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; - int fields, n; - int type, tag, permset, id; + const wchar_t *s, *st; + + 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. @@ -852,7 +1184,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; } @@ -860,78 +1192,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); } /* @@ -977,16 +1441,128 @@ 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; + + if (start >= end) + return (0); + 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; + + if (start >= end) + return (0); + 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); @@ -1033,46 +1609,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, @@ -1082,7 +1660,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; } @@ -1090,72 +1668,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, @@ -1164,7 +1867,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); } @@ -1229,6 +1937,118 @@ ismode(const char *start, const char *end, int *permset) 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(const char *start, const char *end, int *permset) +{ + const char *p; + + if (start >= end) + return (0); + 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; + + if (start >= end) + return (0); + 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 @@ -1264,25 +2084,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/contrib/libarchive/libarchive/archive_acl_private.h b/contrib/libarchive/libarchive/archive_acl_private.h index 1421adbf8..ef0b0234c 100644 --- a/contrib/libarchive/libarchive/archive_acl_private.h +++ b/contrib/libarchive/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/contrib/libarchive/libarchive/archive_entry.c b/contrib/libarchive/libarchive/archive_entry.c index f24002564..556c402af 100644 --- a/contrib/libarchive/libarchive/archive_entry.c +++ b/contrib/libarchive/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 @@ -1446,7 +1447,7 @@ archive_entry_acl_add_entry_w(struct archive_entry *entry, int archive_entry_acl_types(struct archive_entry *entry) { - return ((&entry->acl)->acl_types); + return (archive_acl_types(&entry->acl)); } /* @@ -1486,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/contrib/libarchive/libarchive/archive_entry.h b/contrib/libarchive/libarchive/archive_entry.h index 27c473e5e..42180c451 100644 --- a/contrib/libarchive/libarchive/archive_entry.h +++ b/contrib/libarchive/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 @@ -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,43 @@ __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 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 + +__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 *); diff --git a/contrib/libarchive/libarchive/archive_entry_acl.3 b/contrib/libarchive/libarchive/archive_entry_acl.3 index e85c4ded1..93707d1ff 100644 --- a/contrib/libarchive/libarchive/archive_entry_acl.3 +++ b/contrib/libarchive/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 December 27, 2016 .Dt ARCHIVE_ENTRY_ACL 3 .Os .Sh NAME @@ -30,10 +31,13 @@ .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 @@ -63,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" @@ -84,33 +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 @@ -122,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 @@ -132,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. @@ -153,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 @@ -182,19 +362,50 @@ 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 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 @@ -205,11 +416,20 @@ an ACL already contains POSIX.1e or NFSv4 ACL entries. 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 @@ -224,23 +444,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/contrib/libarchive/libarchive/archive_entry_locale.h b/contrib/libarchive/libarchive/archive_entry_locale.h index 02e024ae2..44550c51e 100644 --- a/contrib/libarchive/libarchive/archive_entry_locale.h +++ b/contrib/libarchive/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/contrib/libarchive/libarchive/archive_entry_strmode.c b/contrib/libarchive/libarchive/archive_entry_strmode.c index 8d7006a05..d80a7d431 100644 --- a/contrib/libarchive/libarchive/archive_entry_strmode.c +++ b/contrib/libarchive/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/contrib/libarchive/libarchive/archive_match.c b/contrib/libarchive/libarchive/archive_match.c index 0719cbd54..be72066ea 100644 --- a/contrib/libarchive/libarchive/archive_match.c +++ b/contrib/libarchive/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) @@ -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/contrib/libarchive/libarchive/archive_platform.h b/contrib/libarchive/libarchive/archive_platform.h index 76816c4d7..31383db68 100644 --- a/contrib/libarchive/libarchive/archive_platform.h +++ b/contrib/libarchive/libarchive/archive_platform.h @@ -147,8 +147,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 , 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 /* diff --git a/contrib/libarchive/libarchive/archive_random.c b/contrib/libarchive/libarchive/archive_random.c index a20b9b111..357f9733a 100644 --- a/contrib/libarchive/libarchive/archive_random.c +++ b/contrib/libarchive/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/contrib/libarchive/libarchive/archive_rb.c b/contrib/libarchive/libarchive/archive_rb.c index 5b5da2034..cf58ac335 100644 --- a/contrib/libarchive/libarchive/archive_rb.c +++ b/contrib/libarchive/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/contrib/libarchive/libarchive/archive_read_disk.3 b/contrib/libarchive/libarchive/archive_read_disk.3 index 525dc59cb..2a5c1305e 100644 --- a/contrib/libarchive/libarchive/archive_read_disk.3 +++ b/contrib/libarchive/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/contrib/libarchive/libarchive/archive_read_disk_entry_from_file.c b/contrib/libarchive/libarchive/archive_read_disk_entry_from_file.c index e9fb8ba30..63aa6171f 100644 --- a/contrib/libarchive/libarchive/archive_read_disk_entry_from_file.c +++ b/contrib/libarchive/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$"); #ifdef HAVE_SYS_ACL_H #include #endif +#ifdef HAVE_DARWIN_ACL +#include +#include +#include +#endif #ifdef HAVE_SYS_EXTATTR_H #include #endif @@ -117,6 +123,15 @@ __FBSDID("$FreeBSD$"); #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 *, @@ -404,17 +419,38 @@ 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 -#ifdef HAVE_POSIX_ACL +#if HAVE_SUN_ACL +static int +sun_acl_is_trivial(acl_t *, mode_t, int *trivialp); +#endif + +#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_SUN_ACL + acl_t *acl; +#else + acl_t acl; +#endif int r; accpath = archive_entry_sourcepath(entry); @@ -439,17 +475,20 @@ setup_acls(struct archive_read_disk *a, acl = NULL; -#ifdef ACL_TYPE_NFS4 - /* Try NFS4 ACL first. */ +#if HAVE_NFS4_ACL + /* Try NFSv4 ACL first. */ if (*fd >= 0) -#if HAVE_ACL_GET_FD_NP - acl = acl_get_fd_np(*fd, ACL_TYPE_NFS4); +#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)) @@ -458,12 +497,24 @@ setup_acls(struct archive_read_disk *a, acl = NULL; #endif else - acl = acl_get_file(accpath, ACL_TYPE_NFS4); +#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 - if (acl != NULL && acl_is_trivial_np(acl, &r) == 0) { - /* Ignore "trivial" ACLs that just mirror the file mode. */ - if (r) { + +#if HAVE_ACL_IS_TRIVIAL_NP || HAVE_SUN_ACL + /* Ignore "trivial" ACLs that just mirror the file mode. */ + 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; /* @@ -473,17 +524,35 @@ setup_acls(struct archive_read_disk *a, return (ARCHIVE_OK); } } -#endif +#endif /* HAVE_ACL_IS_TRIVIAL_NP || HAVE_SUN_ACL */ if (acl != NULL) { r = translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4); acl_free(acl); if (r != ARCHIVE_OK) { archive_set_error(&a->archive, errno, +#if HAVE_SUN_ACL + "Couldn't translate ACLs: %s", accpath); +#else "Couldn't translate NFSv4 ACLs: %s", accpath); +#endif } +#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_count(entry, + ARCHIVE_ENTRY_ACL_TYPE_NFS4) > 0) + add_trivial_nfs4_acl(entry); +#endif return (r); } -#endif /* ACL_TYPE_NFS4 */ +#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) @@ -512,8 +581,7 @@ setup_acls(struct archive_read_disk *a, #endif if (acl != NULL) { - r = 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) { @@ -525,6 +593,11 @@ setup_acls(struct archive_read_disk *a, /* 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) { r = translate_acl(a, entry, acl, @@ -538,68 +611,560 @@ setup_acls(struct archive_read_disk *a, } } } +#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; + int archive_perm; + 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 +#if HAVE_NFS4_ACL +/* + * Translate system NFSv4 inheritance flags into libarchive internal structure + */ static struct { - int archive_inherit; - int platform_inherit; + int archive_inherit; + 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, + * incuding 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; - acl_flagset_t acl_flagset; int brand; +#endif +#if HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL + acl_flagset_t acl_flagset; #endif acl_entry_t acl_entry; acl_permset_t acl_permset; int i, entry_acl_type; 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. @@ -634,14 +1199,19 @@ translate_acl(struct archive_read_disk *a, } #endif - s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry); if (s == -1) { archive_set_error(&a->archive, errno, "Failed to get first ACL entry"); return (ARCHIVE_WARN); } - while (s == 1) { + +#if HAVE_DARWIN_ACL + while (s == 0) +#else /* FreeBSD, Linux */ + while (s == 1) +#endif + { ae_id = -1; ae_name = NULL; ae_perm = 0; @@ -652,14 +1222,25 @@ translate_acl(struct archive_read_disk *a, 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: @@ -674,21 +1255,44 @@ 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; } +#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 +#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 */ @@ -715,6 +1319,7 @@ translate_acl(struct archive_read_disk *a, "Invalid NFSv4 ACL entry type"); return (ARCHIVE_WARN); } +#endif /* HAVE_ACL_TYPE_NFS4 */ /* * Libarchive stores "flag" (NFSv4 inheritance bits) @@ -727,7 +1332,7 @@ translate_acl(struct archive_read_disk *a, "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) { + 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) { @@ -737,9 +1342,9 @@ translate_acl(struct archive_read_disk *a, return (ARCHIVE_WARN); } else if (r) ae_perm |= acl_inherit_map[i].archive_inherit; - } + } } -#endif +#endif /* HAVE_ACL_TYPE_NFS4 || HAVE_DARWIN_ACL */ if (acl_get_permset(acl_entry, &acl_permset) != 0) { archive_set_error(&a->archive, errno, @@ -765,15 +1370,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) @@ -783,7 +1391,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) || \ diff --git a/contrib/libarchive/libarchive/archive_read_disk_posix.c b/contrib/libarchive/libarchive/archive_read_disk_posix.c index bc7fad1d9..b89370421 100644 --- a/contrib/libarchive/libarchive/archive_read_disk_posix.c +++ b/contrib/libarchive/libarchive/archive_read_disk_posix.c @@ -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 @@ -1656,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; @@ -1944,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 diff --git a/contrib/libarchive/libarchive/archive_read_open_filename.c b/contrib/libarchive/libarchive/archive_read_open_filename.c index b2d52aaae..64b017976 100644 --- a/contrib/libarchive/libarchive/archive_read_open_filename.c +++ b/contrib/libarchive/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/contrib/libarchive/libarchive/archive_read_support_filter_lz4.c b/contrib/libarchive/libarchive/archive_read_support_filter_lz4.c index 37b2f5900..663e2d3d6 100644 --- a/contrib/libarchive/libarchive/archive_read_support_filter_lz4.c +++ b/contrib/libarchive/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; @@ -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/contrib/libarchive/libarchive/archive_read_support_filter_lzop.c b/contrib/libarchive/libarchive/archive_read_support_filter_lzop.c index 44ac9964a..a1c392f4f 100644 --- a/contrib/libarchive/libarchive/archive_read_support_filter_lzop.c +++ b/contrib/libarchive/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/contrib/libarchive/libarchive/archive_read_support_filter_program.c b/contrib/libarchive/libarchive/archive_read_support_filter_program.c index 66dc2f424..b8bf12886 100644 --- a/contrib/libarchive/libarchive/archive_read_support_filter_program.c +++ b/contrib/libarchive/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/contrib/libarchive/libarchive/archive_read_support_format_7zip.c b/contrib/libarchive/libarchive/archive_read_support_format_7zip.c index f8d52fb71..3387eaf7e 100644 --- a/contrib/libarchive/libarchive/archive_read_support_format_7zip.c +++ b/contrib/libarchive/libarchive/archive_read_support_format_7zip.c @@ -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; @@ -3288,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; @@ -3506,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) { @@ -3591,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/contrib/libarchive/libarchive/archive_read_support_format_cab.c b/contrib/libarchive/libarchive/archive_read_support_format_cab.c index 2bdc1e285..e2f8c6b70 100644 --- a/contrib/libarchive/libarchive/archive_read_support_format_cab.c +++ b/contrib/libarchive/libarchive/archive_read_support_format_cab.c @@ -1495,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) diff --git a/contrib/libarchive/libarchive/archive_read_support_format_cpio.c b/contrib/libarchive/libarchive/archive_read_support_format_cpio.c index 2a5a829c1..e19c7110f 100644 --- a/contrib/libarchive/libarchive/archive_read_support_format_cpio.c +++ b/contrib/libarchive/libarchive/archive_read_support_format_cpio.c @@ -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 && memcmp((const char *)h, "TRAILER!!!", + 11) == 0) { /* TODO: Store file location of start of block. */ archive_clear_error(&a->archive); return (ARCHIVE_EOF); diff --git a/contrib/libarchive/libarchive/archive_read_support_format_iso9660.c b/contrib/libarchive/libarchive/archive_read_support_format_iso9660.c index 3807abd62..ebbfc2fa5 100644 --- a/contrib/libarchive/libarchive/archive_read_support_format_iso9660.c +++ b/contrib/libarchive/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/contrib/libarchive/libarchive/archive_read_support_format_lha.c b/contrib/libarchive/libarchive/archive_read_support_format_lha.c index a7f1d8d94..d77a7c2e4 100644 --- a/contrib/libarchive/libarchive/archive_read_support_format_lha.c +++ b/contrib/libarchive/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,7 +1714,7 @@ 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 #if defined(_MSC_VER) && _MSC_VER >= 1400 /* Visual Studio */ # define bswap16(x) _byteswap_ushort(x) diff --git a/contrib/libarchive/libarchive/archive_read_support_format_mtree.c b/contrib/libarchive/libarchive/archive_read_support_format_mtree.c index 02c12517a..179f1615a 100644 --- a/contrib/libarchive/libarchive/archive_read_support_format_mtree.c +++ b/contrib/libarchive/libarchive/archive_read_support_format_mtree.c @@ -715,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. */ @@ -1019,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); diff --git a/contrib/libarchive/libarchive/archive_read_support_format_rar.c b/contrib/libarchive/libarchive/archive_read_support_format_rar.c index 9c9f6f12e..1e9849fdd 100644 --- a/contrib/libarchive/libarchive/archive_read_support_format_rar.c +++ b/contrib/libarchive/libarchive/archive_read_support_format_rar.c @@ -906,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/contrib/libarchive/libarchive/archive_read_support_format_tar.c b/contrib/libarchive/libarchive/archive_read_support_format_tar.c index 4f69c6ee5..446d005ff 100644 --- a/contrib/libarchive/libarchive/archive_read_support_format_tar.c +++ b/contrib/libarchive/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 @@ -203,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 *); @@ -938,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; @@ -983,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)", @@ -1016,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, @@ -1478,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); @@ -1559,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)); @@ -1633,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); @@ -1758,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. @@ -1773,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; @@ -1876,53 +1946,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))); @@ -1943,6 +1980,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); diff --git a/contrib/libarchive/libarchive/archive_read_support_format_warc.c b/contrib/libarchive/libarchive/archive_read_support_format_warc.c index a287fc2a0..30cdaf9db 100644 --- a/contrib/libarchive/libarchive/archive_read_support_format_warc.c +++ b/contrib/libarchive/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 @@ -534,7 +534,7 @@ xstrpisotime(const char *s, char **endptr) /* as a courtesy to our callers, and since this is a non-standard * routine, we skip leading whitespace */ - while (isspace((unsigned char)*s)) + while (isblank((unsigned char)*s)) ++s; /* read year */ @@ -562,7 +562,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--; diff --git a/contrib/libarchive/libarchive/archive_read_support_format_xar.c b/contrib/libarchive/libarchive/archive_read_support_format_xar.c index 47ed064bc..d3002af71 100644 --- a/contrib/libarchive/libarchive/archive_read_support_format_xar.c +++ b/contrib/libarchive/libarchive/archive_read_support_format_xar.c @@ -933,6 +933,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; @@ -3047,7 +3048,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; @@ -3171,6 +3172,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/contrib/libarchive/libarchive/archive_read_support_format_zip.c b/contrib/libarchive/libarchive/archive_read_support_format_zip.c index 1aa74458e..53373ff9f 100644 --- a/contrib/libarchive/libarchive/archive_read_support_format_zip.c +++ b/contrib/libarchive/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); } @@ -710,7 +710,7 @@ process_extra(struct archive_read *a, const char *p, size_t extra_length, struct 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 = @@ -905,6 +905,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); @@ -915,6 +916,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); } } } @@ -1518,7 +1520,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, @@ -1627,7 +1629,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); @@ -1709,7 +1711,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); diff --git a/contrib/libarchive/libarchive/archive_string.c b/contrib/libarchive/libarchive/archive_string.c index cf10f093b..f738c549f 100644 --- a/contrib/libarchive/libarchive/archive_string.c +++ b/contrib/libarchive/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) { @@ -597,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) { @@ -1248,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. */ @@ -1261,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) { @@ -1726,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 * @@ -2220,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. */ @@ -2554,7 +2560,7 @@ 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 legal Unicode * values. @@ -2903,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 @@ -3437,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) { @@ -3947,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) { @@ -4079,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/contrib/libarchive/libarchive/archive_string.h b/contrib/libarchive/libarchive/archive_string.h index 60ebf0e5a..f5953d008 100644 --- a/contrib/libarchive/libarchive/archive_string.h +++ b/contrib/libarchive/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 diff --git a/contrib/libarchive/libarchive/archive_string_composition.h b/contrib/libarchive/libarchive/archive_string_composition.h index be41e3365..8902ac1f7 100644 --- a/contrib/libarchive/libarchive/archive_string_composition.h +++ b/contrib/libarchive/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/contrib/libarchive/libarchive/archive_write.c b/contrib/libarchive/libarchive/archive_write.c index f5a9f61be..e441dbe1f 100644 --- a/contrib/libarchive/libarchive/archive_write.c +++ b/contrib/libarchive/libarchive/archive_write.c @@ -231,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/contrib/libarchive/libarchive/archive_write_add_filter_program.c b/contrib/libarchive/libarchive/archive_write_add_filter_program.c index 31a1b6f96..55b5e8ecd 100644 --- a/contrib/libarchive/libarchive/archive_write_add_filter_program.c +++ b/contrib/libarchive/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/contrib/libarchive/libarchive/archive_write_add_filter_xz.c b/contrib/libarchive/libarchive/archive_write_add_filter_xz.c index 46a6c38aa..b0f25a6ef 100644 --- a/contrib/libarchive/libarchive/archive_write_add_filter_xz.c +++ b/contrib/libarchive/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/contrib/libarchive/libarchive/archive_write_disk_acl.c b/contrib/libarchive/libarchive/archive_write_disk_acl.c index e47384a6e..311aebf03 100644 --- a/contrib/libarchive/libarchive/archive_write_disk_acl.c +++ b/contrib/libarchive/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 #endif +#if HAVE_DARWIN_ACL +#include +#endif #ifdef HAVE_ERRNO_H #include #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 */ + /* Simultaeous 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); } +/* + * Translate system ACL permissions into libarchive internal structure + */ static struct { int archive_perm; 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,34 +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 +#if HAVE_NFS4_ACL +/* + * Translate system NFSv4 inheritance flags into libarchive internal structure + */ static struct { int archive_inherit; 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; - int r; +#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; @@ -152,32 +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) { +#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: - acl_set_tag_type(acl_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: + 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; @@ -190,11 +425,13 @@ 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: archive_set_error(a, ARCHIVE_ERRNO_MISC, "Unknown ACL tag"); @@ -202,9 +439,45 @@ set_acl(struct archive *a, int fd, const char *name, 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: r = acl_set_entry_type_np(acl_entry, ACL_ENTRY_TYPE_ALLOW); break; @@ -221,20 +494,35 @@ set_acl(struct archive *a, int fd, const char *name, case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT: // These don't translate directly into the system ACL. break; +#endif /* !HAVE_SUN_ACL */ default: archive_set_error(a, ARCHIVE_ERRNO_MISC, "Unknown ACL entry type"); ret = ARCHIVE_FAILED; goto exit_free; } + 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 +#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"); @@ -247,9 +535,13 @@ set_acl(struct archive *a, int fd, const char *name, 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) + 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, @@ -257,10 +549,20 @@ set_acl(struct archive *a, int fd, const char *name, ret = ARCHIVE_FAILED; goto exit_free; } +#endif + } } -#ifdef ACL_TYPE_NFS4 - if (acl_type == ACL_TYPE_NFS4) { +#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 */ @@ -276,8 +578,13 @@ set_acl(struct archive *a, int fd, const char *name, ret = ARCHIVE_FAILED; goto exit_free; } - for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) { +#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, @@ -285,38 +592,63 @@ set_acl(struct archive *a, int fd, const char *name, 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/contrib/libarchive/libarchive/archive_write_disk_posix.c b/contrib/libarchive/libarchive/archive_write_disk_posix.c index c05059a14..a799524d4 100644 --- a/contrib/libarchive/libarchive/archive_write_disk_posix.c +++ b/contrib/libarchive/libarchive/archive_write_disk_posix.c @@ -110,6 +110,18 @@ __FBSDID("$FreeBSD$"); #include #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 #if TARGET_OS_MAC && !TARGET_OS_EMBEDDED && HAVE_QUARANTINE_H @@ -308,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) /* @@ -323,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" @@ -632,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) @@ -1247,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. */ @@ -1352,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); @@ -1425,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); @@ -1690,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: @@ -2065,6 +2092,7 @@ create_filesystem_object(struct archive_write_disk *a) 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 @@ -2077,6 +2105,7 @@ create_filesystem_object(struct archive_write_disk *a) 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 @@ -2084,6 +2113,7 @@ create_filesystem_object(struct archive_write_disk *a) 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 @@ -2252,8 +2282,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); @@ -4125,10 +4159,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/contrib/libarchive/libarchive/archive_write_open.3 b/contrib/libarchive/libarchive/archive_write_open.3 index a52959b98..457873e61 100644 --- a/contrib/libarchive/libarchive/archive_write_open.3 +++ b/contrib/libarchive/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/contrib/libarchive/libarchive/archive_write_set_format_7zip.c b/contrib/libarchive/libarchive/archive_write_set_format_7zip.c index abd521a46..41ed74daf 100644 --- a/contrib/libarchive/libarchive/archive_write_set_format_7zip.c +++ b/contrib/libarchive/libarchive/archive_write_set_format_7zip.c @@ -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/contrib/libarchive/libarchive/archive_write_set_format_gnutar.c b/contrib/libarchive/libarchive/archive_write_set_format_gnutar.c index a9c41236e..2d858c9f7 100644 --- a/contrib/libarchive/libarchive/archive_write_set_format_gnutar.c +++ b/contrib/libarchive/libarchive/archive_write_set_format_gnutar.c @@ -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/contrib/libarchive/libarchive/archive_write_set_format_iso9660.c b/contrib/libarchive/libarchive/archive_write_set_format_iso9660.c index bf69c3e2e..4e910979e 100644 --- a/contrib/libarchive/libarchive/archive_write_set_format_iso9660.c +++ b/contrib/libarchive/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; @@ -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=', that * : 'boot-image' file won't be converted to zisofs 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( @@ -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. */ @@ -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 @@ -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 --; @@ -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/contrib/libarchive/libarchive/archive_write_set_format_pax.c b/contrib/libarchive/libarchive/archive_write_set_format_pax.c index 786eec490..1a245d742 100644 --- a/contrib/libarchive/libarchive/archive_write_set_format_pax.c +++ b/contrib/libarchive/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 *); @@ -133,6 +143,8 @@ archive_write_set_format_pax(struct archive *_a) "Can't allocate pax data"); return (ARCHIVE_FATAL); } + pax->flags = WRITE_LIBARCHIVE_XATTR | WRITE_SCHILY_XATTR; + a->format_data = pax; a->format_name = "pax"; a->format_options = archive_write_pax_options; @@ -271,6 +283,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 */ @@ -279,7 +302,7 @@ add_pax_attr(struct archive_string *as, const char *key, const char *value) * PAX attributes have the following layout: * <=> */ - len = 1 + (int)strlen(key) + 1 + (int)strlen(value) + 1; + len = 1 + (int)strlen(key) + 1 + (int)value_len + 1; /* * The field includes the length of the field, so @@ -310,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; @@ -345,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); } @@ -449,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 @@ -465,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; @@ -1016,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; @@ -1034,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 @@ -1085,43 +1163,28 @@ 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); + 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/contrib/libarchive/libarchive/archive_write_set_format_warc.c b/contrib/libarchive/libarchive/archive_write_set_format_warc.c index ea66929a9..8b6daf942 100644 --- a/contrib/libarchive/libarchive/archive_write_set_format_warc.c +++ b/contrib/libarchive/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/contrib/libarchive/libarchive/archive_write_set_format_xar.c b/contrib/libarchive/libarchive/archive_write_set_format_xar.c index da6daac4f..495f0d441 100644 --- a/contrib/libarchive/libarchive/archive_write_set_format_xar.c +++ b/contrib/libarchive/libarchive/archive_write_set_format_xar.c @@ -63,7 +63,7 @@ __FBSDID("$FreeBSD$"); * - When writing an XML element , * 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 and elements. * Xar utility generates on BSD platform and on Linux @@ -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: * ../ref/ * 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: * foo/bar * 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/contrib/libarchive/libarchive/archive_write_set_format_zip.c b/contrib/libarchive/libarchive/archive_write_set_format_zip.c index a69ce2052..38a9abfca 100644 --- a/contrib/libarchive/libarchive/archive_write_set_format_zip.c +++ b/contrib/libarchive/libarchive/archive_write_set_format_zip.c @@ -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/contrib/libarchive/libarchive/libarchive-formats.5 b/contrib/libarchive/libarchive/libarchive-formats.5 index 9cec76005..62359ddc2 100644 --- a/contrib/libarchive/libarchive/libarchive-formats.5 +++ b/contrib/libarchive/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/contrib/libarchive/libarchive/tar.5 b/contrib/libarchive/libarchive/tar.5 index 6e6f0c096..30b837dc4 100644 --- a/contrib/libarchive/libarchive/tar.5 +++ b/contrib/libarchive/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/contrib/libarchive/libarchive/test/main.c b/contrib/libarchive/libarchive/test/main.c index 4f3cdac77..d75f1ab4f 100644 --- a/contrib/libarchive/libarchive/test/main.c +++ b/contrib/libarchive/libarchive/test/main.c @@ -216,6 +216,12 @@ invalid_parameter_handler(const wchar_t * expression, unsigned int line, uintptr_t pReserved) { /* nop */ + // Silence unused-parameter compiler warnings. + (void)expression; + (void)function; + (void)file; + (void)line; + (void)pReserved; } #endif @@ -1412,6 +1418,8 @@ assertion_file_mode(const char *file, int line, const char *pathname, int expect failure_start(file, line, "assertFileMode not yet implemented for Windows"); (void)mode; /* UNUSED */ (void)r; /* UNUSED */ + (void)pathname; /* UNUSED */ + (void)expected_mode; /* UNUSED */ #else { struct stat st; @@ -2421,6 +2429,132 @@ extract_reference_files(const char **names) extract_reference_file(*names++); } +/* Set ACLs */ +void +archive_test_set_acls(struct archive_entry *ae, + struct archive_test_acl_t *acls, int n) +{ + int i; + + archive_entry_acl_clear(ae); + for (i = 0; i < n; i++) { + failure("type=%#010x, permset=%#010x, tag=%d, qual=%d name=%s", + acls[i].type, acls[i].permset, acls[i].tag, + acls[i].qual, acls[i].name); + assertEqualInt(ARCHIVE_OK, + archive_entry_acl_add_entry(ae, + acls[i].type, acls[i].permset, acls[i].tag, + acls[i].qual, acls[i].name)); + } +} + +static int +archive_test_acl_match(struct archive_test_acl_t *acl, int type, int permset, + int tag, int qual, const char *name) +{ + if (type != acl->type) + return (0); + if (permset != acl->permset) + return (0); + if (tag != acl->tag) + return (0); + if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) + return (1); + if (tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ) + return (1); + if (tag == ARCHIVE_ENTRY_ACL_EVERYONE) + return (1); + if (tag == ARCHIVE_ENTRY_ACL_OTHER) + return (1); + if (qual != acl->qual) + return (0); + if (name == NULL) { + if (acl->name == NULL || acl->name[0] == '\0') + return (1); + return (0); + } + if (acl->name == NULL) { + if (name[0] == '\0') + return (1); + return (0); + } + return (0 == strcmp(name, acl->name)); +} + +/* Compare ACLs */ +void +archive_test_compare_acls(struct archive_entry *ae, + struct archive_test_acl_t *acls, int cnt, int want_type, int mode) +{ + int *marker; + int i, r, n; + int type, permset, tag, qual; + int matched; + const char *name; + + n = 0; + marker = malloc(sizeof(marker[0]) * cnt); + + for (i = 0; i < cnt; i++) { + if ((acls[i].type & want_type) != 0) { + marker[n] = i; + n++; + } + } + + failure("No ACL's to compare, type mask: %d", want_type); + assert(n > 0); + if (n == 0) + return; + + while (0 == (r = archive_entry_acl_next(ae, want_type, + &type, &permset, &tag, &qual, &name))) { + for (i = 0, matched = 0; i < n && !matched; i++) { + if (archive_test_acl_match(&acls[marker[i]], type, + permset, tag, qual, name)) { + /* We found a match; remove it. */ + marker[i] = marker[n - 1]; + n--; + matched = 1; + } + } + if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS + && tag == ARCHIVE_ENTRY_ACL_USER_OBJ) { + if (!matched) printf("No match for user_obj perm\n"); + failure("USER_OBJ permset (%02o) != user mode (%02o)", + permset, 07 & (mode >> 6)); + assert((permset << 6) == (mode & 0700)); + } else if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS + && tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ) { + if (!matched) printf("No match for group_obj perm\n"); + failure("GROUP_OBJ permset %02o != group mode %02o", + permset, 07 & (mode >> 3)); + assert((permset << 3) == (mode & 0070)); + } else if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS + && tag == ARCHIVE_ENTRY_ACL_OTHER) { + if (!matched) printf("No match for other perm\n"); + failure("OTHER permset (%02o) != other mode (%02o)", + permset, mode & 07); + assert((permset << 0) == (mode & 0007)); + } else { + failure("Could not find match for ACL " + "(type=%#010x,permset=%#010x,tag=%d,qual=%d," + "name=``%s'')", type, permset, tag, qual, name); + assert(matched == 1); + } + } + assertEqualInt(ARCHIVE_EOF, r); + if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) + assert((mode_t)(mode & 0777) == (archive_entry_mode(ae) + & 0777)); + failure("Could not find match for ACL " + "(type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s'')", + acls[marker[0]].type, acls[marker[0]].permset, + acls[marker[0]].tag, acls[marker[0]].qual, acls[marker[0]].name); + assert(n == 0); /* Number of ACLs not matched should == 0 */ + free(marker); +} + /* * * TEST management diff --git a/contrib/libarchive/libarchive/test/test.h b/contrib/libarchive/libarchive/test/test.h index f7ec59f57..dc3f59048 100644 --- a/contrib/libarchive/libarchive/test/test.h +++ b/contrib/libarchive/libarchive/test/test.h @@ -120,6 +120,32 @@ #define O_BINARY 0 #endif +/* + * If this platform has , acl_create(), acl_init(), + * 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 +#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 , 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 + /* * Redefine DEFINE_TEST for use in defining the test functions. */ @@ -346,6 +372,23 @@ extern const char *testworkdir; #include "archive.h" #include "archive_entry.h" +/* ACL structure */ +struct archive_test_acl_t { + int type; /* Type of ACL */ + int permset; /* Permissions for this class of users. */ + int tag; /* Owner, User, Owning group, group, other, etc. */ + int qual; /* GID or UID of user/group, depending on tag. */ + const char *name; /* Name of user/group, depending on tag. */ +}; + +/* Set ACLs */ +void archive_test_set_acls(struct archive_entry *, struct archive_test_acl_t *, + int); + +/* Compare ACLs */ +void archive_test_compare_acls(struct archive_entry *, + struct archive_test_acl_t *, int, int, int); + /* Special customized read-from-memory interface. */ int read_open_memory(struct archive *, const void *, size_t, size_t); /* _minimal version exercises a slightly different set of libarchive APIs. */ diff --git a/contrib/libarchive/libarchive/test/test_acl_nfs4.c b/contrib/libarchive/libarchive/test/test_acl_nfs4.c index c8f59371a..f4e66f522 100644 --- a/contrib/libarchive/libarchive/test/test_acl_nfs4.c +++ b/contrib/libarchive/libarchive/test/test_acl_nfs4.c @@ -33,15 +33,7 @@ __FBSDID("$FreeBSD$"); * filesystems support ACLs or not. */ -struct acl_t { - int type; /* Type of entry: "allow" or "deny" */ - int permset; /* Permissions for this class of users. */ - int tag; /* Owner, User, Owning group, group, everyone, etc. */ - int qual; /* GID or UID of user/group, depending on tag. */ - const char *name; /* Name of user/group, depending on tag. */ -}; - -static struct acl_t acls1[] = { +static struct archive_test_acl_t acls1[] = { { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, { ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_READ_DATA, @@ -52,7 +44,7 @@ static struct acl_t acls1[] = { ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }, }; -static struct acl_t acls2[] = { +static struct archive_test_acl_t acls2[] = { /* An entry for each type. */ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, 0, ARCHIVE_ENTRY_ACL_USER, 108, "user108" }, @@ -136,7 +128,7 @@ static struct acl_t acls2[] = { * Entries that should be rejected when we attempt to set them * on an ACL that already has NFS4 entries. */ -static struct acl_t acls_bad[] = { +static struct archive_test_acl_t acls_bad[] = { /* POSIX.1e ACL types */ { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE, ARCHIVE_ENTRY_ACL_USER, 78, "" }, @@ -156,95 +148,6 @@ static struct acl_t acls_bad[] = { ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" }, }; -static void -set_acls(struct archive_entry *ae, struct acl_t *acls, int n) -{ - int i; - - archive_entry_acl_clear(ae); - for (i = 0; i < n; i++) { - failure("type=%d, permset=%d, tag=%d, qual=%d name=%s", - acls[i].type, acls[i].permset, acls[i].tag, - acls[i].qual, acls[i].name); - assertEqualInt(ARCHIVE_OK, - archive_entry_acl_add_entry(ae, - acls[i].type, acls[i].permset, acls[i].tag, - acls[i].qual, acls[i].name)); - } -} - -static int -acl_match(struct acl_t *acl, int type, int permset, int tag, int qual, - const char *name) -{ - if (acl == NULL) - return (0); - if (type != acl->type) - return (0); - if (permset != acl->permset) - return (0); - if (tag != acl->tag) - return (0); - if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) - return (1); - if (tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ) - return (1); - if (tag == ARCHIVE_ENTRY_ACL_EVERYONE) - return (1); - if (qual != acl->qual) - return (0); - if (name == NULL) { - if (acl->name == NULL || acl->name[0] == '\0') - return (1); - return (0); - } - if (acl->name == NULL) { - if (name[0] == '\0') - return (1); - return (0); - } - return (0 == strcmp(name, acl->name)); -} - -static void -compare_acls(struct archive_entry *ae, struct acl_t *acls, int n) -{ - int *marker = malloc(sizeof(marker[0]) * n); - int i; - int r; - int type, permset, tag, qual; - int matched; - const char *name; - - for (i = 0; i < n; i++) - marker[i] = i; - - while (0 == (r = archive_entry_acl_next(ae, - ARCHIVE_ENTRY_ACL_TYPE_NFS4, - &type, &permset, &tag, &qual, &name))) { - for (i = 0, matched = 0; i < n && !matched; i++) { - if (acl_match(&acls[marker[i]], type, permset, - tag, qual, name)) { - /* We found a match; remove it. */ - marker[i] = marker[n - 1]; - n--; - matched = 1; - } - } - failure("Could not find match for ACL " - "(type=%d,permset=%d,tag=%d,qual=%d,name=``%s'')", - type, permset, tag, qual, name); - assertEqualInt(1, matched); - } - assertEqualInt(ARCHIVE_EOF, r); - failure("Could not find match for ACL " - "(type=%d,permset=%d,tag=%d,qual=%d,name=``%s'')", - acls[marker[0]].type, acls[marker[0]].permset, - acls[marker[0]].tag, acls[marker[0]].qual, acls[marker[0]].name); - assertEqualInt(0, n); /* Number of ACLs not matched should == 0 */ - free(marker); -} - DEFINE_TEST(test_acl_nfs4) { struct archive_entry *ae; @@ -256,22 +159,31 @@ DEFINE_TEST(test_acl_nfs4) archive_entry_set_mode(ae, S_IFREG | 0777); /* Store and read back some basic ACL entries. */ - set_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0])); + archive_test_set_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0])); + + /* Check that entry contains only NFSv4 types */ + assert((archive_entry_acl_types(ae) & + ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) == 0); + assert((archive_entry_acl_types(ae) & + ARCHIVE_ENTRY_ACL_TYPE_NFS4) != 0); + assertEqualInt(4, archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4)); - compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0])); + archive_test_compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]), + ARCHIVE_ENTRY_ACL_TYPE_NFS4, 0); /* A more extensive set of ACLs. */ - set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0])); + archive_test_set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0])); assertEqualInt(32, archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4)); - compare_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0])); + archive_test_compare_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]), + ARCHIVE_ENTRY_ACL_TYPE_NFS4, 0); /* * Check that clearing ACLs gets rid of them all by repeating * the first test. */ - set_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0])); + archive_test_set_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0])); failure("Basic ACLs shouldn't be stored as extended ACLs"); assertEqualInt(4, archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4)); @@ -280,9 +192,9 @@ DEFINE_TEST(test_acl_nfs4) * Different types of malformed ACL entries that should * fail when added to existing NFS4 ACLs. */ - set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0])); + archive_test_set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0])); for (i = 0; i < (int)(sizeof(acls_bad)/sizeof(acls_bad[0])); ++i) { - struct acl_t *p = &acls_bad[i]; + struct archive_test_acl_t *p = &acls_bad[i]; failure("Malformed ACL test #%d", i); assertEqualInt(ARCHIVE_FAILED, archive_entry_acl_add_entry(ae, diff --git a/contrib/libarchive/libarchive/test/test_acl_pax.c b/contrib/libarchive/libarchive/test/test_acl_pax.c index 5fcf61ba6..8dfa0e031 100644 --- a/contrib/libarchive/libarchive/test/test_acl_pax.c +++ b/contrib/libarchive/libarchive/test/test_acl_pax.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 @@ -27,7 +28,7 @@ __FBSDID("$FreeBSD$"); /* * Exercise the system-independent portion of the ACL support. - * Check that pax archive can save and restore ACL data. + * Check that pax archive can save and restore POSIX.1e ACL data. * * This should work on all systems, regardless of whether local * filesystems support ACLs or not. @@ -35,15 +36,7 @@ __FBSDID("$FreeBSD$"); static unsigned char buff[16384]; -struct acl_t { - int type; /* Type of ACL: "access" or "default" */ - int permset; /* Permissions for this class of users. */ - int tag; /* Owner, User, Owning group, group, other, etc. */ - int qual; /* GID or UID of user/group, depending on tag. */ - const char *name; /* Name of user/group, depending on tag. */ -}; - -static struct acl_t acls0[] = { +static struct archive_test_acl_t acls0[] = { { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE, ARCHIVE_ENTRY_ACL_USER_OBJ, 0, "" }, { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ, @@ -52,7 +45,7 @@ static struct acl_t acls0[] = { ARCHIVE_ENTRY_ACL_OTHER, 0, "" }, }; -static struct acl_t acls1[] = { +static struct archive_test_acl_t acls1[] = { { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE, ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ, @@ -63,7 +56,7 @@ static struct acl_t acls1[] = { ARCHIVE_ENTRY_ACL_OTHER, -1, "" }, }; -static struct acl_t acls2[] = { +static struct archive_test_acl_t acls2[] = { { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE | ARCHIVE_ENTRY_ACL_READ, ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ, @@ -78,101 +71,149 @@ static struct acl_t acls2[] = { ARCHIVE_ENTRY_ACL_OTHER, -1, "" }, }; -static void -set_acls(struct archive_entry *ae, struct acl_t *acls, int n) -{ - int i; - - archive_entry_acl_clear(ae); - for (i = 0; i < n; i++) { - archive_entry_acl_add_entry(ae, - acls[i].type, acls[i].permset, acls[i].tag, acls[i].qual, - acls[i].name); - } -} +static struct archive_test_acl_t acls3[] = { + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_WRITE_DATA | + ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_APPEND_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_WRITE_ACL | + ARCHIVE_ENTRY_ACL_WRITE_OWNER | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_USER_OBJ, 0, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_WRITE_DATA | + ARCHIVE_ENTRY_ACL_APPEND_DATA | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_GROUP_OBJ, 0, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_EVERYONE, 0, "" }, +}; -static int -acl_match(struct acl_t *acl, int type, int permset, int tag, int qual, const char *name) -{ - if (type != acl->type) - return (0); - if (permset != acl->permset) - return (0); - if (tag != acl->tag) - return (0); - if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) - return (1); - if (tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ) - return (1); - if (tag == ARCHIVE_ENTRY_ACL_OTHER) - return (1); - if (qual != acl->qual) - return (0); - if (name == NULL) - return (acl->name == NULL || acl->name[0] == '\0'); - if (acl->name == NULL) - return (name == NULL || name[0] == '\0'); - return (0 == strcmp(name, acl->name)); -} +static struct archive_test_acl_t acls4[] = { + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_WRITE_DATA | + ARCHIVE_ENTRY_ACL_APPEND_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_WRITE_ACL | + ARCHIVE_ENTRY_ACL_WRITE_OWNER | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_USER_OBJ, 0, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE | + ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, + ARCHIVE_ENTRY_ACL_USER, 77, "user77" }, + { ARCHIVE_ENTRY_ACL_TYPE_DENY, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_WRITE_DATA | + ARCHIVE_ENTRY_ACL_EXECUTE, + ARCHIVE_ENTRY_ACL_USER, 78, "user78" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_WRITE_DATA | + ARCHIVE_ENTRY_ACL_APPEND_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_GROUP_OBJ, 0, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_DENY, + ARCHIVE_ENTRY_ACL_WRITE_DATA | + ARCHIVE_ENTRY_ACL_APPEND_DATA | + ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_WRITE_ACL | + ARCHIVE_ENTRY_ACL_WRITE_OWNER, + ARCHIVE_ENTRY_ACL_GROUP, 78, "group78" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_EVERYONE, 0, "" }, +}; -static void -compare_acls(struct archive_entry *ae, struct acl_t *acls, int n, int mode) -{ - int *marker = malloc(sizeof(marker[0]) * n); - int i; - int r; - int type, permset, tag, qual; - int matched; - const char *name; - - for (i = 0; i < n; i++) - marker[i] = i; - - while (0 == (r = archive_entry_acl_next(ae, - ARCHIVE_ENTRY_ACL_TYPE_ACCESS, - &type, &permset, &tag, &qual, &name))) { - for (i = 0, matched = 0; i < n && !matched; i++) { - if (acl_match(&acls[marker[i]], type, permset, - tag, qual, name)) { - /* We found a match; remove it. */ - marker[i] = marker[n - 1]; - n--; - matched = 1; - } - } - if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) { - if (!matched) printf("No match for user_obj perm\n"); - failure("USER_OBJ permset (%02o) != user mode (%02o)", - permset, 07 & (mode >> 6)); - assert((permset << 6) == (mode & 0700)); - } else if (tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ) { - if (!matched) printf("No match for group_obj perm\n"); - failure("GROUP_OBJ permset %02o != group mode %02o", - permset, 07 & (mode >> 3)); - assert((permset << 3) == (mode & 0070)); - } else if (tag == ARCHIVE_ENTRY_ACL_OTHER) { - if (!matched) printf("No match for other perm\n"); - failure("OTHER permset (%02o) != other mode (%02o)", - permset, mode & 07); - assert((permset << 0) == (mode & 0007)); - } else { - failure("Could not find match for ACL " - "(type=%d,permset=%d,tag=%d,qual=%d,name=``%s'')", - type, permset, tag, qual, name); - assert(matched == 1); - } - } - assertEqualInt(ARCHIVE_EOF, r); - assert((mode_t)(mode & 0777) == (archive_entry_mode(ae) & 0777)); - failure("Could not find match for ACL " - "(type=%d,permset=%d,tag=%d,qual=%d,name=``%s'')", - acls[marker[0]].type, acls[marker[0]].permset, - acls[marker[0]].tag, acls[marker[0]].qual, acls[marker[0]].name); - assert(n == 0); /* Number of ACLs not matched should == 0 */ - free(marker); -} +static struct archive_test_acl_t acls5[] = { + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_WRITE_DATA | + ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_APPEND_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_WRITE_ACL | + ARCHIVE_ENTRY_ACL_WRITE_OWNER | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_USER_OBJ, 0, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_WRITE_DATA | + ARCHIVE_ENTRY_ACL_APPEND_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_WRITE_OWNER | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_USER, 77, "user77" }, + { ARCHIVE_ENTRY_ACL_TYPE_AUDIT, + ARCHIVE_ENTRY_ACL_WRITE_DATA | + ARCHIVE_ENTRY_ACL_APPEND_DATA | + ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS, + ARCHIVE_ENTRY_ACL_USER, 77, "user77" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_WRITE_DATA | + ARCHIVE_ENTRY_ACL_APPEND_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_GROUP_OBJ, 0, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALARM, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS, + ARCHIVE_ENTRY_ACL_GROUP, 78, "group78" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_EVERYONE, 0, "" }, +}; -DEFINE_TEST(test_acl_pax) +DEFINE_TEST(test_acl_pax_posix1e) { struct archive *a; struct archive_entry *ae; @@ -197,23 +238,23 @@ DEFINE_TEST(test_acl_pax) archive_entry_set_mode(ae, S_IFREG | 0777); /* Basic owner/owning group should just update mode bits. */ - set_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0])); + archive_test_set_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0])); assertA(0 == archive_write_header(a, ae)); /* With any extended ACL entry, we should read back a full set. */ - set_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0])); + archive_test_set_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0])); assertA(0 == archive_write_header(a, ae)); /* A more extensive set of ACLs. */ - set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0])); + archive_test_set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0])); assertA(0 == archive_write_header(a, ae)); /* * Check that clearing ACLs gets rid of them all by repeating * the first test. */ - set_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0])); + archive_test_set_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0])); assertA(0 == archive_write_header(a, ae)); archive_entry_free(ae); @@ -227,13 +268,13 @@ DEFINE_TEST(test_acl_pax) fclose(f); /* Write out the reference data to a file for manual inspection. */ - extract_reference_file("test_acl_pax.tar"); - reference = slurpfile(&reference_size, "test_acl_pax.tar"); + extract_reference_file("test_acl_pax_posix1e.tar"); + reference = slurpfile(&reference_size, "test_acl_pax_posix1e.tar"); /* Assert that the generated data matches the built-in reference data.*/ - failure("Generated pax archive does not match reference; compare 'testout' to 'test_acl_pax.tar' reference file."); + failure("Generated pax archive does not match reference; compare 'testout' to 'test_acl_pax_posix1e.tar' reference file."); assertEqualMem(buff, reference, reference_size); - failure("Generated pax archive does not match reference; compare 'testout' to 'test_acl_pax.tar' reference file."); + failure("Generated pax archive does not match reference; compare 'testout' to 'test_acl_pax_posix1e.tar' reference file."); assertEqualInt((int)used, reference_size); free(reference); @@ -255,15 +296,18 @@ DEFINE_TEST(test_acl_pax) assertA(0 == archive_read_next_header(a, &ae)); failure("One extended ACL should flag all ACLs to be returned."); assert(4 == archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS)); - compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]), 0142); + archive_test_compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]), + ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0142); failure("Basic ACLs should set mode to 0142, not %04o", archive_entry_mode(ae)&0777); assert((archive_entry_mode(ae) & 0777) == 0142); /* Third item has pretty extensive ACLs */ assertA(0 == archive_read_next_header(a, &ae)); - assertEqualInt(6, archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS)); - compare_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]), 0543); + assertEqualInt(6, archive_entry_acl_reset(ae, + ARCHIVE_ENTRY_ACL_TYPE_ACCESS)); + archive_test_compare_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]), + ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0543); failure("Basic ACLs should set mode to 0543, not %04o", archive_entry_mode(ae)&0777); assert((archive_entry_mode(ae) & 0777) == 0543); @@ -280,3 +324,93 @@ DEFINE_TEST(test_acl_pax) assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); } + +DEFINE_TEST(test_acl_pax_nfs4) +{ + struct archive *a; + struct archive_entry *ae; + size_t used; + FILE *f; + void *reference; + size_t reference_size; + + /* Write an archive to memory. */ + assert(NULL != (a = archive_write_new())); + assertA(0 == archive_write_set_format_pax(a)); + assertA(0 == archive_write_add_filter_none(a)); + assertA(0 == archive_write_set_bytes_per_block(a, 1)); + assertA(0 == archive_write_set_bytes_in_last_block(a, 1)); + assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &used)); + + /* Write a series of files to the archive with different ACL info. */ + + /* Create a simple archive_entry. */ + assert((ae = archive_entry_new()) != NULL); + archive_entry_set_pathname(ae, "file"); + archive_entry_set_mode(ae, S_IFREG | 0777); + + /* NFS4 ACLs mirroring 0754 file mode */ + archive_test_set_acls(ae, acls3, sizeof(acls3)/sizeof(acls3[0])); + assertA(0 == archive_write_header(a, ae)); + + /* A more extensive set of NFS4 ACLs. */ + archive_test_set_acls(ae, acls4, sizeof(acls4)/sizeof(acls4[0])); + assertA(0 == archive_write_header(a, ae)); + + /* Set with special (audit, alarm) NFS4 ACLs. */ + archive_test_set_acls(ae, acls5, sizeof(acls5)/sizeof(acls5[0])); + assertA(0 == archive_write_header(a, ae)); + + archive_entry_free(ae); + + /* Close out the archive. */ + assertEqualIntA(a, ARCHIVE_OK, archive_write_close(a)); + assertEqualInt(ARCHIVE_OK, archive_write_free(a)); + + /* Write out the data we generated to a file for manual inspection. */ + assert(NULL != (f = fopen("testout", "wb"))); + assertEqualInt(used, (size_t)fwrite(buff, 1, (unsigned int)used, f)); + fclose(f); + + /* Write out the reference data to a file for manual inspection. */ + extract_reference_file("test_acl_pax_nfs4.tar"); + reference = slurpfile(&reference_size, "test_acl_pax_nfs4.tar"); + + /* Assert that the generated data matches the built-in reference data.*/ + failure("Generated pax archive does not match reference; compare 'testout' to 'test_acl_pax_nfs4.tar' reference file."); + assertEqualMem(buff, reference, reference_size); + failure("Generated pax archive does not match reference; compare 'testout' to 'test_acl_pax_nfs4.tar' reference file."); + assertEqualInt((int)used, reference_size); + free(reference); + + /* Read back each entry and check that the ACL data is right. */ + assert(NULL != (a = archive_read_new())); + assertA(0 == archive_read_support_format_all(a)); + assertA(0 == archive_read_support_filter_all(a)); + assertA(0 == archive_read_open_memory(a, buff, used)); + + /* First item has NFS4 ACLs mirroring file mode */ + assertA(0 == archive_read_next_header(a, &ae)); + assertEqualInt(3, archive_entry_acl_reset(ae, + ARCHIVE_ENTRY_ACL_TYPE_ALLOW)); + archive_test_compare_acls(ae, acls3, sizeof(acls3)/sizeof(acls3[0]), + ARCHIVE_ENTRY_ACL_TYPE_ALLOW, 0); + + /* Second item has has more fine-grained NFS4 ACLs */ + assertA(0 == archive_read_next_header(a, &ae)); + assertEqualInt(6, archive_entry_acl_reset(ae, + ARCHIVE_ENTRY_ACL_TYPE_NFS4)); + archive_test_compare_acls(ae, acls4, sizeof(acls4)/sizeof(acls4[0]), + ARCHIVE_ENTRY_ACL_TYPE_NFS4, 0); + + /* Third item has has audit and alarm NFS4 ACLs */ + assertA(0 == archive_read_next_header(a, &ae)); + assertEqualInt(6, archive_entry_acl_reset(ae, + ARCHIVE_ENTRY_ACL_TYPE_NFS4)); + archive_test_compare_acls(ae, acls5, sizeof(acls5)/sizeof(acls5[0]), + ARCHIVE_ENTRY_ACL_TYPE_NFS4, 0); + + /* Close the archive. */ + assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +} diff --git a/contrib/libarchive/libarchive/test/test_acl_pax_nfs4.tar.uu b/contrib/libarchive/libarchive/test/test_acl_pax_nfs4.tar.uu new file mode 100644 index 000000000..6a41557ff --- /dev/null +++ b/contrib/libarchive/libarchive/test/test_acl_pax_nfs4.tar.uu @@ -0,0 +1,129 @@ +begin 644 test_acl_pax_nfs4.tar +M4&%X2&5A9&5R+V9I;&4````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M`````````````#`P,#``````````````````````````````` +M```````````````````````````````````````````````````````````` +M``````````````````````````````````````````!U'`M+6%!4E=C0V]S.BTM+2TM+2TZ86QL;W``````````````````````` +M```````````````````````````````````````````````````````````` +M``````````````````````````````````````````````````!U``````````````` +M```````````````````````````````````````````````````````````` +M``````````````````````````````````````````````````````````!U +M'`M+6%!4E=C0V]S.BTM+2TM+2TZ86QL;W6]N94`Z= 8 +#if HAVE_POSIX_ACL || HAVE_NFS4_ACL #define _ACL_PRIVATE #include +#if HAVE_DARWIN_ACL +#include +#endif +#endif +#if HAVE_NFS4_ACL struct myacl_t { int type; int permset; @@ -38,11 +44,12 @@ struct myacl_t { }; static struct myacl_t acls_reg[] = { +#if !HAVE_DARWIN_ACL /* For this test, we need the file owner to be able to read and write the ACL. */ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_READ_ACL | ARCHIVE_ENTRY_ACL_WRITE_ACL | ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ARCHIVE_ENTRY_ACL_USER_OBJ, -1, ""}, - +#endif /* An entry for each type. */ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, ARCHIVE_ENTRY_ACL_USER, 108, "user108" }, @@ -84,17 +91,53 @@ static struct myacl_t acls_reg[] = { // ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, ARCHIVE_ENTRY_ACL_GROUP, 136, "group136" }, +#if !HAVE_DARWIN_ACL { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" }, { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_EXECUTE, ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" } +#else /* MacOS - mode 0654 */ + { ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_EXECUTE, + ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_WRITE_DATA | + ARCHIVE_ENTRY_ACL_APPEND_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_WRITE_ACL | + ARCHIVE_ENTRY_ACL_WRITE_OWNER | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" } +#endif }; +static const int acls_reg_cnt = (int)(sizeof(acls_reg)/sizeof(acls_reg[0])); static struct myacl_t acls_dir[] = { /* For this test, we need to be able to read and write the ACL. */ +#if !HAVE_DARWIN_ACL { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_READ_ACL, ARCHIVE_ENTRY_ACL_USER_OBJ, -1, ""}, +#endif /* An entry for each type. */ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, @@ -144,6 +187,9 @@ static struct myacl_t acls_dir[] = { { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ARCHIVE_ENTRY_ACL_USER, 304, "user304" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, + ARCHIVE_ENTRY_ACL_USER, 305, "user305" }, #endif #if 0 @@ -161,12 +207,47 @@ static struct myacl_t acls_dir[] = { ARCHIVE_ENTRY_ACL_USER, 501, "user501" }, { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_GROUP, 502, "group502" }, +#if !HAVE_DARWIN_ACL { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" }, { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" } +#else /* MacOS - mode 0654 */ + { ARCHIVE_ENTRY_ACL_TYPE_DENY, ARCHIVE_ENTRY_ACL_EXECUTE, + ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_WRITE_DATA | + ARCHIVE_ENTRY_ACL_APPEND_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_WRITE_ACL | + ARCHIVE_ENTRY_ACL_WRITE_OWNER | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_EVERYONE, -1, "" } +#endif }; +static const int acls_dir_cnt = (int)(sizeof(acls_dir)/sizeof(acls_dir[0])); + static void set_acls(struct archive_entry *ae, struct myacl_t *acls, int start, int end) { @@ -188,9 +269,50 @@ set_acls(struct archive_entry *ae, struct myacl_t *acls, int start, int end) } static int +#ifdef HAVE_SUN_ACL +acl_permset_to_bitmap(uint32_t a_access_mask) +#else acl_permset_to_bitmap(acl_permset_t opaque_ps) +#endif { static struct { int machine; int portable; } perms[] = { +#ifdef HAVE_SUN_ACL /* Solaris NFSv4 ACL permissions */ + {ACE_EXECUTE, ARCHIVE_ENTRY_ACL_EXECUTE}, + {ACE_READ_DATA, ARCHIVE_ENTRY_ACL_READ_DATA}, + {ACE_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY}, + {ACE_WRITE_DATA, ARCHIVE_ENTRY_ACL_WRITE_DATA}, + {ACE_ADD_FILE, ARCHIVE_ENTRY_ACL_ADD_FILE}, + {ACE_APPEND_DATA, ARCHIVE_ENTRY_ACL_APPEND_DATA}, + {ACE_ADD_SUBDIRECTORY, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY}, + {ACE_READ_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS}, + {ACE_WRITE_NAMED_ATTRS, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS}, + {ACE_DELETE_CHILD, ARCHIVE_ENTRY_ACL_DELETE_CHILD}, + {ACE_READ_ATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES}, + {ACE_WRITE_ATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES}, + {ACE_DELETE, ARCHIVE_ENTRY_ACL_DELETE}, + {ACE_READ_ACL, ARCHIVE_ENTRY_ACL_READ_ACL}, + {ACE_WRITE_ACL, ARCHIVE_ENTRY_ACL_WRITE_ACL}, + {ACE_WRITE_OWNER, ARCHIVE_ENTRY_ACL_WRITE_OWNER}, + {ACE_SYNCHRONIZE, ARCHIVE_ENTRY_ACL_SYNCHRONIZE} +#elif HAVE_DARWIN_ACL /* MacOS NFSv4 ACL permissions */ + {ACL_READ_DATA, ARCHIVE_ENTRY_ACL_READ_DATA}, + {ACL_LIST_DIRECTORY, ARCHIVE_ENTRY_ACL_LIST_DIRECTORY}, + {ACL_WRITE_DATA, ARCHIVE_ENTRY_ACL_WRITE_DATA}, + {ACL_ADD_FILE, ARCHIVE_ENTRY_ACL_ADD_FILE}, + {ACL_EXECUTE, ARCHIVE_ENTRY_ACL_EXECUTE}, + {ACL_DELETE, ARCHIVE_ENTRY_ACL_DELETE}, + {ACL_APPEND_DATA, ARCHIVE_ENTRY_ACL_APPEND_DATA}, + {ACL_ADD_SUBDIRECTORY, ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY}, + {ACL_DELETE_CHILD, ARCHIVE_ENTRY_ACL_DELETE_CHILD}, + {ACL_READ_ATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES}, + {ACL_WRITE_ATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES}, + {ACL_READ_EXTATTRIBUTES, ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS}, + {ACL_WRITE_EXTATTRIBUTES, ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS}, + {ACL_READ_SECURITY, ARCHIVE_ENTRY_ACL_READ_ACL}, + {ACL_WRITE_SECURITY, ARCHIVE_ENTRY_ACL_WRITE_ACL}, + {ACL_CHANGE_OWNER, ARCHIVE_ENTRY_ACL_WRITE_OWNER}, + {ACL_SYNCHRONIZE, ARCHIVE_ENTRY_ACL_SYNCHRONIZE}, +#else /* FreeBSD NFSv4 ACL permissions */ {ACL_EXECUTE, ARCHIVE_ENTRY_ACL_EXECUTE}, {ACL_WRITE, ARCHIVE_ENTRY_ACL_WRITE}, {ACL_READ, ARCHIVE_ENTRY_ACL_READ}, @@ -210,51 +332,201 @@ acl_permset_to_bitmap(acl_permset_t opaque_ps) {ACL_WRITE_ACL, ARCHIVE_ENTRY_ACL_WRITE_ACL}, {ACL_WRITE_OWNER, ARCHIVE_ENTRY_ACL_WRITE_OWNER}, {ACL_SYNCHRONIZE, ARCHIVE_ENTRY_ACL_SYNCHRONIZE} +#endif }; int i, permset = 0; for (i = 0; i < (int)(sizeof(perms)/sizeof(perms[0])); ++i) +#if HAVE_SUN_ACL + if (a_access_mask & perms[i].machine) +#else if (acl_get_perm_np(opaque_ps, perms[i].machine)) +#endif permset |= perms[i].portable; return permset; } static int +#if HAVE_SUN_ACL +acl_flagset_to_bitmap(uint16_t a_flags) +#else acl_flagset_to_bitmap(acl_flagset_t opaque_fs) +#endif { static struct { int machine; int portable; } flags[] = { +#if HAVE_SUN_ACL /* Solaris NFSv4 ACL inheritance flags */ + {ACE_FILE_INHERIT_ACE, ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT}, + {ACE_DIRECTORY_INHERIT_ACE, ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT}, + {ACE_NO_PROPAGATE_INHERIT_ACE, ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT}, + {ACE_INHERIT_ONLY_ACE, ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY}, + {ACE_SUCCESSFUL_ACCESS_ACE_FLAG, ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS}, + {ACE_FAILED_ACCESS_ACE_FLAG, ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS}, + {ACE_INHERITED_ACE, ARCHIVE_ENTRY_ACL_ENTRY_INHERITED} +#elif HAVE_DARWIN_ACL /* MacOS NFSv4 ACL inheritance flags */ + {ACL_ENTRY_INHERITED, ARCHIVE_ENTRY_ACL_ENTRY_INHERITED}, + {ACL_ENTRY_FILE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT}, + {ACL_ENTRY_DIRECTORY_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT}, + {ACL_ENTRY_LIMIT_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT}, + {ACL_ENTRY_ONLY_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY} +#else /* FreeBSD NFSv4 ACL inheritance flags */ {ACL_ENTRY_FILE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT}, {ACL_ENTRY_DIRECTORY_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT}, {ACL_ENTRY_NO_PROPAGATE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT}, + {ACL_ENTRY_SUCCESSFUL_ACCESS, ARCHIVE_ENTRY_ACL_ENTRY_SUCCESSFUL_ACCESS}, + {ACL_ENTRY_NO_PROPAGATE_INHERIT, ARCHIVE_ENTRY_ACL_ENTRY_FAILED_ACCESS}, {ACL_ENTRY_INHERIT_ONLY, ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY}, +#endif }; int i, flagset = 0; for (i = 0; i < (int)(sizeof(flags)/sizeof(flags[0])); ++i) +#if HAVE_SUN_ACL + if (a_flags & flags[i].machine) +#else if (acl_get_flag_np(opaque_fs, flags[i].machine)) +#endif flagset |= flags[i].portable; return flagset; } static int +#if HAVE_SUN_ACL +acl_match(ace_t *ace, struct myacl_t *myacl) +#else acl_match(acl_entry_t aclent, struct myacl_t *myacl) +#endif { +#if !HAVE_SUN_ACL +#if HAVE_DARWIN_ACL + void *q; + uid_t ugid; + int r, idtype; +#else gid_t g, *gp; uid_t u, *up; + acl_entry_type_t entry_type; +#endif /* !HAVE_DARWIN_ACL */ acl_tag_t tag_type; acl_permset_t opaque_ps; acl_flagset_t opaque_fs; +#endif /* !HAVE_SUN_ACL */ int perms; +#if HAVE_SUN_ACL + perms = acl_permset_to_bitmap(ace->a_access_mask) | acl_flagset_to_bitmap(ace->a_flags); +#else acl_get_tag_type(aclent, &tag_type); +#if !HAVE_DARWIN_ACL + acl_get_entry_type_np(aclent, &entry_type); +#endif /* translate the silly opaque permset to a bitmap */ acl_get_permset(aclent, &opaque_ps); acl_get_flagset_np(aclent, &opaque_fs); perms = acl_permset_to_bitmap(opaque_ps) | acl_flagset_to_bitmap(opaque_fs); +#endif if (perms != myacl->permset) return (0); +#if HAVE_SUN_ACL + switch (ace->a_type) { + case ACE_ACCESS_ALLOWED_ACE_TYPE: + if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW) + return (0); + break; + case ACE_ACCESS_DENIED_ACE_TYPE: + if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_DENY) + return (0); + break; + case ACE_SYSTEM_AUDIT_ACE_TYPE: + if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_AUDIT) + return (0); + break; + case ACE_SYSTEM_ALARM_ACE_TYPE: + if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALARM) + return (0); + break; + default: + return (0); + } + + if (ace->a_flags & ACE_OWNER) { + if (myacl->tag != ARCHIVE_ENTRY_ACL_USER_OBJ) + return (0); + } else if (ace->a_flags & ACE_GROUP) { + if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP_OBJ) + return (0); + } else if (ace->a_flags & ACE_EVERYONE) { + if (myacl->tag != ARCHIVE_ENTRY_ACL_EVERYONE) + return (0); + } else if (ace->a_flags & ACE_IDENTIFIER_GROUP) { + if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP) + return (0); + if ((gid_t)myacl->qual != ace->a_who) + return (0); + } else { + if (myacl->tag != ARCHIVE_ENTRY_ACL_USER) + return (0); + if ((uid_t)myacl->qual != ace->a_who) + return (0); + } +#elif HAVE_DARWIN_ACL + r = 0; + switch (tag_type) { + case ACL_EXTENDED_ALLOW: + if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW) + return (0); + break; + case ACL_EXTENDED_DENY: + if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_DENY) + return (0); + break; + default: + return (0); + } + q = acl_get_qualifier(aclent); + if (q == NULL) + return (0); + r = mbr_uuid_to_id((const unsigned char *)q, &ugid, &idtype); + acl_free(q); + if (r != 0) + return (0); + switch (idtype) { + case ID_TYPE_UID: + if (myacl->tag != ARCHIVE_ENTRY_ACL_USER) + return (0); + if ((uid_t)myacl->qual != ugid) + return (0); + break; + case ID_TYPE_GID: + if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP) + return (0); + if ((gid_t)myacl->qual != ugid) + return (0); + break; + default: + return (0); + } +#else /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */ + switch (entry_type) { + case ACL_ENTRY_TYPE_ALLOW: + if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALLOW) + return (0); + break; + case ACL_ENTRY_TYPE_DENY: + if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_DENY) + return (0); + break; + case ACL_ENTRY_TYPE_AUDIT: + if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_AUDIT) + return (0); + case ACL_ENTRY_TYPE_ALARM: + if (myacl->type != ARCHIVE_ENTRY_ACL_TYPE_ALARM) + return (0); + default: + return (0); + } + switch (tag_type) { case ACL_USER_OBJ: if (myacl->tag != ARCHIVE_ENTRY_ACL_USER_OBJ) return (0); @@ -287,17 +559,29 @@ acl_match(acl_entry_t aclent, struct myacl_t *myacl) if (myacl->tag != ARCHIVE_ENTRY_ACL_EVERYONE) return (0); break; } +#endif /* !HAVE_SUN_ACL && !HAVE_DARWIN_ACL */ return (1); } static void -compare_acls(acl_t acl, struct myacl_t *myacls, const char *filename, int start, int end) +compare_acls( +#if HAVE_SUN_ACL + acl_t *acl, +#else + acl_t acl, +#endif + struct myacl_t *myacls, const char *filename, int start, int end) { int *marker; - int entry_id = ACL_FIRST_ENTRY; int matched; int i, n; +#if HAVE_SUN_ACL + int e; + ace_t *acl_entry; +#else + int entry_id = ACL_FIRST_ENTRY; acl_entry_t acl_entry; +#endif n = end - start; marker = malloc(sizeof(marker[0]) * (n + 1)); @@ -313,10 +597,20 @@ compare_acls(acl_t acl, struct myacl_t *myacls, const char *filename, int start, * Iterate over acls in system acl object, try to match each * one with an item in the myacls array. */ - while (1 == acl_get_entry(acl, entry_id, &acl_entry)) { +#if HAVE_SUN_ACL + for (e = 0; e < acl->acl_cnt; e++) +#elif HAVE_DARWIN_ACL + while (0 == acl_get_entry(acl, entry_id, &acl_entry)) +#else + while (1 == acl_get_entry(acl, entry_id, &acl_entry)) +#endif + { +#if HAVE_SUN_ACL + acl_entry = &((ace_t *)acl->acl_aclp)[e]; +#else /* After the first time... */ entry_id = ACL_NEXT_ENTRY; - +#endif /* Search for a matching entry (tag and qualifier) */ for (i = 0, matched = 0; i < n && !matched; i++) { if (acl_match(acl_entry, &myacls[marker[i]])) { @@ -327,14 +621,15 @@ compare_acls(acl_t acl, struct myacl_t *myacls, const char *filename, int start, } } - failure("ACL entry on file %s that shouldn't be there", filename); + failure("ACL entry on file %s that shouldn't be there", + filename); assert(matched == 1); } /* Dump entries in the myacls array that weren't in the system acl. */ for (i = 0; i < n; ++i) { failure(" ACL entry %d missing from %s: " - "type=%d,permset=%x,tag=%d,qual=%d,name=``%s''\n", + "type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s''\n", marker[i], filename, myacls[marker[i]].type, myacls[marker[i]].permset, myacls[marker[i]].tag, myacls[marker[i]].qual, @@ -368,7 +663,8 @@ compare_entry_acls(struct archive_entry *ae, struct myacl_t *myacls, const char * Iterate over acls in entry, try to match each * one with an item in the myacls array. */ - assertEqualInt(n, archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4)); + assertEqualInt(n, archive_entry_acl_reset(ae, + ARCHIVE_ENTRY_ACL_TYPE_NFS4)); while (ARCHIVE_OK == archive_entry_acl_next(ae, ARCHIVE_ENTRY_ACL_TYPE_NFS4, &type, &permset, &tag, &qual, &name)) { @@ -386,7 +682,7 @@ compare_entry_acls(struct archive_entry *ae, struct myacl_t *myacls, const char } failure("ACL entry on file that shouldn't be there: " - "type=%d,permset=%x,tag=%d,qual=%d", + "type=%#010x,permset=%#010x,tag=%d,qual=%d", type,permset,tag,qual); assert(matched == 1); } @@ -394,7 +690,7 @@ compare_entry_acls(struct archive_entry *ae, struct myacl_t *myacls, const char /* Dump entries in the myacls array that weren't in the system acl. */ for (i = 0; i < n; ++i) { failure(" ACL entry %d missing from %s: " - "type=%d,permset=%x,tag=%d,qual=%d,name=``%s''\n", + "type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s''\n", marker[i], filename, myacls[marker[i]].type, myacls[marker[i]].permset, myacls[marker[i]].tag, myacls[marker[i]].qual, @@ -403,53 +699,109 @@ compare_entry_acls(struct archive_entry *ae, struct myacl_t *myacls, const char } free(marker); } -#endif +#endif /* HAVE_NFS4_ACL */ /* - * Verify ACL restore-to-disk. This test is FreeBSD-specific. + * Verify ACL restore-to-disk. This test is Platform-specific. */ -DEFINE_TEST(test_acl_freebsd_nfs4) +DEFINE_TEST(test_acl_platform_nfs4) { -#if !defined(__FreeBSD__) - skipping("FreeBSD-specific NFS4 ACL restore test"); -#elif __FreeBSD__ < 8 - skipping("NFS4 ACLs supported only on FreeBSD 8.0 and later"); +#if !HAVE_NFS4_ACL + skipping("NFS4 ACLs are not supported on this platform"); #else char buff[64]; struct stat st; struct archive *a; struct archive_entry *ae; int i, n; + char *func; +#if HAVE_DARWIN_ACL /* On MacOS we skip trivial ACLs in some tests */ + const int regcnt = acls_reg_cnt - 4; + const int dircnt = acls_dir_cnt - 4; +#else + const int regcnt = acls_reg_cnt; + const int dircnt = acls_dir_cnt; +#endif +#if HAVE_SUN_ACL + acl_t *acl; +#else /* !HAVE_SUN_ACL */ +#if HAVE_DARWIN_ACL + acl_entry_t aclent; + acl_permset_t permset; + const uid_t uid = 1000; + uuid_t uuid; +#endif /* HAVE_DARWIN_ACL */ acl_t acl; +#endif /* !HAVE_SUN_ACL */ /* * First, do a quick manual set/read of ACL data to * verify that the local filesystem does support ACLs. * If it doesn't, we'll simply skip the remaining tests. */ +#if HAVE_POSIX_ACL && HAVE_ACL_TYPE_NFS4 acl = acl_from_text("owner@:rwxp::allow,group@:rwp:f:allow"); + failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno)); + assert((void *)acl != NULL); +#elif HAVE_DARWIN_ACL + acl = acl_init(1); assert((void *)acl != NULL); + assertEqualInt(0, acl_create_entry(&acl, &aclent)); + assertEqualInt(0, acl_set_tag_type(aclent, ACL_EXTENDED_ALLOW)); + assertEqualInt(0, acl_get_permset(aclent, &permset)); + assertEqualInt(0, acl_add_perm(permset, ACL_READ_DATA)); + assertEqualInt(0, acl_add_perm(permset, ACL_WRITE_DATA)); + assertEqualInt(0, acl_add_perm(permset, ACL_APPEND_DATA)); + assertEqualInt(0, acl_add_perm(permset, ACL_EXECUTE)); + assertEqualInt(0, acl_set_permset(aclent, permset)); + assertEqualInt(0, mbr_identifier_to_uuid(ID_TYPE_UID, &uid, + sizeof(uid_t), uuid)); + assertEqualInt(0, acl_set_qualifier(aclent, uuid)); +#endif + /* Create a test dir and try to set an ACL on it. */ if (!assertMakeDir("pretest", 0755)) { +#if !HAVE_SUN_ACL acl_free(acl); +#endif return; } +#if HAVE_SUN_ACL + func = "acl_get()"; + n = acl_get("pretest", 0, &acl); +#else + func = "acl_set_file()"; +#if HAVE_DARWIN_ACL + n = acl_set_file("pretest", ACL_TYPE_EXTENDED, acl); +#else n = acl_set_file("pretest", ACL_TYPE_NFS4, acl); +#endif acl_free(acl); - if (n != 0 && errno == EOPNOTSUPP) { - skipping("NFS4 ACL tests require that NFS4 ACLs" - " be enabled on the filesystem"); - return; +#endif + if (n != 0) { +#if HAVE_SUN_ACL + if (errno == ENOSYS) +#else + if (errno == EOPNOTSUPP || errno == EINVAL) +#endif + { + skipping("NFS4 ACL is not supported on this filesystem"); + return; + } } - if (n != 0 && errno == EINVAL) { - skipping("This filesystem does not support NFS4 ACLs"); + failure("%s: errno = %d (%s)", func, errno, strerror(errno)); + assertEqualInt(0, n); + +#if HAVE_SUN_ACL + if (acl->acl_type != ACE_T) { + acl_free(acl); + skipping("NFS4 ACL is not supported on this filesystem"); return; } - failure("acl_set_file(): errno = %d (%s)", - errno, strerror(errno)); - assertEqualInt(0, n); + acl_free(acl); +#endif /* Create a write-to-disk object. */ assert(NULL != (a = archive_write_disk_new())); @@ -464,7 +816,7 @@ DEFINE_TEST(test_acl_freebsd_nfs4) archive_entry_set_perm(ae, 0654); archive_entry_set_mtime(ae, 123456, 7890); archive_entry_set_size(ae, 0); - set_acls(ae, acls_reg, 0, (int)(sizeof(acls_reg)/sizeof(acls_reg[0]))); + set_acls(ae, acls_reg, 0, acls_reg_cnt); /* Write the entry to disk, including ACLs. */ assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae)); @@ -474,10 +826,10 @@ DEFINE_TEST(test_acl_freebsd_nfs4) archive_entry_set_filetype(ae, AE_IFDIR); archive_entry_set_perm(ae, 0654); archive_entry_set_mtime(ae, 123456, 7890); - set_acls(ae, acls_dir, 0, (int)(sizeof(acls_dir)/sizeof(acls_dir[0]))); + set_acls(ae, acls_dir, 0, acls_dir_cnt); assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae)); - for (i = 0; i < (int)(sizeof(acls_dir)/sizeof(acls_dir[0])); ++i) { + for (i = 0; i < acls_dir_cnt; ++i) { sprintf(buff, "dir%d", i); archive_entry_set_pathname(ae, buff); archive_entry_set_filetype(ae, AE_IFDIR); @@ -496,28 +848,62 @@ DEFINE_TEST(test_acl_freebsd_nfs4) /* Verify the data on disk. */ assertEqualInt(0, stat("testall", &st)); assertEqualInt(st.st_mtime, 123456); +#if HAVE_SUN_ACL + n = acl_get("testall", 0, &acl); + failure("acl_get(): errno = %d (%s)", errno, strerror(errno)); + assertEqualInt(0, n); +#else +#if HAVE_DARWIN_ACL + acl = acl_get_file("testall", ACL_TYPE_EXTENDED); +#else acl = acl_get_file("testall", ACL_TYPE_NFS4); +#endif + failure("acl_get_file(): errno = %d (%s)", errno, strerror(errno)); assert(acl != (acl_t)NULL); - compare_acls(acl, acls_reg, "testall", 0, (int)(sizeof(acls_reg)/sizeof(acls_reg[0]))); +#endif + compare_acls(acl, acls_reg, "testall", 0, regcnt); acl_free(acl); /* Verify single-permission dirs on disk. */ - for (i = 0; i < (int)(sizeof(acls_dir)/sizeof(acls_dir[0])); ++i) { - sprintf(buff, "dir%d", i); - assertEqualInt(0, stat(buff, &st)); - assertEqualInt(st.st_mtime, 123456 + i); - acl = acl_get_file(buff, ACL_TYPE_NFS4); - assert(acl != (acl_t)NULL); - compare_acls(acl, acls_dir, buff, i, i + 1); - acl_free(acl); + for (i = 0; i < dircnt; ++i) { + sprintf(buff, "dir%d", i); + assertEqualInt(0, stat(buff, &st)); + assertEqualInt(st.st_mtime, 123456 + i); +#if HAVE_SUN_ACL + n = acl_get(buff, 0, &acl); + failure("acl_get(): errno = %d (%s)", errno, strerror(errno)); + assertEqualInt(0, n); +#else +#if HAVE_DARWIN_ACL + acl = acl_get_file(buff, ACL_TYPE_EXTENDED); +#else + acl = acl_get_file(buff, ACL_TYPE_NFS4); +#endif + failure("acl_get_file(): errno = %d (%s)", errno, + strerror(errno)); + assert(acl != (acl_t)NULL); +#endif + compare_acls(acl, acls_dir, buff, i, i + 1); + acl_free(acl); } /* Verify "dirall" on disk. */ assertEqualInt(0, stat("dirall", &st)); assertEqualInt(st.st_mtime, 123456); +#if HAVE_SUN_ACL + n = acl_get("dirall", 0, &acl); + failure("acl_get(): errno = %d (%s)", errno, strerror(errno)); + assertEqualInt(0, n); +#else +#if HAVE_DARWIN_ACL + acl = acl_get_file("dirall", ACL_TYPE_EXTENDED); +#else acl = acl_get_file("dirall", ACL_TYPE_NFS4); +#endif + failure("acl_get_file(): errno = %d (%s)", errno, strerror(errno)); assert(acl != (acl_t)NULL); - compare_acls(acl, acls_dir, "dirall", 0, (int)(sizeof(acls_dir)/sizeof(acls_dir[0]))); +#endif + compare_acls(acl, acls_dir, "dirall", 0, dircnt); acl_free(acl); /* Read and compare ACL via archive_read_disk */ @@ -528,7 +914,7 @@ DEFINE_TEST(test_acl_freebsd_nfs4) archive_entry_set_pathname(ae, "testall"); assertEqualInt(ARCHIVE_OK, archive_read_disk_entry_from_file(a, ae, -1, NULL)); - compare_entry_acls(ae, acls_reg, "testall", 0, (int)(sizeof(acls_reg)/sizeof(acls_reg[0]))); + compare_entry_acls(ae, acls_reg, "testall", 0, acls_reg_cnt); archive_entry_free(ae); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); @@ -539,9 +925,9 @@ DEFINE_TEST(test_acl_freebsd_nfs4) assert(ae != NULL); archive_entry_set_pathname(ae, "dirall"); assertEqualInt(ARCHIVE_OK, - archive_read_disk_entry_from_file(a, ae, -1, NULL)); - compare_entry_acls(ae, acls_dir, "dirall", 0, (int)(sizeof(acls_dir)/sizeof(acls_dir[0]))); + archive_read_disk_entry_from_file(a, ae, -1, NULL)); + compare_entry_acls(ae, acls_dir, "dirall", 0, acls_dir_cnt); archive_entry_free(ae); assertEqualInt(ARCHIVE_OK, archive_read_free(a)); -#endif +#endif /* HAVE_NFS4_ACL */ } diff --git a/contrib/libarchive/libarchive/test/test_acl_freebsd_posix1e.c b/contrib/libarchive/libarchive/test/test_acl_platform_posix1e.c similarity index 52% rename from contrib/libarchive/libarchive/test/test_acl_freebsd_posix1e.c rename to contrib/libarchive/libarchive/test/test_acl_platform_posix1e.c index 2eb0a001c..f3e1722f7 100644 --- a/contrib/libarchive/libarchive/test/test_acl_freebsd_posix1e.c +++ b/contrib/libarchive/libarchive/test/test_acl_platform_posix1e.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2003-2008 Tim Kientzle + * Copyright (c) 2017 Martin Matuska * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,18 +26,16 @@ #include "test.h" __FBSDID("$FreeBSD: head/lib/libarchive/test/test_acl_freebsd.c 189427 2009-03-06 04:21:23Z kientzle $"); -#if defined(__FreeBSD__) && __FreeBSD__ > 4 +#if HAVE_POSIX_ACL || HAVE_SUN_ACL #include +#if HAVE_ACL_GET_PERM +#include +#define ACL_GET_PERM acl_get_perm +#elif HAVE_ACL_GET_PERM_NP +#define ACL_GET_PERM acl_get_perm_np +#endif -struct myacl_t { - int type; /* Type of ACL: "access" or "default" */ - int permset; /* Permissions for this class of users. */ - int tag; /* Owner, User, Owning group, group, other, etc. */ - int qual; /* GID or UID of user/group, depending on tag. */ - const char *name; /* Name of user/group, depending on tag. */ -}; - -static struct myacl_t acls2[] = { +static struct archive_test_acl_t acls2[] = { { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE | ARCHIVE_ENTRY_ACL_READ, ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ, @@ -53,35 +52,37 @@ static struct myacl_t acls2[] = { { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_WRITE | ARCHIVE_ENTRY_ACL_READ | ARCHIVE_ENTRY_ACL_EXECUTE, ARCHIVE_ENTRY_ACL_MASK, -1, "" }, - { 0, 0, 0, 0, NULL } }; -static void -set_acls(struct archive_entry *ae, struct myacl_t *acls) -{ - int i; - - archive_entry_acl_clear(ae); - for (i = 0; acls[i].name != NULL; i++) { - archive_entry_acl_add_entry(ae, - acls[i].type, acls[i].permset, acls[i].tag, acls[i].qual, - acls[i].name); - } -} - static int -acl_entry_get_perm(acl_entry_t aclent) { +#if HAVE_SUN_ACL +acl_entry_get_perm(aclent_t *aclent) +#else +acl_entry_get_perm(acl_entry_t aclent) +#endif +{ int permset = 0; +#if HAVE_POSIX_ACL acl_permset_t opaque_ps; +#endif +#if HAVE_SUN_ACL + if (aclent->a_perm & 1) + permset |= ARCHIVE_ENTRY_ACL_EXECUTE; + if (aclent->a_perm & 2) + permset |= ARCHIVE_ENTRY_ACL_WRITE; + if (aclent->a_perm & 4) + permset |= ARCHIVE_ENTRY_ACL_READ; +#else /* translate the silly opaque permset to a bitmap */ acl_get_permset(aclent, &opaque_ps); - if (acl_get_perm_np(opaque_ps, ACL_EXECUTE)) + if (ACL_GET_PERM(opaque_ps, ACL_EXECUTE)) permset |= ARCHIVE_ENTRY_ACL_EXECUTE; - if (acl_get_perm_np(opaque_ps, ACL_WRITE)) + if (ACL_GET_PERM(opaque_ps, ACL_WRITE)) permset |= ARCHIVE_ENTRY_ACL_WRITE; - if (acl_get_perm_np(opaque_ps, ACL_READ)) + if (ACL_GET_PERM(opaque_ps, ACL_READ)) permset |= ARCHIVE_ENTRY_ACL_READ; +#endif return permset; } @@ -127,45 +128,96 @@ acl_get_specific_entry(acl_t acl, acl_tag_t requested_tag_type, int requested_ta #endif static int -acl_match(acl_entry_t aclent, struct myacl_t *myacl) +#if HAVE_SUN_ACL +acl_match(aclent_t *aclent, struct archive_test_acl_t *myacl) +#else +acl_match(acl_entry_t aclent, struct archive_test_acl_t *myacl) +#endif { +#if HAVE_POSIX_ACL gid_t g, *gp; uid_t u, *up; acl_tag_t tag_type; +#endif if (myacl->permset != acl_entry_get_perm(aclent)) return (0); +#if HAVE_SUN_ACL + switch (aclent->a_type) +#else acl_get_tag_type(aclent, &tag_type); - switch (tag_type) { + switch (tag_type) +#endif + { +#if HAVE_SUN_ACL + case DEF_USER_OBJ: + case USER_OBJ: +#else case ACL_USER_OBJ: +#endif if (myacl->tag != ARCHIVE_ENTRY_ACL_USER_OBJ) return (0); break; +#if HAVE_SUN_ACL + case DEF_USER: + case USER: +#else case ACL_USER: +#endif if (myacl->tag != ARCHIVE_ENTRY_ACL_USER) return (0); +#if HAVE_SUN_ACL + if ((uid_t)myacl->qual != aclent->a_id) + return (0); +#else up = acl_get_qualifier(aclent); u = *up; acl_free(up); if ((uid_t)myacl->qual != u) return (0); +#endif break; +#if HAVE_SUN_ACL + case DEF_GROUP_OBJ: + case GROUP_OBJ: +#else case ACL_GROUP_OBJ: +#endif if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP_OBJ) return (0); break; +#if HAVE_SUN_ACL + case DEF_GROUP: + case GROUP: +#else case ACL_GROUP: +#endif if (myacl->tag != ARCHIVE_ENTRY_ACL_GROUP) return (0); +#if HAVE_SUN_ACL + if ((gid_t)myacl->qual != aclent->a_id) + return (0); +#else gp = acl_get_qualifier(aclent); g = *gp; acl_free(gp); if ((gid_t)myacl->qual != g) return (0); +#endif break; +#if HAVE_SUN_ACL + case DEF_CLASS_OBJ: + case CLASS_OBJ: +#else case ACL_MASK: +#endif if (myacl->tag != ARCHIVE_ENTRY_ACL_MASK) return (0); break; +#if HAVE_SUN_ACL + case DEF_OTHER_OBJ: + case OTHER_OBJ: +#else case ACL_OTHER: +#endif if (myacl->tag != ARCHIVE_ENTRY_ACL_OTHER) return (0); break; } @@ -173,33 +225,42 @@ acl_match(acl_entry_t aclent, struct myacl_t *myacl) } static void -compare_acls(acl_t acl, struct myacl_t *myacls) +#if HAVE_SUN_ACL +compare_acls(acl_t *acl, struct archive_test_acl_t *myacls, int n) +#else +compare_acls(acl_t acl, struct archive_test_acl_t *myacls, int n) +#endif { int *marker; - int entry_id = ACL_FIRST_ENTRY; int matched; - int i, n; + int i; +#if HAVE_SUN_ACL + int e; + aclent_t *acl_entry; +#else + int entry_id = ACL_FIRST_ENTRY; acl_entry_t acl_entry; +#endif /* Count ACL entries in myacls array and allocate an indirect array. */ - for (n = 0; myacls[n].name != NULL; ++n) - continue; - if (n) { - marker = malloc(sizeof(marker[0]) * n); - if (marker == NULL) - return; - for (i = 0; i < n; i++) - marker[i] = i; - } else - marker = NULL; + marker = malloc(sizeof(marker[0]) * n); + if (marker == NULL) + return; + for (i = 0; i < n; i++) + marker[i] = i; /* * Iterate over acls in system acl object, try to match each * one with an item in the myacls array. */ +#if HAVE_SUN_ACL + for(e = 0; e < acl->acl_cnt; e++) { + acl_entry = &((aclent_t *)acl->acl_aclp)[e]; +#else while (1 == acl_get_entry(acl, entry_id, &acl_entry)) { /* After the first time... */ entry_id = ACL_NEXT_ENTRY; +#endif /* Search for a matching entry (tag and qualifier) */ for (i = 0, matched = 0; i < n && !matched; i++) { @@ -219,7 +280,7 @@ compare_acls(acl_t acl, struct myacl_t *myacls) /* Dump entries in the myacls array that weren't in the system acl. */ for (i = 0; i < n; ++i) { failure(" ACL entry missing from file: " - "type=%d,permset=%d,tag=%d,qual=%d,name=``%s''\n", + "type=%#010x,permset=%#010x,tag=%d,qual=%d,name=``%s''\n", myacls[marker[i]].type, myacls[marker[i]].permset, myacls[marker[i]].tag, myacls[marker[i]].qual, myacls[marker[i]].name); @@ -232,30 +293,41 @@ compare_acls(acl_t acl, struct myacl_t *myacls) /* - * Verify ACL restore-to-disk. This test is FreeBSD-specific. + * Verify ACL restore-to-disk. This test is Platform-specific. */ -DEFINE_TEST(test_acl_freebsd_posix1e_restore) +DEFINE_TEST(test_acl_platform_posix1e_restore) { -#if !defined(__FreeBSD__) - skipping("FreeBSD-specific ACL restore test"); -#elif __FreeBSD__ < 5 - skipping("ACL restore supported only on FreeBSD 5.0 and later"); -#else +#if !HAVE_SUN_ACL && !HAVE_POSIX_ACL + skipping("POSIX.1e ACLs are not supported on this platform"); +#else /* HAVE_SUN_ACL || HAVE_POSIX_ACL */ struct stat st; struct archive *a; struct archive_entry *ae; int n, fd; + char *func; +#if HAVE_SUN_ACL + acl_t *acl, *acl2; +#else acl_t acl; +#endif /* * First, do a quick manual set/read of ACL data to * verify that the local filesystem does support ACLs. * If it doesn't, we'll simply skip the remaining tests. */ +#if HAVE_SUN_ACL + n = acl_fromtext("user::rwx,user:1:rw-,group::rwx,group:15:r-x,other:rwx,mask:rwx", &acl); + failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno)); + assertEqualInt(0, n); +#else acl = acl_from_text("u::rwx,u:1:rw,g::rwx,g:15:rx,o::rwx,m::rwx"); + failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno)); assert((void *)acl != NULL); - /* Create a test file and try to set an ACL on it. */ +#endif + + /* Create a test file and try ACL on it. */ fd = open("pretest", O_WRONLY | O_CREAT | O_EXCL, 0777); failure("Could not create test file?!"); if (!assert(fd >= 0)) { @@ -263,21 +335,51 @@ DEFINE_TEST(test_acl_freebsd_posix1e_restore) return; } - n = acl_set_fd(fd, acl); - acl_free(acl); - if (n != 0 && errno == EOPNOTSUPP) { +#if HAVE_SUN_ACL + n = facl_get(fd, 0, &acl2); + if (n != 0) { close(fd); - skipping("ACL tests require that ACL support be enabled on the filesystem"); + acl_free(acl); + } + if (errno == ENOSYS) { + skipping("POSIX.1e ACLs are not supported on this filesystem"); return; } - if (n != 0 && errno == EINVAL) { - close(fd); - skipping("This filesystem does not support POSIX.1e ACLs"); + failure("facl_get(): errno = %d (%s)", errno, strerror(errno)); + assertEqualInt(0, n); + + if (acl2->acl_type != ACLENT_T) { + acl_free(acl2); + skipping("POSIX.1e ACLs are not supported on this filesystem"); return; } - failure("acl_set_fd(): errno = %d (%s)", - errno, strerror(errno)); + acl_free(acl2); + + func = "facl_set()"; + n = facl_set(fd, acl); +#else + func = "acl_set_fd()"; + n = acl_set_fd(fd, acl); +#endif + acl_free(acl); + if (n != 0) { +#if HAVE_SUN_ACL + if (errno == ENOSYS) +#else + if (errno == EOPNOTSUPP || errno == EINVAL) +#endif + { + close(fd); + skipping("POSIX.1e ACLs are not supported on this filesystem"); + return; + } + } + failure("%s: errno = %d (%s)", func, errno, strerror(errno)); assertEqualInt(0, n); + +#if HAVE_SUN_ACL + +#endif close(fd); /* Create a write-to-disk object. */ @@ -291,7 +393,7 @@ DEFINE_TEST(test_acl_freebsd_posix1e_restore) archive_entry_set_pathname(ae, "test0"); archive_entry_set_mtime(ae, 123456, 7890); archive_entry_set_size(ae, 0); - set_acls(ae, acls2); + archive_test_set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0])); assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae)); archive_entry_free(ae); @@ -302,28 +404,38 @@ DEFINE_TEST(test_acl_freebsd_posix1e_restore) /* Verify the data on disk. */ assertEqualInt(0, stat("test0", &st)); assertEqualInt(st.st_mtime, 123456); +#if HAVE_SUN_ACL + n = acl_get("test0", 0, &acl); + failure("acl_get(): errno = %d (%s)", errno, strerror(errno)); + assertEqualInt(0, n); +#else acl = acl_get_file("test0", ACL_TYPE_ACCESS); + failure("acl_get_file(): errno = %d (%s)", errno, strerror(errno)); assert(acl != (acl_t)NULL); - compare_acls(acl, acls2); - acl_free(acl); #endif + compare_acls(acl, acls2, sizeof(acls2)/sizeof(acls2[0])); + acl_free(acl); +#endif /* HAVE_SUN_ACL || HAVE_POSIX_ACL */ } /* - * Verify ACL reaed-from-disk. This test is FreeBSD-specific. + * Verify ACL read-from-disk. This test is Platform-specific. */ -DEFINE_TEST(test_acl_freebsd_posix1e_read) +DEFINE_TEST(test_acl_platform_posix1e_read) { -#if !defined(__FreeBSD__) - skipping("FreeBSD-specific ACL read test"); -#elif __FreeBSD__ < 5 - skipping("ACL read supported only on FreeBSD 5.0 and later"); +#if !HAVE_SUN_ACL && !HAVE_POSIX_ACL + skipping("POSIX.1e ACLs are not supported on this platform"); #else struct archive *a; struct archive_entry *ae; - int n, fd; - const char *acl1_text, *acl2_text; - acl_t acl1, acl2; + int n, fd, flags, dflags; + char *func, *acl_text; + const char *acl1_text, *acl2_text, *acl3_text; +#if HAVE_SUN_ACL + acl_t *acl, *acl1, *acl2, *acl3; +#else + acl_t acl1, acl2, acl3; +#endif /* * Manually construct a directory and two files with @@ -332,30 +444,77 @@ DEFINE_TEST(test_acl_freebsd_posix1e_read) */ /* Create a test file f1 with acl1 */ - acl1_text = "user::rwx,group::rwx,other::rwx,user:1:rw-,group:15:r-x,mask::rwx"; +#if HAVE_SUN_ACL + acl1_text = "user::rwx," + "group::rwx," + "other:rwx," + "user:1:rw-," + "group:15:r-x," + "mask:rwx"; + n = acl_fromtext(acl1_text, &acl1); + failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno)); + assertEqualInt(0, n); +#else + acl1_text = "user::rwx\n" + "group::rwx\n" + "other::rwx\n" + "user:1:rw-\n" + "group:15:r-x\n" + "mask::rwx"; acl1 = acl_from_text(acl1_text); + failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno)); assert((void *)acl1 != NULL); +#endif fd = open("f1", O_WRONLY | O_CREAT | O_EXCL, 0777); failure("Could not create test file?!"); if (!assert(fd >= 0)) { acl_free(acl1); return; } - n = acl_set_fd(fd, acl1); - acl_free(acl1); - if (n != 0 && errno == EOPNOTSUPP) { +#if HAVE_SUN_ACL + /* Check if Solars filesystem supports POSIX.1e ACLs */ + n = facl_get(fd, 0, &acl); + if (n != 0) close(fd); - skipping("ACL tests require that ACL support be enabled on the filesystem"); + if (n != 0 && errno == ENOSYS) { + acl_free(acl1); + skipping("POSIX.1e ACLs are not supported on this filesystem"); return; } - if (n != 0 && errno == EINVAL) { + failure("facl_get(): errno = %d (%s)", errno, strerror(errno)); + assertEqualInt(0, n); + + if (acl->acl_type != ACLENT_T) { + acl_free(acl); + acl_free(acl1); close(fd); - skipping("This filesystem does not support POSIX.1e ACLs"); + skipping("POSIX.1e ACLs are not supported on this filesystem"); return; } - failure("acl_set_fd(): errno = %d (%s)", - errno, strerror(errno)); + + func = "facl_set()"; + n = facl_set(fd, acl1); +#else + func = "acl_set_fd()"; + n = acl_set_fd(fd, acl1); +#endif + acl_free(acl1); + + if (n != 0) { +#if HAVE_SUN_ACL + if (errno == ENOSYS) +#else + if (errno == EOPNOTSUPP || errno == EINVAL) +#endif + { + close(fd); + skipping("POSIX.1e ACLs are not supported on this filesystem"); + return; + } + } + failure("%s: errno = %d (%s)", func, errno, strerror(errno)); assertEqualInt(0, n); + close(fd); assertMakeDir("d", 0700); @@ -371,48 +530,124 @@ DEFINE_TEST(test_acl_freebsd_posix1e_read) * to read ACLs, resulting in reading the ACL from a like-named * file in the wrong directory. */ - acl2_text = "user::rwx,group::rwx,other::---,user:1:r--,group:15:r--,mask::rwx"; +#if HAVE_SUN_ACL + acl2_text = "user::rwx," + "group::rwx," + "other:---," + "user:1:r--," + "group:15:r--," + "mask:rwx"; + n = acl_fromtext(acl2_text, &acl2); + failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno)); + assertEqualInt(0, n); +#else + acl2_text = "user::rwx\n" + "group::rwx\n" + "other::---\n" + "user:1:r--\n" + "group:15:r--\n" + "mask::rwx"; acl2 = acl_from_text(acl2_text); + failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno)); assert((void *)acl2 != NULL); +#endif fd = open("d/f1", O_WRONLY | O_CREAT | O_EXCL, 0777); failure("Could not create test file?!"); if (!assert(fd >= 0)) { acl_free(acl2); return; } +#if HAVE_SUN_ACL + func = "facl_set()"; + n = facl_set(fd, acl2); +#else + func = "acl_set_fd()"; n = acl_set_fd(fd, acl2); +#endif acl_free(acl2); - if (n != 0 && errno == EOPNOTSUPP) { + if (n != 0) close(fd); - skipping("ACL tests require that ACL support be enabled on the filesystem"); - return; - } - if (n != 0 && errno == EINVAL) { - close(fd); - skipping("This filesystem does not support POSIX.1e ACLs"); - return; - } - failure("acl_set_fd(): errno = %d (%s)", - errno, strerror(errno)); + failure("%s: errno = %d (%s)", func, errno, strerror(errno)); assertEqualInt(0, n); close(fd); + /* Create directory d2 with default ACLs */ + assertMakeDir("d2", 0755); + +#if HAVE_SUN_ACL + acl3_text = "user::rwx," + "group::r-x," + "other:r-x," + "user:2:r--," + "group:16:-w-," + "mask:rwx," + "default:user::rwx," + "default:user:1:r--," + "default:group::r-x," + "default:group:15:r--," + "default:mask:rwx," + "default:other:r-x"; + n = acl_fromtext(acl3_text, &acl3); + failure("acl_fromtext(): errno = %d (%s)", errno, strerror(errno)); + assertEqualInt(0, n); +#else + acl3_text = "user::rwx\n" + "user:1:r--\n" + "group::r-x\n" + "group:15:r--\n" + "mask::rwx\n" + "other::r-x"; + acl3 = acl_from_text(acl3_text); + failure("acl_from_text(): errno = %d (%s)", errno, strerror(errno)); + assert((void *)acl3 != NULL); +#endif + +#if HAVE_SUN_ACL + func = "acl_set()"; + n = acl_set("d2", acl3); +#else + func = "acl_set_file()"; + n = acl_set_file("d2", ACL_TYPE_DEFAULT, acl3); +#endif + acl_free(acl3); + + failure("%s: errno = %d (%s)", func, errno, strerror(errno)); + assertEqualInt(0, n); + /* Create a read-from-disk object. */ assert(NULL != (a = archive_read_disk_new())); assertEqualIntA(a, ARCHIVE_OK, archive_read_disk_open(a, ".")); assert(NULL != (ae = archive_entry_new())); +#if HAVE_SUN_ACL + flags = ARCHIVE_ENTRY_ACL_TYPE_POSIX1E + | ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA + | ARCHIVE_ENTRY_ACL_STYLE_SOLARIS; + dflags = flags; +#else + flags = ARCHIVE_ENTRY_ACL_TYPE_ACCESS; + dflags = ARCHIVE_ENTRY_ACL_TYPE_DEFAULT; +#endif + /* Walk the dir until we see both of the files */ while (ARCHIVE_OK == archive_read_next_header2(a, ae)) { archive_read_disk_descend(a); if (strcmp(archive_entry_pathname(ae), "./f1") == 0) { - assertEqualString(archive_entry_acl_text(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS), acl1_text); - + acl_text = archive_entry_acl_to_text(ae, NULL, flags); + assertEqualString(acl_text, acl1_text); + free(acl_text); } else if (strcmp(archive_entry_pathname(ae), "./d/f1") == 0) { - assertEqualString(archive_entry_acl_text(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS), acl2_text); + acl_text = archive_entry_acl_to_text(ae, NULL, flags); + assertEqualString(acl_text, acl2_text); + free(acl_text); + } else if (strcmp(archive_entry_pathname(ae), "./d2") == 0) { + acl_text = archive_entry_acl_to_text(ae, NULL, dflags); + assertEqualString(acl_text, acl3_text); + free(acl_text); } } - archive_free(a); + archive_entry_free(ae); + assertEqualInt(ARCHIVE_OK, archive_free(a)); #endif } diff --git a/contrib/libarchive/libarchive/test/test_acl_posix1e.c b/contrib/libarchive/libarchive/test/test_acl_posix1e.c index 9984d4418..01167dae2 100644 --- a/contrib/libarchive/libarchive/test/test_acl_posix1e.c +++ b/contrib/libarchive/libarchive/test/test_acl_posix1e.c @@ -27,21 +27,14 @@ __FBSDID("$FreeBSD: src/lib/libarchive/test/test_acl_basic.c,v 1.6 2008/10/19 00 /* * Exercise the system-independent portion of the ACL support. - * Check that archive_entry objects can save and restore POSIX.1e-style ACL data. + * Check that archive_entry objects can save and restore POSIX.1e-style + * ACL data. * * This should work on all systems, regardless of whether local * filesystems support ACLs or not. */ -struct acl_t { - int type; /* Type of ACL: "access" or "default" */ - int permset; /* Permissions for this class of users. */ - int tag; /* Owner, User, Owning group, group, other, etc. */ - int qual; /* GID or UID of user/group, depending on tag. */ - const char *name; /* Name of user/group, depending on tag. */ -}; - -static struct acl_t acls0[] = { +static struct archive_test_acl_t acls0[] = { { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE, ARCHIVE_ENTRY_ACL_USER_OBJ, 0, "" }, { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ, @@ -50,7 +43,7 @@ static struct acl_t acls0[] = { ARCHIVE_ENTRY_ACL_OTHER, 0, "" }, }; -static struct acl_t acls1[] = { +static struct archive_test_acl_t acls1[] = { { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE, ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ, @@ -61,7 +54,7 @@ static struct acl_t acls1[] = { ARCHIVE_ENTRY_ACL_OTHER, -1, "" }, }; -static struct acl_t acls2[] = { +static struct archive_test_acl_t acls2[] = { { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE | ARCHIVE_ENTRY_ACL_READ, ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ, @@ -80,7 +73,7 @@ static struct acl_t acls2[] = { * NFS4 entry types; attempts to set these on top of POSIX.1e * attributes should fail. */ -static struct acl_t acls_nfs4[] = { +static struct archive_test_acl_t acls_nfs4[] = { /* NFS4 types */ { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, ARCHIVE_ENTRY_ACL_READ, ARCHIVE_ENTRY_ACL_USER, 78, "" }, @@ -104,106 +97,6 @@ static struct acl_t acls_nfs4[] = { ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, }; -static void -set_acls(struct archive_entry *ae, struct acl_t *acls, int n) -{ - int i; - - archive_entry_acl_clear(ae); - for (i = 0; i < n; i++) { - archive_entry_acl_add_entry(ae, - acls[i].type, acls[i].permset, acls[i].tag, acls[i].qual, - acls[i].name); - } -} - -static int -acl_match(struct acl_t *acl, int type, int permset, int tag, int qual, const char *name) -{ - if (type != acl->type) - return (0); - if (permset != acl->permset) - return (0); - if (tag != acl->tag) - return (0); - if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) - return (1); - if (tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ) - return (1); - if (tag == ARCHIVE_ENTRY_ACL_OTHER) - return (1); - if (qual != acl->qual) - return (0); - if (name == NULL) { - if (acl->name == NULL || acl->name[0] == '\0') - return (1); - return (0); - } - if (acl->name == NULL) { - if (name[0] == '\0') - return (1); - return (0); - } - return (0 == strcmp(name, acl->name)); -} - -static void -compare_acls(struct archive_entry *ae, struct acl_t *acls, int n, int mode) -{ - int *marker = malloc(sizeof(marker[0]) * n); - int i; - int r; - int type, permset, tag, qual; - int matched; - const char *name; - - for (i = 0; i < n; i++) - marker[i] = i; - - while (0 == (r = archive_entry_acl_next(ae, - ARCHIVE_ENTRY_ACL_TYPE_ACCESS, - &type, &permset, &tag, &qual, &name))) { - for (i = 0, matched = 0; i < n && !matched; i++) { - if (acl_match(&acls[marker[i]], type, permset, - tag, qual, name)) { - /* We found a match; remove it. */ - marker[i] = marker[n - 1]; - n--; - matched = 1; - } - } - if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) { - if (!matched) printf("No match for user_obj perm\n"); - failure("USER_OBJ permset (%02o) != user mode (%02o)", - permset, 07 & (mode >> 6)); - assert((permset << 6) == (mode & 0700)); - } else if (tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ) { - if (!matched) printf("No match for group_obj perm\n"); - failure("GROUP_OBJ permset %02o != group mode %02o", - permset, 07 & (mode >> 3)); - assert((permset << 3) == (mode & 0070)); - } else if (tag == ARCHIVE_ENTRY_ACL_OTHER) { - if (!matched) printf("No match for other perm\n"); - failure("OTHER permset (%02o) != other mode (%02o)", - permset, mode & 07); - assert((permset << 0) == (mode & 0007)); - } else { - failure("Could not find match for ACL " - "(type=%d,permset=%d,tag=%d,qual=%d,name=``%s'')", - type, permset, tag, qual, name); - assert(matched == 1); - } - } - assertEqualInt(ARCHIVE_EOF, r); - assert((mode_t)(mode & 0777) == (archive_entry_mode(ae) & 0777)); - failure("Could not find match for ACL " - "(type=%d,permset=%d,tag=%d,qual=%d,name=``%s'')", - acls[marker[0]].type, acls[marker[0]].permset, - acls[marker[0]].tag, acls[marker[0]].qual, acls[marker[0]].name); - assert(n == 0); /* Number of ACLs not matched should == 0 */ - free(marker); -} - DEFINE_TEST(test_acl_posix1e) { struct archive_entry *ae; @@ -223,7 +116,7 @@ DEFINE_TEST(test_acl_posix1e) * triggering unnecessary extensions. It's better to identify * trivial ACLs at the point they are being read from disk. */ - set_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0])); + archive_test_set_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0])); failure("Basic ACLs shouldn't be stored as extended ACLs"); assert(0 == archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS)); failure("Basic ACLs should set mode to 0142, not %04o", @@ -232,19 +125,28 @@ DEFINE_TEST(test_acl_posix1e) /* With any extended ACL entry, we should read back a full set. */ - set_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0])); + archive_test_set_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0])); failure("One extended ACL should flag all ACLs to be returned."); + + /* Check that entry contains only POSIX.1e types */ + assert((archive_entry_acl_types(ae) & + ARCHIVE_ENTRY_ACL_TYPE_NFS4) == 0); + assert((archive_entry_acl_types(ae) & + ARCHIVE_ENTRY_ACL_TYPE_POSIX1E) != 0); + assert(4 == archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS)); - compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]), 0142); + archive_test_compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]), + ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0142); failure("Basic ACLs should set mode to 0142, not %04o", archive_entry_mode(ae)&0777); assert((archive_entry_mode(ae) & 0777) == 0142); /* A more extensive set of ACLs. */ - set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0])); + archive_test_set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0])); assertEqualInt(6, archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS)); - compare_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]), 0543); + archive_test_compare_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]), + ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0543); failure("Basic ACLs should set mode to 0543, not %04o", archive_entry_mode(ae)&0777); assert((archive_entry_mode(ae) & 0777) == 0543); @@ -253,7 +155,7 @@ DEFINE_TEST(test_acl_posix1e) * Check that clearing ACLs gets rid of them all by repeating * the first test. */ - set_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0])); + archive_test_set_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0])); failure("Basic ACLs shouldn't be stored as extended ACLs"); assert(0 == archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS)); failure("Basic ACLs should set mode to 0142, not %04o", @@ -264,9 +166,9 @@ DEFINE_TEST(test_acl_posix1e) * Different types of malformed ACL entries that should * fail when added to existing POSIX.1e ACLs. */ - set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0])); + archive_test_set_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0])); for (i = 0; i < (int)(sizeof(acls_nfs4)/sizeof(acls_nfs4[0])); ++i) { - struct acl_t *p = &acls_nfs4[i]; + struct archive_test_acl_t *p = &acls_nfs4[i]; failure("Malformed ACL test #%d", i); assertEqualInt(ARCHIVE_FAILED, archive_entry_acl_add_entry(ae, diff --git a/contrib/libarchive/libarchive/test/test_acl_text.c b/contrib/libarchive/libarchive/test/test_acl_text.c new file mode 100644 index 000000000..23d991e40 --- /dev/null +++ b/contrib/libarchive/libarchive/test/test_acl_text.c @@ -0,0 +1,462 @@ +/*- + * Copyright (c) 2016 Martin Matuska + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" +__FBSDID("$FreeBSD$"); + +/* + * Test converting ACLs to text, both wide and non-wide + * + * This should work on all systems, regardless of whether local + * filesystems support ACLs or not. + */ + +static struct archive_test_acl_t acls0[] = { + { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, + ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_READ | + ARCHIVE_ENTRY_ACL_WRITE, + ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, + ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_READ, + ARCHIVE_ENTRY_ACL_USER, 100, "user100" }, + { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0, + ARCHIVE_ENTRY_ACL_USER, 1000, "user1000" }, + { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, + ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_READ, + ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, + ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_READ | + ARCHIVE_ENTRY_ACL_WRITE, + ARCHIVE_ENTRY_ACL_GROUP, 78, "group78" }, + { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, + ARCHIVE_ENTRY_ACL_READ | + ARCHIVE_ENTRY_ACL_EXECUTE, + ARCHIVE_ENTRY_ACL_OTHER, -1, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, + ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_READ, + ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, + ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_READ, + ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, 0, + ARCHIVE_ENTRY_ACL_OTHER, -1, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, + ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_READ, + ARCHIVE_ENTRY_ACL_USER, 101, "user101"}, + { ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, + ARCHIVE_ENTRY_ACL_EXECUTE, + ARCHIVE_ENTRY_ACL_GROUP, 79, "group79" }, +}; + +static struct archive_test_acl_t acls1[] = { + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_WRITE_DATA | + ARCHIVE_ENTRY_ACL_APPEND_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_WRITE_OWNER, + ARCHIVE_ENTRY_ACL_USER, 77, "user77" }, + { ARCHIVE_ENTRY_ACL_TYPE_DENY, + ARCHIVE_ENTRY_ACL_WRITE_DATA | + ARCHIVE_ENTRY_ACL_APPEND_DATA | + ARCHIVE_ENTRY_ACL_DELETE_CHILD | + ARCHIVE_ENTRY_ACL_DELETE | + ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT | + ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT | + ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY | + ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, + ARCHIVE_ENTRY_ACL_USER, 101, "user101" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_ENTRY_INHERITED, + ARCHIVE_ENTRY_ACL_GROUP, 78, "group78" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_WRITE_DATA | + ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_APPEND_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_WRITE_ACL | + ARCHIVE_ENTRY_ACL_WRITE_OWNER, + ARCHIVE_ENTRY_ACL_USER_OBJ, 0, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_WRITE_DATA | + ARCHIVE_ENTRY_ACL_APPEND_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL, + ARCHIVE_ENTRY_ACL_GROUP_OBJ, 0, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_EVERYONE, 0, "" }, +}; + +const char* acltext[] = { + "user::rwx\n" + "group::r-x\n" + "other::r-x\n" + "user:user100:r-x\n" + "user:user1000:---\n" + "group:group78:rwx\n" + "default:user::r-x\n" + "default:group::r-x\n" + "default:other::---\n" + "default:user:user101:r-x\n" + "default:group:group79:--x", + + "user::rwx\n" + "group::r-x\n" + "other::r-x\n" + "user:user100:r-x:100\n" + "user:user1000:---:1000\n" + "group:group78:rwx:78\n" + "default:user::r-x\n" + "default:group::r-x\n" + "default:other::---\n" + "default:user:user101:r-x:101\n" + "default:group:group79:--x:79", + + "u::rwx\n" + "g::r-x\n" + "o::r-x\n" + "u:user100:r-x:100\n" + "u:user1000:---:1000\n" + "g:group78:rwx:78\n" + "d:user::r-x\n" + "d:group::r-x\n" + "d:other::---\n" + "d:user:user101:r-x:101\n" + "d:group:group79:--x:79", + + "user::rwx\n" + "group::r-x\n" + "other::r-x\n" + "user:user100:r-x\n" + "user:user1000:---\n" + "group:group78:rwx", + + "user::rwx," + "group::r-x," + "other::r-x," + "user:user100:r-x," + "user:user1000:---," + "group:group78:rwx", + + "user::rwx\n" + "group::r-x\n" + "other::r-x\n" + "user:user100:r-x:100\n" + "user:user1000:---:1000\n" + "group:group78:rwx:78", + + "user::r-x\n" + "group::r-x\n" + "other::---\n" + "user:user101:r-x\n" + "group:group79:--x", + + "user::r-x\n" + "group::r-x\n" + "other::---\n" + "user:user101:r-x:101\n" + "group:group79:--x:79", + + "default:user::r-x\n" + "default:group::r-x\n" + "default:other::---\n" + "default:user:user101:r-x\n" + "default:group:group79:--x", + + "user:user77:rw-p--a-R-c-o-:-------:allow\n" + "user:user101:-w-pdD--------:fdin---:deny\n" + "group:group78:r-----a-R-c---:------I:allow\n" + "owner@:rwxp--aARWcCo-:-------:allow\n" + "group@:rw-p--a-R-c---:-------:allow\n" + "everyone@:r-----a-R-c--s:-------:allow", + + "user:user77:rw-p--a-R-c-o-:-------:allow:77\n" + "user:user101:-w-pdD--------:fdin---:deny:101\n" + "group:group78:r-----a-R-c---:------I:allow:78\n" + "owner@:rwxp--aARWcCo-:-------:allow\n" + "group@:rw-p--a-R-c---:-------:allow\n" + "everyone@:r-----a-R-c--s:-------:allow" +}; + +static wchar_t * +convert_s_to_ws(const char *s) +{ + size_t len; + wchar_t *ws = NULL; + + if (s != NULL) { + len = strlen(s) + 1; + ws = malloc(len * sizeof(wchar_t)); + assert(mbstowcs(ws, s, len) != (size_t)-1); + } + + return (ws); +} + +static void +compare_acl_text(struct archive_entry *ae, int flags, const char *s) +{ + char *text; + wchar_t *wtext; + wchar_t *ws; + ssize_t slen; + + ws = convert_s_to_ws(s); + + text = archive_entry_acl_to_text(ae, &slen, flags); + assertEqualString(text, s); + if (text != NULL) + assertEqualInt(strlen(text), slen); + wtext = archive_entry_acl_to_text_w(ae, &slen, flags); + assertEqualWString(wtext, ws); + if (wtext != NULL) { + assertEqualInt(wcslen(wtext), slen); + } + free(text); + free(wtext); + free(ws); +} + +DEFINE_TEST(test_acl_from_text) +{ + struct archive_entry *ae; + wchar_t *ws = NULL; + + /* Create an empty archive_entry. */ + assert((ae = archive_entry_new()) != NULL); + + /* 1a. Read POSIX.1e access ACLs from text */ + assertEqualInt(ARCHIVE_OK, + archive_entry_acl_from_text(ae, acltext[5], + ARCHIVE_ENTRY_ACL_TYPE_ACCESS)); + archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]), + ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0755); + assertEqualInt(6, archive_entry_acl_reset(ae, + ARCHIVE_ENTRY_ACL_TYPE_ACCESS)); + + /* 1b. Now read POSIX.1e default ACLs and append them */ + assertEqualInt(ARCHIVE_OK, + archive_entry_acl_from_text(ae, acltext[7], + ARCHIVE_ENTRY_ACL_TYPE_DEFAULT)); + archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]), + ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, 0755); + assertEqualInt(11, archive_entry_acl_reset(ae, + ARCHIVE_ENTRY_ACL_TYPE_POSIX1E)); + archive_entry_acl_clear(ae); + + /* 1a and 1b with wide strings */ + ws = convert_s_to_ws(acltext[5]); + + assertEqualInt(ARCHIVE_OK, + archive_entry_acl_from_text_w(ae, ws, + ARCHIVE_ENTRY_ACL_TYPE_ACCESS)); + archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]), + ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0755); + assertEqualInt(6, archive_entry_acl_reset(ae, + ARCHIVE_ENTRY_ACL_TYPE_ACCESS)); + + free(ws); + ws = convert_s_to_ws(acltext[7]); + + assertEqualInt(ARCHIVE_OK, + archive_entry_acl_from_text_w(ae, ws, + ARCHIVE_ENTRY_ACL_TYPE_DEFAULT)); + archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]), + ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, 0755); + assertEqualInt(11, archive_entry_acl_reset(ae, + ARCHIVE_ENTRY_ACL_TYPE_POSIX1E)); + archive_entry_acl_clear(ae); + + /* 2. Read POSIX.1e default ACLs from text */ + assertEqualInt(ARCHIVE_OK, + archive_entry_acl_from_text(ae, acltext[7], + ARCHIVE_ENTRY_ACL_TYPE_DEFAULT)); + archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]), + ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, 0); + assertEqualInt(5, archive_entry_acl_reset(ae, + ARCHIVE_ENTRY_ACL_TYPE_DEFAULT)); + archive_entry_acl_clear(ae); + + /* ws is still acltext[7] */ + assertEqualInt(ARCHIVE_OK, + archive_entry_acl_from_text_w(ae, ws, + ARCHIVE_ENTRY_ACL_TYPE_DEFAULT)); + archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]), + ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, 0); + assertEqualInt(5, archive_entry_acl_reset(ae, + ARCHIVE_ENTRY_ACL_TYPE_DEFAULT)); + archive_entry_acl_clear(ae); + + /* 3. Read POSIX.1e access and default ACLs from text */ + assertEqualInt(ARCHIVE_OK, + archive_entry_acl_from_text(ae, acltext[1], + ARCHIVE_ENTRY_ACL_TYPE_POSIX1E)); + archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]), + ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, 0755); + assertEqualInt(11, archive_entry_acl_reset(ae, + ARCHIVE_ENTRY_ACL_TYPE_POSIX1E)); + archive_entry_acl_clear(ae); + + free(ws); + ws = convert_s_to_ws(acltext[1]); + assertEqualInt(ARCHIVE_OK, + archive_entry_acl_from_text_w(ae, ws, + ARCHIVE_ENTRY_ACL_TYPE_POSIX1E)); + archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]), + ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, 0755); + assertEqualInt(11, archive_entry_acl_reset(ae, + ARCHIVE_ENTRY_ACL_TYPE_POSIX1E)); + archive_entry_acl_clear(ae); + + /* 4. Read POSIX.1e access and default ACLs from text (short form) */ + assertEqualInt(ARCHIVE_OK, + archive_entry_acl_from_text(ae, acltext[2], + ARCHIVE_ENTRY_ACL_TYPE_POSIX1E)); + archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]), + ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, 0755); + assertEqualInt(11, archive_entry_acl_reset(ae, + ARCHIVE_ENTRY_ACL_TYPE_POSIX1E)); + archive_entry_acl_clear(ae); + + free(ws); + ws = convert_s_to_ws(acltext[2]); + assertEqualInt(ARCHIVE_OK, + archive_entry_acl_from_text_w(ae, ws, + ARCHIVE_ENTRY_ACL_TYPE_POSIX1E)); + archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]), + ARCHIVE_ENTRY_ACL_TYPE_POSIX1E, 0755); + assertEqualInt(11, archive_entry_acl_reset(ae, + ARCHIVE_ENTRY_ACL_TYPE_POSIX1E)); + archive_entry_acl_clear(ae); + + /* 5. Read NFSv4 ACLs from text */ + assertEqualInt(ARCHIVE_OK, + archive_entry_acl_from_text(ae, acltext[10], + ARCHIVE_ENTRY_ACL_TYPE_NFS4)); + archive_test_compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]), + ARCHIVE_ENTRY_ACL_TYPE_NFS4, 0); + assertEqualInt(6, archive_entry_acl_reset(ae, + ARCHIVE_ENTRY_ACL_TYPE_NFS4)); + archive_entry_acl_clear(ae); + + free(ws); + ws = convert_s_to_ws(acltext[10]); + + assertEqualInt(ARCHIVE_OK, + archive_entry_acl_from_text_w(ae, ws, + ARCHIVE_ENTRY_ACL_TYPE_NFS4)); + archive_test_compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]), + ARCHIVE_ENTRY_ACL_TYPE_NFS4, 0); + assertEqualInt(6, archive_entry_acl_reset(ae, + ARCHIVE_ENTRY_ACL_TYPE_NFS4)); + archive_entry_acl_clear(ae); + + free(ws); + archive_entry_free(ae); +} + +DEFINE_TEST(test_acl_to_text) +{ + struct archive_entry *ae; + + /* Create an empty archive_entry. */ + assert((ae = archive_entry_new()) != NULL); + + /* Write POSIX.1e ACLs */ + archive_test_set_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0])); + + /* No flags should give output like getfacl(1) on linux */ + compare_acl_text(ae, 0, acltext[0]); + + /* This should give the same output as previous test */ + compare_acl_text(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS | + ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, acltext[0]); + + /* This should give the same output as previous two tests */ + compare_acl_text(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS | + ARCHIVE_ENTRY_ACL_TYPE_DEFAULT | + ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT, acltext[0]); + + /* POSIX.1e access and default ACLs with appended ID */ + compare_acl_text(ae, ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID, acltext[1]); + + /* POSIX.1e access acls only, like getfacl(1) on FreeBSD */ + compare_acl_text(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS, acltext[3]); + + /* POSIX.1e access acls separated with comma */ + compare_acl_text(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS | + ARCHIVE_ENTRY_ACL_STYLE_SEPARATOR_COMMA, + acltext[4]); + + /* POSIX.1e access acls with appended user or group ID */ + compare_acl_text(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS | + ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID, acltext[5]); + + /* POSIX.1e default acls */ + compare_acl_text(ae, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, acltext[6]); + + /* POSIX.1e default acls with appended user or group ID */ + compare_acl_text(ae, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT | + ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID, acltext[7]); + + /* POSIX.1e default acls prefixed with default: */ + compare_acl_text(ae, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT | + ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT, acltext[8]); + + /* Write NFSv4 ACLs */ + archive_test_set_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0])); + + /* NFSv4 ACLs like getfacl(1) on FreeBSD */ + compare_acl_text(ae, 0, acltext[9]); + + /* NFSv4 ACLs like "getfacl -i" on FreeBSD */ + compare_acl_text(ae, ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID, acltext[10]); + + archive_entry_free(ae); +} diff --git a/contrib/libarchive/libarchive/test/test_archive_read_add_passphrase.c b/contrib/libarchive/libarchive/test/test_archive_read_add_passphrase.c index 68dec10d9..0ce5a76ae 100644 --- a/contrib/libarchive/libarchive/test/test_archive_read_add_passphrase.c +++ b/contrib/libarchive/libarchive/test/test_archive_read_add_passphrase.c @@ -191,7 +191,7 @@ DEFINE_TEST(test_archive_read_add_passphrase_set_callback3) /* Fist call, we should get "passCallBack" as a passphrase. */ assertEqualString("passCallBack", __archive_read_next_passphrase(ar)); __archive_read_reset_passphrase(ar); - /* After reset passphrase, we should get "passCallBack"passphrase. */ + /* After reset passphrase, we should get "passCallBack" passphrase. */ assertEqualString("passCallBack", __archive_read_next_passphrase(ar)); /* Second call, we should get NULL which means all the passphrases * are passed already. */ diff --git a/contrib/libarchive/libarchive/test/test_archive_string.c b/contrib/libarchive/libarchive/test/test_archive_string.c index 9e3f90702..7fa743ba9 100644 --- a/contrib/libarchive/libarchive/test/test_archive_string.c +++ b/contrib/libarchive/libarchive/test/test_archive_string.c @@ -67,6 +67,8 @@ test_archive_string_ensure(void) assert(&s == archive_string_ensure(&s, EXTENT + 1)); assertNonNULLString(0, 2 * EXTENT, s); + + archive_string_free(&s); } static void @@ -92,6 +94,8 @@ test_archive_strcat(void) /* non-empty target, non-empty source */ assert(&s == archive_strcat(&s, "baz")); assertExactString(8, EXTENT, "fubarbaz", s); + + archive_string_free(&s); } static void @@ -109,6 +113,8 @@ test_archive_strappend_char(void) /* non-empty target */ archive_strappend_char(&s, 'Y'); assertExactString(2, EXTENT, "XY", s); + + archive_string_free(&s); } /* archive_strnXXX() tests focus on length handling. @@ -134,6 +140,8 @@ test_archive_strncat(void) /* long read is ok too! */ assert(&s == archive_strncat(&s, "snafu", 8)); assertExactString(13, EXTENT, "snafubarsnafu", s); + + archive_string_free(&s); } static void @@ -155,6 +163,8 @@ test_archive_strncpy(void) /* long read is ok too! */ assert(&s == archive_strncpy(&s, "snafu", 8)); assertExactString(5, EXTENT, "snafu", s); + + archive_string_free(&s); } static void @@ -176,6 +186,8 @@ test_archive_strcpy(void) /* dirty target, empty source */ assert(&s == archive_strcpy(&s, "")); assertExactString(0, EXTENT, "", s); + + archive_string_free(&s); } static void @@ -222,6 +234,11 @@ test_archive_string_concat(void) archive_string_concat(&t, &s); assertExactString(5, EXTENT, "snafu", s); assertExactString(5, EXTENT, "snafu", t); + + archive_string_free(&v); + archive_string_free(&u); + archive_string_free(&t); + archive_string_free(&s); } static void @@ -274,6 +291,11 @@ test_archive_string_copy(void) archive_string_copy(&t, &s); assertExactString(5, EXTENT, "fubar", s); assertExactString(5, EXTENT, "fubar", t); + + archive_string_free(&v); + archive_string_free(&u); + archive_string_free(&t); + archive_string_free(&s); } static void @@ -328,6 +350,8 @@ test_archive_string_sprintf(void) archive_string_empty(&s); archive_string_sprintf(&s, "%d", 1234567890); assertExactString(10, 8 * EXTENT, "1234567890", s); + + archive_string_free(&s); } DEFINE_TEST(test_archive_string) diff --git a/contrib/libarchive/libarchive/test/test_compat_gtar.c b/contrib/libarchive/libarchive/test/test_compat_gtar.c index b33e6ab65..975b824c4 100644 --- a/contrib/libarchive/libarchive/test/test_compat_gtar.c +++ b/contrib/libarchive/libarchive/test/test_compat_gtar.c @@ -142,6 +142,8 @@ test_compat_gtar_2(void) assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_NONE); assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_GNUTAR); + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); } DEFINE_TEST(test_compat_gtar) diff --git a/contrib/libarchive/libarchive/test/test_compat_solaris_tar_acl.c b/contrib/libarchive/libarchive/test/test_compat_solaris_tar_acl.c index d4654d02f..3d063c1db 100644 --- a/contrib/libarchive/libarchive/test/test_compat_solaris_tar_acl.c +++ b/contrib/libarchive/libarchive/test/test_compat_solaris_tar_acl.c @@ -1,5 +1,6 @@ /*- * 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 @@ -26,101 +27,239 @@ __FBSDID("$FreeBSD$"); /* - * Exercise support for reading Solaris-style ACL data - * from tar archives. + * Verify reading entries with POSIX.1e and NFSv4 ACLs from archives created + * with Solaris tar. * - * This should work on all systems, regardless of whether local - * filesystems support ACLs or not. + * This should work on all systems, regardless of whether local filesystems + * support ACLs or not. */ +static struct archive_test_acl_t acls0[] = { + { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_WRITE | + ARCHIVE_ENTRY_ACL_READ, + ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE, + ARCHIVE_ENTRY_ACL_USER, 71, "lp" }, + { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ, + ARCHIVE_ENTRY_ACL_USER, 666, "666" }, + { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_WRITE | ARCHIVE_ENTRY_ACL_READ, + ARCHIVE_ENTRY_ACL_USER, 1000, "1000" }, + { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ, + ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ, + ARCHIVE_ENTRY_ACL_MASK, -1, ""}, + { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_READ, + ARCHIVE_ENTRY_ACL_OTHER, -1, "" }, +}; + +static struct archive_test_acl_t acls1[] = { + { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_WRITE | ARCHIVE_ENTRY_ACL_READ, + ARCHIVE_ENTRY_ACL_USER_OBJ, -1, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_WRITE | ARCHIVE_ENTRY_ACL_READ, + ARCHIVE_ENTRY_ACL_USER, 2, "bin" }, + { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_READ, + ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_READ, + ARCHIVE_ENTRY_ACL_GROUP, 3, "sys" }, + { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_READ, + ARCHIVE_ENTRY_ACL_MASK, -1, ""}, + { ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0, + ARCHIVE_ENTRY_ACL_OTHER, -1, "" }, +}; + +static struct archive_test_acl_t acls2[] = { + { ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_WRITE | ARCHIVE_ENTRY_ACL_READ, + ARCHIVE_ENTRY_ACL_USER_OBJ, -1 ,"" }, + { ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_WRITE | ARCHIVE_ENTRY_ACL_READ, + ARCHIVE_ENTRY_ACL_USER, 2, "bin" }, + { ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_READ, + ARCHIVE_ENTRY_ACL_GROUP_OBJ, -1, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_READ, + ARCHIVE_ENTRY_ACL_GROUP, 3, "sys" }, + { ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_WRITE | ARCHIVE_ENTRY_ACL_READ, + ARCHIVE_ENTRY_ACL_MASK, -1, ""}, + { ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, 0, + ARCHIVE_ENTRY_ACL_OTHER, -1, "" }, +}; + +static struct archive_test_acl_t acls3[] = { + { ARCHIVE_ENTRY_ACL_TYPE_DENY, + ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_WRITE_DATA | + ARCHIVE_ENTRY_ACL_APPEND_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_WRITE_ACL | + ARCHIVE_ENTRY_ACL_WRITE_OWNER | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_GROUP, 12, "daemon" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_WRITE_DATA | + ARCHIVE_ENTRY_ACL_APPEND_DATA | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_GROUP, 2, "bin" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_USER, 4, "adm" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_WRITE_DATA | + ARCHIVE_ENTRY_ACL_APPEND_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_WRITE_ACL | + ARCHIVE_ENTRY_ACL_WRITE_OWNER | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_USER_OBJ, 0, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_GROUP_OBJ, 0, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_EVERYONE, 0, "" }, +}; + +static struct archive_test_acl_t acls4[] = { + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_WRITE_DATA | + ARCHIVE_ENTRY_ACL_APPEND_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_WRITE_ACL | + ARCHIVE_ENTRY_ACL_WRITE_OWNER | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE | + ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT | + ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT | + ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, + ARCHIVE_ENTRY_ACL_USER, 1100, "1100" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE | + ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT | + ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, + ARCHIVE_ENTRY_ACL_GROUP, 4, "adm" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_WRITE_DATA | + ARCHIVE_ENTRY_ACL_APPEND_DATA | + ARCHIVE_ENTRY_ACL_DELETE_CHILD | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_WRITE_ACL | + ARCHIVE_ENTRY_ACL_WRITE_OWNER | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_USER_OBJ, 0, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_EXECUTE | + ARCHIVE_ENTRY_ACL_READ_DATA | + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_GROUP_OBJ, 0, "" }, + { ARCHIVE_ENTRY_ACL_TYPE_ALLOW, + ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES | + ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS | + ARCHIVE_ENTRY_ACL_READ_ACL | + ARCHIVE_ENTRY_ACL_SYNCHRONIZE, + ARCHIVE_ENTRY_ACL_EVERYONE, 0, "" }, +}; + DEFINE_TEST(test_compat_solaris_tar_acl) { + char name[] = "test_compat_solaris_tar_acl.tar"; struct archive *a; struct archive_entry *ae; - const char *reference1 = "test_compat_solaris_tar_acl.tar"; - int type, permset, tag, qual; - const char *name; - /* Sample file generated on Solaris 10 */ - extract_reference_file(reference1); + /* Read archive file */ assert(NULL != (a = archive_read_new())); - assertA(0 == archive_read_support_format_all(a)); - assertA(0 == archive_read_support_filter_all(a)); - assertA(0 == archive_read_open_filename(a, reference1, 512)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); + extract_reference_file(name); + assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, name, + 10240)); - /* Archive has 1 entry with some ACLs set on it. */ + /* First item has access ACLs */ assertA(0 == archive_read_next_header(a, &ae)); + failure("One extended ACL should flag all ACLs to be returned."); + assertEqualInt(7, archive_entry_acl_reset(ae, + ARCHIVE_ENTRY_ACL_TYPE_ACCESS)); + archive_test_compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]), + ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0644); failure("Basic ACLs should set mode to 0644, not %04o", archive_entry_mode(ae)&0777); - assertEqualInt((archive_entry_mode(ae) & 0777), 0644); - assertEqualInt(7, archive_entry_acl_reset(ae, - ARCHIVE_ENTRY_ACL_TYPE_ACCESS)); - assertEqualInt(ARCHIVE_OK, archive_entry_acl_next(ae, - ARCHIVE_ENTRY_ACL_TYPE_ACCESS, - &type, &permset, &tag, &qual, &name)); - assertEqualInt(ARCHIVE_ENTRY_ACL_TYPE_ACCESS, type); - assertEqualInt(006, permset); - assertEqualInt(ARCHIVE_ENTRY_ACL_USER_OBJ, tag); - assertEqualInt(-1, qual); - assert(name == NULL); - - assertEqualInt(ARCHIVE_OK, archive_entry_acl_next(ae, - ARCHIVE_ENTRY_ACL_TYPE_ACCESS, - &type, &permset, &tag, &qual, &name)); - assertEqualInt(ARCHIVE_ENTRY_ACL_TYPE_ACCESS, type); - assertEqualInt(004, permset); - assertEqualInt(ARCHIVE_ENTRY_ACL_GROUP_OBJ, tag); - assertEqualInt(-1, qual); - assert(name == NULL); + assert((archive_entry_mode(ae) & 0777) == 0644); - assertEqualInt(ARCHIVE_OK, archive_entry_acl_next(ae, - ARCHIVE_ENTRY_ACL_TYPE_ACCESS, - &type, &permset, &tag, &qual, &name)); - assertEqualInt(ARCHIVE_ENTRY_ACL_TYPE_ACCESS, type); - assertEqualInt(004, permset); - assertEqualInt(ARCHIVE_ENTRY_ACL_OTHER, tag); - assertEqualInt(-1, qual); - assert(name == NULL); - - assertEqualInt(ARCHIVE_OK, archive_entry_acl_next(ae, - ARCHIVE_ENTRY_ACL_TYPE_ACCESS, - &type, &permset, &tag, &qual, &name)); - assertEqualInt(ARCHIVE_ENTRY_ACL_TYPE_ACCESS, type); - assertEqualInt(001, permset); - assertEqualInt(ARCHIVE_ENTRY_ACL_USER, tag); - assertEqualInt(71, qual); - assertEqualString(name, "lp"); - - assertEqualInt(ARCHIVE_OK, archive_entry_acl_next(ae, - ARCHIVE_ENTRY_ACL_TYPE_ACCESS, - &type, &permset, &tag, &qual, &name)); - assertEqualInt(ARCHIVE_ENTRY_ACL_TYPE_ACCESS, type); - assertEqualInt(004, permset); - assertEqualInt(ARCHIVE_ENTRY_ACL_USER, tag); - assertEqualInt(666, qual); - assertEqualString(name, "666"); - - assertEqualInt(ARCHIVE_OK, archive_entry_acl_next(ae, - ARCHIVE_ENTRY_ACL_TYPE_ACCESS, - &type, &permset, &tag, &qual, &name)); - assertEqualInt(ARCHIVE_ENTRY_ACL_TYPE_ACCESS, type); - assertEqualInt(007, permset); - assertEqualInt(ARCHIVE_ENTRY_ACL_USER, tag); - assertEqualInt(1000, qual); - assertEqualString(name, "trasz"); + /* Second item has default and access ACLs */ + assertA(0 == archive_read_next_header(a, &ae)); + assertEqualInt(6, archive_entry_acl_reset(ae, + ARCHIVE_ENTRY_ACL_TYPE_ACCESS)); + archive_test_compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]), + ARCHIVE_ENTRY_ACL_TYPE_ACCESS, 0750); + failure("Basic ACLs should set mode to 0750, not %04o", + archive_entry_mode(ae)&0777); + assert((archive_entry_mode(ae) & 0777) == 0750); + assertEqualInt(6, archive_entry_acl_reset(ae, + ARCHIVE_ENTRY_ACL_TYPE_DEFAULT)); + archive_test_compare_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]), + ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, 0750); - assertEqualInt(ARCHIVE_OK, archive_entry_acl_next(ae, - ARCHIVE_ENTRY_ACL_TYPE_ACCESS, - &type, &permset, &tag, &qual, &name)); - assertEqualInt(ARCHIVE_ENTRY_ACL_TYPE_ACCESS, type); - assertEqualInt(004, permset); - assertEqualInt(ARCHIVE_ENTRY_ACL_MASK, tag); - assertEqualInt(-1, qual); - assertEqualString(name, NULL); + /* Third item has NFS4 ACLs */ + assertA(0 == archive_read_next_header(a, &ae)); + assertEqualInt(6, archive_entry_acl_reset(ae, + ARCHIVE_ENTRY_ACL_TYPE_NFS4)); + archive_test_compare_acls(ae, acls3, sizeof(acls3)/sizeof(acls3[0]), + ARCHIVE_ENTRY_ACL_TYPE_NFS4, 0); - assertEqualInt(ARCHIVE_EOF, archive_entry_acl_next(ae, - ARCHIVE_ENTRY_ACL_TYPE_ACCESS, - &type, &permset, &tag, &qual, &name)); + /* Fourth item has NFS4 ACLs and inheritance flags */ + assertA(0 == archive_read_next_header(a, &ae)); + assertEqualInt(5, archive_entry_acl_reset(ae, + ARCHIVE_ENTRY_ACL_TYPE_NFS4)); + archive_test_compare_acls(ae, acls4, sizeof(acls4)/sizeof(acls0[4]), + ARCHIVE_ENTRY_ACL_TYPE_NFS4, 0); /* Close the archive. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); diff --git a/contrib/libarchive/libarchive/test/test_compat_solaris_tar_acl.tar.uu b/contrib/libarchive/libarchive/test/test_compat_solaris_tar_acl.tar.uu index 229b33567..028dd61a4 100644 --- a/contrib/libarchive/libarchive/test/test_compat_solaris_tar_acl.tar.uu +++ b/contrib/libarchive/libarchive/test/test_compat_solaris_tar_acl.tar.uu @@ -1,61 +1,163 @@ -$FreeBSD$ -begin 644 test_acl_solaris.tar -M9FEL92UW:71H+7!O#HW,2QU#HW,2QU#HQ,#`P+&=R;W5P.CIR+2TL;6%S:SIR+69I;&4M=VET:"UP -M;W-I>"UA8VQS```````````````````````````````````````````````` -M```````````````````````````````````````````````````````````P -M,#`P-C0T`#`P,#$W-3``,#`P,#`P,``P,#`P,#`P,#`P,``Q,3$W-#8P-#$U -M-P`P,#$U,30T`#`````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M````````````````````````````=7-T87(`,#!T@`````````````` -M`````````````````````')O;W0````````````````````````````````` -M````,#`P,#(Q,``P,#`P,#$P```````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -M```````````````````````````````````````````````````````````` -H```````````````````````````````````````````````````````` -` +M.C$P,# Z"UA8VQS +M P +M,# P-C0T # P,#$W-3 ,# P,# P, P,# P,# P,# P, Q,3$W-#8P-#$U +M-P P,#$T,#

"QU"QO=&AE"QD969A=6QT=7-E' M+2TM+2TM+2US.BTM+2TM+2TZ86QL;W' M+6%!4E=C0V]S.BTM+2TM+2TZ9&5N>3HQ,BQG +M6]N94 Z+2TM+2TM82U2+6,M+7,Z +M+2TM+2TM+3IA;&QO=P 4 +M +M "HUP@( -, ,S P,# P-0!U' M1&%!4E=C +M0V]S.BTM+2TM+2TZ86QL;W"TM+6$M4BUC+2US.BTM+2TM +M+2TZ86QL;W"TM+2TM+2TM+2TM.BTM+2TM+2TZ9&5N>3HW."QG3HW."QU'`M+6%!4E=C0V]S.BTM+2TM+2TZ86QL;W'`M+6%!4E=C +M+2US.BTM+2TM+2TZ86QL;W"TM+6$M4BUC+2US.BTM +M+2TM+2TZ86QL;W<*```````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M``````````````````````````````````````````````!D:7(Q+P`````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M,#`P,#type) - return (0); - if (permset != acl->permset) - return (0); - if (tag != acl->tag) - return (0); - if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) - return (1); - if (tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ) - return (1); - if (tag == ARCHIVE_ENTRY_ACL_OTHER) - return (1); - if (tag == ARCHIVE_ENTRY_ACL_MASK) - return (1); - if (name == NULL) - return (acl->name == NULL || acl->name[0] == '\0'); - if (acl->name == NULL) - return (name == NULL || name[0] == '\0'); - return (0 == strcmp(name, acl->name)); -} - -static void -compare_acls(struct archive_entry *ae, struct acl_t *acls, int n, int mode, - int want_type) -{ - int *marker = malloc(sizeof(marker[0]) * n); - int i; - int r; - int type, permset, tag, qual; - int matched; - const char *name; - - for (i = 0; i < n; i++) - marker[i] = i; - - while (0 == (r = archive_entry_acl_next(ae, want_type, - &type, &permset, &tag, &qual, &name))) { - for (i = 0, matched = 0; i < n && !matched; i++) { - if (acl_match(&acls[marker[i]], type, permset, - tag, name)) { - /* We found a match; remove it. */ - marker[i] = marker[n - 1]; - n--; - matched = 1; - } - } - if (tag == ARCHIVE_ENTRY_ACL_USER_OBJ) { - if (!matched) printf("No match for user_obj perm\n"); - if (want_type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) { - failure("USER_OBJ permset (%02o) != user mode (%02o)", - permset, 07 & (mode >> 6)); - assert((permset << 6) == (mode & 0700)); - } - } else if (tag == ARCHIVE_ENTRY_ACL_GROUP_OBJ) { - if (!matched) printf("No match for group_obj perm\n"); - if (want_type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) { - failure("GROUP_OBJ permset %02o != group mode %02o", - permset, 07 & (mode >> 3)); - assert((permset << 3) == (mode & 0070)); - } - } else if (tag == ARCHIVE_ENTRY_ACL_OTHER) { - if (!matched) printf("No match for other perm\n"); - if (want_type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) { - failure("OTHER permset (%02o) != other mode (%02o)", - permset, mode & 07); - assert((permset << 0) == (mode & 0007)); - } - } else if (tag != ARCHIVE_ENTRY_ACL_MASK) { - failure("Could not find match for ACL " - "(type=%d,permset=%d,tag=%d,name=``%s'')", - type, permset, tag, name); - assert(matched == 1); - } - } - assertEqualInt(ARCHIVE_EOF, r); - assert((mode_t)(mode & 0777) == (archive_entry_mode(ae) & 0777)); - failure("Could not find match for ACL " - "(type=%d,permset=%d,tag=%d,name=``%s'')", - acls[marker[0]].type, acls[marker[0]].permset, - acls[marker[0]].tag, acls[marker[0]].name); - assert(n == 0); /* Number of ACLs not matched should == 0 */ - free(marker); -} - -DEFINE_TEST(test_compat_star_acl_posix1e) -{ - char name[] = "test_compat_star_acl_posix1e.tar"; - struct archive *a; - struct archive_entry *ae; - - /* Read archive file */ - assert(NULL != (a = archive_read_new())); - assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); - assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); - extract_reference_file(name); - assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, name, 10240)); - - /* First item has a few ACLs */ - assertA(0 == archive_read_next_header(a, &ae)); - failure("One extended ACL should flag all ACLs to be returned."); - assertEqualInt(5, archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS)); - compare_acls(ae, acls0, sizeof(acls0)/sizeof(acls0[0]), 0142, ARCHIVE_ENTRY_ACL_TYPE_ACCESS); - failure("Basic ACLs should set mode to 0142, not %04o", - archive_entry_mode(ae)&0777); - assert((archive_entry_mode(ae) & 0777) == 0142); - - /* Second item has pretty extensive ACLs */ - assertA(0 == archive_read_next_header(a, &ae)); - assertEqualInt(7, archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_ACCESS)); - compare_acls(ae, acls1, sizeof(acls1)/sizeof(acls1[0]), 0543, ARCHIVE_ENTRY_ACL_TYPE_ACCESS); - failure("Basic ACLs should set mode to 0543, not %04o", - archive_entry_mode(ae)&0777); - assert((archive_entry_mode(ae) & 0777) == 0543); - - /* Third item has default ACLs */ - assertA(0 == archive_read_next_header(a, &ae)); - assertEqualInt(6, archive_entry_acl_reset(ae, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT)); - compare_acls(ae, acls2, sizeof(acls2)/sizeof(acls2[0]), 0142, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT); - failure("Basic ACLs should set mode to 0142, not %04o", - archive_entry_mode(ae)&0777); - assert((archive_entry_mode(ae) & 0777) == 0142); - - /* Close the archive. */ - assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); - assertEqualInt(ARCHIVE_OK, archive_read_free(a)); -} diff --git a/contrib/libarchive/libarchive/test/test_compat_uudecode.c b/contrib/libarchive/libarchive/test/test_compat_uudecode.c index 95b1c9a8b..cfb17c857 100644 --- a/contrib/libarchive/libarchive/test/test_compat_uudecode.c +++ b/contrib/libarchive/libarchive/test/test_compat_uudecode.c @@ -40,7 +40,7 @@ static char archive_data[] = { }; /* - * Compatibility: uudecode command ignores junk data placed ater the "end" + * Compatibility: uudecode command ignores junk data placed after the "end" * marker. */ DEFINE_TEST(test_compat_uudecode) diff --git a/contrib/libarchive/libarchive/test/test_fuzz.c b/contrib/libarchive/libarchive/test/test_fuzz.c index b70a415ac..e896f607e 100644 --- a/contrib/libarchive/libarchive/test/test_fuzz.c +++ b/contrib/libarchive/libarchive/test/test_fuzz.c @@ -406,10 +406,12 @@ DEFINE_TEST(test_fuzz_tar) "test_read_format_tar_empty_filename.tar", NULL }; +#if HAVE_LIBLZO2 && HAVE_LZO_LZO1X_H && HAVE_LZO_LZOCONF_H static const char *fileset9[] = { "test_compat_lzop_1.tar.lzo", NULL }; +#endif static const struct files filesets[] = { {0, fileset1}, /* Exercise bzip2 decompressor. */ {1, fileset1}, @@ -420,7 +422,9 @@ DEFINE_TEST(test_fuzz_tar) {0, fileset6}, /* Exercise xz decompressor. */ {0, fileset7}, {0, fileset8}, +#if HAVE_LIBLZO2 && HAVE_LZO_LZO1X_H && HAVE_LZO_LZOCONF_H {0, fileset9}, /* Exercise lzo decompressor. */ +#endif {1, NULL} }; test_fuzz(filesets); diff --git a/contrib/libarchive/libarchive/test/test_read_disk_directory_traversals.c b/contrib/libarchive/libarchive/test/test_read_disk_directory_traversals.c index 31eb76b93..c9aca8fa9 100644 --- a/contrib/libarchive/libarchive/test/test_read_disk_directory_traversals.c +++ b/contrib/libarchive/libarchive/test/test_read_disk_directory_traversals.c @@ -1320,11 +1320,13 @@ test_callbacks(void) assertUtimes("cb", 886622, 0, 886622, 0); assert((ae = archive_entry_new()) != NULL); - if (assert((a = archive_read_disk_new()) != NULL)) { + assert((a = archive_read_disk_new()) != NULL); + if (a == NULL) { archive_entry_free(ae); return; } - if (assert((m = archive_match_new()) != NULL)) { + assert((m = archive_match_new()) != NULL); + if (m == NULL) { archive_entry_free(ae); archive_read_free(a); archive_match_free(m); @@ -1377,6 +1379,10 @@ test_callbacks(void) /* Close the disk object. */ assertEqualInt(ARCHIVE_OK, archive_read_close(a)); + /* Reset name filter */ + assertEqualIntA(a, ARCHIVE_OK, + archive_read_disk_set_matching(a, NULL, NULL, NULL)); + /* * Test2: Traversals with a metadata filter. */ @@ -1394,7 +1400,7 @@ test_callbacks(void) while (file_count--) { archive_entry_clear(ae); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header2(a, ae)); - failure("File 'cb/f1' should be exclueded"); + failure("File 'cb/f1' should be excluded"); assert(strcmp(archive_entry_pathname(ae), "cb/f1") != 0); if (strcmp(archive_entry_pathname(ae), "cb") == 0) { assertEqualInt(archive_entry_filetype(ae), AE_IFDIR); diff --git a/contrib/libarchive/libarchive/test/test_read_filter_lzop.c b/contrib/libarchive/libarchive/test/test_read_filter_lzop.c index 86a5e6e84..acce6a4c2 100644 --- a/contrib/libarchive/libarchive/test/test_read_filter_lzop.c +++ b/contrib/libarchive/libarchive/test/test_read_filter_lzop.c @@ -39,13 +39,16 @@ DEFINE_TEST(test_read_filter_lzop) assert((a = archive_read_new()) != NULL); r = archive_read_support_filter_lzop(a); if (r != ARCHIVE_OK) { - if (r == ARCHIVE_WARN && !canLzop()) { + if (!canLzop()) { assertEqualInt(ARCHIVE_OK, archive_read_free(a)); skipping("lzop compression is not supported " "on this platform"); - } else + return; + } else if (r != ARCHIVE_WARN) { assertEqualIntA(a, ARCHIVE_OK, r); - return; + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); + return; + } } assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); assertEqualIntA(a, ARCHIVE_OK, diff --git a/contrib/libarchive/libarchive/test/test_read_filter_lzop_multiple_parts.c b/contrib/libarchive/libarchive/test/test_read_filter_lzop_multiple_parts.c index 3b0febbd7..82eaf3539 100644 --- a/contrib/libarchive/libarchive/test/test_read_filter_lzop_multiple_parts.c +++ b/contrib/libarchive/libarchive/test/test_read_filter_lzop_multiple_parts.c @@ -36,12 +36,16 @@ DEFINE_TEST(test_read_filter_lzop_multiple_parts) assert((a = archive_read_new()) != NULL); r = archive_read_support_filter_lzop(a); if (r != ARCHIVE_OK) { - if (r == ARCHIVE_WARN && !canLzop()) { - assertEqualInt(ARCHIVE_OK, archive_read_free(a)); + if (!canLzop()) { skipping("lzop compression is not supported " "on this platform"); + } else if (r == ARCHIVE_WARN) { + skipping("lzop multiple parts decoding is not " + "supported via external program"); + } else assertEqualIntA(a, ARCHIVE_OK, r); + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); return; } assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); diff --git a/contrib/libarchive/libarchive/test/test_read_format_7zip.c b/contrib/libarchive/libarchive/test/test_read_format_7zip.c index 14447def8..1d1e4c75d 100644 --- a/contrib/libarchive/libarchive/test/test_read_format_7zip.c +++ b/contrib/libarchive/libarchive/test/test_read_format_7zip.c @@ -688,7 +688,7 @@ test_symname() assertEqualInt(32, archive_read_data(a, buff, sizeof(buff))); assertEqualMem(buff, "hellohellohello\nhellohellohello\n", 32); - /* Verify symbolic-linke symlinkfile. */ + /* Verify symbolic-link symlinkfile. */ assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualInt((AE_IFLNK | 0755), archive_entry_mode(ae)); assertEqualString("symlinkfile", archive_entry_pathname(ae)); diff --git a/contrib/libarchive/libarchive/test/test_read_format_cpio_afio.c b/contrib/libarchive/libarchive/test/test_read_format_cpio_afio.c index 16065eb0a..95d3171e7 100644 --- a/contrib/libarchive/libarchive/test/test_read_format_cpio_afio.c +++ b/contrib/libarchive/libarchive/test/test_read_format_cpio_afio.c @@ -27,7 +27,7 @@ __FBSDID("$FreeBSD$"); /* -ecute the following to rebuild the data for this program: +execute the following to rebuild the data for this program: tail -n +33 test_read_format_cpio_afio.c | /bin/sh # How to make a sample data. diff --git a/contrib/libarchive/libarchive/test/test_read_format_isorr_bz2.c b/contrib/libarchive/libarchive/test/test_read_format_isorr_bz2.c index 3cb30a41a..bff385ca1 100644 --- a/contrib/libarchive/libarchive/test/test_read_format_isorr_bz2.c +++ b/contrib/libarchive/libarchive/test/test_read_format_isorr_bz2.c @@ -26,7 +26,7 @@ __FBSDID("$FreeBSD$"); /* -PLEASE use old cdrtools; mkisofs verion is 2.01. +PLEASE use old cdrtools; mkisofs version is 2.01. This version mkisofs made wrong "SL" System Use Entry of RRIP. Execute the following command to rebuild the data for this program: diff --git a/contrib/libarchive/libarchive/test/test_read_format_zip.c b/contrib/libarchive/libarchive/test/test_read_format_zip.c index 62a49baab..29b3fc22a 100644 --- a/contrib/libarchive/libarchive/test/test_read_format_zip.c +++ b/contrib/libarchive/libarchive/test/test_read_format_zip.c @@ -126,6 +126,7 @@ test_basic(void) assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); assertEqualIntA(a, ARCHIVE_OK, read_open_memory(a, p, s, 31)); verify_basic(a, 0); + free(p); } /* @@ -195,6 +196,7 @@ test_info_zip_ux(void) assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); assertEqualIntA(a, ARCHIVE_OK, read_open_memory(a, p, s, 108)); verify_info_zip_ux(a, 0); + free(p); } /* @@ -258,6 +260,7 @@ test_extract_length_at_end(void) assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); assertEqualIntA(a, ARCHIVE_OK, read_open_memory(a, p, s, 108)); verify_extract_length_at_end(a, 0); + free(p); } static void @@ -294,6 +297,8 @@ test_symlink(void) assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a)); + + free(p); } DEFINE_TEST(test_read_format_zip) diff --git a/contrib/libarchive/libarchive/test/test_read_format_zip_comment_stored.c b/contrib/libarchive/libarchive/test/test_read_format_zip_comment_stored.c index d2b935de2..b92b2886c 100644 --- a/contrib/libarchive/libarchive/test/test_read_format_zip_comment_stored.c +++ b/contrib/libarchive/libarchive/test/test_read_format_zip_comment_stored.c @@ -63,6 +63,8 @@ verify(const char *refname) assertEqualInt(archive_entry_is_encrypted(ae), 0); assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a)); + + free(p); } DEFINE_TEST(test_read_format_zip_comment_stored) diff --git a/contrib/libarchive/libarchive/test/test_read_format_zip_filename.c b/contrib/libarchive/libarchive/test/test_read_format_zip_filename.c index 93ba09b3e..4dd2e8ad6 100644 --- a/contrib/libarchive/libarchive/test/test_read_format_zip_filename.c +++ b/contrib/libarchive/libarchive/test/test_read_format_zip_filename.c @@ -1116,7 +1116,7 @@ DEFINE_TEST(test_read_format_zip_filename_UTF8_CP1251) * - the filename of second file is stored in UTF-8. * * Whenever hdrcharset option is specified, we will correctly read the - * filename of sencod file, which is stored in UTF-8. + * filename of second file, which is stored in UTF-8. */ DEFINE_TEST(test_read_format_zip_filename_KOI8R_UTF8_2) diff --git a/contrib/libarchive/libarchive/test/test_read_format_zip_mac_metadata.c b/contrib/libarchive/libarchive/test/test_read_format_zip_mac_metadata.c index 97aa427b0..99b701232 100644 --- a/contrib/libarchive/libarchive/test/test_read_format_zip_mac_metadata.c +++ b/contrib/libarchive/libarchive/test/test_read_format_zip_mac_metadata.c @@ -112,4 +112,6 @@ DEFINE_TEST(test_read_format_zip_mac_metadata) assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a)); + + free(p); } diff --git a/contrib/libarchive/libarchive/test/test_read_format_zip_malformed.c b/contrib/libarchive/libarchive/test/test_read_format_zip_malformed.c index 2327d9149..e14a3f566 100644 --- a/contrib/libarchive/libarchive/test/test_read_format_zip_malformed.c +++ b/contrib/libarchive/libarchive/test/test_read_format_zip_malformed.c @@ -53,6 +53,7 @@ test_malformed1(void) assertEqualIntA(a, ARCHIVE_OK, read_open_memory(a, p, s, 31)); assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a)); + free(p); } DEFINE_TEST(test_read_format_zip_malformed) diff --git a/contrib/libarchive/libarchive/test/test_read_format_zip_nested.c b/contrib/libarchive/libarchive/test/test_read_format_zip_nested.c index 6830afb71..5f6edf267 100644 --- a/contrib/libarchive/libarchive/test/test_read_format_zip_nested.c +++ b/contrib/libarchive/libarchive/test/test_read_format_zip_nested.c @@ -65,6 +65,8 @@ DEFINE_TEST(test_read_format_zip_nested) assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a)); + free(p); + /* Inspect inner Zip. */ assert((a = archive_read_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_zip(a)); diff --git a/contrib/libarchive/libarchive/test/test_read_format_zip_padded.c b/contrib/libarchive/libarchive/test/test_read_format_zip_padded.c index dae88abba..2094eca35 100644 --- a/contrib/libarchive/libarchive/test/test_read_format_zip_padded.c +++ b/contrib/libarchive/libarchive/test/test_read_format_zip_padded.c @@ -53,6 +53,8 @@ verify_padded_archive(const char *refname) assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a)); + + free(p); } /* diff --git a/contrib/libarchive/libarchive/test/test_read_format_zip_sfx.c b/contrib/libarchive/libarchive/test/test_read_format_zip_sfx.c index d5992d395..dc76ef9b3 100644 --- a/contrib/libarchive/libarchive/test/test_read_format_zip_sfx.c +++ b/contrib/libarchive/libarchive/test/test_read_format_zip_sfx.c @@ -60,4 +60,6 @@ DEFINE_TEST(test_read_format_zip_sfx) assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_free(a)); + + free(p); } diff --git a/contrib/libarchive/libarchive/test/test_read_format_zip_traditional_encryption_data.c b/contrib/libarchive/libarchive/test/test_read_format_zip_traditional_encryption_data.c index 2700be15a..305261567 100644 --- a/contrib/libarchive/libarchive/test/test_read_format_zip_traditional_encryption_data.c +++ b/contrib/libarchive/libarchive/test/test_read_format_zip_traditional_encryption_data.c @@ -28,7 +28,7 @@ __FBSDID("$FreeBSD$"); DEFINE_TEST(test_read_format_zip_traditional_encryption_data) { - /* This file is password protected (Traditional PKWARE Enctypted). + /* This file is password protected (Traditional PKWARE Encrypted). The headers are NOT encrypted. Password is "12345678". */ const char *refname = "test_read_format_zip_traditional_encryption_data.zip"; @@ -36,7 +36,7 @@ DEFINE_TEST(test_read_format_zip_traditional_encryption_data) struct archive *a; char buff[512]; - /* Check if running system has cryptographic functionarity. */ + /* Check if running system has cryptographic functionality. */ assert((a = archive_write_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_zip(a)); assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_none(a)); diff --git a/contrib/libarchive/libarchive/test/test_read_format_zip_winzip_aes.c b/contrib/libarchive/libarchive/test/test_read_format_zip_winzip_aes.c index 082337d7e..cc1e3110d 100644 --- a/contrib/libarchive/libarchive/test/test_read_format_zip_winzip_aes.c +++ b/contrib/libarchive/libarchive/test/test_read_format_zip_winzip_aes.c @@ -33,7 +33,7 @@ test_winzip_aes(const char *refname, int need_libz) struct archive *a; char buff[512]; - /* Check if running system has cryptographic functionarity. */ + /* Check if running system has cryptographic functionality. */ assert((a = archive_write_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_zip(a)); assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_none(a)); diff --git a/contrib/libarchive/libarchive/test/test_read_format_zip_winzip_aes_large.c b/contrib/libarchive/libarchive/test/test_read_format_zip_winzip_aes_large.c index a40d5cf13..6c40ae766 100644 --- a/contrib/libarchive/libarchive/test/test_read_format_zip_winzip_aes_large.c +++ b/contrib/libarchive/libarchive/test/test_read_format_zip_winzip_aes_large.c @@ -34,7 +34,7 @@ DEFINE_TEST(test_read_format_zip_winzip_aes256_large) char buff[512]; - /* Check if running system has cryptographic functionarity. */ + /* Check if running system has cryptographic functionality. */ assert((a = archive_write_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_write_set_format_zip(a)); assertEqualIntA(a, ARCHIVE_OK, archive_write_add_filter_none(a)); diff --git a/contrib/libarchive/libarchive/test/test_read_pax_schily_xattr.c b/contrib/libarchive/libarchive/test/test_read_pax_schily_xattr.c new file mode 100644 index 000000000..7554f6d5d --- /dev/null +++ b/contrib/libarchive/libarchive/test/test_read_pax_schily_xattr.c @@ -0,0 +1,70 @@ +/*- + * Copyright (c) 2016 IBM Corporation + * Copyright (c) 2003-2007 Tim Kientzle + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * This test case's code has been derived from test_entry.c + */ +#include "test.h" + +DEFINE_TEST(test_schily_xattr_pax) +{ + struct archive *a; + struct archive_entry *ae; + const char *refname = "test_read_pax_schily_xattr.tar"; + const char *xname; /* For xattr tests. */ + const void *xval; /* For xattr tests. */ + size_t xsize; /* For xattr tests. */ + const char *string, *array; + + assert((a = archive_read_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); + + extract_reference_file(refname); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_filename(a, refname, 10240)); + + assertEqualInt(ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualInt(2, archive_entry_xattr_count(ae)); + assertEqualInt(2, archive_entry_xattr_reset(ae)); + + assertEqualInt(0, archive_entry_xattr_next(ae, &xname, &xval, &xsize)); + assertEqualString(xname, "security.selinux"); + string = "system_u:object_r:unlabeled_t:s0"; + assertEqualString(xval, string); + /* the xattr's value also contains the terminating \0 */ + assertEqualInt((int)xsize, strlen(string) + 1); + + assertEqualInt(0, archive_entry_xattr_next(ae, &xname, &xval, &xsize)); + assertEqualString(xname, "security.ima"); + assertEqualInt((int)xsize, 265); + /* we only compare the first 12 bytes */ + array = "\x03\x02\x04\xb0\xe9\xd6\x79\x01\x00\x2b\xad\x1e"; + assertEqualMem(xval, array, 12); + + /* Close the archive. */ + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +} diff --git a/contrib/libarchive/libarchive/test/test_read_pax_schily_xattr.tar.uu b/contrib/libarchive/libarchive/test/test_read_pax_schily_xattr.tar.uu new file mode 100644 index 000000000..52f7a8f0d --- /dev/null +++ b/contrib/libarchive/libarchive/test/test_read_pax_schily_xattr.tar.uu @@ -0,0 +1,231 @@ +begin 644 test_schily_xattr_pax.tar +M+B]087A(96%D97)S+C$U,C4O8V]N9F9I;&5S```````````````````````` +M```````````````````````````````````````````````````````````` +M`````````````#`P,#`V-#0`,#`P,#`P,``P,#`P,#`P`#`P,#`P,#`P-C0W +M`#$R-S$R,C$P-3`V`#`Q,C4V-@`@>``````````````````````````````` +M```````````````````````````````````````````````````````````` +M``````````````````````````````````````````!UW6X5O?Y6: +M9^':P2MZR[4)$@W?)B6GX0U@<,0M%6YNMO%OG+IS%/.< +M,"A(N&S.F9]=!*5=\).X."2$GUGJ,0C:@+G#$M_E8UQP,LU-G(8IKW^K^<8* +M*3_.N0'%8.^$8S$`D9XOF+DK<<)U34U'_"O5/22YS96QI;G5X +M/7-Y libarchive_test'. */ diff --git a/contrib/libarchive/libarchive/test/test_write_disk_secure746.c b/contrib/libarchive/libarchive/test/test_write_disk_secure746.c index 460aafef1..5ce1fd9c4 100644 --- a/contrib/libarchive/libarchive/test/test_write_disk_secure746.c +++ b/contrib/libarchive/libarchive/test/test_write_disk_secure746.c @@ -72,6 +72,9 @@ DEFINE_TEST(test_write_disk_secure746a) /* Verify that target file contents are unchanged. */ assertTextFileContents("unmodified", "../target/foo"); + + assertEqualIntA(a, ARCHIVE_FATAL, archive_write_close(a)); + archive_write_free(a); #endif } diff --git a/contrib/libarchive/libarchive/test/test_write_filter_lz4.c b/contrib/libarchive/libarchive/test/test_write_filter_lz4.c index a04369841..4f2135a31 100644 --- a/contrib/libarchive/libarchive/test/test_write_filter_lz4.c +++ b/contrib/libarchive/libarchive/test/test_write_filter_lz4.c @@ -56,6 +56,7 @@ DEFINE_TEST(test_write_filter_lz4) } else { assertEqualInt(ARCHIVE_OK, r); } + assertEqualInt(ARCHIVE_OK, archive_write_free(a)); buffsize = 2000000; assert(NULL != (buff = (char *)malloc(buffsize))); @@ -299,6 +300,7 @@ test_options(const char *options) } else { assertEqualInt(ARCHIVE_OK, r); } + assertEqualInt(ARCHIVE_OK, archive_write_free(a)); buffsize = 2000000; assert(NULL != (buff = (char *)malloc(buffsize))); diff --git a/contrib/libarchive/libarchive/test/test_write_filter_lzop.c b/contrib/libarchive/libarchive/test/test_write_filter_lzop.c index a32932c69..92db7bf3d 100644 --- a/contrib/libarchive/libarchive/test/test_write_filter_lzop.c +++ b/contrib/libarchive/libarchive/test/test_write_filter_lzop.c @@ -43,12 +43,12 @@ DEFINE_TEST(test_write_filter_lzop) assert((a = archive_write_new()) != NULL); r = archive_write_add_filter_lzop(a); + assertEqualInt(ARCHIVE_OK, archive_write_free(a)); if (r != ARCHIVE_OK) { if (canLzop() && r == ARCHIVE_WARN) use_prog = 1; else { skipping("lzop writing not supported on this platform"); - assertEqualInt(ARCHIVE_OK, archive_write_free(a)); return; } } @@ -92,7 +92,7 @@ DEFINE_TEST(test_write_filter_lzop) assert((a = archive_read_new()) != NULL); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); r = archive_read_support_filter_lzop(a); - if (r == ARCHIVE_WARN) { + if (r == ARCHIVE_WARN && !use_prog) { skipping("Can't verify lzop writing by reading back;" " lzop reading not fully supported on this platform"); } else { @@ -212,7 +212,7 @@ DEFINE_TEST(test_write_filter_lzop) assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a)); r = archive_read_support_filter_lzop(a); - if (r == ARCHIVE_WARN) { + if (r == ARCHIVE_WARN && !use_prog) { skipping("lzop reading not fully supported on this platform"); } else { assertEqualIntA(a, ARCHIVE_OK, diff --git a/contrib/libarchive/libarchive/test/test_write_format_iso9660.c b/contrib/libarchive/libarchive/test/test_write_format_iso9660.c index ee6db6fed..e4e98bb95 100644 --- a/contrib/libarchive/libarchive/test/test_write_format_iso9660.c +++ b/contrib/libarchive/libarchive/test/test_write_format_iso9660.c @@ -719,7 +719,7 @@ DEFINE_TEST(test_write_format_iso9660) assertEqualInt(5, archive_entry_ctime(ae)); assert(archive_entry_mtime_is_set(ae)); assertEqualInt(5, archive_entry_mtime(ae)); - /* Trim lngname to 64 characters. */ + /* Trim longname to 64 characters. */ longname[64] = '\0'; assertEqualString(longname, archive_entry_pathname(ae)); assert((AE_IFREG | 0400) == archive_entry_mode(ae)); diff --git a/contrib/libarchive/libarchive/test/test_write_format_iso9660_zisofs.c b/contrib/libarchive/libarchive/test/test_write_format_iso9660_zisofs.c index 136255b32..2140ed8c3 100644 --- a/contrib/libarchive/libarchive/test/test_write_format_iso9660_zisofs.c +++ b/contrib/libarchive/libarchive/test/test_write_format_iso9660_zisofs.c @@ -25,7 +25,7 @@ #include "test.h" /* - * Check that a "zisofs" ISO 9660 imaeg is correctly created. + * Check that a "zisofs" ISO 9660 image is correctly created. */ static const unsigned char primary_id[] = { diff --git a/contrib/libarchive/libarchive/test/test_write_format_zip_large.c b/contrib/libarchive/libarchive/test/test_write_format_zip_large.c index d73dd62de..88788b56d 100644 --- a/contrib/libarchive/libarchive/test/test_write_format_zip_large.c +++ b/contrib/libarchive/libarchive/test/test_write_format_zip_large.c @@ -470,5 +470,6 @@ DEFINE_TEST(test_write_format_zip_large) assertEqualMem(cd_start, "PK\001\002", 4); fileblocks_free(fileblocks); + free(buff); free(nulldata); } diff --git a/contrib/libarchive/libarchive/test/test_write_format_zip_zip64.c b/contrib/libarchive/libarchive/test/test_write_format_zip_zip64.c index b83aeab53..c5f00a2e5 100644 --- a/contrib/libarchive/libarchive/test/test_write_format_zip_zip64.c +++ b/contrib/libarchive/libarchive/test/test_write_format_zip_zip64.c @@ -49,6 +49,8 @@ verify_zip_filesize(uint64_t size, int expected) archive_entry_set_size(ae, size); assertEqualInt(expected, archive_write_header(a, ae)); + archive_entry_free(ae); + /* Don't actually write 4GB! ;-) */ assertEqualIntA(a, ARCHIVE_OK, archive_write_free(a)); } diff --git a/contrib/libarchive/libarchive/xxhash.c b/contrib/libarchive/libarchive/xxhash.c index d7f8e96de..6f5ba52fa 100644 --- a/contrib/libarchive/libarchive/xxhash.c +++ b/contrib/libarchive/libarchive/xxhash.c @@ -29,10 +29,11 @@ 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 #include -#include "archive_platform.h" #include "archive_xxhash.h" #ifdef HAVE_LIBLZ4 @@ -60,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. */ diff --git a/contrib/libarchive/tar/test/test_option_uid_uname.c b/contrib/libarchive/tar/test/test_option_uid_uname.c index 0a8a9bb27..80c061961 100644 --- a/contrib/libarchive/tar/test/test_option_uid_uname.c +++ b/contrib/libarchive/tar/test/test_option_uid_uname.c @@ -45,25 +45,25 @@ DEFINE_TEST(test_option_uid_uname) /* Again with both --uid and --uname */ failure("Error invoking %s c", testprog); assertEqualInt(0, - systemf("%s cf archive2 --uid=17 --uname=foofoofoo --format=ustar file >stdout2.txt 2>stderr2.txt", + systemf("%s cf archive2 --uid=65123 --uname=foofoofoo --format=ustar file >stdout2.txt 2>stderr2.txt", testprog)); assertEmptyFile("stdout2.txt"); assertEmptyFile("stderr2.txt"); data = slurpfile(&s, "archive2"); /* Should force uid and uname fields in ustar header. */ - assertEqualMem(data + 108, "000021 \0", 8); + assertEqualMem(data + 108, "177143 \0", 8); assertEqualMem(data + 265, "foofoofoo\0", 10); free(data); /* Again with just --uid */ failure("Error invoking %s c", testprog); assertEqualInt(0, - systemf("%s cf archive3 --uid=17 --format=ustar file >stdout3.txt 2>stderr3.txt", + systemf("%s cf archive3 --uid=65123 --format=ustar file >stdout3.txt 2>stderr3.txt", testprog)); assertEmptyFile("stdout3.txt"); assertEmptyFile("stderr3.txt"); data = slurpfile(&s, "archive3"); - assertEqualMem(data + 108, "000021 \0", 8); + assertEqualMem(data + 108, "177143 \0", 8); /* Uname field in ustar header should be empty. */ assertEqualMem(data + 265, "\0", 1); free(data); diff --git a/contrib/libarchive/tar/util.c b/contrib/libarchive/tar/util.c index f84560019..84dc53f7d 100644 --- a/contrib/libarchive/tar/util.c +++ b/contrib/libarchive/tar/util.c @@ -140,6 +140,7 @@ safe_fprintf(FILE *f, const char *fmt, ...) } else { /* Leave fmtbuff pointing to the truncated * string in fmtbuff_stack. */ + fmtbuff = fmtbuff_stack; length = sizeof(fmtbuff_stack) - 1; break; } diff --git a/lib/libarchive/config_freebsd.h b/lib/libarchive/config_freebsd.h index c82c8cc2c..24e2d753e 100644 --- a/lib/libarchive/config_freebsd.h +++ b/lib/libarchive/config_freebsd.h @@ -39,6 +39,7 @@ #define HAVE_ACL_SET_FILE 1 #define HAVE_ACL_SET_LINK_NP 1 #define HAVE_ACL_USER 1 +#define HAVE_ACL_TYPE_NFS4 1 #define HAVE_ARC4RANDOM_BUF 1 #define HAVE_EXTATTR_GET_FILE 1 #define HAVE_EXTATTR_LIST_FILE 1 diff --git a/lib/libarchive/tests/Makefile b/lib/libarchive/tests/Makefile index 58c642e08..ec17eee19 100644 --- a/lib/libarchive/tests/Makefile +++ b/lib/libarchive/tests/Makefile @@ -21,11 +21,12 @@ CFLAGS+= -DHAVE_LIBLZMA=1 -DHAVE_LZMA_H=1 .PATH: ${LIBARCHIVEDIR}/libarchive/test TESTS_SRCS= \ - test_acl_freebsd_nfs4.c \ - test_acl_freebsd_posix1e.c \ test_acl_nfs4.c \ test_acl_pax.c \ + test_acl_platform_nfs4.c \ + test_acl_platform_posix1e.c \ test_acl_posix1e.c \ + test_acl_text.c \ test_archive_api_feature.c \ test_archive_clear_error.c \ test_archive_cmdline.c \ @@ -74,7 +75,7 @@ TESTS_SRCS= \ test_compat_plexus_archiver_tar.c \ test_compat_solaris_tar_acl.c \ test_compat_solaris_pax_sparse.c \ - test_compat_star_acl_posix1e.c \ + test_compat_star_acl.c \ test_compat_tar_hardlink.c \ test_compat_uudecode.c \ test_compat_uudecode_large.c \ @@ -327,6 +328,7 @@ FILES+= test_compat_cpio_1.cpio.uu FILES+= test_compat_gtar_1.tar.uu FILES+= test_compat_gtar_2.tar.uu FILES+= test_compat_gzip_1.tgz.uu +FILES+= test_compat_gzip_2.tgz.uu FILES+= test_compat_lz4_1.tar.lz4.uu FILES+= test_compat_lz4_2.tar.lz4.uu FILES+= test_compat_lz4_3.tar.lz4.uu @@ -339,7 +341,6 @@ FILES+= test_compat_lz4_B6.tar.lz4.uu FILES+= test_compat_lz4_B6BD.tar.lz4.uu FILES+= test_compat_lz4_B7.tar.lz4.uu FILES+= test_compat_lz4_B7BD.tar.lz4.uu -FILES+= test_compat_gzip_2.tgz.uu FILES+= test_compat_lzip_1.tlz.uu FILES+= test_compat_lzip_2.tlz.uu FILES+= test_compat_lzma_1.tlz.uu @@ -486,7 +487,7 @@ FILES+= test_read_format_rar_compress_normal.rar.uu FILES+= test_read_format_rar_encryption_data.rar.uu FILES+= test_read_format_rar_encryption_header.rar.uu FILES+= test_read_format_rar_encryption_partially.rar.uu -FILES+= test_read_format_rar_invalid1.rar.uu +FILES+= test_read_format_rar_invalid1.rar.uu FILES+= test_read_format_rar_multi_lzss_blocks.rar.uu FILES+= test_read_format_rar_multivolume.part0001.rar.uu FILES+= test_read_format_rar_multivolume.part0002.rar.uu @@ -521,7 +522,7 @@ FILES+= test_read_format_zip_filename_koi8r.zip.uu FILES+= test_read_format_zip_filename_utf8_jp.zip.uu FILES+= test_read_format_zip_filename_utf8_ru.zip.uu FILES+= test_read_format_zip_filename_utf8_ru2.zip.uu -FILES+= test_read_format_zip_high_compression.zip.uu +FILES+= test_read_format_zip_high_compression.zip.uu FILES+= test_read_format_zip_jar.jar.uu FILES+= test_read_format_zip_length_at_end.zip.uu FILES+= test_read_format_zip_mac_metadata.zip.uu -- 2.45.0