]> git.ipfire.org Git - thirdparty/libarchive.git/commitdiff
unzip: correctly handle arguments following an -x after zipfile
authorMartin Matuska <martin@matuska.de>
Thu, 3 Aug 2023 22:13:51 +0000 (00:13 +0200)
committerMartin Matuska <martin@matuska.de>
Thu, 3 Aug 2023 22:19:29 +0000 (00:19 +0200)
unzip/bsdunzip.c
unzip/bsdunzip.h
unzip/test/test_d.c
unzip/test/test_x.c

index b8f6ff4bbf95ffd7562903a46db611678dc51f21..29c3a1670483225eae89de9d6ca30dba2b98cfd1 100644 (file)
@@ -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++]);
index 3853178189c79b09f1b203c08566fcff9c71d9df..ab81e3930ec2258dbf69f7875c9c807eebb1d994 100644 (file)
@@ -48,11 +48,6 @@ struct bsdunzip {
        const char       *argument;
 };
 
-struct bsdunzip_getopt_ret {
-       int             index;
-       int             opt;
-};
-
 enum {
        OPTION_NONE,
        OPTION_VERSION
index 64950cbbe1657eac7103a056d0c143a4bfcece94..01ab9b8caaa3c76257a04c55396e7055182101e3 100644 (file)
@@ -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");
+}
index 21f01bf65da89af6e5f03cf898855b7e9e710cd5..d55376849ce949bf447aaf890e5c26e665b2d109 100644 (file)
@@ -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");
+}