svn commit: r191576 - in head/lib/libarchive: . test

Tim Kientzle kientzle at FreeBSD.org
Mon Apr 27 18:27:56 UTC 2009


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<#HM+7 at 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


More information about the svn-src-all mailing list