From: Kevin Locke Date: Sat, 11 Jan 2014 23:38:52 +0000 (-0700) Subject: [PATCH v3] Add read_concatenated_archives X-Git-Tag: v3.1.900a~331 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b66ce8c56072aae09601ed04f75888d94c0722e2;p=thirdparty%2Flibarchive.git [PATCH v3] Add read_concatenated_archives 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 --- diff --git a/libarchive/archive_read_set_options.3 b/libarchive/archive_read_set_options.3 index d400272de..1a251cefe 100644 --- a/libarchive/archive_read_set_options.3 +++ b/libarchive/archive_read_set_options.3 @@ -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 .\" diff --git a/libarchive/archive_read_support_format_tar.c b/libarchive/archive_read_support_format_tar.c index 70d2e12c2..051d678cb 100644 --- a/libarchive/archive_read_support_format_tar.c +++ b/libarchive/archive_read_support_format_tar.c @@ -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. */ - 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. */ + 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. + */ } /* diff --git a/tar/bsdtar.1 b/tar/bsdtar.1 index 7bb6a6084..b5ea14295 100644 --- a/tar/bsdtar.1 +++ b/tar/bsdtar.1 @@ -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.