Author: mm
Date: Sat Feb 11 00:56:18 2017
New Revision: 313571
URL: https://svnweb.freebsd.org/changeset/base/313571

Log:
  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

Added:
  stable/10/contrib/libarchive/libarchive/test/test_acl_pax_nfs4.tar.uu
     - copied unchanged from r310866, 
head/contrib/libarchive/libarchive/test/test_acl_pax_nfs4.tar.uu
  stable/10/contrib/libarchive/libarchive/test/test_acl_pax_posix1e.tar.uu
     - copied unchanged from r310866, 
head/contrib/libarchive/libarchive/test/test_acl_pax_posix1e.tar.uu
  stable/10/contrib/libarchive/libarchive/test/test_acl_platform_nfs4.c
     - copied unchanged from r313074, 
head/contrib/libarchive/libarchive/test/test_acl_platform_nfs4.c
  stable/10/contrib/libarchive/libarchive/test/test_acl_platform_posix1e.c
     - copied unchanged from r313074, 
head/contrib/libarchive/libarchive/test/test_acl_platform_posix1e.c
  stable/10/contrib/libarchive/libarchive/test/test_acl_text.c
     - copied, changed from r310866, 
head/contrib/libarchive/libarchive/test/test_acl_text.c
  stable/10/contrib/libarchive/libarchive/test/test_compat_star_acl.c
     - copied unchanged from r310866, 
head/contrib/libarchive/libarchive/test/test_compat_star_acl.c
  stable/10/contrib/libarchive/libarchive/test/test_compat_star_acl_nfs4.tar.uu
     - copied unchanged from r310866, 
head/contrib/libarchive/libarchive/test/test_compat_star_acl_nfs4.tar.uu
  stable/10/contrib/libarchive/libarchive/test/test_read_pax_schily_xattr.c
     - copied unchanged from r311903, 
head/contrib/libarchive/libarchive/test/test_read_pax_schily_xattr.c
  stable/10/contrib/libarchive/libarchive/test/test_read_pax_schily_xattr.tar.uu
     - copied unchanged from r311903, 
head/contrib/libarchive/libarchive/test/test_read_pax_schily_xattr.tar.uu
Deleted:
  stable/10/contrib/libarchive/libarchive/test/test_acl_freebsd_nfs4.c
  stable/10/contrib/libarchive/libarchive/test/test_acl_freebsd_posix1e.c
  stable/10/contrib/libarchive/libarchive/test/test_acl_pax.tar.uu
  stable/10/contrib/libarchive/libarchive/test/test_compat_star_acl_posix1e.c
