diff options
Diffstat (limited to 'contrib/libarchive/libarchive/archive_read_support_format_ar.c')
-rw-r--r-- | contrib/libarchive/libarchive/archive_read_support_format_ar.c | 143 |
1 files changed, 92 insertions, 51 deletions
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_ar.c b/contrib/libarchive/libarchive/archive_read_support_format_ar.c index 8b95f22..7a5f790 100644 --- a/contrib/libarchive/libarchive/archive_read_support_format_ar.c +++ b/contrib/libarchive/libarchive/archive_read_support_format_ar.c @@ -50,11 +50,17 @@ __FBSDID("$FreeBSD$"); #include "archive_read_private.h" struct ar { - off_t entry_bytes_remaining; - off_t entry_offset; - off_t entry_padding; + int64_t entry_bytes_remaining; + /* unconsumed is purely to track data we've gotten from readahead, + * but haven't yet marked as consumed. Must be paired with + * entry_bytes_remaining usage/modification. + */ + size_t entry_bytes_unconsumed; + int64_t entry_offset; + int64_t entry_padding; char *strtab; size_t strtab_size; + char read_global_header; }; /* @@ -75,10 +81,10 @@ struct ar { #define AR_fmag_offset 58 #define AR_fmag_size 2 -static int archive_read_format_ar_bid(struct archive_read *a); +static int archive_read_format_ar_bid(struct archive_read *a, int); static int archive_read_format_ar_cleanup(struct archive_read *a); static int archive_read_format_ar_read_data(struct archive_read *a, - const void **buff, size_t *size, off_t *offset); + const void **buff, size_t *size, int64_t *offset); static int archive_read_format_ar_skip(struct archive_read *a); static int archive_read_format_ar_read_header(struct archive_read *a, struct archive_entry *e); @@ -95,6 +101,9 @@ archive_read_support_format_ar(struct archive *_a) struct ar *ar; int r; + archive_check_magic(_a, ARCHIVE_READ_MAGIC, + ARCHIVE_STATE_NEW, "archive_read_support_format_ar"); + ar = (struct ar *)malloc(sizeof(*ar)); if (ar == NULL) { archive_set_error(&a->archive, ENOMEM, @@ -135,14 +144,11 @@ archive_read_format_ar_cleanup(struct archive_read *a) } static int -archive_read_format_ar_bid(struct archive_read *a) +archive_read_format_ar_bid(struct archive_read *a, int best_bid) { const void *h; - if (a->archive.archive_format != 0 && - (a->archive.archive_format & ARCHIVE_FORMAT_BASE_MASK) != - ARCHIVE_FORMAT_AR) - return(0); + (void)best_bid; /* UNUSED */ /* * Verify the 8-byte file signature. @@ -150,45 +156,23 @@ archive_read_format_ar_bid(struct archive_read *a) */ if ((h = __archive_read_ahead(a, 8, NULL)) == NULL) return (-1); - if (strncmp((const char*)h, "!<arch>\n", 8) == 0) { + if (memcmp(h, "!<arch>\n", 8) == 0) { return (64); } return (-1); } static int -archive_read_format_ar_read_header(struct archive_read *a, - struct archive_entry *entry) +_ar_read_header(struct archive_read *a, struct archive_entry *entry, + struct ar *ar, const char *h, size_t *unconsumed) { char filename[AR_name_size + 1]; - struct ar *ar; uint64_t number; /* Used to hold parsed numbers before validation. */ - ssize_t bytes_read; size_t bsd_name_length, entry_size; char *p, *st; const void *b; - const char *h; int r; - ar = (struct ar*)(a->format->data); - - if (a->archive.file_position == 0) { - /* - * We are now at the beginning of the archive, - * so we need first consume the ar global header. - */ - __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. */ - if ((b = __archive_read_ahead(a, 60, &bytes_read)) == NULL) - /* Broken header. */ - return (ARCHIVE_EOF); - __archive_read_consume(a, 60); - h = (const char *)b; - /* Verify the magic signature on the file header. */ if (strncmp(h + AR_fmag_offset, "`\n", 2) != 0) { archive_set_error(&a->archive, EINVAL, @@ -292,6 +276,12 @@ archive_read_format_ar_read_header(struct archive_read *a, } ar->strtab = st; ar->strtab_size = entry_size; + + if (*unconsumed) { + __archive_read_consume(a, *unconsumed); + *unconsumed = 0; + } + if ((b = __archive_read_ahead(a, entry_size, NULL)) == NULL) return (ARCHIVE_FATAL); memcpy(st, b, entry_size); @@ -347,7 +337,7 @@ archive_read_format_ar_read_header(struct archive_read *a, * overflowing a size_t and against the filename size * being larger than the entire entry. */ if (number > (uint64_t)(bsd_name_length + 1) - || (off_t)bsd_name_length > ar->entry_bytes_remaining) { + || (int64_t)bsd_name_length > ar->entry_bytes_remaining) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Bad input file size"); return (ARCHIVE_FATAL); @@ -356,14 +346,17 @@ archive_read_format_ar_read_header(struct archive_read *a, /* Adjust file size reported to client. */ archive_entry_set_size(entry, ar->entry_bytes_remaining); + if (*unconsumed) { + __archive_read_consume(a, *unconsumed); + *unconsumed = 0; + } + /* Read the long name into memory. */ 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); } - __archive_read_consume(a, bsd_name_length); - /* Store it in the entry. */ p = (char *)malloc(bsd_name_length + 1); if (p == NULL) { @@ -373,6 +366,9 @@ archive_read_format_ar_read_header(struct archive_read *a, } strncpy(p, b, bsd_name_length); p[bsd_name_length] = '\0'; + + __archive_read_consume(a, bsd_name_length); + archive_entry_copy_pathname(entry, p); free(p); return (ARCHIVE_OK); @@ -409,6 +405,42 @@ archive_read_format_ar_read_header(struct archive_read *a, } static int +archive_read_format_ar_read_header(struct archive_read *a, + struct archive_entry *entry) +{ + struct ar *ar = (struct ar*)(a->format->data); + size_t unconsumed; + const void *header_data; + int ret; + + if (!ar->read_global_header) { + /* + * We are now at the beginning of the archive, + * so we need first consume the ar global header. + */ + __archive_read_consume(a, 8); + ar->read_global_header = 1; + /* Set a default format code for now. */ + a->archive.archive_format = ARCHIVE_FORMAT_AR; + } + + /* Read the header for the next file entry. */ + if ((header_data = __archive_read_ahead(a, 60, NULL)) == NULL) + /* Broken header. */ + return (ARCHIVE_EOF); + + unconsumed = 60; + + ret = _ar_read_header(a, entry, ar, (const char *)header_data, &unconsumed); + + if (unconsumed) + __archive_read_consume(a, unconsumed); + + return ret; +} + + +static int ar_parse_common_header(struct ar *ar, struct archive_entry *entry, const char *h) { @@ -434,13 +466,18 @@ ar_parse_common_header(struct ar *ar, struct archive_entry *entry, static int archive_read_format_ar_read_data(struct archive_read *a, - const void **buff, size_t *size, off_t *offset) + const void **buff, size_t *size, int64_t *offset) { ssize_t bytes_read; struct ar *ar; ar = (struct ar *)(a->format->data); + if (ar->entry_bytes_unconsumed) { + __archive_read_consume(a, ar->entry_bytes_unconsumed); + ar->entry_bytes_unconsumed = 0; + } + if (ar->entry_bytes_remaining > 0) { *buff = __archive_read_ahead(a, 1, &bytes_read); if (bytes_read == 0) { @@ -453,20 +490,22 @@ archive_read_format_ar_read_data(struct archive_read *a, if (bytes_read > ar->entry_bytes_remaining) bytes_read = (ssize_t)ar->entry_bytes_remaining; *size = bytes_read; + ar->entry_bytes_unconsumed = bytes_read; *offset = ar->entry_offset; ar->entry_offset += bytes_read; ar->entry_bytes_remaining -= bytes_read; - __archive_read_consume(a, (size_t)bytes_read); return (ARCHIVE_OK); } else { - while (ar->entry_padding > 0) { - *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; - __archive_read_consume(a, (size_t)bytes_read); - ar->entry_padding -= bytes_read; + int64_t skipped = __archive_read_consume(a, ar->entry_padding); + if (skipped >= 0) { + ar->entry_padding -= skipped; + } + if (ar->entry_padding) { + if (skipped >= 0) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "Truncated ar archive- failed consuming padding"); + } + return (ARCHIVE_FATAL); } *buff = NULL; *size = 0; @@ -478,17 +517,19 @@ archive_read_format_ar_read_data(struct archive_read *a, static int archive_read_format_ar_skip(struct archive_read *a) { - off_t bytes_skipped; + int64_t bytes_skipped; struct ar* ar; ar = (struct ar *)(a->format->data); - bytes_skipped = __archive_read_skip(a, - ar->entry_bytes_remaining + ar->entry_padding); + bytes_skipped = __archive_read_consume(a, + ar->entry_bytes_remaining + ar->entry_padding + + ar->entry_bytes_unconsumed); if (bytes_skipped < 0) return (ARCHIVE_FATAL); ar->entry_bytes_remaining = 0; + ar->entry_bytes_unconsumed = 0; ar->entry_padding = 0; return (ARCHIVE_OK); |