]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
[PATCH v3] Add read_concatenated_archives
authorKevin Locke <kevin@kevinlocke.name>
Sat, 11 Jan 2014 23:38:52 +0000 (16:38 -0700)
committerKevin Locke <kevin@kevinlocke.name>
Sun, 12 Jan 2014 20:44:57 +0000 (13:44 -0700)
As discussed in http://code.google.com/p/libarchive/issues/detail?id=348
the read_concatenated_archives option provides functionality similar to
the GNUtar --ignore-zeros option in order to support reading from
archives which have been concatenated together.

Changes in v2:
 * Replace recursion with looping for reading concatenated archives.

Changes in v3:
 * Improve comments about archive format detection and looping when
   reading concatenated archives.

Signed-off-by: Kevin Locke <kevin@kevinlocke.name>
libarchive/archive_read_set_options.3
libarchive/archive_read_support_format_tar.c
tar/bsdtar.1

index d400272dea7b002a5549b8bec8b8e1f0a60555ee..1a251cefecd105e7adda144fe1bca1c8038e0622 100644 (file)
@@ -210,6 +210,10 @@ Defaults to enabled on Mac OS, disabled on other platforms.
 Use
 .Cm !mac-ext
 to disable.
+.It Cm read_concatenated_archives
+Ignore zeroed blocks in the archive, which occurs when multiple tar archives
+have been concatenated together.  Without this option, only the contents of
+the first concatenated archive would be read.
 .El
 .El
 .\"
index 70d2e12c2983b5d4d16d84b676f0fced24ab42a5..051d678cbc2ffd1bd98290438840c4272f732f96 100644 (file)
@@ -152,6 +152,7 @@ struct tar {
        int                      init_default_conversion;
        int                      compat_2x;
        int                      process_mac_extensions;
+       int                      read_concatenated_archives;
 };
 
 static int     archive_block_is_null(const char *p);
@@ -395,6 +396,9 @@ archive_read_format_tar_options(struct archive_read *a,
        } else if (strcmp(key, "mac-ext") == 0) {
                tar->process_mac_extensions = (val != NULL && val[0] != 0);
                return (ARCHIVE_OK);
+       } else if (strcmp(key, "read_concatenated_archives") == 0) {
+               tar->read_concatenated_archives = (val != NULL && val[0] != 0);
+               return (ARCHIVE_OK);
        }
 
        /* Note: The "warn" return is just to inform the options
@@ -629,36 +633,50 @@ tar_read_header(struct archive_read *a, struct tar *tar,
        const struct archive_entry_header_ustar *header;
        const struct archive_entry_header_gnutar *gnuheader;
 
-       tar_flush_unconsumed(a, unconsumed);
+       /* Loop until we find a workable header record. */
+       for (;;) {
+               tar_flush_unconsumed(a, unconsumed);
 
-       /* Read 512-byte header record */
-       h = __archive_read_ahead(a, 512, &bytes);
-       if (bytes < 0)
-               return ((int)bytes);
-       if (bytes == 0) { /* EOF at a block boundary. */
-               /* Some writers do omit the block of nulls. <sigh> */
-               return (ARCHIVE_EOF);
-       }
-       if (bytes < 512) {  /* Short block at EOF; this is bad. */
-               archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
-                   "Truncated tar archive");
-               return (ARCHIVE_FATAL);
-       }
-       *unconsumed = 512;
+               /* Read 512-byte header record */
+               h = __archive_read_ahead(a, 512, &bytes);
+               if (bytes < 0)
+                       return ((int)bytes);
+               if (bytes == 0) { /* EOF at a block boundary. */
+                       /* Some writers do omit the block of nulls. <sigh> */
+                       return (ARCHIVE_EOF);
+               }
+               if (bytes < 512) {  /* Short block at EOF; this is bad. */
+                       archive_set_error(&a->archive,
+                           ARCHIVE_ERRNO_FILE_FORMAT,
+                           "Truncated tar archive");
+                       return (ARCHIVE_FATAL);
+               }
+               *unconsumed = 512;
 
-       /* Check for end-of-archive mark. */
-       if (h[0] == 0 && archive_block_is_null(h)) {
-               /* Try to consume a second all-null record, as well. */
-               tar_flush_unconsumed(a, unconsumed);
-               h = __archive_read_ahead(a, 512, NULL);
-               if (h != NULL && h[0] == 0 && archive_block_is_null(h))
-                       __archive_read_consume(a, 512);
-               archive_clear_error(&a->archive);
+               /* Header is workable if it's not an end-of-archive mark. */
+               if (h[0] != 0 || !archive_block_is_null(h))
+                       break;
+
+               /* Ensure format is set for archives with only null blocks. */
                if (a->archive.archive_format_name == NULL) {
                        a->archive.archive_format = ARCHIVE_FORMAT_TAR;
                        a->archive.archive_format_name = "tar";
                }
-               return (ARCHIVE_EOF);
+
+               if (!tar->read_concatenated_archives) {
+                       /* Try to consume a second all-null record, as well. */
+                       tar_flush_unconsumed(a, unconsumed);
+                       h = __archive_read_ahead(a, 512, NULL);
+                       if (h != NULL && h[0] == 0 && archive_block_is_null(h))
+                               __archive_read_consume(a, 512);
+                       archive_clear_error(&a->archive);
+                       return (ARCHIVE_EOF);
+               }
+
+               /*
+                * We're reading concatenated archives, ignore this block and
+                * loop to get the next.
+                */
        }
 
        /*
index 7bb6a6084d54e81fbe8e89dd9b3207737ae85272..b5ea142957b1505c10fcedd3cd7647e67acf20ff 100644 (file)
@@ -524,6 +524,13 @@ Use
 .Ar type
 as compression method.
 Supported values are store (uncompressed) and deflate (gzip algorithm).
+.It Cm read_concatenated_archives
+Ignore zeroed blocks in the archive, which occurs when multiple tar archives
+have been concatenated together.  Without this option, only the contents of
+the first concatenated archive would be read.  This option is comparable to
+the
+.Fl i , Fl Fl ignore-zeros
+option of GNU tar.
 .El
 If a provided option is not supported by any module, that
 is a fatal error.