Author: mm
Date: Fri Dec 30 01:27:27 2016
New Revision: 310796
URL: https://svnweb.freebsd.org/changeset/base/310796

Log:
  Update vendor/libarchive to git to 379867ecb330b3a952fb7bfa7bffb7bbd5547205
  
  Vendor changes:
  PR #771: Add NFSv4 ACL support to pax and restricted pax

Added:
  vendor/libarchive/dist/libarchive/test/test_acl_pax_nfs4.tar.uu
  vendor/libarchive/dist/libarchive/test/test_acl_pax_posix1e.tar.uu
     - copied, changed from r310795, 
vendor/libarchive/dist/libarchive/test/test_acl_pax.tar.uu
  vendor/libarchive/dist/libarchive/test/test_acl_text.c   (contents, props 
changed)
  vendor/libarchive/dist/libarchive/test/test_compat_star_acl.c
     - copied, changed from r310795, 
vendor/libarchive/dist/libarchive/test/test_compat_star_acl_posix1e.c
  vendor/libarchive/dist/libarchive/test/test_compat_star_acl_nfs4.tar.uu
Deleted:
  vendor/libarchive/dist/libarchive/test/test_acl_pax.tar.uu
  vendor/libarchive/dist/libarchive/test/test_compat_star_acl_posix1e.c
Modified:
  vendor/libarchive/dist/Makefile.am
  vendor/libarchive/dist/NEWS
  vendor/libarchive/dist/libarchive/archive_acl.c
  vendor/libarchive/dist/libarchive/archive_acl_private.h
  vendor/libarchive/dist/libarchive/archive_entry.c
  vendor/libarchive/dist/libarchive/archive_entry.h
  vendor/libarchive/dist/libarchive/archive_entry_acl.3
  vendor/libarchive/dist/libarchive/archive_entry_locale.h
  vendor/libarchive/dist/libarchive/archive_read_disk_entry_from_file.c
  vendor/libarchive/dist/libarchive/archive_read_support_format_tar.c
  vendor/libarchive/dist/libarchive/archive_write_set_format_pax.c
  vendor/libarchive/dist/libarchive/libarchive-formats.5
  vendor/libarchive/dist/libarchive/tar.5
  vendor/libarchive/dist/libarchive/test/CMakeLists.txt
  vendor/libarchive/dist/libarchive/test/main.c
  vendor/libarchive/dist/libarchive/test/test.h
  vendor/libarchive/dist/libarchive/test/test_acl_freebsd_nfs4.c
  vendor/libarchive/dist/libarchive/test/test_acl_freebsd_posix1e.c
  vendor/libarchive/dist/libarchive/test/test_acl_nfs4.c
  vendor/libarchive/dist/libarchive/test/test_acl_pax.c
  vendor/libarchive/dist/libarchive/test/test_acl_posix1e.c

Modified: vendor/libarchive/dist/Makefile.am
==============================================================================
--- vendor/libarchive/dist/Makefile.am  Fri Dec 30 01:24:08 2016        
(r310795)
+++ vendor/libarchive/dist/Makefile.am  Fri Dec 30 01:27:27 2016        
(r310796)
@@ -328,6 +328,7 @@ libarchive_test_SOURCES= \
        libarchive/test/test_acl_nfs4.c \
        libarchive/test/test_acl_pax.c \
        libarchive/test/test_acl_posix1e.c \
+       libarchive/test/test_acl_text.c \
        libarchive/test/test_archive_api_feature.c \
        libarchive/test/test_archive_clear_error.c \
        libarchive/test/test_archive_cmdline.c \
@@ -376,7 +377,7 @@ libarchive_test_SOURCES= \
        libarchive/test/test_compat_plexus_archiver_tar.c \
        libarchive/test/test_compat_solaris_tar_acl.c \
        libarchive/test/test_compat_solaris_pax_sparse.c \
-       libarchive/test/test_compat_star_acl_posix1e.c \
+       libarchive/test/test_compat_star_acl.c \
        libarchive/test/test_compat_tar_hardlink.c \
        libarchive/test/test_compat_uudecode.c \
        libarchive/test/test_compat_uudecode_large.c \
@@ -598,7 +599,8 @@ libarchive_TESTS_ENVIRONMENT= LIBARCHIVE
 
 libarchive_test_EXTRA_DIST=\
        libarchive/test/list.h \
-       libarchive/test/test_acl_pax.tar.uu \
+       libarchive/test/test_acl_pax_posix1e.tar.uu \
+       libarchive/test/test_acl_pax_nfs4.tar.uu \
        libarchive/test/test_archive_string_conversion.txt.Z.uu \
        libarchive/test/test_compat_bzip2_1.tbz.uu \
        libarchive/test/test_compat_bzip2_2.tbz.uu \
@@ -635,6 +637,7 @@ libarchive_test_EXTRA_DIST=\
        libarchive/test/test_compat_solaris_pax_sparse_1.pax.Z.uu \
        libarchive/test/test_compat_solaris_pax_sparse_2.pax.Z.uu \
        libarchive/test/test_compat_solaris_tar_acl.tar.uu \
+       libarchive/test/test_compat_star_acl_nfs4.tar.uu \
        libarchive/test/test_compat_star_acl_posix1e.tar.uu \
        libarchive/test/test_compat_tar_hardlink_1.tar.uu \
        libarchive/test/test_compat_uudecode_large.tar.Z.uu \

Modified: vendor/libarchive/dist/NEWS
==============================================================================
--- vendor/libarchive/dist/NEWS Fri Dec 30 01:24:08 2016        (r310795)
+++ vendor/libarchive/dist/NEWS Fri Dec 30 01:27:27 2016        (r310796)
@@ -1,3 +1,6 @@
+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: vendor/libarchive/dist/libarchive/archive_acl.c
==============================================================================
--- vendor/libarchive/dist/libarchive/archive_acl.c     Fri Dec 30 01:24:08 
2016        (r310795)
+++ vendor/libarchive/dist/libarchive/archive_acl.c     Fri Dec 30 01:27:27 
2016        (r310796)
@@ -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
@@ -375,8 +384,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 +450,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);
+
+       /* The terminating character is included in count */
+       return (length);
+}
 
-       if (count == 0)
+/*
+ * 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 +729,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 +740,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 +751,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 +769,209 @@ 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);
+                       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 +985,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 +996,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 +1007,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 +1025,146 @@ 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);
+                       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;

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

Reply via email to