From: Tim Kientzle Date: Sat, 2 Jan 2010 01:21:05 +0000 (-0500) Subject: After initializing a filter, we try to read from it to X-Git-Tag: v2.8.0~36 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=61dd5abb006d2d7bbc667a98dc2c7d16ad15a824;p=thirdparty%2Flibarchive.git After initializing a filter, we try to read from it to verify that it's working (in particular, this gives early error reporting when external decompression programs are nonexistent or exit immediately). If this read failed, we weren't properly cleaning up the just-initialized filter. Since this is fatal, the easiest fix is to refactor the close() handler and just release the entire filter chain. SVN-Revision: 1790 --- diff --git a/libarchive/archive_read.c b/libarchive/archive_read.c index dc794ef12..f39f5cec2 100644 --- a/libarchive/archive_read.c +++ b/libarchive/archive_read.c @@ -57,6 +57,7 @@ __FBSDID("$FreeBSD: head/lib/libarchive/archive_read.c 201157 2009-12-29 05:30:2 static int build_stream(struct archive_read *); static int choose_format(struct archive_read *); +static int cleanup_filters(struct archive_read *); static struct archive_vtable *archive_read_vtable(void); static int _archive_read_close(struct archive *); static int _archive_read_finish(struct archive *); @@ -393,14 +394,13 @@ build_stream(struct archive_read *a) free(filter); return (r); } + a->filter = filter; /* Verify the filter by asking it for some data. */ __archive_read_filter_ahead(filter, 1, &avail); if (avail < 0) { - /* If the read failed, bail out now. */ - free(filter); - return (avail); + cleanup_filters(a); + return (ARCHIVE_FATAL); } - a->filter = filter; } } @@ -738,18 +738,10 @@ _archive_read_close(struct archive *_a) /* TODO: Clean up the formatters. */ - /* Clean up the filter pipeline. */ - while (a->filter != NULL) { - struct archive_read_filter *t = a->filter->upstream; - if (a->filter->close != NULL) { - r1 = (a->filter->close)(a->filter); - if (r1 < r) - r = r1; - } - free(a->filter->buffer); - free(a->filter); - a->filter = t; - } + /* Release the filter objects. */ + r1 = cleanup_filters(a); + if (r1 < r) + r = r1; /* Release the bidder objects. */ n = sizeof(a->bidders)/sizeof(a->bidders[0]); @@ -764,6 +756,25 @@ _archive_read_close(struct archive *_a) return (r); } +static int +cleanup_filters(struct archive_read *a) +{ + int r = ARCHIVE_OK; + /* Clean up the filter pipeline. */ + while (a->filter != NULL) { + struct archive_read_filter *t = a->filter->upstream; + if (a->filter->close != NULL) { + int r1 = (a->filter->close)(a->filter); + if (r1 < r) + r = r1; + } + free(a->filter->buffer); + free(a->filter); + a->filter = t; + } + return r; +} + /* * Release memory and other resources. */