a more generic system of stackable stream transforms.
In particular, I believe I've edited every place that called the
decompressor directly to go through new __archive_read_ahead(),
__archive_read_consume() and __archive_read_skip() functions, so
the rest of the work here will not require any changes to the
format handlers.
I've also laid out the new types that will be needed for this.
Next step is to rewrite the decompressors to the new interface,
and overhaul the decompression auction to juggle generic "sources."
Then I'll be able to consolidate reblocking into a single place;
the transforms can emit arbitrary-sized blocks and the current
decompress_none logic will be used to reblock as needed by the
consumer format.
The initial impetus for this was to simplify the decompressors by
consolidating the reblocking logic. I recently came up with
some other transforms I'd like to implement (including new
decompressors, an encryption filter for secure backup, and
uudecode handling to simplify test harnesses) that would also
benefit from this. Eventually, I think I might be able to
standardize the interface for new transforms enough to allow
libarchive clients to register their own transforms complete
with bidding logic (the old interface was too wired into libarchive
internals for the API to be exported). In the very long term,
this might divorce the transformation logic from the rest of
libarchive enough to allow it to be packaged as an independent
library.
SVN-Revision: 234
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 ssize_t
+client_close_proxy(struct archive_read_source *self)
+{
+ int r;
+
+ 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,
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,
* (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;
+ 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) {
}
/* 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;
+ 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;
+
+ source = calloc(1, sizeof(*source));
+ if (source == NULL)
+ return (ARCHIVE_FATAL);
+ source->reader = NULL;
+ source->source = 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;
+ }
/* Select a decompression routine. */
choose_decompressor(a, buffer, (size_t)bytes_read);
* 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;
+ if (a->decompressor->skip2 == NULL)
+ a->decompressor->skip2 = dummy_skip;
return (e);
}
off_t bytes_skipped;
for (bytes_skipped = 0; request > 0;) {
- bytes_read = (a->decompressor->read_ahead)(a, &dummy_buffer, 1);
+ bytes_read = (a->decompressor->read_ahead2)(a, &dummy_buffer, 1);
if (bytes_read < 0)
return (bytes_read);
if (bytes_read == 0) {
}
if (bytes_read > request)
bytes_read = (ssize_t)request;
- (a->decompressor->consume)(a, (size_t)bytes_read);
+ (a->decompressor->consume2)(a, (size_t)bytes_read);
request -= bytes_read;
bytes_skipped += bytes_read;
}
}
/* Close the client stream. */
- if (a->client_closer != NULL) {
- r1 = ((a->client_closer)(&a->archive, a->client_data));
+ if (a->client.closer != NULL) {
+ r1 = ((a->client.closer)(&a->archive, a->client.data));
if (r1 < r)
r = r1;
}
/* used internally to simplify read-ahead */
const void *
-__archive_read_ahead(struct archive_read *a, size_t len)
+__archive_read_ahead(struct archive_read *a, size_t len, size_t *avail)
{
+ ssize_t av;
const void *h;
- if ((a->decompressor->read_ahead)(a, &h, len) < (ssize_t)len)
+ av = (a->decompressor->read_ahead2)(a, &h, len);
+ /* Return # bytes avail (also error code) regardless. */
+ if (avail != NULL && av >= 0)
+ *avail = av;
+ /* If it was a short read, return NULL. */
+ if (av < (ssize_t)len)
return (NULL);
return (h);
}
+
+ssize_t
+__archive_read_consume(struct archive_read *a, size_t s)
+{
+ return (a->decompressor->consume2)(a, s);
+}
+
+int64_t
+__archive_read_skip(struct archive_read *a, uint64_t s)
+{
+ return (a->decompressor->skip2)(a, s);
+}
#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)(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_read_source *source, const void *, size_t);
+ /* Release the reader and any configuration data it allocated. */
+ void (*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 *source; /* 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;
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;
int (*init)(struct archive_read *,
const void *buff, size_t);
int (*finish)(struct archive_read *);
- ssize_t (*read_ahead)(struct archive_read *,
+ ssize_t (*read_ahead2)(struct archive_read *,
const void **, size_t);
- ssize_t (*consume)(struct archive_read *, size_t);
- off_t (*skip)(struct archive_read *, off_t);
+ ssize_t (*consume2)(struct archive_read *, size_t);
+ off_t (*skip2)(struct archive_read *, off_t);
} decompressors[5];
/* Pointer to current decompressor. */
*__archive_read_register_compression(struct archive_read *a,
int (*bid)(const void *, size_t),
int (*init)(struct archive_read *, const void *, size_t));
-
const void
- *__archive_read_ahead(struct archive_read *, size_t);
-
+ *__archive_read_ahead(struct archive_read *, size_t, size_t *);
+ssize_t
+ __archive_read_consume(struct archive_read *, size_t);
+int64_t
+ __archive_read_skip(struct archive_read *, uint64_t);
#endif
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->read_ahead2 = read_ahead;
+ a->decompressor->consume2 = read_consume;
+ a->decompressor->skip2 = NULL; /* not supported */
a->decompressor->finish = finish;
/* Initialize compression library. */
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) {
for (;;) {
if (state->stream.avail_in == 0) {
read_buf = state->stream.next_in;
- ret = (a->client_reader)(&a->archive, a->client_data,
- &read_buf);
+ ret = (a->source->read)(a->source, &read_buf);
state->stream.next_in = (void *)(uintptr_t)read_buf;
if (ret < 0) {
/*
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->read_ahead2 = read_ahead;
+ a->decompressor->consume2 = read_consume;
+ a->decompressor->skip2 = NULL; /* not supported */
a->decompressor->finish = finish;
state = (struct private_data *)malloc(sizeof(*state));
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) {
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 = (a->source->read)(a->source, &read_buf);
state->next_in = read_buf;
if (ret < 0)
return (ARCHIVE_FATAL);
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->read_ahead2 = read_ahead;
+ a->decompressor->consume2 = read_consume;
+ a->decompressor->skip2 = NULL; /* not supported */
a->decompressor->finish = finish;
/*
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) {
for (;;) {
if (state->stream.avail_in == 0) {
read_buf = state->stream.next_in;
- ret = (a->client_reader)(&a->archive, a->client_data,
- &read_buf);
+ ret = (a->source->read)(a->source, &read_buf);
state->stream.next_in = (unsigned char *)(uintptr_t)read_buf;
if (ret < 0) {
/*
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->read_ahead2 = archive_decompressor_none_read_ahead;
+ a->decompressor->consume2 = archive_decompressor_none_read_consume;
+ a->decompressor->skip2 = archive_decompressor_none_skip;
a->decompressor->finish = archive_decompressor_none_finish;
return (ARCHIVE_OK);
/* TODO: Change this to return(0) consistent
* with new eof handling commented below. */
}
- bytes_read = (a->client_reader)(&a->archive,
- a->client_data, &state->client_buff);
+ bytes_read = (a->source->read)(a->source,
+ &state->client_buff);
if (bytes_read < 0) { /* Read error. */
state->client_total = state->client_avail = 0;
state->client_next = state->client_buff = NULL;
* If a client_skipper was provided, try that first.
*/
#if ARCHIVE_API_VERSION < 2
- if ((a->client_skipper != NULL) && (request < SSIZE_MAX)) {
+ if ((a->source->skip != NULL) && (request < SSIZE_MAX)) {
#else
- if (a->client_skipper != NULL) {
+ if (a->source->skip != NULL) {
#endif
- bytes_skipped = (a->client_skipper)(&a->archive,
- a->client_data, request);
+ bytes_skipped = (a->source->skip)(a->source, request);
if (bytes_skipped < 0) { /* error */
state->client_total = state->client_avail = 0;
state->client_next = state->client_buff = NULL;
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 = (a->source->read)(a->source, &child_buf);
state->child_in_buf = (const char *)child_buf;
if (ret < 0) {
}
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->read_ahead2 = archive_decompressor_program_read_ahead;
+ a->decompressor->consume2 = archive_decompressor_program_read_consume;
+ a->decompressor->skip2 = NULL;
a->decompressor->finish = archive_decompressor_program_finish;
/* XXX Check that we can read at least one byte? */
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 &&
* 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);
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;
* 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. */
}
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);
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);
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");
*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;
{
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);
static int
archive_read_format_cpio_bid(struct archive_read *a)
{
- int bytes_read;
const void *h;
const unsigned char *p;
struct cpio *cpio;
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;
struct archive_entry *entry)
{
struct cpio *cpio;
- size_t bytes;
const void *h;
size_t namelength;
size_t name_pad;
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);
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)
*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;
size_t skip, bytes, skipped = 0;
for (;;) {
- 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), &bytes);
+ if (h == NULL)
return (ARCHIVE_FATAL);
p = h;
q = p + bytes;
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,
}
}
skip = p - (const char *)h;
- (a->decompressor->consume)(a, skip);
+ __archive_read_consume(a, skip);
skipped += skip;
}
}
{
const void *h;
const struct cpio_newc_header *header;
- size_t bytes;
int r;
r = find_newc_header(a);
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;
size_t skip, bytes, skipped = 0;
for (;;) {
- 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), &bytes);
+ if (h == NULL)
return (ARCHIVE_FATAL);
p = h;
q = p + bytes;
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,
}
}
skip = p - (const char *)h;
- (a->decompressor->consume)(a, skip);
+ __archive_read_consume(a, skip);
skipped += skip;
}
}
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";
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;
{
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;
{
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;
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);
}
* 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;
{
struct iso9660 *iso9660;
struct file_info *file;
- ssize_t bytes_read;
int r;
iso9660 = (struct iso9660 *)(a->format->data);
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;
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;
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);
}
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;
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);
}
}
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);
}
/*
/* 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);
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';
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
/* 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;
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
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);
}
* 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);
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 < 512) { /* Short read or EOF. */
/* Try requesting just one byte and see what happens. */
- bytes = (a->decompressor->read_ahead)(a, &h, 1);
+ h = __archive_read_ahead(a, 1, &bytes);
if (bytes == 0) {
/*
* The archive ends at a 512-byte boundary but
"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;
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;
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);
}
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) {
"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);
/* 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);
}
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? */
"Line too long");
return (ARCHIVE_FATAL);
}
- (a->decompressor->consume)(a, bytes_read);
+ __archive_read_consume(a, bytes_read);
*start = s;
return (bytes_read);
}
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) {
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? */
const void *buff;
size_t bytes_avail, offset;
- if ((p = __archive_read_ahead(a, 4)) == NULL)
+ if ((p = __archive_read_ahead(a, 4, NULL)) == NULL)
return (-1);
/*
offset = 0;
while (offset < 124000) {
/* Get 4k of data beyond where we stopped. */
- bytes_avail = (a->decompressor->read_ahead)(a, &buff,
- offset + 4096);
+ buff = __archive_read_ahead(a, offset + 4096,
+ &bytes_avail);
if (bytes_avail < offset + 1)
break;
p = (const char *)buff + offset;
* reduce the chance of a false positive.
*/
for (;;) {
- bytes = (a->decompressor->read_ahead)(a, &h, 4);
+ h = __archive_read_ahead(a, 4, &bytes);
if (bytes < 4)
return (ARCHIVE_FATAL);
p = h;
/* 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;
}
}
skip = p - (const char *)h;
- (a->decompressor->consume)(a, skip);
+ __archive_read_consume(a, skip);
}
}
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;
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;
}
* 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') {
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);
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);
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] == '/')
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);
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");
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. */
* 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");
}
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;
* 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");
/* 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;
* 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);