PERFORCE change 137792 for review

Kip Macy kmacy at FreeBSD.org
Sat Mar 15 19:02:04 UTC 2008


http://perforce.freebsd.org/chv.cgi?CH=137792

Change 137792 by kmacy at pandemonium:kmacy:iwarp on 2008/03/15 19:01:02

	IFC 137789

Affected files ...

.. //depot/projects/iwarp/lib/libarchive/archive_read_private.h#4 integrate
.. //depot/projects/iwarp/lib/libarchive/archive_read_support_format_mtree.c#3 integrate
.. //depot/projects/iwarp/lib/libarchive/archive_read_support_format_tar.c#6 integrate
.. //depot/projects/iwarp/lib/libarchive/archive_write_disk.c#5 integrate
.. //depot/projects/iwarp/lib/libarchive/archive_write_private.h#2 integrate
.. //depot/projects/iwarp/lib/libarchive/archive_write_set_format_ar.c#4 integrate
.. //depot/projects/iwarp/lib/libarchive/archive_write_set_format_cpio.c#3 integrate
.. //depot/projects/iwarp/lib/libarchive/archive_write_set_format_cpio_newc.c#3 integrate
.. //depot/projects/iwarp/lib/libarchive/archive_write_set_format_pax.c#3 integrate
.. //depot/projects/iwarp/lib/libarchive/archive_write_set_format_shar.c#2 integrate
.. //depot/projects/iwarp/lib/libarchive/archive_write_set_format_ustar.c#3 integrate
.. //depot/projects/iwarp/lib/libarchive/config_freebsd.h#3 integrate
.. //depot/projects/iwarp/lib/libarchive/test/.cvsignore#1 branch
.. //depot/projects/iwarp/lib/libarchive/test/Makefile#6 integrate
.. //depot/projects/iwarp/lib/libarchive/test/test_empty_write.c#2 integrate
.. //depot/projects/iwarp/lib/libarchive/test/test_pax_filename_encoding.c#1 branch
.. //depot/projects/iwarp/lib/libarchive/test/test_pax_filename_encoding.tar.gz.uu#1 branch
.. //depot/projects/iwarp/lib/libarchive/test/test_write_compress.c#2 integrate
.. //depot/projects/iwarp/release/doc/en_US.ISO8859-1/relnotes/article.sgml#8 integrate
.. //depot/projects/iwarp/sys/ia64/isa/isa_dma.c#2 integrate
.. //depot/projects/iwarp/sys/kern/link_elf.c#4 integrate
.. //depot/projects/iwarp/sys/kern/link_elf_obj.c#4 integrate
.. //depot/projects/iwarp/sys/sys/bus_dma.h#2 integrate
.. //depot/projects/iwarp/usr.bin/tar/bsdtar.1#3 integrate
.. //depot/projects/iwarp/usr.bin/tar/bsdtar.c#3 integrate
.. //depot/projects/iwarp/usr.bin/tar/bsdtar.h#3 integrate
.. //depot/projects/iwarp/usr.bin/tar/config_freebsd.h#3 integrate
.. //depot/projects/iwarp/usr.bin/tar/read.c#3 integrate
.. //depot/projects/iwarp/usr.bin/tar/write.c#3 integrate
.. //depot/projects/iwarp/usr.sbin/mixer/mixer.8#2 integrate
.. //depot/projects/iwarp/usr.sbin/mixer/mixer.c#2 integrate

Differences ...

==== //depot/projects/iwarp/lib/libarchive/archive_read_private.h#4 (text+ko) ====

@@ -22,7 +22,7 @@
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
- * $FreeBSD: src/lib/libarchive/archive_read_private.h,v 1.5 2008/03/12 04:58:32 kientzle Exp $
+ * $FreeBSD: src/lib/libarchive/archive_read_private.h,v 1.6 2008/03/15 11:09:16 kientzle Exp $
  */
 
 #ifndef ARCHIVE_READ_PRIVATE_H_INCLUDED
@@ -93,17 +93,10 @@
 
 	/*
 	 * Format detection is mostly the same as compression
-	 * detection, with two significant differences: The bidders
+	 * detection, with one significant difference: The bidders
 	 * use the read_ahead calls above to examine the stream rather
 	 * than having the supervisor hand them a block of data to
-	 * examine, and the auction is repeated for every header.
-	 * Winning bidders should set the archive_format and
-	 * archive_format_name appropriately.  Bid routines should
-	 * check archive_format and decline to bid if the format of
-	 * the last header was incompatible.
-	 *
-	 * Again, write support is considerably simpler because there's
-	 * no need for an auction.
+	 * examine.
 	 */
 
 	struct archive_format_descriptor {

==== //depot/projects/iwarp/lib/libarchive/archive_read_support_format_mtree.c#3 (text+ko) ====

@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_mtree.c,v 1.2 2008/02/19 06:07:10 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_mtree.c,v 1.4 2008/03/15 11:02:47 kientzle Exp $");
 
 #ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
@@ -76,12 +76,18 @@
 	struct mtree_entry	*this_entry;
 	struct archive_string	 current_dir;
 	struct archive_string	 contents_name;
+
+	off_t			 cur_size, cur_offset;
 };
 
 static int	cleanup(struct archive_read *);
 static int	mtree_bid(struct archive_read *);
