From: Tim Kientzle Date: Sun, 21 Mar 2010 06:30:08 +0000 (-0400) Subject: Make read_filter_skip be independent of read_filter_consume. In particular, X-Git-Tag: v3.0.0a~1147 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=3996cebc5bb71db3bbbc712b08286f4be2c232ab;p=thirdparty%2Flibarchive.git Make read_filter_skip be independent of read_filter_consume. In particular, read_skip now does everything that read_consume does, so we're ready to merge read_skip and read_consume. SVN-Revision: 2045 --- diff --git a/libarchive/archive_read.c b/libarchive/archive_read.c index 58080ebce..f461fe1c6 100644 --- a/libarchive/archive_read.c +++ b/libarchive/archive_read.c @@ -1259,63 +1259,78 @@ static int64_t _archive_read_filter_skip(struct archive_read_filter *filter, int64_t request) { int64_t bytes_skipped, total_bytes_skipped = 0; + ssize_t bytes_read; size_t min; if (filter->fatal) return (-1); - /* - * If there is data in the buffers already, use that first. - */ + + /* Use up the copy buffer first. */ if (filter->avail > 0) { - min = minimum(request, (off_t)filter->avail); - bytes_skipped = __archive_read_filter_consume(filter, min); - request -= bytes_skipped; - total_bytes_skipped += bytes_skipped; + min = minimum(request, filter->avail); + filter->next += min; + filter->avail -= min; + request -= min; + filter->bytes_consumed += min; + total_bytes_skipped += min; } + + /* Then use up the client buffer. */ if (filter->client_avail > 0) { - min = minimum(request, (int64_t)filter->client_avail); - bytes_skipped = __archive_read_filter_consume(filter, min); - request -= bytes_skipped; - total_bytes_skipped += bytes_skipped; + min = minimum(request, filter->client_avail); + filter->client_next += min; + filter->client_avail -= min; + request -= min; + filter->bytes_consumed += min; + total_bytes_skipped += min; } if (request == 0) return (total_bytes_skipped); - /* - * If a client_skipper was provided, try that first. - */ + filter->client_total = filter->client_avail = 0; + filter->client_next = filter->client_buff = NULL; + + /* If there's an optimized skip function, use it. */ if (filter->skip != NULL) { bytes_skipped = (filter->skip)(filter, request); if (bytes_skipped < 0) { /* error */ - filter->client_total = filter->client_avail = 0; - filter->client_next = filter->client_buff = NULL; filter->fatal = 1; return (bytes_skipped); } filter->bytes_consumed += bytes_skipped; total_bytes_skipped += bytes_skipped; request -= bytes_skipped; - filter->client_next = filter->client_buff; - filter->client_avail = filter->client_total = 0; + if (request == 0) + return (total_bytes_skipped); } - /* - * Note that client_skipper will usually not satisfy the - * full request (due to low-level blocking concerns), - * so even if client_skipper is provided, we may still - * have to use ordinary reads to finish out the request. - */ - while (request > 0) { - ssize_t bytes_read; - (void)__archive_read_filter_ahead(filter, 1, &bytes_read); - if (bytes_read < 0) + + /* Use ordinary reads as necessary to complete the request. */ + for (;;) { + bytes_read = (filter->read)(filter, &filter->client_buff); + + if (bytes_read < 0) { + filter->client_buff = NULL; + filter->fatal = 1; return (bytes_read); + } + if (bytes_read == 0) { + filter->client_buff = NULL; + filter->end_of_file = 1; return (total_bytes_skipped); } - min = (size_t)(minimum(bytes_read, request)); - bytes_read = __archive_read_filter_consume(filter, min); + + filter->position += bytes_read; + + if (bytes_read >= request) { + filter->client_next = filter->client_buff + request; + filter->client_avail = bytes_read - request; + filter->client_total = bytes_read; + total_bytes_skipped += request; + return (total_bytes_skipped); + } + total_bytes_skipped += bytes_read; request -= bytes_read; } - return (total_bytes_skipped); }