Modified:
  stable/10/ObsoleteFiles.inc
  stable/10/contrib/libarchive/NEWS
  stable/10/contrib/libarchive/cpio/cpio.c
  stable/10/contrib/libarchive/libarchive/archive_acl.c
  stable/10/contrib/libarchive/libarchive/archive_acl_private.h
  stable/10/contrib/libarchive/libarchive/archive_entry.c
  stable/10/contrib/libarchive/libarchive/archive_entry.h
  stable/10/contrib/libarchive/libarchive/archive_entry_acl.3
  stable/10/contrib/libarchive/libarchive/archive_entry_locale.h
  stable/10/contrib/libarchive/libarchive/archive_entry_strmode.c
  stable/10/contrib/libarchive/libarchive/archive_match.c
  stable/10/contrib/libarchive/libarchive/archive_platform.h
  stable/10/contrib/libarchive/libarchive/archive_random.c
  stable/10/contrib/libarchive/libarchive/archive_rb.c
  stable/10/contrib/libarchive/libarchive/archive_read_disk.3
  stable/10/contrib/libarchive/libarchive/archive_read_disk_entry_from_file.c
  stable/10/contrib/libarchive/libarchive/archive_read_disk_posix.c
  stable/10/contrib/libarchive/libarchive/archive_read_open_filename.c
  stable/10/contrib/libarchive/libarchive/archive_read_support_filter_lz4.c
  stable/10/contrib/libarchive/libarchive/archive_read_support_filter_lzop.c
  stable/10/contrib/libarchive/libarchive/archive_read_support_filter_program.c
  stable/10/contrib/libarchive/libarchive/archive_read_support_format_7zip.c
  stable/10/contrib/libarchive/libarchive/archive_read_support_format_cab.c
  stable/10/contrib/libarchive/libarchive/archive_read_support_format_cpio.c
  stable/10/contrib/libarchive/libarchive/archive_read_support_format_iso9660.c
  stable/10/contrib/libarchive/libarchive/archive_read_support_format_lha.c
  stable/10/contrib/libarchive/libarchive/archive_read_support_format_mtree.c
  stable/10/contrib/libarchive/libarchive/archive_read_support_format_rar.c
  stable/10/contrib/libarchive/libarchive/archive_read_support_format_tar.c
  stable/10/contrib/libarchive/libarchive/archive_read_support_format_warc.c
  stable/10/contrib/libarchive/libarchive/archive_read_support_format_xar.c
  stable/10/contrib/libarchive/libarchive/archive_read_support_format_zip.c
  stable/10/contrib/libarchive/libarchive/archive_string.c
  stable/10/contrib/libarchive/libarchive/archive_string.h
  stable/10/contrib/libarchive/libarchive/archive_string_composition.h
  stable/10/contrib/libarchive/libarchive/archive_write.c
  stable/10/contrib/libarchive/libarchive/archive_write_add_filter_program.c
  stable/10/contrib/libarchive/libarchive/archive_write_add_filter_xz.c
  stable/10/contrib/libarchive/libarchive/archive_write_disk_acl.c
  stable/10/contrib/libarchive/libarchive/archive_write_disk_posix.c
  stable/10/contrib/libarchive/libarchive/archive_write_open.3
  stable/10/contrib/libarchive/libarchive/archive_write_set_format_7zip.c
  stable/10/contrib/libarchive/libarchive/archive_write_set_format_gnutar.c
  stable/10/contrib/libarchive/libarchive/archive_write_set_format_iso9660.c
  stable/10/contrib/libarchive/libarchive/archive_write_set_format_pax.c
  stable/10/contrib/libarchive/libarchive/archive_write_set_format_warc.c
  stable/10/contrib/libarchive/libarchive/archive_write_set_format_xar.c
  stable/10/contrib/libarchive/libarchive/archive_write_set_format_zip.c
  stable/10/contrib/libarchive/libarchive/libarchive-formats.5
  stable/10/contrib/libarchive/libarchive/tar.5
  stable/10/contrib/libarchive/libarchive/test/main.c
  stable/10/contrib/libarchive/libarchive/test/test.h
  stable/10/contrib/libarchive/libarchive/test/test_acl_nfs4.c
  stable/10/contrib/libarchive/libarchive/test/test_acl_pax.c
  stable/10/contrib/libarchive/libarchive/test/test_acl_posix1e.c
  
stable/10/contrib/libarchive/libarchive/test/test_archive_read_add_passphrase.c
  stable/10/contrib/libarchive/libarchive/test/test_archive_string.c
  stable/10/contrib/libarchive/libarchive/test/test_compat_gtar.c
  stable/10/contrib/libarchive/libarchive/test/test_compat_solaris_tar_acl.c
  
stable/10/contrib/libarchive/libarchive/test/test_compat_solaris_tar_acl.tar.uu
  stable/10/contrib/libarchive/libarchive/test/test_compat_uudecode.c
  stable/10/contrib/libarchive/libarchive/test/test_fuzz.c
  
stable/10/contrib/libarchive/libarchive/test/test_read_disk_directory_traversals.c
  stable/10/contrib/libarchive/libarchive/test/test_read_filter_lzop.c
  
stable/10/contrib/libarchive/libarchive/test/test_read_filter_lzop_multiple_parts.c
  stable/10/contrib/libarchive/libarchive/test/test_read_format_7zip.c
  stable/10/contrib/libarchive/libarchive/test/test_read_format_cpio_afio.c
  stable/10/contrib/libarchive/libarchive/test/test_read_format_isorr_bz2.c
  stable/10/contrib/libarchive/libarchive/test/test_read_format_zip.c
  
stable/10/contrib/libarchive/libarchive/test/test_read_format_zip_comment_stored.c
  stable/10/contrib/libarchive/libarchive/test/test_read_format_zip_filename.c
  
