diff --git a/Makefile.am b/Makefile.am index c395bb279..06c8bc06f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -409,6 +409,7 @@ libarchive_test_SOURCES= \ libarchive/test/test_read_large.c \ libarchive/test/test_read_pax_truncated.c \ libarchive/test/test_read_position.c \ + libarchive/test/test_read_set_format.c \ libarchive/test/test_read_truncated.c \ libarchive/test/test_read_truncated_filter.c \ libarchive/test/test_sparse_basic.c \ diff --git a/libarchive/archive.h b/libarchive/archive.h index 9fdfa6262..119690650 100644 --- a/libarchive/archive.h +++ b/libarchive/archive.h @@ -372,6 +372,17 @@ __LA_DECL int archive_read_support_format_tar(struct archive *); __LA_DECL int archive_read_support_format_xar(struct archive *); __LA_DECL int archive_read_support_format_zip(struct archive *); +/* Functions to manually set the format and filters to be used. This is + * useful to bypass the bidding process when the format and filters to use + * is known in advance. + */ +__LA_DECL int archive_read_set_format(struct archive *, int); +__LA_DECL int archive_read_append_filter(struct archive *, int); +__LA_DECL int archive_read_append_filter_program(struct archive *, + const char *); +__LA_DECL int archive_read_append_filter_program_signature + (struct archive *, const char *, const void * /* match */, size_t); + /* Set various callbacks. */ __LA_DECL int archive_read_set_open_callback(struct archive *, archive_open_callback *); diff --git a/libarchive/archive_read.c b/libarchive/archive_read.c index 766315345..2a66d4089 100644 --- a/libarchive/archive_read.c +++ b/libarchive/archive_read.c @@ -455,7 +455,7 @@ int archive_read_open1(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; - struct archive_read_filter *filter; + struct archive_read_filter *filter, *tmp; int slot, e; unsigned int i; @@ -499,25 +499,37 @@ archive_read_open1(struct archive *_a) filter->sswitch = client_switch_proxy; filter->name = "none"; filter->code = ARCHIVE_FILTER_NONE; - a->filter = filter; - client_switch_proxy(a->filter, 0); a->client.dataset[0].begin_position = 0; - - /* Build out the input pipeline. */ - e = choose_filters(a); - if (e < ARCHIVE_WARN) { - a->archive.state = ARCHIVE_STATE_FATAL; - return (ARCHIVE_FATAL); + if (!a->filter || !a->bypass_filter_bidding) + { + a->filter = filter; + /* Build out the input pipeline. */ + e = choose_filters(a); + if (e < ARCHIVE_WARN) { + a->archive.state = ARCHIVE_STATE_FATAL; + return (ARCHIVE_FATAL); + } + } + else + { + /* Need to add "NONE" type filter at the end of the filter chain */ + tmp = a->filter; + while (tmp->upstream) + tmp = tmp->upstream; + tmp->upstream = filter; } - slot = choose_format(a); - if (slot < 0) { - close_filters(a); - a->archive.state = ARCHIVE_STATE_FATAL; - return (ARCHIVE_FATAL); + if (!a->format) + { + slot = choose_format(a); + if (slot < 0) { + close_filters(a); + a->archive.state = ARCHIVE_STATE_FATAL; + return (ARCHIVE_FATAL); + } + a->format = &(a->formats[slot]); } - a->format = &(a->formats[slot]); a->archive.state = ARCHIVE_STATE_HEADER; @@ -1622,3 +1634,236 @@ __archive_read_filter_seek(struct archive_read_filter *filter, int64_t offset, } return r; } + +int +archive_read_set_format(struct archive *_a, int code) +{ + int r1, r2, slots, i; + char str[10]; + struct archive_read *a = (struct archive_read *)_a; + + if ((r1 = archive_read_support_format_by_code(_a, code)) < (ARCHIVE_OK)) + return r1; + + r1 = r2 = (ARCHIVE_OK); + if (a->format) + r2 = (ARCHIVE_WARN); + switch (code & ARCHIVE_FORMAT_BASE_MASK) + { + case ARCHIVE_FORMAT_7ZIP: + strcpy(str, "7zip"); + break; + case ARCHIVE_FORMAT_AR: + strcpy(str, "ar"); + break; + case ARCHIVE_FORMAT_CAB: + strcpy(str, "cab"); + break; + case ARCHIVE_FORMAT_CPIO: + strcpy(str, "cpio"); + break; + case ARCHIVE_FORMAT_ISO9660: + strcpy(str, "iso9660"); + break; + case ARCHIVE_FORMAT_LHA: + strcpy(str, "lha"); + break; + case ARCHIVE_FORMAT_MTREE: + strcpy(str, "mtree"); + break; + case ARCHIVE_FORMAT_RAR: + strcpy(str, "rar"); + break; + case ARCHIVE_FORMAT_TAR: + strcpy(str, "tar"); + break; + case ARCHIVE_FORMAT_XAR: + strcpy(str, "xar"); + break; + case ARCHIVE_FORMAT_ZIP: + strcpy(str, "zip"); + break; + default: + archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, + "Invalid format code specified"); + return (ARCHIVE_FATAL); + } + + slots = sizeof(a->formats) / sizeof(a->formats[0]); + a->format = &(a->formats[0]); + for (i = 0; i < slots; i++, a->format++) { + if (!a->format->name || !strcmp(a->format->name, str)) + break; + } + if (!a->format->name || strcmp(a->format->name, str)) + { + archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, + "Internal error: Unable to set format"); + r1 = (ARCHIVE_FATAL); + } + + return (r1 < r2) ? r1 : r2; +} + +int +archive_read_append_filter(struct archive *_a, int code) +{ + int r1, r2, number_bidders, i; + char str[10]; + struct archive_read_filter_bidder *bidder; + struct archive_read_filter *filter; + struct archive_read *a = (struct archive_read *)_a; + + r1 = r2 = (ARCHIVE_OK); + switch (code) + { + case ARCHIVE_FILTER_NONE: + /* No filter to add, so do nothing. + * NOTE: An initial "NONE" type filter is always set at the end of the + * filter chain. + */ + r1 = (ARCHIVE_OK); + break; + case ARCHIVE_FILTER_GZIP: + strcpy(str, "gzip"); + r1 = archive_read_support_filter_gzip(_a); + break; + case ARCHIVE_FILTER_BZIP2: + strcpy(str, "bzip2"); + r1 = archive_read_support_filter_bzip2(_a); + break; + case ARCHIVE_FILTER_COMPRESS: + strcpy(str, "compress (.Z)"); + r1 = archive_read_support_filter_compress(_a); + break; + case ARCHIVE_FILTER_PROGRAM: + archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, + "Cannot append program filter using archive_read_append_filter"); + return (ARCHIVE_FATAL); + case ARCHIVE_FILTER_LZMA: + strcpy(str, "lzma"); + r1 = archive_read_support_filter_lzma(_a); + break; + case ARCHIVE_FILTER_XZ: + strcpy(str, "xz"); + r1 = archive_read_support_filter_xz(_a); + break; + case ARCHIVE_FILTER_UU: + strcpy(str, "uu"); + r1 = archive_read_support_filter_uu(_a); + break; + case ARCHIVE_FILTER_RPM: + strcpy(str, "rpm"); + r1 = archive_read_support_filter_rpm(_a); + break; + case ARCHIVE_FILTER_LZIP: + strcpy(str, "lzip"); + r1 = archive_read_support_filter_lzip(_a); + break; + case ARCHIVE_FILTER_LRZIP: + strcpy(str, "lrzip"); + r1 = archive_read_support_filter_lrzip(_a); + break; + default: + archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, + "Invalid filter code specified"); + return (ARCHIVE_FATAL); + } + + if (code != ARCHIVE_FILTER_NONE) + { + number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]); + + bidder = a->bidders; + for (i = 0; i < number_bidders; i++, bidder++) + { + if (!bidder->name || !strcmp(bidder->name, str)) + break; + } + if (!bidder->name || strcmp(bidder->name, str)) + { + archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, + "Internal error: Unable to append filter"); + return (ARCHIVE_FATAL); + } + + filter + = (struct archive_read_filter *)calloc(1, sizeof(*filter)); + if (filter == NULL) + { + archive_set_error(&a->archive, ENOMEM, "Out of memory"); + return (ARCHIVE_FATAL); + } + filter->bidder = bidder; + filter->archive = a; + filter->upstream = a->filter; + a->filter = filter; + r2 = (bidder->init)(a->filter); + if (r2 != ARCHIVE_OK) { + close_filters(a); + free_filters(a); + return (ARCHIVE_FATAL); + } + } + + a->bypass_filter_bidding = 1; + return (r1 < r2) ? r1 : r2; +} + +int +archive_read_append_filter_program(struct archive *_a, const char *cmd) +{ + return (archive_read_append_filter_program_signature(_a, cmd, NULL, 0)); +} + +int +archive_read_append_filter_program_signature(struct archive *_a, + const char *cmd, const void *signature, size_t signature_len) +{ + int r, number_bidders, i; + struct archive_read_filter_bidder *bidder; + struct archive_read_filter *filter; + struct archive_read *a = (struct archive_read *)_a; + + if (archive_read_support_filter_program_signature(_a, cmd, signature, + signature_len) != (ARCHIVE_OK)) + return (ARCHIVE_FATAL); + + number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]); + + bidder = a->bidders; + for (i = 0; i < number_bidders; i++, bidder++) + { + /* Program bidder name set to filter name after initialization */ + if (bidder->data && !bidder->name) + break; + } + if (!bidder->data) + { + archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, + "Internal error: Unable to append program filter"); + return (ARCHIVE_FATAL); + } + + filter + = (struct archive_read_filter *)calloc(1, sizeof(*filter)); + if (filter == NULL) + { + archive_set_error(&a->archive, ENOMEM, "Out of memory"); + return (ARCHIVE_FATAL); + } + filter->bidder = bidder; + filter->archive = a; + filter->upstream = a->filter; + a->filter = filter; + r = (bidder->init)(a->filter); + if (r != ARCHIVE_OK) { + close_filters(a); + free_filters(a); + return (ARCHIVE_FATAL); + } + bidder->name = a->filter->name; + + a->bypass_filter_bidding = 1; + return r; +} diff --git a/libarchive/archive_read_private.h b/libarchive/archive_read_private.h index de3f3cdb5..0ef686f9a 100644 --- a/libarchive/archive_read_private.h +++ b/libarchive/archive_read_private.h @@ -58,6 +58,8 @@ struct archive_read_filter; struct archive_read_filter_bidder { /* Configuration data for the bidder. */ void *data; + /* Name of the filter */ + const char *name; /* Taste the upstream filter to see if we handle this. */ int (*bid)(struct archive_read_filter_bidder *, struct archive_read_filter *); @@ -168,6 +170,9 @@ struct archive_read { /* Last filter in chain */ struct archive_read_filter *filter; + /* Whether to bypass filter bidding process */ + int bypass_filter_bidding; + /* File offset of beginning of most recently-read header. */ int64_t header_position; diff --git a/libarchive/archive_read_support_filter_bzip2.c b/libarchive/archive_read_support_filter_bzip2.c index 35c6eb01b..3885a7cf6 100644 --- a/libarchive/archive_read_support_filter_bzip2.c +++ b/libarchive/archive_read_support_filter_bzip2.c @@ -94,6 +94,7 @@ archive_read_support_filter_bzip2(struct archive *_a) return (ARCHIVE_FATAL); reader->data = NULL; + reader->name = "bzip2"; reader->bid = bzip2_reader_bid; reader->init = bzip2_reader_init; reader->options = NULL; diff --git a/libarchive/archive_read_support_filter_compress.c b/libarchive/archive_read_support_filter_compress.c index b8b626030..3f5d1f37e 100644 --- a/libarchive/archive_read_support_filter_compress.c +++ b/libarchive/archive_read_support_filter_compress.c @@ -163,6 +163,7 @@ archive_read_support_filter_compress(struct archive *_a) return (ARCHIVE_FATAL); bidder->data = NULL; + bidder->name = "compress (.Z)"; bidder->bid = compress_bidder_bid; bidder->init = compress_bidder_init; bidder->options = NULL; diff --git a/libarchive/archive_read_support_filter_gzip.c b/libarchive/archive_read_support_filter_gzip.c index 475cc1737..fa8c675de 100644 --- a/libarchive/archive_read_support_filter_gzip.c +++ b/libarchive/archive_read_support_filter_gzip.c @@ -100,6 +100,7 @@ archive_read_support_filter_gzip(struct archive *_a) return (ARCHIVE_FATAL); bidder->data = NULL; + bidder->name = "gzip"; bidder->bid = gzip_bidder_bid; bidder->init = gzip_bidder_init; bidder->options = NULL; diff --git a/libarchive/archive_read_support_filter_lrzip.c b/libarchive/archive_read_support_filter_lrzip.c index 0b2924243..c82a8e2f1 100644 --- a/libarchive/archive_read_support_filter_lrzip.c +++ b/libarchive/archive_read_support_filter_lrzip.c @@ -73,6 +73,7 @@ archive_read_support_filter_lrzip(struct archive *_a) return (ARCHIVE_FATAL); reader->data = NULL; + reader->name = "lrzip"; reader->bid = lrzip_bidder_bid; reader->init = lrzip_bidder_init; reader->options = NULL; diff --git a/libarchive/archive_read_support_filter_program.c b/libarchive/archive_read_support_filter_program.c index 850ab4545..66dc2f424 100644 --- a/libarchive/archive_read_support_filter_program.c +++ b/libarchive/archive_read_support_filter_program.c @@ -88,6 +88,7 @@ archive_read_support_filter_program(struct archive *a, const char *cmd) * bid twice in the same pipeline. */ struct program_bidder { + char *description; char *cmd; void *signature; size_t signature_len; diff --git a/libarchive/archive_read_support_filter_rpm.c b/libarchive/archive_read_support_filter_rpm.c index 237d98015..e7e58e51f 100644 --- a/libarchive/archive_read_support_filter_rpm.c +++ b/libarchive/archive_read_support_filter_rpm.c @@ -85,6 +85,7 @@ archive_read_support_filter_rpm(struct archive *_a) return (ARCHIVE_FATAL); bidder->data = NULL; + bidder->name = "rpm"; bidder->bid = rpm_bidder_bid; bidder->init = rpm_bidder_init; bidder->options = NULL; diff --git a/libarchive/archive_read_support_filter_uu.c b/libarchive/archive_read_support_filter_uu.c index 493338d0b..471771b6f 100644 --- a/libarchive/archive_read_support_filter_uu.c +++ b/libarchive/archive_read_support_filter_uu.c @@ -89,6 +89,7 @@ archive_read_support_filter_uu(struct archive *_a) return (ARCHIVE_FATAL); bidder->data = NULL; + bidder->name = "uu"; bidder->bid = uudecode_bidder_bid; bidder->init = uudecode_bidder_init; bidder->options = NULL; diff --git a/libarchive/archive_read_support_filter_xz.c b/libarchive/archive_read_support_filter_xz.c index c3c00fc9e..15824b1d0 100644 --- a/libarchive/archive_read_support_filter_xz.c +++ b/libarchive/archive_read_support_filter_xz.c @@ -136,6 +136,7 @@ archive_read_support_filter_xz(struct archive *_a) return (ARCHIVE_FATAL); bidder->data = NULL; + bidder->name = "xz"; bidder->bid = xz_bidder_bid; bidder->init = xz_bidder_init; bidder->options = NULL; @@ -170,6 +171,7 @@ archive_read_support_filter_lzma(struct archive *_a) return (ARCHIVE_FATAL); bidder->data = NULL; + bidder->name = "lzma"; bidder->bid = lzma_bidder_bid; bidder->init = lzma_bidder_init; bidder->options = NULL; @@ -207,6 +209,7 @@ archive_read_support_filter_lzip(struct archive *_a) return (ARCHIVE_FATAL); bidder->data = NULL; + bidder->name = "lzip"; bidder->bid = lzip_bidder_bid; bidder->init = lzip_bidder_init; bidder->options = NULL; diff --git a/libarchive/test/CMakeLists.txt b/libarchive/test/CMakeLists.txt index eba089bc6..99c00f3b9 100644 --- a/libarchive/test/CMakeLists.txt +++ b/libarchive/test/CMakeLists.txt @@ -144,6 +144,7 @@ IF(ENABLE_TEST) test_read_large.c test_read_pax_truncated.c test_read_position.c + test_read_set_format.c test_read_truncated.c test_read_truncated_filter.c test_sparse_basic.c diff --git a/libarchive/test/test_read_set_format.c b/libarchive/test/test_read_set_format.c new file mode 100644 index 000000000..2b3ec1bdc --- /dev/null +++ b/libarchive/test/test_read_set_format.c @@ -0,0 +1,219 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * Copyright (c) 2012 Andres Mejia + * Copyright (c) 2011-2012 Michihiro NAKAJIMA + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" + +DEFINE_TEST(test_read_set_format) +{ + char buff[64]; + const char reffile[] = "test_read_format_rar.rar"; + const char test_txt[] = "test text document\r\n"; + int size = sizeof(test_txt)-1; + struct archive_entry *ae; + struct archive *a; + + extract_reference_file(reffile); + assert((a = archive_read_new()) != NULL); + assertA(0 == archive_read_set_format(a, ARCHIVE_FORMAT_RAR)); + assertA(0 == archive_read_append_filter(a, ARCHIVE_FILTER_NONE)); + assertA(0 == archive_read_open_filename(a, reffile, 10240)); + + /* First header. */ + assertA(0 == archive_read_next_header(a, &ae)); + assertEqualString("test.txt", archive_entry_pathname(ae)); + assertA((int)archive_entry_mtime(ae)); + assertA((int)archive_entry_ctime(ae)); + assertA((int)archive_entry_atime(ae)); + assertEqualInt(20, archive_entry_size(ae)); + assertEqualInt(33188, archive_entry_mode(ae)); + assertA(size == archive_read_data(a, buff, size)); + assertEqualMem(buff, test_txt, size); + + /* Second header. */ + assertA(0 == archive_read_next_header(a, &ae)); + assertEqualString("testlink", archive_entry_pathname(ae)); + assertA((int)archive_entry_mtime(ae)); + assertA((int)archive_entry_ctime(ae)); + assertA((int)archive_entry_atime(ae)); + assertEqualInt(0, archive_entry_size(ae)); + assertEqualInt(41471, archive_entry_mode(ae)); + assertEqualString("test.txt", archive_entry_symlink(ae)); + assertEqualIntA(a, 0, archive_read_data(a, buff, sizeof(buff))); + + /* Third header. */ + assertA(0 == archive_read_next_header(a, &ae)); + assertEqualString("testdir/test.txt", archive_entry_pathname(ae)); + assertA((int)archive_entry_mtime(ae)); + assertA((int)archive_entry_ctime(ae)); + assertA((int)archive_entry_atime(ae)); + assertEqualInt(20, archive_entry_size(ae)); + assertEqualInt(33188, archive_entry_mode(ae)); + assertA(size == archive_read_data(a, buff, size)); + assertEqualMem(buff, test_txt, size); + + /* Fourth header. */ + assertA(0 == archive_read_next_header(a, &ae)); + assertEqualString("testdir", archive_entry_pathname(ae)); + assertA((int)archive_entry_mtime(ae)); + assertA((int)archive_entry_ctime(ae)); + assertA((int)archive_entry_atime(ae)); + assertEqualInt(0, archive_entry_size(ae)); + assertEqualInt(16877, archive_entry_mode(ae)); + + /* Fifth header. */ + assertA(0 == archive_read_next_header(a, &ae)); + assertEqualString("testemptydir", archive_entry_pathname(ae)); + assertA((int)archive_entry_mtime(ae)); + assertA((int)archive_entry_ctime(ae)); + assertA((int)archive_entry_atime(ae)); + assertEqualInt(0, archive_entry_size(ae)); + assertEqualInt(16877, archive_entry_mode(ae)); + + /* Test EOF */ + assertA(1 == archive_read_next_header(a, &ae)); + assertEqualInt(5, archive_file_count(a)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +} + +DEFINE_TEST(test_read_set_wrong_format) +{ + const char reffile[] = "test_read_format_zip.zip"; + struct archive_entry *ae; + struct archive *a; + + extract_reference_file(reffile); + assert((a = archive_read_new()) != NULL); + assertA(0 == archive_read_set_format(a, ARCHIVE_FORMAT_RAR)); + assertA(0 == archive_read_append_filter(a, ARCHIVE_FILTER_NONE)); + assertA(0 == archive_read_open_filename(a, reffile, 10240)); + + /* Check that this actually fails, then close the archive. */ + assertA(archive_read_next_header(a, &ae) < (ARCHIVE_WARN)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +} + +static unsigned char archive[] = { +31,139,8,0,222,'C','p','C',0,3,211,'c',160,'=','0','0','0','0','7','5','U', +0,210,134,230,166,6,200,'4',28,'(',24,26,24,27,155,24,152,24,154,27,155,')', +24,24,26,152,154,25,'2','(',152,210,193,'m',12,165,197,'%',137,'E','@',167, +148,'d',230,226,'U','G','H',30,234,15,'8','=',10,'F',193,'(',24,5,131,28, +0,0,29,172,5,240,0,6,0,0}; + +DEFINE_TEST(test_read_append_filter) +{ + struct archive_entry *ae; + struct archive *a; + int r; + + assert((a = archive_read_new()) != NULL); + assertA(0 == archive_read_set_format(a, ARCHIVE_FORMAT_TAR)); + r = archive_read_append_filter(a, ARCHIVE_FILTER_GZIP); + if (r == ARCHIVE_WARN) { + skipping("gzip reading not fully supported on this platform"); + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); + return; + } + assertEqualInt(ARCHIVE_OK, + archive_read_open_memory(a, archive, sizeof(archive))); + assertEqualInt(ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualInt(1, archive_file_count(a)); + assertEqualInt(archive_filter_code(a, 0), ARCHIVE_COMPRESSION_GZIP); + assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_USTAR); + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); + assertEqualInt(ARCHIVE_OK,archive_read_free(a)); +} + +DEFINE_TEST(test_read_append_wrong_filter) +{ + struct archive_entry *ae; + struct archive *a; + int r; + + assert((a = archive_read_new()) != NULL); + assertA(0 == archive_read_set_format(a, ARCHIVE_FORMAT_TAR)); + r = archive_read_append_filter(a, ARCHIVE_FILTER_XZ); + if (r == ARCHIVE_WARN) { + skipping("gzip reading not fully supported on this platform"); + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); + return; + } + assertEqualInt(ARCHIVE_OK, + archive_read_open_memory(a, archive, sizeof(archive))); + assertA(archive_read_next_header(a, &ae) < (ARCHIVE_WARN)); + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); + assertEqualInt(ARCHIVE_OK,archive_read_free(a)); +} + +DEFINE_TEST(test_read_append_filter_program) +{ + struct archive_entry *ae; + struct archive *a; + + /* + * If we have "gzip -d", try using that. + */ + if (!canGzip()) { + skipping("Can't run gunzip program on this platform"); + return; + } + assert((a = archive_read_new()) != NULL); + assertA(0 == archive_read_set_format(a, ARCHIVE_FORMAT_TAR)); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_append_filter_program(a, "gunzip")); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_memory(a, archive, sizeof(archive))); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_next_header(a, &ae)); + assertEqualInt(archive_filter_code(a, 0), ARCHIVE_FILTER_PROGRAM); + assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_USTAR); + assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a)); + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +} + +DEFINE_TEST(test_read_append_filter_wrong_program) +{ + struct archive_entry *ae; + struct archive *a; + + /* + * If we have "bunzip2 -q", try using that. + */ + if (!canRunCommand("bunzip2 -V")) { + skipping("Can't run bunzip2 program on this platform"); + return; + } + assert((a = archive_read_new()) != NULL); + assertA(0 == archive_read_set_format(a, ARCHIVE_FORMAT_TAR)); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_append_filter_program(a, "bunzip2 -q")); + assertEqualIntA(a, ARCHIVE_OK, + archive_read_open_memory(a, archive, sizeof(archive))); + assertA(archive_read_next_header(a, &ae) < (ARCHIVE_WARN)); + assertEqualIntA(a, ARCHIVE_WARN, archive_read_close(a)); + assertEqualInt(ARCHIVE_OK, archive_read_free(a)); +}