Fixes from Joerg Sonnenberger, reviewed by Kai Wang.

This commit is contained in:
Tim Kientzle 2007-04-14 08:30:21 +00:00
parent 015f35775b
commit 22ff6c7af3
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=168707

View file

@ -45,11 +45,11 @@ __FBSDID("$FreeBSD$");
struct ar {
int bid;
int has_strtab;
off_t entry_bytes_remaining;
off_t entry_offset;
off_t entry_padding;
char *strtab;
size_t strtab_size;
};
/*
@ -92,7 +92,7 @@ static int archive_read_format_ar_read_header(struct archive_read *a,
static int64_t ar_atol8(const char *p, unsigned char_cnt);
static int64_t ar_atol10(const char *p, unsigned char_cnt);
static int ar_parse_string_table(struct archive_read *, struct ar *,
const void *, ssize_t);
const void *, size_t);
/*
* ANSI C99 defines constants for these, but not everyone supports
@ -131,6 +131,7 @@ archive_read_support_format_ar(struct archive *_a)
}
memset(ar, 0, sizeof(*ar));
ar->bid = -1;
ar->strtab = NULL;
r = __archive_read_register_format(a,
ar,
@ -153,8 +154,7 @@ archive_read_format_ar_cleanup(struct archive_read *a)
struct ar *ar;
ar = (struct ar *)*(a->pformat_data);
if (ar->has_strtab > 0)
free(ar->strtab);
free(ar->strtab);
free(ar);
*(a->pformat_data) = NULL;
return (ARCHIVE_OK);
@ -196,9 +196,11 @@ static int
archive_read_format_ar_read_header(struct archive_read *a,
struct archive_entry *entry)
{
int r, bsd_append;
int r;
size_t bsd_append;
ssize_t bytes;
int64_t nval;
size_t tab_size;
char *fname, *p;
struct ar *ar;
const void *b;
@ -247,22 +249,29 @@ archive_read_format_ar_read_header(struct archive_read *a,
* string table.
*/
nval = ar_atol10(h + AR_size_offset, AR_size_size);
bytes = (a->compression_read_ahead)(a, &b, nval);
if (nval < 0 || nval > SIZE_MAX) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"String table too large");
return (ARCHIVE_FATAL);
}
tab_size = (size_t)nval;
bytes = (a->compression_read_ahead)(a, &b, tab_size);
if (bytes <= 0)
return (ARCHIVE_FATAL);
if (bytes < nval) {
if (bytes < tab_size) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Truncated input file");
return (ARCHIVE_FATAL);
}
r = ar_parse_string_table(a, ar, b, nval);
r = ar_parse_string_table(a, ar, b, tab_size);
if (r == ARCHIVE_OK) {
/*
* Archive string table only have ar_name and ar_size fileds
* in its header.
*/
archive_entry_copy_pathname(entry, "//");
h = (const char *)b;
nval = ar_atol10(h + AR_size_offset, AR_size_size);
archive_entry_set_size(entry, nval);
@ -279,15 +288,19 @@ archive_read_format_ar_read_header(struct archive_read *a,
* "/" followed by one or more digit(s) in the ar_name
* filed indicates an index to the string table.
*/
if (ar->has_strtab > 0) {
nval = ar_atol10(h + AR_name_offset + 1,
AR_name_size - 1);
archive_entry_copy_pathname(entry, &ar->strtab[nval]);
} else {
if (ar->strtab == NULL) {
archive_set_error(&a->archive, EINVAL,
"String table does not exist");
return (ARCHIVE_WARN);
}
nval = ar_atol10(h + AR_name_offset + 1, AR_name_size - 1);
if (nval < 0 || nval > ar->strtab_size) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"String table overflow");
return (ARCHIVE_FATAL);
}
archive_entry_copy_pathname(entry, &ar->strtab[(size_t)nval]);
goto remain;
}
@ -300,7 +313,13 @@ archive_read_format_ar_read_header(struct archive_read *a,
*/
nval = ar_atol10(h + AR_name_offset + SAR_EFMT1,
AR_name_size - SAR_EFMT1);
bytes = (a->compression_read_ahead)(a, &b, nval);
if (nval < 0 || nval >= SIZE_MAX) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Bad input file size");
return (ARCHIVE_FATAL);
}
bsd_append = (size_t)nval;
bytes = (a->compression_read_ahead)(a, &b, bsd_append);
if (bytes <= 0)
return (ARCHIVE_FATAL);
if (bytes < nval) {
@ -309,21 +328,20 @@ archive_read_format_ar_read_header(struct archive_read *a,
return (ARCHIVE_FATAL);
}
(a->compression_read_consume)(a, nval);
(a->compression_read_consume)(a, bsd_append);
fname = (char *)malloc(nval + 1);
fname = (char *)malloc(bsd_append + 1);
if (fname == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate fname buffer");
return (ARCHIVE_FATAL);
}
strncpy(fname, b, nval);
fname[nval] = '\0';
strncpy(fname, b, bsd_append);
fname[bsd_append] = '\0';
archive_entry_copy_pathname(entry, fname);
free(fname);
fname = NULL;
bsd_append = nval;
goto remain;
}
@ -373,13 +391,13 @@ archive_read_format_ar_read_header(struct archive_read *a,
remain:
/* Copy remaining header */
archive_entry_set_mtime(entry,
ar_atol10(h + AR_date_offset, AR_date_size), 0);
(time_t)ar_atol10(h + AR_date_offset, AR_date_size), 0L);
archive_entry_set_uid(entry,
ar_atol10(h + AR_uid_offset, AR_uid_size));
(uid_t)ar_atol10(h + AR_uid_offset, AR_uid_size));
archive_entry_set_gid(entry,
ar_atol10(h + AR_gid_offset, AR_gid_size));
(gid_t)ar_atol10(h + AR_gid_offset, AR_gid_size));
archive_entry_set_mode(entry,
ar_atol8(h + AR_mode_offset, AR_mode_size));
(mode_t)ar_atol8(h + AR_mode_offset, AR_mode_size));
nval = ar_atol10(h + AR_size_offset, AR_size_size);
ar->entry_offset = 0;
@ -391,6 +409,11 @@ archive_read_format_ar_read_header(struct archive_read *a,
* real file size. But remember we should do this only
* after we had calculated the padding.
*/
if (bsd_append > nval) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Truncated input file");
return (ARCHIVE_FATAL);
}
if (bsd_append > 0)
nval -= bsd_append;
@ -418,13 +441,14 @@ archive_read_format_ar_read_data(struct archive_read *a,
}
if (bytes_read < 0)
return (ARCHIVE_FATAL);
/* XXX I don't get this. */
if (bytes_read > ar->entry_bytes_remaining)
bytes_read = ar->entry_bytes_remaining;
bytes_read = (ssize_t)ar->entry_bytes_remaining;
*size = bytes_read;
*offset = ar->entry_offset;
ar->entry_offset += bytes_read;
ar->entry_bytes_remaining -= bytes_read;
(a->compression_read_consume)(a, bytes_read);
(a->compression_read_consume)(a, (size_t)bytes_read);
return (ARCHIVE_OK);
} else {
while (ar->entry_padding > 0) {
@ -432,8 +456,8 @@ archive_read_format_ar_read_data(struct archive_read *a,
if (bytes_read <= 0)
return (ARCHIVE_FATAL);
if (bytes_read > ar->entry_padding)
bytes_read = ar->entry_padding;
(a->compression_read_consume)(a, bytes_read);
bytes_read = (ssize_t)ar->entry_padding;
(a->compression_read_consume)(a, (size_t)bytes_read);
ar->entry_padding -= bytes_read;
}
*buff = NULL;
@ -473,17 +497,23 @@ archive_read_format_ar_skip(struct archive_read *a)
static int
ar_parse_string_table(struct archive_read *a, struct ar *ar,
const void *h, ssize_t size)
const void *h, size_t size)
{
char *p;
if (ar->has_strtab > 0) {
if (ar->strtab != NULL) {
archive_set_error(&a->archive, EINVAL,
"More than one string tables exist");
return (ARCHIVE_WARN);
}
ar->strtab = (char *)malloc(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");
@ -491,35 +521,33 @@ ar_parse_string_table(struct archive_read *a, struct ar *ar,
}
(void)memcpy(ar->strtab, h, size);
p = ar->strtab;
while (p < ar->strtab + size - 1) {
for (p = ar->strtab; p < ar->strtab + size - 1; ++p) {
if (*p == '/') {
*p++ = '\0';
if (*p == '\n')
*p++ = '\0';
else {
archive_set_error(&a->archive, EINVAL,
"Invalid string table");
free(ar->strtab);
return (ARCHIVE_WARN);
}
} else
p++;
if (*p != '\n')
goto bad_string_table;
*p = '\0';
}
}
/*
* Sanity check, last two chars must be `/\n' or '\n\n',
* depending on whether the string table is padded by a '\n'
* (string table produced by GNU ar always has a even size).
*/
if (p != ar->strtab + size && *p != '\n') {
archive_set_error(&a->archive, EINVAL,
"Invalid string table");
free(ar->strtab);
return (ARCHIVE_WARN);
}
if (p != ar->strtab + size && *p != '\n')
goto bad_string_table;
/* Enforce zero termination. */
ar->strtab[size - 1] = '\0';
ar->has_strtab = 1;
return (ARCHIVE_OK);
bad_string_table:
archive_set_error(&a->archive, EINVAL,
"Invalid string table");
free(ar->strtab);
ar->strtab = NULL;
return (ARCHIVE_WARN);
}
static int64_t
@ -553,6 +581,10 @@ ar_atol8(const char *p, unsigned char_cnt)
return (sign < 0) ? -l : l;
}
/*
* XXX This is not really correct for negative numbers,
* as min_int64_t can never be returned. That one is unused BTW.
*/
static int64_t
ar_atol10(const char *p, unsigned char_cnt)
{