summaryrefslogtreecommitdiffstats
path: root/contrib/libarchive/libarchive/archive_read_support_format_ar.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/libarchive/libarchive/archive_read_support_format_ar.c')
-rw-r--r--contrib/libarchive/libarchive/archive_read_support_format_ar.c143
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);
OpenPOWER on IntegriCloud