git: 0db84579ce20 - stable/13 - libarchive: merge from vendor branch

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

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

commit 0db84579ce2024b674062d961f1e3e26a253ffdd
Author:     Martin Matuska <mm@FreeBSD.org>
AuthorDate: 2023-07-31 11:13:30 +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 d91bfe0fb7faab2e1f0b8e160b0cf59afb8576c4)
---
 contrib/libarchive/cat/cmdline.c             |  12 +-
 contrib/libarchive/unzip/bsdunzip.c          |  66 +++++--
 contrib/libarchive/unzip/bsdunzip.h          |  63 +++++++
 contrib/libarchive/unzip/cmdline.c           | 250 +++++++++++++++++++++++++++
 contrib/libarchive/unzip/test/test.h         |   2 +-
 contrib/libarchive/unzip/test/test_version.c |  34 ++++
 6 files changed, 402 insertions(+), 25 deletions(-)

diff --git a/contrib/libarchive/cat/cmdline.c b/contrib/libarchive/cat/cmdline.c
index cae19beb7d4c..3c4b7a8c4b9e 100644
--- a/contrib/libarchive/cat/cmdline.c
+++ b/contrib/libarchive/cat/cmdline.c
@@ -24,7 +24,7 @@
  */
 
 /*
- * Command line parser for tar.
+ * Command line parser for bsdcat.
  */
 
 #include "bsdcat_platform.h"
@@ -44,12 +44,12 @@ __FBSDID("$FreeBSD$");
 #include "err.h"
 
 /*
- * Short options for tar.  Please keep this sorted.
+ * Short options for bsdcat.  Please keep this sorted.
  */
 static const char *short_options = "h";
 
 /*
- * Long options for tar.  Please keep this list sorted.
+ * Long options for bsdcat.  Please keep this list sorted.
  *
  * The symbolic names for options that lack a short equivalent are
  * defined in bsdcat.h.  Also note that so far I've found no need
@@ -61,7 +61,7 @@ static const struct bsdcat_option {
 	const char *name;
 	int required;      /* 1 if this option requires an argument. */
 	int equivalent;    /* Equivalent short option. */
