Import libarchive-3.1.2.
authorPeter Avalos <pavalos@dragonflybsd.org>
Sun, 17 Feb 2013 10:25:30 +0000 (02:25 -0800)
committerPeter Avalos <pavalos@dragonflybsd.org>
Sun, 17 Feb 2013 10:25:30 +0000 (02:25 -0800)
-Add basic archive read and write filter support for lrzip.
-Implement function used to seek within data blocks.
-Add support for lzop.
-Introduce uuencode filter.
-Introduce b64encode filter.
-Add support for grzip compression.
-Add support for writing v7 tar format.
-Implement functions to manually set the format and filters used.

115 files changed:
contrib/libarchive/NEWS
contrib/libarchive/README
contrib/libarchive/README.DELETED
contrib/libarchive/build/version
contrib/libarchive/cpio/bsdcpio.1
contrib/libarchive/cpio/cmdline.c
contrib/libarchive/cpio/cpio.c
contrib/libarchive/cpio/cpio.h
contrib/libarchive/libarchive/archive.h
contrib/libarchive/libarchive/archive_cmdline.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_cmdline_private.h [copied from contrib/libarchive/libarchive/filter_fork.h with 75% similarity]
contrib/libarchive/libarchive/archive_crypto.c
contrib/libarchive/libarchive/archive_entry.c
contrib/libarchive/libarchive/archive_entry.h
contrib/libarchive/libarchive/archive_entry_link_resolver.c
contrib/libarchive/libarchive/archive_match.c
contrib/libarchive/libarchive/archive_options.c
contrib/libarchive/libarchive/archive_ppmd7.c
contrib/libarchive/libarchive/archive_private.h
contrib/libarchive/libarchive/archive_rb.c
contrib/libarchive/libarchive/archive_read.c
contrib/libarchive/libarchive/archive_read_append_filter.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_read_data.3 [new file with mode: 0644]
contrib/libarchive/libarchive/archive_read_disk_entry_from_file.c
contrib/libarchive/libarchive/archive_read_disk_posix.c
contrib/libarchive/libarchive/archive_read_extract.3 [new file with mode: 0644]
contrib/libarchive/libarchive/archive_read_extract.c
contrib/libarchive/libarchive/archive_read_filter.3 [new file with mode: 0644]
contrib/libarchive/libarchive/archive_read_format.3 [new file with mode: 0644]
contrib/libarchive/libarchive/archive_read_free.3 [new file with mode: 0644]
contrib/libarchive/libarchive/archive_read_header.3 [new file with mode: 0644]
contrib/libarchive/libarchive/archive_read_new.3 [new file with mode: 0644]
contrib/libarchive/libarchive/archive_read_open.3 [new file with mode: 0644]
contrib/libarchive/libarchive/archive_read_open_fd.c
contrib/libarchive/libarchive/archive_read_open_file.c
contrib/libarchive/libarchive/archive_read_open_filename.c
contrib/libarchive/libarchive/archive_read_private.h
contrib/libarchive/libarchive/archive_read_set_format.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_read_support_filter_all.c
contrib/libarchive/libarchive/archive_read_support_filter_bzip2.c
contrib/libarchive/libarchive/archive_read_support_filter_compress.c
contrib/libarchive/libarchive/archive_read_support_filter_grzip.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_read_support_filter_gzip.c
contrib/libarchive/libarchive/archive_read_support_filter_lrzip.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_read_support_filter_lzop.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_read_support_filter_program.c
contrib/libarchive/libarchive/archive_read_support_filter_rpm.c
contrib/libarchive/libarchive/archive_read_support_filter_uu.c
contrib/libarchive/libarchive/archive_read_support_filter_xz.c
contrib/libarchive/libarchive/archive_read_support_format_7zip.c
contrib/libarchive/libarchive/archive_read_support_format_ar.c
contrib/libarchive/libarchive/archive_read_support_format_cab.c
contrib/libarchive/libarchive/archive_read_support_format_cpio.c
contrib/libarchive/libarchive/archive_read_support_format_empty.c
contrib/libarchive/libarchive/archive_read_support_format_iso9660.c
contrib/libarchive/libarchive/archive_read_support_format_lha.c
contrib/libarchive/libarchive/archive_read_support_format_mtree.c
contrib/libarchive/libarchive/archive_read_support_format_rar.c
contrib/libarchive/libarchive/archive_read_support_format_raw.c
contrib/libarchive/libarchive/archive_read_support_format_tar.c
contrib/libarchive/libarchive/archive_read_support_format_xar.c
contrib/libarchive/libarchive/archive_read_support_format_zip.c
contrib/libarchive/libarchive/archive_string.c
contrib/libarchive/libarchive/archive_util.c
contrib/libarchive/libarchive/archive_virtual.c
contrib/libarchive/libarchive/archive_write.c
contrib/libarchive/libarchive/archive_write_add_filter.c
contrib/libarchive/libarchive/archive_write_add_filter_b64encode.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_write_add_filter_by_name.c [copied from contrib/libarchive/libarchive/archive_write_add_filter.c with 59% similarity]
contrib/libarchive/libarchive/archive_write_add_filter_bzip2.c
contrib/libarchive/libarchive/archive_write_add_filter_compress.c
contrib/libarchive/libarchive/archive_write_add_filter_grzip.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_write_add_filter_gzip.c
contrib/libarchive/libarchive/archive_write_add_filter_lrzip.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_write_add_filter_lzop.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_write_add_filter_program.c
contrib/libarchive/libarchive/archive_write_add_filter_uuencode.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_write_add_filter_xz.c
contrib/libarchive/libarchive/archive_write_blocksize.3 [new file with mode: 0644]
contrib/libarchive/libarchive/archive_write_data.3 [new file with mode: 0644]
contrib/libarchive/libarchive/archive_write_disk_acl.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_write_disk_posix.c
contrib/libarchive/libarchive/archive_write_disk_private.h
contrib/libarchive/libarchive/archive_write_filter.3 [new file with mode: 0644]
contrib/libarchive/libarchive/archive_write_finish_entry.3 [new file with mode: 0644]
contrib/libarchive/libarchive/archive_write_format.3 [new file with mode: 0644]
contrib/libarchive/libarchive/archive_write_free.3 [new file with mode: 0644]
contrib/libarchive/libarchive/archive_write_header.3 [new file with mode: 0644]
contrib/libarchive/libarchive/archive_write_new.3 [new file with mode: 0644]
contrib/libarchive/libarchive/archive_write_open.3 [new file with mode: 0644]
contrib/libarchive/libarchive/archive_write_open_filename.c
contrib/libarchive/libarchive/archive_write_private.h
contrib/libarchive/libarchive/archive_write_set_format_7zip.c
contrib/libarchive/libarchive/archive_write_set_format_ar.c
contrib/libarchive/libarchive/archive_write_set_format_by_name.c
contrib/libarchive/libarchive/archive_write_set_format_iso9660.c
contrib/libarchive/libarchive/archive_write_set_format_mtree.c
contrib/libarchive/libarchive/archive_write_set_format_pax.c
contrib/libarchive/libarchive/archive_write_set_format_v7tar.c [new file with mode: 0644]
contrib/libarchive/libarchive/archive_write_set_format_xar.c
contrib/libarchive/libarchive/archive_write_set_format_zip.c
contrib/libarchive/libarchive/archive_write_set_options.c
contrib/libarchive/libarchive/filter_fork.h
contrib/libarchive/libarchive/filter_fork_posix.c [moved from contrib/libarchive/libarchive/filter_fork.c with 62% similarity]
contrib/libarchive/libarchive/libarchive-formats.5
contrib/libarchive/libarchive/libarchive_changes.3 [new file with mode: 0644]
contrib/libarchive/tar/bsdtar.1
contrib/libarchive/tar/bsdtar.c
contrib/libarchive/tar/bsdtar.h
contrib/libarchive/tar/cmdline.c
contrib/libarchive/tar/creation_set.c [new file with mode: 0644]
contrib/libarchive/tar/read.c
contrib/libarchive/tar/subst.c
contrib/libarchive/tar/util.c
contrib/libarchive/tar/write.c

index 5c28068..107d4da 100644 (file)
@@ -1,3 +1,30 @@
+Feb 09, 2013: libarchive 3.1.2 released
+
+Jan 28, 2013: libarchive's new website moved to http://www.libarchive.org.
+
+Jan 13, 2013: libarchive 3.1.1 released
+
+Jan 13, 2013: libarchive 3.1.0 released
+
+Dec 07, 2012: Implement functions to manually set the format and filters used.
+    
+Nov 11, 2012: Add support for __MACOSX directory in Zip archives, which resource
+    forks are stored in.
+
+Oct 20, 2012: Add support for writing v7 tar format.
+
+Oct 09, 2012: Add support for grzip compression.
+
+Oct 07, 2012: Introduce b64encode filter.    
+Oct 07, 2012: Introduce uuencode filter.
+
+Oct 06, 2012: Add support for lzop.
+    
+Sep 27, 2012: Implement function used to seek within data blocks.
+    (Currently only supported for uncompressed RAR archives).
+    
+Apr 22, 2012: Add basic archive read and write filter support for lrzip.
+
 Mar 27, 2012: libarchive 3.0.4 released
 
 Feb 05, 2012: libarchive development now hosted at GitHub.
index 4ffc3b7..1c974fd 100644 (file)
@@ -1,7 +1,7 @@
 README for libarchive bundle.
 
 Questions?  Issues?
-   * http://libarchive.github.com/ is the home for ongoing
+   * http://www.libarchive.org is the home for ongoing
      libarchive development, including documentation, and
      links to the libarchive mailing lists.
    * To report an issue, use the issue tracker at
index d5076a2..6c5b48e 100644 (file)
@@ -35,3 +35,4 @@ tar/bsdtar_windows.c
 tar/bsdtar_windows.h
 tar/config_freebsd.h
 tar/test/
+test_utils/
index 5611b20..b3d0d40 100644 (file)
@@ -24,7 +24,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd December 24, 2011
+.Dd October 7, 2012
 .Dt CPIO 1
 .Os
 .Sh NAME
@@ -176,11 +176,21 @@ With this option, the target of the link will be archived or copied instead.
 (p mode only)
 Create links from the target directory to the original files,
 instead of copying.
+.It Fl Fl lrzip
+(o mode only)
+Compress the resulting archive with
+.Xr lrzip 1 .
+In input mode, this option is ignored.
 .It Fl Fl lzma
 (o mode only)
 Compress the file with lzma-compatible compression before writing it.
 In input mode, this option is ignored; lzma compression is recognized
 automatically on input.
+.It Fl Fl lzop
+(o mode only)
+Compress the resulting archive with
+.Xr lzop 1 .
+In input mode, this option is ignored.
 .It Fl m , Fl Fl preserve-modification-time
 (i and p modes)
 Set file modification time on created files to match