stable/10/contrib/libarchive/libarchive/test/test_read_format_zip_mac_metadata.c
  stable/10/contrib/libarchive/libarchive/test/test_read_format_zip_malformed.c
  stable/10/contrib/libarchive/libarchive/test/test_read_format_zip_nested.c
  stable/10/contrib/libarchive/libarchive/test/test_read_format_zip_padded.c
  stable/10/contrib/libarchive/libarchive/test/test_read_format_zip_sfx.c
  
stable/10/contrib/libarchive/libarchive/test/test_read_format_zip_traditional_encryption_data.c
  stable/10/contrib/libarchive/libarchive/test/test_read_format_zip_winzip_aes.c
  
stable/10/contrib/libarchive/libarchive/test/test_read_format_zip_winzip_aes_large.c
  stable/10/contrib/libarchive/libarchive/test/test_sparse_basic.c
  stable/10/contrib/libarchive/libarchive/test/test_write_disk_secure746.c
  stable/10/contrib/libarchive/libarchive/test/test_write_filter_lz4.c
  stable/10/contrib/libarchive/libarchive/test/test_write_filter_lzop.c
  stable/10/contrib/libarchive/libarchive/test/test_write_format_iso9660.c
  
stable/10/contrib/libarchive/libarchive/test/test_write_format_iso9660_zisofs.c
  stable/10/contrib/libarchive/libarchive/test/test_write_format_zip_large.c
  stable/10/contrib/libarchive/libarchive/test/test_write_format_zip_zip64.c
  stable/10/contrib/libarchive/libarchive/xxhash.c
  stable/10/contrib/libarchive/tar/test/test_option_uid_uname.c
  stable/10/contrib/libarchive/tar/util.c
  stable/10/lib/libarchive/config_freebsd.h
  stable/10/lib/libarchive/tests/Makefile
Directory Properties:
  stable/10/   (props changed)

Modified: stable/10/ObsoleteFiles.inc
==============================================================================
--- stable/10/ObsoleteFiles.inc Sat Feb 11 00:54:16 2017        (r313570)
+++ stable/10/ObsoleteFiles.inc Sat Feb 11 00:56:18 2017        (r313571)
@@ -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

Modified: stable/10/contrib/libarchive/NEWS
==============================================================================
--- stable/10/contrib/libarchive/NEWS   Sat Feb 11 00:54:16 2017        
(r313570)
+++ stable/10/contrib/libarchive/NEWS   Sat Feb 11 00:56:18 2017        
(r313571)
@@ -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

Modified: stable/10/contrib/libarchive/cpio/cpio.c
==============================================================================
--- stable/10/contrib/libarchive/cpio/cpio.c    Sat Feb 11 00:54:16 2017        
(r313570)
+++ stable/10/contrib/libarchive/cpio/cpio.c    Sat Feb 11 00:56:18 2017        
(r313571)
@@ -703,6 +703,7 @@ file_to_archive(struct cpio *cpio, const
                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);
        }

Modified: stable/10/contrib/libarchive/libarchive/archive_acl.c
==============================================================================
--- stable/10/contrib/libarchive/libarchive/archive_acl.c       Sat Feb 11 
00:54:16 2017        (r313570)
+++ stable/10/contrib/libarchive/libarchive/archive_acl.c       Sat Feb 11 
00:56:18 2017        (r313571)
@@ -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
 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
@@ -340,6 +349,15 @@ archive_acl_count(struct archive_acl *ac
 }
 
 /*
+ * Return a bitmask of stored ACL types in an ACL list
+ */
+int
+archive_acl_types(struct archive_acl *acl)
+{
+       return (acl->acl_types);
+}
+
+/*
  * Prepare for reading entries from the ACL data.  Returns a count
  * of entries matching "want_type", or zero if there are no
  * non-extended ACL entries of that type.
@@ -375,8 +393,8 @@ archive_acl_reset(struct archive_acl *ac
  * 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, stru
 }
 
 /*
- * 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
        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
        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
                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 *prefi
        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 *prefi
        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 *prefi
                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;

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
_______________________________________________
svn-src-stable-10@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-stable-10
To unsubscribe, send any mail to "svn-src-stable-10-unsubscr...@freebsd.org"

Reply via email to