-} tar_longopts[] = {
+} bsdcat_longopts[] = {
 	{ "help",                 0, 'h' },
 	{ "version",              0, OPTION_VERSION },
 	{ NULL, 0, 0 }
@@ -90,7 +90,7 @@ static const struct bsdcat_option {
  * -W long options: There's an obscure GNU convention (only rarely
  * supported even there) that allows "-W option=argument" as an
  * alternative way to support long options.  This was supported in
- * early bsdcat as a way to access long options on platforms that did
+ * early bsdtar as a way to access long options on platforms that did
  * not support getopt_long() and is preserved here for backwards
  * compatibility.  (Of course, if I'd started with a custom
  * command-line parser from the beginning, I would have had normal
@@ -223,7 +223,7 @@ bsdcat_getopt(struct bsdcat *bsdcat)
 		}
 
 		/* Search the table for an unambiguous match. */
-		for (popt = tar_longopts; popt->name != NULL; popt++) {
+		for (popt = bsdcat_longopts; popt->name != NULL; popt++) {
 			/* Short-circuit if first chars don't match. */
 			if (popt->name[0] != bsdcat->getopt_word[0])
 				continue;
diff --git a/contrib/libarchive/unzip/bsdunzip.c b/contrib/libarchive/unzip/bsdunzip.c
index 0b6506a18adc..b8f6ff4bbf95 100644
--- a/contrib/libarchive/unzip/bsdunzip.c
+++ b/contrib/libarchive/unzip/bsdunzip.c
@@ -79,8 +79,7 @@
 #endif
 #endif
 
-#include <archive.h>
-#include <archive_entry.h>
+#include "bsdunzip.h"
 #include "passphrase.h"
 #include "err.h"
 
@@ -90,19 +89,20 @@ static int		 C_opt;		/* match case-insensitively */
 static int		 c_opt;		/* extract to stdout */
 static const char	*d_arg;		/* directory */
 static int		 f_opt;		/* update existing files only */
-static char		*O_arg;		/* encoding */
+static const char	*O_arg;		/* encoding */
 static int		 j_opt;		/* junk directories */
 static int		 L_opt;		/* lowercase names */
 static int		 n_opt;		/* never overwrite */
 static int		 o_opt;		/* always overwrite */
 static int		 p_opt;		/* extract to stdout, quiet */
-static char		*P_arg;		/* passphrase */
+static const char	*P_arg;		/* passphrase */
 static int		 q_opt;		/* quiet */
 static int		 t_opt;		/* test */
 static int		 u_opt;		/* update */
 static int		 v_opt;		/* verbose/list */
 static const char	*y_str = "";	/* 4 digit year */
 static int		 Z1_opt;	/* zipinfo mode list files only */
+static int		 version_opt;	/* version string */
 
 /* debug flag */
 static int		 unzip_debug;
@@ -113,6 +113,8 @@ static int		 zipinfo_mode;
 /* running on tty? */
 static int		 tty;
 
+int bsdunzip_optind;
+
 /* convenience macro */
 /* XXX should differentiate between ARCHIVE_{WARN,FAIL,RETRY} */
 #define ac(call)						\
@@ -1089,20 +1091,30 @@ usage(void)
 	exit(EXIT_FAILURE);
 }
 
+static void
+version(void)
+{
+        printf("bsdunzip %s - %s \n",
+            BSDUNZIP_VERSION_STRING,
+            archive_version_details());
+        exit(0);
+}
+
 static int
 getopts(int argc, char *argv[])
 {
+	struct bsdunzip *bsdunzip, bsdunzip_storage;
 	int opt;
+	bsdunzip_optind = 1;
 
-	optind = 1;
-#ifdef HAVE_GETOPT_OPTRESET
-	optreset = 1;
-#endif
-	while ((opt = getopt(argc, argv, "aCcd:fI:jLlnO:opP:qtuvx:yZ1")) != -1)
+	bsdunzip = &bsdunzip_storage;
+	memset(bsdunzip, 0, sizeof(*bsdunzip));
+
+        bsdunzip->argv = argv;
+        bsdunzip->argc = argc;
+
+	while ((opt = bsdunzip_getopt(bsdunzip)) != -1) {
 		switch (opt) {
-		case '1':
-			Z1_opt = 1;
-			break;
 		case 'a':
 			a_opt = 1;
 			break;
@@ -1113,14 +1125,14 @@ getopts(int argc, char *argv[])
 			c_opt = 1;
 			break;
 		case 'd':
-			d_arg = optarg;
+			d_arg = bsdunzip->argument;
 			break;
 		case 'f':
 			f_opt = 1;
 			break;
 		case 'I':
 		case 'O':
-			O_arg = optarg;
+			O_arg = bsdunzip->argument;
 			break;
 		case 'j':
 			j_opt = 1;
@@ -1143,7 +1155,7 @@ getopts(int argc, char *argv[])
 			p_opt = 1;
 			break;
 		case 'P':
-			P_arg = optarg;
+			P_arg = bsdunzip->argument;
 			break;
 		case 'q':
 			q_opt = 1;
@@ -1158,19 +1170,30 @@ getopts(int argc, char *argv[])
 			v_opt = 2;
 			break;
 		case 'x':
-			add_pattern(&exclude, optarg);
+			add_pattern(&exclude, bsdunzip->argument);
 			break;
 		case 'y':
 			y_str = "  ";
 			break;
 		case 'Z':
 			zipinfo_mode = 1;
+			if (bsdunzip->argument != NULL &&
+			    strcmp(bsdunzip->argument, "1") == 0) {
+				Z1_opt = 1;
+			}
+			break;
+		case OPTION_VERSION:
+			version_opt = 1;
+			break;
+		case OPTION_NONE:
 			break;
 		default:
 			usage();
 		}
-
-	return (optind);
+		if (opt == OPTION_NONE)
+			break;
+	}
+	return (bsdunzip_optind);
 }
 
 int
@@ -1179,6 +1202,8 @@ main(int argc, char *argv[])
 	const char *zipfile;
 	int nopts;
 
+	lafe_setprogname(*argv, "bsdunzip");
+
 	if (isatty(STDOUT_FILENO))
 		tty = 1;
 
@@ -1199,6 +1224,11 @@ main(int argc, char *argv[])
 	 */
 	nopts = getopts(argc, argv);
 
+	if (version_opt == 1) {
+		version();
+		exit(EXIT_SUCCESS);
+	}
+
 	/*
 	 * When more of the zipinfo mode options are implemented, this
 	 * will need to change.
diff --git a/contrib/libarchive/unzip/bsdunzip.h b/contrib/libarchive/unzip/bsdunzip.h
new file mode 100644
index 000000000000..12b65cefb466
--- /dev/null
+++ b/contrib/libarchive/unzip/bsdunzip.h
@@ -0,0 +1,63 @@
+/*-
+ * Copyright (c) 2023, Martin Matuska
+ * 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.
+ */
+
+#ifndef BSDUNZIP_H_INCLUDED
+#define BSDUNZIP_H_INCLUDED
+
+#if defined(PLATFORM_CONFIG_H)
+/* Use hand-built config.h in environments that need it. */
+#include PLATFORM_CONFIG_H
+#else
+/* Not having a config.h of some sort is a serious problem. */
+#include "config.h"
+#endif
+
+#include <archive.h>
+#include <archive_entry.h>
+
+struct bsdunzip {
+	/* Option parser state */
+	int		  getopt_state;
+	char		 *getopt_word;
+
+	/* Miscellaneous state information */
+	int		  argc;
+	char		**argv;
+	const char	 *argument;
+};
+
+struct bsdunzip_getopt_ret {
+	int		index;
+	int		opt;
+};
+
+enum {
+	OPTION_NONE,
+	OPTION_VERSION
+};
+
+int bsdunzip_getopt(struct bsdunzip *);
+
+#endif
diff --git a/contrib/libarchive/unzip/cmdline.c b/contrib/libarchive/unzip/cmdline.c
new file mode 100644
index 000000000000..95d4f99b8242
--- /dev/null
+++ b/contrib/libarchive/unzip/cmdline.c
@@ -0,0 +1,250 @@
+/*-
+ * Copyright (c) 2003-2008 Tim Kientzle
+ * 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.
+ */
+
+/*
+ * Command line parser for bsdunzip.
+ */
+
+#include "bsdunzip_platform.h"
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "bsdunzip.h"
+#include "err.h"
+
+extern int bsdunzip_optind;
+
+/*
+ * Short options for bsdunzip.  Please keep this sorted.
+ */
+static const char *short_options
+	= "aCcd:fI:jLlnO:opP:qtuvx:yZ:";
+
+/*
+ * Long options for bsdunzip.  Please keep this list sorted.
+ *
+ * The symbolic names for options that lack a short equivalent are
+ * defined in bsdunzip.h.  Also note that so far I've found no need
+ * to support optional arguments to long options.  That would be
+ * a small change to the code below.
+ */
+
+static const struct bsdunzip_option {
+	const char *name;
+	int required;      /* 1 if this option requires an argument. */
+	int equivalent;    /* Equivalent short option. */
+} bsdunzip_longopts[] = {
+	{ "version", 0, OPTION_VERSION },
+	{ NULL, 0, 0 }
+};
+
+/*
+ * This getopt implementation has two key features that common
+ * getopt_long() implementations lack.  Apart from those, it's a
+ * straightforward option parser, considerably simplified by not
+ * needing to support the wealth of exotic getopt_long() features.  It
+ * has, of course, been shamelessly tailored for bsdunzip.  (If you're
+ * looking for a generic getopt_long() implementation for your
+ * project, I recommend Gregory Pietsch's public domain getopt_long()
+ * implementation.)  The two additional features are:
+ */
+
+int
+bsdunzip_getopt(struct bsdunzip *bsdunzip)
+{
+	enum { state_start = 0, state_next_word, state_short, state_long };
+
+	const struct bsdunzip_option *popt, *match = NULL, *match2 = NULL;
+	const char *p, *long_prefix = "--";
+	size_t optlength;
+	int opt = OPTION_NONE;
+	int required = 0;
+
+	bsdunzip->argument = NULL;
+
+	/* First time through, initialize everything. */
+	if (bsdunzip->getopt_state == state_start) {
+		/* Skip program name. */
+		++bsdunzip->argv;
+		--bsdunzip->argc;
+		if (*bsdunzip->argv == NULL)
+			return (-1);
+		bsdunzip->getopt_state = state_next_word;
+	}
+
+	/*
+	 * We're ready to look at the next word in argv.
+	 */
+	if (bsdunzip->getopt_state == state_next_word) {
+		/* No more arguments, so no more options. */
+		if (bsdunzip->argv[0] == NULL)
+			return (-1);
+		/* Doesn't start with '-', so no more options. */
+		if (bsdunzip->argv[0][0] != '-')
+			return (-1);
+		/* "--" marks end of options; consume it and return. */
+		if (strcmp(bsdunzip->argv[0], "--") == 0) {
+			++bsdunzip->argv;
+			--bsdunzip->argc;
+			return (-1);
+		}
+		/* Get next word for parsing. */
+		bsdunzip->getopt_word = *bsdunzip->argv++;
+		--bsdunzip->argc;
+		bsdunzip_optind++;
+		if (bsdunzip->getopt_word[1] == '-') {
+			/* Set up long option parser. */
+			bsdunzip->getopt_state = state_long;
+			bsdunzip->getopt_word += 2; /* Skip leading '--' */
+		} else {
+			/* Set up short option parser. */
+			bsdunzip->getopt_state = state_short;
+			++bsdunzip->getopt_word;  /* Skip leading '-' */
+		}
+	}
+
+	/*
+	 * We're parsing a group of POSIX-style single-character options.
+	 */
+	if (bsdunzip->getopt_state == state_short) {
+		/* Peel next option off of a group of short options. */
+		opt = *bsdunzip->getopt_word++;
+		if (opt == '\0') {
+			/* End of this group; recurse to get next option. */
+			bsdunzip->getopt_state = state_next_word;
+			return bsdunzip_getopt(bsdunzip);
+		}
+
+		/* Does this option take an argument? */
+		p = strchr(short_options, opt);
+		if (p == NULL)
+			return ('?');
+		if (p[1] == ':')
+			required = 1;
+
+		/* If it takes an argument, parse that. */
+		if (required) {
+			/* If arg is run-in, bsdunzip->getopt_word already points to it. */
+			if (bsdunzip->getopt_word[0] == '\0') {
+				/* Otherwise, pick up the next word. */
+				bsdunzip->getopt_word = *bsdunzip->argv;
+				if (bsdunzip->getopt_word == NULL) {
+					lafe_warnc(0,
+					    "Option -%c requires an argument",
+					    opt);
+					return ('?');
+				}
+				++bsdunzip->argv;
+				--bsdunzip->argc;
+				bsdunzip_optind++;
+			}
+			bsdunzip->getopt_state = state_next_word;
+			bsdunzip->argument = bsdunzip->getopt_word;
+		}
+	}
+
+	/* We're reading a long option */
+	if (bsdunzip->getopt_state == state_long) {
+		/* After this long option, we'll be starting a new word. */
+		bsdunzip->getopt_state = state_next_word;
+
+		/* Option name ends at '=' if there is one. */
+		p = strchr(bsdunzip->getopt_word, '=');
+		if (p != NULL) {
+			optlength = (size_t)(p - bsdunzip->getopt_word);
+			bsdunzip->argument = (char *)(uintptr_t)(p + 1);
+		} else {
+			optlength = strlen(bsdunzip->getopt_word);
+		}
+
+		/* Search the table for an unambiguous match. */
+		for (popt = bsdunzip_longopts; popt->name != NULL; popt++) {
+			/* Short-circuit if first chars don't match. */
+			if (popt->name[0] != bsdunzip->getopt_word[0])
+				continue;
+			/* If option is a prefix of name in table, record it.*/
+			if (strncmp(bsdunzip->getopt_word, popt->name, optlength) == 0) {
+				match2 = match; /* Record up to two matches. */
+				match = popt;
+				/* If it's an exact match, we're done. */
+				if (strlen(popt->name) == optlength) {
+					match2 = NULL; /* Forget the others. */
+					break;
+				}
+			}
+		}
+
+		/* Fail if there wasn't a unique match. */
+		if (match == NULL) {
+			lafe_warnc(0,
+			    "Option %s%s is not supported",
+			    long_prefix, bsdunzip->getopt_word);
+			return ('?');
+		}
+		if (match2 != NULL) {
+			lafe_warnc(0,
+			    "Ambiguous option %s%s (matches --%s and --%s)",
+			    long_prefix, bsdunzip->getopt_word, match->name, match2->name);
+			return ('?');
+		}
+
+		/* We've found a unique match; does it need an argument? */
+		if (match->required) {
+			/* Argument required: get next word if necessary. */
+			if (bsdunzip->argument == NULL) {
+				bsdunzip->argument = *bsdunzip->argv;
+				if (bsdunzip->argument == NULL) {
+					lafe_warnc(0,
+					    "Option %s%s requires an argument",
+					    long_prefix, match->name);
+					return ('?');
+				}
+				++bsdunzip->argv;
+				--bsdunzip->argc;
+				bsdunzip_optind++;
+			}
+		} else {
+			/* Argument forbidden: fail if there is one. */
+			if (bsdunzip->argument != NULL) {
+				lafe_warnc(0,
+				    "Option %s%s does not allow an argument",
+				    long_prefix, match->name);
+				return ('?');
+			}
+		}
+		return (match->equivalent);
+	}
+
+	return (opt);
+}
diff --git a/contrib/libarchive/unzip/test/test.h b/contrib/libarchive/unzip/test/test.h
index 8da017f68e16..ba876afd8e24 100644
--- a/contrib/libarchive/unzip/test/test.h
+++ b/contrib/libarchive/unzip/test/test.h
@@ -35,6 +35,6 @@
 #undef	EXTRA_DUMP	  /* How to dump extra data */
 #undef	EXTRA_ERRNO	  /* How to dump errno */
 /* How to generate extra version info. */
-#define	EXTRA_VERSION     (systemf("%s -v", testprog) ? "" : "")
+#define	EXTRA_VERSION     (systemf("%s --version", testprog) ? "" : "")
 
 #include "test_common.h"
diff --git a/contrib/libarchive/unzip/test/test_version.c b/contrib/libarchive/unzip/test/test_version.c
new file mode 100644
index 000000000000..efa797982d57
--- /dev/null
+++ b/contrib/libarchive/unzip/test/test_version.c
@@ -0,0 +1,34 @@
+/*-
+ * Copyright (c) 2003-2017 Tim Kientzle
+ * 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"
+
+/*
+ * Test that --version option works and generates reasonable output.
+ */
+
+DEFINE_TEST(test_version)
+{
+	assertVersion(testprog, "bsdunzip");
+}