summaryrefslogtreecommitdiffstats
path: root/lib/libarchive
diff options
context:
space:
mode:
authorkientzle <kientzle@FreeBSD.org>2008-12-06 06:45:15 +0000
committerkientzle <kientzle@FreeBSD.org>2008-12-06 06:45:15 +0000
commite59163f249e40175754ba81c7d87afbe5d1ed3b5 (patch)
tree07033908f13a75f6e70696ff70c73d1160bb8e74 /lib/libarchive
parent01e9b693cc22dbc3f9dcb3d8873312befa9c0e25 (diff)
downloadFreeBSD-src-e59163f249e40175754ba81c7d87afbe5d1ed3b5.zip
FreeBSD-src-e59163f249e40175754ba81c7d87afbe5d1ed3b5.tar.gz
MfP4: Big read filter refactoring.
This is an attempt to eliminate a lot of redundant code from the read ("decompression") filters by changing them to juggle arbitrary-sized blocks and consolidate reblocking code at a single point in archive_read.c. Along the way, I've changed the internal read/consume API used by the format handlers to a slightly different style originally suggested by des@. It does seem to simplify a lot of common cases. The most dramatic change is, of course, to archive_read_support_compression_none(), which has just evaporated into a no-op as the blocking code this used to hold has all been moved up a level. There's at least one more big round of refactoring yet to come before the individual filters are as straightforward as I think they should be...
Diffstat (limited to 'lib/libarchive')
-rw-r--r--lib/libarchive/archive_read.c598
-rw-r--r--lib/libarchive/archive_read_private.h138
-rw-r--r--lib/libarchive/archive_read_support_compression_all.c6
-rw-r--r--lib/libarchive/archive_read_support_compression_bzip2.c411
-rw-r--r--lib/libarchive/archive_read_support_compression_compress.c213
-rw-r--r--lib/libarchive/archive_read_support_compression_gzip.c633
-rw-r--r--lib/libarchive/archive_read_support_compression_none.c338
-rw-r--r--lib/libarchive/archive_read_support_compression_program.c222
-rw-r--r--lib/libarchive/archive_read_support_format_ar.c56
-rw-r--r--lib/libarchive/archive_read_support_format_cpio.c74
-rw-r--r--lib/libarchive/archive_read_support_format_empty.c5
-rw-r--r--lib/libarchive/archive_read_support_format_iso9660.c40
-rw-r--r--lib/libarchive/archive_read_support_format_mtree.c35
-rw-r--r--lib/libarchive/archive_read_support_format_tar.c103
-rw-r--r--lib/libarchive/archive_read_support_format_zip.c105
15 files changed, 1427 insertions, 1550 deletions
diff --git a/lib/libarchive/archive_read.c b/lib/libarchive/archive_read.c
index 259fd7c..6973847 100644
--- a/lib/libarchive/archive_read.c
+++ b/lib/libarchive/archive_read.c
@@ -53,9 +53,10 @@ __FBSDID("$FreeBSD$");
#include "archive_private.h"
#include "archive_read_private.h"
-static void choose_decompressor(struct archive_read *, const void*, size_t);
+#define minimum(a, b) (a < b ? a : b)
+
+static int build_stream(struct archive_read *);
static int choose_format(struct archive_read *);
-static off_t dummy_skip(struct archive_read *, off_t);
/*
* Allocate, initialize and return a struct archive object.
@@ -74,8 +75,15 @@ archive_read_new(void)
a->archive.state = ARCHIVE_STATE_NEW;
a->entry = archive_entry_new();
- /* We always support uncompressed archives. */
- archive_read_support_compression_none(&a->archive);
+ /* Initialize reblocking logic. */
+ a->buffer_size = 64 * 1024; /* 64k */
+ a->buffer = (char *)malloc(a->buffer_size);
+ a->next = a->buffer;
+ if (a->buffer == NULL) {
+ archive_entry_free(a->entry);
+ free(a);
+ return (NULL);
+ }
return (&a->archive);
}
@@ -108,6 +116,33 @@ archive_read_open(struct archive *a, void *client_data,
client_reader, NULL, client_closer);
}
+static ssize_t
+client_read_proxy(struct archive_read_source *self, const void **buff)
+{
+ return (self->archive->client.reader)((struct archive *)self->archive,
+ self->data, buff);
+}
+
+static int64_t
+client_skip_proxy(struct archive_read_source *self, int64_t request)
+{
+ return (self->archive->client.skipper)((struct archive *)self->archive,
+ self->data, request);
+}
+
+static int
+client_close_proxy(struct archive_read_source *self)
+{
+ int r = ARCHIVE_OK;
+
+ if (self->archive->client.closer != NULL)
+ r = (self->archive->client.closer)((struct archive *)self->archive,
+ self->data);
+ free(self);
+ return (r);
+}
+
+
int
archive_read_open2(struct archive *_a, void *client_data,
archive_open_callback *client_opener,
@@ -116,28 +151,15 @@ archive_read_open2(struct archive *_a, void *client_data,
archive_close_callback *client_closer)
{
struct archive_read *a = (struct archive_read *)_a;
- const void *buffer;
- ssize_t bytes_read;
int e;
- __archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_open");
+ __archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
+ "archive_read_open");
if (client_reader == NULL)
__archive_errx(1,
"No reader function provided to archive_read_open");
- /*
- * Set these NULL initially. If the open or initial read fails,
- * we'll leave them NULL to indicate that the file is invalid.
- * (In particular, this helps ensure that the closer doesn't
- * get called more than once.)
- */
- a->client_opener = NULL;
- a->client_reader = NULL;
- a->client_skipper = NULL;
- a->client_closer = NULL;
- a->client_data = NULL;
-
/* Open data source. */
if (client_opener != NULL) {
e =(client_opener)(&a->archive, client_data);
@@ -149,129 +171,103 @@ archive_read_open2(struct archive *_a, void *client_data,
}
}
- /* Read first block now for compress format detection. */
- bytes_read = (client_reader)(&a->archive, client_data, &buffer);
-
- if (bytes_read < 0) {
- /* If the first read fails, close before returning error. */
- if (client_closer)
- (client_closer)(&a->archive, client_data);
- /* client_reader should have already set error information. */
- return (ARCHIVE_FATAL);
- }
+ /* Save the client functions and mock up the initial source. */
+ a->client.opener = client_opener; /* Do we need to remember this? */
+ a->client.reader = client_reader;
+ a->client.skipper = client_skipper;
+ a->client.closer = client_closer;
+ a->client.data = client_data;
- /* Now that the client callbacks have worked, remember them. */
- a->client_opener = client_opener; /* Do we need to remember this? */
- a->client_reader = client_reader;
- a->client_skipper = client_skipper;
- a->client_closer = client_closer;
- a->client_data = client_data;
+ {
+ struct archive_read_source *source;
- /* Select a decompression routine. */
- choose_decompressor(a, buffer, (size_t)bytes_read);
- if (a->decompressor == NULL)
- return (ARCHIVE_FATAL);
+ source = calloc(1, sizeof(*source));
+ if (source == NULL)
+ return (ARCHIVE_FATAL);
+ source->reader = NULL;
+ source->upstream = NULL;
+ source->archive = a;
+ source->data = client_data;
+ source->read = client_read_proxy;
+ source->skip = client_skip_proxy;
+ source->close = client_close_proxy;
+ a->source = source;
+ }
- /* Initialize decompression routine with the first block of data. */
- e = (a->decompressor->init)(a, buffer, (size_t)bytes_read);
+ /* In case there's no filter. */
+ a->archive.compression_code = ARCHIVE_COMPRESSION_NONE;
+ a->archive.compression_name = "none";
+ /* Build out the input pipeline. */
+ e = build_stream(a);
if (e == ARCHIVE_OK)
a->archive.state = ARCHIVE_STATE_HEADER;
- /*
- * If the decompressor didn't register a skip function, provide a
- * dummy compression-layer skip function.
- */
- if (a->decompressor->skip == NULL)
- a->decompressor->skip = dummy_skip;
-
return (e);
}
/*
- * Allow each registered decompression routine to bid on whether it
- * wants to handle this stream. Return index of winning bidder.
+ * Allow each registered stream transform to bid on whether
+ * it wants to handle this stream. Repeat until we've finished
+ * building the pipeline.
*/
-static void
-choose_decompressor(struct archive_read *a,
- const void *buffer, size_t bytes_read)
+static int
+build_stream(struct archive_read *a)
{
- int decompression_slots, i, bid, best_bid;
- struct decompressor_t *decompressor, *best_decompressor;
+ int number_readers, i, bid, best_bid;
+ struct archive_reader *reader, *best_reader;
+ struct archive_read_source *source;
+ const void *block;
+ ssize_t bytes_read;
- decompression_slots = sizeof(a->decompressors) /
- sizeof(a->decompressors[0]);
+ /* Read first block now for compress format detection. */
+ bytes_read = (a->source->read)(a->source, &block);
+ if (bytes_read < 0) {
+ /* If the first read fails, close before returning error. */
+ if (a->source->close != NULL) {
+ (a->source->close)(a->source);
+ a->source = NULL;
+ }
+ /* source->read should have already set error information. */
+ return (ARCHIVE_FATAL);
+ }
+
+ number_readers = sizeof(a->readers) / sizeof(a->readers[0]);
best_bid = 0;
- a->decompressor = NULL;
- best_decompressor = NULL;
-
- decompressor = a->decompressors;
- for (i = 0; i < decompression_slots; i++) {
- if (decompressor->bid) {
- bid = (decompressor->bid)(buffer, bytes_read);
- if (bid > best_bid || best_decompressor == NULL) {
+ best_reader = NULL;
+
+ reader = a->readers;
+ for (i = 0, reader = a->readers; i < number_readers; i++, reader++) {
+ if (reader->bid != NULL) {
+ bid = (reader->bid)(reader, block, bytes_read);
+ if (bid > best_bid) {
best_bid = bid;
- best_decompressor = decompressor;
+ best_reader = reader;
}
}
- decompressor ++;
}
/*
- * There were no bidders; this is a serious programmer error
- * and demands a quick and definitive abort.
- */
- if (best_decompressor == NULL)
- __archive_errx(1, "No decompressors were registered; you "
- "must call at least one "
- "archive_read_support_compression_XXX function in order "
- "to successfully read an archive.");
-
- /*
- * There were bidders, but no non-zero bids; this means we can't
- * support this stream.
+ * If we have a winner, it becomes the next stage in the pipeline.
*/
- if (best_bid < 1) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "Unrecognized archive format");
- return;
- }
-
- /* Record the best decompressor for this stream. */
- a->decompressor = best_decompressor;
-}
-
-/*
- * Dummy skip function, for use if the compression layer doesn't provide
- * one: This code just reads data and discards it.
- */
-static off_t
-dummy_skip(struct archive_read * a, off_t request)
-{
- const void * dummy_buffer;
- ssize_t bytes_read;
- off_t bytes_skipped;
-
- for (bytes_skipped = 0; request > 0;) {
- bytes_read = (a->decompressor->read_ahead)(a, &dummy_buffer, 1);
- if (bytes_read < 0)
- return (bytes_read);
- if (bytes_read == 0) {
- /* Premature EOF. */
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Truncated input file (need to skip %jd bytes)",
- (intmax_t)request);
+ if (best_reader != NULL) {
+ source = (best_reader->init)(a, best_reader, a->source,
+ block, bytes_read);
+ if (source == NULL)
return (ARCHIVE_FATAL);
- }
- if (bytes_read > request)
- bytes_read = (ssize_t)request;
- (a->decompressor->consume)(a, (size_t)bytes_read);
- request -= bytes_read;
- bytes_skipped += bytes_read;
+ /* Record the best decompressor for this stream. */
+ a->source = source;
+ /* Recurse to get next pipeline stage. */
+ return (build_stream(a));
}
- return (bytes_skipped);
+ /* Save first block of data. */
+ a->client_buff = block;
+ a->client_total = bytes_read;
+ a->client_next = a->client_buff;
+ a->client_avail = a->client_total;
+ return (ARCHIVE_OK);
}
/*
@@ -598,23 +594,24 @@ archive_read_close(struct archive *_a)
/* TODO: Clean up the formatters. */
- /* Clean up the decompressors. */
- n = sizeof(a->decompressors)/sizeof(a->decompressors[0]);
+ /* Clean up the stream pipeline. */
+ if (a->source != NULL) {
+ r1 = (a->source->close)(a->source);
+ if (r1 < r)
+ r = r1;
+ a->source = NULL;
+ }
+
+ /* Release the reader objects. */
+ n = sizeof(a->readers)/sizeof(a->readers[0]);
for (i = 0; i < n; i++) {
- if (a->decompressors[i].finish != NULL) {
- r1 = (a->decompressors[i].finish)(a);
+ if (a->readers[i].free != NULL) {
+ r1 = (a->readers[i].free)(&a->readers[i]);
if (r1 < r)
r = r1;
}
}
- /* Close the client stream. */
- if (a->client_closer != NULL) {
- r1 = ((a->client_closer)(&a->archive, a->client_data));
- if (r1 < r)
- r = r1;
- }
-
return (r);
}
@@ -651,6 +648,7 @@ archive_read_finish(struct archive *_a)
if (a->entry)
archive_entry_free(a->entry);
a->archive.magic = 0;
+ free(a->buffer);
free(a);
#if ARCHIVE_API_VERSION > 1
return (r);
@@ -700,40 +698,350 @@ __archive_read_register_format(struct archive_read *a,
* Used internally by decompression routines to register their bid and
* initialization functions.
*/
-struct decompressor_t *
-__archive_read_register_compression(struct archive_read *a,
- int (*bid)(const void *, size_t),
- int (*init)(struct archive_read *, const void *, size_t))
+struct archive_reader *
+__archive_read_get_reader(struct archive_read *a)
{
int i, number_slots;
__archive_check_magic(&a->archive,
ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
- "__archive_read_register_compression");
+ "__archive_read_get_reader");
- number_slots = sizeof(a->decompressors) / sizeof(a->decompressors[0]);
+ number_slots = sizeof(a->readers) / sizeof(a->readers[0]);
for (i = 0; i < number_slots; i++) {
- if (a->decompressors[i].bid == bid)
- return (a->decompressors + i);
- if (a->decompressors[i].bid == NULL) {
- a->decompressors[i].bid = bid;
- a->decompressors[i].init = init;
- return (a->decompressors + i);
- }
+ if (a->readers[i].bid == NULL)
+ return (a->readers + i);
}
__archive_errx(1, "Not enough slots for compression registration");
return (NULL); /* Never actually executed. */
}
-/* used internally to simplify read-ahead */
+/*
+ * The next three functions comprise the peek/consume internal I/O
+ * system used by archive format readers. This system allows fairly
+ * flexible read-ahead and allows the I/O code to operate in a
+ * zero-copy manner most of the time.
+ *
+ * In the ideal case, block providers give the I/O code blocks of data
+ * and __archive_read_ahead() just returns pointers directly into
+ * those blocks. Then __archive_read_consume() just bumps those
+ * pointers. Only if your request would span blocks does the I/O
+ * layer use a copy buffer to provide you with a contiguous block of
+ * data. The __archive_read_skip() is an optimization; it scans ahead
+ * very quickly (it usually translates into a seek() operation if
+ * you're reading uncompressed disk files).
+ *
+ * A couple of useful idioms:
+ * * "I just want some data." Ask for 1 byte and pay attention to
+ * the "number of bytes available" from __archive_read_ahead().
+ * You can consume more than you asked for; you just can't consume
+ * more than is available right now. If you consume everything that's
+ * immediately available, the next read_ahead() call will pull
+ * the next block.
+ * * "I want to output a large block of data." As above, ask for 1 byte,
+ * emit all that's available (up to whatever limit you have), then
+ * repeat until you're done.
+ * * "I want to peek ahead by a large amount." Ask for 4k or so, then
+ * double and repeat until you get an error or have enough. Note
+ * that the I/O layer will likely end up expanding its copy buffer
+ * to fit your request, so use this technique cautiously. This
+ * technique is used, for example, by some of the format tasting
+ * code that has uncertain look-ahead needs.
+ *
+ * TODO: Someday, provide a more generic __archive_read_seek() for
+ * those cases where it's useful. This is tricky because there are lots
+ * of cases where seek() is not available (reading gzip data from a
+ * network socket, for instance), so there needs to be a good way to
+ * communicate whether seek() is available and users of that interface
+ * need to use non-seeking strategies whenever seek() is not available.
+ */
+
+/*
+ * Looks ahead in the input stream:
+ * * If 'avail' pointer is provided, that returns number of bytes available
+ * in the current buffer, which may be much larger than requested.
+ * * If end-of-file, *avail gets set to zero.
+ * * If error, *avail gets error code.
+ * * If request can be met, returns pointer to data, returns NULL
+ * if request is not met.
+ *
+ * Note: If you just want "some data", ask for 1 byte and pay attention
+ * to *avail, which will have the actual amount available. If you
+ * know exactly how many bytes you need, just ask for that and treat
+ * a NULL return as an error.
+ *
+ * Important: This does NOT move the file pointer. See
+ * __archive_read_consume() below.
+ */
+
+/*
+ * This is tricky. We need to provide our clients with pointers to
+ * contiguous blocks of memory but we want to avoid copying whenever
+ * possible.
+ *
+ * Mostly, this code returns pointers directly into the block of data
+ * provided by the client_read routine. It can do this unless the
+ * request would split across blocks. In that case, we have to copy
+ * into an internal buffer to combine reads.
+ */
const void *
-__archive_read_ahead(struct archive_read *a, size_t len)
+__archive_read_ahead(struct archive_read *a, size_t min, ssize_t *avail)
{
- const void *h;
+ ssize_t bytes_read;
+ size_t tocopy;
- if ((a->decompressor->read_ahead)(a, &h, len) < (ssize_t)len)
+ if (a->fatal) {
+ if (avail)
+ *avail = ARCHIVE_FATAL;
return (NULL);
- return (h);
+ }
+
+ /*
+ * Keep pulling more data until we can satisfy the request.
+ */
+ for (;;) {
+
+ /*
+ * If we can satisfy from the copy buffer, we're done.
+ */
+ if (a->avail >= min) {
+ if (avail != NULL)
+ *avail = a->avail;
+ return (a->next);
+ }
+
+ /*
+ * We can satisfy directly from client buffer if everything
+ * currently in the copy buffer is still in the client buffer.
+ */
+ if (a->client_total >= a->client_avail + a->avail
+ && a->client_avail + a->avail >= min) {
+ /* "Roll back" to client buffer. */
+ a->client_avail += a->avail;
+ a->client_next -= a->avail;
+ /* Copy buffer is now empty. */
+ a->avail = 0;
+ a->next = a->buffer;
+ /* Return data from client buffer. */
+ if (avail != NULL)
+ *avail = a->client_avail;
+ return (a->client_next);
+ }
+
+ /* Move data forward in copy buffer if necessary. */
+ if (a->next > a->buffer &&
+ a->next + min > a->buffer + a->buffer_size) {
+ if (a->avail > 0)
+ memmove(a->buffer, a->next, a->avail);
+ a->next = a->buffer;
+ }
+
+ /* If we've used up the client data, get more. */
+ if (a->client_avail <= 0) {
+ if (a->end_of_file) {
+ if (avail != NULL)
+ *avail = 0;
+ return (NULL);
+ }
+ bytes_read = (a->source->read)(a->source,
+ &a->client_buff);
+ if (bytes_read < 0) { /* Read error. */
+ a->client_total = a->client_avail = 0;
+ a->client_next = a->client_buff = NULL;
+ a->fatal = 1;
+ if (avail != NULL)
+ *avail = ARCHIVE_FATAL;
+ return (NULL);
+ }
+ if (bytes_read == 0) { /* Premature end-of-file. */
+ a->client_total = a->client_avail = 0;
+ a->client_next = a->client_buff = NULL;
+ a->end_of_file = 1;
+ /* Return whatever we do have. */
+ if (avail != NULL)
+ *avail = a->avail;
+ return (NULL);
+ }
+ a->archive.raw_position += bytes_read;
+ a->client_total = bytes_read;
+ a->client_avail = a->client_total;
+ a->client_next = a->client_buff;
+ }
+ else
+ {
+ /*
+ * We can't satisfy the request from the copy
+ * buffer or the existing client data, so we
+ * need to copy more client data over to the
+ * copy buffer.
+ */
+
+ /* Ensure the buffer is big enough. */
+ if (min > a->buffer_size) {
+ size_t s, t;
+ char *p;
+
+ /* Double the buffer; watch for overflow. */
+ s = t = a->buffer_size;
+ while (s < min) {
+ t *= 2;
+ if (t <= s) { /* Integer overflow! */
+ archive_set_error(&a->archive,
+ ENOMEM,
+ "Unable to allocate copy buffer");
+ a->fatal = 1;
+ if (avail != NULL)
+ *avail = ARCHIVE_FATAL;
+ return (NULL);
+ }
+ s = t;
+ }
+ /* Now s >= min, so allocate a new buffer. */
+ p = (char *)malloc(s);
+ if (p == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Unable to allocate copy buffer");
+ a->fatal = 1;
+ if (avail != NULL)
+ *avail = ARCHIVE_FATAL;
+ return (NULL);
+ }
+ /* Move data into newly-enlarged buffer. */
+ if (a->avail > 0)
+ memmove(p, a->next, a->avail);
+ free(a->buffer);
+ a->next = a->buffer = p;
+ a->buffer_size = s;
+ }
+
+ /* We can add client data to copy buffer. */
+ /* First estimate: copy to fill rest of buffer. */
+ tocopy = (a->buffer + a->buffer_size)
+ - (a->next + a->avail);
+ /* Don't waste time buffering more than we need to. */
+ if (tocopy + a->avail > min)
+ tocopy = min - a->avail;
+ /* Don't copy more than is available. */
+ if (tocopy > a->client_avail)
+ tocopy = a->client_avail;
+
+ memcpy(a->next + a->avail, a->client_next,
+ tocopy);
+ /* Remove this data from client buffer. */
+ a->client_next += tocopy;
+ a->client_avail -= tocopy;
+ /* add it to copy buffer. */
+ a->avail += tocopy;
+ }
+ }
+}
+
+/*
+ * Move the file pointer forward. This should be called after
+ * __archive_read_ahead() returns data to you. Don't try to move
+ * ahead by more than the amount of data available according to
+ * __archive_read_ahead().
+ */
+/*
+ * Mark the appropriate data as used. Note that the request here will
+ * often be much smaller than the size of the previous read_ahead
+ * request.
+ */
+ssize_t
+__archive_read_consume(struct archive_read *a, size_t request)
+{
+ if (a->avail > 0) {
+ /* Read came from copy buffer. */
+ a->next += request;
+ a->avail -= request;
+ } else {
+ /* Read came from client buffer. */
+ a->client_next += request;
+ a->client_avail -= request;
+ }
+ a->archive.file_position += request;
+ return (request);
+}
+
+/*
+ * Move the file pointer ahead by an arbitrary amount. If you're
+ * reading uncompressed data from a disk file, this will actually
+ * translate into a seek() operation. Even in cases where seek()
+ * isn't feasible, this at least pushes the read-and-discard loop
+ * down closer to the data source.
+ */
+int64_t
+__archive_read_skip(struct archive_read *a, int64_t request)
+{
+ off_t bytes_skipped, total_bytes_skipped = 0;
+ size_t min;
+
+ if (a->fatal)
+ return (-1);
+ /*
+ * If there is data in the buffers already, use that first.
+ */
+ if (a->avail > 0) {
+ min = minimum(request, (off_t)a->avail);
+ bytes_skipped = __archive_read_consume(a, min);
+ request -= bytes_skipped;
+ total_bytes_skipped += bytes_skipped;
+ }
+ if (a->client_avail > 0) {
+ min = minimum(request, (off_t)a->client_avail);
+ bytes_skipped = __archive_read_consume(a, min);
+ request -= bytes_skipped;
+ total_bytes_skipped += bytes_skipped;
+ }
+ if (request == 0)
+ return (total_bytes_skipped);
+ /*
+ * If a client_skipper was provided, try that first.
+ */
+#if ARCHIVE_API_VERSION < 2
+ if ((a->source->skip != NULL) && (request < SSIZE_MAX)) {
+#else
+ if (a->source->skip != NULL) {
+#endif
+ bytes_skipped = (a->source->skip)(a->source, request);
+ if (bytes_skipped < 0) { /* error */
+ a->client_total = a->client_avail = 0;
+ a->client_next = a->client_buff = NULL;
+ a->fatal = 1;
+ return (bytes_skipped);
+ }
+ total_bytes_skipped += bytes_skipped;
+ a->archive.file_position += bytes_skipped;
+ request -= bytes_skipped;
+ a->client_next = a->client_buff;
+ a->archive.raw_position += bytes_skipped;
+ a->client_avail = a->client_total = 0;
+ }
+ /*
+ * Note that client_skipper will usually not satisfy the
+ * full request (due to low-level blocking concerns),
+ * so even if client_skipper is provided, we may still
+ * have to use ordinary reads to finish out the request.
+ */
+ while (request > 0) {
+ const void* dummy_buffer;
+ ssize_t bytes_read;
+ dummy_buffer = __archive_read_ahead(a, 1, &bytes_read);
+ if (bytes_read < 0)
+ return (bytes_read);
+ if (bytes_read == 0) {
+ /* We hit EOF before we satisfied the skip request. */
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Truncated input file (need to skip %jd bytes)",
+ (intmax_t)request);
+ return (ARCHIVE_FATAL);
+ }
+ min = (size_t)(minimum(bytes_read, request));
+ bytes_read = __archive_read_consume(a, min);
+ total_bytes_skipped += bytes_read;
+ request -= bytes_read;
+ }
+ return (total_bytes_skipped);
}
diff --git a/lib/libarchive/archive_read_private.h b/lib/libarchive/archive_read_private.h
index 4353983..da0b83f 100644
--- a/lib/libarchive/archive_read_private.h
+++ b/lib/libarchive/archive_read_private.h
@@ -32,6 +32,75 @@
#include "archive_string.h"
#include "archive_private.h"
+struct archive_read;
+struct archive_reader;
+struct archive_read_source;
+
+/*
+ * A "reader" knows how to provide blocks. That can include something
+ * that reads blocks from disk or socket or a transformation layer
+ * that reads blocks from another source and transforms them. This
+ * includes decompression and decryption filters.
+ *
+ * How bidding works:
+ * * The bid manager reads the first block from the current source.
+ * * It shows that block to each registered bidder.
+ * * The winning bidder is initialized (with the block and information
+ * about the source)
+ * * The winning bidder becomes the new source and the process repeats
+ * This ends only when no reader provides a non-zero bid.
+ */
+struct archive_reader {
+ /* Configuration data for the reader. */
+ void *data;
+ /* Bidder is handed the initial block from its source. */
+ int (*bid)(struct archive_reader *, const void *buff, size_t);
+ /* Init() is given the archive, upstream source, and the initial
+ * block above. It returns a populated source structure. */
+ struct archive_read_source *(*init)(struct archive_read *,
+ struct archive_reader *, struct archive_read_source *source,
+ const void *, size_t);
+ /* Release the reader and any configuration data it allocated. */
+ int (*free)(struct archive_reader *);
+};
+
+/*
+ * A "source" is an instance of a reader. This structure is
+ * allocated and initialized by the init() method of a reader
+ * above.
+ */
+struct archive_read_source {
+ /* Essentially all sources will need these values, so
+ * just declare them here. */
+ struct archive_reader *reader; /* Reader that I'm an instance of. */
+ struct archive_read_source *upstream; /* Who I get blocks from. */
+ struct archive_read *archive; /* associated archive. */
+ /* Return next block. */
+ ssize_t (*read)(struct archive_read_source *, const void **);
+ /* Skip forward this many bytes. */
+ int64_t (*skip)(struct archive_read_source *self, int64_t request);
+ /* Close (recursively) and free(self). */
+ int (*close)(struct archive_read_source *self);
+ /* My private data. */
+ void *data;
+};
+
+/*
+ * The client source is almost the same as an internal source.
+ *
+ * TODO: Make archive_read_source and archive_read_client identical so
+ * that users of the library can easily register their own
+ * transformation filters. This will probably break the API/ABI and
+ * so should be deferred until libarchive 3.0.
+ */
+struct archive_read_client {
+ archive_open_callback *opener;
+ archive_read_callback *reader;
+ archive_skip_callback *skipper;
+ archive_close_callback *closer;
+ void *data;
+};
+
struct archive_read {
struct archive archive;
@@ -50,46 +119,30 @@ struct archive_read {
off_t read_data_output_offset;
size_t read_data_remaining;
- /* Callbacks to open/read/write/close archive stream. */
- archive_open_callback *client_opener;
- archive_read_callback *client_reader;
- archive_skip_callback *client_skipper;
- archive_close_callback *client_closer;
- void *client_data;
+ /* Callbacks to open/read/write/close client archive stream. */
+ struct archive_read_client client;
+
+ /* Registered readers. */
+ struct archive_reader readers[8];
+
+ /* Source */
+ struct archive_read_source *source;
/* File offset of beginning of most recently-read header. */
off_t header_position;
- /*
- * Decompressors have a very specific lifecycle:
- * public setup function initializes a slot in this table
- * 'config' holds minimal configuration data
- * bid() examines a block of data and returns a bid [1]
- * init() is called for successful bidder
- * 'data' is initialized by init()
- * read() returns a pointer to the next block of data
- * consume() indicates how much data is used
- * skip() ignores bytes of data
- * finish() cleans up and frees 'data' and 'config'
- *
- * [1] General guideline: bid the number of bits that you actually
- * test, e.g., 16 if you test a 2-byte magic value.
- */
- struct decompressor_t {
- void *config;
- void *data;
- int (*bid)(const void *buff, size_t);
- int (*init)(struct archive_read *,
- const void *buff, size_t);
- int (*finish)(struct archive_read *);
- ssize_t (*read_ahead)(struct archive_read *,
- const void **, size_t);
- ssize_t (*consume)(struct archive_read *, size_t);
- off_t (*skip)(struct archive_read *, off_t);
- } decompressors[4];
-
- /* Pointer to current decompressor. */
- struct decompressor_t *decompressor;
+
+ /* Used by reblocking logic. */
+ char *buffer;
+ size_t buffer_size;
+ char *next; /* Current read location. */
+ size_t avail; /* Bytes in my buffer. */
+ const void *client_buff; /* Client buffer information. */
+ size_t client_total;
+ const char *client_next;
+ size_t client_avail;
+ char end_of_file;
+ char fatal;
/*
* Format detection is mostly the same as compression
@@ -124,12 +177,13 @@ int __archive_read_register_format(struct archive_read *a,
int (*read_data_skip)(struct archive_read *),
int (*cleanup)(struct archive_read *));
-struct decompressor_t
- *__archive_read_register_compression(struct archive_read *a,
- int (*bid)(const void *, size_t),
- int (*init)(struct archive_read *, const void *, size_t));
+struct archive_reader
+ *__archive_read_get_reader(struct archive_read *a);
const void
- *__archive_read_ahead(struct archive_read *, size_t);
-
+ *__archive_read_ahead(struct archive_read *, size_t, ssize_t *);
+ssize_t
+ __archive_read_consume(struct archive_read *, size_t);
+int64_t
+ __archive_read_skip(struct archive_read *, int64_t);
#endif
diff --git a/lib/libarchive/archive_read_support_compression_all.c b/lib/libarchive/archive_read_support_compression_all.c
index de3d585..967546d 100644
--- a/lib/libarchive/archive_read_support_compression_all.c
+++ b/lib/libarchive/archive_read_support_compression_all.c
@@ -39,5 +39,11 @@ archive_read_support_compression_all(struct archive *a)
#if HAVE_ZLIB_H
archive_read_support_compression_gzip(a);
#endif
+#if HAVE_LZMADEC_H
+ /* LZMA bidding is subject to false positives because
+ * the LZMA file format has a very weak signature. It
+ * may not be feasible to include LZMA detection here. */
+ /* archive_read_support_compression_lzma(a); */
+#endif
return (ARCHIVE_OK);
}
diff --git a/lib/libarchive/archive_read_support_compression_bzip2.c b/lib/libarchive/archive_read_support_compression_bzip2.c
index b08b6b5..6849771 100644
--- a/lib/libarchive/archive_read_support_compression_bzip2.c
+++ b/lib/libarchive/archive_read_support_compression_bzip2.c
@@ -51,30 +51,49 @@ __FBSDID("$FreeBSD$");
#if HAVE_BZLIB_H
struct private_data {
bz_stream stream;
- char *uncompressed_buffer;
- size_t uncompressed_buffer_size;
- char *read_next;
- int64_t total_out;
+ char *out_block;
+ size_t out_block_size;
+ char valid; /* True = decompressor is initialized */
char eof; /* True = found end of compressed data. */
};
-static int finish(struct archive_read *);
-static ssize_t read_ahead(struct archive_read *, const void **, size_t);
-static ssize_t read_consume(struct archive_read *, size_t);
-static int drive_decompressor(struct archive_read *a, struct private_data *);
+/* Bzip2 source */
+static ssize_t bzip2_source_read(struct archive_read_source *, const void **);
+static int bzip2_source_close(struct archive_read_source *);
#endif
-/* These two functions are defined even if we lack the library. See below. */
-static int bid(const void *, size_t);
-static int init(struct archive_read *, const void *, size_t);
+/*
+ * Note that we can detect bzip2 archives even if we can't decompress
+ * them. (In fact, we like detecting them because we can give better
+ * error messages.) So the bid framework here gets compiled even
+ * if bzlib is unavailable.
+ */
+static int bzip2_reader_bid(struct archive_reader *, const void *, size_t);
+static struct archive_read_source *bzip2_reader_init(struct archive_read *,
+ struct archive_reader *, struct archive_read_source *,
+ const void *, size_t);
+static int bzip2_reader_free(struct archive_reader *);
int
archive_read_support_compression_bzip2(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
- if (__archive_read_register_compression(a, bid, init) != NULL)
- return (ARCHIVE_OK);
- return (ARCHIVE_FATAL);
+ struct archive_reader *reader = __archive_read_get_reader(a);
+
+ if (reader == NULL)
+ return (ARCHIVE_FATAL);
+
+ reader->data = NULL;
+ reader->bid = bzip2_reader_bid;
+ reader->init = bzip2_reader_init;
+ reader->free = bzip2_reader_free;
+ return (ARCHIVE_OK);
+}
+
+static int
+bzip2_reader_free(struct archive_reader *self){
+ (void)self; /* UNUSED */
+ return (ARCHIVE_OK);
}
/*
@@ -85,11 +104,13 @@ archive_read_support_compression_bzip2(struct archive *_a)
* from verifying as much as we would like.
*/
static int
-bid(const void *buff, size_t len)
+bzip2_reader_bid(struct archive_reader *self, const void *buff, size_t len)
{
const unsigned char *buffer;
int bits_checked;
+ (void)self; /* UNUSED */
+
if (len < 1)
return (0);
@@ -150,16 +171,19 @@ bid(const void *buff, size_t len)
* decompression. We can, however, still detect compressed archives
* and emit a useful message.
*/
-static int
-init(struct archive_read *a, const void *buff, size_t n)
+static struct archive_read_source *
+bzip2_reader_init(struct archive_read *a, struct archive_reader *reader,
+ struct archive_read_source *upstream, const void *buff, size_t n)
{
(void)a; /* UNUSED */
+ (void)reader; /* UNUSED */
+ (void)upstream; /* UNUSED */
(void)buff; /* UNUSED */
(void)n; /* UNUSED */
archive_set_error(&a->archive, -1,
"This version of libarchive was compiled without bzip2 support");
- return (ARCHIVE_FATAL);
+ return (NULL);
}
@@ -168,37 +192,42 @@ init(struct archive_read *a, const void *buff, size_t n)
/*
* Setup the callbacks.
*/
-static int
-init(struct archive_read *a, const void *buff, size_t n)
+static struct archive_read_source *
+bzip2_reader_init(struct archive_read *a, struct archive_reader *reader,
+ struct archive_read_source *upstream, const void *buff, size_t n)
{
+ static const size_t out_block_size = 64 * 1024;
+ void *out_block;
+ struct archive_read_source *self;
struct private_data *state;
- int ret;
+
+ (void)reader; /* UNUSED */
a->archive.compression_code = ARCHIVE_COMPRESSION_BZIP2;
a->archive.compression_name = "bzip2";
- state = (struct private_data *)malloc(sizeof(*state));
- if (state == NULL) {
+ self = calloc(sizeof(*self), 1);
+ state = (struct private_data *)calloc(sizeof(*state), 1);
+ out_block = (unsigned char *)malloc(out_block_size);
+ if (self == NULL || state == NULL || out_block == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate data for %s decompression",
a->archive.compression_name);
- return (ARCHIVE_FATAL);
+ free(out_block);
+ free(state);
+ free(self);
+ return (NULL);
}
- memset(state, 0, sizeof(*state));
- state->uncompressed_buffer_size = 64 * 1024;
- state->uncompressed_buffer = (char *)malloc(state->uncompressed_buffer_size);
- state->stream.next_out = state->uncompressed_buffer;
- state->read_next = state->uncompressed_buffer;
- state->stream.avail_out = state->uncompressed_buffer_size;
- if (state->uncompressed_buffer == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate %s decompression buffers",
- a->archive.compression_name);
- free(state);
- return (ARCHIVE_FATAL);
- }
+ self->archive = a;
+ self->data = state;
+ state->out_block_size = out_block_size;
+ state->out_block = out_block;
+ self->upstream = upstream;
+ self->read = bzip2_source_read;
+ self->skip = NULL; /* not supported */
+ self->close = bzip2_source_close;
/*
* A bug in bzlib.h: stream.next_in should be marked 'const'
@@ -209,218 +238,160 @@ init(struct archive_read *a, const void *buff, size_t n)
state->stream.next_in = (char *)(uintptr_t)(const void *)buff;
state->stream.avail_in = n;
- a->decompressor->read_ahead = read_ahead;
- a->decompressor->consume = read_consume;
- a->decompressor->skip = NULL; /* not supported */
- a->decompressor->finish = finish;
-
- /* Initialize compression library. */
- ret = BZ2_bzDecompressInit(&(state->stream),
- 0 /* library verbosity */,
- 0 /* don't use slow low-mem algorithm */);
-
- /* If init fails, try using low-memory algorithm instead. */
- if (ret == BZ_MEM_ERROR) {
- ret = BZ2_bzDecompressInit(&(state->stream),
- 0 /* library verbosity */,
- 1 /* do use slow low-mem algorithm */);
- }
-
- if (ret == BZ_OK) {
- a->decompressor->data = state;
- return (ARCHIVE_OK);
- }
+ state->stream.next_out = state->out_block;
+ state->stream.avail_out = state->out_block_size;
- /* Library setup failed: Clean up. */
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Internal error initializing %s library",
- a->archive.compression_name);
- free(state->uncompressed_buffer);
- free(state);
-
- /* Override the error message if we know what really went wrong. */
- switch (ret) {
- case BZ_PARAM_ERROR:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Internal error initializing compression library: "
- "invalid setup parameter");
- break;
- case BZ_MEM_ERROR:
- archive_set_error(&a->archive, ENOMEM,
- "Internal error initializing compression library: "
- "out of memory");
- break;
- case BZ_CONFIG_ERROR:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Internal error initializing compression library: "
- "mis-compiled library");
- break;
- }
-
- return (ARCHIVE_FATAL);
+ return (self);
}
/*
- * Return a block of data from the decompression buffer. Decompress more
- * as necessary.
+ * Return the next block of decompressed data.
*/
static ssize_t
-read_ahead(struct archive_read *a, const void **p, size_t min)
+bzip2_source_read(struct archive_read_source *self, const void **p)
{
struct private_data *state;
- size_t read_avail, was_avail;
+ size_t read_avail, decompressed;
+ const void *read_buf;
int ret;
- state = (struct private_data *)a->decompressor->data;
- if (!a->client_reader) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
- "No read callback is registered? "
- "This is probably an internal programming error.");
- return (ARCHIVE_FATAL);
- }
-
- read_avail = state->stream.next_out - state->read_next;
-
- if (read_avail + state->stream.avail_out < min) {
- memmove(state->uncompressed_buffer, state->read_next,
- read_avail);
- state->read_next = state->uncompressed_buffer;
- state->stream.next_out = state->read_next + read_avail;
- state->stream.avail_out
- = state->uncompressed_buffer_size - read_avail;
- }
-
- while (read_avail < min && /* Haven't satisfied min. */
- read_avail < state->uncompressed_buffer_size) { /* !full */
- was_avail = read_avail;
- if ((ret = drive_decompressor(a, state)) < ARCHIVE_OK)
- return (ret);
- if (ret == ARCHIVE_EOF)
- break; /* Break on EOF even if we haven't met min. */
- read_avail = state->stream.next_out - state->read_next;
- if (was_avail == read_avail) /* No progress? */
- break;
- }
-
- *p = state->read_next;
- return (read_avail);
-}
-
-/*
- * Mark a previously-returned block of data as read.
- */
-static ssize_t
-read_consume(struct archive_read *a, size_t n)
-{
- struct private_data *state;
-
- state = (struct private_data *)a->decompressor->data;
- a->archive.file_position += n;
- state->read_next += n;
- if (state->read_next > state->stream.next_out)
- __archive_errx(1, "Request to consume too many "
- "bytes from bzip2 decompressor");
- return (n);
-}
+ state = (struct private_data *)self->data;
+ read_avail = 0;
-/*
- * Clean up the decompressor.
- */
-static int
-finish(struct archive_read *a)
-{
- struct private_data *state;
- int ret;
-
- state = (struct private_data *)a->decompressor->data;
- ret = ARCHIVE_OK;
- switch (BZ2_bzDecompressEnd(&(state->stream))) {
- case BZ_OK:
- break;
- default:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Failed to clean up %s compressor",
- a->archive.compression_name);
- ret = ARCHIVE_FATAL;
+ if (state->eof) {
+ *p = NULL;
+ return (0);
}
- free(state->uncompressed_buffer);
- free(state);
-
- a->decompressor->data = NULL;
- return (ret);
-}
-
-/*
- * Utility function to pull data through decompressor, reading input
- * blocks as necessary.
- */
-static int
-drive_decompressor(struct archive_read *a, struct private_data *state)
-{
- ssize_t ret;
- int decompressed, total_decompressed;
- char *output;
- const void *read_buf;
+ /* Empty our output buffer. */
+ state->stream.next_out = state->out_block;
+ state->stream.avail_out = state->out_block_size;
- if (state->eof)
- return (ARCHIVE_EOF);
- total_decompressed = 0;
+ /* Try to fill the output buffer. */
for (;;) {
+ /* If the last upstream block is done, get another one. */
if (state->stream.avail_in == 0) {
- read_buf = state->stream.next_in;
- ret = (a->client_reader)(&a->archive, a->client_data,
+ ret = (self->upstream->read)(self->upstream,
&read_buf);
- state->stream.next_in = (void *)(uintptr_t)read_buf;
- if (ret < 0) {
- /*
- * TODO: Find a better way to handle
- * this read failure.
- */
- goto fatal;
- }
- if (ret == 0 && total_decompressed == 0) {
- archive_set_error(&a->archive, EIO,
- "Premature end of %s compressed data",
- a->archive.compression_name);
+ /* stream.next_in is really const, but bzlib
+ * doesn't declare it so. <sigh> */
+ state->stream.next_in
+ = (unsigned char *)(uintptr_t)read_buf;
+ if (ret < 0)
return (ARCHIVE_FATAL);
+ /* There is no more data, return whatever we have. */
+ if (ret == 0) {
+ state->eof = 1;
+ *p = state->out_block;
+ decompressed = state->stream.next_out
+ - state->out_block;
+ return (decompressed);
}
- a->archive.raw_position += ret;
state->stream.avail_in = ret;
}
- {
- output = state->stream.next_out;
-
- /* Decompress some data. */
- ret = BZ2_bzDecompress(&(state->stream));
- decompressed = state->stream.next_out - output;
-
- /* Accumulate the total bytes of output. */
- state->total_out += decompressed;
- total_decompressed += decompressed;
+ if (!state->valid) {
+ if (state->stream.next_in[0] != 'B') {
+ state->eof = 1;
+ *p = state->out_block;
+ decompressed = state->stream.next_out
+ - state->out_block;
+ return (decompressed);
+ }
+ /* Initialize compression library. */
+ ret = BZ2_bzDecompressInit(&(state->stream),
+ 0 /* library verbosity */,
+ 0 /* don't use low-mem algorithm */);
+
+ /* If init fails, try low-memory algorithm instead. */
+ if (ret == BZ_MEM_ERROR)
+ ret = BZ2_bzDecompressInit(&(state->stream),
+ 0 /* library verbosity */,
+ 1 /* do use low-mem algo */);
+
+ if (ret != BZ_OK) {
+ const char *detail = NULL;
+ int err = ARCHIVE_ERRNO_MISC;
+ switch (ret) {
+ case BZ_PARAM_ERROR:
+ detail = "invalid setup parameter";
+ break;
+ case BZ_MEM_ERROR:
+ err = ENOMEM;
+ detail = "out of memory";
+ break;
+ case BZ_CONFIG_ERROR:
+ detail = "mis-compiled library";
+ break;
+ }
+ archive_set_error(&self->archive->archive, err,
+ "Internal error initializing decompressor%s%s",
+ detail == NULL ? "" : ": ",
+ detail);
+ return (ARCHIVE_FATAL);
+ }
+ state->valid = 1;
+ }
- switch (ret) {
- case BZ_OK: /* Decompressor made some progress. */
- if (decompressed > 0)
- return (ARCHIVE_OK);
+ /* Decompress as much as we can in one pass. */
+ ret = BZ2_bzDecompress(&(state->stream));
+ switch (ret) {
+ case BZ_STREAM_END: /* Found end of stream. */
+ switch (BZ2_bzDecompressEnd(&(state->stream))) {
+ case BZ_OK:
break;
- case BZ_STREAM_END: /* Found end of stream. */
- state->eof = 1;
- return (ARCHIVE_OK);
default:
- /* Any other return value is an error. */
- goto fatal;
+ archive_set_error(&(self->archive->archive),
+ ARCHIVE_ERRNO_MISC,
+ "Failed to clean up decompressor");
+ return (ARCHIVE_FATAL);
}
+ state->valid = 0;
+ /* FALLTHROUGH */
+ case BZ_OK: /* Decompressor made some progress. */
+ /* If we filled our buffer, update stats and return. */
+ if (state->stream.avail_out == 0) {
+ *p = state->out_block;
+ decompressed = state->stream.next_out
+ - state->out_block;
+ return (decompressed);
+ }
+ break;
+ default: /* Return an error. */
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC, "bzip decompression failed");
+ return (ARCHIVE_FATAL);
}
}
- return (ARCHIVE_OK);
+}
+
+/*
+ * Clean up the decompressor.
+ */
+static int
+bzip2_source_close(struct archive_read_source *self)
+{
+ struct private_data *state;
+ int ret = ARCHIVE_OK;
+
+ state = (struct private_data *)self->data;
- /* Return a fatal error. */
-fatal:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "%s decompression failed", a->archive.compression_name);
- return (ARCHIVE_FATAL);
+ if (state->valid) {
+ switch (BZ2_bzDecompressEnd(&state->stream)) {
+ case BZ_OK:
+ break;
+ default:
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Failed to clean up decompressor");
+ ret = ARCHIVE_FATAL;
+ }
+ }
+
+ free(state->out_block);
+ free(state);
+ free(self);
+ return (ARCHIVE_OK);
}
#endif /* HAVE_BZLIB_H */
diff --git a/lib/libarchive/archive_read_support_compression_compress.c b/lib/libarchive/archive_read_support_compression_compress.c
index f45b7cd..5ae0b8a 100644
--- a/lib/libarchive/archive_read_support_compression_compress.c
+++ b/lib/libarchive/archive_read_support_compression_compress.c
@@ -100,11 +100,8 @@ struct private_data {
size_t bytes_in_section;
/* Output variables. */
- size_t uncompressed_buffer_size;
- void *uncompressed_buffer;
- unsigned char *read_next; /* Data for client. */
- unsigned char *next_out; /* Where to write new data. */
- size_t avail_out; /* Space at end of buffer. */
+ size_t out_block_size;
+ void *out_block;
/* Decompression status variables. */
int use_reset_code;
@@ -133,21 +130,32 @@ struct private_data {
unsigned char stack[65300];
};
-static int bid(const void *, size_t);
-static int finish(struct archive_read *);
-static int init(struct archive_read *, const void *, size_t);
-static ssize_t read_ahead(struct archive_read *, const void **, size_t);
-static ssize_t read_consume(struct archive_read *, size_t);
-static int getbits(struct archive_read *, struct private_data *, int n);
-static int next_code(struct archive_read *a, struct private_data *state);
+static int compress_reader_bid(struct archive_reader *, const void *, size_t);
+static struct archive_read_source *compress_reader_init(struct archive_read *,
+ struct archive_reader *, struct archive_read_source *,
+ const void *, size_t);
+static int compress_reader_free(struct archive_reader *);
+
+static ssize_t compress_source_read(struct archive_read_source *, const void **);
+static int compress_source_close(struct archive_read_source *);
+
+static int getbits(struct archive_read_source *, int n);
+static int next_code(struct archive_read_source *);
int
archive_read_support_compression_compress(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
- if (__archive_read_register_compression(a, bid, init) != NULL)
- return (ARCHIVE_OK);
- return (ARCHIVE_FATAL);
+ struct archive_reader *reader = __archive_read_get_reader(a);
+
+ if (reader == NULL)
+ return (ARCHIVE_FATAL);
+
+ reader->data = NULL;
+ reader->bid = compress_reader_bid;
+ reader->init = compress_reader_init;
+ reader->free = compress_reader_free;
+ return (ARCHIVE_OK);
}
/*
@@ -158,11 +166,13 @@ archive_read_support_compression_compress(struct archive *_a)
* from verifying as much as we would like.
*/
static int
-bid(const void *buff, size_t len)
+compress_reader_bid(struct archive_reader *self, const void *buff, size_t len)
{
const unsigned char *buffer;
int bits_checked;
+ (void)self; /* UNUSED */
+
if (len < 1)
return (0);
@@ -190,34 +200,43 @@ bid(const void *buff, size_t len)
/*
* Setup the callbacks.
*/
-static int
-init(struct archive_read *a, const void *buff, size_t n)
+static struct archive_read_source *
+compress_reader_init(struct archive_read *a, struct archive_reader *reader,
+ struct archive_read_source *upstream, const void *buff, size_t n)
{
+ struct archive_read_source *self;
struct private_data *state;
int code;
+ (void)reader; /* UNUSED */
+
a->archive.compression_code = ARCHIVE_COMPRESSION_COMPRESS;
a->archive.compression_name = "compress (.Z)";
- a->decompressor->read_ahead = read_ahead;
- a->decompressor->consume = read_consume;
- a->decompressor->skip = NULL; /* not supported */
- a->decompressor->finish = finish;
+ self = calloc(sizeof(*self), 1);
+ if (self == NULL)
+ return (NULL);
+
+ self->read = compress_source_read;
+ self->skip = NULL; /* not supported */
+ self->close = compress_source_close;
+ self->upstream = upstream;
+ self->archive = a;
- state = (struct private_data *)malloc(sizeof(*state));
+ state = (struct private_data *)calloc(sizeof(*state), 1);
if (state == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate data for %s decompression",
a->archive.compression_name);
- return (ARCHIVE_FATAL);
+ free(self);
+ return (NULL);
}
- memset(state, 0, sizeof(*state));
- a->decompressor->data = state;
+ self->data = state;
- state->uncompressed_buffer_size = 64 * 1024;
- state->uncompressed_buffer = malloc(state->uncompressed_buffer_size);
+ state->out_block_size = 64 * 1024;
+ state->out_block = malloc(state->out_block_size);
- if (state->uncompressed_buffer == NULL) {
+ if (state->out_block == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate %s decompression buffers",
a->archive.compression_name);
@@ -226,14 +245,12 @@ init(struct archive_read *a, const void *buff, size_t n)
state->next_in = (const unsigned char *)buff;
state->avail_in = n;
- state->read_next = state->next_out = (unsigned char *)state->uncompressed_buffer;
- state->avail_out = state->uncompressed_buffer_size;
- code = getbits(a, state, 8);
+ code = getbits(self, 8);
if (code != 037) /* This should be impossible. */
goto fatal;
- code = getbits(a, state, 8);
+ code = getbits(self, 8);
if (code != 0235) {
/* This can happen if the library is receiving 1-byte
* blocks and gzip and compress are both enabled.
@@ -244,7 +261,7 @@ init(struct archive_read *a, const void *buff, size_t n)
goto fatal;
}
- code = getbits(a, state, 8);
+ code = getbits(self, 8);
state->maxcode_bits = code & 0x1f;
state->maxcode = (1 << state->maxcode_bits);
state->use_reset_code = code & 0x80;
@@ -261,12 +278,12 @@ init(struct archive_read *a, const void *buff, size_t n)
state->prefix[code] = 0;
state->suffix[code] = code;
}
- next_code(a, state);
- return (ARCHIVE_OK);
+ next_code(self);
+ return (self);
fatal:
- finish(a);
- return (ARCHIVE_FATAL);
+ compress_source_close(self);
+ return (NULL);
}
/*
@@ -274,93 +291,59 @@ fatal:
* as necessary.
*/
static ssize_t
-read_ahead(struct archive_read *a, const void **p, size_t min)
+compress_source_read(struct archive_read_source *self, const void **pblock)
{
struct private_data *state;
- size_t read_avail;
+ unsigned char *p, *start, *end;
int ret;
- state = (struct private_data *)a->decompressor->data;
- if (!a->client_reader) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
- "No read callback is registered? "
- "This is probably an internal programming error.");
- return (ARCHIVE_FATAL);
- }
-
- read_avail = state->next_out - state->read_next;
-
- if (read_avail < min && state->end_of_stream) {
- if (state->end_of_stream == ARCHIVE_EOF)
- return (0);
- else
- return (-1);
+ state = (struct private_data *)self->data;
+ if (state->end_of_stream) {
+ *pblock = NULL;
+ return (0);
}
-
- if (read_avail < min) {
- memmove(state->uncompressed_buffer, state->read_next,
- read_avail);
- state->read_next = (unsigned char *)state->uncompressed_buffer;
- state->next_out = state->read_next + read_avail;
- state->avail_out
- = state->uncompressed_buffer_size - read_avail;
-
- while (read_avail < state->uncompressed_buffer_size
- && !state->end_of_stream) {
- if (state->stackp > state->stack) {
- *state->next_out++ = *--state->stackp;
- state->avail_out--;
- read_avail++;
- } else {
- ret = next_code(a, state);
- if (ret == ARCHIVE_EOF)
- state->end_of_stream = ret;
- else if (ret != ARCHIVE_OK)
- return (ret);
- }
+ p = start = (unsigned char *)state->out_block;
+ end = start + state->out_block_size;
+
+ while (p < end && !state->end_of_stream) {
+ if (state->stackp > state->stack) {
+ *p++ = *--state->stackp;
+ } else {
+ ret = next_code(self);
+ if (ret == ARCHIVE_EOF)
+ state->end_of_stream = ret;
+ else if (ret != ARCHIVE_OK)
+ return (ret);
}
}
- *p = state->read_next;
- return (read_avail);
+ *pblock = start;
+ return (p - start);
}
/*
- * Mark a previously-returned block of data as read.
+ * Clean up the reader.
*/
-static ssize_t
-read_consume(struct archive_read *a, size_t n)
+static int
+compress_reader_free(struct archive_reader *self)
{
- struct private_data *state;
-
- state = (struct private_data *)a->decompressor->data;
- a->archive.file_position += n;
- state->read_next += n;
- if (state->read_next > state->next_out)
- __archive_errx(1, "Request to consume too many "
- "bytes from compress decompressor");
- return (n);
+ self->data = NULL;
+ return (ARCHIVE_OK);
}
/*
- * Clean up the decompressor.
+ * Close and release a source.
*/
static int
-finish(struct archive_read *a)
+compress_source_close(struct archive_read_source *self)
{
- struct private_data *state;
- int ret = ARCHIVE_OK;
-
- state = (struct private_data *)a->decompressor->data;
+ struct private_data *state = (struct private_data *)self->data;
- if (state != NULL) {
- if (state->uncompressed_buffer != NULL)
- free(state->uncompressed_buffer);
- free(state);
- }
-
- a->decompressor->data = NULL;
- return (ret);
+ self->upstream->close(self->upstream);
+ free(state->out_block);
+ free(state);
+ free(self);
+ return (ARCHIVE_OK);
}
/*
@@ -369,14 +352,15 @@ finish(struct archive_read *a)
* format error, ARCHIVE_EOF if we hit end of data, ARCHIVE_OK otherwise.
*/
static int
-next_code(struct archive_read *a, struct private_data *state)
+next_code(struct archive_read_source *self)
{
+ struct private_data *state = (struct private_data *)self->data;
int code, newcode;
static int debug_buff[1024];
static unsigned debug_index;
- code = newcode = getbits(a, state, state->bits);
+ code = newcode = getbits(self, state->bits);
if (code < 0)
return (code);
@@ -398,7 +382,7 @@ next_code(struct archive_read *a, struct private_data *state)
skip_bytes %= state->bits;
state->bits_avail = 0; /* Discard rest of this byte. */
while (skip_bytes-- > 0) {
- code = getbits(a, state, 8);
+ code = getbits(self, 8);
if (code < 0)
return (code);
}
@@ -408,12 +392,13 @@ next_code(struct archive_read *a, struct private_data *state)
state->section_end_code = (1 << state->bits) - 1;
state->free_ent = 257;
state->oldcode = -1;
- return (next_code(a, state));
+ return (next_code(self));
}
if (code > state->free_ent) {
/* An invalid code is a fatal error. */
- archive_set_error(&a->archive, -1, "Invalid compressed data");
+ archive_set_error(&(self->archive->archive), -1,
+ "Invalid compressed data");
return (ARCHIVE_FATAL);
}
@@ -457,8 +442,9 @@ next_code(struct archive_read *a, struct private_data *state)
* -1 indicates end of available data.
*/
static int
-getbits(struct archive_read *a, struct private_data *state, int n)
+getbits(struct archive_read_source *self, int n)
{
+ struct private_data *state = (struct private_data *)self->data;
int code, ret;
static const int mask[] = {
0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff,
@@ -469,14 +455,13 @@ getbits(struct archive_read *a, struct private_data *state, int n)
while (state->bits_avail < n) {
if (state->avail_in <= 0) {
read_buf = state->next_in;
- ret = (a->client_reader)(&a->archive, a->client_data,
- &read_buf);
+ ret = (self->upstream->read)(self->upstream, &read_buf);
state->next_in = read_buf;
if (ret < 0)
return (ARCHIVE_FATAL);
if (ret == 0)
return (ARCHIVE_EOF);
- a->archive.raw_position += ret;
+/* TODO: Fix this a->archive.raw_position += ret; */
state->avail_in = ret;
}
state->bit_buffer |= *state->next_in++ << state->bits_avail;
diff --git a/lib/libarchive/archive_read_support_compression_gzip.c b/lib/libarchive/archive_read_support_compression_gzip.c
index 7ca2feb..1e8f818 100644
--- a/lib/libarchive/archive_read_support_compression_gzip.c
+++ b/lib/libarchive/archive_read_support_compression_gzip.c
@@ -51,32 +51,54 @@ __FBSDID("$FreeBSD$");
#ifdef HAVE_ZLIB_H
struct private_data {
z_stream stream;
- unsigned char *uncompressed_buffer;
- size_t uncompressed_buffer_size;
- unsigned char *read_next;
+ unsigned char *out_block;
+ size_t out_block_size;
int64_t total_out;
unsigned long crc;
+ int header_count;
char header_done;
+ char header_state;
+ char header_flags;
char eof; /* True = found end of compressed data. */
};
-static int finish(struct archive_read *);
-static ssize_t read_ahead(struct archive_read *, const void **, size_t);
-static ssize_t read_consume(struct archive_read *, size_t);
-static int drive_decompressor(struct archive_read *a, struct private_data *);
+/* Gzip Source. */
+static ssize_t gzip_source_read(struct archive_read_source *, const void **);
+static int gzip_source_close(struct archive_read_source *);
#endif
-/* These two functions are defined even if we lack the library. See below. */
-static int bid(const void *, size_t);
-static int init(struct archive_read *, const void *, size_t);
+/*
+ * Note that we can detect gzip archives even if we can't decompress
+ * them. (In fact, we like detecting them because we can give better
+ * error messages.) So the bid framework here gets compiled even
+ * if zlib is unavailable.
+ */
+static int gzip_reader_bid(struct archive_reader *, const void *, size_t);
+static struct archive_read_source *gzip_reader_init(struct archive_read *,
+ struct archive_reader *, struct archive_read_source *,
+ const void *, size_t);
+static int gzip_reader_free(struct archive_reader *);
int
archive_read_support_compression_gzip(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
- if (__archive_read_register_compression(a, bid, init) != NULL)
- return (ARCHIVE_OK);
- return (ARCHIVE_FATAL);
+ struct archive_reader *reader = __archive_read_get_reader(a);
+
+ if (reader == NULL)
+ return (ARCHIVE_FATAL);
+
+ reader->data = NULL;
+ reader->bid = gzip_reader_bid;
+ reader->init = gzip_reader_init;
+ reader->free = gzip_reader_free;
+ return (ARCHIVE_OK);
+}
+
+static int
+gzip_reader_free(struct archive_reader *self){
+ (void)self; /* UNUSED */
+ return (ARCHIVE_OK);
}
/*
@@ -87,11 +109,13 @@ archive_read_support_compression_gzip(struct archive *_a)
* from verifying as much as we would like.
*/
static int
-bid(const void *buff, size_t len)
+gzip_reader_bid(struct archive_reader *self, const void *buff, size_t len)
{
const unsigned char *buffer;
int bits_checked;
+ (void)self; /* UNUSED */
+
if (len < 1)
return (0);
@@ -139,8 +163,9 @@ bid(const void *buff, size_t len)
* decompression. We can, however, still detect compressed archives
* and emit a useful message.
*/
-static int
-init(struct archive_read *a, const void *buff, size_t n)
+static struct archive_read_source *
+gzip_reader_init(struct archive_read *a, struct archive_reader *reader,
+ struct archive_read_source *upstream, const void *buff, size_t n)
{
(void)a; /* UNUSED */
(void)buff; /* UNUSED */
@@ -148,50 +173,53 @@ init(struct archive_read *a, const void *buff, size_t n)
archive_set_error(&a->archive, -1,
"This version of libarchive was compiled without gzip support");
- return (ARCHIVE_FATAL);
+ return (NULL);
}
-
#else
/*
- * Setup the callbacks.
+ * Initialize the source object.
*/
-static int
-init(struct archive_read *a, const void *buff, size_t n)
+static struct archive_read_source *
+gzip_reader_init(struct archive_read *a, struct archive_reader *reader,
+ struct archive_read_source *upstream, const void *buff, size_t n)
{
+ static const size_t out_block_size = 64 * 1024;
+ void *out_block;
+ struct archive_read_source *self;
struct private_data *state;
- int ret;
+
+ (void)reader; /* UNUSED */
a->archive.compression_code = ARCHIVE_COMPRESSION_GZIP;
a->archive.compression_name = "gzip";
- state = (struct private_data *)malloc(sizeof(*state));
- if (state == NULL) {
+ self = calloc(sizeof(*self), 1);
+ state = (struct private_data *)calloc(sizeof(*state), 1);
+ out_block = (unsigned char *)malloc(out_block_size);
+ if (self == NULL || state == NULL || out_block == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate data for %s decompression",
a->archive.compression_name);
- return (ARCHIVE_FATAL);
+ free(out_block);
+ free(state);
+ free(self);
+ return (NULL);
}
- memset(state, 0, sizeof(*state));
+
+ self->archive = a;
+ self->data = state;
+ state->out_block_size = out_block_size;
+ state->out_block = out_block;
+ self->upstream = upstream;
+ self->read = gzip_source_read;
+ self->skip = NULL; /* not supported */
+ self->close = gzip_source_close;
state->crc = crc32(0L, NULL, 0);
state->header_done = 0; /* We've not yet begun to parse header... */
- state->uncompressed_buffer_size = 64 * 1024;
- state->uncompressed_buffer = (unsigned char *)malloc(state->uncompressed_buffer_size);
- state->stream.next_out = state->uncompressed_buffer;
- state->read_next = state->uncompressed_buffer;
- state->stream.avail_out = state->uncompressed_buffer_size;
-
- if (state->uncompressed_buffer == NULL) {
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate %s decompression buffers",
- a->archive.compression_name);
- free(state);
- return (ARCHIVE_FATAL);
- }
-
/*
* A bug in zlib.h: stream.next_in should be marked 'const'
* but isn't (the library never alters data through the
@@ -201,349 +229,262 @@ init(struct archive_read *a, const void *buff, size_t n)
state->stream.next_in = (Bytef *)(uintptr_t)(const void *)buff;
state->stream.avail_in = n;
- a->decompressor->read_ahead = read_ahead;
- a->decompressor->consume = read_consume;
- a->decompressor->skip = NULL; /* not supported */
- a->decompressor->finish = finish;
-
- /*
- * TODO: Do I need to parse the gzip header before calling
- * inflateInit2()? In particular, one of the header bytes
- * marks "best compression" or "fastest", which may be
- * appropriate for setting the second parameter here.
- * However, I think the only penalty for not setting it
- * correctly is wasted memory. If this is necessary, it
- * should probably go into drive_decompressor() below.
- */
-
- /* Initialize compression library. */
- ret = inflateInit2(&(state->stream),
- -15 /* Don't check for zlib header */);
- if (ret == Z_OK) {
- a->decompressor->data = state;
- return (ARCHIVE_OK);
- }
-
- /* Library setup failed: Clean up. */
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Internal error initializing %s library",
- a->archive.compression_name);
- free(state->uncompressed_buffer);
- free(state);
-
- /* Override the error message if we know what really went wrong. */
- switch (ret) {
- case Z_STREAM_ERROR:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Internal error initializing compression library: "
- "invalid setup parameter");
- break;
- case Z_MEM_ERROR:
- archive_set_error(&a->archive, ENOMEM,
- "Internal error initializing compression library: "
- "out of memory");
- break;
- case Z_VERSION_ERROR:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Internal error initializing compression library: "
- "invalid library version");
- break;
- }
-
- return (ARCHIVE_FATAL);
+ return (self);
}
-/*
- * Return a block of data from the decompression buffer. Decompress more
- * as necessary.
- */
-static ssize_t
-read_ahead(struct archive_read *a, const void **p, size_t min)
+static int
+header(struct archive_read_source *self)
{
struct private_data *state;
- size_t read_avail, was_avail;
- int ret;
-
- state = (struct private_data *)a->decompressor->data;
- if (!a->client_reader) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
- "No read callback is registered? "
- "This is probably an internal programming error.");
- return (ARCHIVE_FATAL);
- }
+ int ret, b;
- read_avail = state->stream.next_out - state->read_next;
+ state = (struct private_data *)self->data;
- if (read_avail + state->stream.avail_out < min) {
- memmove(state->uncompressed_buffer, state->read_next,
- read_avail);
- state->read_next = state->uncompressed_buffer;
- state->stream.next_out = state->read_next + read_avail;
- state->stream.avail_out
- = state->uncompressed_buffer_size - read_avail;
- }
+ /*
+ * If still parsing the header, interpret the
+ * next byte.
+ */
+ b = *(state->stream.next_in++);
+ state->stream.avail_in--;
- while (read_avail < min && /* Haven't satisfied min. */
- read_avail < state->uncompressed_buffer_size) { /* !full */
- was_avail = read_avail;
- if ((ret = drive_decompressor(a, state)) < ARCHIVE_OK)
- return (ret);
- if (ret == ARCHIVE_EOF)
- break; /* Break on EOF even if we haven't met min. */
- read_avail = state->stream.next_out - state->read_next;
- if (was_avail == read_avail) /* No progress? */
+ /*
+ * Simple state machine to parse the GZip header one byte at
+ * a time. If you see a way to make this easier to understand,
+ * please let me know. ;-)
+ */
+ switch (state->header_state) {
+ case 0: /* First byte of signature. */
+ /* We only return EOF for a failure here. */
+ if (b != 037)
+ return (ARCHIVE_EOF);
+ state->header_state = 1;
+ break;
+ case 1: /* Second byte of signature. */
+ case 2: /* Compression type must be 8 == deflate. */
+ if (b != (0xff & "\037\213\010"[(int)state->header_state])) {
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Invalid GZip header (saw %d at offset %d)",
+ b, state->header_state);
+ return (ARCHIVE_FATAL);
+ }
+ ++state->header_state;
+ break;
+ case 3: /* GZip flags. */
+ state->header_flags = b;
+ state->header_state = 4;
+ break;
+ case 4: case 5: case 6: case 7: /* Mod time. */
+ case 8: /* Deflate flags. */
+ case 9: /* OS. */
+ ++state->header_state;
+ break;
+ case 10: /* Optional Extra: First byte of Length. */
+ if ((state->header_flags & 4)) {
+ state->header_count = 255 & (int)b;
+ state->header_state = 11;
+ break;
+ }
+ /* Fall through if no Optional Extra field. */
+ case 11: /* Optional Extra: Second byte of Length. */
+ if ((state->header_flags & 4)) {
+ state->header_count
+ = (0xff00 & ((int)b << 8)) | state->header_count;
+ state->header_state = 12;
+ break;
+ }
+ /* Fall through if no Optional Extra field. */
+ case 12: /* Optional Extra Field: counted length. */
+ if ((state->header_flags & 4)) {
+ --state->header_count;
+ if (state->header_count == 0) state->header_state = 13;
+ else state->header_state = 12;
+ break;
+ }
+ /* Fall through if no Optional Extra field. */
+ case 13: /* Optional Original Filename. */
+ if ((state->header_flags & 8)) {
+ if (b == 0) state->header_state = 14;
+ else state->header_state = 13;
+ break;
+ }
+ /* Fall through if no Optional Original Filename. */
+ case 14: /* Optional Comment. */
+ if ((state->header_flags & 16)) {
+ if (b == 0) state->header_state = 15;
+ else state->header_state = 14;
+ break;
+ }
+ /* Fall through if no Optional Comment. */
+ case 15: /* Optional Header CRC: First byte. */
+ if ((state->header_flags & 2)) {
+ state->header_state = 16;
+ break;
+ }
+ /* Fall through if no Optional Header CRC. */
+ case 16: /* Optional Header CRC: Second byte. */
+ if ((state->header_flags & 2)) {
+ state->header_state = 17;
+ break;
+ }
+ /* Fall through if no Optional Header CRC. */
+ case 17: /* First byte of compressed data. */
+ state->header_done = 1; /* done with header */
+ state->stream.avail_in++; /* Discard first byte. */
+ state->stream.next_in--;
+
+ /* Initialize compression library. */
+ ret = inflateInit2(&(state->stream),
+ -15 /* Don't check for zlib header */);
+
+ /* Decipher the error code. */
+ switch (ret) {
+ case Z_OK:
+ return (ARCHIVE_OK);
+ case Z_STREAM_ERROR:
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Internal error initializing compression library: "
+ "invalid setup parameter");
+ break;
+ case Z_MEM_ERROR:
+ archive_set_error(&self->archive->archive, ENOMEM,
+ "Internal error initializing compression library: "
+ "out of memory");
+ break;
+ case Z_VERSION_ERROR:
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Internal error initializing compression library: "
+ "invalid library version");
break;
+ default:
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Internal error initializing compression library: "
+ " Zlib error %d", ret);
+ break;
+ }
+ return (ARCHIVE_FATAL);
}
- *p = state->read_next;
- return (read_avail);
+ return (ARCHIVE_OK);
}
-/*
- * Mark a previously-returned block of data as read.
- */
static ssize_t
-read_consume(struct archive_read *a, size_t n)
-{
- struct private_data *state;
-
- state = (struct private_data *)a->decompressor->data;
- a->archive.file_position += n;
- state->read_next += n;
- if (state->read_next > state->stream.next_out)
- __archive_errx(1, "Request to consume too many "
- "bytes from gzip decompressor");
- return (n);
-}
-
-/*
- * Clean up the decompressor.
- */
-static int
-finish(struct archive_read *a)
+gzip_source_read(struct archive_read_source *self, const void **p)
{
struct private_data *state;
+ size_t read_avail, decompressed;
+ const void *read_buf;
int ret;
- state = (struct private_data *)a->decompressor->data;
- ret = ARCHIVE_OK;
- switch (inflateEnd(&(state->stream))) {
- case Z_OK:
- break;
- default:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Failed to clean up %s compressor",
- a->archive.compression_name);
- ret = ARCHIVE_FATAL;
- }
-
- free(state->uncompressed_buffer);
- free(state);
-
- a->decompressor->data = NULL;
- return (ret);
-}
+ state = (struct private_data *)self->data;
+ read_avail = 0;
-/*
- * Utility function to pull data through decompressor, reading input
- * blocks as necessary.
- */
-static int
-drive_decompressor(struct archive_read *a, struct private_data *state)
-{
- ssize_t ret;
- size_t decompressed, total_decompressed;
- int count, flags, header_state;
- unsigned char *output;
- unsigned char b;
- const void *read_buf;
+ /* Empty our output buffer. */
+ state->stream.next_out = state->out_block;
+ state->stream.avail_out = state->out_block_size;
- if (state->eof)
- return (ARCHIVE_EOF);
- flags = 0;
- count = 0;
- header_state = 0;
- total_decompressed = 0;
- for (;;) {
+ /* Try to fill the output buffer. */
+ while (state->stream.avail_out > 0 && !state->eof) {
+ /* If the last upstream block is done, get another one. */
if (state->stream.avail_in == 0) {
- read_buf = state->stream.next_in;
- ret = (a->client_reader)(&a->archive, a->client_data,
+ ret = (self->upstream->read)(self->upstream,
&read_buf);
- state->stream.next_in = (unsigned char *)(uintptr_t)read_buf;
- if (ret < 0) {
- /*
- * TODO: Find a better way to handle
- * this read failure.
- */
- goto fatal;
- }
- if (ret == 0 && total_decompressed == 0) {
- archive_set_error(&a->archive, EIO,
- "Premature end of %s compressed data",
- a->archive.compression_name);
+ /* stream.next_in is really const, but zlib
+ * doesn't declare it so. <sigh> */
+ state->stream.next_in
+ = (unsigned char *)(uintptr_t)read_buf;
+ if (ret < 0)
return (ARCHIVE_FATAL);
- }
- a->archive.raw_position += ret;
state->stream.avail_in = ret;
+ /* There is no more data, return whatever we have. */
+ if (ret == 0) {
+ state->eof = 1;
+ break;
+ }
}
+ /* If we're still parsing header bytes, walk through those. */
if (!state->header_done) {
- /*
- * If still parsing the header, interpret the
- * next byte.
- */
- b = *(state->stream.next_in++);
- state->stream.avail_in--;
-
- /*
- * Yes, this is somewhat crude, but it works,
- * GZip format isn't likely to change anytime
- * in the near future, and header parsing is
- * certainly not a performance issue, so
- * there's little point in making this more
- * elegant. Of course, if you see an easy way
- * to make this more elegant, please let me
- * know.. ;-)
- */
- switch (header_state) {
- case 0: /* First byte of signature. */
- if (b != 037)
- goto fatal;
- header_state = 1;
- break;
- case 1: /* Second byte of signature. */
- if (b != 0213)
- goto fatal;
- header_state = 2;
- break;
- case 2: /* Compression type must be 8. */
- if (b != 8)
- goto fatal;
- header_state = 3;
- break;
- case 3: /* GZip flags. */
- flags = b;
- header_state = 4;
- break;
- case 4: case 5: case 6: case 7: /* Mod time. */
- header_state++;
- break;
- case 8: /* Deflate flags. */
- header_state = 9;
- break;
- case 9: /* OS. */
- header_state = 10;
- break;
- case 10: /* Optional Extra: First byte of Length. */
- if ((flags & 4)) {
- count = 255 & (int)b;
- header_state = 11;
- break;
- }
- /*
- * Fall through if there is no
- * Optional Extra field.
- */
- case 11: /* Optional Extra: Second byte of Length. */
- if ((flags & 4)) {
- count = (0xff00 & ((int)b << 8)) | count;
- header_state = 12;
- break;
- }
- /*
- * Fall through if there is no
- * Optional Extra field.
- */
- case 12: /* Optional Extra Field: counted length. */
- if ((flags & 4)) {
- --count;
- if (count == 0) header_state = 13;
- else header_state = 12;
- break;
- }
- /*
- * Fall through if there is no
- * Optional Extra field.
- */
- case 13: /* Optional Original Filename. */
- if ((flags & 8)) {
- if (b == 0) header_state = 14;
- else header_state = 13;
- break;
- }
- /*
- * Fall through if no Optional
- * Original Filename.
- */
- case 14: /* Optional Comment. */
- if ((flags & 16)) {
- if (b == 0) header_state = 15;
- else header_state = 14;
- break;
- }
- /* Fall through if no Optional Comment. */
- case 15: /* Optional Header CRC: First byte. */
- if ((flags & 2)) {
- header_state = 16;
- break;
- }
- /* Fall through if no Optional Header CRC. */
- case 16: /* Optional Header CRC: Second byte. */
- if ((flags & 2)) {
- header_state = 17;
+ ret = header(self);
+ if (ret < ARCHIVE_OK)
+ return (ret);
+ if (ret == ARCHIVE_EOF)
+ state->eof = 1;
+ } else {
+ /* Decompress as much as we can in one pass. */
+ /* XXX Skip trailer XXX */
+ ret = inflate(&(state->stream), 0);
+ switch (ret) {
+ case Z_STREAM_END: /* Found end of stream. */
+ switch (inflateEnd(&(state->stream))) {
+ case Z_OK:
break;
+ default:
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Failed to clean up gzip decompressor");
+ return (ARCHIVE_FATAL);
}
- /* Fall through if no Optional Header CRC. */
- case 17: /* First byte of compressed data. */
- state->header_done = 1; /* done with header */
- state->stream.avail_in++;
- state->stream.next_in--;
+ /* Restart header parser with the next block. */
+ state->header_state = state->header_done = 0;
+ /* FALL THROUGH */
+ case Z_OK: /* Decompressor made some progress. */
+ /* If we filled our buffer, update stats and return. */
+ break;
+ default:
+ /* Return an error. */
+ archive_set_error(&self->archive->archive,
+ ARCHIVE_ERRNO_MISC,
+ "%s decompression failed",
+ self->archive->archive.compression_name);
+ return (ARCHIVE_FATAL);
}
+ }
+ }
- /*
- * TODO: Consider moving the inflateInit2 call
- * here so it can include the compression type
- * from the header?
- */
- } else {
- output = state->stream.next_out;
+ /* We've read as much as we can. */
+ decompressed = state->stream.next_out - state->out_block;
+ state->total_out += decompressed;
+ if (decompressed == 0)
+ *p = NULL;
+ else
+ *p = state->out_block;
+ return (decompressed);
- /* Decompress some data. */
- ret = inflate(&(state->stream), 0);
- decompressed = state->stream.next_out - output;
+}
- /* Accumulate the CRC of the uncompressed data. */
- state->crc = crc32(state->crc, output, decompressed);
+/*
+ * Clean up the decompressor.
+ */
+static int
+gzip_source_close(struct archive_read_source *self)
+{
+ struct private_data *state;
+ int ret;
- /* Accumulate the total bytes of output. */
- state->total_out += decompressed;
- total_decompressed += decompressed;
+ state = (struct private_data *)self->data;
+ ret = ARCHIVE_OK;
- switch (ret) {
- case Z_OK: /* Decompressor made some progress. */
- if (decompressed > 0)
- return (ARCHIVE_OK);
- break;
- case Z_STREAM_END: /* Found end of stream. */
- /*
- * TODO: Verify gzip trailer
- * (uncompressed length and CRC).
- */
- state->eof = 1;
- return (ARCHIVE_OK);
- default:
- /* Any other return value is an error. */
- goto fatal;
- }
+ if (state->header_done) {
+ switch (inflateEnd(&(state->stream))) {
+ case Z_OK:
+ break;
+ default:
+ archive_set_error(&(self->archive->archive),
+ ARCHIVE_ERRNO_MISC,
+ "Failed to clean up %s compressor",
+ self->archive->archive.compression_name);
+ ret = ARCHIVE_FATAL;
}
}
- return (ARCHIVE_OK);
- /* Return a fatal error. */
-fatal:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "%s decompression failed", a->archive.compression_name);
- return (ARCHIVE_FATAL);
+ free(state->out_block);
+ free(state);
+ free(self);
+ return (ret);
}
#endif /* HAVE_ZLIB_H */
diff --git a/lib/libarchive/archive_read_support_compression_none.c b/lib/libarchive/archive_read_support_compression_none.c
index 2b9d43f..e05614f 100644
--- a/lib/libarchive/archive_read_support_compression_none.c
+++ b/lib/libarchive/archive_read_support_compression_none.c
@@ -26,345 +26,15 @@
#include "archive_platform.h"
__FBSDID("$FreeBSD$");
-#ifdef HAVE_ERRNO_H
-#include <errno.h>
-#endif
-#ifdef HAVE_LIMITS_H
-#include <limits.h>
-#endif
-#ifdef HAVE_STDLIB_H
-#include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
-#include <string.h>
-#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
-
#include "archive.h"
-#include "archive_private.h"
-#include "archive_read_private.h"
-
-struct archive_decompress_none {
- char *buffer;
- size_t buffer_size;
- char *next; /* Current read location. */
- size_t avail; /* Bytes in my buffer. */
- const void *client_buff; /* Client buffer information. */
- size_t client_total;
- const char *client_next;
- size_t client_avail;
- char end_of_file;
- char fatal;
-};
/*
- * Size of internal buffer used for combining short reads. This is
- * also an upper limit on the size of a read request. Recall,
- * however, that we can (and will!) return blocks of data larger than
- * this. The read semantics are: you ask for a minimum, I give you a
- * pointer to my best-effort match and tell you how much data is
- * there. It could be less than you asked for, it could be much more.
- * For example, a client might use mmap() to "read" the entire file as
- * a single block. In that case, I will return that entire block to
- * my clients.
+ * Uncompressed streams are handled implicitly by the read core,
+ * so this is now a no-op.
*/
-#define BUFFER_SIZE 65536
-
-#define minimum(a, b) (a < b ? a : b)
-
-static int archive_decompressor_none_bid(const void *, size_t);
-static int archive_decompressor_none_finish(struct archive_read *);
-static int archive_decompressor_none_init(struct archive_read *,
- const void *, size_t);
-static ssize_t archive_decompressor_none_read_ahead(struct archive_read *,
- const void **, size_t);
-static ssize_t archive_decompressor_none_read_consume(struct archive_read *,
- size_t);
-static off_t archive_decompressor_none_skip(struct archive_read *, off_t);
-
int
-archive_read_support_compression_none(struct archive *_a)
+archive_read_support_compression_none(struct archive *a)
{
- struct archive_read *a = (struct archive_read *)_a;
- if (__archive_read_register_compression(a,
- archive_decompressor_none_bid,
- archive_decompressor_none_init) != NULL)
- return (ARCHIVE_OK);
- return (ARCHIVE_FATAL);
-}
-
-/*
- * Try to detect an "uncompressed" archive.
- */
-static int
-archive_decompressor_none_bid(const void *buff, size_t len)
-{
- (void)buff;
- (void)len;
-
- return (1); /* Default: We'll take it if noone else does. */
-}
-
-static int
-archive_decompressor_none_init(struct archive_read *a, const void *buff, size_t n)
-{
- struct archive_decompress_none *state;
-
- a->archive.compression_code = ARCHIVE_COMPRESSION_NONE;
- a->archive.compression_name = "none";
-
- state = (struct archive_decompress_none *)malloc(sizeof(*state));
- if (!state) {
- archive_set_error(&a->archive, ENOMEM, "Can't allocate input data");
- return (ARCHIVE_FATAL);
- }
- memset(state, 0, sizeof(*state));
-
- state->buffer_size = BUFFER_SIZE;
- state->buffer = (char *)malloc(state->buffer_size);
- state->next = state->buffer;
- if (state->buffer == NULL) {
- free(state);
- archive_set_error(&a->archive, ENOMEM, "Can't allocate input buffer");
- return (ARCHIVE_FATAL);
- }
-
- /* Save reference to first block of data. */
- state->client_buff = buff;
- state->client_total = n;
- state->client_next = state->client_buff;
- state->client_avail = state->client_total;
-
- a->decompressor->data = state;
- a->decompressor->read_ahead = archive_decompressor_none_read_ahead;
- a->decompressor->consume = archive_decompressor_none_read_consume;
- a->decompressor->skip = archive_decompressor_none_skip;
- a->decompressor->finish = archive_decompressor_none_finish;
-
- return (ARCHIVE_OK);
-}
-
-/*
- * We just pass through pointers to the client buffer if we can.
- * If the client buffer is short, then we copy stuff to our internal
- * buffer to combine reads.
- */
-static ssize_t
-archive_decompressor_none_read_ahead(struct archive_read *a, const void **buff,
- size_t min)
-{
- struct archive_decompress_none *state;
- ssize_t bytes_read;
-
- state = (struct archive_decompress_none *)a->decompressor->data;
- if (state->fatal)
- return (-1);
-
- /*
- * Don't make special efforts to handle requests larger than
- * the copy buffer.
- */
- if (min > state->buffer_size)
- min = state->buffer_size;
-
- /*
- * Keep pulling more data until we can satisfy the request.
- */
- for (;;) {
-
- /*
- * If we can satisfy from the copy buffer, we're done.
- */
- if (state->avail >= min) {
- *buff = state->next;
- return (state->avail);
- }
-
- /*
- * We can satisfy directly from client buffer if everything
- * currently in the copy buffer is still in the client buffer.
- */
- if (state->client_total >= state->client_avail + state->avail
- && state->client_avail + state->avail >= min) {
- /* "Roll back" to client buffer. */
- state->client_avail += state->avail;
- state->client_next -= state->avail;
- /* Copy buffer is now empty. */
- state->avail = 0;
- state->next = state->buffer;
- /* Return data from client buffer. */
- *buff = state->client_next;
- return (state->client_avail);
- }
-
- /* Move data forward in copy buffer if necessary. */
- if (state->next > state->buffer &&
- state->next + min > state->buffer + state->buffer_size) {
- if (state->avail > 0)
- memmove(state->buffer, state->next, state->avail);
- state->next = state->buffer;
- }
-
- /* If we've used up the client data, get more. */
- if (state->client_avail <= 0) {
- bytes_read = (a->client_reader)(&a->archive,
- a->client_data, &state->client_buff);
- if (bytes_read < 0) { /* Read error. */
- state->client_total = state->client_avail = 0;
- state->client_next = state->client_buff = NULL;
- state->fatal = 1;
- return (-1);
- }
- if (bytes_read == 0) { /* End-of-file. */
- state->client_total = state->client_avail = 0;
- state->client_next = state->client_buff = NULL;
- state->end_of_file = 1;
- /* Return whatever we do have. */
- *buff = state->next;
- return (state->avail);
- }
- a->archive.raw_position += bytes_read;
- state->client_total = bytes_read;
- state->client_avail = state->client_total;
- state->client_next = state->client_buff;
- }
- else
- {
- /* We can add client data to copy buffer. */
- /* First estimate: copy to fill rest of buffer. */
- size_t tocopy = (state->buffer + state->buffer_size)
- - (state->next + state->avail);
- /* Don't copy more than is available. */
- if (tocopy > state->client_avail)
- tocopy = state->client_avail;
- memcpy(state->next + state->avail, state->client_next,
- tocopy);
- /* Remove this data from client buffer. */
- state->client_next += tocopy;
- state->client_avail -= tocopy;
- /* add it to copy buffer. */
- state->avail += tocopy;
- }
- }
-}
-
-/*
- * Mark the appropriate data as used. Note that the request here will
- * often be much smaller than the size of the previous read_ahead
- * request.
- */
-static ssize_t
-archive_decompressor_none_read_consume(struct archive_read *a, size_t request)
-{
- struct archive_decompress_none *state;
-
- state = (struct archive_decompress_none *)a->decompressor->data;
- if (state->avail > 0) {
- /* Read came from copy buffer. */
- state->next += request;
- state->avail -= request;
- } else {
- /* Read came from client buffer. */
- state->client_next += request;
- state->client_avail -= request;
- }
- a->archive.file_position += request;
- return (request);
-}
-
-/*
- * Skip forward by exactly the requested bytes or else return
- * ARCHIVE_FATAL. Note that this differs from the contract for
- * read_ahead, which does not guarantee a minimum count.
- */
-static off_t
-archive_decompressor_none_skip(struct archive_read *a, off_t request)
-{
- struct archive_decompress_none *state;
- off_t bytes_skipped, total_bytes_skipped = 0;
- size_t min;
-
- state = (struct archive_decompress_none *)a->decompressor->data;
- if (state->fatal)
- return (-1);
- /*
- * If there is data in the buffers already, use that first.
- */
- if (state->avail > 0) {
- min = minimum(request, (off_t)state->avail);
- bytes_skipped = archive_decompressor_none_read_consume(a, min);
- request -= bytes_skipped;
- total_bytes_skipped += bytes_skipped;
- }
- if (state->client_avail > 0) {
- min = minimum(request, (off_t)state->client_avail);
- bytes_skipped = archive_decompressor_none_read_consume(a, min);
- request -= bytes_skipped;
- total_bytes_skipped += bytes_skipped;
- }
- if (request == 0)
- return (total_bytes_skipped);
- /*
- * If a client_skipper was provided, try that first.
- */
-#if ARCHIVE_API_VERSION < 2
- if ((a->client_skipper != NULL) && (request < SSIZE_MAX)) {
-#else
- if (a->client_skipper != NULL) {
-#endif
- bytes_skipped = (a->client_skipper)(&a->archive,
- a->client_data, request);
- if (bytes_skipped < 0) { /* error */
- state->client_total = state->client_avail = 0;
- state->client_next = state->client_buff = NULL;
- state->fatal = 1;
- return (bytes_skipped);
- }
- total_bytes_skipped += bytes_skipped;
- a->archive.file_position += bytes_skipped;
- request -= bytes_skipped;
- state->client_next = state->client_buff;
- a->archive.raw_position += bytes_skipped;
- state->client_avail = state->client_total = 0;
- }
- /*
- * Note that client_skipper will usually not satisfy the
- * full request (due to low-level blocking concerns),
- * so even if client_skipper is provided, we may still
- * have to use ordinary reads to finish out the request.
- */
- while (request > 0) {
- const void* dummy_buffer;
- ssize_t bytes_read;
- bytes_read = archive_decompressor_none_read_ahead(a,
- &dummy_buffer, 1);
- if (bytes_read < 0)
- return (bytes_read);
- if (bytes_read == 0) {
- /* We hit EOF before we satisfied the skip request. */
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Truncated input file (need to skip %jd bytes)",
- (intmax_t)request);
- return (ARCHIVE_FATAL);
- }
- min = (size_t)(minimum(bytes_read, request));
- bytes_read = archive_decompressor_none_read_consume(a, min);
- total_bytes_skipped += bytes_read;
- request -= bytes_read;
- }
- return (total_bytes_skipped);
-}
-
-static int
-archive_decompressor_none_finish(struct archive_read *a)
-{
- struct archive_decompress_none *state;
-
- state = (struct archive_decompress_none *)a->decompressor->data;
- free(state->buffer);
- free(state);
- a->decompressor->data = NULL;
+ (void)a; /* UNUSED */
return (ARCHIVE_OK);
}
diff --git a/lib/libarchive/archive_read_support_compression_program.c b/lib/libarchive/archive_read_support_compression_program.c
index 0bea78d..a9d6c5f 100644
--- a/lib/libarchive/archive_read_support_compression_program.c
+++ b/lib/libarchive/archive_read_support_compression_program.c
@@ -75,64 +75,94 @@ archive_read_support_compression_program(struct archive *_a, const char *cmd)
#include "filter_fork.h"
-struct archive_decompress_program {
+struct program_reader {
+ char *cmd;
+ int bid;
+};
+
+struct program_source {
char *description;
pid_t child;
int child_stdin, child_stdout;
- char *child_out_buf;
- char *child_out_buf_next;
- size_t child_out_buf_len, child_out_buf_avail;
+ char *out_buf;
+ size_t out_buf_len;
const char *child_in_buf;
size_t child_in_buf_avail;
};
-static int archive_decompressor_program_bid(const void *, size_t);
-static int archive_decompressor_program_finish(struct archive_read *);
-static int archive_decompressor_program_init(struct archive_read *,
+static int program_reader_bid(struct archive_reader *,
const void *, size_t);
-static ssize_t archive_decompressor_program_read_ahead(struct archive_read *,
- const void **, size_t);
-static ssize_t archive_decompressor_program_read_consume(struct archive_read *,
- size_t);
+static struct archive_read_source *program_reader_init(struct archive_read *,
+ struct archive_reader *, struct archive_read_source *,
+ const void *, size_t);
+static int program_reader_free(struct archive_reader *);
+
+static ssize_t program_source_read(struct archive_read_source *,
+ const void **);
+static int program_source_close(struct archive_read_source *);
+
int
archive_read_support_compression_program(struct archive *_a, const char *cmd)
{
struct archive_read *a = (struct archive_read *)_a;
- struct decompressor_t *decompressor;
+ struct archive_reader *reader = __archive_read_get_reader(a);
+ struct program_reader *state;
- if (cmd == NULL || *cmd == '\0')
- return (ARCHIVE_WARN);
+ state = (struct program_reader *)calloc(sizeof (*state), 1);
- decompressor = __archive_read_register_compression(a,
- archive_decompressor_program_bid,
- archive_decompressor_program_init);
- if (decompressor == NULL)
- return (ARCHIVE_WARN);
+ if (state == NULL)
+ return (ARCHIVE_FATAL);
+ if (reader == NULL)
+ return (ARCHIVE_FATAL);
- decompressor->config = strdup(cmd);
+ state->cmd = strdup(cmd);
+ state->bid = INT_MAX;
+
+ reader->data = state;
+ reader->bid = program_reader_bid;
+ reader->init = program_reader_init;
+ reader->free = program_reader_free;
+ return (ARCHIVE_OK);
+}
+
+static int
+program_reader_free(struct archive_reader *self)
+{
+ free(self->data);
return (ARCHIVE_OK);
}
/*
* If the user used us to register, they must really want us to
- * handle it, so this module always bids INT_MAX.
+ * handle it, so we always bid INT_MAX the first time we're called.
+ * After that, we always return zero, lest we end up instantiating
+ * an infinite pipeline.
*/
static int
-archive_decompressor_program_bid(const void *buff, size_t len)
+program_reader_bid(struct archive_reader *self, const void *buff, size_t len)
{
+ struct program_reader *state = self->data;
+ int bid = state->bid;
+
(void)buff; /* UNUSED */
(void)len; /* UNUSED */
- return (INT_MAX); /* Default: We'll take it. */
+ state->bid = 0; /* Don't bid again on this pipeline. */
+
+ return (bid); /* Default: We'll take it if we haven't yet bid. */
}
+/*
+ * Use select() to decide whether the child is ready for read or write.
+ */
+
static ssize_t
-child_read(struct archive_read *a, char *buf, size_t buf_len)
+child_read(struct archive_read_source *self, char *buf, size_t buf_len)
{
- struct archive_decompress_program *state = a->decompressor->data;
+ struct program_source *state = self->data;
ssize_t ret, requested;
const void *child_buf;
@@ -161,8 +191,7 @@ restart_read:
if (state->child_in_buf_avail == 0) {
child_buf = state->child_in_buf;
- ret = (a->client_reader)(&a->archive,
- a->client_data,&child_buf);
+ ret = (self->upstream->read)(self->upstream, &child_buf);
state->child_in_buf = (const char *)child_buf;
if (ret < 0) {
@@ -211,118 +240,103 @@ restart_read:
}
}
-static int
-archive_decompressor_program_init(struct archive_read *a, const void *buff, size_t n)
+static struct archive_read_source *
+program_reader_init(struct archive_read *a, struct archive_reader *reader,
+ struct archive_read_source *upstream, const void *buff, size_t n)
{
- struct archive_decompress_program *state;
- const char *cmd = a->decompressor->config;
+ struct program_source *state;
+ struct program_reader *reader_state;
+ struct archive_read_source *self;
+ static const size_t out_buf_len = 65536;
+ char *out_buf;
+ char *description;
const char *prefix = "Program: ";
- state = (struct archive_decompress_program *)malloc(sizeof(*state));
- if (!state) {
+ reader_state = (struct program_reader *)reader->data;
+
+ self = (struct archive_read_source *)malloc(sizeof(*self));
+ state = (struct program_source *)malloc(sizeof(*state));
+ out_buf = (char *)malloc(out_buf_len);
+ description = (char *)malloc(strlen(prefix) + strlen(reader_state->cmd) + 1);
+ if (self == NULL
+ || state == NULL
+ || out_buf == NULL
+ || description == NULL)
+ {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate input data");
- return (ARCHIVE_FATAL);
+ free(self);
+ free(state);
+ free(out_buf);
+ free(description);
+ return (NULL);
}
a->archive.compression_code = ARCHIVE_COMPRESSION_PROGRAM;
- state->description = (char *)malloc(strlen(prefix) + strlen(cmd) + 1);
+ state->description = description;
strcpy(state->description, prefix);
- strcat(state->description, cmd);
+ strcat(state->description, reader_state->cmd);
a->archive.compression_name = state->description;
- state->child_out_buf_next = state->child_out_buf = malloc(65536);
- if (!state->child_out_buf) {
- free(state);
- archive_set_error(&a->archive, ENOMEM,
- "Can't allocate filter buffer");
- return (ARCHIVE_FATAL);
- }
- state->child_out_buf_len = 65536;
- state->child_out_buf_avail = 0;
+ state->out_buf = out_buf;
+ state->out_buf_len = out_buf_len;
state->child_in_buf = buff;
state->child_in_buf_avail = n;
- if ((state->child = __archive_create_child(cmd,
+ if ((state->child = __archive_create_child(reader_state->cmd,
&state->child_stdin, &state->child_stdout)) == -1) {
- free(state->child_out_buf);
+ free(state->out_buf);
free(state);
archive_set_error(&a->archive, EINVAL,
"Can't initialise filter");
- return (ARCHIVE_FATAL);
+ return (NULL);
}
- a->decompressor->data = state;
- a->decompressor->read_ahead = archive_decompressor_program_read_ahead;
- a->decompressor->consume = archive_decompressor_program_read_consume;
- a->decompressor->skip = NULL;
- a->decompressor->finish = archive_decompressor_program_finish;
+ self->data = state;
+ self->read = program_source_read;
+ self->skip = NULL;
+ self->close = program_source_close;
+ self->upstream = upstream;
+ self->archive = a;
/* XXX Check that we can read at least one byte? */
- return (ARCHIVE_OK);
+ return (self);
}
static ssize_t
-archive_decompressor_program_read_ahead(struct archive_read *a, const void **buff,
- size_t min)
+program_source_read(struct archive_read_source *self, const void **buff)
{
- struct archive_decompress_program *state;
- ssize_t bytes_read;
-
- state = (struct archive_decompress_program *)a->decompressor->data;
-
- if (min > state->child_out_buf_len)
- min = state->child_out_buf_len;
-
- while (state->child_stdout != -1 && min > state->child_out_buf_avail) {
- if (state->child_out_buf != state->child_out_buf_next) {
- memmove(state->child_out_buf, state->child_out_buf_next,
- state->child_out_buf_avail);
- state->child_out_buf_next = state->child_out_buf;
- }
-
- bytes_read = child_read(a,
- state->child_out_buf + state->child_out_buf_avail,
- state->child_out_buf_len - state->child_out_buf_avail);
- if (bytes_read == -1)
- return (-1);
- if (bytes_read == 0)
+ struct program_source *state;
+ ssize_t bytes, total;
+ char *p;
+
+ state = (struct program_source *)self->data;
+
+ total = 0;
+ p = state->out_buf;
+ while (state->child_stdout != -1) {
+ bytes = child_read(self, p, state->out_buf_len - total);
+ if (bytes < 0)
+ return (bytes);
+ if (bytes == 0)
break;
- state->child_out_buf_avail += bytes_read;
- a->archive.raw_position += bytes_read;
+ total += bytes;
+/* TODO: fix this */ /* a->archive.raw_position += bytes_read; */
}
- *buff = state->child_out_buf_next;
- return (state->child_out_buf_avail);
-}
-
-static ssize_t
-archive_decompressor_program_read_consume(struct archive_read *a, size_t request)
-{
- struct archive_decompress_program *state;
-
- state = (struct archive_decompress_program *)a->decompressor->data;
-
- state->child_out_buf_next += request;
- state->child_out_buf_avail -= request;
-
- a->archive.file_position += request;
- return (request);
+ *buff = state->out_buf;
+ return (total);
}
static int
-archive_decompressor_program_finish(struct archive_read *a)
+program_source_close(struct archive_read_source *self)
{
- struct archive_decompress_program *state;
+ struct program_source *state;
int status;
- state = (struct archive_decompress_program *)a->decompressor->data;
-
- /* Release our configuration data. */
- free(a->decompressor->config);
- a->decompressor->config = NULL;
+ state = (struct program_source *)self->data;
/* Shut down the child. */
if (state->child_stdin != -1)
@@ -333,10 +347,10 @@ archive_decompressor_program_finish(struct archive_read *a)
continue;
/* Release our private data. */
- free(state->child_out_buf);
+ free(state->out_buf);
free(state->description);
free(state);
- a->decompressor->data = NULL;
+ free(self);
return (ARCHIVE_OK);
}
diff --git a/lib/libarchive/archive_read_support_format_ar.c b/lib/libarchive/archive_read_support_format_ar.c
index 175876e..7f3588c 100644
--- a/lib/libarchive/archive_read_support_format_ar.c
+++ b/lib/libarchive/archive_read_support_format_ar.c
@@ -135,7 +135,6 @@ static int
archive_read_format_ar_bid(struct archive_read *a)
{
struct ar *ar;
- ssize_t bytes_read;
const void *h;
if (a->archive.archive_format != 0 &&
@@ -149,8 +148,7 @@ archive_read_format_ar_bid(struct archive_read *a)
* Verify the 8-byte file signature.
* TODO: Do we need to check more than this?
*/
- bytes_read = (a->decompressor->read_ahead)(a, &h, 8);
- if (bytes_read < 8)
+ if ((h = __archive_read_ahead(a, 8, NULL)) == NULL)
return (-1);
if (strncmp((const char*)h, "!<arch>\n", 8) == 0) {
return (64);
@@ -166,7 +164,7 @@ archive_read_format_ar_read_header(struct archive_read *a,
struct ar *ar;
uint64_t number; /* Used to hold parsed numbers before validation. */
ssize_t bytes_read;
- size_t bsd_name_length, entry_size, s;
+ size_t bsd_name_length, entry_size;
char *p, *st;
const void *b;
const char *h;
@@ -179,18 +177,16 @@ archive_read_format_ar_read_header(struct archive_read *a,
* We are now at the beginning of the archive,
* so we need first consume the ar global header.
*/
- (a->decompressor->consume)(a, 8);
+ __archive_read_consume(a, 8);
/* Set a default format code for now. */
a->archive.archive_format = ARCHIVE_FORMAT_AR;
}
/* Read the header for the next file entry. */
- bytes_read = (a->decompressor->read_ahead)(a, &b, 60);
- if (bytes_read < 60) {
+ if ((b = __archive_read_ahead(a, 60, &bytes_read)) == NULL)
/* Broken header. */
return (ARCHIVE_EOF);
- }
- (a->decompressor->consume)(a, 60);
+ __archive_read_consume(a, 60);
h = (const char *)b;
/* Verify the magic signature on the file header. */
@@ -296,16 +292,10 @@ archive_read_format_ar_read_header(struct archive_read *a,
}
ar->strtab = st;
ar->strtab_size = entry_size;
- for (s = entry_size; s > 0; s -= bytes_read) {
- bytes_read = (a->decompressor->read_ahead)(a, &b, s);
- if (bytes_read <= 0)
- return (ARCHIVE_FATAL);
- if (bytes_read > (ssize_t)s)
- bytes_read = s;
- memcpy(st, b, bytes_read);
- st += bytes_read;
- (a->decompressor->consume)(a, bytes_read);
- }
+ if ((b = __archive_read_ahead(a, entry_size, NULL)) == NULL)
+ return (ARCHIVE_FATAL);
+ memcpy(st, b, entry_size);
+ __archive_read_consume(a, entry_size);
/* All contents are consumed. */
ar->entry_bytes_remaining = 0;
archive_entry_set_size(entry, ar->entry_bytes_remaining);
@@ -365,15 +355,12 @@ archive_read_format_ar_read_header(struct archive_read *a,
archive_entry_set_size(entry, ar->entry_bytes_remaining);
/* Read the long name into memory. */
- bytes_read = (a->decompressor->read_ahead)(a, &b, bsd_name_length);
- if (bytes_read <= 0)
- return (ARCHIVE_FATAL);
- if ((size_t)bytes_read < bsd_name_length) {
+ if ((b = __archive_read_ahead(a, bsd_name_length, NULL)) == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Truncated input file");
return (ARCHIVE_FATAL);
}
- (a->decompressor->consume)(a, bsd_name_length);
+ __archive_read_consume(a, bsd_name_length);
/* Store it in the entry. */
p = (char *)malloc(bsd_name_length + 1);
@@ -453,7 +440,7 @@ archive_read_format_ar_read_data(struct archive_read *a,
ar = (struct ar *)(a->format->data);
if (ar->entry_bytes_remaining > 0) {
- bytes_read = (a->decompressor->read_ahead)(a, buff, 1);
+ *buff = __archive_read_ahead(a, 1, &bytes_read);
if (bytes_read == 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Truncated ar archive");
@@ -467,16 +454,16 @@ archive_read_format_ar_read_data(struct archive_read *a,
*offset = ar->entry_offset;
ar->entry_offset += bytes_read;
ar->entry_bytes_remaining -= bytes_read;
- (a->decompressor->consume)(a, (size_t)bytes_read);
+ __archive_read_consume(a, (size_t)bytes_read);
return (ARCHIVE_OK);
} else {
while (ar->entry_padding > 0) {
- bytes_read = (a->decompressor->read_ahead)(a, buff, 1);
+ *buff = __archive_read_ahead(a, 1, &bytes_read);
if (bytes_read <= 0)
return (ARCHIVE_FATAL);
if (bytes_read > ar->entry_padding)
bytes_read = (ssize_t)ar->entry_padding;
- (a->decompressor->consume)(a, (size_t)bytes_read);
+ __archive_read_consume(a, (size_t)bytes_read);
ar->entry_padding -= bytes_read;
}
*buff = NULL;
@@ -491,20 +478,11 @@ archive_read_format_ar_skip(struct archive_read *a)
{
off_t bytes_skipped;
struct ar* ar;
- int r = ARCHIVE_OK;
- const void *b; /* Dummy variables */
- size_t s;
- off_t o;
ar = (struct ar *)(a->format->data);
- if (a->decompressor->skip == NULL) {
- while (r == ARCHIVE_OK)
- r = archive_read_format_ar_read_data(a, &b, &s, &o);
- return (r);
- }
- bytes_skipped = (a->decompressor->skip)(a, ar->entry_bytes_remaining +
- ar->entry_padding);
+ bytes_skipped = __archive_read_skip(a,
+ ar->entry_bytes_remaining + ar->entry_padding);
if (bytes_skipped < 0)
return (ARCHIVE_FATAL);
diff --git a/lib/libarchive/archive_read_support_format_cpio.c b/lib/libarchive/archive_read_support_format_cpio.c
index 5cb5fe6..218371a 100644
--- a/lib/libarchive/archive_read_support_format_cpio.c
+++ b/lib/libarchive/archive_read_support_format_cpio.c
@@ -165,7 +165,6 @@ archive_read_support_format_cpio(struct archive *_a)
static int
archive_read_format_cpio_bid(struct archive_read *a)
{
- int bytes_read;
const void *h;
const unsigned char *p;
struct cpio *cpio;
@@ -173,11 +172,7 @@ archive_read_format_cpio_bid(struct archive_read *a)
cpio = (struct cpio *)(a->format->data);
- bytes_read = (a->decompressor->read_ahead)(a, &h, 6);
- /* Convert error code into error return. */
- if (bytes_read < 0)
- return ((int)bytes_read);
- if (bytes_read < 6)
+ if ((h = __archive_read_ahead(a, 6, NULL)) == NULL)
return (-1);
p = (const unsigned char *)h;
@@ -228,7 +223,6 @@ archive_read_format_cpio_read_header(struct archive_read *a,
struct archive_entry *entry)
{
struct cpio *cpio;
- size_t bytes;
const void *h;
size_t namelength;
size_t name_pad;
@@ -241,21 +235,20 @@ archive_read_format_cpio_read_header(struct archive_read *a,
return (r);
/* Read name from buffer. */
- bytes = (a->decompressor->read_ahead)(a, &h, namelength + name_pad);
- if (bytes < namelength + name_pad)
+ h = __archive_read_ahead(a, namelength + name_pad, NULL);
+ if (h == NULL)
return (ARCHIVE_FATAL);
- (a->decompressor->consume)(a, namelength + name_pad);
+ __archive_read_consume(a, namelength + name_pad);
archive_strncpy(&cpio->entry_name, (const char *)h, namelength);
archive_entry_set_pathname(entry, cpio->entry_name.s);
cpio->entry_offset = 0;
/* If this is a symlink, read the link contents. */
if (archive_entry_filetype(entry) == AE_IFLNK) {
- bytes = (a->decompressor->read_ahead)(a, &h,
- cpio->entry_bytes_remaining);
- if ((off_t)bytes < cpio->entry_bytes_remaining)
+ h = __archive_read_ahead(a, cpio->entry_bytes_remaining, NULL);
+ if (h == NULL)
return (ARCHIVE_FATAL);
- (a->decompressor->consume)(a, cpio->entry_bytes_remaining);
+ __archive_read_consume(a, cpio->entry_bytes_remaining);
archive_strncpy(&cpio->entry_linkname, (const char *)h,
cpio->entry_bytes_remaining);
archive_entry_set_symlink(entry, cpio->entry_linkname.s);
@@ -284,7 +277,7 @@ archive_read_format_cpio_read_data(struct archive_read *a,
cpio = (struct cpio *)(a->format->data);
if (cpio->entry_bytes_remaining > 0) {
- bytes_read = (a->decompressor->read_ahead)(a, buff, 1);
+ *buff = __archive_read_ahead(a, 1, &bytes_read);
if (bytes_read <= 0)
return (ARCHIVE_FATAL);
if (bytes_read > cpio->entry_bytes_remaining)
@@ -293,16 +286,16 @@ archive_read_format_cpio_read_data(struct archive_read *a,
*offset = cpio->entry_offset;
cpio->entry_offset += bytes_read;
cpio->entry_bytes_remaining -= bytes_read;
- (a->decompressor->consume)(a, bytes_read);
+ __archive_read_consume(a, bytes_read);
return (ARCHIVE_OK);
} else {
while (cpio->entry_padding > 0) {
- bytes_read = (a->decompressor->read_ahead)(a, buff, 1);
+ *buff = __archive_read_ahead(a, 1, &bytes_read);
if (bytes_read <= 0)
return (ARCHIVE_FATAL);
if (bytes_read > cpio->entry_padding)
bytes_read = cpio->entry_padding;
- (a->decompressor->consume)(a, bytes_read);
+ __archive_read_consume(a, bytes_read);
cpio->entry_padding -= bytes_read;
}
*buff = NULL;
@@ -339,8 +332,8 @@ find_newc_header(struct archive_read *a)
size_t skip, bytes, skipped = 0;
for (;;) {
- bytes = (a->decompressor->read_ahead)(a, &h, 2048);
- if (bytes < sizeof(struct cpio_newc_header))
+ h = __archive_read_ahead(a, sizeof(struct cpio_newc_header), &bytes);
+ if (h == NULL)
return (ARCHIVE_FATAL);
p = h;
q = p + bytes;
@@ -362,7 +355,7 @@ find_newc_header(struct archive_read *a)
if (memcmp("07070", p, 5) == 0
&& is_hex(p, sizeof(struct cpio_newc_header))) {
skip = p - (const char *)h;
- (a->decompressor->consume)(a, skip);
+ __archive_read_consume(a, skip);
skipped += skip;
if (skipped > 0) {
archive_set_error(&a->archive,
@@ -385,7 +378,7 @@ find_newc_header(struct archive_read *a)
}
}
skip = p - (const char *)h;
- (a->decompressor->consume)(a, skip);
+ __archive_read_consume(a, skip);
skipped += skip;
}
}
@@ -396,7 +389,6 @@ header_newc(struct archive_read *a, struct cpio *cpio,
{
const void *h;
const struct cpio_newc_header *header;
- size_t bytes;
int r;
r = find_newc_header(a);
@@ -404,10 +396,10 @@ header_newc(struct archive_read *a, struct cpio *cpio,
return (r);
/* Read fixed-size portion of header. */
- bytes = (a->decompressor->read_ahead)(a, &h, sizeof(struct cpio_newc_header));
- if (bytes < sizeof(struct cpio_newc_header))
+ h = __archive_read_ahead(a, sizeof(struct cpio_newc_header), NULL);
+ if (h == NULL)
return (ARCHIVE_FATAL);
- (a->decompressor->consume)(a, sizeof(struct cpio_newc_header));
+ __archive_read_consume(a, sizeof(struct cpio_newc_header));
/* Parse out hex fields. */
header = (const struct cpio_newc_header *)h;
@@ -474,8 +466,8 @@ find_odc_header(struct archive_read *a)
size_t skip, bytes, skipped = 0;
for (;;) {
- bytes = (a->decompressor->read_ahead)(a, &h, 512);
- if (bytes < sizeof(struct cpio_odc_header))
+ h = __archive_read_ahead(a, sizeof(struct cpio_odc_header), &bytes);
+ if (h == NULL)
return (ARCHIVE_FATAL);
p = h;
q = p + bytes;
@@ -495,7 +487,7 @@ find_odc_header(struct archive_read *a)
if (memcmp("070707", p, 6) == 0
&& is_octal(p, sizeof(struct cpio_odc_header))) {
skip = p - (const char *)h;
- (a->decompressor->consume)(a, skip);
+ __archive_read_consume(a, skip);
skipped += skip;
if (skipped > 0) {
archive_set_error(&a->archive,
@@ -518,7 +510,7 @@ find_odc_header(struct archive_read *a)
}
}
skip = p - (const char *)h;
- (a->decompressor->consume)(a, skip);
+ __archive_read_consume(a, skip);
skipped += skip;
}
}
@@ -530,7 +522,6 @@ header_odc(struct archive_read *a, struct cpio *cpio,
const void *h;
int r;
const struct cpio_odc_header *header;
- size_t bytes;
a->archive.archive_format = ARCHIVE_FORMAT_CPIO_POSIX;
a->archive.archive_format_name = "POSIX octet-oriented cpio";
@@ -541,10 +532,10 @@ header_odc(struct archive_read *a, struct cpio *cpio,
return (r);
/* Read fixed-size portion of header. */
- bytes = (a->decompressor->read_ahead)(a, &h, sizeof(struct cpio_odc_header));
- if (bytes < sizeof(struct cpio_odc_header))
+ h = __archive_read_ahead(a, sizeof(struct cpio_odc_header), NULL);
+ if (h == NULL)
return (ARCHIVE_FATAL);
- (a->decompressor->consume)(a, sizeof(struct cpio_odc_header));
+ __archive_read_consume(a, sizeof(struct cpio_odc_header));
/* Parse out octal fields. */
header = (const struct cpio_odc_header *)h;
@@ -578,16 +569,15 @@ header_bin_le(struct archive_read *a, struct cpio *cpio,
{
const void *h;
const struct cpio_bin_header *header;
- size_t bytes;
a->archive.archive_format = ARCHIVE_FORMAT_CPIO_BIN_LE;
a->archive.archive_format_name = "cpio (little-endian binary)";
/* Read fixed-size portion of header. */
- bytes = (a->decompressor->read_ahead)(a, &h, sizeof(struct cpio_bin_header));
- if (bytes < sizeof(struct cpio_bin_header))
+ h = __archive_read_ahead(a, sizeof(struct cpio_bin_header), NULL);
+ if (h == NULL)
return (ARCHIVE_FATAL);
- (a->decompressor->consume)(a, sizeof(struct cpio_bin_header));
+ __archive_read_consume(a, sizeof(struct cpio_bin_header));
/* Parse out binary fields. */
header = (const struct cpio_bin_header *)h;
@@ -615,17 +605,15 @@ header_bin_be(struct archive_read *a, struct cpio *cpio,
{
const void *h;
const struct cpio_bin_header *header;
- size_t bytes;
a->archive.archive_format = ARCHIVE_FORMAT_CPIO_BIN_BE;
a->archive.archive_format_name = "cpio (big-endian binary)";
/* Read fixed-size portion of header. */
- bytes = (a->decompressor->read_ahead)(a, &h,
- sizeof(struct cpio_bin_header));
- if (bytes < sizeof(struct cpio_bin_header))
+ h = __archive_read_ahead(a, sizeof(struct cpio_bin_header), NULL);
+ if (h == NULL)
return (ARCHIVE_FATAL);
- (a->decompressor->consume)(a, sizeof(struct cpio_bin_header));
+ __archive_read_consume(a, sizeof(struct cpio_bin_header));
/* Parse out binary fields. */
header = (const struct cpio_bin_header *)h;
diff --git a/lib/libarchive/archive_read_support_format_empty.c b/lib/libarchive/archive_read_support_format_empty.c
index 976306c..5850320 100644
--- a/lib/libarchive/archive_read_support_format_empty.c
+++ b/lib/libarchive/archive_read_support_format_empty.c
@@ -57,11 +57,10 @@ archive_read_support_format_empty(struct archive *_a)
static int
archive_read_format_empty_bid(struct archive_read *a)
{
- int bytes_read;
const void *h;
- bytes_read = (a->decompressor->read_ahead)(a, &h, 1);
- if (bytes_read > 0)
+ h = __archive_read_ahead(a, 1, NULL);
+ if (h != NULL)
return (-1);
return (1);
}
diff --git a/lib/libarchive/archive_read_support_format_iso9660.c b/lib/libarchive/archive_read_support_format_iso9660.c
index 6e0da0e..0ec55aa 100644
--- a/lib/libarchive/archive_read_support_format_iso9660.c
+++ b/lib/libarchive/archive_read_support_format_iso9660.c
@@ -288,8 +288,8 @@ archive_read_format_iso9660_bid(struct archive_read *a)
* 8 sectors of the volume descriptor table. Of course,
* if the I/O layer gives us more, we'll take it.
*/
- bytes_read = (a->decompressor->read_ahead)(a, &h, 32768 + 8*2048);
- if (bytes_read < 32768 + 8*2048)
+ h = __archive_read_ahead(a, 32768 + 8*2048, &bytes_read);
+ if (h == NULL)
return (-1);
p = (const unsigned char *)h;
@@ -334,7 +334,6 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
{
struct iso9660 *iso9660;
struct file_info *file;
- ssize_t bytes_read;
int r;
iso9660 = (struct iso9660 *)(a->format->data);
@@ -407,20 +406,18 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
ssize_t step = iso9660->logical_block_size;
if (step > iso9660->entry_bytes_remaining)
step = iso9660->entry_bytes_remaining;
- bytes_read = (a->decompressor->read_ahead)(a, &block, step);
- if (bytes_read < step) {
+ block = __archive_read_ahead(a, step, NULL);
+ if (block == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Failed to read full block when scanning ISO9660 directory list");
release_file(iso9660, file);
return (ARCHIVE_FATAL);
}
- if (bytes_read > step)
- bytes_read = step;
- (a->decompressor->consume)(a, bytes_read);
- iso9660->current_position += bytes_read;
- iso9660->entry_bytes_remaining -= bytes_read;
+ __archive_read_consume(a, step);
+ iso9660->current_position += step;
+ iso9660->entry_bytes_remaining -= step;
for (p = (const unsigned char *)block;
- *p != 0 && p < (const unsigned char *)block + bytes_read;
+ *p != 0 && p < (const unsigned char *)block + step;
p += *p) {
struct file_info *child;
@@ -472,11 +469,11 @@ archive_read_format_iso9660_read_data(struct archive_read *a,
return (ARCHIVE_EOF);
}
- bytes_read = (a->decompressor->read_ahead)(a, buff, 1);
+ *buff = __archive_read_ahead(a, 1, &bytes_read);
if (bytes_read == 0)
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Truncated input file");
- if (bytes_read <= 0)
+ if (buff == NULL)
return (ARCHIVE_FATAL);
if (bytes_read > iso9660->entry_bytes_remaining)
bytes_read = iso9660->entry_bytes_remaining;
@@ -485,7 +482,7 @@ archive_read_format_iso9660_read_data(struct archive_read *a,
iso9660->entry_sparse_offset += bytes_read;
iso9660->entry_bytes_remaining -= bytes_read;
iso9660->current_position += bytes_read;
- (a->decompressor->consume)(a, bytes_read);
+ __archive_read_consume(a, bytes_read);
return (ARCHIVE_OK);
}
@@ -926,7 +923,7 @@ fprintf(stderr, " *** Discarding CE data.\n");
if (iso9660->current_position < offset) {
off_t step = offset - iso9660->current_position;
off_t bytes_read;
- bytes_read = (a->decompressor->skip)(a, step);
+ bytes_read = __archive_read_skip(a, step);
if (bytes_read < 0)
return (bytes_read);
iso9660->current_position = offset;
@@ -940,19 +937,18 @@ fprintf(stderr, " *** Discarding CE data.\n");
if (offset == file->ce_offset) {
const void *p;
ssize_t size = file->ce_size;
- ssize_t bytes_read;
const unsigned char *rr_start;
file->ce_offset = 0;
file->ce_size = 0;
- bytes_read = (a->decompressor->read_ahead)(a, &p, size);
- if (bytes_read > size)
- bytes_read = size;
+ p = __archive_read_ahead(a, size, NULL);
+ if (p == NULL)
+ return (ARCHIVE_FATAL);
rr_start = (const unsigned char *)p;
parse_rockridge(iso9660, file, rr_start,
- rr_start + bytes_read);
- (a->decompressor->consume)(a, bytes_read);
- iso9660->current_position += bytes_read;
+ rr_start + size);
+ __archive_read_consume(a, size);
+ iso9660->current_position += size;
add_entry(iso9660, file);
}
}
diff --git a/lib/libarchive/archive_read_support_format_mtree.c b/lib/libarchive/archive_read_support_format_mtree.c
index a94e488..7617d04 100644
--- a/lib/libarchive/archive_read_support_format_mtree.c
+++ b/lib/libarchive/archive_read_support_format_mtree.c
@@ -187,32 +187,17 @@ cleanup(struct archive_read *a)
static int
mtree_bid(struct archive_read *a)
{
- struct mtree *mtree;
- ssize_t bytes_read;
- const void *h;
const char *signature = "#mtree";
const char *p;
- int bid;
-
- mtree = (struct mtree *)(a->format->data);
/* Now let's look at the actual header and see if it matches. */
- bytes_read = (a->decompressor->read_ahead)(a, &h, strlen(signature));
-
- if (bytes_read <= 0)
- return (bytes_read);
-
- p = h;
- bid = 0;
- while (bytes_read > 0 && *signature != '\0') {
- if (*p != *signature)
- return (bid = 0);
- bid += 8;
- p++;
- signature++;
- bytes_read--;
- }
- return (bid);
+ p = __archive_read_ahead(a, strlen(signature), NULL);
+ if (p == NULL)
+ return (-1);
+
+ if (strncmp(p, signature, strlen(signature)) == 0)
+ return (8 * strlen(signature));
+ return (0);
}
/*
@@ -1239,8 +1224,8 @@ readline(struct archive_read *a, struct mtree *mtree, char **start, ssize_t limi
/* Accumulate line in a line buffer. */
for (;;) {
/* Read some more. */
- bytes_read = (a->decompressor->read_ahead)(a, &t, 1);
- if (bytes_read == 0)
+ t = __archive_read_ahead(a, 1, &bytes_read);
+ if (t == NULL)
return (0);
if (bytes_read < 0)
return (ARCHIVE_FATAL);
@@ -1263,7 +1248,7 @@ readline(struct archive_read *a, struct mtree *mtree, char **start, ssize_t limi
return (ARCHIVE_FATAL);
}
memcpy(mtree->line.s + total_size, t, bytes_read);
- (a->decompressor->consume)(a, bytes_read);
+ __archive_read_consume(a, bytes_read);
total_size += bytes_read;
/* Null terminate. */
mtree->line.s[total_size] = '\0';
diff --git a/lib/libarchive/archive_read_support_format_tar.c b/lib/libarchive/archive_read_support_format_tar.c
index e624a90..ae0c528 100644
--- a/lib/libarchive/archive_read_support_format_tar.c
+++ b/lib/libarchive/archive_read_support_format_tar.c
@@ -294,21 +294,15 @@ static int
archive_read_format_tar_bid(struct archive_read *a)
{
int bid;
- ssize_t bytes_read;
const void *h;
const struct archive_entry_header_ustar *header;
bid = 0;
/* Now let's look at the actual header and see if it matches. */
- if (a->decompressor->read_ahead != NULL)
- bytes_read = (a->decompressor->read_ahead)(a, &h, 512);
- else
- bytes_read = 0; /* Empty file. */
- if (bytes_read < 0)
- return (ARCHIVE_FATAL);
- if (bytes_read < 512)
- return (0);
+ h = __archive_read_ahead(a, 512, NULL);
+ if (h == NULL)
+ return (-1);
/* If it's an end-of-archive mark, we can handle it. */
if ((*(const char *)h) == 0
@@ -479,7 +473,7 @@ archive_read_format_tar_read_data(struct archive_read *a,
/* If we're at end of file, return EOF. */
if (tar->sparse_list == NULL || tar->entry_bytes_remaining == 0) {
- if ((a->decompressor->skip)(a, tar->entry_padding) < 0)
+ if (__archive_read_skip(a, tar->entry_padding) < 0)
return (ARCHIVE_FATAL);
tar->entry_padding = 0;
*buff = NULL;
@@ -488,14 +482,14 @@ archive_read_format_tar_read_data(struct archive_read *a,
return (ARCHIVE_EOF);
}
- bytes_read = (a->decompressor->read_ahead)(a, buff, 1);
- if (bytes_read == 0) {
+ *buff = __archive_read_ahead(a, 1, &bytes_read);
+ if (bytes_read < 0)
+ return (ARCHIVE_FATAL);
+ if (*buff == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Truncated tar archive");
return (ARCHIVE_FATAL);
}
- if (bytes_read < 0)
- return (ARCHIVE_FATAL);
if (bytes_read > tar->entry_bytes_remaining)
bytes_read = tar->entry_bytes_remaining;
/* Don't read more than is available in the
@@ -507,7 +501,7 @@ archive_read_format_tar_read_data(struct archive_read *a,
tar->sparse_list->remaining -= bytes_read;
tar->sparse_list->offset += bytes_read;
tar->entry_bytes_remaining -= bytes_read;
- (a->decompressor->consume)(a, bytes_read);
+ __archive_read_consume(a, bytes_read);
return (ARCHIVE_OK);
}
@@ -524,8 +518,8 @@ archive_read_format_tar_skip(struct archive_read *a)
* length requested or fail, so we can rely upon the entire entry
* plus padding being skipped.
*/
- bytes_skipped = (a->decompressor->skip)(a, tar->entry_bytes_remaining +
- tar->entry_padding);
+ bytes_skipped = __archive_read_skip(a,
+ tar->entry_bytes_remaining + tar->entry_padding);
if (bytes_skipped < 0)
return (ARCHIVE_FATAL);
@@ -552,31 +546,35 @@ tar_read_header(struct archive_read *a, struct tar *tar,
const struct archive_entry_header_ustar *header;
/* Read 512-byte header record */
- bytes = (a->decompressor->read_ahead)(a, &h, 512);
+ h = __archive_read_ahead(a, 512, &bytes);
if (bytes < 0)
return (bytes);
- if (bytes == 0) {
- /*
- * An archive that just ends without a proper
- * end-of-archive marker. Yes, there are tar programs
- * that do this; hold our nose and accept it.
- */
- return (ARCHIVE_EOF);
- }
- if (bytes < 512) {
+ if (bytes < 512) { /* Short read or EOF. */
+ /* Try requesting just one byte and see what happens. */
+ h = __archive_read_ahead(a, 1, &bytes);
+ if (bytes == 0) {
+ /*
+ * The archive ends at a 512-byte boundary but
+ * without a proper end-of-archive marker.
+ * Yes, there are tar writers that do this;
+ * hold our nose and accept it.
+ */
+ return (ARCHIVE_EOF);
+ }
+ /* Archive ends with a partial block; this is bad. */
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated tar archive");
return (ARCHIVE_FATAL);
}
- (a->decompressor->consume)(a, 512);
+ __archive_read_consume(a, 512);
/* Check for end-of-archive mark. */
if (((*(const char *)h)==0) && archive_block_is_null((const unsigned char *)h)) {
/* Try to consume a second all-null record, as well. */
- bytes = (a->decompressor->read_ahead)(a, &h, 512);
- if (bytes > 0)
- (a->decompressor->consume)(a, bytes);
+ h = __archive_read_ahead(a, 512, NULL);
+ if (h != NULL)
+ __archive_read_consume(a, 512);
archive_set_error(&a->archive, 0, NULL);
if (a->archive.archive_format_name == NULL) {
a->archive.archive_format = ARCHIVE_FORMAT_TAR;
@@ -837,10 +835,8 @@ read_body_to_string(struct archive_read *a, struct tar *tar,
struct archive_string *as, const void *h)
{
off_t size, padded_size;
- ssize_t bytes_read, bytes_to_copy;
const struct archive_entry_header_ustar *header;
const void *src;
- char *dest;
(void)tar; /* UNUSED */
header = (const struct archive_entry_header_ustar *)h;
@@ -858,27 +854,14 @@ read_body_to_string(struct archive_read *a, struct tar *tar,
return (ARCHIVE_FATAL);
}
- /* Read the body into the string. */
+ /* Read the body into the string. */
padded_size = (size + 511) & ~ 511;
- dest = as->s;
- while (padded_size > 0) {
- bytes_read = (a->decompressor->read_ahead)(a, &src, padded_size);
- if (bytes_read == 0)
- return (ARCHIVE_EOF);
- if (bytes_read < 0)
- return (ARCHIVE_FATAL);
- if (bytes_read > padded_size)
- bytes_read = padded_size;
- (a->decompressor->consume)(a, bytes_read);
- bytes_to_copy = bytes_read;
- if ((off_t)bytes_to_copy > size)
- bytes_to_copy = (ssize_t)size;
- memcpy(dest, src, bytes_to_copy);
- dest += bytes_to_copy;
- size -= bytes_to_copy;
- padded_size -= bytes_read;
- }
- *dest = '\0';
+ src = __archive_read_ahead(a, padded_size, NULL);
+ if (src == NULL)
+ return (ARCHIVE_FATAL);
+ memcpy(as->s, src, size);
+ __archive_read_consume(a, padded_size);
+ as->s[size] = '\0';
return (ARCHIVE_OK);
}
@@ -1766,7 +1749,7 @@ gnu_sparse_old_read(struct archive_read *a, struct tar *tar,
return (ARCHIVE_OK);
do {
- bytes_read = (a->decompressor->read_ahead)(a, &data, 512);
+ data = __archive_read_ahead(a, 512, &bytes_read);
if (bytes_read < 0)
return (ARCHIVE_FATAL);
if (bytes_read < 512) {
@@ -1775,7 +1758,7 @@ gnu_sparse_old_read(struct archive_read *a, struct tar *tar,
"detected while reading sparse file data");
return (ARCHIVE_FATAL);
}
- (a->decompressor->consume)(a, 512);
+ __archive_read_consume(a, 512);
ext = (const struct extended *)data;
gnu_sparse_old_parse(tar, ext->sparse, 21);
} while (ext->isextended[0] != 0);
@@ -1953,7 +1936,7 @@ gnu_sparse_10_read(struct archive_read *a, struct tar *tar)
/* Skip rest of block... */
bytes_read = tar->entry_bytes_remaining - remaining;
to_skip = 0x1ff & -bytes_read;
- if (to_skip != (a->decompressor->skip)(a, to_skip))
+ if (to_skip != __archive_read_skip(a, to_skip))
return (ARCHIVE_FATAL);
return (bytes_read + to_skip);
}
@@ -2108,7 +2091,7 @@ readline(struct archive_read *a, struct tar *tar, const char **start,
const char *s;
void *p;
- bytes_read = (a->decompressor->read_ahead)(a, &t, 1);
+ t = __archive_read_ahead(a, 1, &bytes_read);
if (bytes_read <= 0)
return (ARCHIVE_FATAL);
s = t; /* Start of line? */
@@ -2122,7 +2105,7 @@ readline(struct archive_read *a, struct tar *tar, const char **start,
"Line too long");
return (ARCHIVE_FATAL);
}
- (a->decompressor->consume)(a, bytes_read);
+ __archive_read_consume(a, bytes_read);
*start = s;
return (bytes_read);
}
@@ -2140,7 +2123,7 @@ readline(struct archive_read *a, struct tar *tar, const char **start,
return (ARCHIVE_FATAL);
}
memcpy(tar->line.s + total_size, t, bytes_read);
- (a->decompressor->consume)(a, bytes_read);
+ __archive_read_consume(a, bytes_read);
total_size += bytes_read;
/* If we found '\n', clean up and return. */
if (p != NULL) {
@@ -2148,7 +2131,7 @@ readline(struct archive_read *a, struct tar *tar, const char **start,
return (total_size);
}
/* Read some more. */
- bytes_read = (a->decompressor->read_ahead)(a, &t, 1);
+ t = __archive_read_ahead(a, 1, &bytes_read);
if (bytes_read <= 0)
return (ARCHIVE_FATAL);
s = t; /* Start of line? */
diff --git a/lib/libarchive/archive_read_support_format_zip.c b/lib/libarchive/archive_read_support_format_zip.c
index 575cd33..a86c533 100644
--- a/lib/libarchive/archive_read_support_format_zip.c
+++ b/lib/libarchive/archive_read_support_format_zip.c
@@ -36,6 +36,10 @@ __FBSDID("$FreeBSD$");
#include <time.h>
#ifdef HAVE_ZLIB_H
#include <zlib.h>
+#else
+/* Hmmm... This is necessary, but means that we can't correctly extract
+ * even uncompressed entries on platforms that lack zlib. */
+#define crc32(crc, buf, len) (unsigned long)0
#endif
#include "archive.h"
@@ -167,9 +171,9 @@ archive_read_format_zip_bid(struct archive_read *a)
{
const char *p;
const void *buff;
- size_t bytes_avail;
+ size_t bytes_avail, offset;
- if ((p = __archive_read_ahead(a, 4)) == NULL)
+ if ((p = __archive_read_ahead(a, 4, NULL)) == NULL)
return (-1);
/*
@@ -189,42 +193,37 @@ archive_read_format_zip_bid(struct archive_read *a)
/*
* Attempt to handle self-extracting archives
* by noting a PE header and searching forward
- * up to 64k for a 'PK\003\004' marker.
+ * up to 128k for a 'PK\003\004' marker.
*/
if (p[0] == 'M' && p[1] == 'Z') {
/*
- * TODO: Additional checks that this really is a PE
- * file before we invoke the 128k lookahead below.
- * No point in allocating a bigger lookahead buffer
- * if we don't need to.
- */
- /*
- * TODO: Of course, the compression layer lookahead
- * buffers aren't dynamically sized yet; they should be.
- */
- bytes_avail = (a->decompressor->read_ahead)(a, &buff, 128*1024);
- p = (const char *)buff;
-
- /*
- * TODO: Optimize by jumping forward based on values
- * in the PE header. Note that we don't need to be
- * exact, but we mustn't skip too far. The search
- * below will compensate if we undershoot. Skipping
- * will also reduce the chance of false positives
- * (which is not really all that high to begin with,
- * so maybe skipping isn't really necessary).
+ * TODO: Optimize by initializing 'offset' to an
+ * estimate of the likely start of the archive data
+ * based on values in the PE header. Note that we
+ * don't need to be exact, but we mustn't skip too
+ * far. The search below will compensate if we
+ * undershoot.
*/
-
- while (p < bytes_avail + (const char *)buff) {
- if (p[0] == 'P' && p[1] == 'K' /* "PK" signature */
- && p[2] == 3 && p[3] == 4 /* File entry */
- && p[8] == 8 /* compression == deflate */
- && p[9] == 0 /* High byte of compression */
- )
- {
- return (30);
+ offset = 0;
+ while (offset < 124000) {
+ /* Get 4k of data beyond where we stopped. */
+ buff = __archive_read_ahead(a, offset + 4096,
+ &bytes_avail);
+ if (bytes_avail < offset + 1)
+ break;
+ p = (const char *)buff + offset;
+ while (p + 9 < (const char *)buff + bytes_avail) {
+ if (p[0] == 'P' && p[1] == 'K' /* signature */
+ && p[2] == 3 && p[3] == 4 /* File entry */
+ && p[8] == 8 /* compression == deflate */
+ && p[9] == 0 /* High byte of compression */
+ )
+ {
+ return (30);
+ }
+ ++p;
}
- ++p;
+ offset = p - (const char *)buff;
}
}
@@ -251,7 +250,7 @@ skip_sfx(struct archive_read *a)
* reduce the chance of a false positive.
*/
for (;;) {
- bytes = (a->decompressor->read_ahead)(a, &h, 4096);
+ h = __archive_read_ahead(a, 4, &bytes);
if (bytes < 4)
return (ARCHIVE_FATAL);
p = h;
@@ -267,7 +266,7 @@ skip_sfx(struct archive_read *a)
/* TODO: Additional verification here. */
if (memcmp("PK\003\004", p, 4) == 0) {
skip = p - (const char *)h;
- (a->decompressor->consume)(a, skip);
+ __archive_read_consume(a, skip);
return (ARCHIVE_OK);
}
p += 4;
@@ -279,7 +278,7 @@ skip_sfx(struct archive_read *a)
}
}
skip = p - (const char *)h;
- (a->decompressor->consume)(a, skip);
+ __archive_read_consume(a, skip);
}
}
@@ -303,7 +302,7 @@ archive_read_format_zip_read_header(struct archive_read *a,
zip->entry_uncompressed_bytes_read = 0;
zip->entry_compressed_bytes_read = 0;
zip->entry_crc32 = crc32(0, NULL, 0);
- if ((h = __archive_read_ahead(a, 4)) == NULL)
+ if ((h = __archive_read_ahead(a, 4, NULL)) == NULL)
return (ARCHIVE_FATAL);
signature = (const char *)h;
@@ -312,7 +311,7 @@ archive_read_format_zip_read_header(struct archive_read *a,
r = skip_sfx(a);
if (r < ARCHIVE_WARN)
return (r);
- if ((h = __archive_read_ahead(a, 4)) == NULL)
+ if ((h = __archive_read_ahead(a, 4, NULL)) == NULL)
return (ARCHIVE_FATAL);
signature = (const char *)h;
}
@@ -329,8 +328,8 @@ archive_read_format_zip_read_header(struct archive_read *a,
* skip the PK00; the first real file header should follow.
*/
if (signature[2] == '0' && signature[3] == '0') {
- (a->decompressor->consume)(a, 4);
- if ((h = __archive_read_ahead(a, 4)) == NULL)
+ __archive_read_consume(a, 4);
+ if ((h = __archive_read_ahead(a, 4, NULL)) == NULL)
return (ARCHIVE_FATAL);
signature = (const char *)h;
if (signature[0] != 'P' || signature[1] != 'K') {
@@ -381,7 +380,7 @@ zip_read_file_header(struct archive_read *a, struct archive_entry *entry,
const struct zip_file_header *p;
const void *h;
- if ((p = __archive_read_ahead(a, sizeof *p)) == NULL) {
+ if ((p = __archive_read_ahead(a, sizeof *p, NULL)) == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP file header");
return (ARCHIVE_FATAL);
@@ -408,11 +407,11 @@ zip_read_file_header(struct archive_read *a, struct archive_entry *entry,
zip->uncompressed_size = archive_le32dec(p->uncompressed_size);
zip->compressed_size = archive_le32dec(p->compressed_size);
- (a->decompressor->consume)(a, sizeof(struct zip_file_header));
+ __archive_read_consume(a, sizeof(struct zip_file_header));
/* Read the filename. */
- if ((h = __archive_read_ahead(a, zip->filename_length)) == NULL) {
+ if ((h = __archive_read_ahead(a, zip->filename_length, NULL)) == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP file header");
return (ARCHIVE_FATAL);
@@ -420,7 +419,7 @@ zip_read_file_header(struct archive_read *a, struct archive_entry *entry,
if (archive_string_ensure(&zip->pathname, zip->filename_length) == NULL)
__archive_errx(1, "Out of memory");
archive_strncpy(&zip->pathname, h, zip->filename_length);
- (a->decompressor->consume)(a, zip->filename_length);
+ __archive_read_consume(a, zip->filename_length);
archive_entry_set_pathname(entry, zip->pathname.s);
if (zip->pathname.s[archive_strlen(&zip->pathname) - 1] == '/')
@@ -429,13 +428,13 @@ zip_read_file_header(struct archive_read *a, struct archive_entry *entry,
zip->mode = AE_IFREG | 0777;
/* Read the extra data. */
- if ((h = __archive_read_ahead(a, zip->extra_length)) == NULL) {
+ if ((h = __archive_read_ahead(a, zip->extra_length, NULL)) == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP file header");
return (ARCHIVE_FATAL);
}
process_extra(h, zip);
- (a->decompressor->consume)(a, zip->extra_length);
+ __archive_read_consume(a, zip->extra_length);
/* Populate some additional entry fields: */
archive_entry_set_mode(entry, zip->mode);
@@ -504,7 +503,7 @@ archive_read_format_zip_read_data(struct archive_read *a,
if (zip->flags & ZIP_LENGTH_AT_END) {
const char *p;
- if ((p = __archive_read_ahead(a, 16)) == NULL) {
+ if ((p = __archive_read_ahead(a, 16, NULL)) == NULL) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP end-of-file record");
@@ -513,7 +512,7 @@ archive_read_format_zip_read_data(struct archive_read *a,
zip->crc32 = archive_le32dec(p + 4);
zip->compressed_size = archive_le32dec(p + 8);
zip->uncompressed_size = archive_le32dec(p + 12);
- (a->decompressor->consume)(a, 16);
+ __archive_read_consume(a, 16);
}
/* Check file size, CRC against these values. */
@@ -622,7 +621,7 @@ zip_read_data_none(struct archive_read *a, const void **buff,
* available bytes; asking for more than that forces the
* decompressor to combine reads by copying data.
*/
- bytes_avail = (a->decompressor->read_ahead)(a, buff, 1);
+ *buff = __archive_read_ahead(a, 1, &bytes_avail);
if (bytes_avail <= 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP file data");
@@ -630,7 +629,7 @@ zip_read_data_none(struct archive_read *a, const void **buff,
}
if (bytes_avail > zip->entry_bytes_remaining)
bytes_avail = zip->entry_bytes_remaining;
- (a->decompressor->consume)(a, bytes_avail);
+ __archive_read_consume(a, bytes_avail);
*size = bytes_avail;
*offset = zip->entry_offset;
zip->entry_offset += *size;
@@ -688,7 +687,7 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,
* available bytes; asking for more than that forces the
* decompressor to combine reads by copying data.
*/
- bytes_avail = (a->decompressor->read_ahead)(a, &compressed_buff, 1);
+ compressed_buff = __archive_read_ahead(a, 1, &bytes_avail);
if (bytes_avail <= 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP file body");
@@ -727,7 +726,7 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,
/* Consume as much as the compressor actually used. */
bytes_avail = zip->stream.total_in;
- (a->decompressor->consume)(a, bytes_avail);
+ __archive_read_consume(a, bytes_avail);
zip->entry_bytes_remaining -= bytes_avail;
zip->entry_compressed_bytes_read += bytes_avail;
@@ -784,7 +783,7 @@ archive_read_format_zip_read_data_skip(struct archive_read *a)
* If the length is at the beginning, we can skip the
* compressed data much more quickly.
*/
- bytes_skipped = (a->decompressor->skip)(a, zip->entry_bytes_remaining);
+ bytes_skipped = __archive_read_skip(a, zip->entry_bytes_remaining);
if (bytes_skipped < 0)
return (ARCHIVE_FATAL);
OpenPOWER on IntegriCloud