Current 'ar' read support in libarchive can only handle a GNU/SVR4
filename table whose size is less than 65536 bytes. The original intention was to not consume the filename table, so the client will have a chance to look at it. To achieve that, the library call decompressor->read_ahead to read(look ahead) but do not call decompressor->consume to consume the data, thus a limit was raised since read_ahead call can only look ahead at most BUFFER_SIZE(65536) bytes at the moment, and you can not "look any further" before you consume what you already "saw". This commit will turn GNU/SVR4 filename table into "archive format data", i.e., filename table will be consumed by libarchive, so the 65536-bytes limit will be gone, but client can no longer have access to the content of filename table. 'ar' support test suite is changed accordingly. BSD ar(1) is not affected by this change since it doesn't look at the filename table. Reported by: erwin Discussed with: jkoshy, kientzle Reviewed by: jkoshy, kientzle Approved by: jkoshy(mentor), kientzle
This commit is contained in:
parent
e249f70262
commit
a739eb8374
@ -83,8 +83,7 @@ static int archive_read_format_ar_read_header(struct archive_read *a,
|
||||
struct archive_entry *e);
|
||||
static uint64_t ar_atol8(const char *p, unsigned char_cnt);
|
||||
static uint64_t ar_atol10(const char *p, unsigned char_cnt);
|
||||
static int ar_parse_gnu_filename_table(struct archive_read *, struct ar *,
|
||||
const void *, size_t);
|
||||
static int ar_parse_gnu_filename_table(struct archive_read *a);
|
||||
static int ar_parse_common_header(struct ar *ar, struct archive_entry *,
|
||||
const char *h);
|
||||
|
||||
@ -167,8 +166,8 @@ 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;
|
||||
char *p;
|
||||
size_t bsd_name_length, entry_size, s;
|
||||
char *p, *st;
|
||||
const void *b;
|
||||
const char *h;
|
||||
int r;
|
||||
@ -277,22 +276,42 @@ archive_read_format_ar_read_header(struct archive_read *a,
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
entry_size = (size_t)number;
|
||||
if (entry_size == 0) {
|
||||
archive_set_error(&a->archive, EINVAL,
|
||||
"Invalid string table");
|
||||
return (ARCHIVE_WARN);
|
||||
}
|
||||
if (ar->strtab != NULL) {
|
||||
archive_set_error(&a->archive, EINVAL,
|
||||
"More than one string tables exist");
|
||||
return (ARCHIVE_WARN);
|
||||
}
|
||||
|
||||
/* Read the filename table into memory. */
|
||||
bytes_read = (a->decompressor->read_ahead)(a, &b, entry_size);
|
||||
if (bytes_read <= 0)
|
||||
return (ARCHIVE_FATAL);
|
||||
if ((size_t)bytes_read < entry_size) {
|
||||
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
|
||||
"Truncated input file");
|
||||
st = malloc(entry_size);
|
||||
if (st == NULL) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Can't allocate filename table buffer");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
/*
|
||||
* Don't consume the contents, so the client will
|
||||
* also get a shot at reading it.
|
||||
*/
|
||||
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);
|
||||
}
|
||||
/* All contents are consumed. */
|
||||
ar->entry_bytes_remaining = 0;
|
||||
archive_entry_set_size(entry, ar->entry_bytes_remaining);
|
||||
|
||||
/* Parse the filename table. */
|
||||
return (ar_parse_gnu_filename_table(a, ar, b, entry_size));
|
||||
return (ar_parse_gnu_filename_table(a));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -492,31 +511,15 @@ archive_read_format_ar_skip(struct archive_read *a)
|
||||
}
|
||||
|
||||
static int
|
||||
ar_parse_gnu_filename_table(struct archive_read *a, struct ar *ar,
|
||||
const void *h, size_t size)
|
||||
ar_parse_gnu_filename_table(struct archive_read *a)
|
||||
{
|
||||
struct ar *ar;
|
||||
char *p;
|
||||
size_t size;
|
||||
|
||||
if (ar->strtab != NULL) {
|
||||
archive_set_error(&a->archive, EINVAL,
|
||||
"More than one string tables exist");
|
||||
return (ARCHIVE_WARN);
|
||||
}
|
||||
ar = (struct ar*)(a->format->data);
|
||||
size = ar->strtab_size;
|
||||
|
||||
if (size == 0) {
|
||||
archive_set_error(&a->archive, EINVAL, "Invalid string table");
|
||||
return (ARCHIVE_WARN);
|
||||
}
|
||||
|
||||
ar->strtab_size = size;
|
||||
ar->strtab = malloc(size);
|
||||
if (ar->strtab == NULL) {
|
||||
archive_set_error(&a->archive, ENOMEM,
|
||||
"Can't allocate string table buffer");
|
||||
return (ARCHIVE_FATAL);
|
||||
}
|
||||
|
||||
(void)memcpy(ar->strtab, h, size);
|
||||
for (p = ar->strtab; p < ar->strtab + size - 1; ++p) {
|
||||
if (*p == '/') {
|
||||
*p++ = '\0';
|
||||
|
@ -75,9 +75,7 @@ DEFINE_TEST(test_read_format_ar)
|
||||
assertEqualInt(0, archive_entry_mtime(ae));
|
||||
assertEqualInt(0, archive_entry_uid(ae));
|
||||
assertEqualInt(0, archive_entry_gid(ae));
|
||||
assertEqualInt(40, archive_entry_size(ae));
|
||||
assertEqualIntA(a, 40, archive_read_data(a, buff, 50));
|
||||
assert(0 == memcmp(buff, "yyytttsssaaafff.o/\nhhhhjjjjkkkkllll.o/\n\n", 40));
|
||||
assertEqualInt(0, archive_entry_size(ae));
|
||||
|
||||
/* First Entry */
|
||||
assertA(0 == archive_read_next_header(a, &ae));
|
||||
|
@ -119,9 +119,7 @@ DEFINE_TEST(test_write_format_ar)
|
||||
assertA(0 == archive_read_next_header(a, &ae));
|
||||
assertEqualInt(0, archive_entry_mtime(ae));
|
||||
assertEqualString("//", archive_entry_pathname(ae));
|
||||
assertEqualInt(strlen(strtab), archive_entry_size(ae));
|
||||
assertEqualIntA(a, strlen(strtab), archive_read_data(a, buff2, 100));
|
||||
assert(0 == memcmp(buff2, strtab, strlen(strtab)));
|
||||
assertEqualInt(0, archive_entry_size(ae));
|
||||
|
||||
assertA(0 == archive_read_next_header(a, &ae));
|
||||
assert(1 == archive_entry_mtime(ae));
|
||||
|
Loading…
x
Reference in New Issue
Block a user