diff options
author | kientzle <kientzle@FreeBSD.org> | 2006-07-30 00:29:01 +0000 |
---|---|---|
committer | kientzle <kientzle@FreeBSD.org> | 2006-07-30 00:29:01 +0000 |
commit | f501dbec5fe3a8ec80a115b83f7f07e2671bfc95 (patch) | |
tree | 7a38c3d6e84fc5da7d1e72df478099c6b6a417f6 /lib/libarchive/archive_read_support_format_tar.c | |
parent | 61dd143cfb0a5bd3bf9dc7304f3f4126ae2e5acd (diff) | |
download | FreeBSD-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.c | 47 |
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. |