git: db2cc817faf9 - stable/13 - libarchive: merge from vendor branch

From: Martin Matuska <mm_at_FreeBSD.org>
Date: Sat, 04 May 2024 12:37:37 UTC
The branch stable/13 has been updated by mm:

URL: https://cgit.FreeBSD.org/src/commit/?id=db2cc817faf924bd898046547dde984162f806ec

commit db2cc817faf924bd898046547dde984162f806ec
Author:     Martin Matuska <mm@FreeBSD.org>
AuthorDate: 2023-08-03 23:04:14 +0000
Commit:     Martin Matuska <mm@FreeBSD.org>
CommitDate: 2024-05-04 11:53:07 +0000

    libarchive: merge from vendor branch
    
    Changes to not yet connected unzip only.
    
    (cherry picked from commit 058ab969fd2f7a8d04240d1e9bc9d63918480226)
---
 contrib/libarchive/unzip/bsdunzip.c    | 19 ++++++++++++++++
 contrib/libarchive/unzip/bsdunzip.h    |  7 ++----
 contrib/libarchive/unzip/cmdline.c     |  2 --
 contrib/libarchive/unzip/test/test_d.c | 22 +++++++++++++++++--
 contrib/libarchive/unzip/test/test_x.c | 40 ++++++++++++++++++++++++++++++++--
 5 files changed, 79 insertions(+), 11 deletions(-)

diff --git a/contrib/libarchive/unzip/bsdunzip.c b/contrib/libarchive/unzip/bsdunzip.c
index b8f6ff4bbf95..29c3a1670483 100644
--- a/contrib/libarchive/unzip/bsdunzip.c
+++ b/contrib/libarchive/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/contrib/libarchive/unzip/bsdunzip.h b/contrib/libarchive/unzip/bsdunzip.h
index 12b65cefb466..ab81e3930ec2 100644
--- a/contrib/libarchive/unzip/bsdunzip.h
+++ b/contrib/libarchive/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
@@ -60,4 +55,6 @@ enum {
 
 int bsdunzip_getopt(struct bsdunzip *);
 
+extern int bsdunzip_optind;
+
 #endif
diff --git a/contrib/libarchive/unzip/cmdline.c b/contrib/libarchive/unzip/cmdline.c
index 95d4f99b8242..76eb423de116 100644
--- a/contrib/libarchive/unzip/cmdline.c
+++ b/contrib/libarchive/unzip/cmdline.c
@@ -43,8 +43,6 @@ __FBSDID("$FreeBSD$");
 #include "bsdunzip.h"
 #include "err.h"
 
-extern int bsdunzip_optind;
-
 /*
  * Short options for bsdunzip.  Please keep this sorted.
  */
diff --git a/contrib/libarchive/unzip/test/test_d.c b/contrib/libarchive/unzip/test/test_d.c
index 64950cbbe165..01ab9b8caaa3 100644
--- a/contrib/libarchive/unzip/test/test_d.c
+++ b/contrib/libarchive/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/contrib/libarchive/unzip/test/test_x.c b/contrib/libarchive/unzip/test/test_x.c
index 21f01bf65da8..d55376849ce9 100644
--- a/contrib/libarchive/unzip/test/test_x.c
+++ b/contrib/libarchive/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");
+}