index 438c27c..0121fd1 100644 (file)
@@ -61,16 +61,20 @@ static const struct option {
        int required;   /* 1 if this option requires an argument */
        int equivalent; /* Equivalent short option. */
 } cpio_longopts[] = {
+       { "b64encode",                  0, OPTION_B64ENCODE },
        { "create",                     0, 'o' },
        { "dot",                        0, 'V' },
        { "extract",                    0, 'i' },
        { "file",                       1, 'F' },
        { "format",                     1, 'H' },
+       { "grzip",                      0, OPTION_GRZIP },
        { "help",                       0, 'h' },
        { "insecure",                   0, OPTION_INSECURE },
        { "link",                       0, 'l' },
        { "list",                       0, 't' },
+       { "lrzip",                      0, OPTION_LRZIP },
        { "lzma",                       0, OPTION_LZMA },
+       { "lzop",                       0, OPTION_LZOP },
        { "make-directories",           0, 'd' },
        { "no-preserve-owner",          0, OPTION_NO_PRESERVE_OWNER },
        { "null",                       0, '0' },
@@ -81,6 +85,7 @@ static const struct option {
        { "preserve-owner",             0, OPTION_PRESERVE_OWNER },
        { "quiet",                      0, OPTION_QUIET },
        { "unconditional",              0, 'u' },
+       { "uuencode",                   0, OPTION_UUENCODE },
        { "verbose",                    0, 'v' },
        { "version",                    0, OPTION_VERSION },
        { "xz",                         0, 'J' },
index 7095b62..6f57d95 100644 (file)
@@ -207,6 +207,9 @@ main(int argc, char *argv[])
                case 'B': /* POSIX 1997 */
                        cpio->bytes_per_block = 5120;
                        break;
+               case OPTION_B64ENCODE:
+                       cpio->add_filter = opt;
+                       break;
                case 'C': /* NetBSD/OpenBSD */
                        cpio->bytes_per_block = atoi(cpio->argument);
                        if (cpio->bytes_per_block <= 0)
@@ -234,6 +237,9 @@ main(int argc, char *argv[])
                                lafe_errc(1, 0, "Error : %s",
                                    archive_error_string(cpio->matching));
                        break;
+               case OPTION_GRZIP:
+                       cpio->compress = opt;
+                       break;
                case 'H': /* GNU cpio (also --format) */
                        cpio->format = cpio->argument;
                        break;
@@ -265,7 +271,9 @@ main(int argc, char *argv[])
                case 'l': /* POSIX 1997 */
                        cpio->option_link = 1;
                        break;
+               case OPTION_LRZIP:
                case OPTION_LZMA: /* GNU tar, others */
+               case OPTION_LZOP: /* GNU tar, others */
                        cpio->compress = opt;
                        break;
                case 'm': /* POSIX 1997 */
@@ -326,6 +334,9 @@ main(int argc, char *argv[])
                        cpio->extract_flags
                            &= ~ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER;
                        break;
+               case OPTION_UUENCODE:
+                       cpio->add_filter = opt;
+                       break;
                case 'v': /* POSIX 1997 */
                        cpio->verbose++;
                        break;
@@ -417,6 +428,7 @@ main(int argc, char *argv[])
        archive_match_free(cpio->matching);
        free_cache(cpio->gname_cache);
        free_cache(cpio->uname_cache);
+       free(cpio->destdir);
        return (cpio->return_value);
 }
 
@@ -516,27 +528,49 @@ mode_out(struct cpio *cpio)
        if (cpio->archive == NULL)
                lafe_errc(1, 0, "Failed to allocate archive object");
        switch (cpio->compress) {
+       case OPTION_GRZIP:
+               r = archive_write_add_filter_grzip(cpio->archive);
+               break;
        case 'J':
-               r = archive_write_set_compression_xz(cpio->archive);
+               r = archive_write_add_filter_xz(cpio->archive);
+               break;
+       case OPTION_LRZIP:
+               r = archive_write_add_filter_lrzip(cpio->archive);
                break;
        case OPTION_LZMA:
-               r = archive_write_set_compression_lzma(cpio->archive);
+               r = archive_write_add_filter_lzma(cpio->archive);
+               break;
+       case OPTION_LZOP:
+               r = archive_write_add_filter_lzop(cpio->archive);
                break;
        case 'j': case 'y':
-               r = archive_write_set_compression_bzip2(cpio->archive);
+               r = archive_write_add_filter_bzip2(cpio->archive);
                break;
        case 'z':
-               r = archive_write_set_compression_gzip(cpio->archive);
+               r = archive_write_add_filter_gzip(cpio->archive);
                break;
        case 'Z':
-               r = archive_write_set_compression_compress(cpio->archive);
+               r = archive_write_add_filter_compress(cpio->archive);
                break;
        default:
-               r = archive_write_set_compression_none(cpio->archive);
+               r = archive_write_add_filter_none(cpio->archive);
                break;
        }
        if (r < ARCHIVE_WARN)
                lafe_errc(1, 0, "Requested compression not available");
+       switch (cpio->add_filter) {
+       case 0:
+               r = ARCHIVE_OK;
+               break;
+       case OPTION_B64ENCODE:
+               r = archive_write_add_filter_b64encode(cpio->archive);
+               break;
+       case OPTION_UUENCODE:
+               r = archive_write_add_filter_uuencode(cpio->archive);
+               break;
+       }
+       if (r < ARCHIVE_WARN)
+               lafe_errc(1, 0, "Requested filter not available");
        r = archive_write_set_format_by_name(cpio->archive, cpio->format);
        if (r != ARCHIVE_OK)
                lafe_errc(1, 0, "%s", archive_error_string(cpio->archive));
@@ -548,7 +582,7 @@ mode_out(struct cpio *cpio)
        /*
         * The main loop:  Copy each file into the output archive.
         */
-       r = archive_write_open_file(cpio->archive, cpio->filename);
+       r = archive_write_open_filename(cpio->archive, cpio->filename);
        if (r != ARCHIVE_OK)
                lafe_errc(1, 0, "%s", archive_error_string(cpio->archive));
        lr = lafe_line_reader("-", cpio->option_null);
@@ -577,7 +611,7 @@ mode_out(struct cpio *cpio)
 
        if (!cpio->quiet) {
                int64_t blocks =
-                       (archive_position_uncompressed(cpio->archive) + 511)
+                       (archive_filter_bytes(cpio->archive, 0) + 511)
                        / 512;
                fprintf(stderr, "%lu %s\n", (unsigned long)blocks,
                    blocks == 1 ? "block" : "blocks");
@@ -806,18 +840,21 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry)
                exit(1);
 
        if (r >= ARCHIVE_WARN && archive_entry_size(entry) > 0 && fd >= 0) {
-               bytes_read = read(fd, cpio->buff, cpio->buff_size);
+               bytes_read = read(fd, cpio->buff, (unsigned)cpio->buff_size);
                while (bytes_read > 0) {
-                       r = archive_write_data(cpio->archive,
+                       ssize_t bytes_write;
+                       bytes_write = archive_write_data(cpio->archive,
                            cpio->buff, bytes_read);
-                       if (r < 0)
+                       if (bytes_write < 0)
                                lafe_errc(1, archive_errno(cpio->archive),
                                    "%s", archive_error_string(cpio->archive));
-                       if (r < bytes_read) {
+                       if (bytes_write < bytes_read) {
                                lafe_warnc(0,
-                                   "Truncated write; file may have grown while being archived.");
+                                   "Truncated write; file may have "
+                                   "grown while being archived.");
                        }
-                       bytes_read = read(fd, cpio->buff, cpio->buff_size);
+                       bytes_read = read(fd, cpio->buff,
+                           (unsigned)cpio->buff_size);
                }
        }
 
@@ -908,7 +945,8 @@ mode_in(struct cpio *cpio)
        archive_read_support_filter_all(a);
        archive_read_support_format_all(a);
 
-       if (archive_read_open_file(a, cpio->filename, cpio->bytes_per_block))
+       if (archive_read_open_filename(a, cpio->filename,
+                                       cpio->bytes_per_block))
                lafe_errc(1, archive_errno(a),
                    "%s", archive_error_string(a));
        for (;;) {
@@ -957,7 +995,7 @@ mode_in(struct cpio *cpio)
        if (r != ARCHIVE_OK)
                lafe_errc(1, 0, "%s", archive_error_string(ext));
        if (!cpio->quiet) {
-               int64_t blocks = (archive_position_uncompressed(a) + 511)
+               int64_t blocks = (archive_filter_bytes(a, 0) + 511)
                              / 512;
                fprintf(stderr, "%lu %s\n", (unsigned long)blocks,
                    blocks == 1 ? "block" : "blocks");
@@ -988,7 +1026,7 @@ extract_data(struct archive *ar, struct archive *aw)
                            "%s", archive_error_string(ar));
                        exit(1);
                }
-               r = archive_write_data_block(aw, block, size, offset);
+               r = (int)archive_write_data_block(aw, block, size, offset);
                if (r != ARCHIVE_OK) {
                        lafe_warnc(archive_errno(aw),
                            "%s", archive_error_string(aw));
@@ -1010,7 +1048,8 @@ mode_list(struct cpio *cpio)
        archive_read_support_filter_all(a);
        archive_read_support_format_all(a);
 
-       if (archive_read_open_file(a, cpio->filename, cpio->bytes_per_block))
+       if (archive_read_open_filename(a, cpio->filename,
+                                       cpio->bytes_per_block))
                lafe_errc(1, archive_errno(a),
                    "%s", archive_error_string(a));
        for (;;) {
@@ -1032,7 +1071,7 @@ mode_list(struct cpio *cpio)
        if (r != ARCHIVE_OK)
                lafe_errc(1, 0, "%s", archive_error_string(a));
        if (!cpio->quiet) {
-               int64_t blocks = (archive_position_uncompressed(a) + 511)
+               int64_t blocks = (archive_filter_bytes(a, 0) + 511)
                              / 512;
                fprintf(stderr, "%lu %s\n", (unsigned long)blocks,
                    blocks == 1 ? "block" : "blocks");
@@ -1167,7 +1206,7 @@ mode_pass(struct cpio *cpio, const char *destdir)
 
        if (!cpio->quiet) {
                int64_t blocks =
-                       (archive_position_uncompressed(cpio->archive) + 511)
+                       (archive_filter_bytes(cpio->archive, 0) + 511)
                        / 512;
                fprintf(stderr, "%lu %s\n", (unsigned long)blocks,
                    blocks == 1 ? "block" : "blocks");
index 7e276bd..3e951ce 100644 (file)
@@ -44,6 +44,7 @@ struct cpio {
        const char       *argument;
 
        /* Options */
+       int               add_filter; /* --uuencode */
        const char       *filename;
        int               mode; /* -i -o -p */
        int               compress; /* -j, -y, or -z */
@@ -96,11 +97,16 @@ const char *owner_parse(const char *, int *, int *);
 
 /* Fake short equivalents for long options that otherwise lack them. */
 enum {
-       OPTION_INSECURE = 1,
+       OPTION_B64ENCODE = 1,
+       OPTION_GRZIP,
+       OPTION_INSECURE,
+       OPTION_LRZIP,
        OPTION_LZMA,
+       OPTION_LZOP,
        OPTION_NO_PRESERVE_OWNER,
        OPTION_PRESERVE_OWNER,
        OPTION_QUIET,
+       OPTION_UUENCODE,
        OPTION_VERSION
 };
 
index d5316ca..f56bc38 100644 (file)
 #define        __LA_PRINTF(fmtarg, firstvararg)        /* nothing */
 #endif
 
+#if defined(__GNUC__) && __GNUC__ >= 3 && __GNUC_MINOR__ >= 1
+# define __LA_DEPRECATED __attribute__((deprecated))
+#else
+# define __LA_DEPRECATED
+#endif
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -118,13 +124,13 @@ extern "C" {
  * assert that ARCHIVE_VERSION_NUMBER >= 2012108.
  */
 /* Note: Compiler will complain if this does not match archive_entry.h! */
-#define        ARCHIVE_VERSION_NUMBER 3000004
+#define        ARCHIVE_VERSION_NUMBER 3001002
 __LA_DECL int          archive_version_number(void);
 
 /*
  * Textual name/version of the library, useful for version displays.
  */
-#define        ARCHIVE_VERSION_STRING "libarchive 3.0.4"
+#define        ARCHIVE_VERSION_STRING "libarchive 3.1.2"
 __LA_DECL const char * archive_version_string(void);
 
 /* Declare our basic types. */
@@ -194,6 +200,13 @@ typedef int        archive_open_callback(struct archive *, void *_client_data);
 
 typedef int    archive_close_callback(struct archive *, void *_client_data);
 
+/* Switches from one client data object to the next/prev client data object.
+ * This is useful for reading from different data blocks such as a set of files
+ * that make up one large file.
+ */
+typedef int archive_switch_callback(struct archive *, void *_client_data1,
+                           void *_client_data2);
+
 /*
  * Codes to identify various stream filters.
  */
@@ -207,6 +220,9 @@ typedef int archive_close_callback(struct archive *, void *_client_data);
 #define        ARCHIVE_FILTER_UU       7
 #define        ARCHIVE_FILTER_RPM      8
 #define        ARCHIVE_FILTER_LZIP     9
+#define        ARCHIVE_FILTER_LRZIP    10
+#define        ARCHIVE_FILTER_LZOP     11
+#define        ARCHIVE_FILTER_GRZIP    12
 
 #if ARCHIVE_VERSION_NUMBER < 4000000
 #define        ARCHIVE_COMPRESSION_NONE        ARCHIVE_FILTER_NONE
@@ -219,6 +235,7 @@ typedef int archive_close_callback(struct archive *, void *_client_data);
 #define        ARCHIVE_COMPRESSION_UU          ARCHIVE_FILTER_UU
 #define        ARCHIVE_COMPRESSION_RPM         ARCHIVE_FILTER_RPM
 #define        ARCHIVE_COMPRESSION_LZIP        ARCHIVE_FILTER_LZIP
+#define        ARCHIVE_COMPRESSION_LRZIP       ARCHIVE_FILTER_LRZIP
 #endif
 
 /*
@@ -291,37 +308,49 @@ __LA_DECL struct archive  *archive_read_new(void);
  */
 
 #if ARCHIVE_VERSION_NUMBER < 4000000
-__LA_DECL int archive_read_support_compression_all(struct archive *);
-__LA_DECL int archive_read_support_compression_bzip2(struct archive *);
-__LA_DECL int archive_read_support_compression_compress(struct archive *);
-__LA_DECL int archive_read_support_compression_gzip(struct archive *);
-__LA_DECL int archive_read_support_compression_lzip(struct archive *);
-__LA_DECL int archive_read_support_compression_lzma(struct archive *);
-__LA_DECL int archive_read_support_compression_none(struct archive *);
+__LA_DECL int archive_read_support_compression_all(struct archive *)
+               __LA_DEPRECATED;
+__LA_DECL int archive_read_support_compression_bzip2(struct archive *)
+               __LA_DEPRECATED;
+__LA_DECL int archive_read_support_compression_compress(struct archive *)
+               __LA_DEPRECATED;
+__LA_DECL int archive_read_support_compression_gzip(struct archive *)
+               __LA_DEPRECATED;
+__LA_DECL int archive_read_support_compression_lzip(struct archive *)
+               __LA_DEPRECATED;
+__LA_DECL int archive_read_support_compression_lzma(struct archive *)
+               __LA_DEPRECATED;
+__LA_DECL int archive_read_support_compression_none(struct archive *)
+               __LA_DEPRECATED;
 __LA_DECL int archive_read_support_compression_program(struct archive *,
-                    const char *command);
+                    const char *command) __LA_DEPRECATED;
 __LA_DECL int archive_read_support_compression_program_signature
                (struct archive *, const char *,
-                                   const void * /* match */, size_t);
-
-__LA_DECL int archive_read_support_compression_rpm(struct archive *);
-__LA_DECL int archive_read_support_compression_uu(struct archive *);
-__LA_DECL int archive_read_support_compression_xz(struct archive *);
+                const void * /* match */, size_t) __LA_DEPRECATED;
+
+__LA_DECL int archive_read_support_compression_rpm(struct archive *)
+               __LA_DEPRECATED;
+__LA_DECL int archive_read_support_compression_uu(struct archive *)
+               __LA_DEPRECATED;
+__LA_DECL int archive_read_support_compression_xz(struct archive *)
+               __LA_DEPRECATED;
 #endif
 
 __LA_DECL int archive_read_support_filter_all(struct archive *);
 __LA_DECL int archive_read_support_filter_bzip2(struct archive *);
 __LA_DECL int archive_read_support_filter_compress(struct archive *);
 __LA_DECL int archive_read_support_filter_gzip(struct archive *);
+__LA_DECL int archive_read_support_filter_grzip(struct archive *);
+__LA_DECL int archive_read_support_filter_lrzip(struct archive *);
 __LA_DECL int archive_read_support_filter_lzip(struct archive *);
 __LA_DECL int archive_read_support_filter_lzma(struct archive *);
+__LA_DECL int archive_read_support_filter_lzop(struct archive *);
 __LA_DECL int archive_read_support_filter_none(struct archive *);
 __LA_DECL int archive_read_support_filter_program(struct archive *,
                     const char *command);
 __LA_DECL int archive_read_support_filter_program_signature
-               (struct archive *, const char *,
+               (struct archive *, const char * /* cmd */,
                                    const void * /* match */, size_t);
-
 __LA_DECL int archive_read_support_filter_rpm(struct archive *);
 __LA_DECL int archive_read_support_filter_uu(struct archive *);
 __LA_DECL int archive_read_support_filter_xz(struct archive *);
@@ -343,6 +372,17 @@ __LA_DECL int archive_read_support_format_tar(struct archive *);
 __LA_DECL int archive_read_support_format_xar(struct archive *);
 __LA_DECL int archive_read_support_format_zip(struct archive *);
 
+/* Functions to manually set the format and filters to be used. This is
+ * useful to bypass the bidding process when the format and filters to use
+ * is known in advance.
+ */
+__LA_DECL int archive_read_set_format(struct archive *, int);
+__LA_DECL int archive_read_append_filter(struct archive *, int);
+__LA_DECL int archive_read_append_filter_program(struct archive *,
+    const char *);
+__LA_DECL int archive_read_append_filter_program_signature
+    (struct archive *, const char *, const void * /* match */, size_t);
+
 /* Set various callbacks. */
 __LA_DECL int archive_read_set_open_callback(struct archive *,
     archive_open_callback *);
@@ -354,8 +394,23 @@ __LA_DECL int archive_read_set_skip_callback(struct archive *,
     archive_skip_callback *);
 __LA_DECL int archive_read_set_close_callback(struct archive *,
     archive_close_callback *);
-/* The callback data is provided to all of the callbacks above. */
+/* Callback used to switch between one data object to the next */
+__LA_DECL int archive_read_set_switch_callback(struct archive *,
+    archive_switch_callback *);
+
+/* This sets the first data object. */
 __LA_DECL int archive_read_set_callback_data(struct archive *, void *);
+/* This sets data object at specified index */
+__LA_DECL int archive_read_set_callback_data2(struct archive *, void *,
+    unsigned int);
+/* This adds a data object at the specified index. */
+__LA_DECL int archive_read_add_callback_data(struct archive *, void *,
+    unsigned int);
+/* This appends a data object to the end of list */
+__LA_DECL int archive_read_append_callback_data(struct archive *, void *);
+/* This prepends a data object to the beginning of list */
+__LA_DECL int archive_read_prepend_callback_data(struct archive *, void *);
+
 /* Opening freezes the callbacks. */
 __LA_DECL int archive_read_open1(struct archive *);
 
@@ -375,11 +430,15 @@ __LA_DECL int archive_read_open2(struct archive *, void *_client_data,
 /* Use this if you know the filename.  Note: NULL indicates stdin. */
 __LA_DECL int archive_read_open_filename(struct archive *,
                     const char *_filename, size_t _block_size);
+/* Use this for reading multivolume files by filenames.
+ * NOTE: Must be NULL terminated. Sorting is NOT done. */
+__LA_DECL int archive_read_open_filenames(struct archive *,
+                    const char **_filenames, size_t _block_size);
 __LA_DECL int archive_read_open_filename_w(struct archive *,
                     const wchar_t *_filename, size_t _block_size);
 /* archive_read_open_file() is a deprecated synonym for ..._open_filename(). */
 __LA_DECL int archive_read_open_file(struct archive *,
-                    const char *_filename, size_t _block_size);
+                    const char *_filename, size_t _block_size) __LA_DEPRECATED;
 /* Read an archive that's stored in memory. */
 __LA_DECL int archive_read_open_memory(struct archive *,
                     void * buff, size_t size);
@@ -411,6 +470,9 @@ __LA_DECL __LA_INT64_T               archive_read_header_position(struct archive *);
 __LA_DECL __LA_SSIZE_T          archive_read_data(struct archive *,
                                    void *, size_t);
 
+/* Seek within the body of an entry.  Similar to lseek(2). */
+__LA_DECL __LA_INT64_T archive_seek_data(struct archive *, __LA_INT64_T, int);
+
 /*
  * A zero-copy version of archive_read_data that also exposes the file offset
  * of each returned block.  Note that the client has no way to specify
@@ -494,6 +556,12 @@ __LA_DECL int archive_read_set_options(struct archive *_a,
 /* Default: Do not restore Mac extended metadata. */
 /* This has no effect except on Mac OS. */
 #define        ARCHIVE_EXTRACT_MAC_METADATA            (0x2000)
+/* Default: Use HFS+ compression if it was compressed. */
+/* This has no effect except on Mac OS v10.6 or later. */
+#define        ARCHIVE_EXTRACT_NO_HFS_COMPRESSION      (0x4000)
+/* Default: Do not use HFS+ compression if it was not compressed. */
+/* This has no effect except on Mac OS v10.6 or later. */
+#define        ARCHIVE_EXTRACT_HFS_COMPRESSION_FORCED  (0x8000)
 
 __LA_DECL int archive_read_extract(struct archive *, struct archive_entry *,
                     int flags);
@@ -514,7 +582,7 @@ __LA_DECL int                archive_read_close(struct archive *);
 __LA_DECL int           archive_read_free(struct archive *);
 #if ARCHIVE_VERSION_NUMBER < 4000000
 /* Synonym for archive_read_free() for backwards compatibility. */
-__LA_DECL int           archive_read_finish(struct archive *);
+__LA_DECL int           archive_read_finish(struct archive *) __LA_DEPRECATED;
 #endif
 
 /*-
@@ -547,27 +615,41 @@ __LA_DECL int archive_write_set_skip_file(struct archive *,
     __LA_INT64_T, __LA_INT64_T);
 
 #if ARCHIVE_VERSION_NUMBER < 4000000
-__LA_DECL int archive_write_set_compression_bzip2(struct archive *);
-__LA_DECL int archive_write_set_compression_compress(struct archive *);
-__LA_DECL int archive_write_set_compression_gzip(struct archive *);
-__LA_DECL int archive_write_set_compression_lzip(struct archive *);
-__LA_DECL int archive_write_set_compression_lzma(struct archive *);
-__LA_DECL int archive_write_set_compression_none(struct archive *);
+__LA_DECL int archive_write_set_compression_bzip2(struct archive *)
+               __LA_DEPRECATED;
+__LA_DECL int archive_write_set_compression_compress(struct archive *)
+               __LA_DEPRECATED;
+__LA_DECL int archive_write_set_compression_gzip(struct archive *)
+               __LA_DEPRECATED;
+__LA_DECL int archive_write_set_compression_lzip(struct archive *)
+               __LA_DEPRECATED;
+__LA_DECL int archive_write_set_compression_lzma(struct archive *)
+               __LA_DEPRECATED;
+__LA_DECL int archive_write_set_compression_none(struct archive *)
+               __LA_DEPRECATED;
 __LA_DECL int archive_write_set_compression_program(struct archive *,
-                    const char *cmd);
-__LA_DECL int archive_write_set_compression_xz(struct archive *);
+                    const char *cmd) __LA_DEPRECATED;
+__LA_DECL int archive_write_set_compression_xz(struct archive *)
+               __LA_DEPRECATED;
 #endif
 
 /* A convenience function to set the filter based on the code. */
 __LA_DECL int archive_write_add_filter(struct archive *, int filter_code);
+__LA_DECL int archive_write_add_filter_by_name(struct archive *,
+                    const char *name);
+__LA_DECL int archive_write_add_filter_b64encode(struct archive *);
 __LA_DECL int archive_write_add_filter_bzip2(struct archive *);
 __LA_DECL int archive_write_add_filter_compress(struct archive *);
+__LA_DECL int archive_write_add_filter_grzip(struct archive *);
 __LA_DECL int archive_write_add_filter_gzip(struct archive *);
+__LA_DECL int archive_write_add_filter_lrzip(struct archive *);
 __LA_DECL int archive_write_add_filter_lzip(struct archive *);
 __LA_DECL int archive_write_add_filter_lzma(struct archive *);
+__LA_DECL int archive_write_add_filter_lzop(struct archive *);
 __LA_DECL int archive_write_add_filter_none(struct archive *);
 __LA_DECL int archive_write_add_filter_program(struct archive *,
                     const char *cmd);
+__LA_DECL int archive_write_add_filter_uuencode(struct archive *);
 __LA_DECL int archive_write_add_filter_xz(struct archive *);
 
 
@@ -584,14 +666,18 @@ __LA_DECL int archive_write_set_format_cpio_newc(struct archive *);
 __LA_DECL int archive_write_set_format_gnutar(struct archive *);
 __LA_DECL int archive_write_set_format_iso9660(struct archive *);
 __LA_DECL int archive_write_set_format_mtree(struct archive *);
+__LA_DECL int archive_write_set_format_mtree_classic(struct archive *);
 /* TODO: int archive_write_set_format_old_tar(struct archive *); */
 __LA_DECL int archive_write_set_format_pax(struct archive *);
 __LA_DECL int archive_write_set_format_pax_restricted(struct archive *);
 __LA_DECL int archive_write_set_format_shar(struct archive *);
 __LA_DECL int archive_write_set_format_shar_dump(struct archive *);
 __LA_DECL int archive_write_set_format_ustar(struct archive *);
+__LA_DECL int archive_write_set_format_v7tar(struct archive *);
 __LA_DECL int archive_write_set_format_xar(struct archive *);
 __LA_DECL int archive_write_set_format_zip(struct archive *);
+__LA_DECL int archive_write_zip_set_compression_deflate(struct archive *);
+__LA_DECL int archive_write_zip_set_compression_store(struct archive *);
 __LA_DECL int archive_write_open(struct archive *, void *,
                     archive_open_callback *, archive_write_callback *,
                     archive_close_callback *);
@@ -600,7 +686,8 @@ __LA_DECL int archive_write_open_filename(struct archive *, const char *_file);
 __LA_DECL int archive_write_open_filename_w(struct archive *,
                     const wchar_t *_file);
 /* A deprecated synonym for archive_write_open_filename() */
-__LA_DECL int archive_write_open_file(struct archive *, const char *_file);
+__LA_DECL int archive_write_open_file(struct archive *, const char *_file)
+               __LA_DEPRECATED;
 __LA_DECL int archive_write_open_FILE(struct archive *, FILE *);
 /* _buffSize is the size of the buffer, _used refers to a variable that
  * will be updated after each write into the buffer. */
@@ -622,12 +709,16 @@ __LA_DECL __LA_SSIZE_T     archive_write_data_block(struct archive *,
 
 __LA_DECL int           archive_write_finish_entry(struct archive *);
 __LA_DECL int           archive_write_close(struct archive *);
+/* Marks the archive as FATAL so that a subsequent free() operation
+ * won't try to close() cleanly.  Provides a fast abort capability
+ * when the client discovers that things have gone wrong. */
+__LA_DECL int            archive_write_fail(struct archive *);
 /* This can fail if the archive wasn't already closed, in which case
  * archive_write_free() will implicitly call archive_write_close(). */
 __LA_DECL int           archive_write_free(struct archive *);
 #if ARCHIVE_VERSION_NUMBER < 4000000
 /* Synonym for archive_write_free() for backwards compatibility. */
-__LA_DECL int           archive_write_finish(struct archive *);
+__LA_DECL int           archive_write_finish(struct archive *) __LA_DEPRECATED;
 #endif
 
 /*
@@ -806,13 +897,17 @@ __LA_DECL const char *     archive_filter_name(struct archive *, int);
 /* These don't properly handle multiple filters, so are deprecated and
  * will eventually be removed. */
 /* As of libarchive 3.0, this is an alias for archive_filter_bytes(a, -1); */
-__LA_DECL __LA_INT64_T  archive_position_compressed(struct archive *);
+__LA_DECL __LA_INT64_T  archive_position_compressed(struct archive *)
+                               __LA_DEPRECATED;
 /* As of libarchive 3.0, this is an alias for archive_filter_bytes(a, 0); */
-__LA_DECL __LA_INT64_T  archive_position_uncompressed(struct archive *);
+__LA_DECL __LA_INT64_T  archive_position_uncompressed(struct archive *)
+                               __LA_DEPRECATED;
 /* As of libarchive 3.0, this is an alias for archive_filter_name(a, 0); */
-__LA_DECL const char   *archive_compression_name(struct archive *);
+__LA_DECL const char   *archive_compression_name(struct archive *)
+                               __LA_DEPRECATED;
 /* As of libarchive 3.0, this is an alias for archive_filter_code(a, 0); */
-__LA_DECL int           archive_compression(struct archive *);
+__LA_DECL int           archive_compression(struct archive *)
+                               __LA_DEPRECATED;
 #endif
 
 __LA_DECL int           archive_errno(struct archive *);
diff --git a/contrib/libarchive/libarchive/archive_cmdline.c b/contrib/libarchive/libarchive/archive_cmdline.c
new file mode 100644 (file)
index 0000000..7d3bac5
--- /dev/null
@@ -0,0 +1,227 @@
+/*-
+ * Copyright (c) 2012 Michihiro NAKAJIMA 
+ * 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 "archive_platform.h"
+
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_STRING_H
+#  include <string.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#  include <stdlib.h>
+#endif
+
+#include "archive.h"
+#include "archive_cmdline_private.h"
+#include "archive_string.h"
+
+static int cmdline_set_path(struct archive_cmdline *, const char *);
+static int cmdline_add_arg(struct archive_cmdline *, const char *);
+
+static ssize_t
+extract_quotation(struct archive_string *as, const char *p)
+{
+       const char *s;
+
+       for (s = p + 1; *s;) {
+               if (*s == '\\') {
+                       if (s[1] != '\0') {
+                               archive_strappend_char(as, s[1]);
+                               s += 2;
+                       } else
+                               s++;
+               } else if (*s == '"')
+                       break;
+               else {
+                       archive_strappend_char(as, s[0]);
+                       s++;
+               }
+       }
+       if (*s != '"')
+               return (ARCHIVE_FAILED);/* Invalid sequence. */
+       return ((ssize_t)(s + 1 - p));
+}
+
+static ssize_t
+get_argument(struct archive_string *as, const char *p)
+{
+       const char *s = p;
+
+       archive_string_empty(as);
+
+       /* Skip beginning space characters. */
+       while (*s != '\0' && *s == ' ')
+               s++;
+       /* Copy non-space characters. */
+       while (*s != '\0' && *s != ' ') {
+               if (*s == '\\') {
+                       if (s[1] != '\0') {
+                               archive_strappend_char(as, s[1]);
+                               s += 2;
+                       } else {
+                               s++;/* Ignore this character.*/
+                               break;
+                       }
+               } else if (*s == '"') {
+                       ssize_t q = extract_quotation(as, s);
+                       if (q < 0)
+                               return (ARCHIVE_FAILED);/* Invalid sequence. */
+                       s += q;
+               } else {
+                       archive_strappend_char(as, s[0]);
+                       s++;
+               }
+       }
+       return ((ssize_t)(s - p));
+}
+
+/*
+ * Set up command line arguments.
+ * Returns ARChIVE_OK if everything okey.
+ * Returns ARChIVE_FAILED if there is a lack of the `"' terminator or an
+ * empty command line.
+ * Returns ARChIVE_FATAL if no memory.
+ */
+int
+__archive_cmdline_parse(struct archive_cmdline *data, const char *cmd)
+{
+       struct archive_string as;
+       const char *p;
+       ssize_t al;
+       int r;
+
+       archive_string_init(&as);
+
+       /* Get first argument as a command path. */
+       al = get_argument(&as, cmd);
+       if (al < 0) {
+               r = ARCHIVE_FAILED;/* Invalid sequence. */
+               goto exit_function;
+       }
+       if (archive_strlen(&as) == 0) {
+               r = ARCHIVE_FAILED;/* An empty command path. */
+               goto exit_function;
+       }
+       r = cmdline_set_path(data, as.s);
+       if (r != ARCHIVE_OK)
+               goto exit_function;
+       p = strrchr(as.s, '/');
+       if (p == NULL)
+               p = as.s;
+       else
+               p++;
+       r = cmdline_add_arg(data, p);
+       if (r != ARCHIVE_OK)
+               goto exit_function;
+       cmd += al;
+
+       for (;;) {
+               al = get_argument(&as, cmd);
+               if (al < 0) {
+                       r = ARCHIVE_FAILED;/* Invalid sequence. */
+                       goto exit_function;
+               }
+               if (al == 0)
+                       break;
+               cmd += al;
+               if (archive_strlen(&as) == 0 && *cmd == '\0')
+                       break;
+               r = cmdline_add_arg(data, as.s);
+               if (r != ARCHIVE_OK)
+                       goto exit_function;
+       }
+       r = ARCHIVE_OK;
+exit_function:
+       archive_string_free(&as);
+       return (r);
+}
+
+/*
+ * Set the program path.
+ */
+static int
+cmdline_set_path(struct archive_cmdline *data, const char *path)
+{
+       char *newptr;
+
+       newptr = realloc(data->path, strlen(path) + 1);
+       if (newptr == NULL)
+               return (ARCHIVE_FATAL);
+       data->path = newptr;
+       strcpy(data->path, path);
+       return (ARCHIVE_OK);
+}
+
+/*
+ * Add a argument for the program.
+ */
+static int
+cmdline_add_arg(struct archive_cmdline *data, const char *arg)
+{
+       char **newargv;
+
+       if (data->path == NULL)
+               return (ARCHIVE_FAILED);
+
+       newargv = realloc(data->argv, (data->argc + 2) * sizeof(char *));
+       if (newargv == NULL)
+               return (ARCHIVE_FATAL);
+       data->argv = newargv;
+       data->argv[data->argc] = strdup(arg);
+       if (data->argv[data->argc] == NULL)
+               return (ARCHIVE_FATAL);
+       /* Set the terminator of argv. */
+       data->argv[++data->argc] = NULL;
+       return (ARCHIVE_OK);
+}
+
+struct archive_cmdline *
+__archive_cmdline_allocate(void)
+{
+       return (struct archive_cmdline *)
+               calloc(1, sizeof(struct archive_cmdline));
+}
+
+/*
+ * Release the resources.
+ */
+int
+__archive_cmdline_free(struct archive_cmdline *data)
+{
+
+       if (data) {
+               free(data->path);
+               if (data->argv != NULL) {
+                       int i;
+                       for (i = 0; data->argv[i] != NULL; i++)
+                               free(data->argv[i]);
+                       free(data->argv);
+               }
+               free(data);
+       }
+       return (ARCHIVE_OK);
+}
+
@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2007 Joerg Sonnenberger
+ * Copyright (c) 2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * (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: head/lib/libarchive/filter_fork.h 201087 2009-12-28 02:18:26Z kientzle $
+ * $FreeBSD$
  */
 
 #ifndef __LIBARCHIVE_BUILD
+#ifndef __LIBARCHIVE_TEST
 #error This header is only to be used internally to libarchive.
 #endif
+#endif
 
-#ifndef FILTER_FORK_H
-#define FILTER_FORK_H
+#ifndef ARCHIVE_CMDLINE_PRIVATE_H
+#define ARCHIVE_CMDLINE_PRIVATE_H
 
-pid_t
-__archive_create_child(const char *path, int *child_stdin, int *child_stdout);
+struct archive_cmdline {
+        char            *path;
+        char            **argv;
+        int              argc;
+};
 
-void
-__archive_check_child(int in, int out);
+struct archive_cmdline *__archive_cmdline_allocate(void);
+int __archive_cmdline_parse(struct archive_cmdline *, const char *);
+int __archive_cmdline_free(struct archive_cmdline *);
 
 #endif
index 2caf571..85aba3a 100644 (file)
@@ -90,7 +90,7 @@ win_crypto_Update(Digest_CTX *ctx, const unsigned char *buf, size_t len)
 static int
 win_crypto_Final(unsigned char *buf, size_t bufsize, Digest_CTX *ctx)
 {
-       DWORD siglen = bufsize;
+       DWORD siglen = (DWORD)bufsize;
 
        if (!ctx->valid)
                return (ARCHIVE_FAILED);
@@ -1222,8 +1222,10 @@ __archive_stub_sha512final(archive_sha512_ctx *ctx, void *md)
  * 2. libc2
  * 3. libc3
  * 4. libSystem
- * 5. OpenSSL
- * 6. Windows API
+ * 5. Nettle
+ * 6. OpenSSL
+ * 7. libmd
+ * 8. Windows API
  */
 const struct archive_crypto __archive_crypto =
 {
index b531c77..386e51d 100644 (file)
@@ -1449,6 +1449,9 @@ static struct flag {
        { "nouunlnk",   L"nouunlnk",            UF_NOUNLINK,    0 },
        { "nouunlink",  L"nouunlink",           UF_NOUNLINK,    0 },
 #endif
+#ifdef UF_COMPRESSED
+       { "nocompressed",L"nocompressed",       UF_COMPRESSED,  0 },
+#endif
 #ifdef EXT2_UNRM_FL
         { "nouunlink", L"nouunlink",           EXT2_UNRM_FL,   0},
 #endif
index 5fd7cab..a905065 100644 (file)
@@ -29,7 +29,7 @@
 #define        ARCHIVE_ENTRY_H_INCLUDED
 
 /* Note: Compiler will complain if this does not match archive.h! */
-#define        ARCHIVE_VERSION_NUMBER 3000004
+#define        ARCHIVE_VERSION_NUMBER 3001002
 
 /*
  * Note: archive_entry.h is for use outside of libarchive; the
index 07f0d36..c7d5949 100644 (file)
@@ -244,6 +244,9 @@ archive_entry_linkify(struct archive_entry_linkresolver *res,
                         * for future use.
                         */
                        le = insert_entry(res, *e);
+                       if (le == NULL)
+                               /* XXX We should return an error code XXX */
+                               return;
                        le->entry = *e;
                        *e = NULL;
                }
index 6b533e6..6b6be9c 100644 (file)
@@ -1376,6 +1376,7 @@ add_entry(struct archive_match *a, int flag,
        archive_mstring_copy_wcs(&(f->pathname), pathname);
        a->exclusion_tree.rbt_ops = &rb_ops_wcs;
 #else
+       (void)rb_ops_wcs;
        pathname = archive_entry_pathname(entry);
        if (pathname == NULL) {
                free(f);
@@ -1515,6 +1516,7 @@ time_excluded(struct archive_match *a, struct archive_entry *entry)
        pathname = archive_entry_pathname_w(entry);
        a->exclusion_tree.rbt_ops = &rb_ops_wcs;
 #else
+       (void)rb_ops_wcs;
        pathname = archive_entry_pathname(entry);
        a->exclusion_tree.rbt_ops = &rb_ops_mbs;
 #endif
@@ -1675,13 +1677,16 @@ add_owner_id(struct archive_match *a, struct id_array *ids, int64_t id)
        unsigned i;
 
        if (ids->count + 1 >= ids->size) {
+               void *p;
+
                if (ids->size == 0)
                        ids->size = 8;
                else
                        ids->size *= 2;
-               ids->ids = realloc(ids->ids, sizeof(*ids->ids) * ids->size);
-               if (ids->ids == NULL)
+               p = realloc(ids->ids, sizeof(*ids->ids) * ids->size);
+               if (p == NULL)
                        return (error_nomem(a));
+               ids->ids = (int64_t *)p;
        }
 
        /* Find an insert point. */
@@ -1709,7 +1714,7 @@ match_owner_id(struct id_array *ids, int64_t id)
        unsigned b, m, t;
 
        t = 0;
-       b = ids->count;
+       b = (unsigned)ids->count;
        while (t < b) {
                m = (t + b)>>1;
                if (ids->ids[m] == id)
index 08a348f..8af6239 100644 (file)
@@ -87,6 +87,8 @@ _archive_set_either_option(struct archive *a, const char *m, const char *o, cons
        if (r2 == ARCHIVE_FATAL)
                return (ARCHIVE_FATAL);
 
+       if (r2 == ARCHIVE_WARN - 1)
+               return r1;
        return r1 > r2 ? r1 : r2;
 }
 
@@ -94,7 +96,7 @@ int
 _archive_set_options(struct archive *a, const char *options,
     int magic, const char *fn, option_handler use_option)
 {
-       int allok = 1, anyok = 0, r;
+       int allok = 1, anyok = 0, ignore_mod_err = 0, r;
        char *data;
        const char *s, *mod, *opt, *val;
 
@@ -111,6 +113,15 @@ _archive_set_options(struct archive *a, const char *options,
                mod = opt = val = NULL;
 
                parse_option(&s, &mod, &opt, &val);
+               if (mod == NULL && opt != NULL &&
+                   strcmp("__ignore_wrong_module_name__", opt) == 0) {
+                       /* Ignore module name error */
+                       if (val != NULL) {
+                               ignore_mod_err = 1;
+                               anyok = 1;
+                       }
+                       continue;
+               }
 
                r = use_option(a, mod, opt, val);
                if (r == ARCHIVE_FATAL) {
@@ -122,6 +133,8 @@ _archive_set_options(struct archive *a, const char *options,
                        return (ARCHIVE_FAILED);
                }
                if (r == ARCHIVE_WARN - 1) {
+                       if (ignore_mod_err)
+                               continue;
                        /* The module name is wrong. */
                        archive_set_error(a, ARCHIVE_ERRNO_MISC,
                            "Unknown module name: `%s'", mod);
index 13a2581..fe0b031 100644 (file)
@@ -990,7 +990,7 @@ static void RangeEnc_ShiftLow(CPpmd7z_RangeEnc *p)
     p->Cache = (Byte)((UInt32)p->Low >> 24);
   }
   p->CacheSize++;
-  p->Low = (UInt32)p->Low << 8;
+  p->Low = ((UInt32)p->Low << 8) & 0xFFFFFFFF;
 }
 
 static void RangeEnc_Encode(CPpmd7z_RangeEnc *p, UInt32 start, UInt32 size, UInt32 total)
index 470f500..30d472f 100644 (file)
@@ -134,6 +134,7 @@ int __archive_check_magic(struct archive *, unsigned int magic,
 
 void   __archive_errx(int retvalue, const char *msg) __LA_DEAD;
 
+void   __archive_ensure_cloexec_flag(int fd);
 int    __archive_mktemp(const char *tmpdir);
 
 int    __archive_clean(struct archive *);
index 70bf7e6..5b5da20 100644 (file)
@@ -237,6 +237,8 @@ __archive_rb_tree_reparent_nodes(
        struct archive_rb_node * const new_father = old_child;
        struct archive_rb_node * const new_child = old_father;
 
+       if (new_father == NULL)
+               return;
        /*
         * Exchange descendant linkages.
         */
@@ -552,6 +554,8 @@ __archive_rb_tree_removal_rebalance(struct archive_rb_tree *rbt,
                unsigned int other = which ^ RB_DIR_OTHER;
                struct archive_rb_node *brother = parent->rb_nodes[other];
 
+               if (brother == NULL)
+                       return;/* The tree may be broken. */
                /*
                 * For cases 1, 2a, and 2b, our brother's children must
                 * be black and our father must be black
@@ -573,6 +577,8 @@ __archive_rb_tree_removal_rebalance(struct archive_rb_tree *rbt,
                                 */
                                __archive_rb_tree_reparent_nodes(parent, other);
                                brother = parent->rb_nodes[other];
+                               if (brother == NULL)
+                                       return;/* The tree may be broken. */
                        } else {
                                /*
                                 * Both our parent and brother are black.
@@ -656,6 +662,8 @@ __archive_rb_tree_removal_rebalance(struct archive_rb_tree *rbt,
                         * If we had two red nephews, then after the swap,
                         * our former father would have a red grandson. 
                         */
+                       if (brother->rb_nodes[other] == NULL)
+                               return;/* The tree may be broken. */
                        RB_MARK_BLACK(brother->rb_nodes[other]);
                        __archive_rb_tree_reparent_nodes(parent, other);
                        break;          /* We're done! */
index e99906f..048c316 100644 (file)
@@ -57,8 +57,6 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read.c 201157 2009-12-29 05:30:2
 
 static int     choose_filters(struct archive_read *);
 static int     choose_format(struct archive_read *);
-static void    free_filters(struct archive_read *);
-static int     close_filters(struct archive_read *);
 static struct archive_vtable *archive_read_vtable(void);
 static int64_t _archive_filter_bytes(struct archive *, int);
 static int     _archive_filter_code(struct archive *, int);
@@ -194,8 +192,8 @@ client_skip_proxy(struct archive_read_filter *self, int64_t request)
                        int64_t get, ask = request;
                        if (ask > skip_limit)
                                ask = skip_limit;
-                       get = (self->archive->client.skipper)(&self->archive->archive,
-                           self->data, ask);
+                       get = (self->archive->client.skipper)
+                               (&self->archive->archive, self->data, ask);
                        if (get == 0)
                                return (total);
                        request -= get;
@@ -215,8 +213,8 @@ client_skip_proxy(struct archive_read_filter *self, int64_t request)
                 * only do this for skips of over 64k.
                 */
                int64_t before = self->position;
-               int64_t after = (self->archive->client.seeker)(&self->archive->archive,
-                   self->data, request, SEEK_CUR);
+               int64_t after = (self->archive->client.seeker)
+                   (&self->archive->archive, self->data, request, SEEK_CUR);
                if (after != before + request)
                        return ARCHIVE_FATAL;
                return after - before;
@@ -241,14 +239,64 @@ client_seek_proxy(struct archive_read_filter *self, int64_t offset, int whence)
 static int
 client_close_proxy(struct archive_read_filter *self)
 {
-       int r = ARCHIVE_OK;
+       int r = ARCHIVE_OK, r2;
+       unsigned int i;
+
+       if (self->archive->client.closer == NULL)
+               return (r);
+       for (i = 0; i < self->archive->client.nodes; i++)
+       {
+               r2 = (self->archive->client.closer)
+                       ((struct archive *)self->archive,
+                               self->archive->client.dataset[i].data);
+               if (r > r2)
+                       r = r2;
+       }
+       return (r);
+}
 
-       if (self->archive->client.closer != NULL)
-               r = (self->archive->client.closer)((struct archive *)self->archive,
-                   self->data);
+static int
+client_open_proxy(struct archive_read_filter *self)
+{
+  int r = ARCHIVE_OK;
+       if (self->archive->client.opener != NULL)
+               r = (self->archive->client.opener)(
+                   (struct archive *)self->archive, self->data);
        return (r);
 }
 
+static int
+client_switch_proxy(struct archive_read_filter *self, unsigned int iindex)
+{
+  int r1 = ARCHIVE_OK, r2 = ARCHIVE_OK;
+       void *data2 = NULL;
+
+       /* Don't do anything if already in the specified data node */
+       if (self->archive->client.cursor == iindex)
+               return (ARCHIVE_OK);
+
+       self->archive->client.cursor = iindex;
+       data2 = self->archive->client.dataset[self->archive->client.cursor].data;
+       if (self->archive->client.switcher != NULL)
+       {
+               r1 = r2 = (self->archive->client.switcher)
+                       ((struct archive *)self->archive, self->data, data2);
+               self->data = data2;
+       }
+       else
+       {
+               /* Attempt to call close and open instead */
+               if (self->archive->client.closer != NULL)
+                       r1 = (self->archive->client.closer)
+                               ((struct archive *)self->archive, self->data);
+               self->data = data2;
+               if (self->archive->client.opener != NULL)
+                       r2 = (self->archive->client.opener)
+                               ((struct archive *)self->archive, self->data);
+       }
+       return (r1 < r2) ? r1 : r2;
+}
+
 int
 archive_read_set_open_callback(struct archive *_a,
     archive_open_callback *client_opener)
@@ -304,22 +352,110 @@ archive_read_set_close_callback(struct archive *_a,
        return ARCHIVE_OK;
 }
 
+int
+archive_read_set_switch_callback(struct archive *_a,
+    archive_switch_callback *client_switcher)
+{
+       struct archive_read *a = (struct archive_read *)_a;
+       archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
+           "archive_read_set_switch_callback");
+       a->client.switcher = client_switcher;
+       return ARCHIVE_OK;
+}
+
 int
 archive_read_set_callback_data(struct archive *_a, void *client_data)
+{
+       return archive_read_set_callback_data2(_a, client_data, 0);
+}
+
+int
+archive_read_set_callback_data2(struct archive *_a, void *client_data,
+    unsigned int iindex)
 {
        struct archive_read *a = (struct archive_read *)_a;
        archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
-           "archive_read_set_callback_data");
-       a->client.data = client_data;
+           "archive_read_set_callback_data2");
+
+       if (a->client.nodes == 0)
+       {
+               a->client.dataset = (struct archive_read_data_node *)
+                   calloc(1, sizeof(*a->client.dataset));
+               if (a->client.dataset == NULL)
+               {
+                       archive_set_error(&a->archive, ENOMEM,
+                               "No memory.");
+                       return ARCHIVE_FATAL;
+               }
+               a->client.nodes = 1;
+       }
+
+       if (iindex > a->client.nodes - 1)
+       {
+               archive_set_error(&a->archive, EINVAL,
+                       "Invalid index specified.");
+               return ARCHIVE_FATAL;
+       }
+       a->client.dataset[iindex].data = client_data;
+       a->client.dataset[iindex].begin_position = -1;
+       a->client.dataset[iindex].total_size = -1;
+       return ARCHIVE_OK;
+}
+
+int
+archive_read_add_callback_data(struct archive *_a, void *client_data,
+    unsigned int iindex)
+{
+       struct archive_read *a = (struct archive_read *)_a;
+       void *p;
+       unsigned int i;
+
+       archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
+           "archive_read_add_callback_data");
+       if (iindex > a->client.nodes) {
+               archive_set_error(&a->archive, EINVAL,
+                       "Invalid index specified.");
+               return ARCHIVE_FATAL;
+       }
+       p = realloc(a->client.dataset, sizeof(*a->client.dataset)
+               * (++(a->client.nodes)));
+       if (p == NULL) {
+               archive_set_error(&a->archive, ENOMEM,
+                       "No memory.");
+               return ARCHIVE_FATAL;
+       }
+       a->client.dataset = (struct archive_read_data_node *)p;
+       for (i = a->client.nodes - 1; i > iindex && i > 0; i--) {
+               a->client.dataset[i].data = a->client.dataset[i-1].data;
+               a->client.dataset[i].begin_position = -1;
+               a->client.dataset[i].total_size = -1;
+       }
+       a->client.dataset[iindex].data = client_data;
+       a->client.dataset[iindex].begin_position = -1;
+       a->client.dataset[iindex].total_size = -1;
        return ARCHIVE_OK;
 }
 
+int
+archive_read_append_callback_data(struct archive *_a, void *client_data)
+{
+       struct archive_read *a = (struct archive_read *)_a;
+       return archive_read_add_callback_data(_a, client_data, a->client.nodes);
+}
+
+int
+archive_read_prepend_callback_data(struct archive *_a, void *client_data)
+{
+       return archive_read_add_callback_data(_a, client_data, 0);
+}
+
 int
 archive_read_open1(struct archive *_a)
 {
        struct archive_read *a = (struct archive_read *)_a;
-       struct archive_read_filter *filter;
+       struct archive_read_filter *filter, *tmp;
        int slot, e;
+       unsigned int i;
 
        archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
            "archive_read_open");
@@ -334,11 +470,14 @@ archive_read_open1(struct archive *_a)
 
        /* Open data source. */
        if (a->client.opener != NULL) {
-               e =(a->client.opener)(&a->archive, a->client.data);
+               e = (a->client.opener)(&a->archive, a->client.dataset[0].data);
                if (e != 0) {
                        /* If the open failed, call the closer to clean up. */
-                       if (a->client.closer)
-                               (a->client.closer)(&a->archive, a->client.data);
+                       if (a->client.closer) {
+                               for (i = 0; i < a->client.nodes; i++)
+                                       (a->client.closer)(&a->archive,
+                                           a->client.dataset[i].data);
+                       }
                        return (e);
                }
        }
@@ -349,31 +488,51 @@ archive_read_open1(struct archive *_a)
        filter->bidder = NULL;
        filter->upstream = NULL;
        filter->archive = a;
-       filter->data = a->client.data;
+       filter->data = a->client.dataset[0].data;
+       filter->open = client_open_proxy;
        filter->read = client_read_proxy;
        filter->skip = client_skip_proxy;
        filter->seek = client_seek_proxy;
        filter->close = client_close_proxy;
+       filter->sswitch = client_switch_proxy;
        filter->name = "none";
-       filter->code = ARCHIVE_COMPRESSION_NONE;
-       a->filter = filter;
+       filter->code = ARCHIVE_FILTER_NONE;
 
-       /* Build out the input pipeline. */
-       e = choose_filters(a);
-       if (e < ARCHIVE_WARN) {
-               a->archive.state = ARCHIVE_STATE_FATAL;
-               return (ARCHIVE_FATAL);
+       a->client.dataset[0].begin_position = 0;
+       if (!a->filter || !a->bypass_filter_bidding)
+       {
+               a->filter = filter;
+               /* Build out the input pipeline. */
+               e = choose_filters(a);
+               if (e < ARCHIVE_WARN) {
+                       a->archive.state = ARCHIVE_STATE_FATAL;
+                       return (ARCHIVE_FATAL);
+               }
+       }
+       else
+       {
+               /* Need to add "NONE" type filter at the end of the filter chain */
+               tmp = a->filter;
+               while (tmp->upstream)
+                       tmp = tmp->upstream;
+               tmp->upstream = filter;
        }
 
-       slot = choose_format(a);
-       if (slot < 0) {
-               close_filters(a);
-               a->archive.state = ARCHIVE_STATE_FATAL;
-               return (ARCHIVE_FATAL);
+       if (!a->format)
+       {
+               slot = choose_format(a);
+               if (slot < 0) {
+                       __archive_read_close_filters(a);
+                       a->archive.state = ARCHIVE_STATE_FATAL;
+                       return (ARCHIVE_FATAL);
+               }
+               a->format = &(a->formats[slot]);
        }
-       a->format = &(a->formats[slot]);
 
        a->archive.state = ARCHIVE_STATE_HEADER;
+
+       /* Ensure libarchive starts from the first node in a multivolume set */
+       client_switch_proxy(a->filter, 0);
        return (e);
 }
 
@@ -413,8 +572,8 @@ choose_filters(struct archive_read *a)
                        /* Verify the filter by asking it for some data. */
                        __archive_read_filter_ahead(a->filter, 1, &avail);
                        if (avail < 0) {
-                               close_filters(a);
-                               free_filters(a);
+                               __archive_read_close_filters(a);
+                               __archive_read_free_filters(a);
                                return (ARCHIVE_FATAL);
                        }
                        a->archive.compression_name = a->filter->name;
@@ -432,8 +591,8 @@ choose_filters(struct archive_read *a)
                a->filter = filter;
                r = (best_bidder->init)(a->filter);
                if (r != ARCHIVE_OK) {
-                       close_filters(a);
-                       free_filters(a);
+                       __archive_read_close_filters(a);
+                       __archive_read_free_filters(a);
                        return (ARCHIVE_FATAL);
                }
        }
@@ -501,6 +660,9 @@ _archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
 
        a->read_data_output_offset = 0;
        a->read_data_remaining = 0;
+       a->read_data_is_posix_read = 0;
+       a->read_data_requested = 0;
+       a->data_start_node = a->client.cursor;
        /* EOF always wins; otherwise return the worst error. */
        return (r2 < r1 || r2 == ARCHIVE_EOF) ? r2 : r1;
 }
@@ -611,6 +773,8 @@ archive_read_data(struct archive *_a, void *buff, size_t s)
        while (s > 0) {
                if (a->read_data_remaining == 0) {
                        read_buf = a->read_data_block;
+                       a->read_data_is_posix_read = 1;
+                       a->read_data_requested = s;
                        r = _archive_read_data_block(&a->archive, &read_buf,
                            &a->read_data_remaining, &a->read_data_offset);
                        a->read_data_block = read_buf;
@@ -664,6 +828,8 @@ archive_read_data(struct archive *_a, void *buff, size_t s)
                        bytes_read += len;
                }
        }
+       a->read_data_is_posix_read = 0;
+       a->read_data_requested = 0;
        return (bytes_read);
 }
 
@@ -698,6 +864,23 @@ archive_read_data_skip(struct archive *_a)
        return (r);
 }
 
+int64_t
+archive_seek_data(struct archive *_a, int64_t offset, int whence)
+{
+       struct archive_read *a = (struct archive_read *)_a;
+       archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA,
+           "archive_seek_data_block");
+
+       if (a->format->seek_data == NULL) {
+               archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
+                   "Internal error: "
+                   "No format_seek_data_block function registered");
+               return (ARCHIVE_FATAL);
+       }
+
+       return (a->format->seek_data)(a, offset, whence);
+}
+
 /*
  * Read the next block of entry data from the archive.
  * This is a zero-copy interface; the client receives a pointer,
@@ -724,8 +907,8 @@ _archive_read_data_block(struct archive *_a,
        return (a->format->read_data)(a, buff, size, offset);
 }
 
-static int
-close_filters(struct archive_read *a)
+int
+__archive_read_close_filters(struct archive_read *a)
 {
        struct archive_read_filter *f = a->filter;
        int r = ARCHIVE_OK;
@@ -745,8 +928,8 @@ close_filters(struct archive_read *a)
        return r;
 }
 
-static void
-free_filters(struct archive_read *a)
+void
+__archive_read_free_filters(struct archive_read *a)
 {
        while (a->filter != NULL) {
                struct archive_read_filter *t = a->filter->upstream;
@@ -790,7 +973,7 @@ _archive_read_close(struct archive *_a)
        /* TODO: Clean up the formatters. */
 
        /* Release the filter objects. */
-       r1 = close_filters(a);
+       r1 = __archive_read_close_filters(a);
        if (r1 < r)
                r = r1;
 
@@ -829,7 +1012,7 @@ _archive_read_free(struct archive *_a)
        }
 
        /* Free the filters */
-       free_filters(a);
+       __archive_read_free_filters(a);
 
        /* Release the bidder objects. */
        n = sizeof(a->bidders)/sizeof(a->bidders[0]);
@@ -846,6 +1029,7 @@ _archive_read_free(struct archive *_a)
                archive_entry_free(a->entry);
        a->archive.magic = 0;
        __archive_clean(&a->archive);
+       free(a->client.dataset);
        free(a);
        return (r);
 }
@@ -855,7 +1039,8 @@ get_filter(struct archive *_a, int n)
 {
        struct archive_read *a = (struct archive_read *)_a;
        struct archive_read_filter *f = a->filter;
-       /* We use n == -1 for 'the last filter', which is always the client proxy. */
+       /* We use n == -1 for 'the last filter', which is always the
+        * client proxy. */
        if (n == -1 && f != NULL) {
                struct archive_read_filter *last = f;
                f = f->upstream;
@@ -908,6 +1093,7 @@ __archive_read_register_format(struct archive_read *a,
     int (*read_header)(struct archive_read *, struct archive_entry *),
     int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *),
     int (*read_data_skip)(struct archive_read *),
+    int64_t (*seek_data)(struct archive_read *, int64_t, int),
     int (*cleanup)(struct archive_read *))
 {
        int i, number_slots;
@@ -927,6 +1113,7 @@ __archive_read_register_format(struct archive_read *a,
                        a->formats[i].read_header = read_header;
                        a->formats[i].read_data = read_data;
                        a->formats[i].read_data_skip = read_data_skip;
+                       a->formats[i].seek_data = seek_data;
                        a->formats[i].cleanup = cleanup;
                        a->formats[i].data = format_data;
                        a->formats[i].name = name;
@@ -1073,7 +1260,8 @@ __archive_read_filter_ahead(struct archive_read_filter *filter,
                if (filter->next > filter->buffer &&
                    filter->next + min > filter->buffer + filter->buffer_size) {
                        if (filter->avail > 0)
-                               memmove(filter->buffer, filter->next, filter->avail);
+                               memmove(filter->buffer, filter->next,
+                                   filter->avail);
                        filter->next = filter->buffer;
                }
 
@@ -1088,15 +1276,26 @@ __archive_read_filter_ahead(struct archive_read_filter *filter,
                            &filter->client_buff);
                        if (bytes_read < 0) {           /* Read error. */
                                filter->client_total = filter->client_avail = 0;
-                               filter->client_next = filter->client_buff = NULL;
+                               filter->client_next =
+                                   filter->client_buff = NULL;
                                filter->fatal = 1;
                                if (avail != NULL)
                                        *avail = ARCHIVE_FATAL;
                                return (NULL);
                        }
-                       if (bytes_read == 0) {  /* Premature end-of-file. */
+                       if (bytes_read == 0) {
+                               /* Check for another client object first */
+                               if (filter->archive->client.cursor !=
+                                     filter->archive->client.nodes - 1) {
+                                       if (client_switch_proxy(filter,
+                                           filter->archive->client.cursor + 1)
+                                           == ARCHIVE_OK)
+                                               continue;
+                               }
+                               /* Premature end-of-file. */
                                filter->client_total = filter->client_avail = 0;
-                               filter->client_next = filter->client_buff = NULL;
+                               filter->client_next =
+                                   filter->client_buff = NULL;
                                filter->end_of_file = 1;
                                /* Return whatever we do have. */
                                if (avail != NULL)
@@ -1106,9 +1305,7 @@ __archive_read_filter_ahead(struct archive_read_filter *filter,
                        filter->client_total = bytes_read;
                        filter->client_avail = filter->client_total;
                        filter->client_next = filter->client_buff;
-               }
-               else
-               {
+               } else {
                        /*
                         * We can't satisfy the request from the copy
                         * buffer or the existing client data, so we
@@ -1129,9 +1326,10 @@ __archive_read_filter_ahead(struct archive_read_filter *filter,
                                        t *= 2;
                                        if (t <= s) { /* Integer overflow! */
                                                archive_set_error(
-                                                       &filter->archive->archive,
-                                                       ENOMEM,
-                                                   "Unable to allocate copy buffer");
+                                                   &filter->archive->archive,
+                                                   ENOMEM,
+                                                   "Unable to allocate copy"
+                                                   " buffer");
                                                filter->fatal = 1;
                                                if (avail != NULL)
                                                        *avail = ARCHIVE_FATAL;
@@ -1170,8 +1368,8 @@ __archive_read_filter_ahead(struct archive_read_filter *filter,
                        if (tocopy > filter->client_avail)
                                tocopy = filter->client_avail;
 
-                       memcpy(filter->next + filter->avail, filter->client_next,
-                           tocopy);
+                       memcpy(filter->next + filter->avail,
+                           filter->client_next, tocopy);
                        /* Remove this data from client buffer. */
                        filter->client_next += tocopy;
                        filter->client_avail -= tocopy;
@@ -1274,6 +1472,13 @@ advance_file_pointer(struct archive_read_filter *filter, int64_t request)
                }
 
                if (bytes_read == 0) {
+                       if (filter->archive->client.cursor !=
+                             filter->archive->client.nodes - 1) {
+                               if (client_switch_proxy(filter,
+                                   filter->archive->client.cursor + 1)
+                                   == ARCHIVE_OK)
+                                       continue;
+                       }
                        filter->client_buff = NULL;
                        filter->end_of_file = 1;
                        return (total_bytes_skipped);
@@ -1305,15 +1510,109 @@ __archive_read_seek(struct archive_read *a, int64_t offset, int whence)
 }
 
 int64_t
-__archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset, int whence)
+__archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset,
+    int whence)
 {
+       struct archive_read_client *client;
        int64_t r;
+       unsigned int cursor;
 
        if (filter->closed || filter->fatal)
                return (ARCHIVE_FATAL);
        if (filter->seek == NULL)
                return (ARCHIVE_FAILED);
-       r = filter->seek(filter, offset, whence);
+
+       client = &(filter->archive->client);
+       switch (whence) {
+       case SEEK_CUR:
+               /* Adjust the offset and use SEEK_SET instead */
+               offset += filter->position;                     
+       case SEEK_SET:
+               cursor = 0;
+               while (1)
+               {
+                       if (client->dataset[cursor].begin_position < 0 ||
+                           client->dataset[cursor].total_size < 0 ||
+                           client->dataset[cursor].begin_position +
+                             client->dataset[cursor].total_size - 1 > offset ||
+                           cursor + 1 >= client->nodes)
+                               break;
+                       r = client->dataset[cursor].begin_position +
+                               client->dataset[cursor].total_size;
+                       client->dataset[++cursor].begin_position = r;
+               }
+               while (1) {
+                       r = client_switch_proxy(filter, cursor);
+                       if (r != ARCHIVE_OK)
+                               return r;
+                       if ((r = client_seek_proxy(filter, 0, SEEK_END)) < 0)
+                               return r;
+                       client->dataset[cursor].total_size = r;
+                       if (client->dataset[cursor].begin_position +
+                           client->dataset[cursor].total_size - 1 > offset ||
+                           cursor + 1 >= client->nodes)
+                               break;
+                       r = client->dataset[cursor].begin_position +
+                               client->dataset[cursor].total_size;
+                       client->dataset[++cursor].begin_position = r;
+               }
+               offset -= client->dataset[cursor].begin_position;
+               if (offset < 0)
+                       offset = 0;
+               else if (offset > client->dataset[cursor].total_size - 1)
+                       offset = client->dataset[cursor].total_size - 1;
+               if ((r = client_seek_proxy(filter, offset, SEEK_SET)) < 0)
+                       return r;
+               break;
+
+       case SEEK_END:
+               cursor = 0;
+               while (1) {
+                       if (client->dataset[cursor].begin_position < 0 ||
+                           client->dataset[cursor].total_size < 0 ||
+                           cursor + 1 >= client->nodes)
+                               break;
+                       r = client->dataset[cursor].begin_position +
+                               client->dataset[cursor].total_size;
+                       client->dataset[++cursor].begin_position = r;
+               }
+               while (1) {
+                       r = client_switch_proxy(filter, cursor);
+                       if (r != ARCHIVE_OK)
+                               return r;
+                       if ((r = client_seek_proxy(filter, 0, SEEK_END)) < 0)
+                               return r;
+                       client->dataset[cursor].total_size = r;
+                       r = client->dataset[cursor].begin_position +
+                               client->dataset[cursor].total_size;
+                       if (cursor + 1 >= client->nodes)
+                               break;
+                       client->dataset[++cursor].begin_position = r;
+               }
+               while (1) {
+                       if (r + offset >=
+                           client->dataset[cursor].begin_position)
+                               break;
+                       offset += client->dataset[cursor].total_size;
+                       if (cursor == 0)
+                               break;
+                       cursor--;
+                       r = client->dataset[cursor].begin_position +
+                               client->dataset[cursor].total_size;
+               }
+               offset = (r + offset) - client->dataset[cursor].begin_position;
+               if ((r = client_switch_proxy(filter, cursor)) != ARCHIVE_OK)
+                       return r;
+               r = client_seek_proxy(filter, offset, SEEK_SET);
+               if (r < ARCHIVE_OK)
+                       return r;
+               break;
+
+       default:
+               return (ARCHIVE_FATAL);
+       }
+       r += client->dataset[cursor].begin_position;
+
        if (r >= 0) {
                /*
                 * Ouch.  Clearing the buffer like this hurts, especially
diff --git a/contrib/libarchive/libarchive/archive_read_append_filter.c b/contrib/libarchive/libarchive/archive_read_append_filter.c
new file mode 100644 (file)
index 0000000..017d7c6
--- /dev/null
@@ -0,0 +1,198 @@
+/*-
+ * Copyright (c) 2003-2012 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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_read_private.h"
+
+int
+archive_read_append_filter(struct archive *_a, int code)
+{
+  int r1, r2, number_bidders, i;
+  char str[20];
+  struct archive_read_filter_bidder *bidder;
+  struct archive_read_filter *filter;
+  struct archive_read *a = (struct archive_read *)_a;
+
+  r1 = r2 = (ARCHIVE_OK);
+  switch (code)
+  {
+    case ARCHIVE_FILTER_NONE:
+      /* No filter to add, so do nothing.
+       * NOTE: An initial "NONE" type filter is always set at the end of the
+       * filter chain.
+       */
+      r1 = (ARCHIVE_OK);
+      break;
+    case ARCHIVE_FILTER_GZIP:
+      strcpy(str, "gzip");
+      r1 = archive_read_support_filter_gzip(_a);
+      break;
+    case ARCHIVE_FILTER_BZIP2:
+      strcpy(str, "bzip2");
+      r1 = archive_read_support_filter_bzip2(_a);
+      break;
+    case ARCHIVE_FILTER_COMPRESS:
+      strcpy(str, "compress (.Z)");
+      r1 = archive_read_support_filter_compress(_a);
+      break;
+    case ARCHIVE_FILTER_PROGRAM:
+      archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
+          "Cannot append program filter using archive_read_append_filter");
+      return (ARCHIVE_FATAL);
+    case ARCHIVE_FILTER_LZMA:
+      strcpy(str, "lzma");
+      r1 = archive_read_support_filter_lzma(_a);
+      break;
+    case ARCHIVE_FILTER_XZ:
+      strcpy(str, "xz");
+      r1 = archive_read_support_filter_xz(_a);
+      break;
+    case ARCHIVE_FILTER_UU:
+      strcpy(str, "uu");
+      r1 = archive_read_support_filter_uu(_a);
+      break;
+    case ARCHIVE_FILTER_RPM:
+      strcpy(str, "rpm");
+      r1 = archive_read_support_filter_rpm(_a);
+      break;
+    case ARCHIVE_FILTER_LZIP:
+      strcpy(str, "lzip");
+      r1 = archive_read_support_filter_lzip(_a);
+      break;
+    case ARCHIVE_FILTER_LRZIP:
+      strcpy(str, "lrzip");
+      r1 = archive_read_support_filter_lrzip(_a);
+      break;
+    default:
+      archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
+          "Invalid filter code specified");
+      return (ARCHIVE_FATAL);
+  }
+
+  if (code != ARCHIVE_FILTER_NONE)
+  {
+    number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]);
+
+    bidder = a->bidders;
+    for (i = 0; i < number_bidders; i++, bidder++)
+    {
+      if (!bidder->name || !strcmp(bidder->name, str))
+        break;
+    }
+    if (!bidder->name || strcmp(bidder->name, str))
+    {
+      archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
+          "Internal error: Unable to append filter");
+      return (ARCHIVE_FATAL);
+    }
+
+    filter
+        = (struct archive_read_filter *)calloc(1, sizeof(*filter));
+    if (filter == NULL)
+    {
+      archive_set_error(&a->archive, ENOMEM, "Out of memory");
+      return (ARCHIVE_FATAL);
+    }
+    filter->bidder = bidder;
+    filter->archive = a;
+    filter->upstream = a->filter;
+    a->filter = filter;
+    r2 = (bidder->init)(a->filter);
+    if (r2 != ARCHIVE_OK) {
+      __archive_read_close_filters(a);
+      __archive_read_free_filters(a);
+      return (ARCHIVE_FATAL);
+    }
+  }
+
+  a->bypass_filter_bidding = 1;
+  return (r1 < r2) ? r1 : r2;
+}
+
+int
+archive_read_append_filter_program(struct archive *_a, const char *cmd)
+{
+  return (archive_read_append_filter_program_signature(_a, cmd, NULL, 0));
+}
+
+int
+archive_read_append_filter_program_signature(struct archive *_a,
+  const char *cmd, const void *signature, size_t signature_len)
+{
+  int r, number_bidders, i;
+  struct archive_read_filter_bidder *bidder;
+  struct archive_read_filter *filter;
+  struct archive_read *a = (struct archive_read *)_a;
+
+  if (archive_read_support_filter_program_signature(_a, cmd, signature,
+    signature_len) != (ARCHIVE_OK))
+    return (ARCHIVE_FATAL);
+
+  number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]);
+
+  bidder = a->bidders;
+  for (i = 0; i < number_bidders; i++, bidder++)
+  {
+    /* Program bidder name set to filter name after initialization */
+    if (bidder->data && !bidder->name)
+      break;
+  }
+  if (!bidder->data)
+  {
+    archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
+        "Internal error: Unable to append program filter");
+    return (ARCHIVE_FATAL);
+  }
+
+  filter
+      = (struct archive_read_filter *)calloc(1, sizeof(*filter));
+  if (filter == NULL)
+  {
+    archive_set_error(&a->archive, ENOMEM, "Out of memory");
+    return (ARCHIVE_FATAL);
+  }
+  filter->bidder = bidder;
+  filter->archive = a;
+  filter->upstream = a->filter;
+  a->filter = filter;
+  r = (bidder->init)(a->filter);
+  if (r != ARCHIVE_OK) {
+    __archive_read_close_filters(a);
+    __archive_read_free_filters(a);
+    return (ARCHIVE_FATAL);
+  }
+  bidder->name = a->filter->name;
+
+  a->bypass_filter_bidding = 1;
+  return r;
+}
diff --git a/contrib/libarchive/libarchive/archive_read_data.3 b/contrib/libarchive/libarchive/archive_read_data.3
new file mode 100644 (file)
index 0000000..bf0578c
--- /dev/null
@@ -0,0 +1,130 @@
+.\" Copyright (c) 2003-2011 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 2, 2012
+.Dt ARCHIVE_READ_DATA 3
+.Os
+.Sh NAME
+.Nm archive_read_data
+.Nm archive_read_data_block ,
+.Nm archive_read_data_skip ,
+.Nm archive_read_data_into_fd
+.Nd functions for reading streaming archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
+.Sh SYNOPSIS
+.In archive.h
+.Ft ssize_t
+.Fn archive_read_data "struct archive *" "void *buff" "size_t len"
+.Ft int
+.Fo archive_read_data_block
+.Fa "struct archive *"
+.Fa "const void **buff"
+.Fa "size_t *len"
+.Fa "off_t *offset"
+.Fc
+.Ft int
+.Fn archive_read_data_skip "struct archive *"
+.Ft int
+.Fn archive_read_data_into_fd "struct archive *" "int fd"
+.\"
+.Sh DESCRIPTION
+.Bl -tag -compact -width indent
+.It Fn archive_read_data
+Read data associated with the header just read.
+Internally, this is a convenience function that calls
+.Fn archive_read_data_block
+and fills any gaps with nulls so that callers see a single
+continuous stream of data.
+.It Fn archive_read_data_block
+Return the next available block of data for this entry.
+Unlike
+.Fn archive_read_data ,
+the
+.Fn archive_read_data_block
+function avoids copying data and allows you to correctly handle
+sparse files, as supported by some archive formats.
+The library guarantees that offsets will increase and that blocks
+will not overlap.
+Note that the blocks returned from this function can be much larger
+than the block size read from disk, due to compression
+and internal buffer optimizations.
+.It Fn archive_read_data_skip
+A convenience function that repeatedly calls
+.Fn archive_read_data_block
+to skip all of the data for this archive entry.
+Note that this function is invoked automatically by
+.Fn archive_read_next_header2
+if the previous entry was not completely consumed.
+.It Fn archive_read_data_into_fd
+A convenience function that repeatedly calls
+.Fn archive_read_data_block
+to copy the entire entry to the provided file descriptor.
+.El
+.\"
+.Sh RETURN VALUES
+Most functions return zero on success, non-zero on error.
+The possible return codes include:
+.Cm ARCHIVE_OK
+(the operation succeeded),
+.Cm ARCHIVE_WARN
+(the operation succeeded but a non-critical error was encountered),
+.Cm ARCHIVE_EOF
+(end-of-archive was encountered),
+.Cm ARCHIVE_RETRY
+(the operation failed but can be retried),
+and
+.Cm ARCHIVE_FATAL
+(there was a fatal error; the archive should be closed immediately).
+.Pp
+.Fn archive_read_data
+returns a count of bytes actually read or zero at the end of the entry.
+On error, a value of
+.Cm ARCHIVE_FATAL ,
+.Cm ARCHIVE_WARN ,
+or
+.Cm ARCHIVE_RETRY
+is returned.
+.\"
+.Sh ERRORS
+Detailed error codes and textual descriptions are available from the
+.Fn archive_errno
+and
+.Fn archive_error_string
+functions.
+.\"
+.Sh SEE ALSO
+.Xr tar 1 ,
+.Xr libarchive 3 ,
+.Xr archive_read 3 ,
+.Xr archive_read_extract 3 ,
+.Xr archive_read_filter 3 ,
+.Xr archive_read_format 3 ,
+.Xr archive_read_header 3 ,
+.Xr archive_read_open 3 ,
+.Xr archive_read_set_options 3 ,
+.Xr archive_util 3 ,
+.Xr tar 5
index a43c0ad..e984aaa 100644 (file)
@@ -49,8 +49,10 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 2010
 #ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
 #endif
-#ifdef HAVE_SYS_XATTR_H
+#if defined(HAVE_SYS_XATTR_H)
 #include <sys/xattr.h>
+#elif defined(HAVE_ATTR_XATTR_H)
+#include <attr/xattr.h>
 #endif
 #ifdef HAVE_SYS_EA_H
 #include <sys/ea.h>
@@ -58,9 +60,6 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 2010
 #ifdef HAVE_ACL_LIBACL_H
 #include <acl/libacl.h>
 #endif
-#ifdef HAVE_ATTR_XATTR_H
-#include <attr/xattr.h>
-#endif
 #ifdef HAVE_COPYFILE_H
 #include <copyfile.h>
 #endif
@@ -104,6 +103,10 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 2010
 #include "archive_private.h"
 #include "archive_read_disk_private.h"
 
+#ifndef O_CLOEXEC
+#define O_CLOEXEC      0
+#endif
+
 /*
  * Linux and FreeBSD plug this obvious hole in POSIX.1e in
  * different ways.
@@ -114,7 +117,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_disk_entry_from_file.c 2010
 #define        ACL_GET_PERM acl_get_perm_np
 #endif
 
-static int setup_acls_posix1e(struct archive_read_disk *,
+static int setup_acls(struct archive_read_disk *,
     struct archive_entry *, int *fd);
 static int setup_mac_metadata(struct archive_read_disk *,
     struct archive_entry *, int *fd);
@@ -168,15 +171,16 @@ archive_read_disk_entry_from_file(struct archive *_a,
                        st = &s;
                }
                archive_entry_copy_stat(entry, st);
-               /* Lookup uname/gname */
-               name = archive_read_disk_uname(_a, archive_entry_uid(entry));
-               if (name != NULL)
-                       archive_entry_copy_uname(entry, name);
-               name = archive_read_disk_gname(_a, archive_entry_gid(entry));
-               if (name != NULL)
-                       archive_entry_copy_gname(entry, name);
        }
 
+       /* Lookup uname/gname */
+       name = archive_read_disk_uname(_a, archive_entry_uid(entry));
+       if (name != NULL)
+               archive_entry_copy_uname(entry, name);
+       name = archive_read_disk_gname(_a, archive_entry_gid(entry));
+       if (name != NULL)
+               archive_entry_copy_gname(entry, name);
+
 #ifdef HAVE_STRUCT_STAT_ST_FLAGS
        /* On FreeBSD, we get flags for free with the stat. */
        /* TODO: Does this belong in copy_stat()? */
@@ -192,12 +196,14 @@ archive_read_disk_entry_from_file(struct archive *_a,
                if (fd < 0) {
                        if (a->tree != NULL)
                                fd = a->open_on_current_dir(a->tree, path,
-                                       O_RDONLY | O_NONBLOCK);
+                                       O_RDONLY | O_NONBLOCK | O_CLOEXEC);
                        else
-                               fd = open(path, O_RDONLY | O_NONBLOCK);
+                               fd = open(path, O_RDONLY | O_NONBLOCK |
+                                               O_CLOEXEC);
+                       __archive_ensure_cloexec_flag(fd);
                }
                if (fd >= 0) {
-                       unsigned long stflags;
+                       int stflags;
                        r = ioctl(fd, EXT2_IOC_GETFLAGS, &stflags);
                        if (r == 0 && stflags != 0)
                                archive_entry_set_fflags(entry, stflags, 0);
@@ -244,7 +250,7 @@ archive_read_disk_entry_from_file(struct archive *_a,
        }
 #endif /* HAVE_READLINK || HAVE_READLINKAT */
 
-       r = setup_acls_posix1e(a, entry, &fd);
+       r = setup_acls(a, entry, &fd);
        r1 = setup_xattrs(a, entry, &fd);
        if (r1 < r)
                r = r1;
@@ -285,9 +291,10 @@ setup_mac_metadata(struct archive_read_disk *a,
        int copyfile_flags = COPYFILE_NOFOLLOW | COPYFILE_ACL | COPYFILE_XATTR;
        struct stat copyfile_stat;
        int ret = ARCHIVE_OK;
-       void *buff;
+       void *buff = NULL;
        int have_attrs;
-       const char *name, *tempdir, *tempfile = NULL;
+       const char *name, *tempdir;
+       struct archive_string tempfile;
 
        (void)fd; /* UNUSED */
        name = archive_entry_sourcepath(entry);
@@ -322,25 +329,28 @@ setup_mac_metadata(struct archive_read_disk *a,
                tempdir = getenv("TMPDIR");
        if (tempdir == NULL)
                tempdir = _PATH_TMP;
-       tempfile = tempnam(tempdir, "tar.md.");
+       archive_string_init(&tempfile);
+       archive_strcpy(&tempfile, tempdir);
+       archive_strcat(&tempfile, "tar.md.XXXXXX");
+       tempfd = mkstemp(tempfile.s);
+       if (tempfd < 0) {
+               archive_set_error(&a->archive, errno,
+                   "Could not open extended attribute file");
+               ret = ARCHIVE_WARN;
+               goto cleanup;
+       }
+       __archive_ensure_cloexec_flag(tempfd);
 
        /* XXX I wish copyfile() could pack directly to a memory
         * buffer; that would avoid the temp file here.  For that
         * matter, it would be nice if fcopyfile() actually worked,
         * that would reduce the many open/close races here. */
-       if (copyfile(name, tempfile, 0, copyfile_flags | COPYFILE_PACK)) {
+       if (copyfile(name, tempfile.s, 0, copyfile_flags | COPYFILE_PACK)) {
                archive_set_error(&a->archive, errno,
                    "Could not pack extended attributes");
                ret = ARCHIVE_WARN;
                goto cleanup;
        }
-       tempfd = open(tempfile, O_RDONLY);
-       if (tempfd < 0) {
-               archive_set_error(&a->archive, errno,
-                   "Could not open extended attribute file");
-               ret = ARCHIVE_WARN;
-               goto cleanup;
-       }
        if (fstat(tempfd, &copyfile_stat)) {
                archive_set_error(&a->archive, errno,
                    "Could not check size of extended attributes");
@@ -363,10 +373,12 @@ setup_mac_metadata(struct archive_read_disk *a,
        archive_entry_copy_mac_metadata(entry, buff, copyfile_stat.st_size);
 
 cleanup:
-       if (tempfd >= 0)
+       if (tempfd >= 0) {
                close(tempfd);
-       if (tempfile != NULL)
-               unlink(tempfile);
+               unlink(tempfile.s);
+       }
+       archive_string_free(&tempfile);
+       free(buff);
        return (ret);
 }
 
@@ -387,16 +399,19 @@ setup_mac_metadata(struct archive_read_disk *a,
 #endif
 
 
-#ifdef HAVE_POSIX_ACL
-static void setup_acl_posix1e(struct archive_read_disk *a,
+#if defined(HAVE_POSIX_ACL) && defined(ACL_TYPE_NFS4)
+static int translate_acl(struct archive_read_disk *a,
     struct archive_entry *entry, acl_t acl, int archive_entry_acl_type);
 
 static int
-setup_acls_posix1e(struct archive_read_disk *a,
+setup_acls(struct archive_read_disk *a,
     struct archive_entry *entry, int *fd)
 {
        const char      *accpath;
        acl_t            acl;
+#if HAVE_ACL_IS_TRIVIAL_NP
+       int             r;
+#endif
 
        accpath = archive_entry_sourcepath(entry);
        if (accpath == NULL)
@@ -404,15 +419,33 @@ setup_acls_posix1e(struct archive_read_disk *a,
 
        archive_entry_acl_clear(entry);
 
-       if (*fd < 0 && a->tree != NULL &&
-           (a->follow_symlinks || archive_entry_filetype(entry) != AE_IFLNK)){
-               *fd = a->open_on_current_dir(a->tree, accpath,
-                               O_RDONLY | O_NONBLOCK);
-               if (*fd < 0) {
-                       archive_set_error(&a->archive, errno,
-                           "Couldn't access %s", accpath);
-                       return (ARCHIVE_FAILED);
-               }
+       /* Try NFS4 ACL first. */
+       if (*fd >= 0)
+               acl = acl_get_fd(*fd);
+#if HAVE_ACL_GET_LINK_NP
+       else if (!a->follow_symlinks)
+               acl = acl_get_link_np(accpath, ACL_TYPE_NFS4);
+#else
+       else if ((!a->follow_symlinks)
+           && (archive_entry_filetype(entry) == AE_IFLNK))
+               /* We can't get the ACL of a symlink, so we assume it can't
+                  have one. */
+               acl = NULL;
+#endif
+       else
+               acl = acl_get_file(accpath, ACL_TYPE_NFS4);
+#if HAVE_ACL_IS_TRIVIAL_NP
+       /* Ignore "trivial" ACLs that just mirror the file mode. */
+       acl_is_trivial_np(acl, &r);
+       if (r) {
+               acl_free(acl);
+               acl = NULL;
+       }
+#endif
+       if (acl != NULL) {
+               translate_acl(a, entry, acl, ARCHIVE_ENTRY_ACL_TYPE_NFS4);
+               acl_free(acl);
+               return (ARCHIVE_OK);
        }
 
        /* Retrieve access ACL from file. */
@@ -431,7 +464,7 @@ setup_acls_posix1e(struct archive_read_disk *a,
        else
                acl = acl_get_file(accpath, ACL_TYPE_ACCESS);
        if (acl != NULL) {
-               setup_acl_posix1e(a, entry, acl,
+               translate_acl(a, entry, acl,
                    ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
                acl_free(acl);
        }
@@ -440,7 +473,7 @@ setup_acls_posix1e(struct archive_read_disk *a,
        if (S_ISDIR(archive_entry_mode(entry))) {
                acl = acl_get_file(accpath, ACL_TYPE_DEFAULT);
                if (acl != NULL) {
-                       setup_acl_posix1e(a, entry, acl,
+                       translate_acl(a, entry, acl,
                            ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
                        acl_free(acl);
                }
@@ -449,68 +482,180 @@ setup_acls_posix1e(struct archive_read_disk *a,
 }
 
 /*
- * Translate POSIX.1e ACL into libarchive internal structure.
+ * Translate system ACL into libarchive internal structure.
  */
-static void
-setup_acl_posix1e(struct archive_read_disk *a,
-    struct archive_entry *entry, acl_t acl, int archive_entry_acl_type)
+
+static struct {
+        int archive_perm;
+        int platform_perm;
+} acl_perm_map[] = {
+        {ARCHIVE_ENTRY_ACL_EXECUTE, ACL_EXECUTE},
+        {ARCHIVE_ENTRY_ACL_WRITE, ACL_WRITE},
+        {ARCHIVE_ENTRY_ACL_READ, ACL_READ},
+        {ARCHIVE_ENTRY_ACL_READ_DATA, ACL_READ_DATA},
+        {ARCHIVE_ENTRY_ACL_LIST_DIRECTORY, ACL_LIST_DIRECTORY},
+        {ARCHIVE_ENTRY_ACL_WRITE_DATA, ACL_WRITE_DATA},
+        {ARCHIVE_ENTRY_ACL_ADD_FILE, ACL_ADD_FILE},
+        {ARCHIVE_ENTRY_ACL_APPEND_DATA, ACL_APPEND_DATA},
+        {ARCHIVE_ENTRY_ACL_ADD_SUBDIRECTORY, ACL_ADD_SUBDIRECTORY},
+        {ARCHIVE_ENTRY_ACL_READ_NAMED_ATTRS, ACL_READ_NAMED_ATTRS},
+        {ARCHIVE_ENTRY_ACL_WRITE_NAMED_ATTRS, ACL_WRITE_NAMED_ATTRS},
+        {ARCHIVE_ENTRY_ACL_DELETE_CHILD, ACL_DELETE_CHILD},
+        {ARCHIVE_ENTRY_ACL_READ_ATTRIBUTES, ACL_READ_ATTRIBUTES},
+        {ARCHIVE_ENTRY_ACL_WRITE_ATTRIBUTES, ACL_WRITE_ATTRIBUTES},
+        {ARCHIVE_ENTRY_ACL_DELETE, ACL_DELETE},
+        {ARCHIVE_ENTRY_ACL_READ_ACL, ACL_READ_ACL},
+        {ARCHIVE_ENTRY_ACL_WRITE_ACL, ACL_WRITE_ACL},
+        {ARCHIVE_ENTRY_ACL_WRITE_OWNER, ACL_WRITE_OWNER},
+        {ARCHIVE_ENTRY_ACL_SYNCHRONIZE, ACL_SYNCHRONIZE}
+};
+
+static struct {
+        int archive_inherit;
+        int platform_inherit;
+} acl_inherit_map[] = {
+        {ARCHIVE_ENTRY_ACL_ENTRY_FILE_INHERIT, ACL_ENTRY_FILE_INHERIT},
+       {ARCHIVE_ENTRY_ACL_ENTRY_DIRECTORY_INHERIT, ACL_ENTRY_DIRECTORY_INHERIT},
+       {ARCHIVE_ENTRY_ACL_ENTRY_NO_PROPAGATE_INHERIT, ACL_ENTRY_NO_PROPAGATE_INHERIT},
+       {ARCHIVE_ENTRY_ACL_ENTRY_INHERIT_ONLY, ACL_ENTRY_INHERIT_ONLY}
+};
+
+static int
+translate_acl(struct archive_read_disk *a,
+    struct archive_entry *entry, acl_t acl, int default_entry_acl_type)
 {
        acl_tag_t        acl_tag;
+       acl_entry_type_t acl_type;
+       acl_flagset_t    acl_flagset;
        acl_entry_t      acl_entry;
        acl_permset_t    acl_permset;
+       int              brand, i, r, entry_acl_type;
        int              s, ae_id, ae_tag, ae_perm;
        const char      *ae_name;
 
+
+       // FreeBSD "brands" ACLs as POSIX.1e or NFSv4
+       // Make sure the "brand" on this ACL is consistent
+       // with the default_entry_acl_type bits provided.
+       acl_get_brand_np(acl, &brand);
+       switch (brand) {
+       case ACL_BRAND_POSIX:
+               switch (default_entry_acl_type) {
+               case ARCHIVE_ENTRY_ACL_TYPE_ACCESS:
+               case ARCHIVE_ENTRY_ACL_TYPE_DEFAULT:
+                       break;
+               default:
+                       // XXX set warning message?
+                       return ARCHIVE_FAILED;
+               }
+               break;
+       case ACL_BRAND_NFS4:
+               if (default_entry_acl_type & ~ARCHIVE_ENTRY_ACL_TYPE_NFS4) {
+                       // XXX set warning message?
+                       return ARCHIVE_FAILED;
+               }
+               break;
+       default:
+               // XXX set warning message?
+               return ARCHIVE_FAILED;
+               break;
+       }
+
+
        s = acl_get_entry(acl, ACL_FIRST_ENTRY, &acl_entry);
        while (s == 1) {
                ae_id = -1;
                ae_name = NULL;
+               ae_perm = 0;
 
                acl_get_tag_type(acl_entry, &acl_tag);
-               if (acl_tag == ACL_USER) {
+               switch (acl_tag) {
+               case ACL_USER:
                        ae_id = (int)*(uid_t *)acl_get_qualifier(acl_entry);
                        ae_name = archive_read_disk_uname(&a->archive, ae_id);
                        ae_tag = ARCHIVE_ENTRY_ACL_USER;
-               } else if (acl_tag == ACL_GROUP) {
+                       break;
+               case ACL_GROUP:
                        ae_id = (int)*(gid_t *)acl_get_qualifier(acl_entry);
                        ae_name = archive_read_disk_gname(&a->archive, ae_id);
                        ae_tag = ARCHIVE_ENTRY_ACL_GROUP;
-               } else if (acl_tag == ACL_MASK) {
+                       break;
+               case ACL_MASK:
                        ae_tag = ARCHIVE_ENTRY_ACL_MASK;
-               } else if (acl_tag == ACL_USER_OBJ) {
+                       break;
+               case ACL_USER_OBJ:
                        ae_tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
-               } else if (acl_tag == ACL_GROUP_OBJ) {
+                       break;
+               case ACL_GROUP_OBJ:
                        ae_tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
-               } else if (acl_tag == ACL_OTHER) {
+                       break;
+               case ACL_OTHER:
                        ae_tag = ARCHIVE_ENTRY_ACL_OTHER;
-               } else {
+                       break;
+               case ACL_EVERYONE:
+                       ae_tag = ARCHIVE_ENTRY_ACL_EVERYONE;
+                       break;
+               default:
                        /* Skip types that libarchive can't support. */
+                       s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
                        continue;
                }
 
-               acl_get_permset(acl_entry, &acl_permset);
-               ae_perm = 0;
+               // XXX acl type maps to allow/deny/audit/YYYY bits
+               // XXX acl_get_entry_type_np on FreeBSD returns EINVAL for
+               // non-NFSv4 ACLs
+               entry_acl_type = default_entry_acl_type;
+               r = acl_get_entry_type_np(acl_entry, &acl_type);
+               if (r == 0) {
+                       switch (acl_type) {
+                       case ACL_ENTRY_TYPE_ALLOW:
+                               entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALLOW;
+                               break;
+                       case ACL_ENTRY_TYPE_DENY:
+                               entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_DENY;
+                               break;
+                       case ACL_ENTRY_TYPE_AUDIT:
+                               entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_AUDIT;
+                               break;
+                       case ACL_ENTRY_TYPE_ALARM:
+                               entry_acl_type = ARCHIVE_ENTRY_ACL_TYPE_ALARM;
+                               break;
+                       }
+               }
+
                /*
-                * acl_get_perm() is spelled differently on different
-                * platforms; see above.
+                * Libarchive stores "flag" (NFSv4 inheritance bits)
+                * in the ae_perm bitmap.
                 */
-               if (ACL_GET_PERM(acl_permset, ACL_EXECUTE))
-                       ae_perm |= ARCHIVE_ENTRY_ACL_EXECUTE;
-               if (ACL_GET_PERM(acl_permset, ACL_READ))
-                       ae_perm |= ARCHIVE_ENTRY_ACL_READ;
-               if (ACL_GET_PERM(acl_permset, ACL_WRITE))
-                       ae_perm |= ARCHIVE_ENTRY_ACL_WRITE;
+               acl_get_flagset_np(acl_entry, &acl_flagset);
+                for (i = 0; i < (int)(sizeof(acl_inherit_map) / sizeof(acl_inherit_map[0])); ++i) {
+                       if (acl_get_flag_np(acl_flagset,
+                                           acl_inherit_map[i].platform_inherit))
+                               ae_perm |= acl_inherit_map[i].archive_inherit;
 
-               archive_entry_acl_add_entry(entry,
-                   archive_entry_acl_type, ae_perm, ae_tag,
-                   ae_id, ae_name);
+                }
+
+               acl_get_permset(acl_entry, &acl_permset);
+                for (i = 0; i < (int)(sizeof(acl_perm_map) / sizeof(acl_perm_map[0])); ++i) {
+                       /*
+                        * acl_get_perm() is spelled differently on different
+                        * platforms; see above.
+                        */
+                       if (ACL_GET_PERM(acl_permset, acl_perm_map[i].platform_perm))
+                               ae_perm |= acl_perm_map[i].archive_perm;
+               }
+
+               archive_entry_acl_add_entry(entry, entry_acl_type,
+                                           ae_perm, ae_tag,
+                                           ae_id, ae_name);
 
                s = acl_get_entry(acl, ACL_NEXT_ENTRY, &acl_entry);
        }
+       return (ARCHIVE_OK);
 }
 #else
 static int
-setup_acls_posix1e(struct archive_read_disk *a,
+setup_acls(struct archive_read_disk *a,
     struct archive_entry *entry, int *fd)
 {
        (void)a;      /* UNUSED */
@@ -901,16 +1046,19 @@ setup_sparse(struct archive_read_disk *a,
                        path = archive_entry_pathname(entry);
                if (a->tree != NULL)
                        *fd = a->open_on_current_dir(a->tree, path,
-                               O_RDONLY | O_NONBLOCK);
+                               O_RDONLY | O_NONBLOCK | O_CLOEXEC);
                else
-                       *fd = open(path, O_RDONLY | O_NONBLOCK);
+                       *fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
                if (*fd < 0) {
                        archive_set_error(&a->archive, errno,
                            "Can't open `%s'", path);
                        return (ARCHIVE_FAILED);
                }
+               __archive_ensure_cloexec_flag(*fd);
        }
 
+       /* Initialize buffer to avoid the error valgrind complains about. */
+       memset(buff, 0, sizeof(buff));
        count = (sizeof(buff) - sizeof(*fm))/sizeof(*fe);
        fm = (struct fiemap *)buff;
        fm->fm_start = 0;
@@ -1012,12 +1160,13 @@ setup_sparse(struct archive_read_disk *a,
                        
                if (pathconf(path, _PC_MIN_HOLE_SIZE) <= 0)
                        return (ARCHIVE_OK);
-               *fd = open(path, O_RDONLY | O_NONBLOCK);
+               *fd = open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC);
                if (*fd < 0) {
                        archive_set_error(&a->archive, errno,
                            "Can't open `%s'", path);
                        return (ARCHIVE_FAILED);
                }
+               __archive_ensure_cloexec_flag(*fd);
                initial_off = 0;
        }
 
index 698600e..a13dbbf 100644 (file)
@@ -105,6 +105,9 @@ __FBSDID("$FreeBSD$");
 #ifndef O_BINARY
 #define O_BINARY       0
 #endif
+#ifndef O_CLOEXEC
+#define O_CLOEXEC      0
+#endif
 
 /*-
  * This is a new directory-walking system that addresses a number
@@ -361,6 +364,7 @@ static int  setup_sparse(struct archive_read_disk *, struct archive_entry *);
 static int     close_and_restore_time(int fd, struct tree *,
                    struct restore_time *);
 static int     open_on_current_dir(struct tree *, const char *, int);
+static int     tree_dup(int);
 
 
 static struct archive_vtable *
@@ -717,7 +721,7 @@ _archive_read_data_block(struct archive *_a, const void **buff,
         * Open the current file.
         */
        if (t->entry_fd < 0) {
-               int flags = O_RDONLY | O_BINARY;
+               int flags = O_RDONLY | O_BINARY | O_CLOEXEC;
 
                /*
                 * Eliminate or reduce cache effects if we can.
@@ -740,6 +744,7 @@ _archive_read_data_block(struct archive *_a, const void **buff,
 #endif
                        t->entry_fd = open_on_current_dir(t,
                            tree_current_access_path(t), flags);
+                       __archive_ensure_cloexec_flag(t->entry_fd);
 #if defined(O_NOATIME)
                        /*
                         * When we did open the file with O_NOATIME flag,
@@ -984,10 +989,12 @@ next_entry(struct archive_read_disk *a, struct tree *t,
 #elif defined(EXT2_IOC_GETFLAGS) && defined(EXT2_NODUMP_FL) &&\
       defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)
                if (S_ISREG(st->st_mode) || S_ISDIR(st->st_mode)) {
-                       unsigned long stflags;
+                       int stflags;
 
                        t->entry_fd = open_on_current_dir(t,
-                           tree_current_access_path(t), O_RDONLY | O_NONBLOCK);
+                           tree_current_access_path(t),
+                           O_RDONLY | O_NONBLOCK | O_CLOEXEC);
+                       __archive_ensure_cloexec_flag(t->entry_fd);
                        if (t->entry_fd >= 0) {
                                r = ioctl(t->entry_fd, EXT2_IOC_GETFLAGS,
                                        &stflags);
@@ -1359,15 +1366,17 @@ update_current_filesystem(struct archive_read_disk *a, int64_t dev)
        fid = t->max_filesystem_id++;
        if (t->max_filesystem_id > t->allocated_filesytem) {
                size_t s;
+               void *p;
 
                s = t->max_filesystem_id * 2;
-               t->filesystem_table = realloc(t->filesystem_table,
-                   s * sizeof(*t->filesystem_table));
-               if (t->filesystem_table == NULL) {
+               p = realloc(t->filesystem_table,
+                       s * sizeof(*t->filesystem_table));
+               if (p == NULL) {
                        archive_set_error(&a->archive, ENOMEM,
                            "Can't allocate tar data");
                        return (ARCHIVE_FATAL);
                }
+               t->filesystem_table = (struct filesystem *)p;
                t->allocated_filesytem = s;
        }
        t->current_filesystem_id = fid;
@@ -1482,7 +1491,8 @@ setup_current_filesystem(struct archive_read_disk *a)
                 * where current is.
                 */
                int fd = openat(tree_current_dir_fd(t),
-                   tree_current_access_path(t), O_RDONLY);
+                   tree_current_access_path(t), O_RDONLY | O_CLOEXEC);
+               __archive_ensure_cloexec_flag(fd);
                if (fd < 0) {
                        archive_set_error(&a->archive, errno,
                            "openat failed");
@@ -1660,7 +1670,8 @@ setup_current_filesystem(struct archive_read_disk *a)
                 * where current is.
                 */
                int fd = openat(tree_current_dir_fd(t),
-                   tree_current_access_path(t), O_RDONLY);
+                   tree_current_access_path(t), O_RDONLY | O_CLOEXEC);
+               __archive_ensure_cloexec_flag(fd);
                if (fd < 0) {
                        archive_set_error(&a->archive, errno,
                            "openat failed");
@@ -1768,7 +1779,8 @@ setup_current_filesystem(struct archive_read_disk *a)
                 * where current is.
                 */
                int fd = openat(tree_current_dir_fd(t),
-                   tree_current_access_path(t), O_RDONLY);
+                   tree_current_access_path(t), O_RDONLY | O_CLOEXEC);
+               __archive_ensure_cloexec_flag(fd);
                if (fd < 0) {
                        archive_set_error(&a->archive, errno,
                            "openat failed");
@@ -1889,7 +1901,8 @@ static int
 close_and_restore_time(int fd, struct tree *t, struct restore_time *rt)
 {
 #ifndef HAVE_UTIMES
-       (void)a; /* UNUSED */
+       (void)t; /* UNUSED */
+       (void)rt; /* UNUSED */
        return (close(fd));
 #else
 #if defined(HAVE_FUTIMENS) && !defined(__CYGWIN__)
@@ -1952,6 +1965,28 @@ open_on_current_dir(struct tree *t, const char *path, int flags)
 #endif
 }
 
+static int
+tree_dup(int fd)
+{
+       int new_fd;
+#ifdef F_DUPFD_CLOEXEC
+       static volatile int can_dupfd_cloexec = 1;
+
+       if (can_dupfd_cloexec) {
+               new_fd = fcntl(fd, F_DUPFD_CLOEXEC);
+               if (new_fd != -1)
+                       return (new_fd);
+               /* Linux 2.6.18 - 2.6.23 declare F_DUPFD_CLOEXEC,
+                * but it cannot be used. So we have to try dup(). */
+               /* We won't try F_DUPFD_CLOEXEC. */
+               can_dupfd_cloexec = 0;
+       }
+#endif /* F_DUPFD_CLOEXEC */
+       new_fd = dup(fd);
+       __archive_ensure_cloexec_flag(new_fd);
+       return (new_fd);
+}
+
 /*
  * Add a directory path to the current stack.
  */
@@ -2052,8 +2087,9 @@ tree_reopen(struct tree *t, const char *path, int restore_time)
        tree_push(t, path, 0, 0, 0, NULL);
        t->stack->flags = needsFirstVisit;
        t->maxOpenCount = t->openCount = 1;
-       t->initial_dir_fd = open(".", O_RDONLY);
-       t->working_dir_fd = dup(t->initial_dir_fd);
+       t->initial_dir_fd = open(".", O_RDONLY | O_CLOEXEC);
+       __archive_ensure_cloexec_flag(t->initial_dir_fd);
+       t->working_dir_fd = tree_dup(t->initial_dir_fd);
        return (t);
 }
 
@@ -2063,11 +2099,12 @@ tree_descent(struct tree *t)
        int flag, new_fd, r = 0;
 
        t->dirname_length = archive_strlen(&t->path);
-       flag = O_RDONLY;
+       flag = O_RDONLY | O_CLOEXEC;
 #if defined(O_DIRECTORY)
        flag |= O_DIRECTORY;
 #endif
        new_fd = open_on_current_dir(t, t->stack->name.s, flag);
+       __archive_ensure_cloexec_flag(new_fd);
        if (new_fd < 0) {
                t->tree_errno = errno;
                r = TREE_ERROR_DIR;
@@ -2101,8 +2138,10 @@ tree_ascend(struct tree *t)
        prev_dir_fd = t->working_dir_fd;
        if (te->flags & isDirLink)
                new_fd = te->symlink_parent_fd;
-       else
-               new_fd = open_on_current_dir(t, "..", O_RDONLY);
+       else {
+               new_fd = open_on_current_dir(t, "..", O_RDONLY | O_CLOEXEC);
+               __archive_ensure_cloexec_flag(new_fd);
+       }
        if (new_fd < 0) {
                t->tree_errno = errno;
                r = TREE_ERROR_FATAL;
@@ -2265,11 +2304,16 @@ tree_dir_next_posix(struct tree *t)
 #endif
 
 #if defined(HAVE_FDOPENDIR)
-               if ((t->d = fdopendir(dup(t->working_dir_fd))) == NULL) {
-#else
-               if (tree_enter_working_dir(t) != 0 ||
-                   (t->d = opendir(".")) == NULL) {
+               t->d = fdopendir(tree_dup(t->working_dir_fd));
+#else /* HAVE_FDOPENDIR */
+               if (tree_enter_working_dir(t) == 0) {
+                       t->d = opendir(".");
+#if HAVE_DIRFD || defined(dirfd)
+                       __archive_ensure_cloexec_flag(dirfd(t->d));
 #endif
+               }
+#endif /* HAVE_FDOPENDIR */
+               if (t->d == NULL) {
                        r = tree_ascend(t); /* Undo "chdir" */
                        tree_pop(t);
                        t->tree_errno = errno;
@@ -2296,11 +2340,21 @@ tree_dir_next_posix(struct tree *t)
 #endif /* HAVE_READDIR_R */
        }
        for (;;) {
+               errno = 0;
 #if defined(HAVE_READDIR_R)
                r = readdir_r(t->d, t->dirent, &t->de);
+#ifdef _AIX
+               /* Note: According to the man page, return value 9 indicates
+                * that the readdir_r was not successful and the error code
+                * is set to the global errno variable. And then if the end
+                * of directory entries was reached, the return value is 9
+                * and the third parameter is set to NULL and errno is
+                * unchanged. */
+               if (r == 9)
+                       r = errno;
+#endif /* _AIX */
                if (r != 0 || t->de == NULL) {
 #else
-               errno = 0;
                t->de = readdir(t->d);
                if (t->de == NULL) {
                        r = errno;
@@ -2391,7 +2445,7 @@ tree_current_is_dir(struct tree *t)
                        return 1;
                /* Not a dir; might be a link to a dir. */
                /* If it's not a link, then it's not a link to a dir. */
-               if (!S_ISLNK(tree_current_lstat(t)->st_mode))
+               if (!S_ISLNK(st->st_mode))
                        return 0;
                /*
                 * It's a link, but we don't know what it's a link to,
diff --git a/contrib/libarchive/libarchive/archive_read_extract.3 b/contrib/libarchive/libarchive/archive_read_extract.3
new file mode 100644 (file)
index 0000000..6ec0ced
--- /dev/null
@@ -0,0 +1,137 @@
+.\" Copyright (c) 2003-2011 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 2, 2012
+.Dt ARCHIVE_READ_EXTRACT 3
+.Os
+.Sh NAME
+.Nm archive_read_extract ,
+.Nm archive_read_extract2 ,
+.Nm archive_read_extract_set_progress_callback
+.Nd functions for reading streaming archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
+.Sh SYNOPSIS
+.In archive.h
+.Ft int
+.Fo archive_read_extract
+.Fa "struct archive *"
+.Fa "struct archive_entry *"
+.Fa "int flags"
+.Fc
+.Ft int
+.Fo archive_read_extract2
+.Fa "struct archive *src"
+.Fa "struct archive_entry *"
+.Fa "struct archive *dest"
+.Fc
+.Ft void
+.Fo archive_read_extract_set_progress_callback
+.Fa "struct archive *"
+.Fa "void (*func)(void *)"
+.Fa "void *user_data"
+.Fc
+.Sh DESCRIPTION
+.Bl -tag -compact -width indent
+.It Fn archive_read_extract , Fn archive_read_extract_set_skip_file
+A convenience function that wraps the corresponding
+.Xr archive_write_disk 3
+interfaces.
+The first call to
+.Fn archive_read_extract
+creates a restore object using
+.Xr archive_write_disk_new 3
+and
+.Xr archive_write_disk_set_standard_lookup 3 ,
+then transparently invokes
+.Xr archive_write_disk_set_options 3 ,
+.Xr archive_write_header 3 ,
+.Xr archive_write_data 3 ,
+and
+.Xr archive_write_finish_entry 3
+to create the entry on disk and copy data into it.
+The
+.Va flags
+argument is passed unmodified to
+.Xr archive_write_disk_set_options 3 .
+.It Fn archive_read_extract2
+This is another version of
+.Fn archive_read_extract
+that allows you to provide your own restore object.
+In particular, this allows you to override the standard lookup functions
+using
+.Xr archive_write_disk_set_group_lookup 3 ,
+and
+.Xr archive_write_disk_set_user_lookup 3 .
+Note that
+.Fn archive_read_extract2
+does not accept a
+.Va flags
+argument; you should use
+.Fn archive_write_disk_set_options
+to set the restore options yourself.
+.It Fn archive_read_extract_set_progress_callback
+Sets a pointer to a user-defined callback that can be used
+for updating progress displays during extraction.
+The progress function will be invoked during the extraction of large
+regular files.
+The progress function will be invoked with the pointer provided to this call.
+Generally, the data pointed to should include a reference to the archive
+object and the archive_entry object so that various statistics
+can be retrieved for the progress display.
+.El
+.\"
+.Sh RETURN VALUES
+Most functions return zero on success, non-zero on error.
+The possible return codes include:
+.Cm ARCHIVE_OK
+(the operation succeeded),
+.Cm ARCHIVE_WARN
+(the operation succeeded but a non-critical error was encountered),
+.Cm ARCHIVE_EOF
+(end-of-archive was encountered),
+.Cm ARCHIVE_RETRY
+(the operation failed but can be retried),
+and
+.Cm ARCHIVE_FATAL
+(there was a fatal error; the archive should be closed immediately).
+.Sh ERRORS
+Detailed error codes and textual descriptions are available from the
+.Fn archive_errno
+and
+.Fn archive_error_string
+functions.
+.Sh SEE ALSO
+.Xr tar 1 ,
+.Xr libarchive 3 ,
+.Xr archive_read 3 ,
+.Xr archive_read_data 3 ,
+.Xr archive_read_filter 3 ,
+.Xr archive_read_format 3 ,
+.Xr archive_read_open 3 ,
+.Xr archive_read_set_options 3 ,
+.Xr archive_util 3 ,
+.Xr tar 5
index aad8ac5..795f2ab 100644 (file)
@@ -154,7 +154,7 @@ copy_data(struct archive *ar, struct archive *aw)
                        return (ARCHIVE_OK);
                if (r != ARCHIVE_OK)
                        return (r);
-               r = archive_write_data_block(aw, buff, size, offset);
+               r = (int)archive_write_data_block(aw, buff, size, offset);
                if (r < ARCHIVE_WARN)
                        r = ARCHIVE_WARN;
                if (r != ARCHIVE_OK) {
diff --git a/contrib/libarchive/libarchive/archive_read_filter.3 b/contrib/libarchive/libarchive/archive_read_filter.3
new file mode 100644 (file)
index 0000000..8761127
--- /dev/null
@@ -0,0 +1,129 @@
+.\" Copyright (c) 2003-2011 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 2, 2012
+.Dt ARCHIVE_READ_FILTER 3
+.Os
+.Sh NAME
+.Nm archive_read_support_filter_all ,
+.Nm archive_read_support_filter_bzip2 ,
+.Nm archive_read_support_filter_compress ,
+.Nm archive_read_support_filter_gzip ,
+.Nm archive_read_support_filter_lzma ,
+.Nm archive_read_support_filter_none ,
+.Nm archive_read_support_filter_xz ,
+.Nm archive_read_support_filter_program ,
+.Nm archive_read_support_filter_program_signature
+.Nd functions for reading streaming archives
+.\"
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
+.Sh SYNOPSIS
+.In archive.h
+.Ft int
+.Fn archive_read_support_filter_all "struct archive *"
+.Ft int
+.Fn archive_read_support_filter_bzip2 "struct archive *"
+.Ft int
+.Fn archive_read_support_filter_compress "struct archive *"
+.Ft int
+.Fn archive_read_support_filter_gzip "struct archive *"
+.Ft int
+.Fn archive_read_support_filter_lzma "struct archive *"
+.Ft int
+.Fn archive_read_support_filter_none "struct archive *"
+.Ft int
+.Fn archive_read_support_filter_xz "struct archive *"
+.Ft int
+.Fo archive_read_support_filter_program
+.Fa "struct archive *"
+.Fa "const char *cmd"
+.Fc
+.Ft int
+.Fo archive_read_support_filter_program_signature
+.Fa "struct archive *"
+.Fa "const char *cmd"
+.Fa "const void *signature"
+.Fa "size_t signature_length"
+.Fc
+.\"
+.Sh DESCRIPTION
+.Bl -tag -compact -width indent
+.It Xo
+.Fn archive_read_support_filter_bzip2 ,
+.Fn archive_read_support_filter_compress ,
+.Fn archive_read_support_filter_gzip ,
+.Fn archive_read_support_filter_lzma ,
+.Fn archive_read_support_filter_none ,
+.Fn archive_read_support_filter_xz
+.Xc
+Enables auto-detection code and decompression support for the
+specified compression.
+These functions may fall back on external programs if an appropriate
+library was not available at build time.
+Decompression using an external program is usually slower than
+decompression through built-in libraries.
+Note that
+.Dq none
+is always enabled by default.
+.It Fn archive_read_support_filter_all
+Enables all available decompression filters.
+.It Fn archive_read_support_filter_program
+Data is fed through the specified external program before being dearchived.
+Note that this disables automatic detection of the compression format,
+so it makes no sense to specify this in conjunction with any other
+decompression option.
+.It Fn archive_read_support_filter_program_signature
+This feeds data through the specified external program
+but only if the initial bytes of the data match the specified
+signature value.
+.El
+.\"
+.\". Sh EXAMPLE
+.\"
+.Sh RETURN VALUES
+These functions return
+.Cm ARCHIVE_OK
+if the compression is fully supported,
+.Cm ARCHIVE_WARN
+if the compression is supported only through an external program.
+.Pp
+.Fn archive_read_support_filter_none
+always succeeds.
+.\"
+.Sh ERRORS
+Detailed error codes and textual descriptions are available from the
+.Fn archive_errno
+and
+.Fn archive_error_string
+functions.
+.\"
+.Sh SEE ALSO
+.Xr libarchive 3 ,
+.Xr archive_read 3 ,
+.Xr archive_read_data 3 ,
+.Xr archive_read_format 3 ,
+.Xr archive_read_format 3
diff --git a/contrib/libarchive/libarchive/archive_read_format.3 b/contrib/libarchive/libarchive/archive_read_format.3
new file mode 100644 (file)
index 0000000..53b9a7e
--- /dev/null
@@ -0,0 +1,177 @@
+.\" Copyright (c) 2003-2011 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 2, 2012
+.Dt ARCHIVE_READ_FORMAT 3
+.Os
+.Sh NAME
+.Nm archive_read_support_format_7zip ,
+.Nm archive_read_support_format_all ,
+.Nm archive_read_support_format_ar ,
+.Nm archive_read_support_format_by_code ,
+.Nm archive_read_support_format_cab ,
+.Nm archive_read_support_format_cpio ,
+.Nm archive_read_support_format_empty ,
+.Nm archive_read_support_format_iso9660 ,
+.Nm archive_read_support_format_lha ,
+.Nm archive_read_support_format_mtree,
+.Nm archive_read_support_format_rar,
+.Nm archive_read_support_format_raw,
+.Nm archive_read_support_format_tar ,
+.Nm archive_read_support_format_xar ,
+.Nm archive_read_support_format_zip
+.Nd functions for reading streaming archives
+.\"
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
+.Sh SYNOPSIS
+.In archive.h
+.Ft int
+.Fn archive_read_support_format_7zip "struct archive *"
+.Ft int
+.Fn archive_read_support_format_all "struct archive *"
+.Ft int
+.Fn archive_read_support_format_ar "struct archive *"
+.Ft int
+.Fn archive_read_support_format_by_code "struct archive *" "int"
+.Ft int
+.Fn archive_read_support_format_cab "struct archive *"
+.Ft int
+.Fn archive_read_support_format_cpio "struct archive *"
+.Ft int
+.Fn archive_read_support_format_empty "struct archive *"
+.Ft int
+.Fn archive_read_support_format_iso9660 "struct archive *"
+.Ft int
+.Fn archive_read_support_format_lha "struct archive *"
+.Ft int
+.Fn archive_read_support_format_mtree "struct archive *"
+.Ft int
+.Fn archive_read_support_format_rar "struct archive *"
+.Ft int
+.Fn archive_read_support_format_raw "struct archive *"
+.Ft int
+.Fn archive_read_support_format_tar "struct archive *"
+.Ft int
+.Fn archive_read_support_format_xar "struct archive *"
+.Ft int
+.Fn archive_read_support_format_zip "struct archive *"
+.\"
+.Sh DESCRIPTION
+.Bl -tag -compact -width indent
+.It Xo
+.Fn archive_read_support_format_7zip ,
+.Fn archive_read_support_format_ar ,
+.Fn archive_read_support_format_cab ,
+.Fn archive_read_support_format_cpio ,
+.Fn archive_read_support_format_iso9660 ,
+.Fn archive_read_support_format_lha ,
+.Fn archive_read_support_format_mtree ,
+.Fn archive_read_support_format_rar ,
+.Fn archive_read_support_format_raw ,
+.Fn archive_read_support_format_tar ,
+.Fn archive_read_support_format_xar ,
+.Fn archive_read_support_format_zip
+.Xc
+Enables support---including auto-detection code---for the
+specified archive format.
+For example,
+.Fn archive_read_support_format_tar
+enables support for a variety of standard tar formats, old-style tar,
+ustar, pax interchange format, and many common variants.
+.It Fn archive_read_support_format_all 
+Enables support for all available formats except the
+.Dq raw
+format (see below).
+.It Fn archive_read_support_format_by_code
+Enables a single format specified by the format code.
+This can be useful when reading a single archive twice;
+use
+.Fn archive_format
+after reading the first time and pass the resulting code
+to this function to selectively enable only the necessary
+format support.
+Note:  In statically-linked executables, this will cause
+your program to include support for every format.
+If executable size is a concern, you may wish to avoid
+using this function.
+.It Fn archive_read_support_format_empty
+Enables support for treating empty files as empty archives.
+Because empty files are valid for several different formats,
+it is not possible to accurately determine a format for
+an empty file based purely on contents.
+So empty files are treated by libarchive as a distinct
+format.
+.It Fn archive_read_support_format_raw 
+The
+.Dq raw
+format handler allows libarchive to be used to read arbitrary data.
+It treats any data stream as an archive with a single entry.
+The pathname of this entry is
+.Dq data ;
+all other entry fields are unset.
+This is not enabled by
+.Fn archive_read_support_format_all
+in order to avoid erroneous handling of damaged archives.
+.El
+.\" .Sh EXAMPLE
+.Sh RETURN VALUES
+These functions return
+.Cm ARCHIVE_OK
+on success, or
+.Cm ARCHIVE_FATAL .
+.\"
+.Sh ERRORS
+Detailed error codes and textual descriptions are available from the
+.Fn archive_errno
+and
+.Fn archive_error_string
+functions.
+.\"
+.Sh SEE ALSO
+.Xr tar 1 ,
+.Xr libarchive 3 ,
+.Xr archive_read_data 3 ,
+.Xr archive_read_filter 3 ,
+.Xr archive_read_set_options 3 ,
+.Xr archive_util 3 ,
+.Xr tar 5
+.Sh BUGS
+Many traditional archiver programs treat
+empty files as valid empty archives.
+For example, many implementations of
+.Xr tar 1
+allow you to append entries to an empty file.
+Of course, it is impossible to determine the format of an empty file
+by inspecting the contents, so this library treats empty files as
+having a special
+.Dq empty
+format.
+.Pp
+Using the
+.Dq raw
+handler together with any other handler will often work
+but can produce surprising results.
diff --git a/contrib/libarchive/libarchive/archive_read_free.3 b/contrib/libarchive/libarchive/archive_read_free.3
new file mode 100644 (file)
index 0000000..5b21822
--- /dev/null
@@ -0,0 +1,93 @@
+.\" Copyright (c) 2003-2011 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 2, 2012
+.Dt ARCHIVE_READ_FREE 3
+.Os
+.Sh NAME
+.Nm archive_read_close ,
+.Nm archive_read_finish ,
+.Nm archive_read_free
+.Nd functions for reading streaming archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
+.Sh SYNOPSIS
+.In archive.h
+.Ft int
+.Fn archive_read_close "struct archive *"
+.Ft int
+.Fn archive_read_finish "struct archive *"
+.Ft int
+.Fn archive_read_free "struct archive *"
+.\"
+.Sh DESCRIPTION
+.Bl -tag -compact -width indent
+.It Fn archive_read_close
+Complete the archive and invoke the close callback.
+.It Fn archive_read_finish
+This is a deprecated synonym for
+.Fn archive_read_free .
+The new name was introduced with libarchive 3.0.
+Applications that need to compile with either libarchive 2
+or libarchive 3 should continue to use the
+.Fn archive_read_finish
+name.
+Both names will be supported until libarchive 4.0 is
+released, which is not expected to occur earlier
+than 2013.
+.It Fn archive_read_free
+Invokes
+.Fn archive_read_close
+if it was not invoked manually, then release all resources.
+Note: In libarchive 1.x, this function was declared to return
+.Ft void ,
+which made it impossible to detect certain errors when
+.Fn archive_read_close
+was invoked implicitly from this function.
+The declaration is corrected beginning with libarchive 2.0.
+.El
+.Sh RETURN VALUES
+These functions return
+.Cm ARCHIVE_OK
+on success, or
+.Cm ARCHIVE_FATAL .
+.\"
+.Sh ERRORS
+Detailed error codes and textual descriptions are available from the
+.Fn archive_errno
+and
+.Fn archive_error_string
+functions.
+.\"
+.Sh SEE ALSO
+.Xr libarchive 3 ,
+.Xr archive_read_new 3 ,
+.Xr archive_read_data 3 ,
+.Xr archive_read_filter 3 ,
+.Xr archive_read_format 3 ,
+.Xr archive_read_open 3 ,
+.Xr archive_read_set_options 3 ,
+.Xr archive_util 3
diff --git a/contrib/libarchive/libarchive/archive_read_header.3 b/contrib/libarchive/libarchive/archive_read_header.3
new file mode 100644 (file)
index 0000000..480a666
--- /dev/null
@@ -0,0 +1,91 @@
+.\" Copyright (c) 2003-2011 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 2, 2012
+.Dt ARCHIVE_READ_HEADER 3
+.Os
+.Sh NAME
+.Nm archive_read_next_header ,
+.Nm archive_read_next_header2
+.Nd functions for reading streaming archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
+.Sh SYNOPSIS
+.In archive.h
+.Ft int
+.Fn archive_read_next_header "struct archive *" "struct archive_entry **"
+.Ft int
+.Fn archive_read_next_header2 "struct archive *" "struct archive_entry *"
+.\"
+.Sh DESCRIPTION
+.Bl -tag -compact -width indent
+.It Fn archive_read_next_header
+Read the header for the next entry and return a pointer to
+a
+.Tn struct archive_entry .
+This is a convenience wrapper around
+.Fn archive_read_next_header2
+that reuses an internal
+.Tn struct archive_entry
+object for each request.
+.It Fn archive_read_next_header2
+Read the header for the next entry and populate the provided
+.Tn struct archive_entry .
+.El
+.\"
+.Sh RETURN VALUES
+These functions return
+.Cm ARCHIVE_OK
+(the operation succeeded),
+.Cm ARCHIVE_WARN
+(the operation succeeded but a non-critical error was encountered),
+.Cm ARCHIVE_EOF
+(end-of-archive was encountered),
+.Cm ARCHIVE_RETRY
+(the operation failed but can be retried),
+and
+.Cm ARCHIVE_FATAL
+(there was a fatal error; the archive should be closed immediately).
+.\"
+.Sh ERRORS
+Detailed error codes and textual descriptions are available from the
+.Fn archive_errno
+and
+.Fn archive_error_string
+functions.
+.\"
+.Sh SEE ALSO
+.Xr tar 1 ,
+.Xr libarchive 3 ,
+.Xr archive_read 3 ,
+.Xr archive_read_data 3 ,
+.Xr archive_read_extract 3 ,
+.Xr archive_read_filter 3 ,
+.Xr archive_read_format 3 ,
+.Xr archive_read_open 3 ,
+.Xr archive_read_set_options 3 ,
+.Xr archive_util 3 ,
+.Xr tar 5
diff --git a/contrib/libarchive/libarchive/archive_read_new.3 b/contrib/libarchive/libarchive/archive_read_new.3
new file mode 100644 (file)
index 0000000..0c9d1a7
--- /dev/null
@@ -0,0 +1,59 @@
+.\" Copyright (c) 2003-2011 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 2, 2012
+.Dt ARCHIVE_READ_NEW 3
+.Os
+.Sh NAME
+.Nm archive_read_new
+.Nd functions for reading streaming archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
+.Sh SYNOPSIS
+.In archive.h
+.Ft struct archive *
+.Fn archive_read_new "void"
+.Sh DESCRIPTION
+Allocates and initializes a
+.Tn struct archive
+object suitable for reading from an archive.
+.Dv NULL
+is returned on error.
+.Pp
+A complete description of the
+.Tn struct archive
+object can be found in the overview manual page for
+.Xr libarchive 3 .
+.\" .Sh ERRORS
+.Sh SEE ALSO
+.Xr tar 1 ,
+.Xr libarchive 3 ,
+.Xr archive_read_data 3 ,
+.Xr archive_read_filter 3 ,
+.Xr archive_read_format 3 ,
+.Xr archive_read_set_options 3 ,
+.Xr archive_util 3 ,
+.Xr tar 5
diff --git a/contrib/libarchive/libarchive/archive_read_open.3 b/contrib/libarchive/libarchive/archive_read_open.3
new file mode 100644 (file)
index 0000000..30a740b
--- /dev/null
@@ -0,0 +1,233 @@
+.\" Copyright (c) 2003-2011 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 AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd February 2, 2012
+.Dt ARCHIVE_READ_OPEN 3
+.Os
+.Sh NAME
+.Nm archive_read_open ,
+.Nm archive_read_open2 ,
+.Nm archive_read_open_fd ,
+.Nm archive_read_open_FILE ,
+.Nm archive_read_open_filename ,
+.Nm archive_read_open_memory ,
+.Nd functions for reading streaming archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
+.Sh SYNOPSIS
+.In archive.h
+.Ft int
+.Fo archive_read_open
+.Fa "struct archive *"
+.Fa "void *client_data"
+.Fa "archive_open_callback *"
+.Fa "archive_read_callback *"
+.Fa "archive_close_callback *"
+.Fc
+.Ft int
+.Fo archive_read_open2
+.Fa "struct archive *"
+.Fa "void *client_data"
+.Fa "archive_open_callback *"
+.Fa "archive_read_callback *"
+.Fa "archive_skip_callback *"
+.Fa "archive_close_callback *"
+.Fc
+.Ft int
+.Fn archive_read_open_FILE "struct archive *" "FILE *file"
+.Ft int
+.Fn archive_read_open_fd "struct archive *" "int fd" "size_t block_size"
+.Ft int
+.Fo archive_read_open_filename
+.Fa "struct archive *"
+.Fa "const char *filename"
+.Fa "size_t block_size"
+.Fc
+.Ft int
+.Fn archive_read_open_memory "struct archive *" "void *buff" "size_t size"
+.Sh DESCRIPTION
+.Bl -tag -compact -width indent
+.It Fn archive_read_open
+The same as
+.Fn archive_read_open2 ,
+except that the skip callback is assumed to be
+.Dv NULL .
+.It Fn archive_read_open2
+Freeze the settings, open the archive, and prepare for reading entries.
+This is the most generic version of this call, which accepts
+four callback functions.
+Most clients will want to use
+.Fn archive_read_open_filename ,
+.Fn archive_read_open_FILE ,
+.Fn archive_read_open_fd ,
+or
+.Fn archive_read_open_memory
+instead.
+The library invokes the client-provided functions to obtain
+raw bytes from the archive.
+.It Fn archive_read_open_FILE
+Like
+.Fn archive_read_open ,
+except that it accepts a
+.Ft "FILE *"
+pointer.
+This function should not be used with tape drives or other devices
+that require strict I/O blocking.
+.It Fn archive_read_open_fd
+Like
+.Fn archive_read_open ,
+except that it accepts a file descriptor and block size rather than
+a set of function pointers.
+Note that the file descriptor will not be automatically closed at
+end-of-archive.
+This function is safe for use with tape drives or other blocked devices.
+.It Fn archive_read_open_file
+This is a deprecated synonym for
+.Fn archive_read_open_filename .
+.It Fn archive_read_open_filename
+Like
+.Fn archive_read_open ,
+except that it accepts a simple filename and a block size.
+A NULL filename represents standard input.
+This function is safe for use with tape drives or other blocked devices.
+.It Fn archive_read_open_memory
+Like
+.Fn archive_read_open ,
+except that it accepts a pointer and size of a block of
+memory containing the archive data.
+.El
+.Pp
+A complete description of the
+.Tn struct archive
+and
+.Tn struct archive_entry
+objects can be found in the overview manual page for
+.Xr libarchive 3 .
+.Sh CLIENT CALLBACKS
+The callback functions must match the following prototypes:
+.Bl -item -offset indent
+.It
+.Ft typedef ssize_t
+.Fo archive_read_callback
+.Fa "struct archive *"
+.Fa "void *client_data"
+.Fa "const void **buffer"
+.Fc
+.It
+.Ft typedef off_t
+.Fo archive_skip_callback
+.Fa "struct archive *"
+.Fa "void *client_data"
+.Fa "off_t request"
+.Fc
+.It
+.Ft typedef int
+.Fn archive_open_callback "struct archive *" "void *client_data"
+.It
+.Ft typedef int
+.Fn archive_close_callback "struct archive *" "void *client_data"
+.El
+.Pp
+The open callback is invoked by
+.Fn archive_open .
+It should return
+.Cm ARCHIVE_OK
+if the underlying file or data source is successfully
+opened.
+If the open fails, it should call
+.Fn archive_set_error
+to register an error code and message and return
+.Cm ARCHIVE_FATAL .
+.Pp
+The read callback is invoked whenever the library
+requires raw bytes from the archive.
+The read callback should read data into a buffer,
+set the
+.Li const void **buffer
+argument to point to the available data, and
+return a count of the number of bytes available.
+The library will invoke the read callback again
+only after it has consumed this data.
+The library imposes no constraints on the size
+of the data blocks returned.
+On end-of-file, the read callback should
+return zero.
+On error, the read callback should invoke
+.Fn archive_set_error
+to register an error code and message and
+return -1.
+.Pp
+The skip callback is invoked when the
+library wants to ignore a block of data.
+The return value is the number of bytes actually
+skipped, which may differ from the request.
+If the callback cannot skip data, it should return
+zero.
+If the skip callback is not provided (the
+function pointer is
+.Dv NULL ),
+the library will invoke the read function
+instead and simply discard the result.
+A skip callback can provide significant
+performance gains when reading uncompressed
+archives from slow disk drives or other media
+that can skip quickly.
+.Pp
+The close callback is invoked by archive_close when
+the archive processing is complete.
+The callback should return
+.Cm ARCHIVE_OK
+on success.
+On failure, the callback should invoke
+.Fn archive_set_error
+to register an error code and message and
+return
+.Cm ARCHIVE_FATAL.
+.\" .Sh EXAMPLE
+.\"
+.Sh RETURN VALUES
+These functions return
+.Cm ARCHIVE_OK
+on success, or
+.Cm ARCHIVE_FATAL .
+.\"
+.Sh ERRORS
+Detailed error codes and textual descriptions are available from the
+.Fn archive_errno
+and
+.Fn archive_error_string
+functions.
+.\"
+.Sh SEE ALSO
+.Xr tar 1 ,
+.Xr libarchive 3 ,
+.Xr archive_read 3 ,
+.Xr archive_read_data 3 ,
+.Xr archive_read_filter 3 ,
+.Xr archive_read_format 3 ,
+.Xr archive_read_set_options 3 ,
+.Xr archive_util 3 ,
+.Xr tar 5
index 7972841..e0f95bf 100644 (file)
@@ -119,7 +119,8 @@ file_read(struct archive *a, void *client_data, const void **buff)
                if (bytes_read < 0) {
                        if (errno == EINTR)
                                continue;
-                       archive_set_error(a, errno, "Error reading fd %d", mine->fd);
+                       archive_set_error(a, errno, "Error reading fd %d",
+                           mine->fd);
                }
                return (bytes_read);
        }
index b1aac0a..3a33c25 100644 (file)
@@ -108,11 +108,11 @@ static ssize_t
 file_read(struct archive *a, void *client_data, const void **buff)
 {
        struct read_FILE_data *mine = (struct read_FILE_data *)client_data;
-       ssize_t bytes_read;
+       size_t bytes_read;
 
        *buff = mine->buffer;
        bytes_read = fread(mine->buffer, 1, mine->block_size, mine->f);
-       if (bytes_read < 0) {
+       if (bytes_read < mine->block_size && ferror(mine->f)) {
                archive_set_error(a, errno, "Error reading file");
        }
        return (bytes_read);
index 69c44ea..fefcd90 100644 (file)
@@ -60,11 +60,15 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read_open_filename.c 201093 2009
 #endif
 
 #include "archive.h"
+#include "archive_private.h"
 #include "archive_string.h"
 
 #ifndef O_BINARY
 #define O_BINARY 0
 #endif
+#ifndef O_CLOEXEC
+#define O_CLOEXEC      0
+#endif
 
 struct read_file_data {
        int      fd;
@@ -79,9 +83,10 @@ struct read_file_data {
        } filename; /* Must be last! */
 };
 
+static int     file_open(struct archive *, void *);
 static int     file_close(struct archive *, void *);
-static int     file_open_filename(struct archive *, enum fnt_e, const void *,
-                   size_t);
+static int file_close2(struct archive *, void *);
+static int file_switch(struct archive *, void *, void *);
 static ssize_t file_read(struct archive *, void *, const void **buff);
 static int64_t file_seek(struct archive *, void *, int64_t request, int);
 static int64_t file_skip(struct archive *, void *, int64_t request);
@@ -98,26 +103,76 @@ int
 archive_read_open_filename(struct archive *a, const char *filename,
     size_t block_size)
 {
-       enum fnt_e filename_type;
+       const char *filenames[2] = { filename, NULL };
+       return archive_read_open_filenames(a, filenames, block_size);
+}
+
+int
+archive_read_open_filenames(struct archive *a, const char **filenames,
+    size_t block_size)
+{
+       struct read_file_data *mine;
+       const char *filename = NULL;
+       if (filenames)
+               filename = *(filenames++);
 
-       if (filename == NULL || filename[0] == '\0') {
-               filename_type = FNT_STDIN;
-       } else
-               filename_type = FNT_MBS;
-       return (file_open_filename(a, filename_type, filename, block_size));
+       archive_clear_error(a);
+       do
+       {
+               if (filename == NULL)
+                       filename = "";
+               mine = (struct read_file_data *)calloc(1,
+                       sizeof(*mine) + strlen(filename));
+               if (mine == NULL)
+                       goto no_memory;
+               strcpy(mine->filename.m, filename);
+               mine->block_size = block_size;
+               mine->fd = -1;
+               mine->buffer = NULL;
+               mine->st_mode = mine->use_lseek = 0;
+               if (filename == NULL || filename[0] == '\0') {
+                       mine->filename_type = FNT_STDIN;
+               } else
+                       mine->filename_type = FNT_MBS;
+               if (archive_read_append_callback_data(a, mine) != (ARCHIVE_OK))
+                       return (ARCHIVE_FATAL);
+               if (filenames == NULL)
+                       break;
+               filename = *(filenames++);
+       } while (filename != NULL && filename[0] != '\0');
+       archive_read_set_open_callback(a, file_open);
+       archive_read_set_read_callback(a, file_read);
+       archive_read_set_skip_callback(a, file_skip);
+       archive_read_set_close_callback(a, file_close);
+       archive_read_set_switch_callback(a, file_switch);
+       archive_read_set_seek_callback(a, file_seek);
+
+       return (archive_read_open1(a));
+no_memory:
+       archive_set_error(a, ENOMEM, "No memory");
+       return (ARCHIVE_FATAL);
 }
 
 int
 archive_read_open_filename_w(struct archive *a, const wchar_t *wfilename,
     size_t block_size)
 {
-       enum fnt_e filename_type;
+       struct read_file_data *mine = (struct read_file_data *)calloc(1,
+               sizeof(*mine) + wcslen(wfilename) * sizeof(wchar_t));
+       if (!mine)
+       {
+               archive_set_error(a, ENOMEM, "No memory");
+               return (ARCHIVE_FATAL);
+       }
+       mine->fd = -1;
+       mine->block_size = block_size;
 
        if (wfilename == NULL || wfilename[0] == L'\0') {
-               filename_type = FNT_STDIN;
+               mine->filename_type = FNT_STDIN;
        } else {
 #if defined(_WIN32) && !defined(__CYGWIN__)
-               filename_type = FNT_WCS;
+               mine->filename_type = FNT_WCS;
+               wcscpy(mine->filename.w, wfilename);
 #else
                /*
                 * POSIX system does not support a wchar_t interface for
@@ -125,7 +180,6 @@ archive_read_open_filename_w(struct archive *a, const wchar_t *wfilename,
                 * filename to multi-byte one and use it.
                 */
                struct archive_string fn;
-               int r;
 
                archive_string_init(&fn);
                if (archive_string_append_from_wcs(&fn, wfilename,
@@ -138,22 +192,31 @@ archive_read_open_filename_w(struct archive *a, const wchar_t *wfilename,
                                    "Failed to convert a wide-character"
                                    " filename to a multi-byte filename");
                        archive_string_free(&fn);
+                       free(mine);
                        return (ARCHIVE_FATAL);
                }
-               r = file_open_filename(a, FNT_MBS, fn.s, block_size);
+               mine->filename_type = FNT_MBS;
+               strcpy(mine->filename.m, fn.s);
                archive_string_free(&fn);
-               return (r);
 #endif
        }
-       return (file_open_filename(a, filename_type, wfilename, block_size));
+       if (archive_read_append_callback_data(a, mine) != (ARCHIVE_OK))
+               return (ARCHIVE_FATAL);
+       archive_read_set_open_callback(a, file_open);
+       archive_read_set_read_callback(a, file_read);
+       archive_read_set_skip_callback(a, file_skip);
+       archive_read_set_close_callback(a, file_close);
+       archive_read_set_switch_callback(a, file_switch);
+       archive_read_set_seek_callback(a, file_seek);
+
+       return (archive_read_open1(a));
 }
 
 static int
-file_open_filename(struct archive *a, enum fnt_e filename_type,
-    const void *_filename, size_t block_size)
+file_open(struct archive *a, void *client_data)
 {
        struct stat st;
-       struct read_file_data *mine;
+       struct read_file_data *mine = (struct read_file_data *)client_data;
        void *buffer;
        const char *filename = NULL;
        const wchar_t *wfilename = NULL;
@@ -168,7 +231,7 @@ file_open_filename(struct archive *a, enum fnt_e filename_type,
 #endif
 
        archive_clear_error(a);
-       if (filename_type == FNT_STDIN) {
+       if (mine->filename_type == FNT_STDIN) {
                /* We used to delegate stdin support by
                 * directly calling archive_read_open_fd(a,0,block_size)
                 * here, but that doesn't (and shouldn't) handle the
@@ -183,9 +246,10 @@ file_open_filename(struct archive *a, enum fnt_e filename_type,
                setmode(0, O_BINARY);
 #endif
                filename = "";
-       } else if (filename_type == FNT_MBS) {
-               filename = (const char *)_filename;
-               fd = open(filename, O_RDONLY | O_BINARY);
+       } else if (mine->filename_type == FNT_MBS) {
+               filename = mine->filename.m;
+               fd = open(filename, O_RDONLY | O_BINARY | O_CLOEXEC);
+               __archive_ensure_cloexec_flag(fd);
                if (fd < 0) {
                        archive_set_error(a, errno,
                            "Failed to open '%s'", filename);
@@ -193,7 +257,7 @@ file_open_filename(struct archive *a, enum fnt_e filename_type,
                }
        } else {
 #if defined(_WIN32) && !defined(__CYGWIN__)
-               wfilename = (const wchar_t *)_filename;
+               wfilename = mine->filename.w;
                fd = _wopen(wfilename, O_RDONLY | O_BINARY);
                if (fd < 0 && errno == ENOENT) {
                        wchar_t *fullpath;
@@ -215,7 +279,7 @@ file_open_filename(struct archive *a, enum fnt_e filename_type,
 #endif
        }
        if (fstat(fd, &st) != 0) {
-               if (filename_type == FNT_WCS)
+               if (mine->filename_type == FNT_WCS)
                        archive_set_error(a, errno, "Can't stat '%S'",
                            wfilename);
                else
@@ -280,50 +344,32 @@ file_open_filename(struct archive *a, enum fnt_e filename_type,
 #endif
        /* TODO: Add an "is_tape_like" variable and appropriate tests. */
 
-       if (filename_type == FNT_WCS)
-               mine = (struct read_file_data *)calloc(1,
-                   sizeof(*mine) + wcslen(wfilename) * sizeof(wchar_t));
-       else
-               mine = (struct read_file_data *)calloc(1,
-                   sizeof(*mine) + strlen(filename));
        /* Disk-like devices prefer power-of-two block sizes.  */
        /* Use provided block_size as a guide so users have some control. */
        if (is_disk_like) {
                size_t new_block_size = 64 * 1024;
-               while (new_block_size < block_size
+               while (new_block_size < mine->block_size
                    && new_block_size < 64 * 1024 * 1024)
                        new_block_size *= 2;
-               block_size = new_block_size;
+               mine->block_size = new_block_size;
        }
-       buffer = malloc(block_size);
+       buffer = malloc(mine->block_size);
        if (mine == NULL || buffer == NULL) {
                archive_set_error(a, ENOMEM, "No memory");
                free(mine);
                free(buffer);
                return (ARCHIVE_FATAL);
        }
-       if (filename_type == FNT_WCS)
-               wcscpy(mine->filename.w, wfilename);
-       else
-               strcpy(mine->filename.m, filename);
-       mine->filename_type = filename_type;
-       mine->block_size = block_size;
        mine->buffer = buffer;
        mine->fd = fd;
        /* Remember mode so close can decide whether to flush. */
        mine->st_mode = st.st_mode;
 
        /* Disk-like inputs can use lseek(). */
-       if (is_disk_like) {
-               archive_read_set_seek_callback(a, file_seek);
+       if (is_disk_like)
                mine->use_lseek = 1;
-       }
 
-       archive_read_set_read_callback(a, file_read);
-       archive_read_set_skip_callback(a, file_skip);
-       archive_read_set_close_callback(a, file_close);
-       archive_read_set_callback_data(a, mine);
-       return (archive_read_open1(a));
+       return (ARCHIVE_OK);
 }
 
 static ssize_t
@@ -401,9 +447,7 @@ file_skip_lseek(struct archive *a, void *client_data, int64_t request)
        /* TODO: Deal with case where off_t isn't 64 bits.
         * This shouldn't be a problem on Linux or other POSIX
         * systems, since the configuration logic for libarchive
-        * tries to obtain a 64-bit off_t.  It's still an issue
-        * on Windows, though, so it might suffice to just use
-        * _lseeki64() on Windows.
+        * tries to obtain a 64-bit off_t.
         */
        if ((old_offset = lseek(mine->fd, 0, SEEK_CUR)) >= 0 &&
            (new_offset = lseek(mine->fd, request, SEEK_CUR)) >= 0)
@@ -475,7 +519,7 @@ file_seek(struct archive *a, void *client_data, int64_t request, int whence)
 }
 
 static int
-file_close(struct archive *a, void *client_data)
+file_close2(struct archive *a, void *client_data)
 {
        struct read_file_data *mine = (struct read_file_data *)client_data;
 
@@ -508,6 +552,23 @@ file_close(struct archive *a, void *client_data)
                        close(mine->fd);
        }
        free(mine->buffer);
+       mine->buffer = NULL;
+       mine->fd = -1;
+       return (ARCHIVE_OK);
+}
+
+static int
+file_close(struct archive *a, void *client_data)
+{
+       struct read_file_data *mine = (struct read_file_data *)client_data;
+       file_close2(a, client_data);
        free(mine);
        return (ARCHIVE_OK);
 }
+
+static int
+file_switch(struct archive *a, void *client_data1, void *client_data2)
+{
+       file_close2(a, client_data1);
+       return file_open(a, client_data2);
+}
index 445c557..8a6c859 100644 (file)
@@ -58,6 +58,8 @@ struct archive_read_filter;
 struct archive_read_filter_bidder {
        /* Configuration data for the bidder. */
        void *data;
+       /* Name of the filter */
+       const char *name;
        /* Taste the upstream filter to see if we handle this. */
        int (*bid)(struct archive_read_filter_bidder *,
            struct archive_read_filter *);
@@ -82,6 +84,8 @@ struct archive_read_filter {
        struct archive_read_filter_bidder *bidder; /* My bidder. */
        struct archive_read_filter *upstream; /* Who I read from. */
        struct archive_read *archive; /* Associated archive. */
+       /* Open a block for reading */
+       int (*open)(struct archive_read_filter *self);
        /* Return next block. */
        ssize_t (*read)(struct archive_read_filter *, const void **);
        /* Skip forward this many bytes. */
@@ -90,6 +94,8 @@ struct archive_read_filter {
        int64_t (*seek)(struct archive_read_filter *self, int64_t offset, int whence);
        /* Close (just this filter) and free(self). */
        int (*close)(struct archive_read_filter *self);
+       /* Function that handles switching from reading one block to the next/prev */
+       int (*sswitch)(struct archive_read_filter *self, unsigned int iindex);
        /* My private data. */
        void *data;
 
@@ -118,13 +124,22 @@ struct archive_read_filter {
  * transformation filters.  This will probably break the API/ABI and
  * so should be deferred at least until libarchive 3.0.
  */
+struct archive_read_data_node {
+       int64_t begin_position;
+       int64_t total_size;
+       void *data;
+};
 struct archive_read_client {
        archive_open_callback   *opener;
        archive_read_callback   *reader;
        archive_skip_callback   *skipper;
        archive_seek_callback   *seeker;
        archive_close_callback  *closer;
-       void *data;
+       archive_switch_callback *switcher;
+       unsigned int nodes;
+       unsigned int cursor;
+       int64_t position;
+       struct archive_read_data_node *dataset;
 };
 
 struct archive_read {
@@ -146,18 +161,33 @@ struct archive_read {
        int64_t           read_data_output_offset;
        size_t            read_data_remaining;
 
-       /* Callbacks to open/read/write/close client archive stream. */
+       /*
+        * Used by formats/filters to determine the amount of data
+        * requested from a call to archive_read_data(). This is only
+        * useful when the format/filter has seek support.
+        */
+       char              read_data_is_posix_read;
+       size_t            read_data_requested;
+
+       /* Callbacks to open/read/write/close client archive streams. */
        struct archive_read_client client;
 
        /* Registered filter bidders. */
-       struct archive_read_filter_bidder bidders[9];
+       struct archive_read_filter_bidder bidders[14];
 
        /* Last filter in chain */
        struct archive_read_filter *filter;
 
+       /* Whether to bypass filter bidding process */
+       int bypass_filter_bidding;
+
        /* File offset of beginning of most recently-read header. */
        int64_t           header_position;
 
+       /* Nodes and offsets of compressed data block */
+       unsigned int data_start_node;
+       unsigned int data_end_node;
+
        /*
         * Format detection is mostly the same as compression
         * detection, with one significant difference: The bidders
@@ -175,6 +205,7 @@ struct archive_read {
                int     (*read_header)(struct archive_read *, struct archive_entry *);
                int     (*read_data)(struct archive_read *, const void **, size_t *, int64_t *);
                int     (*read_data_skip)(struct archive_read *);
+               int64_t (*seek_data)(struct archive_read *, int64_t, int);
                int     (*cleanup)(struct archive_read *);
        }       formats[16];
        struct archive_format_descriptor        *format; /* Active format. */
@@ -194,6 +225,7 @@ int __archive_read_register_format(struct archive_read *a,
            int (*read_header)(struct archive_read *, struct archive_entry *),
            int (*read_data)(struct archive_read *, const void **, size_t *, int64_t *),
            int (*read_data_skip)(struct archive_read *),
+           int64_t (*seek_data)(struct archive_read *, int64_t, int),
            int (*cleanup)(struct archive_read *));
 
 int __archive_read_get_bidder(struct archive_read *a,
@@ -207,4 +239,6 @@ int64_t     __archive_read_filter_seek(struct archive_read_filter *, int64_t, int);
 int64_t        __archive_read_consume(struct archive_read *, int64_t);
 int64_t        __archive_read_filter_consume(struct archive_read_filter *, int64_t);
 int __archive_read_program(struct archive_read_filter *, const char *);
+void __archive_read_free_filters(struct archive_read *);
+int  __archive_read_close_filters(struct archive_read *);
 #endif
diff --git a/contrib/libarchive/libarchive/archive_read_set_format.c b/contrib/libarchive/libarchive/archive_read_set_format.c
new file mode 100644 (file)
index 0000000..190f436
--- /dev/null
@@ -0,0 +1,105 @@
+/*-
+ * Copyright (c) 2003-2012 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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_read_private.h"
+
+int
+archive_read_set_format(struct archive *_a, int code)
+{
+  int r1, r2, slots, i;
+  char str[10];
+  struct archive_read *a = (struct archive_read *)_a;
+
+  if ((r1 = archive_read_support_format_by_code(_a, code)) < (ARCHIVE_OK))
+    return r1;
+
+  r1 = r2 = (ARCHIVE_OK);
+  if (a->format)
+    r2 = (ARCHIVE_WARN);
+  switch (code & ARCHIVE_FORMAT_BASE_MASK)
+  {
+    case ARCHIVE_FORMAT_7ZIP:
+      strcpy(str, "7zip");
+      break;
+    case ARCHIVE_FORMAT_AR:
+      strcpy(str, "ar");
+      break;
+    case ARCHIVE_FORMAT_CAB:
+      strcpy(str, "cab");
+      break;
+    case ARCHIVE_FORMAT_CPIO:
+      strcpy(str, "cpio");
+      break;
+    case ARCHIVE_FORMAT_ISO9660:
+      strcpy(str, "iso9660");
+      break;
+    case ARCHIVE_FORMAT_LHA:
+      strcpy(str, "lha");
+      break;
+    case ARCHIVE_FORMAT_MTREE:
+      strcpy(str, "mtree");
+      break;
+    case ARCHIVE_FORMAT_RAR:
+      strcpy(str, "rar");
+      break;
+    case ARCHIVE_FORMAT_TAR:
+      strcpy(str, "tar");
+      break;
+    case ARCHIVE_FORMAT_XAR:
+      strcpy(str, "xar");
+      break;
+    case ARCHIVE_FORMAT_ZIP:
+      strcpy(str, "zip");
+      break;
+    default:
+      archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
+          "Invalid format code specified");
+      return (ARCHIVE_FATAL);
+  }
+
+  slots = sizeof(a->formats) / sizeof(a->formats[0]);
+  a->format = &(a->formats[0]);
+  for (i = 0; i < slots; i++, a->format++) {
+    if (!a->format->name || !strcmp(a->format->name, str))
+      break;
+  }
+  if (!a->format->name || strcmp(a->format->name, str))
+  {
+    archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
+        "Internal error: Unable to set format");
+    r1 = (ARCHIVE_FATAL);
+  }
+
+  return (r1 < r2) ? r1 : r2;
+}
index 733d862..b778cfb 100644 (file)
@@ -48,7 +48,7 @@ archive_read_support_filter_all(struct archive *a)
        archive_read_support_filter_bzip2(a);
        /* The decompress code doesn't use an outside library. */
        archive_read_support_filter_compress(a);
-       /* Gzip decompress falls back to "gunzip" command-line. */
+       /* Gzip decompress falls back to "gzip -d" command-line. */
        archive_read_support_filter_gzip(a);
        /* Lzip falls back to "unlzip" command-line program. */
        archive_read_support_filter_lzip(a);
@@ -63,6 +63,12 @@ archive_read_support_filter_all(struct archive *a)
        archive_read_support_filter_uu(a);
        /* The decode code doesn't use an outside library. */
        archive_read_support_filter_rpm(a);
+       /* The decode code always uses "lrzip -q -d" command-line. */
+       archive_read_support_filter_lrzip(a);
+       /* Lzop decompress falls back to "lzop -d" command-line. */
+       archive_read_support_filter_lzop(a);
+       /* The decode code always uses "grzip -d" command-line. */
+       archive_read_support_filter_grzip(a);
 
        /* Note: We always return ARCHIVE_OK here, even if some of the
         * above return ARCHIVE_WARN.  The intent here is to enable
index 8d5bd1c..3885a7c 100644 (file)
@@ -94,6 +94,7 @@ archive_read_support_filter_bzip2(struct archive *_a)
                return (ARCHIVE_FATAL);
 
        reader->data = NULL;
+       reader->name = "bzip2";
        reader->bid = bzip2_reader_bid;
        reader->init = bzip2_reader_init;
        reader->options = NULL;
@@ -102,7 +103,7 @@ archive_read_support_filter_bzip2(struct archive *_a)
        return (ARCHIVE_OK);
 #else
        archive_set_error(_a, ARCHIVE_ERRNO_MISC,
-           "Using external bunzip2 program");
+           "Using external bzip2 program");
        return (ARCHIVE_WARN);
 #endif
 }
@@ -170,11 +171,11 @@ bzip2_reader_init(struct archive_read_filter *self)
 {
        int r;
 
-       r = __archive_read_program(self, "bunzip2");
+       r = __archive_read_program(self, "bzip2 -d");
        /* Note: We set the format here even if __archive_read_program()
         * above fails.  We do, after all, know what the format is
         * even if we weren't able to read it. */
-       self->code = ARCHIVE_COMPRESSION_BZIP2;
+       self->code = ARCHIVE_FILTER_BZIP2;
        self->name = "bzip2";
        return (r);
 }
@@ -192,7 +193,7 @@ bzip2_reader_init(struct archive_read_filter *self)
        void *out_block;
        struct private_data *state;
 
-       self->code = ARCHIVE_COMPRESSION_BZIP2;
+       self->code = ARCHIVE_FILTER_BZIP2;
        self->name = "bzip2";
 
        state = (struct private_data *)calloc(sizeof(*state), 1);
index 1b85300..3f5d1f3 100644 (file)
@@ -163,6 +163,7 @@ archive_read_support_filter_compress(struct archive *_a)
                return (ARCHIVE_FATAL);
 
        bidder->data = NULL;
+       bidder->name = "compress (.Z)";
        bidder->bid = compress_bidder_bid;
        bidder->init = compress_bidder_init;
        bidder->options = NULL;
@@ -212,7 +213,7 @@ compress_bidder_init(struct archive_read_filter *self)
        void *out_block;
        int code;
 
-       self->code = ARCHIVE_COMPRESSION_COMPRESS;
+       self->code = ARCHIVE_FILTER_COMPRESS;
        self->name = "compress (.Z)";
 
        state = (struct private_data *)calloc(sizeof(*state), 1);
diff --git a/contrib/libarchive/libarchive/archive_read_support_filter_grzip.c b/contrib/libarchive/libarchive/archive_read_support_filter_grzip.c
new file mode 100644 (file)
index 0000000..84c86ae
--- /dev/null
@@ -0,0 +1,121 @@
+/*-
+ * Copyright (c) 2012 Michihiro NAKAJIMA
+ * 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 "archive_platform.h"
+
+__FBSDID("$FreeBSD$");
+
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_read_private.h"
+
+static const unsigned char grzip_magic[] = {
+       0x47, 0x52, 0x5a, 0x69, 0x70, 0x49, 0x49, 0x00,
+       0x02, 0x04, 0x3a, 0x29 };
+
+static int     grzip_bidder_bid(struct archive_read_filter_bidder *,
+                   struct archive_read_filter *);
+static int     grzip_bidder_init(struct archive_read_filter *);
+
+
+static int
+grzip_reader_free(struct archive_read_filter_bidder *self)
+{
+       (void)self; /* UNUSED */
+       return (ARCHIVE_OK);
+}
+
+int
+archive_read_support_filter_grzip(struct archive *_a)
+{
+       struct archive_read *a = (struct archive_read *)_a;
+       struct archive_read_filter_bidder *reader;
+
+       archive_check_magic(_a, ARCHIVE_READ_MAGIC,
+           ARCHIVE_STATE_NEW, "archive_read_support_filter_grzip");
+
+       if (__archive_read_get_bidder(a, &reader) != ARCHIVE_OK)
+               return (ARCHIVE_FATAL);
+
+       reader->data = NULL;
+       reader->bid = grzip_bidder_bid;
+       reader->init = grzip_bidder_init;
+       reader->options = NULL;
+       reader->free = grzip_reader_free;
+       /* This filter always uses an external program. */
+       archive_set_error(_a, ARCHIVE_ERRNO_MISC,
+           "Using external grzip program for grzip decompression");
+       return (ARCHIVE_WARN);
+}
+
+/*
+ * Bidder just verifies the header and returns the number of verified bits.
+ */
+static int
+grzip_bidder_bid(struct archive_read_filter_bidder *self,
+    struct archive_read_filter *filter)
+{
+       const unsigned char *p;
+       ssize_t avail;
+
+       (void)self; /* UNUSED */
+
+       p = __archive_read_filter_ahead(filter, sizeof(grzip_magic), &avail);
+       if (p == NULL || avail == 0)
+               return (0);
+
+       if (memcmp(p, grzip_magic, sizeof(grzip_magic)))
+               return (0);
+
+       return (sizeof(grzip_magic) * 8);
+}
+
+static int
+grzip_bidder_init(struct archive_read_filter *self)
+{
+       int r;
+
+       r = __archive_read_program(self, "grzip -d");
+       /* Note: We set the format here even if __archive_read_program()
+        * above fails.  We do, after all, know what the format is
+        * even if we weren't able to read it. */
+       self->code = ARCHIVE_FILTER_GRZIP;
+       self->name = "grzip";
+       return (r);
+}
index f6d5595..fa8c675 100644 (file)
@@ -72,7 +72,7 @@ static int    gzip_filter_close(struct archive_read_filter *);
  *
  * TODO: If zlib is unavailable, gzip_bidder_init() should
  * use the compress_program framework to try to fire up an external
- * gunzip program.
+ * gzip program.
  */
 static int     gzip_bidder_bid(struct archive_read_filter_bidder *,
                    struct archive_read_filter *);
@@ -100,6 +100,7 @@ archive_read_support_filter_gzip(struct archive *_a)
                return (ARCHIVE_FATAL);
 
        bidder->data = NULL;
+       bidder->name = "gzip";
        bidder->bid = gzip_bidder_bid;
        bidder->init = gzip_bidder_init;
        bidder->options = NULL;
@@ -109,7 +110,7 @@ archive_read_support_filter_gzip(struct archive *_a)
        return (ARCHIVE_OK);
 #else
        archive_set_error(_a, ARCHIVE_ERRNO_MISC,
-           "Using external gunzip program");
+           "Using external gzip program");
        return (ARCHIVE_WARN);
 #endif
 }
@@ -121,7 +122,7 @@ archive_read_support_filter_gzip(struct archive *_a)
  * number of bytes in header.  If pbits is non-NULL, it receives a
  * count of bits verified, suitable for use by bidder.
  */
-static int
+static ssize_t
 peek_at_header(struct archive_read_filter *filter, int *pbits)
 {
        const unsigned char *p;
@@ -223,7 +224,7 @@ gzip_bidder_bid(struct archive_read_filter_bidder *self,
 
 /*
  * If we don't have the library on this system, we can't do the
- * decompression directly.  We can, however, try to run gunzip
+ * decompression directly.  We can, however, try to run "gzip -d"
  * in case that's available.
  */
 static int
@@ -231,11 +232,11 @@ gzip_bidder_init(struct archive_read_filter *self)
 {
        int r;
 
-       r = __archive_read_program(self, "gunzip");
+       r = __archive_read_program(self, "gzip -d");
        /* Note: We set the format here even if __archive_read_program()
         * above fails.  We do, after all, know what the format is
         * even if we weren't able to read it. */
-       self->code = ARCHIVE_COMPRESSION_GZIP;
+       self->code = ARCHIVE_FILTER_GZIP;
        self->name = "gzip";
        return (r);
 }
@@ -252,7 +253,7 @@ gzip_bidder_init(struct archive_read_filter *self)
        static const size_t out_block_size = 64 * 1024;
        void *out_block;
 
-       self->code = ARCHIVE_COMPRESSION_GZIP;
+       self->code = ARCHIVE_FILTER_GZIP;
        self->name = "gzip";
 
        state = (struct private_data *)calloc(sizeof(*state), 1);
@@ -299,7 +300,7 @@ consume_header(struct archive_read_filter *self)
        /* Initialize compression library. */
        state->stream.next_in = (unsigned char *)(uintptr_t)
            __archive_read_filter_ahead(self->upstream, 1, &avail);
-       state->stream.avail_in = avail;
+       state->stream.avail_in = (uInt)avail;
        ret = inflateInit2(&(state->stream),
            -15 /* Don't check for zlib header */);
 
@@ -380,7 +381,7 @@ gzip_filter_read(struct archive_read_filter *self, const void **p)
 
        /* Empty our output buffer. */
        state->stream.next_out = state->out_block;
-       state->stream.avail_out = state->out_block_size;
+       state->stream.avail_out = (uInt)state->out_block_size;
 
        /* Try to fill the output buffer. */
        while (state->stream.avail_out > 0 && !state->eof) {
@@ -407,7 +408,7 @@ gzip_filter_read(struct archive_read_filter *self, const void **p)
                            "truncated gzip input");
                        return (ARCHIVE_FATAL);
                }
-               state->stream.avail_in = avail_in;
+               state->stream.avail_in = (uInt)avail_in;
 
                /* Decompress and consume some of that data. */
                ret = inflate(&(state->stream), 0);
diff --git a/contrib/libarchive/libarchive/archive_read_support_filter_lrzip.c b/contrib/libarchive/libarchive/archive_read_support_filter_lrzip.c
new file mode 100644 (file)
index 0000000..c82a8e2
--- /dev/null
@@ -0,0 +1,132 @@
+/*-
+ * Copyright (c) 2003-2007 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 "archive_platform.h"
+
+__FBSDID("$FreeBSD$");
+
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_read_private.h"
+
+#define LRZIP_HEADER_MAGIC "LRZI"
+#define LRZIP_HEADER_MAGIC_LEN 4
+
+static int     lrzip_bidder_bid(struct archive_read_filter_bidder *,
+                   struct archive_read_filter *);
+static int     lrzip_bidder_init(struct archive_read_filter *);
+
+
+static int
+lrzip_reader_free(struct archive_read_filter_bidder *self)
+{
+       (void)self; /* UNUSED */
+       return (ARCHIVE_OK);
+}
+
+int
+archive_read_support_filter_lrzip(struct archive *_a)
+{
+       struct archive_read *a = (struct archive_read *)_a;
+       struct archive_read_filter_bidder *reader;
+
+       archive_check_magic(_a, ARCHIVE_READ_MAGIC,
+           ARCHIVE_STATE_NEW, "archive_read_support_filter_lrzip");
+
+       if (__archive_read_get_bidder(a, &reader) != ARCHIVE_OK)
+               return (ARCHIVE_FATAL);
+
+       reader->data = NULL;
+       reader->name = "lrzip";
+       reader->bid = lrzip_bidder_bid;
+       reader->init = lrzip_bidder_init;
+       reader->options = NULL;
+       reader->free = lrzip_reader_free;
+       /* This filter always uses an external program. */
+       archive_set_error(_a, ARCHIVE_ERRNO_MISC,
+           "Using external lrzip program for lrzip decompression");
+       return (ARCHIVE_WARN);
+}
+
+/*
+ * Bidder just verifies the header and returns the number of verified bits.
+ */
+static int
+lrzip_bidder_bid(struct archive_read_filter_bidder *self,
+    struct archive_read_filter *filter)
+{
+       const unsigned char *p;
+       ssize_t avail, len;
+       int i;
+
+       (void)self; /* UNUSED */
+       /* Start by looking at the first six bytes of the header, which
+        * is all fixed layout. */
+       len = 6;
+       p = __archive_read_filter_ahead(filter, len, &avail);
+       if (p == NULL || avail == 0)
+               return (0);
+
+       if (memcmp(p, LRZIP_HEADER_MAGIC, LRZIP_HEADER_MAGIC_LEN))
+               return (0);
+
+       /* current major version is always 0, verify this */
+       if (p[LRZIP_HEADER_MAGIC_LEN])
+               return 0;
+       /* support only v0.6+ lrzip for sanity */
+       i = p[LRZIP_HEADER_MAGIC_LEN + 1];
+       if ((i < 6) || (i > 10))
+               return 0;
+
+       return (int)len;
+}
+
+static int
+lrzip_bidder_init(struct archive_read_filter *self)
+{
+       int r;
+
+       r = __archive_read_program(self, "lrzip -d -q");
+       /* Note: We set the format here even if __archive_read_program()
+        * above fails.  We do, after all, know what the format is
+        * even if we weren't able to read it. */
+       self->code = ARCHIVE_FILTER_LRZIP;
+       self->name = "lrzip";
+       return (r);
+}
diff --git a/contrib/libarchive/libarchive/archive_read_support_filter_lzop.c b/contrib/libarchive/libarchive/archive_read_support_filter_lzop.c
new file mode 100644 (file)
index 0000000..713af31
--- /dev/null
@@ -0,0 +1,486 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2012 Michihiro NAKAJIMA
+ * 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 "archive_platform.h"
+
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_LZO_LZOCONF_H
+#include <lzo/lzoconf.h>
+#endif
+#ifdef HAVE_LZO_LZO1X_H
+#include <lzo/lzo1x.h>
+#endif
+#ifdef HAVE_ZLIB_H
+#include <zlib.h> /* for crc32 and adler32 */
+#endif
+
+#include "archive.h"
+#if !defined(HAVE_ZLIB_H) &&\
+     defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
+#include "archive_crc32.h"
+#endif
+#include "archive_endian.h"
+#include "archive_private.h"
+#include "archive_read_private.h"
+
+#ifndef HAVE_ZLIB_H
+#define adler32        lzo_adler32
+#endif
+
+#define LZOP_HEADER_MAGIC "\x89\x4c\x5a\x4f\x00\x0d\x0a\x1a\x0a"
+#define LZOP_HEADER_MAGIC_LEN 9
+
+#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
+struct read_lzop {
+       unsigned char   *out_block;
+       size_t           out_block_size;
+       int64_t          total_out;
+       int              flags;
+       uint32_t         compressed_cksum;
+       uint32_t         uncompressed_cksum;
+       size_t           compressed_size;
+       size_t           uncompressed_size;
+       size_t           unconsumed_bytes;
+       char             in_stream;
+       char             eof; /* True = found end of compressed data. */
+};
+
+#define FILTER                 0x0800
+#define CRC32_HEADER           0x1000
+#define EXTRA_FIELD            0x0040
+#define ADLER32_UNCOMPRESSED   0x0001
+#define ADLER32_COMPRESSED     0x0002
+#define CRC32_UNCOMPRESSED     0x0100
+#define CRC32_COMPRESSED       0x0200
+#define MAX_BLOCK_SIZE         (64 * 1024 * 1024)
+
+static ssize_t  lzop_filter_read(struct archive_read_filter *, const void **);
+static int     lzop_filter_close(struct archive_read_filter *);
+#endif
+
+static int lzop_bidder_bid(struct archive_read_filter_bidder *,
+    struct archive_read_filter *);
+static int lzop_bidder_init(struct archive_read_filter *);
+
+int
+archive_read_support_filter_lzop(struct archive *_a)
+{
+       struct archive_read *a = (struct archive_read *)_a;
+       struct archive_read_filter_bidder *reader;
+
+       archive_check_magic(_a, ARCHIVE_READ_MAGIC,
+           ARCHIVE_STATE_NEW, "archive_read_support_filter_lzop");
+
+       if (__archive_read_get_bidder(a, &reader) != ARCHIVE_OK)
+               return (ARCHIVE_FATAL);
+
+       reader->data = NULL;
+       reader->bid = lzop_bidder_bid;
+       reader->init = lzop_bidder_init;
+       reader->options = NULL;
+       reader->free = NULL;
+       /* Signal the extent of lzop support with the return value here. */
+#if defined(HAVE_LZO_LZOCONF_H) && defined(HAVE_LZO_LZO1X_H)
+       return (ARCHIVE_OK);
+#else
+       /* Return ARCHIVE_WARN since this always uses an external program. */
+       archive_set_error(_a, ARCHIVE_ERRNO_MISC,
+           "Using external lzop program for lzop decompression");
+       return (ARCHIVE_WARN);
+#endif
+}
+
+/*
+ * Bidder just verifies the header and returns the number of verified bits.
+ */
+static int
+lzop_bidder_bid(struct archive_read_filter_bidder *self,
+    struct archive_read_filter *filter)
+{
+       const unsigned char *p;
+       ssize_t avail;
+
+       (void)self; /* UNUSED */
+
+       p = __archive_read_filter_ahead(filter, LZOP_HEADER_MAGIC_LEN, &avail);
+       if (p == NULL || avail == 0)
+               return (0);
+
+       if (memcmp(p, LZOP_HEADER_MAGIC, LZOP_HEADER_MAGIC_LEN))
+               return (0);
+
+       return (LZOP_HEADER_MAGIC_LEN * 8);
+}
+
+#if !defined(HAVE_LZO_LZOCONF_H) || !defined(HAVE_LZO_LZO1X_H)
+/*
+ * If we don't have the library on this system, we can't do the
+ * decompression directly.  We can, however, try to run "lzop -d"
+ * in case that's available.
+ */
+static int
+lzop_bidder_init(struct archive_read_filter *self)
+{
+       int r;
+
+       r = __archive_read_program(self, "lzop -d");
+       /* Note: We set the format here even if __archive_read_program()
+        * above fails.  We do, after all, know what the format is
+        * even if we weren't able to read it. */
+       self->code = ARCHIVE_FILTER_LZOP;
+       self->name = "lzop";
+       return (r);
+}
+#else
+/*
+ * Initialize the filter object.
+ */
+static int
+lzop_bidder_init(struct archive_read_filter *self)
+{
+       struct read_lzop *state;
+
+       self->code = ARCHIVE_FILTER_LZOP;
+       self->name = "lzop";
+
+       state = (struct read_lzop *)calloc(sizeof(*state), 1);
+       if (state == NULL) {
+               archive_set_error(&self->archive->archive, ENOMEM,
+                   "Can't allocate data for lzop decompression");
+               return (ARCHIVE_FATAL);
+       }
+
+       self->data = state;
+       self->read = lzop_filter_read;
+       self->skip = NULL; /* not supported */
+       self->close = lzop_filter_close;
+
+       return (ARCHIVE_OK);
+}
+
+static int
+consume_header(struct archive_read_filter *self)
+{
+       struct read_lzop *state = (struct read_lzop *)self->data;
+       const unsigned char *p, *_p;
+       unsigned checksum, flags, len, method, version;
+
+       /*
+        * Check LZOP magic code.
+        */
+       p = __archive_read_filter_ahead(self->upstream,
+               LZOP_HEADER_MAGIC_LEN, NULL);
+       if (p == NULL)
+               return (ARCHIVE_EOF);
+
+       if (memcmp(p, LZOP_HEADER_MAGIC, LZOP_HEADER_MAGIC_LEN))
+               return (ARCHIVE_EOF);
+       __archive_read_filter_consume(self->upstream,
+           LZOP_HEADER_MAGIC_LEN);
+
+       p = __archive_read_filter_ahead(self->upstream, 29, NULL);
+       if (p == NULL)
+               goto truncated;
+       _p = p;
+       version = archive_be16dec(p);
+       p += 4;/* version(2 bytes) + library version(2 bytes) */
+
+       if (version >= 0x940) {
+               unsigned reqversion = archive_be16dec(p); p += 2;
+               if (reqversion < 0x900) {
+                       archive_set_error(&self->archive->archive,
+                           ARCHIVE_ERRNO_MISC, "Invalid required version");
+                       return (ARCHIVE_FAILED);
+               }
+       }
+
+       method = *p++;
+       if (method < 1 || method > 3) {
+               archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
+                   "Unsupported method");
+               return (ARCHIVE_FAILED);
+       }
+
+       if (version >= 0x940) {
+               unsigned level = *p++;
+               if (method == 1 && level == 0) level = 3;
+               if (method == 2 && level == 0) level = 1;
+               if (method == 3 && level == 0) level = 9;
+               if (level < 1 && level > 9) {
+                       archive_set_error(&self->archive->archive,
+                           ARCHIVE_ERRNO_MISC, "Invalid level");
+                       return (ARCHIVE_FAILED);
+               }
+       }
+
+       flags = archive_be32dec(p); p += 4;
+
+       if (flags & FILTER)
+               p += 4; /* Skip filter */
+       p += 4; /* Skip mode */
+       if (version >= 0x940)
+               p += 8; /* Skip mtime */
+       else
+               p += 4; /* Skip mtime */
+       len = *p++; /* Read filename length */
+       len += p - _p;
+       /* Make sure we have all bytes we need to calculate checksum. */
+       p = __archive_read_filter_ahead(self->upstream, len + 4, NULL);
+       if (p == NULL)
+               goto truncated;
+       if (flags & CRC32_HEADER)
+               checksum = crc32(crc32(0, NULL, 0), p, len);
+       else
+               checksum = adler32(adler32(0, NULL, 0), p, len);
+       if (archive_be32dec(p + len) != checksum)
+               goto corrupted;
+       __archive_read_filter_consume(self->upstream, len + 4);
+       if (flags & EXTRA_FIELD) {
+               /* Skip extra field */
+               p = __archive_read_filter_ahead(self->upstream, 4, NULL);
+               if (p == NULL)
+                       goto truncated;
+               len = archive_be32dec(p);
+               __archive_read_filter_consume(self->upstream, len + 4 + 4);
+       }
+       state->flags = flags;
+       state->in_stream = 1;
+       return (ARCHIVE_OK);
+truncated:
+       archive_set_error(&self->archive->archive,
+           ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data");
+       return (ARCHIVE_FAILED);
+corrupted:
+       archive_set_error(&self->archive->archive,
+           ARCHIVE_ERRNO_FILE_FORMAT, "Corrupted lzop header");
+       return (ARCHIVE_FAILED);
+}
+
+static int
+consume_block_info(struct archive_read_filter *self)
+{
+       struct read_lzop *state = (struct read_lzop *)self->data;
+       const unsigned char *p;
+       unsigned flags = state->flags;
+
+       p = __archive_read_filter_ahead(self->upstream, 4, NULL);
+       if (p == NULL)
+               goto truncated;
+       state->uncompressed_size = archive_be32dec(p);
+       __archive_read_filter_consume(self->upstream, 4);
+       if (state->uncompressed_size == 0)
+               return (ARCHIVE_EOF);
+       if (state->uncompressed_size > MAX_BLOCK_SIZE)
+               goto corrupted;
+
+       p = __archive_read_filter_ahead(self->upstream, 4, NULL);
+       if (p == NULL)
+               goto truncated;
+       state->compressed_size = archive_be32dec(p);
+       __archive_read_filter_consume(self->upstream, 4);
+       if (state->compressed_size > state->uncompressed_size)
+               goto corrupted;
+
+       if (flags & (CRC32_UNCOMPRESSED | ADLER32_UNCOMPRESSED)) {
+               p = __archive_read_filter_ahead(self->upstream, 4, NULL);
+               if (p == NULL)
+                       goto truncated;
+               state->compressed_cksum = state->uncompressed_cksum =
+                   archive_be32dec(p);
+               __archive_read_filter_consume(self->upstream, 4);
+       }
+       if ((flags & (CRC32_COMPRESSED | ADLER32_COMPRESSED)) &&
+           state->compressed_size < state->uncompressed_size) {
+               p = __archive_read_filter_ahead(self->upstream, 4, NULL);
+               if (p == NULL)
+                       goto truncated;
+               state->compressed_cksum = archive_be32dec(p);
+               __archive_read_filter_consume(self->upstream, 4);
+       }
+       return (ARCHIVE_OK);
+truncated:
+       archive_set_error(&self->archive->archive,
+           ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data");
+       return (ARCHIVE_FAILED);
+corrupted:
+       archive_set_error(&self->archive->archive,
+           ARCHIVE_ERRNO_FILE_FORMAT, "Corrupted lzop header");
+       return (ARCHIVE_FAILED);
+}
+
+static ssize_t
+lzop_filter_read(struct archive_read_filter *self, const void **p)
+{
+       struct read_lzop *state = (struct read_lzop *)self->data;
+       const void *b;
+       lzo_uint out_size;
+       uint32_t cksum;
+       int ret, r;
+
+       if (state->unconsumed_bytes) {
+               __archive_read_filter_consume(self->upstream,
+                   state->unconsumed_bytes);
+               state->unconsumed_bytes = 0;
+       }
+       if (state->eof)
+               return (0);
+
+       for (;;) {
+               if (!state->in_stream) {
+                       ret = consume_header(self);
+                       if (ret < ARCHIVE_OK)
+                               return (ret);
+                       if (ret == ARCHIVE_EOF) {
+                               state->eof = 1;
+                               return (0);
+                       }
+               }
+               ret = consume_block_info(self);
+               if (ret < ARCHIVE_OK)
+                       return (ret);
+               if (ret == ARCHIVE_EOF)
+                       state->in_stream = 0;
+               else
+                       break;
+       }
+
+       if (state->out_block == NULL ||
+           state->out_block_size < state->uncompressed_size) {
+               void *new_block;
+
+               new_block = realloc(state->out_block, state->uncompressed_size);
+               if (new_block == NULL) {
+                       archive_set_error(&self->archive->archive, ENOMEM,
+                           "Can't allocate data for lzop decompression");
+                       return (ARCHIVE_FATAL);
+               }
+               state->out_block = new_block;
+               state->out_block_size = state->uncompressed_size;
+       }
+
+       b = __archive_read_filter_ahead(self->upstream,
+               state->compressed_size, NULL);
+       if (b == NULL) {
+               archive_set_error(&self->archive->archive,
+                   ARCHIVE_ERRNO_FILE_FORMAT, "Truncated lzop data");
+               return (ARCHIVE_FATAL);
+       }
+       if (state->flags & CRC32_COMPRESSED)
+               cksum = crc32(crc32(0, NULL, 0), b, state->compressed_size);
+       else if (state->flags & ADLER32_COMPRESSED)
+               cksum = adler32(adler32(0, NULL, 0), b, state->compressed_size);
+       else
+               cksum = state->compressed_cksum;
+       if (cksum != state->compressed_cksum) {
+               archive_set_error(&self->archive->archive,
+                   ARCHIVE_ERRNO_MISC, "Corrupted data");
+               return (ARCHIVE_FATAL);
+       }
+
+       /*
+        * If the both uncompressed size and compressed size are the same,
+        * we do not decompress this block.
+        */
+       if (state->uncompressed_size == state->compressed_size) {
+               *p = b;
+               state->total_out += state->compressed_size;
+               state->unconsumed_bytes = state->compressed_size;
+               return ((ssize_t)state->uncompressed_size);
+       }
+
+       /*
+        * Drive lzo uncompresison.
+        */
+       out_size = (lzo_uint)state->uncompressed_size;
+       r = lzo1x_decompress_safe(b, (lzo_uint)state->compressed_size,
+               state->out_block, &out_size, NULL);
+       switch (r) {
+       case LZO_E_OK:
+               if (out_size == state->uncompressed_size)
+                       break;
+               archive_set_error(&self->archive->archive,
+                   ARCHIVE_ERRNO_MISC, "Corrupted data");
+               return (ARCHIVE_FATAL);
+       case LZO_E_OUT_OF_MEMORY:
+               archive_set_error(&self->archive->archive, ENOMEM,
+                   "lzop decompression failed: out of memory");
+               return (ARCHIVE_FATAL);
+       default:
+               archive_set_error(&self->archive->archive, ARCHIVE_ERRNO_MISC,
+                   "lzop decompression failed: %d", r);
+               return (ARCHIVE_FATAL);
+       }
+
+       if (state->flags & CRC32_UNCOMPRESSED)
+               cksum = crc32(crc32(0, NULL, 0), state->out_block,
+                   state->uncompressed_size);
+       else if (state->flags & ADLER32_UNCOMPRESSED)
+               cksum = adler32(adler32(0, NULL, 0), state->out_block,
+                   state->uncompressed_size);
+       else
+               cksum = state->uncompressed_cksum;
+       if (cksum != state->uncompressed_cksum) {
+               archive_set_error(&self->archive->archive,
+                   ARCHIVE_ERRNO_MISC, "Corrupted data");
+               return (ARCHIVE_FATAL);
+       }
+
+       __archive_read_filter_consume(self->upstream, state->compressed_size);
+       *p = state->out_block;
+       state->total_out += out_size;
+       return ((ssize_t)out_size);
+}
+
+/*
+ * Clean up the decompressor.
+ */
+static int
+lzop_filter_close(struct archive_read_filter *self)
+{
+       struct read_lzop *state = (struct read_lzop *)self->data;
+
+       free(state->out_block);
+       free(state);
+       return (ARCHIVE_OK);
+}
+
+#endif
index b05eb03..66dc2f4 100644 (file)
@@ -1,5 +1,6 @@
 /*-
  * Copyright (c) 2007 Joerg Sonnenberger
+ * Copyright (c) 2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -53,7 +54,9 @@ __FBSDID("$FreeBSD$");
 
 #include "archive.h"
 #include "archive_private.h"
+#include "archive_string.h"
 #include "archive_read_private.h"
+#include "filter_fork.h"
 
 
 #if ARCHIVE_VERSION_NUMBER < 4000000
@@ -79,50 +82,13 @@ archive_read_support_filter_program(struct archive *a, const char *cmd)
        return (archive_read_support_filter_program_signature(a, cmd, NULL, 0));
 }
 
-
-/* This capability is only available on POSIX systems. */
-#if (!defined(HAVE_PIPE) || !defined(HAVE_FCNTL) || \
-    !(defined(HAVE_FORK) || defined(HAVE_VFORK))) && (!defined(_WIN32) || defined(__CYGWIN__))
-
-/*
- * On non-Posix systems, allow the program to build, but choke if
- * this function is actually invoked.
- */
-int
-archive_read_support_filter_program_signature(struct archive *_a,
-    const char *cmd, const void *signature, size_t signature_len)
-{
-       (void)_a; /* UNUSED */
-       (void)cmd; /* UNUSED */
-       (void)signature; /* UNUSED */
-       (void)signature_len; /* UNUSED */
-
-       archive_set_error(_a, -1,
-           "External compression programs not supported on this platform");
-       return (ARCHIVE_FATAL);
-}
-
-int
-__archive_read_program(struct archive_read_filter *self, const char *cmd)
-{
-       (void)self; /* UNUSED */
-       (void)cmd; /* UNUSED */
-
-       archive_set_error(&self->archive->archive, -1,
-           "External compression programs not supported on this platform");
-       return (ARCHIVE_FATAL);
-}
-
-#else
-
-#include "filter_fork.h"
-
 /*
  * The bidder object stores the command and the signature to watch for.
  * The 'inhibit' entry here is used to ensure that unchecked filters never
  * bid twice in the same pipeline.
  */
 struct program_bidder {
+       char *description;
        char *cmd;
        void *signature;
        size_t signature_len;
@@ -138,8 +104,12 @@ static int program_bidder_free(struct archive_read_filter_bidder *);
  * The actual filter needs to track input and output data.
  */
 struct program_filter {
-       char            *description;
+       struct archive_string description;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+       HANDLE           child;
+#else
        pid_t            child;
+#endif
        int              exit_status;
        int              waitpid_return;
        int              child_stdin, child_stdout;
@@ -151,6 +121,29 @@ struct program_filter {
 static ssize_t program_filter_read(struct archive_read_filter *,
                    const void **);
 static int     program_filter_close(struct archive_read_filter *);
+static void    free_state(struct program_bidder *);
+
+static int
+set_bidder_signature(struct archive_read_filter_bidder *bidder,
+    struct program_bidder *state, const void *signature, size_t signature_len)
+{
+
+       if (signature != NULL && signature_len > 0) {
+               state->signature_len = signature_len;
+               state->signature = malloc(signature_len);
+               memcpy(state->signature, signature, signature_len);
+       }
+
+       /*
+        * Fill in the bidder object.
+        */
+       bidder->data = state;
+       bidder->bid = program_bidder_bid;
+       bidder->init = program_bidder_init;
+       bidder->options = NULL;
+       bidder->free = program_bidder_free;
+       return (ARCHIVE_OK);
+}
 
 int
 archive_read_support_filter_program_signature(struct archive *_a,
@@ -169,37 +162,40 @@ archive_read_support_filter_program_signature(struct archive *_a,
        /*
         * Allocate our private state.
         */
-       state = (struct program_bidder *)calloc(sizeof (*state), 1);
+       state = (struct program_bidder *)calloc(1, sizeof (*state));
        if (state == NULL)
-               return (ARCHIVE_FATAL);
+               goto memerr;
        state->cmd = strdup(cmd);
-       if (signature != NULL && signature_len > 0) {
-               state->signature_len = signature_len;
-               state->signature = malloc(signature_len);
-               memcpy(state->signature, signature, signature_len);
-       }
+       if (state->cmd == NULL)
+               goto memerr;
 
-       /*
-        * Fill in the bidder object.
-        */
-       bidder->data = state;
-       bidder->bid = program_bidder_bid;
-       bidder->init = program_bidder_init;
-       bidder->options = NULL;
-       bidder->free = program_bidder_free;
-       return (ARCHIVE_OK);
+       return set_bidder_signature(bidder, state, signature, signature_len);
+memerr:
+       free_state(state);
+       archive_set_error(_a, ENOMEM, "Can't allocate memory");
+       return (ARCHIVE_FATAL);
 }
 
 static int
 program_bidder_free(struct archive_read_filter_bidder *self)
 {
        struct program_bidder *state = (struct program_bidder *)self->data;
-       free(state->cmd);
-       free(state->signature);
-       free(self->data);
+
+       free_state(state);
        return (ARCHIVE_OK);
 }
 
+static void
+free_state(struct program_bidder *state)
+{
+
+       if (state) {
+               free(state->cmd);
+               free(state->signature);
+               free(state);
+       }
+}
+
 /*
  * If we do have a signature, bid only if that matches.
  *
@@ -258,6 +254,9 @@ child_stop(struct archive_read_filter *self, struct program_filter *state)
                        state->waitpid_return
                            = waitpid(state->child, &state->exit_status, 0);
                } while (state->waitpid_return == -1 && errno == EINTR);
+#if defined(_WIN32) && !defined(__CYGWIN__)
+               CloseHandle(state->child);
+#endif
                state->child = 0;
        }
 
@@ -310,11 +309,35 @@ child_read(struct archive_read_filter *self, char *buf, size_t buf_len)
        struct program_filter *state = self->data;
        ssize_t ret, requested, avail;
        const char *p;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+       HANDLE handle = (HANDLE)_get_osfhandle(state->child_stdout);
+#endif
 
        requested = buf_len > SSIZE_MAX ? SSIZE_MAX : buf_len;
 
        for (;;) {
                do {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+                       /* Avoid infinity wait.
+                        * Note: If there is no data in the pipe, ReadFile()
+                        * called in read() never returns and so we won't
+                        * write remaining encoded data to the pipe.
+                        * Note: This way may cause performance problem.
+                        * we are looking forward to great code to resolve
+                        * this.  */
+                       DWORD pipe_avail = -1;
+                       int cnt = 2;
+
+                       while (PeekNamedPipe(handle, NULL, 0, NULL,
+                           &pipe_avail, NULL) != 0 && pipe_avail == 0 &&
+                           cnt--)
+                               Sleep(5);
+                       if (pipe_avail == 0) {
+                               ret = -1;
+                               errno = EAGAIN;
+                               break;
+                       }
+#endif
                        ret = read(state->child_stdout, buf, requested);
                } while (ret == -1 && errno == EINTR);
 
@@ -376,38 +399,57 @@ __archive_read_program(struct archive_read_filter *self, const char *cmd)
        struct program_filter   *state;
        static const size_t out_buf_len = 65536;
        char *out_buf;
-       char *description;
        const char *prefix = "Program: ";
+       pid_t child;
+       size_t l;
 
+       l = strlen(prefix) + strlen(cmd) + 1;
        state = (struct program_filter *)calloc(1, sizeof(*state));
        out_buf = (char *)malloc(out_buf_len);
-       description = (char *)malloc(strlen(prefix) + strlen(cmd) + 1);
-       if (state == NULL || out_buf == NULL || description == NULL) {
+       if (state == NULL || out_buf == NULL ||
+           archive_string_ensure(&state->description, l) == NULL) {
                archive_set_error(&self->archive->archive, ENOMEM,
                    "Can't allocate input data");
-               free(state);
+               if (state != NULL) {
+                       archive_string_free(&state->description);
+                       free(state);
+               }
                free(out_buf);
-               free(description);
                return (ARCHIVE_FATAL);
        }
+       archive_strcpy(&state->description, prefix);
+       archive_strcat(&state->description, cmd);
 
-       self->code = ARCHIVE_COMPRESSION_PROGRAM;
-       state->description = description;
-       strcpy(state->description, prefix);
-       strcat(state->description, cmd);
-       self->name = state->description;
+       self->code = ARCHIVE_FILTER_PROGRAM;
+       self->name = state->description.s;
 
        state->out_buf = out_buf;
        state->out_buf_len = out_buf_len;
 
-       if ((state->child = __archive_create_child(cmd,
-                &state->child_stdin, &state->child_stdout)) == -1) {
+       child = __archive_create_child(cmd, &state->child_stdin,
+           &state->child_stdout);
+       if (child == -1) {
+               free(state->out_buf);
+               free(state);
+               archive_set_error(&self->archive->archive, EINVAL,
+                   "Can't initialize filter; unable to run program \"%s\"",
+                   cmd);
+               return (ARCHIVE_FATAL);
+       }
+#if defined(_WIN32) && !defined(__CYGWIN__)
+       state->child = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, child);
+       if (state->child == NULL) {
+               child_stop(self, state);
                free(state->out_buf);
                free(state);
                archive_set_error(&self->archive->archive, EINVAL,
-                   "Can't initialize filter; unable to run program \"%s\"", cmd);
+                   "Can't initialize filter; unable to run program \"%s\"",
+                   cmd);
                return (ARCHIVE_FATAL);
        }
+#else
+       state->child = child;
+#endif
 
        self->data = state;
        self->read = program_filter_read;
@@ -467,10 +509,8 @@ program_filter_close(struct archive_read_filter *self)
 
        /* Release our private data. */
        free(state->out_buf);
-       free(state->description);
+       archive_string_free(&state->description);
        free(state);
 
        return (e);
 }
-
-#endif /* !defined(HAVE_PIPE) || !defined(HAVE_VFORK) || !defined(HAVE_FCNTL) */
index 1b3e124..e7e58e5 100644 (file)
@@ -85,6 +85,7 @@ archive_read_support_filter_rpm(struct archive *_a)
                return (ARCHIVE_FATAL);
 
        bidder->data = NULL;
+       bidder->name = "rpm";
        bidder->bid = rpm_bidder_bid;
        bidder->init = rpm_bidder_init;
        bidder->options = NULL;
@@ -137,7 +138,7 @@ rpm_bidder_init(struct archive_read_filter *self)
 {
        struct rpm   *rpm;
 
-       self->code = ARCHIVE_COMPRESSION_RPM;
+       self->code = ARCHIVE_FILTER_RPM;
        self->name = "rpm";
        self->read = rpm_filter_read;
        self->skip = NULL; /* not supported */
index a75ef75..471771b 100644 (file)
@@ -56,6 +56,7 @@ struct uudecode {
 #define ST_READ_UU     1
 #define ST_UUEND       2
 #define ST_READ_BASE64 3
+#define ST_IGNORE      4
 };
 
 static int     uudecode_bidder_bid(struct archive_read_filter_bidder *,
@@ -88,6 +89,7 @@ archive_read_support_filter_uu(struct archive *_a)
                return (ARCHIVE_FATAL);
 
        bidder->data = NULL;
+       bidder->name = "uu";
        bidder->bid = uudecode_bidder_bid;
        bidder->init = uudecode_bidder_init;
        bidder->options = NULL;
@@ -377,7 +379,7 @@ uudecode_bidder_init(struct archive_read_filter *self)
        void *out_buff;
        void *in_buff;
 
-       self->code = ARCHIVE_COMPRESSION_UU;
+       self->code = ARCHIVE_FILTER_UU;
        self->name = "uu";
        self->read = uudecode_filter_read;
        self->skip = NULL; /* not supported */
@@ -470,6 +472,10 @@ read_more:
        total = 0;
        out = uudecode->out_buff;
        ravail = avail_in;
+       if (uudecode->state == ST_IGNORE) {
+               used = avail_in;
+               goto finish;
+       }
        if (uudecode->in_cnt) {
                /*
                 * If there is remaining data which is saved by
@@ -485,12 +491,18 @@ read_more:
                uudecode->in_cnt = 0;
        }
        for (;used < avail_in; d += llen, used += llen) {
-               int l, body;
+               int64_t l, body;
 
                b = d;
                len = get_line(b, avail_in - used, &nl);
                if (len < 0) {
                        /* Non-ascii character is found. */
+                       if (uudecode->state == ST_FIND_HEAD &&
+                           (uudecode->total > 0 || total > 0)) {
+                               uudecode->state = ST_IGNORE;
+                               used = avail_in;
+                               goto finish;
+                       }
                        archive_set_error(&self->archive->archive,
                            ARCHIVE_ERRNO_MISC,
                            "Insufficient compressed data");
@@ -507,7 +519,7 @@ read_more:
                                return (ARCHIVE_FATAL);
                        if (uudecode->in_buff != b)
                                memmove(uudecode->in_buff, b, len);
-                       uudecode->in_cnt = len;
+                       uudecode->in_cnt = (int)len;
                        if (total == 0) {
                                /* Do not return 0; it means end-of-file.
                                 * We should try to read bytes more. */
@@ -545,7 +557,7 @@ read_more:
                        break;
                case ST_READ_UU:
                        if (total + len * 2 > OUT_BUFF_SIZE)
-                               break;
+                               goto finish;
                        body = len - nl;
                        if (!uuchar[*b] || body <= 0) {
                                archive_set_error(&self->archive->archive,
@@ -611,7 +623,7 @@ read_more:
                        break;
                case ST_READ_BASE64:
                        if (total + len * 2 > OUT_BUFF_SIZE)
-                               break;
+                               goto finish;
                        l = len - nl;
                        if (l >= 3 && b[0] == '=' && b[1] == '=' &&
                            b[2] == '=') {
@@ -657,8 +669,10 @@ read_more:
                        break;
                }
        }
-
-       __archive_read_filter_consume(self->upstream, ravail);
+finish:
+       if (ravail < avail_in)
+               used -= avail_in - ravail;
+       __archive_read_filter_consume(self->upstream, used);
 
        *buff = uudecode->out_buff;
        uudecode->total += total;
index cf762a4..15824b1 100644 (file)
@@ -136,6 +136,7 @@ archive_read_support_filter_xz(struct archive *_a)
                return (ARCHIVE_FATAL);
 
        bidder->data = NULL;
+       bidder->name = "xz";
        bidder->bid = xz_bidder_bid;
        bidder->init = xz_bidder_init;
        bidder->options = NULL;
@@ -144,7 +145,7 @@ archive_read_support_filter_xz(struct archive *_a)
        return (ARCHIVE_OK);
 #else
        archive_set_error(_a, ARCHIVE_ERRNO_MISC,
-           "Using external unxz program for xz decompression");
+           "Using external xz program for xz decompression");
        return (ARCHIVE_WARN);
 #endif
 }
@@ -170,6 +171,7 @@ archive_read_support_filter_lzma(struct archive *_a)
                return (ARCHIVE_FATAL);
 
        bidder->data = NULL;
+       bidder->name = "lzma";
        bidder->bid = lzma_bidder_bid;
        bidder->init = lzma_bidder_init;
        bidder->options = NULL;
@@ -180,7 +182,7 @@ archive_read_support_filter_lzma(struct archive *_a)
        return (ARCHIVE_OK);
 #else
        archive_set_error(_a, ARCHIVE_ERRNO_MISC,
-           "Using external unlzma program for lzma decompression");
+           "Using external lzma program for lzma decompression");
        return (ARCHIVE_WARN);
 #endif
 }
@@ -207,6 +209,7 @@ archive_read_support_filter_lzip(struct archive *_a)
                return (ARCHIVE_FATAL);
 
        bidder->data = NULL;
+       bidder->name = "lzip";
        bidder->bid = lzip_bidder_bid;
        bidder->init = lzip_bidder_init;
        bidder->options = NULL;
@@ -415,7 +418,7 @@ lzip_bidder_bid(struct archive_read_filter_bidder *self,
 static int
 xz_bidder_init(struct archive_read_filter *self)
 {
-       self->code = ARCHIVE_COMPRESSION_XZ;
+       self->code = ARCHIVE_FILTER_XZ;
        self->name = "xz";
        return (xz_lzma_bidder_init(self));
 }
@@ -423,7 +426,7 @@ xz_bidder_init(struct archive_read_filter *self)
 static int
 lzma_bidder_init(struct archive_read_filter *self)
 {
-       self->code = ARCHIVE_COMPRESSION_LZMA;
+       self->code = ARCHIVE_FILTER_LZMA;
        self->name = "lzma";
        return (xz_lzma_bidder_init(self));
 }
@@ -431,7 +434,7 @@ lzma_bidder_init(struct archive_read_filter *self)
 static int
 lzip_bidder_init(struct archive_read_filter *self)
 {
-       self->code = ARCHIVE_COMPRESSION_LZIP;
+       self->code = ARCHIVE_FILTER_LZIP;
        self->name = "lzip";
        return (xz_lzma_bidder_init(self));
 }
@@ -518,7 +521,7 @@ xz_lzma_bidder_init(struct archive_read_filter *self)
        state->stream.avail_out = state->out_block_size;
 
        state->crc32 = 0;
-       if (self->code == ARCHIVE_COMPRESSION_LZIP) {
+       if (self->code == ARCHIVE_FILTER_LZIP) {
                /*
                 * We have to read a lzip header and use it to initialize
                 * compression library, thus we cannot initialize the
@@ -530,7 +533,7 @@ xz_lzma_bidder_init(struct archive_read_filter *self)
                state->in_stream = 1;
 
        /* Initialize compression library. */
-       if (self->code == ARCHIVE_COMPRESSION_XZ)
+       if (self->code == ARCHIVE_FILTER_XZ)
                ret = lzma_stream_decoder(&(state->stream),
                    LZMA_MEMLIMIT,/* memlimit */
                    LZMA_CONCATENATED);
@@ -730,7 +733,7 @@ xz_filter_read(struct archive_read_filter *self, const void **p)
                *p = NULL;
        else {
                *p = state->out_block;
-               if (self->code == ARCHIVE_COMPRESSION_LZIP) {
+               if (self->code == ARCHIVE_FILTER_LZIP) {
                        state->crc32 = lzma_crc32(state->out_block,
                            decompressed, state->crc32);
                        if (state->eof) {
@@ -778,7 +781,7 @@ lzma_bidder_init(struct archive_read_filter *self)
        struct private_data *state;
        ssize_t ret, avail_in;
 
-       self->code = ARCHIVE_COMPRESSION_LZMA;
+       self->code = ARCHIVE_FILTER_LZMA;
        self->name = "lzma";
 
        state = (struct private_data *)calloc(sizeof(*state), 1);
@@ -941,11 +944,11 @@ lzma_bidder_init(struct archive_read_filter *self)
 {
        int r;
 
-       r = __archive_read_program(self, "unlzma");
+       r = __archive_read_program(self, "lzma -d -qq");
        /* Note: We set the format here even if __archive_read_program()
         * above fails.  We do, after all, know what the format is
         * even if we weren't able to read it. */
-       self->code = ARCHIVE_COMPRESSION_LZMA;
+       self->code = ARCHIVE_FILTER_LZMA;
        self->name = "lzma";
        return (r);
 }
@@ -958,11 +961,11 @@ xz_bidder_init(struct archive_read_filter *self)
 {
        int r;
 
-       r = __archive_read_program(self, "unxz");
+       r = __archive_read_program(self, "xz -d -qq");
        /* Note: We set the format here even if __archive_read_program()
         * above fails.  We do, after all, know what the format is
         * even if we weren't able to read it. */
-       self->code = ARCHIVE_COMPRESSION_XZ;
+       self->code = ARCHIVE_FILTER_XZ;
        self->name = "xz";
        return (r);
 }
@@ -972,11 +975,11 @@ lzip_bidder_init(struct archive_read_filter *self)
 {
        int r;
 
-       r = __archive_read_program(self, "unlzip");
+       r = __archive_read_program(self, "lzip -d -q");
        /* Note: We set the format here even if __archive_read_program()
         * above fails.  We do, after all, know what the format is
         * even if we weren't able to read it. */
-       self->code = ARCHIVE_COMPRESSION_LZIP;
+       self->code = ARCHIVE_FILTER_LZIP;
        self->name = "lzip";
        return (r);
 }
index 39a46ed..194b8d5 100644 (file)
@@ -409,6 +409,7 @@ archive_read_support_format_7zip(struct archive *_a)
            archive_read_format_7zip_read_header,
            archive_read_format_7zip_read_data,
            archive_read_format_7zip_read_data_skip,
+           NULL,
            archive_read_format_7zip_cleanup);
 
        if (r != ARCHIVE_OK)
@@ -684,8 +685,8 @@ archive_read_format_7zip_read_header(struct archive_read *a,
                        symname[symsize] = '\0';
                        archive_entry_copy_symlink(entry,
                            (const char *)symname);
-                       free(symname);
                }
+               free(symname);
                archive_entry_set_size(entry, 0);
        }
 
@@ -709,16 +710,15 @@ archive_read_format_7zip_read_data(struct archive_read *a,
        if (zip->pack_stream_bytes_unconsumed)
                read_consume(a);
 
+       *offset = zip->entry_offset;
+       *size = 0;
+       *buff = NULL;
        /*
         * If we hit end-of-entry last time, clean up and return
         * ARCHIVE_EOF this time.
         */
-       if (zip->end_of_entry) {
-               *offset = zip->entry_offset;
-               *size = 0;
-               *buff = NULL;
+       if (zip->end_of_entry)
                return (ARCHIVE_EOF);
-       }
 
        bytes = read_stream(a, buff,
                (size_t)zip->entry_bytes_remaining, 0);
@@ -736,7 +736,8 @@ archive_read_format_7zip_read_data(struct archive_read *a,
 
        /* Update checksum */
        if ((zip->entry->flg & CRC32_IS_SET) && bytes)
-               zip->entry_crc32 = crc32(zip->entry_crc32, *buff, bytes);
+               zip->entry_crc32 = crc32(zip->entry_crc32, *buff,
+                   (unsigned)bytes);
 
        /* If we hit the end, swallow any end-of-data marker. */
        if (zip->end_of_entry) {
@@ -1363,9 +1364,9 @@ decompress(struct archive_read *a, struct _7zip *zip,
 #ifdef HAVE_ZLIB_H
        case _7Z_DEFLATE:
                zip->stream.next_in = (Bytef *)(uintptr_t)t_next_in;
-               zip->stream.avail_in = t_avail_in;
+               zip->stream.avail_in = (uInt)t_avail_in;
                zip->stream.next_out = t_next_out;
-               zip->stream.avail_out = t_avail_out;
+               zip->stream.avail_out = (uInt)t_avail_out;
                r = inflate(&(zip->stream), 0);
                switch (r) {
                case Z_STREAM_END: /* Found end of stream. */
@@ -1607,9 +1608,10 @@ read_Digests(struct archive_read *a, struct _7z_digests *d, size_t num)
        const unsigned char *p;
        unsigned i;
 
+       if (num == 0)
+               return (-1);
        memset(d, 0, sizeof(*d));
 
-
        d->defineds = malloc(num);
        if (d->defineds == NULL)
                return (-1);
@@ -2687,7 +2689,7 @@ header_bytes(struct archive_read *a, size_t rbytes)
        }
 
        /* Update checksum */
-       zip->header_crc32 = crc32(zip->header_crc32, p, rbytes);
+       zip->header_crc32 = crc32(zip->header_crc32, p, (unsigned)rbytes);
        return (p);
 }
 
@@ -2966,16 +2968,19 @@ extract_pack_stream(struct archive_read *a, size_t minimum)
                         * Expand the uncompressed buffer up to
                         * the minimum size.
                         */
-                       zip->uncompressed_buffer_size = minimum + 1023;
-                       zip->uncompressed_buffer_size &= ~0x3ff;
-                       zip->uncompressed_buffer =
-                           realloc(zip->uncompressed_buffer,
-                               zip->uncompressed_buffer_size);
-                       if (zip->uncompressed_buffer == NULL) {
+                       void *p;
+                       size_t new_size;
+
+                       new_size = minimum + 1023;
+                       new_size &= ~0x3ff;
+                       p = realloc(zip->uncompressed_buffer, new_size);
+                       if (p == NULL) {
                                archive_set_error(&a->archive, ENOMEM,
                                    "No memory for 7-Zip decompression");
                                return (ARCHIVE_FATAL);
                        }
+                       zip->uncompressed_buffer = (unsigned char *)p;
+                       zip->uncompressed_buffer_size = new_size;
                }
                /*
                 * Move unconsumed bytes to the head.
@@ -3095,7 +3100,7 @@ read_stream(struct archive_read *a, const void **buff, size_t size,
 {
        struct _7zip *zip = (struct _7zip *)a->format->data;
        uint64_t skip_bytes = 0;
-       int r;
+       ssize_t r;
 
        if (zip->uncompressed_buffer_bytes_remaining == 0) {
                if (zip->pack_stream_inbytes_remaining > 0) {
@@ -3346,8 +3351,10 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
                for (i = 0; i < 3; i++) {
                        const struct _7z_coder *coder = scoder[i];
 
-                       if ((r = seek_pack(a)) < 0)
+                       if ((r = seek_pack(a)) < 0) {
+                               free(b[0]); free(b[1]); free(b[2]);
                                return (r);
+                       }
 
                        if (sunpack[i] == (uint64_t)-1)
                                zip->folder_outbytes_remaining =
@@ -3356,13 +3363,16 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
                                zip->folder_outbytes_remaining = sunpack[i];
 
                        r = init_decompression(a, zip, coder, NULL);
-                       if (r != ARCHIVE_OK)
+                       if (r != ARCHIVE_OK) {
+                               free(b[0]); free(b[1]); free(b[2]);
                                return (ARCHIVE_FATAL);
+                       }
 
                        /* Allocate memory for the decorded data of a sub
                         * stream. */
                        b[i] = malloc((size_t)zip->folder_outbytes_remaining);
                        if (b[i] == NULL) {
+                               free(b[0]); free(b[1]); free(b[2]);
                                archive_set_error(&a->archive, ENOMEM,
                                    "No memory for 7-Zip decompression");
                                return (ARCHIVE_FATAL);
@@ -3370,14 +3380,18 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
 
                        /* Extract a sub stream. */
                        while (zip->pack_stream_inbytes_remaining > 0) {
-                               r = extract_pack_stream(a, 0);
-                               if (r < 0)
+                               r = (int)extract_pack_stream(a, 0);
+                               if (r < 0) {
+                                       free(b[0]); free(b[1]); free(b[2]);
                                        return (r);
+                               }
                                bytes = get_uncompressed_data(a, &buff,
                                    zip->uncompressed_buffer_bytes_remaining,
                                    0);
-                               if (bytes < 0)
+                               if (bytes < 0) {
+                                       free(b[0]); free(b[1]); free(b[2]);
                                        return ((int)bytes);
+                               }
                                memcpy(b[i]+s[i], buff, bytes);
                                s[i] += bytes;
                                if (zip->pack_stream_bytes_unconsumed)
@@ -3557,7 +3571,7 @@ x86_Convert(struct _7zip *zip, uint8_t *data, size_t size)
        }
        zip->bcj_prevPosT = prevPosT;
        zip->bcj_prevMask = prevMask;
-       zip->bcj_ip += bufferPos;
+       zip->bcj_ip += (uint32_t)bufferPos;
        return (bufferPos);
 }
 
@@ -3701,7 +3715,7 @@ Bcj2_Decode(struct _7zip *zip, uint8_t *outBuf, size_t outSize)
                            ((uint32_t)v[1] << 16) |
                            ((uint32_t)v[2] << 8) |
                            ((uint32_t)v[3])) -
-                           ((uint32_t)zip->bcj2_outPos + outPos + 4);
+                           ((uint32_t)zip->bcj2_outPos + (uint32_t)outPos + 4);
                        out[0] = (uint8_t)dest;
                        out[1] = (uint8_t)(dest >> 8);
                        out[2] = (uint8_t)(dest >> 16);
@@ -3716,7 +3730,7 @@ Bcj2_Decode(struct _7zip *zip, uint8_t *outBuf, size_t outSize)
                                 */
                                zip->odd_bcj_size = 4 -i;
                                for (; i < 4; i++) {
-                                       j = i - 4 + zip->odd_bcj_size;
+                                       j = i - 4 + (unsigned)zip->odd_bcj_size;
                                        zip->odd_bcj[j] = out[i];
                                }
                                break;
index 9feb547..40be18c 100644 (file)
@@ -121,6 +121,7 @@ archive_read_support_format_ar(struct archive *_a)
            archive_read_format_ar_read_header,
            archive_read_format_ar_read_data,
            archive_read_format_ar_skip,
+           NULL,
            archive_read_format_ar_cleanup);
 
        if (r != ARCHIVE_OK) {
index aa0152a..3c9f94c 100644 (file)
@@ -382,6 +382,7 @@ archive_read_support_format_cab(struct archive *_a)
            archive_read_format_cab_read_header,
            archive_read_format_cab_read_data,
            archive_read_format_cab_read_data_skip,
+           NULL,
            archive_read_format_cab_cleanup);
 
        if (r != ARCHIVE_OK)
@@ -539,7 +540,7 @@ truncated_error(struct archive_read *a)
        return (ARCHIVE_FATAL);
 }
 
-static int
+static ssize_t
 cab_strnlen(const unsigned char *p, size_t maxlen)
 {
        size_t i;
@@ -550,7 +551,7 @@ cab_strnlen(const unsigned char *p, size_t maxlen)
        }
        if (i > maxlen)
                return (-1);/* invalid */
-       return (i);
+       return ((ssize_t)i);
 }
 
 /* Read bytes as much as remaining. */
@@ -626,8 +627,9 @@ cab_read_header(struct archive_read *a)
        struct cab *cab;
        struct cfheader *hd;
        size_t bytes, used;
+       ssize_t len;
        int64_t skip;
-       int err, i, len;
+       int err, i;
        int cur_folder, prev_folder;
        uint32_t offset32;
        
@@ -1066,13 +1068,13 @@ static uint32_t
 cab_checksum_cfdata_4(const void *p, size_t bytes, uint32_t seed)
 {
        const unsigned char *b;
-       int u32num;
+       unsigned u32num;
        uint32_t sum;
 
-       u32num = bytes / 4;
+       u32num = (unsigned)bytes / 4;
        sum = seed;
        b = p;
-       while (--u32num >= 0) {
+       for (;u32num > 0; --u32num) {
                sum ^= archive_le32dec(b);
                b += 4;
        }
@@ -1485,7 +1487,7 @@ cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)
                 * cast to remove 'const'.
                 */
                cab->stream.next_in = (Bytef *)(uintptr_t)d;
-               cab->stream.avail_in = bytes_avail;
+               cab->stream.avail_in = (uInt)bytes_avail;
                cab->stream.total_in = 0;
 
                /* Cut out a tow-byte MSZIP signature(0x43, 0x4b). */
@@ -1506,7 +1508,7 @@ cab_read_ahead_cfdata_deflate(struct archive_read *a, ssize_t *avail)
                                        *avail = ARCHIVE_FATAL;
                                        return (NULL);
                                }
-                               mszip -= bytes_avail;
+                               mszip -= (int)bytes_avail;
                                continue;
                        }
                        if (mszip == 1 && cab->stream.next_in[0] != 0x4b)
@@ -1935,7 +1937,7 @@ cab_read_data(struct archive_read *a, const void **buff,
                            ARCHIVE_ERRNO_FILE_FORMAT, "Invalid CFDATA");
                        return (ARCHIVE_FATAL);
                } else
-                       return (bytes_avail);
+                       return ((int)bytes_avail);
        }
        if (bytes_avail > cab->entry_bytes_remaining)
                bytes_avail = (ssize_t)cab->entry_bytes_remaining;
@@ -2001,7 +2003,8 @@ archive_read_format_cab_read_data_skip(struct archive_read *a)
 
        /* If the compression type is none(uncompressed), we've already
         * consumed data as much as the current entry size. */
-       if (cab->entry_cffolder->comptype == COMPTYPE_NONE)
+       if (cab->entry_cffolder->comptype == COMPTYPE_NONE &&
+           cab->entry_cfdata != NULL)
                cab->entry_cfdata->unconsumed = 0;
 
        /* This entry is finished and done. */
@@ -2198,7 +2201,7 @@ lzx_translation(struct lzx_stream *strm, void *p, size_t size, uint32_t offset)
                size_t i = b - (unsigned char *)p;
                int32_t cp, displacement, value;
 
-               cp = offset + i;
+               cp = (int32_t)(offset + (uint32_t)i);
                value = archive_le32dec(&b[1]);
                if (value >= -cp && value < (int32_t)ds->translation_size) {
                        if (value >= 0)
@@ -2584,7 +2587,7 @@ lzx_read_blocks(struct lzx_stream *strm, int last)
                                                goto failed;
                                        return (ARCHIVE_OK);
                                }
-                               l = ds->block_bytes_avail;
+                               l = (int)ds->block_bytes_avail;
                                if (l > ds->w_size - ds->w_pos)
                                        l = ds->w_size - ds->w_pos;
                                if (l > strm->avail_out)
@@ -2746,8 +2749,8 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
        struct lzx_br bre = ds->br;
        struct huffman *at = &(ds->at), *lt = &(ds->lt), *mt = &(ds->mt);
        const struct lzx_pos_tbl *pos_tbl = ds->pos_tbl;
-       unsigned char *outp = strm->next_out;
-       unsigned char *endp = outp + strm->avail_out;
+       unsigned char *noutp = strm->next_out;
+       unsigned char *endp = noutp + strm->avail_out;
        unsigned char *w_buff = ds->w_buff;
        unsigned char *at_bitlen = at->bitlen;
        unsigned char *lt_bitlen = lt->bitlen;
@@ -2781,10 +2784,10 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
                                        ds->position_slot = position_slot;
                                        ds->r0 = r0; ds->r1 = r1; ds->r2 = r2;
                                        ds->w_pos = w_pos;
-                                       strm->avail_out = endp - outp;
+                                       strm->avail_out = endp - noutp;
                                        return (ARCHIVE_EOF);
                                }
-                               if (outp >= endp)
+                               if (noutp >= endp)
                                        /* Output buffer is empty. */
                                        goto next_data;
 
@@ -2818,7 +2821,7 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
                                w_buff[w_pos] = c;
                                w_pos = (w_pos + 1) & w_mask;
                                /* Store the decoded code to output buffer. */
-                               *outp++ = c;
+                               *noutp++ = c;
                                block_bytes_avail--;
                        }
                        /*
@@ -2963,22 +2966,22 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
                                        if (l > w_size - w_pos)
                                                l = w_size - w_pos;
                                }
-                               if (outp + l >= endp)
-                                       l = endp - outp;
+                               if (noutp + l >= endp)
+                                       l = (int)(endp - noutp);
                                s = w_buff + copy_pos;
                                if (l >= 8 && ((copy_pos + l < w_pos)
                                  || (w_pos + l < copy_pos))) {
                                        memcpy(w_buff + w_pos, s, l);
-                                       memcpy(outp, s, l);
+                                       memcpy(noutp, s, l);
                                } else {
                                        unsigned char *d;
                                        int li;
 
                                        d = w_buff + w_pos;
                                        for (li = 0; li < l; li++)
-                                               outp[li] = d[li] = s[li];
+                                               noutp[li] = d[li] = s[li];
                                }
-                               outp += l;
+                               noutp += l;
                                copy_pos = (copy_pos + l) & w_mask;
                                w_pos = (w_pos + l) & w_mask;
                                block_bytes_avail -= l;
@@ -2986,7 +2989,7 @@ lzx_decode_blocks(struct lzx_stream *strm, int last)
                                        /* A copy of current pattern ended. */
                                        break;
                                copy_len -= l;
-                               if (outp >= endp) {
+                               if (noutp >= endp) {
                                        /* Output buffer is empty. */
                                        state = ST_COPY;
                                        goto next_data;
@@ -3009,7 +3012,7 @@ next_data:
        ds->r0 = r0; ds->r1 = r1; ds->r2 = r2;
        ds->state = state;
        ds->w_pos = w_pos;
-       strm->avail_out = endp - outp;
+       strm->avail_out = endp - noutp;
        return (ARCHIVE_OK);
 }
 
@@ -3126,7 +3129,7 @@ lzx_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits)
                hf->bitlen = calloc(len_size,  sizeof(hf->bitlen[0]));
                if (hf->bitlen == NULL)
                        return (ARCHIVE_FATAL);
-               hf->len_size = len_size;
+               hf->len_size = (int)len_size;
        } else
                memset(hf->bitlen, 0, len_size *  sizeof(hf->bitlen[0]));
        if (hf->tbl == NULL) {
@@ -3134,7 +3137,7 @@ lzx_huffman_init(struct huffman *hf, size_t len_size, int tbl_bits)
                        bits = tbl_bits;
                else
                        bits = HTBL_BITS;
-               hf->tbl = malloc((1 << bits) * sizeof(hf->tbl[0]));
+               hf->tbl = malloc(((size_t)1 << bits) * sizeof(hf->tbl[0]));
                if (hf->tbl == NULL)
                        return (ARCHIVE_FATAL);
                hf->tbl_bits = tbl_bits;
index ff29e1f..819f4a4 100644 (file)
@@ -242,6 +242,7 @@ archive_read_support_format_cpio(struct archive *_a)
            archive_read_format_cpio_read_header,
            archive_read_format_cpio_read_data,
            archive_read_format_cpio_skip,
+           NULL,
            archive_read_format_cpio_cleanup);
 
        if (r != ARCHIVE_OK)
index 3dc2196..3660738 100644 (file)
@@ -53,6 +53,7 @@ archive_read_support_format_empty(struct archive *_a)
            archive_read_format_empty_read_header,
            archive_read_format_empty_read_data,
            NULL,
+           NULL,
            NULL);
 
        return (r);
index d38c7cf..914bc71 100644 (file)
@@ -1,7 +1,7 @@
 /*-
  * Copyright (c) 2003-2007 Tim Kientzle
  * Copyright (c) 2009 Andreas Henriksson <andreas@fatal.se>
- * Copyright (c) 2009-2011 Michihiro NAKAJIMA
+ * Copyright (c) 2009-2012 Michihiro NAKAJIMA
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -374,6 +374,8 @@ struct iso9660 {
        size_t           utf16be_path_len;
        unsigned char *utf16be_previous_path;
        size_t           utf16be_previous_path_len;
+       /* Null buufer used in bidder to improve its performance. */
+       unsigned char    null[2048];
 };
 
 static int     archive_read_format_iso9660_bid(struct archive_read *, int);
@@ -475,6 +477,7 @@ archive_read_support_format_iso9660(struct archive *_a)
            archive_read_format_iso9660_read_header,
            archive_read_format_iso9660_read_data,
            archive_read_format_iso9660_read_data_skip,
+           NULL,
            archive_read_format_iso9660_cleanup);
 
        if (r != ARCHIVE_OK) {
@@ -587,6 +590,23 @@ archive_read_format_iso9660_options(struct archive_read *a,
        return (ARCHIVE_WARN);
 }
 
+static int
+isNull(struct iso9660 *iso9660, const unsigned char *h, unsigned offset,
+unsigned bytes)
+{
+
+       while (bytes >= sizeof(iso9660->null)) {
+               if (!memcmp(iso9660->null, h + offset, sizeof(iso9660->null)))
+                       return (0);
+               offset += sizeof(iso9660->null);
+               bytes -= sizeof(iso9660->null);
+       }
+       if (bytes)
+               return memcmp(iso9660->null, h + offset, bytes) == 0;
+       else
+               return (1);
+}
+
 static int
 isBootRecord(struct iso9660 *iso9660, const unsigned char *h)
 {
@@ -632,8 +652,6 @@ isVolumePartition(struct iso9660 *iso9660, const unsigned char *h)
 static int
 isVDSetTerminator(struct iso9660 *iso9660, const unsigned char *h)
 {
-       int i;
-
        (void)iso9660; /* UNUSED */
 
        /* Type of the Volume Descriptor Set Terminator must be 255. */
@@ -645,9 +663,8 @@ isVDSetTerminator(struct iso9660 *iso9660, const unsigned char *h)
                return (0);
 
        /* Reserved field must be 0. */
-       for (i = 7; i < 2048; ++i)
-               if (h[i] != 0)
-                       return (0);
+       if (!isNull(iso9660, h, 7, 2048-7))
+               return (0);
 
        return (1);
 }
@@ -708,7 +725,6 @@ isSVD(struct iso9660 *iso9660, const unsigned char *h)
        ssize_t logical_block_size;
        int32_t volume_block;
        int32_t location;
-       int i;
 
        (void)iso9660; /* UNUSED */
 
@@ -717,15 +733,12 @@ isSVD(struct iso9660 *iso9660, const unsigned char *h)
                return (0);
 
        /* Reserved field must be 0. */
-       for (i = 0; i < SVD_reserved1_size; ++i)
-               if (h[SVD_reserved1_offset + i] != 0)
-                       return (0);
-       for (i = 0; i < SVD_reserved2_size; ++i)
-               if (h[SVD_reserved2_offset + i] != 0)
-                       return (0);
-       for (i = 0; i < SVD_reserved3_size; ++i)
-               if (h[SVD_reserved3_offset + i] != 0)
-                       return (0);
+       if (!isNull(iso9660, h, SVD_reserved1_offset, SVD_reserved1_size))
+               return (0);
+       if (!isNull(iso9660, h, SVD_reserved2_offset, SVD_reserved2_size))
+               return (0);
+       if (!isNull(iso9660, h, SVD_reserved3_offset, SVD_reserved3_size))
+               return (0);
 
        /* File structure version must be 1 for ISO9660/ECMA119. */
        if (h[SVD_file_structure_version_offset] != 1)
@@ -771,7 +784,6 @@ isEVD(struct iso9660 *iso9660, const unsigned char *h)
        ssize_t logical_block_size;
        int32_t volume_block;
        int32_t location;
-       int i;
 
        (void)iso9660; /* UNUSED */
 
@@ -788,14 +800,12 @@ isEVD(struct iso9660 *iso9660, const unsigned char *h)
                return (0);
 
        /* Reserved field must be 0. */
-       for (i = 0; i < PVD_reserved2_size; ++i)
-               if (h[PVD_reserved2_offset + i] != 0)
-                       return (0);
+       if (!isNull(iso9660, h, PVD_reserved2_offset, PVD_reserved2_size))
+               return (0);
 
        /* Reserved field must be 0. */
-       for (i = 0; i < PVD_reserved3_size; ++i)
-               if (h[PVD_reserved3_offset + i] != 0)
-                       return (0);
+       if (!isNull(iso9660, h, PVD_reserved3_offset, PVD_reserved3_size))
+               return (0);
 
        /* Logical block size must be > 0. */
        /* I've looked at Ecma 119 and can't find any stronger
@@ -830,14 +840,12 @@ isEVD(struct iso9660 *iso9660, const unsigned char *h)
                return (0);
 
        /* Reserved field must be 0. */
-       for (i = 0; i < PVD_reserved4_size; ++i)
-               if (h[PVD_reserved4_offset + i] != 0)
-                       return (0);
+       if (!isNull(iso9660, h, PVD_reserved4_offset, PVD_reserved4_size))
+               return (0);
 
        /* Reserved field must be 0. */
-       for (i = 0; i < PVD_reserved5_size; ++i)
-               if (h[PVD_reserved5_offset + i] != 0)
-                       return (0);
+       if (!isNull(iso9660, h, PVD_reserved5_offset, PVD_reserved5_size))
+               return (0);
 
        /* Read Root Directory Record in Volume Descriptor. */
        p = h + PVD_root_directory_record_offset;
@@ -869,14 +877,12 @@ isPVD(struct iso9660 *iso9660, const unsigned char *h)
                return (0);
 
        /* Reserved field must be 0. */
-       for (i = 0; i < PVD_reserved2_size; ++i)
-               if (h[PVD_reserved2_offset + i] != 0)
-                       return (0);
+       if (!isNull(iso9660, h, PVD_reserved2_offset, PVD_reserved2_size))
+               return (0);
 
        /* Reserved field must be 0. */
-       for (i = 0; i < PVD_reserved3_size; ++i)
-               if (h[PVD_reserved3_offset + i] != 0)
-                       return (0);
+       if (!isNull(iso9660, h, PVD_reserved3_offset, PVD_reserved3_size))
+               return (0);
 
        /* Logical block size must be > 0. */
        /* I've looked at Ecma 119 and can't find any stronger
@@ -919,9 +925,8 @@ isPVD(struct iso9660 *iso9660, const unsigned char *h)
                        return (0);
 
        /* Reserved field must be 0. */
-       for (i = 0; i < PVD_reserved5_size; ++i)
-               if (h[PVD_reserved5_offset + i] != 0)
-                       return (0);
+       if (!isNull(iso9660, h, PVD_reserved5_offset, PVD_reserved5_size))
+               return (0);
 
        /* XXX TODO: Check other values for sanity; reject more
         * malformed PVDs. XXX */
@@ -934,8 +939,10 @@ isPVD(struct iso9660 *iso9660, const unsigned char *h)
        if (!iso9660->primary.location) {
                iso9660->logical_block_size = logical_block_size;
                iso9660->volume_block = volume_block;
-               iso9660->volume_size = logical_block_size * (uint64_t)volume_block;
-               iso9660->primary.location = archive_le32dec(p + DR_extent_offset);
+               iso9660->volume_size =
+                   logical_block_size * (uint64_t)volume_block;
+               iso9660->primary.location =
+                   archive_le32dec(p + DR_extent_offset);
                iso9660->primary.size = archive_le32dec(p + DR_size_offset);
        }
 
@@ -951,6 +958,12 @@ read_children(struct archive_read *a, struct file_info *parent)
        size_t step, skip_size;
 
        iso9660 = (struct iso9660 *)(a->format->data);
+       /* flush any remaining bytes from the last round to ensure
+        * we're positioned */
+       if (iso9660->entry_bytes_unconsumed) {
+               __archive_read_consume(a, iso9660->entry_bytes_unconsumed);
+               iso9660->entry_bytes_unconsumed = 0;
+       }
        if (iso9660->current_position > parent->offset) {
                archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
                    "Ignoring out-of-order directory (%s) %jd > %jd",
@@ -1060,101 +1073,112 @@ read_children(struct archive_read *a, struct file_info *parent)
 }
 
 static int
-archive_read_format_iso9660_read_header(struct archive_read *a,
-    struct archive_entry *entry)
+choose_volume(struct archive_read *a, struct iso9660 *iso9660)
 {
-       struct iso9660 *iso9660;
        struct file_info *file;
-       int r, rd_r = ARCHIVE_OK;
-
-       iso9660 = (struct iso9660 *)(a->format->data);
+       int64_t skipsize;
+       struct vd *vd;
+       const void *block;
+       char seenJoliet;
 
-       if (!a->archive.archive_format) {
-               a->archive.archive_format = ARCHIVE_FORMAT_ISO9660;
-               a->archive.archive_format_name = "ISO9660";
+       vd = &(iso9660->primary);
+       if (!iso9660->opt_support_joliet)
+               iso9660->seenJoliet = 0;
+       if (iso9660->seenJoliet &&
+               vd->location > iso9660->joliet.location)
+               /* This condition is unlikely; by way of caution. */
+               vd = &(iso9660->joliet);
+
+       skipsize = LOGICAL_BLOCK_SIZE * vd->location;
+       skipsize = __archive_read_consume(a, skipsize);
+       if (skipsize < 0)
+               return ((int)skipsize);
+       iso9660->current_position = skipsize;
+
+       block = __archive_read_ahead(a, vd->size, NULL);
+       if (block == NULL) {
+               archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+                   "Failed to read full block when scanning "
+                   "ISO9660 directory list");
+               return (ARCHIVE_FATAL);
        }
 
-       if (iso9660->current_position == 0) {
-               int64_t skipsize;
-               struct vd *vd;
-               const void *block;
-               char seenJoliet;
-
-               vd = &(iso9660->primary);
-               if (!iso9660->opt_support_joliet)
-                       iso9660->seenJoliet = 0;
-               if (iso9660->seenJoliet &&
-                       vd->location > iso9660->joliet.location)
-                       /* This condition is unlikely; by way of caution. */
-                       vd = &(iso9660->joliet);
+       /*
+        * While reading Root Directory, flag seenJoliet must be zero to
+        * avoid converting special name 0x00(Current Directory) and
+        * next byte to UCS2.
+        */
+       seenJoliet = iso9660->seenJoliet;/* Save flag. */
+       iso9660->seenJoliet = 0;
+       file = parse_file_info(a, NULL, block);
+       if (file == NULL)
+               return (ARCHIVE_FATAL);
+       iso9660->seenJoliet = seenJoliet;
+
+       /*
+        * If the iso image has both RockRidge and Joliet, we preferentially
+        * use RockRidge Extensions rather than Joliet ones.
+        */
+       if (vd == &(iso9660->primary) && iso9660->seenRockridge
+           && iso9660->seenJoliet)
+               iso9660->seenJoliet = 0;
 
+       if (vd == &(iso9660->primary) && !iso9660->seenRockridge
+           && iso9660->seenJoliet) {
+               /* Switch reading data from primary to joliet. */
+               vd = &(iso9660->joliet);
                skipsize = LOGICAL_BLOCK_SIZE * vd->location;
+               skipsize -= iso9660->current_position;