summaryrefslogtreecommitdiff
path: root/libarchive/archive_read_support_format_tar.c
diff options
context:
space:
mode:
authorKevin Locke <kevin@kevinlocke.name>2014-01-11 16:38:52 -0700
committerKevin Locke <kevin@kevinlocke.name>2014-01-12 13:44:57 -0700
commitb66ce8c56072aae09601ed04f75888d94c0722e2 (patch)
treec49bd064cb0d88dcf61a4204499fe8afe0b4ef56 /libarchive/archive_read_support_format_tar.c
parenta6c076b1c844f41d471c06da1db770efe5518e20 (diff)
downloadlibarchive-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.c66
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.
+ */
}
/*