Author: kientzle
Date: Mon Apr 27 18:27:54 2009
New Revision: 191576
URL: http://svn.freebsd.org/changeset/base/191576

Log:
  Merge r1053,r1055,r1056,r1057,r1065 from libarchive.googlecode.com:
   * Fix parsing of POSIX.1e ACLs from Solaris tar archives
   * Test the above
   * Preserve the order of POSIX.1e ACL entries
   * Update tests whose results depended on the order of ACL entries
   * Identify NFSv4 ACLs in Solaris tar archives and warn that
     they're not yet supported. (In particular, don't try to parse
     them as POSIX.1e ACLs.)
  
  Thanks to: Edward Napierala sent me some Solaris 10 tar archives to test

Added:
  head/lib/libarchive/test/test_compat_solaris_tar_acl.c   (contents, props 
changed)
  head/lib/libarchive/test/test_compat_solaris_tar_acl.tar.uu   (contents, 
props changed)
Modified:
  head/lib/libarchive/archive_entry.c
  head/lib/libarchive/archive_read_support_format_tar.c
  head/lib/libarchive/test/Makefile
  head/lib/libarchive/test/test_acl_pax.c

Modified: head/lib/libarchive/archive_entry.c
==============================================================================
--- head/lib/libarchive/archive_entry.c Mon Apr 27 18:17:32 2009        
(r191575)
+++ head/lib/libarchive/archive_entry.c Mon Apr 27 18:27:54 2009        
(r191576)
@@ -115,6 +115,7 @@ static int  acl_special(struct archive_en
 static struct ae_acl *acl_new_entry(struct archive_entry *entry,
                    int type, int permset, int tag, int id);
 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 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,
@@ -1238,7 +1239,7 @@ static struct ae_acl *
 acl_new_entry(struct archive_entry *entry,
     int type, int permset, int tag, int id)
 {
-       struct ae_acl *ap;
+       struct ae_acl *ap, *aq;
 
        if (type != ARCHIVE_ENTRY_ACL_TYPE_ACCESS &&
            type != ARCHIVE_ENTRY_ACL_TYPE_DEFAULT)
@@ -1251,20 +1252,26 @@ acl_new_entry(struct archive_entry *entr
        /* XXX TODO: More sanity-checks on the arguments XXX */
 
        /* If there's a matching entry already in the list, overwrite it. */
-       for (ap = entry->acl_head; ap != NULL; ap = ap->next) {
+       ap = entry->acl_head;
+       aq = NULL;
+       while (ap != NULL) {
                if (ap->type == type && ap->tag == tag && ap->id == id) {
                        ap->permset = permset;
                        return (ap);
                }
+               aq = ap;
+               ap = ap->next;
        }
 
-       /* Add a new entry to the list. */
+       /* Add a new entry to the end of the list. */
        ap = (struct ae_acl *)malloc(sizeof(*ap));
        if (ap == NULL)
                return (NULL);
        memset(ap, 0, sizeof(*ap));
-       ap->next = entry->acl_head;
-       entry->acl_head = ap;
+       if (aq == NULL)
+               entry->acl_head = ap;
+       else
+               aq->next = ap;
        ap->type = type;
        ap->tag = tag;
        ap->id = id;
@@ -1586,11 +1593,10 @@ __archive_entry_acl_parse_w(struct archi
        struct {
                const wchar_t *start;
                const wchar_t *end;
-       } field[4];
+       } field[4], name;
 
        int fields;
        int type, tag, permset, id;
-       const wchar_t *p;
        wchar_t sep;
 
        while (text != NULL  &&  *text != L'\0') {
@@ -1609,9 +1615,6 @@ __archive_entry_acl_parse_w(struct archi
                        ++fields;
                } while (sep == L':');
 
-               if (fields < 3)
-                       return (ARCHIVE_WARN);
-
                /* Check for a numeric ID in field 1 or 3. */
                id = -1;
                isint_w(field[1].start, field[1].end, &id);
@@ -1619,27 +1622,6 @@ __archive_entry_acl_parse_w(struct archi
                if (id == -1 && fields > 3)
                        isint_w(field[3].start, field[3].end, &id);
 
-               /* Parse the permissions from field 2. */
-               permset = 0;
-               p = field[2].start;
-               while (p < field[2].end) {
-                       switch (*p++) {
-                       case 'r': case 'R':
-                               permset |= ARCHIVE_ENTRY_ACL_READ;
-                               break;
-                       case 'w': case 'W':
-                               permset |= ARCHIVE_ENTRY_ACL_WRITE;
-                               break;
-                       case 'x': case 'X':
-                               permset |= ARCHIVE_ENTRY_ACL_EXECUTE;
-                               break;
-                       case '-':
-                               break;
-                       default:
-                               return (ARCHIVE_WARN);
-                       }
-               }
-
                /*
                 * Solaris extension:  "defaultuser::rwx" is the
                 * default ACL corresponding to "user::rwx", etc.
@@ -1651,22 +1633,47 @@ __archive_entry_acl_parse_w(struct archi
                } else
                        type = default_type;
 
+               name.start = name.end = NULL;
                if (prefix_w(field[0].start, field[0].end, L"user")) {
-                       if (id != -1 || field[1].start < field[1].end)
+                       if (!ismode_w(field[2].start, field[2].end, &permset))
+                               return (ARCHIVE_WARN);
+                       if (id != -1 || field[1].start < field[1].end) {
                                tag = ARCHIVE_ENTRY_ACL_USER;
-                       else
+                               name = field[1];
+                       } else
                                tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
                } else if (prefix_w(field[0].start, field[0].end, L"group")) {
-                       if (id != -1 || field[1].start < field[1].end)
+                       if (!ismode_w(field[2].start, field[2].end, &permset))
+                               return (ARCHIVE_WARN);
+                       if (id != -1 || field[1].start < field[1].end) {
                                tag = ARCHIVE_ENTRY_ACL_GROUP;
-                       else
+                               name = field[1];
+                       } else
                                tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
                } else if (prefix_w(field[0].start, field[0].end, L"other")) {
-                       if (id != -1 || field[1].start < field[1].end)
+                       if (fields == 2
+                           && field[1].start < field[1].end
+                           && ismode_w(field[1].start, field[2].end, 
&permset)) {
+                               /* This is Solaris-style "other:rwx" */
+                       } else if (fields == 3
+                           && field[1].start == field[1].end
+                           && field[2].start < field[2].end
+                           && ismode_w(field[2].start, field[2].end, 
&permset)) {
+                               /* This is FreeBSD-style "other::rwx" */
+                       } else
                                return (ARCHIVE_WARN);
                        tag = ARCHIVE_ENTRY_ACL_OTHER;
                } else if (prefix_w(field[0].start, field[0].end, L"mask")) {
-                       if (id != -1 || field[1].start < field[1].end)
+                       if (fields == 2
+                           && field[1].start < field[1].end
+                           && ismode_w(field[1].start, field[1].end, 
&permset)) {
+                               /* This is Solaris-style "mask:rwx" */
+                       } else if (fields == 3
+                           && field[1].start == field[1].end
+                           && field[2].start < field[2].end
+                           && ismode_w(field[2].start, field[2].end, 
&permset)) {
+                               /* This is FreeBSD-style "mask::rwx" */
+                       } else
                                return (ARCHIVE_WARN);
                        tag = ARCHIVE_ENTRY_ACL_MASK;
                } else
@@ -1674,7 +1681,7 @@ __archive_entry_acl_parse_w(struct archi
 
                /* Add entry to the internal list. */
                archive_entry_acl_add_entry_w_len(entry, type, permset,
-                   tag, id, field[1].start, field[1].end - field[1].start);
+                   tag, id, name.start, name.end - name.start);
        }
        return (ARCHIVE_OK);
 }
@@ -1798,6 +1805,38 @@ isint_w(const wchar_t *start, const wcha
 }
 
 /*
+ * Parse a string as a mode field.  Returns true if
+ * the string is non-empty and consists only of mode characters,
+ * false otherwise.
+ */
+static int
+ismode_w(const wchar_t *start, const wchar_t *end, int *permset)
+{
+       const wchar_t *p;
+
+       p = start;
+       *permset = 0;
+       while (p < end) {
+               switch (*p++) {
+               case 'r': case 'R':
+                       *permset |= ARCHIVE_ENTRY_ACL_READ;
+                       break;
+               case 'w': case 'W':
+                       *permset |= ARCHIVE_ENTRY_ACL_WRITE;
+                       break;
+               case 'x': case 'X':
+                       *permset |= ARCHIVE_ENTRY_ACL_EXECUTE;
+                       break;
+               case '-':
+                       break;
+               default:
+                       return (0);
+               }
+       }
+       return (1);
+}
+
+/*
  * Match "[:whitespace:]*(.*)[:whitespace:]*[:,\n]".  *wp is updated
  * to point to just after the separator.  *start points to the first
  * character of the matched text and *end just after the last

Modified: head/lib/libarchive/archive_read_support_format_tar.c
==============================================================================
--- head/lib/libarchive/archive_read_support_format_tar.c       Mon Apr 27 
18:17:32 2009        (r191575)
+++ head/lib/libarchive/archive_read_support_format_tar.c       Mon Apr 27 
18:27:54 2009        (r191576)
@@ -732,6 +732,7 @@ header_Solaris_ACL(struct archive_read *
        const struct archive_entry_header_ustar *header;
        size_t size;
        int err;
+       int64_t type;
        char *acl, *p;
        wchar_t *wp;
 
@@ -744,24 +745,57 @@ header_Solaris_ACL(struct archive_read *
        err = read_body_to_string(a, tar, &(tar->acl_text), h);
        if (err != ARCHIVE_OK)
                return (err);
+       /* Recursively read next header */
        err = tar_read_header(a, tar, entry);
        if ((err != ARCHIVE_OK) && (err != ARCHIVE_WARN))
                return (err);
 
-       /* Skip leading octal number. */
-       /* XXX TODO: Parse the octal number and sanity-check it. */
+       /* TODO: Examine the first characters to see if this
+        * is an AIX ACL descriptor.  We'll likely never support
+        * them, but it would be polite to recognize and warn when
+        * we do see them. */
+
+       /* Leading octal number indicates ACL type and number of entries. */
        p = acl = tar->acl_text.s;
-       while (*p != '\0' && p < acl + size)
+       type = 0;
+       while (*p != '\0' && p < acl + size) {
+               if (*p < '0' || *p > '7') {
+                       archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+                           "Malformed Solaris ACL attribute (invalid digit)");
+                       return(ARCHIVE_WARN);
+               }
+               type <<= 3;
+               type += *p - '0';
+               if (type > 077777777) {
+                       archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+                           "Malformed Solaris ACL attribute (count too 
large)");
+                       return (ARCHIVE_WARN);
+               }
                p++;
+       }
+       switch (type & ~0777777) {
+       case 01000000:
+               /* POSIX.1e ACL */
+               break;
+       case 03000000:
+               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+                   "Solaris NFSv4 ACLs not supported");
+               return (ARCHIVE_WARN);
+       default:
+               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+                   "Malformed Solaris ACL attribute (unsupported type %o)",
+                   (int)type);
+               return (ARCHIVE_WARN);
+       }
        p++;
 
        if (p >= acl + size) {
                archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-                   "Malformed Solaris ACL attribute");
