From: Martin Matuska Date: Thu, 3 Aug 2023 22:13:51 +0000 (+0200) Subject: unzip: correctly handle arguments following an -x after zipfile X-Git-Tag: v3.7.2~17 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=5c5a9f2b76ed51f060752b356c9e96ef3aee1baf;p=thirdparty%2Flibarchive.git unzip: correctly handle arguments following an -x after zipfile --- diff --git a/unzip/bsdunzip.c b/unzip/bsdunzip.c index b8f6ff4bb..29c3a1670 100644 --- a/unzip/bsdunzip.c +++ b/unzip/bsdunzip.c @@ -113,6 +113,9 @@ static int zipinfo_mode; /* running on tty? */ static int tty; +/* processing exclude list */ +static int unzip_exclude_mode = 0; + int bsdunzip_optind; /* convenience macro */ @@ -1114,6 +1117,7 @@ getopts(int argc, char *argv[]) bsdunzip->argc = argc; while ((opt = bsdunzip_getopt(bsdunzip)) != -1) { + unzip_exclude_mode = 0; switch (opt) { case 'a': a_opt = 1; @@ -1171,6 +1175,7 @@ getopts(int argc, char *argv[]) break; case 'x': add_pattern(&exclude, bsdunzip->argument); + unzip_exclude_mode = 1; break; case 'y': y_str = " "; @@ -1245,12 +1250,26 @@ main(int argc, char *argv[]) if (strcmp(zipfile, "-") == 0) zipfile = NULL; /* STDIN */ + unzip_exclude_mode = 0; + while (nopts < argc && *argv[nopts] != '-') add_pattern(&include, argv[nopts++]); nopts--; /* fake argv[0] */ nopts += getopts(argc - nopts, argv + nopts); + /* + * For compatibility with Info-ZIP's unzip(1) we need to treat + * non-option arguments following an -x after the zipfile as + * exclude list members. + */ + if (unzip_exclude_mode) { + while (nopts < argc && *argv[nopts] != '-') + add_pattern(&exclude, argv[nopts++]); + nopts--; /* fake argv[0] */ + nopts += getopts(argc - nopts, argv + nopts); + } + /* There may be residual arguments if we encountered -- */ while (nopts < argc) add_pattern(&include, argv[nopts++]); diff --git a/unzip/bsdunzip.h b/unzip/bsdunzip.h index 385317818..ab81e3930 100644 --- a/unzip/bsdunzip.h +++ b/unzip/bsdunzip.h @@ -48,11 +48,6 @@ struct bsdunzip { const char *argument; }; -struct bsdunzip_getopt_ret { - int index; - int opt; -}; - enum { OPTION_NONE, OPTION_VERSION diff --git a/unzip/test/test_d.c b/unzip/test/test_d.c index 64950cbbe..01ab9b8ca 100644 --- a/unzip/test/test_d.c +++ b/unzip/test/test_d.c @@ -25,8 +25,8 @@ */ #include "test.h" -/* Test d arg - extract to target dir */ -DEFINE_TEST(test_d) +/* Test d arg - extract to target dir - before zipfile argument */ +DEFINE_TEST(test_d_before_zipfile) { const char *reffile = "test_basic.zip"; int r; @@ -42,3 +42,21 @@ DEFINE_TEST(test_d) assertTextFileContents("contents c\n", "foobar/test_basic/c"); assertTextFileContents("contents CAPS\n", "foobar/test_basic/CAPS"); } + +/* Test d arg - extract to target dir - after zipfile argument */ +DEFINE_TEST(test_d_after_zipfile) +{ + const char *reffile = "test_basic.zip"; + int r; + + extract_reference_file(reffile); + r = systemf("%s %s -d foobar >test.out 2>test.err", testprog, reffile); + assertEqualInt(0, r); + assertNonEmptyFile("test.out"); + assertEmptyFile("test.err"); + + assertTextFileContents("contents a\n", "foobar/test_basic/a"); + assertTextFileContents("contents b\n", "foobar/test_basic/b"); + assertTextFileContents("contents c\n", "foobar/test_basic/c"); + assertTextFileContents("contents CAPS\n", "foobar/test_basic/CAPS"); +} diff --git a/unzip/test/test_x.c b/unzip/test/test_x.c index 21f01bf65..d55376849 100644 --- a/unzip/test/test_x.c +++ b/unzip/test/test_x.c @@ -25,8 +25,8 @@ */ #include "test.h" -/* Test x arg - Exclude paths */ -DEFINE_TEST(test_x) +/* Test x arg with single exclude path */ +DEFINE_TEST(test_x_single) { const char *reffile = "test_basic.zip"; int r; @@ -42,3 +42,39 @@ DEFINE_TEST(test_x) assertFileNotExists("test_basic/c"); assertTextFileContents("contents CAPS\n", "test_basic/CAPS"); } + +/* Test x arg with multiple exclude paths */ +DEFINE_TEST(test_x_multiple) +{ + const char *reffile = "test_basic.zip"; + int r; + + extract_reference_file(reffile); + r = systemf("%s %s -x test_basic/c test_basic/b >test.out 2>test.err", testprog, reffile); + assertEqualInt(0, r); + assertNonEmptyFile("test.out"); + assertEmptyFile("test.err"); + + assertTextFileContents("contents a\n", "test_basic/a"); + assertFileNotExists("test_basic/b"); + assertFileNotExists("test_basic/c"); + assertTextFileContents("contents CAPS\n", "test_basic/CAPS"); +} + +/* Test x arg with multiple exclude paths and a d arg afterwards */ +DEFINE_TEST(test_x_multiple_with_d) +{ + const char *reffile = "test_basic.zip"; + int r; + + extract_reference_file(reffile); + r = systemf("%s %s -x test_basic/c test_basic/b -d foobar >test.out 2>test.err", testprog, reffile); + assertEqualInt(0, r); + assertNonEmptyFile("test.out"); + assertEmptyFile("test.err"); + + assertTextFileContents("contents a\n", "foobar/test_basic/a"); + assertFileNotExists("foobar/test_basic/b"); + assertFileNotExists("foobar/test_basic/c"); + assertTextFileContents("contents CAPS\n", "foobar/test_basic/CAPS"); +}