+static int	parse_file(struct archive_read *, struct archive_entry *,
+		    struct mtree *, struct mtree_entry *);
 static void	parse_escapes(char *, struct mtree_entry *);
-static int	parse_setting(struct archive_read *, struct mtree *,
+static int	parse_line(struct archive_read *, struct archive_entry *,
+		    struct mtree *, struct mtree_entry *);
+static int	parse_keyword(struct archive_read *, struct mtree *,
 		    struct archive_entry *, char *, char *);
 static int	read_data(struct archive_read *a,
 		    const void **buff, size_t *size, off_t *offset);
@@ -252,14 +258,16 @@
 	}
 }
 
+/*
+ * Read in the entire mtree file into memory on the first request.
+ * Then use the next unused file to satisfy each header request.
+ */
 static int
 read_header(struct archive_read *a, struct archive_entry *entry)
 {
-	struct stat st;
 	struct mtree *mtree;
-	struct mtree_entry *mentry, *mentry2;
-	char *p, *q;
-	int r = ARCHIVE_OK, r1;
+	char *p;
+	int r;
 
 	mtree = (struct mtree *)(a->format->data);
 
@@ -278,16 +286,10 @@
 	a->archive.archive_format_name = mtree->archive_format_name;
 
 	for (;;) {
-		mentry = mtree->this_entry;
-		if (mentry == NULL) {
-			mtree->this_entry = NULL;
+		if (mtree->this_entry == NULL)
 			return (ARCHIVE_EOF);
-		}
-		mtree->this_entry = mentry->next;
-		if (mentry->used)
-			continue;
-		mentry->used = 1;
-		if (strcmp(mentry->name, "..") == 0) {
+		if (strcmp(mtree->this_entry->name, "..") == 0) {
+			mtree->this_entry->used = 1;
 			if (archive_strlen(&mtree->current_dir) > 0) {
 				/* Roll back current path. */
 				p = mtree->current_dir.s
@@ -299,117 +301,165 @@
 				mtree->current_dir.length
 				    = p - mtree->current_dir.s + 1;
 			}
-			continue;
+		}
+		if (!mtree->this_entry->used) {
+			r = parse_file(a, entry, mtree, mtree->this_entry);
+			return (r);
 		}
+		mtree->this_entry = mtree->this_entry->next;
+	}
+}
+
+/*
+ * A single file can have multiple lines contribute specifications.
+ * Parse as many lines as necessary, then pull additional information
+ * from a backing file on disk as necessary.
+ */
+static int
+parse_file(struct archive_read *a, struct archive_entry *entry,
+    struct mtree *mtree, struct mtree_entry *mentry)
+{
+	struct stat st;
+	struct mtree_entry *mp;
+	int r = ARCHIVE_OK, r1;
 
-		mtree->filetype = AE_IFREG;
+	mentry->used = 1;
 
-		/* Parse options. */
-		p = mentry->option_start;
-		while (p < mentry->option_end) {
-			q = p + strlen(p);
-			r1 = parse_setting(a, mtree, entry, p, q);
-			if (r1 != ARCHIVE_OK)
-				r = r1;
-			p = q + 1;
-		}
+	/* Initialize reasonable defaults. */
+	mtree->filetype = AE_IFREG;
+	archive_entry_set_size(entry, 0);
 
-		if (mentry->full) {
-			archive_entry_copy_pathname(entry, mentry->name);
-			/*
-			 * "Full" entries are allowed to have multiple
-			 * lines and those lines aren't required to be
-			 * adjacent.  We don't support multiple lines
-			 * for "relative" entries nor do we make any
-			 * attempt to merge data from separate
-			 * "relative" and "full" entries.  (Merging
-			 * "relative" and "full" entries would require
-			 * dealing with pathname canonicalization,
-			 * which is a very tricky subject.)
-			 */
-			mentry2 = mentry->next;
-			while (mentry2 != NULL) {
-				if (mentry2->full
-				    && !mentry2->used
-				    && strcmp(mentry->name, mentry2->name) == 0) {
-					/*
-					 * Add those options as well;
-					 * later lines override
-					 * earlier ones.
-					 */
-					p = mentry2->option_start;
-					while (p < mentry2->option_end) {
-						q = p + strlen(p);
-						r1 = parse_setting(a, mtree, entry, p, q);
-						if (r1 != ARCHIVE_OK)
-							r = r1;
-						p = q + 1;
-					}
-					mentry2->used = 1;
-				}
-				mentry2 = mentry2->next;
-			}
-		} else {
-			/*
-			 * Relative entries require us to construct
-			 * the full path and possibly update the
-			 * current directory.
-			 */
-			size_t n = archive_strlen(&mtree->current_dir);
-			if (n > 0)
-				archive_strcat(&mtree->current_dir, "/");
-			archive_strcat(&mtree->current_dir, mentry->name);
-			archive_entry_copy_pathname(entry, mtree->current_dir.s);
-			if (archive_entry_filetype(entry) != AE_IFDIR)
-				mtree->current_dir.length = n;
-		}
+	/* Parse options from this line. */
+	r = parse_line(a, entry, mtree, mentry);
 
+	if (mentry->full) {
+		archive_entry_copy_pathname(entry, mentry->name);
 		/*
-		 * Try to open and stat the file to get the real size.
-		 * It would be nice to avoid this here so that getting
-		 * a listing of an mtree wouldn't require opening
-		 * every referenced contents file.  But then we
-		 * wouldn't know the actual contents size, so I don't
-		 * see a really viable way around this.  (Also, we may
-		 * want to someday pull other unspecified info from
-		 * the contents file on disk.)
+		 * "Full" entries are allowed to have multiple lines
+		 * and those lines aren't required to be adjacent.  We
+		 * don't support multiple lines for "relative" entries
+		 * nor do we make any attempt to merge data from
+		 * separate "relative" and "full" entries.  (Merging
+		 * "relative" and "full" entries would require dealing
+		 * with pathname canonicalization, which is a very
+		 * tricky subject.)
 		 */
-		if (archive_strlen(&mtree->contents_name) > 0) {
-			mtree->fd = open(mtree->contents_name.s,
-			    O_RDONLY | O_BINARY);
-			if (mtree->fd < 0) {
-				archive_set_error(&a->archive, errno,
-				    "Can't open content=\"%s\"",
-				    mtree->contents_name.s);
-				r = ARCHIVE_WARN;
+		for (mp = mentry->next; mp != NULL; mp = mp->next) {
+			if (mp->full && !mp->used
+			    && strcmp(mentry->name, mp->name) == 0) {
+				/* Later lines override earlier ones. */
+				mp->used = 1;
+				r1 = parse_line(a, entry, mtree, mp);
+				if (r1 < r)
+					r = r1;
 			}
-		} else {
-			/* If the specified path opens, use it. */
-			mtree->fd = open(mtree->current_dir.s,
-			    O_RDONLY | O_BINARY);
-			/* But don't fail if it's not there. */
 		}
-
+	} else {
 		/*
-		 * If there is a contents file on disk, use that size;
-		 * otherwise leave it as-is (it might have been set from
-		 * the mtree size= keyword).
+		 * Relative entries require us to construct
+		 * the full path and possibly update the
+		 * current directory.
 		 */
-		if (mtree->fd >= 0) {
-			fstat(mtree->fd, &st);
+		size_t n = archive_strlen(&mtree->current_dir);
+		if (n > 0)
+			archive_strcat(&mtree->current_dir, "/");
+		archive_strcat(&mtree->current_dir, mentry->name);
+		archive_entry_copy_pathname(entry, mtree->current_dir.s);
+		if (archive_entry_filetype(entry) != AE_IFDIR)
+			mtree->current_dir.length = n;
+	}
+
+	/*
+	 * Try to open and stat the file to get the real size
+	 * and other file info.  It would be nice to avoid
+	 * this here so that getting a listing of an mtree
+	 * wouldn't require opening every referenced contents
+	 * file.  But then we wouldn't know the actual
+	 * contents size, so I don't see a really viable way
+	 * around this.  (Also, we may want to someday pull
+	 * other unspecified info from the contents file on
+	 * disk.)
+	 */
+	mtree->fd = -1;
+	if (archive_strlen(&mtree->contents_name) > 0) {
+		mtree->fd = open(mtree->contents_name.s,
+		    O_RDONLY | O_BINARY);
+		if (mtree->fd < 0) {
+			archive_set_error(&a->archive, errno,
+			    "Can't open content=\"%s\"",
+			    mtree->contents_name.s);
+			r = ARCHIVE_WARN;
+		}
+	} else if (archive_entry_filetype(entry) == AE_IFREG) {
+		mtree->fd = open(archive_entry_pathname(entry),
+		    O_RDONLY | O_BINARY);
+	}
+
+	/*
+	 * If there is a contents file on disk, use that size;
+	 * otherwise leave it as-is (it might have been set from
+	 * the mtree size= keyword).
+	 */
+	if (mtree->fd >= 0) {
+		if (fstat(mtree->fd, &st) != 0) {
+			archive_set_error(&a->archive, errno,
+			    "could not stat %s",
+			    archive_entry_pathname(entry));
+			r = ARCHIVE_WARN;
+			/* If we can't stat it, don't keep it open. */
+			close(mtree->fd);
+			mtree->fd = -1;
+		} else if ((st.st_mode & S_IFMT) != S_IFREG) {
+			archive_set_error(&a->archive, errno,
+			    "%s is not a regular file",
+			    archive_entry_pathname(entry));
+			r = ARCHIVE_WARN;
+			/* Don't hold a non-regular file open. */
+			close(mtree->fd);
+			mtree->fd = -1;
+		} else {
 			archive_entry_set_size(entry, st.st_size);
+			archive_entry_set_ino(entry, st.st_ino);
+			archive_entry_set_dev(entry, st.st_dev);
+			archive_entry_set_nlink(entry, st.st_nlink);
 		}
+	}
+	mtree->cur_size = archive_entry_size(entry);
+	mtree->offset = 0;
 
-		return r;
+	return r;
+}
+
+/*
+ * Each line contains a sequence of keywords.
+ */
+static int
+parse_line(struct archive_read *a, struct archive_entry *entry,
+    struct mtree *mtree, struct mtree_entry *mp)
+{
+	char *p, *q;
+	int r = ARCHIVE_OK, r1;
+
+	p = mp->option_start;
+	while (p < mp->option_end) {
+		q = p + strlen(p);
+		r1 = parse_keyword(a, mtree, entry, p, q);
+		if (r1 < r)
+			r = r1;
+		p = q + 1;
 	}
+	return (r);
 }
 
+/*
+ * Parse a single keyword and its value.
+ */
 static int
-parse_setting(struct archive_read *a, struct mtree *mtree, struct archive_entry *entry, char *key, char *end)
+parse_keyword(struct archive_read *a, struct mtree *mtree,
+    struct archive_entry *entry, char *key, char *end)
 {
 	char *val;
 
-
 	if (end == key)
 		return (ARCHIVE_OK);
 	if (*key == '\0')
@@ -427,7 +477,8 @@
 
 	switch (key[0]) {
 	case 'c':
-		if (strcmp(key, "content") == 0) {
+		if (strcmp(key, "content") == 0
+		    || strcmp(key, "contents") == 0) {
 			parse_escapes(val, NULL);
 			archive_strcpy(&mtree->contents_name, val);
 			break;
@@ -441,6 +492,11 @@
 			archive_entry_copy_gname(entry, val);
 			break;
 		}
+	case 'l':
+		if (strcmp(key, "link") == 0) {
+			archive_entry_set_link(entry, val);
+			break;
+		}
 	case 'm':
 		if (strcmp(key, "mode") == 0) {
 			if (val[0] == '0') {
@@ -452,6 +508,11 @@
 				    "Symbolic mode \"%s\" unsupported", val);
 			break;
 		}
+	case 's':
+		if (strcmp(key, "size") == 0) {
+			archive_entry_set_size(entry, mtree_atol10(&val));
+			break;
+		}
 	case 't':
 		if (strcmp(key, "type") == 0) {
 			switch (val[0]) {
@@ -517,6 +578,7 @@
 static int
 read_data(struct archive_read *a, const void **buff, size_t *size, off_t *offset)
 {
+	size_t bytes_to_read;
 	ssize_t bytes_read;
 	struct mtree *mtree;
 
@@ -538,7 +600,11 @@
 
 	*buff = mtree->buff;
 	*offset = mtree->offset;
-	bytes_read = read(mtree->fd, mtree->buff, mtree->buffsize);
+	if ((off_t)mtree->buffsize > mtree->cur_size - mtree->offset)
+		bytes_to_read = mtree->cur_size - mtree->offset;
+	else
+		bytes_to_read = mtree->buffsize;
+	bytes_read = read(mtree->fd, mtree->buff, bytes_to_read);
 	if (bytes_read < 0) {
 		archive_set_error(&a->archive, errno, "Can't read");
 		return (ARCHIVE_WARN);
@@ -548,7 +614,7 @@
 		return (ARCHIVE_EOF);
 	}
 	mtree->offset += bytes_read;
-	*size = (size_t)bytes_read;
+	*size = bytes_read;
 	return (ARCHIVE_OK);
 }
 

==== //depot/projects/iwarp/lib/libarchive/archive_read_support_format_tar.c#6 (text+ko) ====

@@ -24,7 +24,7 @@
  */
 
 #include "archive_platform.h"
-__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_tar.c,v 1.66 2008/03/14 20:32:20 kientzle Exp $");
+__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_tar.c,v 1.67 2008/03/15 01:43:58 kientzle Exp $");
 
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
@@ -144,8 +144,8 @@
 
 struct tar {
 	struct archive_string	 acl_text;
-	struct archive_string	 entry_name;
-	struct archive_string	 entry_linkname;
+	struct archive_string	 entry_pathname;
+	struct archive_string	 entry_linkpath;
 	struct archive_string	 entry_uname;
 	struct archive_string	 entry_gname;
 	struct archive_string	 longlink;
@@ -153,6 +153,7 @@
 	struct archive_string	 pax_header;
 	struct archive_string	 pax_global;
 	struct archive_string	 line;
+	int			 pax_hdrcharset_binary;
 	wchar_t 		*pax_entry;
 	size_t			 pax_entry_length;
 	int			 header_recursion_depth;
@@ -169,9 +170,9 @@
 	char			 sparse_gnu_pending;
 };
 
-static size_t	UTF8_mbrtowc(wchar_t *pwc, const char *s, size_t n);
+static ssize_t	UTF8_mbrtowc(wchar_t *pwc, const char *s, size_t n);
 static int	archive_block_is_null(const unsigned char *p);
-static char	*base64_decode(const wchar_t *, size_t, size_t *);
+static char	*base64_decode(const char *, size_t, size_t *);
 static void	 gnu_add_sparse_entry(struct tar *,
 		    off_t offset, off_t remaining);
 static void	gnu_clear_sparse_list(struct tar *);
@@ -179,7 +180,7 @@
 		    const struct archive_entry_header_gnutar *header);
 static void	gnu_sparse_old_parse(struct tar *,
 		    const struct gnu_sparse *sparse, int length);
-static int	gnu_sparse_01_parse(struct tar *, const wchar_t *);
+static int	gnu_sparse_01_parse(struct tar *, const char *);
 static ssize_t	gnu_sparse_10_read(struct archive_read *, struct tar *);
 static int	header_Solaris_ACL(struct archive_read *,  struct tar *,
 		    struct archive_entry *, const void *);
@@ -210,24 +211,23 @@
 		    struct archive_entry *);
 static int	checksum(struct archive_read *, const void *);
 static int 	pax_attribute(struct tar *, struct archive_entry *,
-		    wchar_t *key, wchar_t *value);
+		    char *key, char *value);
 static int 	pax_header(struct archive_read *, struct tar *,
 		    struct archive_entry *, char *attr);
-static void	pax_time(const wchar_t *, int64_t *sec, long *nanos);
+static void	pax_time(const char *, int64_t *sec, long *nanos);
 static ssize_t	readline(struct archive_read *, struct tar *, const char **,
 		    ssize_t limit);
 static int	read_body_to_string(struct archive_read *, struct tar *,
 		    struct archive_string *, const void *h);
 static int64_t	tar_atol(const char *, unsigned);
-static int64_t	tar_atol10(const wchar_t *, unsigned);
+static int64_t	tar_atol10(const char *, unsigned);
 static int64_t	tar_atol256(const char *, unsigned);
 static int64_t	tar_atol8(const char *, unsigned);
 static int	tar_read_header(struct archive_read *, struct tar *,
 		    struct archive_entry *);
 static int	tohex(int c);
 static char	*url_decode(const char *);
-static int	utf8_decode(wchar_t *, const char *, size_t length);
-static char	*wide_to_narrow(const wchar_t *wval);
+static wchar_t	*utf8_decode(struct tar *, const char *, size_t length);
 
 int
 archive_read_support_format_gnutar(struct archive *a)
@@ -271,8 +271,8 @@
 	tar = (struct tar *)(a->format->data);
 	gnu_clear_sparse_list(tar);
 	archive_string_free(&tar->acl_text);
-	archive_string_free(&tar->entry_name);
-	archive_string_free(&tar->entry_linkname);
+	archive_string_free(&tar->entry_pathname);
+	archive_string_free(&tar->entry_linkpath);
 	archive_string_free(&tar->entry_uname);
 	archive_string_free(&tar->entry_gname);
 	archive_string_free(&tar->line);
@@ -766,16 +766,9 @@
 	while (*p != '\0' && p < acl + size)
 		p++;
 
-	wp = (wchar_t *)malloc((p - acl + 1) * sizeof(wchar_t));
-	if (wp == NULL) {
-		archive_set_error(&a->archive, ENOMEM,
-		    "Can't allocate work buffer for ACL parsing");
-		return (ARCHIVE_FATAL);
-	}
-	utf8_decode(wp, acl, p - acl);
+	wp = utf8_decode(tar, acl, p - acl);
 	err = __archive_entry_acl_parse_w(entry, wp,
 	    ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
-	free(wp);
 	return (err);
 }
 
@@ -795,7 +788,7 @@
 	if ((err != ARCHIVE_OK) && (err != ARCHIVE_WARN))
 		return (err);
 	/* Set symlink if symlink already set, else hardlink. */
-	archive_entry_set_link(entry, tar->longlink.s);
+	archive_entry_copy_link(entry, tar->longlink.s);
 	return (ARCHIVE_OK);
 }
 
@@ -815,7 +808,7 @@
 	err = tar_read_header(a, tar, entry);
 	if ((err != ARCHIVE_OK) && (err != ARCHIVE_WARN))
 		return (err);
-	archive_entry_set_pathname(entry, tar->longname.s);
+	archive_entry_copy_pathname(entry, tar->longname.s);
 	return (ARCHIVE_OK);
 }
 
@@ -907,10 +900,10 @@
 
 	header = (const struct archive_entry_header_ustar *)h;
 	if (header->linkname[0])
-		archive_strncpy(&(tar->entry_linkname), header->linkname,
+		archive_strncpy(&(tar->entry_linkpath), header->linkname,
 		    sizeof(header->linkname));
 	else
-		archive_string_empty(&(tar->entry_linkname));
+		archive_string_empty(&(tar->entry_linkpath));
 
 	/* Parse out the numeric fields (all are octal) */
 	archive_entry_set_mode(entry, tar_atol(header->mode, sizeof(header->mode)));
@@ -926,7 +919,7 @@
 
 	switch (tartype) {
 	case '1': /* Hard link */
-		archive_entry_set_hardlink(entry, tar->entry_linkname.s);
+		archive_entry_copy_hardlink(entry, tar->entry_linkpath.s);
 		/*
 		 * The following may seem odd, but: Technically, tar
 		 * does not store the file type for a "hard link"
@@ -988,7 +981,7 @@
 		archive_entry_set_filetype(entry, AE_IFLNK);
 		archive_entry_set_size(entry, 0);
 		tar->entry_bytes_remaining = 0;
-		archive_entry_set_symlink(entry, tar->entry_linkname.s);
+		archive_entry_copy_symlink(entry, tar->entry_linkpath.s);
 		break;
 	case '3': /* Character device */
 		archive_entry_set_filetype(entry, AE_IFCHR);
@@ -1060,8 +1053,8 @@
 
 	/* Copy filename over (to ensure null termination). */
 	header = (const struct archive_entry_header_ustar *)h;
-	archive_strncpy(&(tar->entry_name), header->name, sizeof(header->name));
-	archive_entry_set_pathname(entry, tar->entry_name.s);
+	archive_strncpy(&(tar->entry_pathname), header->name, sizeof(header->name));
+	archive_entry_copy_pathname(entry, tar->entry_pathname.s);
 
 	/* Grab rest of common fields */
 	header_common(a, tar, entry, h);
@@ -1132,7 +1125,7 @@
 	header = (const struct archive_entry_header_ustar *)h;
 
 	/* Copy name into an internal buffer to ensure null-termination. */
-	as = &(tar->entry_name);
+	as = &(tar->entry_pathname);
 	if (header->prefix[0]) {
 		archive_strncpy(as, header->prefix, sizeof(header->prefix));
 		if (as->s[archive_strlen(as) - 1] != '/')
@@ -1141,7 +1134,7 @@
 	} else
 		archive_strncpy(as, header->name, sizeof(header->name));
 
-	archive_entry_set_pathname(entry, as->s);
+	archive_entry_copy_pathname(entry, as->s);
 
 	/* Handle rest of common fields. */
 	header_common(a, tar, entry, h);
@@ -1149,11 +1142,11 @@
 	/* Handle POSIX ustar fields. */
 	archive_strncpy(&(tar->entry_uname), header->uname,
 	    sizeof(header->uname));
-	archive_entry_set_uname(entry, tar->entry_uname.s);
+	archive_entry_copy_uname(entry, tar->entry_uname.s);
 
 	archive_strncpy(&(tar->entry_gname), header->gname,
 	    sizeof(header->gname));
-	archive_entry_set_gname(entry, tar->entry_gname.s);
+	archive_entry_copy_gname(entry, tar->entry_gname.s);
 
 	/* Parse out device numbers only for char and block specials. */
 	if (header->typeflag[0] == '3' || header->typeflag[0] == '4') {
@@ -1180,10 +1173,16 @@
 {
 	size_t attr_length, l, line_length;
 	char *line, *p;
-	wchar_t *key, *wp, *value;
+	char *key, *value;
+	wchar_t *wp;
 	int err, err2;
 
 	attr_length = strlen(attr);
+	tar->pax_hdrcharset_binary = 0;
+	archive_string_empty(&(tar->entry_gname));
+	archive_string_empty(&(tar->entry_linkpath));
+	archive_string_empty(&(tar->entry_pathname));
+	archive_string_empty(&(tar->entry_uname));
 	err = ARCHIVE_OK;
 	while (attr_length > 0) {
 		/* Parse decimal length field at start of line. */
@@ -1226,49 +1225,24 @@
 			return (ARCHIVE_WARN);
 		}
 
-		/* Ensure pax_entry buffer is big enough. */
-		if (tar->pax_entry_length <= line_length) {
-			wchar_t *old_entry = tar->pax_entry;
+		/* Null-terminate the line. */
+		attr[line_length - 1] = '\0';
 
-			if (tar->pax_entry_length <= 0)
-				tar->pax_entry_length = 1024;
-			while (tar->pax_entry_length <= line_length + 1)
-				tar->pax_entry_length *= 2;
-
-			old_entry = tar->pax_entry;
-			tar->pax_entry = (wchar_t *)realloc(tar->pax_entry,
-			    tar->pax_entry_length * sizeof(wchar_t));
-			if (tar->pax_entry == NULL) {
-				free(old_entry);
-				archive_set_error(&a->archive, ENOMEM,
-					"No memory");
-				return (ARCHIVE_FATAL);
-			}
-		}
-
-		/* Decode UTF-8 to wchar_t, null-terminate result. */
-		if (utf8_decode(tar->pax_entry, p,
-			line_length - (p - attr) - 1)) {
-			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
-			   "Invalid UTF8 character in pax extended attribute");
-			err = err_combine(err, ARCHIVE_WARN);
-		}
-
-		/* Null-terminate 'key' value. */
-		wp = key = tar->pax_entry;
-		if (key[0] == L'=')
+		/* Find end of key and null terminate it. */
+		key = p;
+		if (key[0] == '=')
 			return (-1);
-		while (*wp && *wp != L'=')
-			++wp;
-		if (*wp == L'\0') {
+		while (*p && *p != '=')
+			++p;
+		if (*p == '\0') {
 			archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
 			    "Invalid pax extended attributes");
 			return (ARCHIVE_WARN);
 		}
-		*wp = 0;
+		*p = '\0';
 
 		/* Identify null-terminated 'value' portion. */
-		value = wp + 1;
+		value = p + 1;
 
 		/* Identify this attribute and set it in the entry. */
 		err2 = pax_attribute(tar, entry, key, value);
@@ -1278,33 +1252,85 @@
 		attr += line_length;
 		attr_length -= line_length;
 	}
+	if (archive_strlen(&(tar->entry_gname)) > 0) {
+		value = tar->entry_gname.s;
+		if (tar->pax_hdrcharset_binary)
+			archive_entry_copy_gname(entry, value);
+		else {
+			wp = utf8_decode(tar, value, strlen(value));
+			if (wp == NULL) {
+				archive_entry_copy_gname(entry, value);
+				if (err > ARCHIVE_WARN)
+					err = ARCHIVE_WARN;
+			} else
+				archive_entry_copy_gname_w(entry, wp);
+		}
+	}
+	if (archive_strlen(&(tar->entry_linkpath)) > 0) {
+		value = tar->entry_linkpath.s;
+		if (tar->pax_hdrcharset_binary)
+			archive_entry_copy_link(entry, value);
+		else {
+			wp = utf8_decode(tar, value, strlen(value));
+			if (wp == NULL) {
+				archive_entry_copy_link(entry, value);
+				if (err > ARCHIVE_WARN)
+					err = ARCHIVE_WARN;
+			} else
+				archive_entry_copy_link_w(entry, wp);
+		}
+	}
+	if (archive_strlen(&(tar->entry_pathname)) > 0) {
+		value = tar->entry_pathname.s;
+		if (tar->pax_hdrcharset_binary)
+			archive_entry_copy_pathname(entry, value);
+		else {
+			wp = utf8_decode(tar, value, strlen(value));
+			if (wp == NULL) {
+				archive_entry_copy_pathname(entry, value);
+				if (err > ARCHIVE_WARN)
+					err = ARCHIVE_WARN;
+			} else
+				archive_entry_copy_pathname_w(entry, wp);
+		}
+	}
+	if (archive_strlen(&(tar->entry_uname)) > 0) {
+		value = tar->entry_uname.s;
+		if (tar->pax_hdrcharset_binary)
+			archive_entry_copy_uname(entry, value);
+		else {
+			wp = utf8_decode(tar, value, strlen(value));
+			if (wp == NULL) {
+				archive_entry_copy_uname(entry, value);
+				if (err > ARCHIVE_WARN)
+					err = ARCHIVE_WARN;
+			} else
+				archive_entry_copy_uname_w(entry, wp);
+		}
+	}
 	return (err);
 }
 
 static int
 pax_attribute_xattr(struct archive_entry *entry,
-	wchar_t *name, wchar_t *value)
+	char *name, char *value)
 {
-	char *name_decoded, *name_narrow;
+	char *name_decoded;
 	void *value_decoded;
 	size_t value_len;
 
-	if (wcslen(name) < 18 || (wcsncmp(name, L"LIBARCHIVE.xattr.", 17)) != 0)
+	if (strlen(name) < 18 || (strncmp(name, "LIBARCHIVE.xattr.", 17)) != 0)
 		return 3;
 
 	name += 17;
 
 	/* URL-decode name */
-	name_narrow = wide_to_narrow(name);
-	if (name_narrow == NULL)
-		return 2;
-	name_decoded = url_decode(name_narrow);
-	free(name_narrow);
+	name_decoded = url_decode(name);
 	if (name_decoded == NULL)
 		return 2;
 
 	/* Base-64 decode value */
-	value_decoded = base64_decode(value, wcslen(value), &value_len);
+	value_decoded = base64_decode(value, strlen(value), &value_len);
 	if (value_decoded == NULL) {
 		free(name_decoded);
 		return 1;
@@ -1333,22 +1359,23 @@
  */
 static int
 pax_attribute(struct tar *tar, struct archive_entry *entry,
-    wchar_t *key, wchar_t *value)
+    char *key, char *value)
 {
 	int64_t s;
 	long n;
+	wchar_t *wp;
 
 	switch (key[0]) {
 	case 'G':
 		/* GNU "0.0" sparse pax format. */
-		if (wcscmp(key, L"GNU.sparse.numblocks") == 0) {
+		if (strcmp(key, "GNU.sparse.numblocks") == 0) {
 			tar->sparse_offset = -1;
 			tar->sparse_numbytes = -1;
 			tar->sparse_gnu_major = 0;
 			tar->sparse_gnu_minor = 0;
 		}
-		if (wcscmp(key, L"GNU.sparse.offset") == 0) {
-			tar->sparse_offset = tar_atol10(value, wcslen(value));
+		if (strcmp(key, "GNU.sparse.offset") == 0) {
+			tar->sparse_offset = tar_atol10(value, strlen(value));
 			if (tar->sparse_numbytes != -1) {
 				gnu_add_sparse_entry(tar,
 				    tar->sparse_offset, tar->sparse_numbytes);
@@ -1356,8 +1383,8 @@
 				tar->sparse_numbytes = -1;
 			}
 		}
-		if (wcscmp(key, L"GNU.sparse.numbytes") == 0) {
-			tar->sparse_numbytes = tar_atol10(value, wcslen(value));
+		if (strcmp(key, "GNU.sparse.numbytes") == 0) {
+			tar->sparse_numbytes = tar_atol10(value, strlen(value));
 			if (tar->sparse_numbytes != -1) {
 				gnu_add_sparse_entry(tar,
 				    tar->sparse_offset, tar->sparse_numbytes);
@@ -1365,13 +1392,13 @@
 				tar->sparse_numbytes = -1;
 			}
 		}
-		if (wcscmp(key, L"GNU.sparse.size") == 0) {
-			tar->realsize = tar_atol10(value, wcslen(value));
+		if (strcmp(key, "GNU.sparse.size") == 0) {
+			tar->realsize = tar_atol10(value, strlen(value));
 			archive_entry_set_size(entry, tar->realsize);
 		}
 
 		/* GNU "0.1" sparse pax format. */
-		if (wcscmp(key, L"GNU.sparse.map") == 0) {
+		if (strcmp(key, "GNU.sparse.map") == 0) {
 			tar->sparse_gnu_major = 0;
 			tar->sparse_gnu_minor = 1;
 			if (gnu_sparse_01_parse(tar, value) != ARCHIVE_OK)
@@ -1379,18 +1406,23 @@
 		}
 
 		/* GNU "1.0" sparse pax format */
-		if (wcscmp(key, L"GNU.sparse.major") == 0) {
-			tar->sparse_gnu_major = tar_atol10(value, wcslen(value));
+		if (strcmp(key, "GNU.sparse.major") == 0) {
+			tar->sparse_gnu_major = tar_atol10(value, strlen(value));
 			tar->sparse_gnu_pending = 1;
 		}
-		if (wcscmp(key, L"GNU.sparse.minor") == 0) {
-			tar->sparse_gnu_minor = tar_atol10(value, wcslen(value));
+		if (strcmp(key, "GNU.sparse.minor") == 0) {
+			tar->sparse_gnu_minor = tar_atol10(value, strlen(value));
 			tar->sparse_gnu_pending = 1;
 		}
-		if (wcscmp(key, L"GNU.sparse.name") == 0)
-			archive_entry_copy_pathname_w(entry, value);
-		if (wcscmp(key, L"GNU.sparse.realsize") == 0) {
-			tar->realsize = tar_atol10(value, wcslen(value));
+		if (strcmp(key, "GNU.sparse.name") == 0) {
+			wp = utf8_decode(tar, value, strlen(value));
+			if (wp != NULL)
+				archive_entry_copy_pathname_w(entry, wp);
+			else
+				archive_entry_copy_pathname(entry, value);
+		}
+		if (strcmp(key, "GNU.sparse.realsize") == 0) {
+			tar->realsize = tar_atol10(value, strlen(value));
 			archive_entry_set_size(entry, tar->realsize);
 		}
 		break;
@@ -1401,85 +1433,107 @@
 		if (strcmp(key, "LIBARCHIVE.xxxxxxx")==0)
 			archive_entry_set_xxxxxx(entry, value);
 */
-		if (wcsncmp(key, L"LIBARCHIVE.xattr.", 17)==0)
+		if (strncmp(key, "LIBARCHIVE.xattr.", 17)==0)
 			pax_attribute_xattr(entry, key, value);
 		break;
 	case 'S':
 		/* We support some keys used by the "star" archiver */
-		if (wcscmp(key, L"SCHILY.acl.access")==0)
-			__archive_entry_acl_parse_w(entry, value,
+		if (strcmp(key, "SCHILY.acl.access")==0) {
+			wp = utf8_decode(tar, value, strlen(value));
+			/* TODO: if (wp == NULL) */
+			__archive_entry_acl_parse_w(entry, wp,
 			    ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
-		else if (wcscmp(key, L"SCHILY.acl.default")==0)
-			__archive_entry_acl_parse_w(entry, value,
+		} else if (strcmp(key, "SCHILY.acl.default")==0) {
+			wp = utf8_decode(tar, value, strlen(value));
+			/* TODO: if (wp == NULL) */
+			__archive_entry_acl_parse_w(entry, wp,
 			    ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
-		else if (wcscmp(key, L"SCHILY.devmajor")==0)
-			archive_entry_set_rdevmajor(entry, tar_atol10(value, wcslen(value)));
-		else if (wcscmp(key, L"SCHILY.devminor")==0)
-			archive_entry_set_rdevminor(entry, tar_atol10(value, wcslen(value)));
-		else if (wcscmp(key, L"SCHILY.fflags")==0)
-			archive_entry_copy_fflags_text_w(entry, value);
-		else if (wcscmp(key, L"SCHILY.dev")==0)
-			archive_entry_set_dev(entry, tar_atol10(value, wcslen(value)));
-		else if (wcscmp(key, L"SCHILY.ino")==0)
-			archive_entry_set_ino(entry, tar_atol10(value, wcslen(value)));
-		else if (wcscmp(key, L"SCHILY.nlink")==0)
-			archive_entry_set_nlink(entry, tar_atol10(value, wcslen(value)));
-		else if (wcscmp(key, L"SCHILY.realsize")==0) {
-			tar->realsize = tar_atol10(value, wcslen(value));
+		} else if (strcmp(key, "SCHILY.devmajor")==0) {
+			archive_entry_set_rdevmajor(entry,
+			    tar_atol10(value, strlen(value)));
+		} else if (strcmp(key, "SCHILY.devminor")==0) {
+			archive_entry_set_rdevminor(entry,
+			    tar_atol10(value, strlen(value)));
+		} else if (strcmp(key, "SCHILY.fflags")==0) {
+			wp = utf8_decode(tar, value, strlen(value));
+			/* TODO: if (wp == NULL) */
+			archive_entry_copy_fflags_text_w(entry, wp);
+		} else if (strcmp(key, "SCHILY.dev")==0) {
+			archive_entry_set_dev(entry,
+			    tar_atol10(value, strlen(value)));
+		} else if (strcmp(key, "SCHILY.ino")==0) {
+			archive_entry_set_ino(entry,
+			    tar_atol10(value, strlen(value)));
+		} else if (strcmp(key, "SCHILY.nlink")==0) {
+			archive_entry_set_nlink(entry,
+			    tar_atol10(value, strlen(value)));
+		} else if (strcmp(key, "SCHILY.realsize")==0) {
+			tar->realsize = tar_atol10(value, strlen(value));
 			archive_entry_set_size(entry, tar->realsize);
 		}
 		break;
 	case 'a':
-		if (wcscmp(key, L"atime")==0) {
+		if (strcmp(key, "atime")==0) {
 			pax_time(value, &s, &n);
 			archive_entry_set_atime(entry, s, n);
 		}
 		break;
 	case 'c':
-		if (wcscmp(key, L"ctime")==0) {
+		if (strcmp(key, "ctime")==0) {
 			pax_time(value, &s, &n);

>>> TRUNCATED FOR MAIL (1000 lines) <<<


More information about the p4-projects mailing list