From 7a4f3ab2c487bbe3fea2959e9137423f5283579e Mon Sep 17 00:00:00 2001 From: Tim Kientzle Date: Fri, 4 Jun 2004 23:24:21 +0000 Subject: [PATCH] Correct the layering violation in read_body_to_string. The previous version called the higher-level archive_read_data and archive_read_data_skip functions, which screwed up state management of those functions. This bit of mis-design has existed for a long time, but became a serious issue with the recent changes to the archive_read_data APIs, which added more internal state to the high-level archive_read_data function. Most common symptom was a failure to correctly read 'L' entries (long filename) from GNU-style archives, causing the message ": Can't open: No such file or directory" with an empty filename. Pointed out by: Numerous port build failures Thanks to: Kris Kennaway --- .../archive_read_support_format_tar.c | 41 +++++++++++-------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/lib/libarchive/archive_read_support_format_tar.c b/lib/libarchive/archive_read_support_format_tar.c index 1617b0fd0168..a30562f196f6 100644 --- a/lib/libarchive/archive_read_support_format_tar.c +++ b/lib/libarchive/archive_read_support_format_tar.c @@ -580,30 +580,37 @@ static int read_body_to_string(struct archive *a, struct tar *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; - off_t size; - unsigned oldstate; - int err, err2; + const void *src; + char *dest; + (void)tar; /* UNUSED */ header = h; size = tar_atol(header->size, sizeof(header->size)); - /* Temporarily fudge internal state for read_data call. */ - oldstate = a->state; - a->state = ARCHIVE_STATE_DATA; - /* Read the body into the string. */ - tar->entry_bytes_remaining = size; - tar->entry_padding = 0x1ff & -size; archive_string_ensure(as, size+1); - err = archive_read_data_into_buffer(a, as->s, size); - as->s[size] = 0; /* Null terminate name! */ - err2 = archive_read_data_skip(a); /* Resync for next header. */ - - /* Restore the state. */ - a->state = oldstate; - - return (err_combine(err, err2)); + padded_size = (size + 511) & ~ 511; + dest = as->s; + while (padded_size > 0) { + bytes_read = (a->compression_read_ahead)(a, &src, padded_size); + if (bytes_read < 0) + return (ARCHIVE_FATAL); + if (bytes_read > padded_size) + bytes_read = padded_size; + (a->compression_read_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'; + return (ARCHIVE_OK); } /*