diff options
author | Kevin Locke <kevin@kevinlocke.name> | 2014-01-11 16:38:52 -0700 |
---|---|---|
committer | Kevin Locke <kevin@kevinlocke.name> | 2014-01-12 13:44:57 -0700 |
commit | b66ce8c56072aae09601ed04f75888d94c0722e2 (patch) | |
tree | c49bd064cb0d88dcf61a4204499fe8afe0b4ef56 /libarchive/archive_read_support_format_tar.c | |
parent | a6c076b1c844f41d471c06da1db770efe5518e20 (diff) | |
download | libarchive-b66ce8c56072aae09601ed04f75888d94c0722e2.tar.gz |
[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 <kevin@kevinlocke.name>
Diffstat (limited to 'libarchive/archive_read_support_format_tar.c')
-rw-r--r-- | libarchive/archive_read_support_format_tar.c | 66 |
1 files changed, 42 insertions, 24 deletions
diff --git a/libarchive/archive_read_support_format_tar.c b/libarchive/archive_read_support_format_tar.c index 70d2e12c..051d678c 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. <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. + */ } /* |