+                   "Malformed Solaris ACL attribute (body overflow)");
                return(ARCHIVE_WARN);
        }
 
-       /* Skip leading octal number. */
+       /* ACL text is null-terminated; find the end. */
        size -= (p - acl);
        acl = p;
 
@@ -771,6 +805,9 @@ header_Solaris_ACL(struct archive_read *
        wp = utf8_decode(tar, acl, p - acl);
        err = __archive_entry_acl_parse_w(entry, wp,
            ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
+       if (err != ARCHIVE_OK)
+               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+                   "Malformed Solaris ACL attribute (unparsable)");
        return (err);
 }
 

Modified: head/lib/libarchive/test/Makefile
==============================================================================
--- head/lib/libarchive/test/Makefile   Mon Apr 27 18:17:32 2009        
(r191575)
+++ head/lib/libarchive/test/Makefile   Mon Apr 27 18:27:54 2009        
(r191576)
@@ -16,6 +16,7 @@ TESTS= \
        test_compat_bzip2.c                     \
        test_compat_gtar.c                      \
        test_compat_gzip.c                      \
+       test_compat_solaris_tar_acl.c           \
        test_compat_tar_hardlink.c              \
        test_compat_xz.c                        \
        test_compat_zip.c                       \

Modified: head/lib/libarchive/test/test_acl_pax.c
==============================================================================
--- head/lib/libarchive/test/test_acl_pax.c     Mon Apr 27 18:17:32 2009        
(r191575)
+++ head/lib/libarchive/test/test_acl_pax.c     Mon Apr 27 18:27:54 2009        
(r191576)
@@ -151,10 +151,10 @@ static unsigned char reference[] = {
 0,0,0,0,0,0,0,0,0,0,'1','1','3',' ','S','C','H','I','L','Y','.','a','c','l',
 '.','a','c','c','e','s','s','=','u','s','e','r',':',':','r','-','x',',','g',
 'r','o','u','p',':',':','r','-','-',',','o','t','h','e','r',':',':','-','w',
-'x',',','g','r','o','u','p',':','g','r','o','u','p','7','8',':','r','w','x',
-':','7','8',',','u','s','e','r',':','u','s','e','r','7','8',':','-','-','-',
-':','7','8',',','u','s','e','r',':','u','s','e','r','7','7',':','r','-','-',
-':','7','7',10,'1','6',' ','S','C','H','I','L','Y','.','d','e','v','=','0',
+'x',',','u','s','e','r',':','u','s','e','r','7','7',':','r','-','-',':','7',
+'7',',','u','s','e','r',':','u','s','e','r','7','8',':','-','-','-',':','7',
+'8',',','g','r','o','u','p',':','g','r','o','u','p','7','8',':','r','w','x',
+':','7','8',10,'1','6',' ','S','C','H','I','L','Y','.','d','e','v','=','0',
 10,'1','6',' ','S','C','H','I','L','Y','.','i','n','o','=','0',10,'1','8',
 ' ','S','C','H','I','L','Y','.','n','l','i','n','k','=','0',10,0,0,0,0,0,
 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
@@ -464,7 +464,7 @@ DEFINE_TEST(test_acl_pax)
 
        /* Assert that the generated data matches the built-in reference data.*/
        failure("Generated pax archive does not match reference; check 
'testout' and 'reference' files.");
-       assert(0 == memcmp(buff, reference, sizeof(reference)));
+       assertEqualMem(buff, reference, sizeof(reference));
        failure("Generated pax archive does not match reference; check 
'testout' and 'reference' files.");
        assertEqualInt((int)used, sizeof(reference));
 

Added: head/lib/libarchive/test/test_compat_solaris_tar_acl.c
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/lib/libarchive/test/test_compat_solaris_tar_acl.c      Mon Apr 27 
18:27:54 2009        (r191576)
@@ -0,0 +1,128 @@
+/*-
+ * Copyright (c) 2003-2009 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+/*
+ * Exercise support for reading Solaris-style ACL data
+ * from tar archives.
+ *
+ * This should work on all systems, regardless of whether local
+ * filesystems support ACLs or not.
+ */
+
+DEFINE_TEST(test_compat_solaris_tar_acl)
+{
+       struct archive *a;
+       struct archive_entry *ae;
+       const char *reference1 = "test_compat_solaris_tar_acl.tar";
+       int type, permset, tag, qual;
+       const char *name;
+
+       /* Sample file generated on Solaris 10 */
+       extract_reference_file(reference1);
+       assert(NULL != (a = archive_read_new()));
+       assertA(0 == archive_read_support_format_all(a));
+       assertA(0 == archive_read_support_compression_all(a));
+       assertA(0 == archive_read_open_filename(a, reference1, 512));
+
+       /* Archive has 1 entry with some ACLs set on it. */
+       assertA(0 == archive_read_next_header(a, &ae));
+       failure("Basic ACLs should set mode to 0640, not %04o",
+           archive_entry_mode(ae)&0777);
+       assertEqualInt((archive_entry_mode(ae) & 0777), 0640);
+       assertEqualInt(7, archive_entry_acl_reset(ae,
+               ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+       assertEqualInt(ARCHIVE_OK, archive_entry_acl_next(ae,
+               ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+               &type, &permset, &tag, &qual, &name));
+       assertEqualInt(ARCHIVE_ENTRY_ACL_TYPE_ACCESS, type);
+       assertEqualInt(006, permset);
+       assertEqualInt(ARCHIVE_ENTRY_ACL_USER_OBJ, tag);
+       assertEqualInt(-1, qual);
+       assert(name == NULL);
+
+       assertEqualInt(ARCHIVE_OK, archive_entry_acl_next(ae,
+               ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+               &type, &permset, &tag, &qual, &name));
+       assertEqualInt(ARCHIVE_ENTRY_ACL_TYPE_ACCESS, type);
+       assertEqualInt(004, permset);
+       assertEqualInt(ARCHIVE_ENTRY_ACL_GROUP_OBJ, tag);
+       assertEqualInt(-1, qual);
+       assert(name == NULL);
+
+       assertEqualInt(ARCHIVE_OK, archive_entry_acl_next(ae,
+               ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+               &type, &permset, &tag, &qual, &name));
+       assertEqualInt(ARCHIVE_ENTRY_ACL_TYPE_ACCESS, type);
+       assertEqualInt(000, permset);
+       assertEqualInt(ARCHIVE_ENTRY_ACL_OTHER, tag);
+       assertEqualInt(-1, qual);
+       assert(name == NULL);
+
+       assertEqualInt(ARCHIVE_OK, archive_entry_acl_next(ae,
+               ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+               &type, &permset, &tag, &qual, &name));
+       assertEqualInt(ARCHIVE_ENTRY_ACL_TYPE_ACCESS, type);
+       assertEqualInt(001, permset);
+       assertEqualInt(ARCHIVE_ENTRY_ACL_USER, tag);
+       assertEqualInt(71, qual);
+       assertEqualString(name, "lp");
+
+       assertEqualInt(ARCHIVE_OK, archive_entry_acl_next(ae,
+               ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+               &type, &permset, &tag, &qual, &name));
+       assertEqualInt(ARCHIVE_ENTRY_ACL_TYPE_ACCESS, type);
+       assertEqualInt(004, permset);
+       assertEqualInt(ARCHIVE_ENTRY_ACL_USER, tag);
+       assertEqualInt(666, qual);
+       assertEqualString(name, "666");
+
+       assertEqualInt(ARCHIVE_OK, archive_entry_acl_next(ae,
+               ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+               &type, &permset, &tag, &qual, &name));
+       assertEqualInt(ARCHIVE_ENTRY_ACL_TYPE_ACCESS, type);
+       assertEqualInt(007, permset);
+       assertEqualInt(ARCHIVE_ENTRY_ACL_USER, tag);
+       assertEqualInt(1000, qual);
+       assertEqualString(name, "trasz");
+
+       assertEqualInt(ARCHIVE_OK, archive_entry_acl_next(ae,
+               ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+               &type, &permset, &tag, &qual, &name));
+       assertEqualInt(ARCHIVE_ENTRY_ACL_TYPE_ACCESS, type);
+       assertEqualInt(004, permset);
+       assertEqualInt(ARCHIVE_ENTRY_ACL_MASK, tag);
+       assertEqualInt(-1, qual);
+       assertEqualString(name, NULL);
+
+       assertEqualInt(ARCHIVE_EOF, archive_entry_acl_next(ae,
+               ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+               &type, &permset, &tag, &qual, &name));
+
+       /* Close the archive. */
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+       assertEqualInt(ARCHIVE_OK, archive_read_finish(a));
+}

Added: head/lib/libarchive/test/test_compat_solaris_tar_acl.tar.uu
==============================================================================
--- /dev/null   00:00:00 1970   (empty, because file is newly added)
+++ head/lib/libarchive/test/test_compat_solaris_tar_acl.tar.uu Mon Apr 27 
18:27:54 2009        (r191576)
@@ -0,0 +1,61 @@
+$FreeBSD$
+begin 644 test_acl_solaris.tar
+M9FEL92UW:71H+7!O<VEX+6%C;',`````````````````````````````````
+M````````````````````````````````````````````````````````````
+M`````````````#`P,#`V-#0`,#`P,3<U,``P,#`P,#`P`#`P,#`P,#`P,30T
+M`#$Q,3<T-C`T,34W`#`P,34Q-S8`00``````````````````````````````
+M````````````````````````````````````````````````````````````
+M``````````````````````````````````````````!U<W1A<@`P,'1R87-Z
+M````````````````````````````````````<F]O=```````````````````
+M```````````````````P,#`P,C$P`#`P,#`P,3``````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M```````````````````````Q,#`P,#`W`'5S97(Z.G)W+2QU<V5R.FQP.BTM
+M>#HW,2QU<V5R.C8V-CIR+2TZ-C8V+'5S97(Z=')A<WHZ<G=X.C$P,#`L9W)O
+M=7`Z.G(M+2QM87-K.G(M+2QO=&AE<CIR+2T``````````3````````/-...@```
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````!%&8`````````&L`````,3`P,#`P-P!U
+M<V5R.CIR=RTL=7-E<CIL<#h...@z-s$l=7-e<CHV-C8Z<BTM.C8V-BQU<V5R
+M.G1R87-Z.G)W>#HQ,#`P+&=R;W5P.CIR+2TL;6%S:SIR+69I;&4M=VET:"UP
+M;W-I>"UA8VQS````````````````````````````````````````````````
+M```````````````````````````````````````````````````````````P
+M,#`P-C0T`#`P,#$W-3``,#`P,#`P,``P,#`P,#`P,#`P,``Q,3$W-#8P-#$U
+M-P`P,#$U,30T`#``````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````=7-T87(`,#!T<F%S>@``````````````
+M`````````````````````')O;W0`````````````````````````````````
+M````,#`P,#(Q,``P,#`P,#$P````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+M````````````````````````````````````````````````````````````
+H````````````````````````````````````````````````````````
+`
+end
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to