summaryrefslogtreecommitdiffstats
path: root/lib/libarchive/archive_read_support_format_tar.c
diff options
context:
space:
mode:
authorkientzle <kientzle@FreeBSD.org>2006-07-30 00:29:01 +0000
committerkientzle <kientzle@FreeBSD.org>2006-07-30 00:29:01 +0000
commitf501dbec5fe3a8ec80a115b83f7f07e2671bfc95 (patch)
tree7a38c3d6e84fc5da7d1e72df478099c6b6a417f6 /lib/libarchive/archive_read_support_format_tar.c
parent61dd143cfb0a5bd3bf9dc7304f3f4126ae2e5acd (diff)
downloadFreeBSD-src-f501dbec5fe3a8ec80a115b83f7f07e2671bfc95.zip
FreeBSD-src-f501dbec5fe3a8ec80a115b83f7f07e2671bfc95.tar.gz
Use 'skip' when ignoring data in tar archives. This dramatically
increases performance when extracting a single entry from a large uncompressed archive, especially on slow devices such as USB hard drives. Requires a number of changes: * New archive_read_open2() supports a 'skip' client function * Old archive_read_open() is implemented as a wrapper now, to continue supporting the old API/ABI. * _read_open_fd and _read_open_file sprout new 'skip' functions. * compression layer gets a new 'skip' operation. * compression_none passes skip requests through to client. * compression_{gzip,bzip2,compress} simply ignore skip requests. Thanks to: Benjamin Lutz, who designed and implemented the whole thing. I'm just committing it. ;-) TODO: Need to update the documentation a little bit.
Diffstat (limited to 'lib/libarchive/archive_read_support_format_tar.c')
-rw-r--r--lib/libarchive/archive_read_support_format_tar.c47
1 files changed, 46 insertions, 1 deletions
diff --git a/lib/libarchive/archive_read_support_format_tar.c b/lib/libarchive/archive_read_support_format_tar.c
index 271a41f..cc0b5ed 100644
--- a/lib/libarchive/archive_read_support_format_tar.c
+++ b/lib/libarchive/archive_read_support_format_tar.c
@@ -193,6 +193,7 @@ static int archive_read_format_tar_bid(struct archive *);
static int archive_read_format_tar_cleanup(struct archive *);
static int archive_read_format_tar_read_data(struct archive *a,
const void **buff, size_t *size, off_t *offset);
+static int archive_read_format_tar_skip(struct archive *a);
static int archive_read_format_tar_read_header(struct archive *,
struct archive_entry *);
static int checksum(struct archive *, const void *);
@@ -260,7 +261,7 @@ archive_read_support_format_tar(struct archive *a)
archive_read_format_tar_bid,
archive_read_format_tar_read_header,
archive_read_format_tar_read_data,
- NULL,
+ archive_read_format_tar_skip,
archive_read_format_tar_cleanup);
if (r != ARCHIVE_OK)
@@ -522,6 +523,50 @@ archive_read_format_tar_read_data(struct archive *a,
}
}
+static int
+archive_read_format_tar_skip(struct archive *a)
+{
+ ssize_t bytes_skipped;
+ struct tar* tar;
+ struct sparse_block *p;
+ int r = ARCHIVE_OK;
+ const void *b; /* dummy variables */
+ size_t s;
+ off_t o;
+
+
+ tar = *(a->pformat_data);
+ if (a->compression_skip == NULL) {
+ while (r == ARCHIVE_OK)
+ r = archive_read_format_tar_read_data(a, &b, &s, &o);
+ return (r);
+ }
+ bytes_skipped = (a->compression_skip)(a, tar->entry_bytes_remaining);
+ if (bytes_skipped < 0)
+ return (ARCHIVE_FATAL);
+ /* same code as above in _tar_read_data() */
+ tar->entry_bytes_remaining -= bytes_skipped;
+ while (tar->sparse_list != NULL &&
+ tar->sparse_list->remaining == 0) {
+ p = tar->sparse_list;
+ tar->sparse_list = p->next;
+ free(p);
+ if (tar->sparse_list != NULL)
+ tar->entry_offset = tar->sparse_list->offset;
+ }
+ if (tar->sparse_list != NULL) {
+ if (tar->sparse_list->remaining < bytes_skipped)
+ bytes_skipped = tar->sparse_list->remaining;
+ tar->sparse_list->remaining -= bytes_skipped;
+ }
+ tar->entry_offset += bytes_skipped;
+ tar->entry_bytes_remaining -= bytes_skipped;
+ /* Reuse padding code above. */
+ while (r == ARCHIVE_OK)
+ r = archive_read_format_tar_read_data(a, &b, &s, &o);
+ return (r);
+}
+
/*
* This function recursively interprets all of the headers associated
* with a single entry.
OpenPOWER on IntegriCloud