Date: Sat, 15 Mar 2008 19:02:03 GMT From: Kip Macy <kmacy@FreeBSD.org> To: Perforce Change Reviews <perforce@freebsd.org> Subject: PERFORCE change 137792 for review Message-ID: <200803151902.m2FJ23Jh062263@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=137792 Change 137792 by kmacy@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) <<<
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200803151902.m2FJ23Jh062263>