diff --git a/Makefile.am b/Makefile.am index d8d52a35..4293a21d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -404,6 +404,7 @@ libarchive_test_SOURCES= \ libarchive/test/test_archive_pathmatch_oob.c \ libarchive/test/test_archive_read.c \ libarchive/test/test_archive_read_add_passphrase.c \ + libarchive/test/test_archive_read_append_filter.c \ libarchive/test/test_archive_read_close_twice.c \ libarchive/test/test_archive_read_multiple_data_objects.c \ libarchive/test/test_archive_read_next_header_empty.c \ diff --git a/libarchive/archive_read.c b/libarchive/archive_read.c index e844e42d..406d84de 100644 --- a/libarchive/archive_read.c +++ b/libarchive/archive_read.c @@ -1290,7 +1290,6 @@ __archive_read_register_format(struct archive_read *a, int __archive_read_register_bidder(struct archive_read *a, void *bidder_data, - const char *name, const struct archive_read_filter_bidder_vtable *vtable) { struct archive_read_filter_bidder *bidder; @@ -1307,7 +1306,6 @@ __archive_read_register_bidder(struct archive_read *a, memset(a->bidders + i, 0, sizeof(a->bidders[0])); bidder = (a->bidders + i); bidder->data = bidder_data; - bidder->name = name; bidder->vtable = vtable; if (bidder->vtable->bid == NULL || bidder->vtable->init == NULL) { archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, diff --git a/libarchive/archive_read_append_filter.c b/libarchive/archive_read_append_filter.c index 8de1b2ea..5cc8ff55 100644 --- a/libarchive/archive_read_append_filter.c +++ b/libarchive/archive_read_append_filter.c @@ -33,14 +33,25 @@ #include "archive_private.h" #include "archive_read_private.h" +static struct archive_read_filter_bidder * +get_last_bidder(struct archive_read *a) +{ + size_t i; + + for (i = 0; i < sizeof(a->bidders) / sizeof(a->bidders[0]); i++) + { + if (a->bidders[i].vtable == NULL) + break; + } + + return a->bidders + (i - 1); +} + int archive_read_append_filter(struct archive *_a, int code) { - int r1, r2, number_bidders, i; - const char *str; - struct archive_read_filter_bidder *b; - struct archive_read_filter *f; struct archive_read *a = (struct archive_read *)_a; + int r1, r2; r2 = (ARCHIVE_OK); switch (code) @@ -53,15 +64,12 @@ archive_read_append_filter(struct archive *_a, int code) r1 = (ARCHIVE_OK); break; case ARCHIVE_FILTER_GZIP: - str = "gzip"; r1 = archive_read_support_filter_gzip(_a); break; case ARCHIVE_FILTER_BZIP2: - str = "bzip2"; r1 = archive_read_support_filter_bzip2(_a); break; case ARCHIVE_FILTER_COMPRESS: - str = "compress (.Z)"; r1 = archive_read_support_filter_compress(_a); break; case ARCHIVE_FILTER_PROGRAM: @@ -69,43 +77,33 @@ archive_read_append_filter(struct archive *_a, int code) "Cannot append program filter using archive_read_append_filter"); return (ARCHIVE_FATAL); case ARCHIVE_FILTER_LZMA: - str = "lzma"; r1 = archive_read_support_filter_lzma(_a); break; case ARCHIVE_FILTER_XZ: - str = "xz"; r1 = archive_read_support_filter_xz(_a); break; case ARCHIVE_FILTER_UU: - str = "uu"; r1 = archive_read_support_filter_uu(_a); break; case ARCHIVE_FILTER_RPM: - str = "rpm"; r1 = archive_read_support_filter_rpm(_a); break; case ARCHIVE_FILTER_LZ4: - str = "lz4"; r1 = archive_read_support_filter_lz4(_a); break; case ARCHIVE_FILTER_ZSTD: - str = "zstd"; r1 = archive_read_support_filter_zstd(_a); break; case ARCHIVE_FILTER_LZIP: - str = "lzip"; r1 = archive_read_support_filter_lzip(_a); break; case ARCHIVE_FILTER_LZOP: - str = "lzop"; r1 = archive_read_support_filter_lzop(_a); break; case ARCHIVE_FILTER_LRZIP: - str = "lrzip"; r1 = archive_read_support_filter_lrzip(_a); break; case ARCHIVE_FILTER_GRZIP: - str = "grzip"; r1 = archive_read_support_filter_grzip(_a); break; default: @@ -114,22 +112,10 @@ archive_read_append_filter(struct archive *_a, int code) return (ARCHIVE_FATAL); } - if (code != ARCHIVE_FILTER_NONE) + if (r1 > ARCHIVE_FATAL && code != ARCHIVE_FILTER_NONE) { - number_bidders = sizeof(a->bidders) / sizeof(a->bidders[0]); - - b = a->bidders; - for (i = 1; i < number_bidders; i++, b++) - { - if (!b->name || !strcmp(b->name, str)) - break; - } - if (!b->name || strcmp(b->name, str)) - { - archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, - "Internal error: Unable to append filter"); - return (ARCHIVE_FATAL); - } + struct archive_read_filter_bidder *b; + struct archive_read_filter *f; f = calloc(1, sizeof(*f)); if (f == NULL) @@ -137,6 +123,7 @@ archive_read_append_filter(struct archive *_a, int code) archive_set_error(&a->archive, ENOMEM, "Out of memory"); return (ARCHIVE_FATAL); } + b = get_last_bidder(a); f->bidder = b; f->archive = a; f->upstream = a->filter; @@ -162,37 +149,22 @@ 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 *a = (struct archive_read *)_a; struct archive_read_filter_bidder *b; struct archive_read_filter *f; - struct archive_read *a = (struct archive_read *)_a; + int r; 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]); - - b = a->bidders; - for (i = 0; i < number_bidders; i++, b++) - { - /* Program bidder name set to filter name after initialization */ - if (b->data && !b->name) - break; - } - if (!b->data) - { - archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, - "Internal error: Unable to append program filter"); - return (ARCHIVE_FATAL); - } - f = calloc(1, sizeof(*f)); if (f == NULL) { archive_set_error(&a->archive, ENOMEM, "Out of memory"); return (ARCHIVE_FATAL); } + b = get_last_bidder(a); f->bidder = b; f->archive = a; f->upstream = a->filter; @@ -202,7 +174,6 @@ archive_read_append_filter_program_signature(struct archive *_a, __archive_read_free_filters(a); return (ARCHIVE_FATAL); } - b->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 3bd8de2d..e30b6c2b 100644 --- a/libarchive/archive_read_private.h +++ b/libarchive/archive_read_private.h @@ -68,8 +68,6 @@ struct archive_read_filter_bidder_vtable { struct archive_read_filter_bidder { /* Configuration data for the bidder. */ void *data; - /* Name of the filter */ - const char *name; const struct archive_read_filter_bidder_vtable *vtable; }; @@ -250,7 +248,6 @@ int __archive_read_register_format(struct archive_read *a, int __archive_read_register_bidder(struct archive_read *a, void *bidder_data, - const char *name, const struct archive_read_filter_bidder_vtable *vtable); const void *__archive_read_ahead(struct archive_read *, size_t, ssize_t *); diff --git a/libarchive/archive_read_support_filter_bzip2.c b/libarchive/archive_read_support_filter_bzip2.c index 588953f2..1cfc55dc 100644 --- a/libarchive/archive_read_support_filter_bzip2.c +++ b/libarchive/archive_read_support_filter_bzip2.c @@ -91,7 +91,7 @@ archive_read_support_filter_bzip2(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; - if (__archive_read_register_bidder(a, NULL, "bzip2", + if (__archive_read_register_bidder(a, NULL, &bzip2_bidder_vtable) != ARCHIVE_OK) return (ARCHIVE_FATAL); diff --git a/libarchive/archive_read_support_filter_compress.c b/libarchive/archive_read_support_filter_compress.c index 4e1f1dc5..4763995e 100644 --- a/libarchive/archive_read_support_filter_compress.c +++ b/libarchive/archive_read_support_filter_compress.c @@ -160,7 +160,7 @@ archive_read_support_filter_compress(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; - return __archive_read_register_bidder(a, NULL, "compress (.Z)", + return __archive_read_register_bidder(a, NULL, &compress_bidder_vtable); } diff --git a/libarchive/archive_read_support_filter_grzip.c b/libarchive/archive_read_support_filter_grzip.c index 9d9ad46e..8457ec7c 100644 --- a/libarchive/archive_read_support_filter_grzip.c +++ b/libarchive/archive_read_support_filter_grzip.c @@ -62,7 +62,7 @@ archive_read_support_filter_grzip(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; - if (__archive_read_register_bidder(a, NULL, "grzip", + if (__archive_read_register_bidder(a, NULL, &grzip_bidder_vtable) != ARCHIVE_OK) return (ARCHIVE_FATAL); diff --git a/libarchive/archive_read_support_filter_gzip.c b/libarchive/archive_read_support_filter_gzip.c index 89ae0f37..34b174b7 100644 --- a/libarchive/archive_read_support_filter_gzip.c +++ b/libarchive/archive_read_support_filter_gzip.c @@ -96,7 +96,7 @@ archive_read_support_filter_gzip(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; - if (__archive_read_register_bidder(a, NULL, "gzip", + if (__archive_read_register_bidder(a, NULL, &gzip_bidder_vtable) != ARCHIVE_OK) return (ARCHIVE_FATAL); diff --git a/libarchive/archive_read_support_filter_lrzip.c b/libarchive/archive_read_support_filter_lrzip.c index 33910fe1..a1d45d77 100644 --- a/libarchive/archive_read_support_filter_lrzip.c +++ b/libarchive/archive_read_support_filter_lrzip.c @@ -61,7 +61,7 @@ archive_read_support_filter_lrzip(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; - if (__archive_read_register_bidder(a, NULL, "lrzip", + if (__archive_read_register_bidder(a, NULL, &lrzip_bidder_vtable) != ARCHIVE_OK) return (ARCHIVE_FATAL); diff --git a/libarchive/archive_read_support_filter_lz4.c b/libarchive/archive_read_support_filter_lz4.c index 19086a1f..28189a07 100644 --- a/libarchive/archive_read_support_filter_lz4.c +++ b/libarchive/archive_read_support_filter_lz4.c @@ -118,7 +118,7 @@ archive_read_support_filter_lz4(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; - if (__archive_read_register_bidder(a, NULL, "lz4", + if (__archive_read_register_bidder(a, NULL, &lz4_bidder_vtable) != ARCHIVE_OK) return (ARCHIVE_FATAL); diff --git a/libarchive/archive_read_support_filter_lzop.c b/libarchive/archive_read_support_filter_lzop.c index ebfaf01e..5a552fce 100644 --- a/libarchive/archive_read_support_filter_lzop.c +++ b/libarchive/archive_read_support_filter_lzop.c @@ -109,7 +109,7 @@ archive_read_support_filter_lzop(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; - if (__archive_read_register_bidder(a, NULL, "lzop", + if (__archive_read_register_bidder(a, NULL, &lzop_bidder_vtable) != ARCHIVE_OK) return (ARCHIVE_FATAL); diff --git a/libarchive/archive_read_support_filter_program.c b/libarchive/archive_read_support_filter_program.c index cf7c3613..a9e02a32 100644 --- a/libarchive/archive_read_support_filter_program.c +++ b/libarchive/archive_read_support_filter_program.c @@ -156,7 +156,7 @@ archive_read_support_filter_program_signature(struct archive *_a, memcpy(state->signature, signature, signature_len); } - if (__archive_read_register_bidder(a, state, NULL, + if (__archive_read_register_bidder(a, state, &program_bidder_vtable) != ARCHIVE_OK) { free_state(state); return (ARCHIVE_FATAL); diff --git a/libarchive/archive_read_support_filter_rpm.c b/libarchive/archive_read_support_filter_rpm.c index 01bd1bf7..1cfddf75 100644 --- a/libarchive/archive_read_support_filter_rpm.c +++ b/libarchive/archive_read_support_filter_rpm.c @@ -71,7 +71,7 @@ archive_read_support_filter_rpm(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; - return __archive_read_register_bidder(a, NULL, "rpm", + return __archive_read_register_bidder(a, NULL, &rpm_bidder_vtable); } diff --git a/libarchive/archive_read_support_filter_uu.c b/libarchive/archive_read_support_filter_uu.c index c0f6f48e..10d49648 100644 --- a/libarchive/archive_read_support_filter_uu.c +++ b/libarchive/archive_read_support_filter_uu.c @@ -92,7 +92,7 @@ archive_read_support_filter_uu(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; - return __archive_read_register_bidder(a, NULL, "uu", + return __archive_read_register_bidder(a, NULL, &uudecode_bidder_vtable); } diff --git a/libarchive/archive_read_support_filter_xz.c b/libarchive/archive_read_support_filter_xz.c index 7c8e0cb5..b00ba543 100644 --- a/libarchive/archive_read_support_filter_xz.c +++ b/libarchive/archive_read_support_filter_xz.c @@ -115,7 +115,7 @@ archive_read_support_filter_xz(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; - if (__archive_read_register_bidder(a, NULL, "xz", + if (__archive_read_register_bidder(a, NULL, &xz_bidder_vtable) != ARCHIVE_OK) return (ARCHIVE_FATAL); @@ -147,7 +147,7 @@ archive_read_support_filter_lzma(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; - if (__archive_read_register_bidder(a, NULL, "lzma", + if (__archive_read_register_bidder(a, NULL, &lzma_bidder_vtable) != ARCHIVE_OK) return (ARCHIVE_FATAL); @@ -180,7 +180,7 @@ archive_read_support_filter_lzip(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; - if (__archive_read_register_bidder(a, NULL, "lzip", + if (__archive_read_register_bidder(a, NULL, &lzip_bidder_vtable) != ARCHIVE_OK) return (ARCHIVE_FATAL); diff --git a/libarchive/archive_read_support_filter_zstd.c b/libarchive/archive_read_support_filter_zstd.c index 12eac04c..163f54b5 100644 --- a/libarchive/archive_read_support_filter_zstd.c +++ b/libarchive/archive_read_support_filter_zstd.c @@ -87,7 +87,7 @@ archive_read_support_filter_zstd(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; - if (__archive_read_register_bidder(a, NULL, "zstd", + if (__archive_read_register_bidder(a, NULL, &zstd_bidder_vtable) != ARCHIVE_OK) return (ARCHIVE_FATAL); diff --git a/libarchive/test/CMakeLists.txt b/libarchive/test/CMakeLists.txt index 14e02084..91d537f5 100644 --- a/libarchive/test/CMakeLists.txt +++ b/libarchive/test/CMakeLists.txt @@ -33,6 +33,7 @@ IF(ENABLE_TEST) test_archive_pathmatch_oob.c test_archive_read.c test_archive_read_add_passphrase.c + test_archive_read_append_filter.c test_archive_read_close_twice.c test_archive_read_multiple_data_objects.c test_archive_read_next_header_empty.c diff --git a/libarchive/test/test_archive_read_append_filter.c b/libarchive/test/test_archive_read_append_filter.c new file mode 100644 index 00000000..5c301d52 --- /dev/null +++ b/libarchive/test/test_archive_read_append_filter.c @@ -0,0 +1,54 @@ +/*- + * Copyright (c) 2026 Tobias Stoeckmann + * 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 "archive.h" +#include "test.h" + +DEFINE_TEST(test_archive_read_append_filter) +{ + struct archive *a; + int r; + + a = archive_read_new(); + assert(a != NULL); + + /* Append a program bidder (without filter). */ + assertEqualIntA(a, ARCHIVE_OK, + archive_read_support_filter_program(a, "prog1")); + + /* Append a filter program which comes with its own bidder. */ + r = archive_read_append_filter_program(a, "prog2"); + + /* Verify that filter uses its own bidder. */ + if (r == ARCHIVE_FATAL) { + assertEqualStringA(a, "Can't initialize filter; unable to run program \"prog2\"", + archive_error_string(a)); + } else { + assertEqualIntA(a, ARCHIVE_OK, r); + assertEqualStringA(a, "Program: prog2", archive_filter_name(a, 0)); + } + + archive_read_free(a); +}