git: 2cb0ab6bc177 - stable/13 - libarchive: merge from vendor branch

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

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

commit 2cb0ab6bc1772f2bc0d296d45b49d89f256febee
Author:     Martin Matuska <mm@FreeBSD.org>
AuthorDate: 2023-07-29 20:43:36 +0000
Commit:     Martin Matuska <mm@FreeBSD.org>
CommitDate: 2024-05-04 11:53:07 +0000

    libarchive: merge from vendor branch
    
    Libarchive 3.7.1
    
    Important changes (relevant to FreeBSD):
      ISSUE #1934: stack buffer overflow in cpio verbose mode
      ISSUE #1935: SEGV in cpio verbose mode
      PR #1731 tar: respect --strip-components and -s patterns in cru modes
    
    (cherry picked from commit 64884e0d4ce7ed57c970e1b34f93e3754c656900)
---
 contrib/libarchive/NEWS                            |   2 +
 contrib/libarchive/cpio/cpio.c                     |   7 +-
 contrib/libarchive/libarchive/archive.h            |   4 +-
 contrib/libarchive/libarchive/archive_entry.h      |   2 +-
 .../libarchive/archive_read_disk_posix.c           |   2 +-
 .../libarchive/archive_read_support_filter_bzip2.c |   4 +-
 .../libarchive/archive_read_support_filter_lz4.c   |   2 +-
 .../libarchive/archive_read_support_format_7zip.c  |   8 +-
 .../libarchive/archive_read_support_format_lha.c   |   7 +-
 .../libarchive/archive_read_support_format_rar.c   |   4 +-
 .../libarchive/archive_read_support_format_rar5.c  |   2 +-
 .../libarchive/archive_read_support_format_zip.c   |   4 +-
 .../libarchive/archive_write_add_filter_bzip2.c    |   6 +-
 .../libarchive/archive_write_add_filter_lz4.c      |   8 +-
 .../libarchive/archive_write_add_filter_zstd.c     |   4 +-
 .../libarchive/archive_write_disk_posix.c          |   7 +-
 .../libarchive/archive_write_set_format_7zip.c     |   8 +-
 contrib/libarchive/tar/write.c                     |   2 +
 contrib/libarchive/unzip/CMakeLists.txt            |  37 -
 contrib/libarchive/unzip/bsdunzip.1                |   8 +-
 contrib/libarchive/unzip/bsdunzip.c                |  56 +-
 contrib/libarchive/unzip/bsdunzip_platform.h       |   8 -
 contrib/libarchive/unzip/la_getline.c              |  99 +++
 contrib/libarchive/unzip/la_queue.h                | 840 +++++++++++++++++++++
 contrib/libarchive/unzip/test/CMakeLists.txt       |  80 --
 25 files changed, 1044 insertions(+), 167 deletions(-)

diff --git a/contrib/libarchive/NEWS b/contrib/libarchive/NEWS
index 61d1ca47340e..7509c9ce5fa1 100644
--- a/contrib/libarchive/NEWS
+++ b/contrib/libarchive/NEWS
@@ -1,3 +1,5 @@
+Jul 29, 2023: libarchive 3.7.1 released
+
 Jul 18, 2023: libarchive 3.7.0 released
 
 Jul 14, 2023: bsdunzip port from FreeBSD
diff --git a/contrib/libarchive/cpio/cpio.c b/contrib/libarchive/cpio/cpio.c
index fbeae4133091..7bd6a782b5b2 100644
--- a/contrib/libarchive/cpio/cpio.c
+++ b/contrib/libarchive/cpio/cpio.c
@@ -1146,7 +1146,7 @@ list_item_verbose(struct cpio *cpio, struct archive_entry *entry)
 {
 	char			 size[32];
 	char			 date[32];
-	char			 uids[16], gids[16];
+	char			 uids[22], gids[22];
 	const char 		*uname, *gname;
 	FILE			*out = stdout;
 	const char		*fmt;
@@ -1210,7 +1210,10 @@ list_item_verbose(struct cpio *cpio, struct archive_entry *entry)
 #else
 	ltime = localtime(&mtime);
 #endif
-	strftime(date, sizeof(date), fmt, ltime);
+	if (ltime != NULL)
+		strftime(date, sizeof(date), fmt, ltime);
+	else
+		strcpy(date, "invalid mtime");
 
 	fprintf(out, "%s%3d %-8s %-8s %8s %12s %s",
 	    archive_entry_strmode(entry),
diff --git a/contrib/libarchive/libarchive/archive.h b/contrib/libarchive/libarchive/archive.h
index 4182cc55d4a4..25e47e96c058 100644
--- a/contrib/libarchive/libarchive/archive.h
+++ b/contrib/libarchive/libarchive/archive.h
@@ -36,7 +36,7 @@
  * assert that ARCHIVE_VERSION_NUMBER >= 2012108.
  */
 /* Note: Compiler will complain if this does not match archive_entry.h! */
-#define	ARCHIVE_VERSION_NUMBER 3007000
+#define	ARCHIVE_VERSION_NUMBER 3007001
 
 #include <sys/stat.h>
 #include <stddef.h>  /* for wchar_t */
@@ -157,7 +157,7 @@ __LA_DECL int		archive_version_number(void);
 /*
  * Textual name/version of the library, useful for version displays.
  */
-#define	ARCHIVE_VERSION_ONLY_STRING "3.7.0"
+#define	ARCHIVE_VERSION_ONLY_STRING "3.7.1"
 #define	ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
 __LA_DECL const char *	archive_version_string(void);
 
diff --git a/contrib/libarchive/libarchive/archive_entry.h b/contrib/libarchive/libarchive/archive_entry.h
index 74033564396d..f6860ec9afcb 100644
--- a/contrib/libarchive/libarchive/archive_entry.h
+++ b/contrib/libarchive/libarchive/archive_entry.h
@@ -30,7 +30,7 @@
 #define	ARCHIVE_ENTRY_H_INCLUDED
 
 /* Note: Compiler will complain if this does not match archive.h! */
-#define	ARCHIVE_VERSION_NUMBER 3007000
+#define	ARCHIVE_VERSION_NUMBER 3007001
 
 /*
  * Note: archive_entry.h is for use outside of libarchive; the
diff --git a/contrib/libarchive/libarchive/archive_read_disk_posix.c b/contrib/libarchive/libarchive/archive_read_disk_posix.c
index e9657f6a72e8..8d5c32f0385e 100644
--- a/contrib/libarchive/libarchive/archive_read_disk_posix.c
+++ b/contrib/libarchive/libarchive/archive_read_disk_posix.c
@@ -1866,7 +1866,7 @@ setup_current_filesystem(struct archive_read_disk *a)
 #if defined(USE_READDIR_R)
 	/* Set maximum filename length. */
 #if defined(HAVE_STATVFS)
-	t->current_filesystem->name_max = svfs.f_namelen;
+	t->current_filesystem->name_max = svfs.f_namemax;
 #else
 	t->current_filesystem->name_max = sfs.f_namelen;
 #endif
diff --git a/contrib/libarchive/libarchive/archive_read_support_filter_bzip2.c b/contrib/libarchive/libarchive/archive_read_support_filter_bzip2.c
index 793d605c8725..9158e668eb42 100644
--- a/contrib/libarchive/libarchive/archive_read_support_filter_bzip2.c
+++ b/contrib/libarchive/libarchive/archive_read_support_filter_bzip2.c
@@ -230,7 +230,7 @@ bzip2_filter_read(struct archive_read_filter *self, const void **p)
 
 	/* Empty our output buffer. */
 	state->stream.next_out = state->out_block;
-	state->stream.avail_out = state->out_block_size;
+	state->stream.avail_out = (uint32_t)state->out_block_size;
 
 	/* Try to fill the output buffer. */
 	for (;;) {
@@ -288,7 +288,7 @@ bzip2_filter_read(struct archive_read_filter *self, const void **p)
 			return (ARCHIVE_FATAL);
 		}
 		state->stream.next_in = (char *)(uintptr_t)read_buf;
-		state->stream.avail_in = ret;
+		state->stream.avail_in = (uint32_t)ret;
 		/* There is no more data, return whatever we have. */
 		if (ret == 0) {
 			state->eof = 1;
diff --git a/contrib/libarchive/libarchive/archive_read_support_filter_lz4.c b/contrib/libarchive/libarchive/archive_read_support_filter_lz4.c
index 1e99542d7b7b..d0fc1a83e462 100644
--- a/contrib/libarchive/libarchive/archive_read_support_filter_lz4.c
+++ b/contrib/libarchive/libarchive/archive_read_support_filter_lz4.c
@@ -584,7 +584,7 @@ lz4_filter_read_data_block(struct archive_read_filter *self, const void **p)
 		    state->out_block + prefix64k, (int)compressed_size,
 		    state->flags.block_maximum_size,
 		    state->out_block,
-		    prefix64k);
+		    (int)prefix64k);
 #else
 		uncompressed_size = LZ4_decompress_safe_withPrefix64k(
 		    read_buf + 4,
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_7zip.c b/contrib/libarchive/libarchive/archive_read_support_format_7zip.c
index bb595b3e4b07..b171bea01a2f 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_7zip.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_7zip.c
@@ -1477,9 +1477,9 @@ decompress(struct archive_read *a, struct _7zip *zip,
 #if defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR)
 	case _7Z_BZ2:
 		zip->bzstream.next_in = (char *)(uintptr_t)t_next_in;
-		zip->bzstream.avail_in = t_avail_in;
+		zip->bzstream.avail_in = (uint32_t)t_avail_in;
 		zip->bzstream.next_out = (char *)(uintptr_t)t_next_out;
-		zip->bzstream.avail_out = t_avail_out;
+		zip->bzstream.avail_out = (uint32_t)t_avail_out;
 		r = BZ2_bzDecompress(&(zip->bzstream));
 		switch (r) {
 		case BZ_STREAM_END: /* Found end of stream. */
@@ -3833,7 +3833,7 @@ arm_Convert(struct _7zip *zip, uint8_t *buf, size_t size)
 		}
 	}
 
-	zip->bcj_ip += i;
+	zip->bcj_ip += (uint32_t)i;
 
 	return i;
 }
@@ -3896,7 +3896,7 @@ arm64_Convert(struct _7zip *zip, uint8_t *buf, size_t size)
 		}
 	}
 
-	zip->bcj_ip += i;
+	zip->bcj_ip += (uint32_t)i;
 
 	return i;
 }
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_lha.c b/contrib/libarchive/libarchive/archive_read_support_format_lha.c
index fa907a346408..1c64b2900b8e 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_lha.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_lha.c
@@ -1818,13 +1818,16 @@ lha_crc16(uint16_t crc, const void *pp, size_t len)
 		/* This if statement expects compiler optimization will
 		 * remove the statement which will not be executed. */
 #undef bswap16
+#ifndef __has_builtin
+#define __has_builtin(x) 0
+#endif
 #if defined(_MSC_VER) && _MSC_VER >= 1400  /* Visual Studio */
 #  define bswap16(x) _byteswap_ushort(x)
 #elif defined(__GNUC__) && ((__GNUC__ == 4 && __GNUC_MINOR__ >= 8) || __GNUC__ > 4)
 /* GCC 4.8 and later has __builtin_bswap16() */
 #  define bswap16(x) __builtin_bswap16(x)
-#elif defined(__clang__)
-/* All clang versions have __builtin_bswap16() */
+#elif defined(__clang__) && __has_builtin(__builtin_bswap16)
+/* Newer clang versions have __builtin_bswap16() */
 #  define bswap16(x) __builtin_bswap16(x)
 #else
 #  define bswap16(x) ((((x) >> 8) & 0xff) | ((x) << 8))
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_rar.c b/contrib/libarchive/libarchive/archive_read_support_format_rar.c
index 8f239da9b39d..16b6e6eed8df 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_rar.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_rar.c
@@ -1062,7 +1062,7 @@ archive_read_format_rar_read_header(struct archive_read *a,
 		      return (ARCHIVE_FATAL);
 	      }
 	      p = h;
-	      crc32_val = crc32(crc32_val, (const unsigned char *)p, to_read);
+	      crc32_val = crc32(crc32_val, (const unsigned char *)p, (unsigned int)to_read);
 	      __archive_read_consume(a, to_read);
 	      skip -= to_read;
       }
@@ -3437,7 +3437,7 @@ compile_program(const uint8_t *bytes, size_t length)
   prog = calloc(1, sizeof(*prog));
   if (!prog)
     return NULL;
-  prog->fingerprint = crc32(0, bytes, length) | ((uint64_t)length << 32);
+  prog->fingerprint = crc32(0, bytes, (unsigned int)length) | ((uint64_t)length << 32);
 
   if (membr_bits(&br, 1))
   {
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_rar5.c b/contrib/libarchive/libarchive/archive_read_support_format_rar5.c
index 38979cbe91a8..1f9099439412 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_rar5.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_rar5.c
@@ -2475,7 +2475,7 @@ static void update_crc(struct rar5* rar, const uint8_t* p, size_t to_read) {
 		 * `stored_crc32` info filled in. */
 		if(rar->file.stored_crc32 > 0) {
 			rar->file.calculated_crc32 =
-				crc32(rar->file.calculated_crc32, p, to_read);
+				crc32(rar->file.calculated_crc32, p, (unsigned int)to_read);
 		}
 
 		/* Check if the file uses an optional BLAKE2sp checksum
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_zip.c b/contrib/libarchive/libarchive/archive_read_support_format_zip.c
index 0e05ea59ce67..5ba1085857bb 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_zip.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_zip.c
@@ -2186,11 +2186,11 @@ zip_read_data_zipx_bzip2(struct archive_read *a, const void **buff,
 
 	/* Setup buffer boundaries. */
 	zip->bzstream.next_in = (char*)(uintptr_t) compressed_buff;
-	zip->bzstream.avail_in = in_bytes;
+	zip->bzstream.avail_in = (uint32_t)in_bytes;
 	zip->bzstream.total_in_hi32 = 0;
 	zip->bzstream.total_in_lo32 = 0;
 	zip->bzstream.next_out = (char*) zip->uncompressed_buffer;
-	zip->bzstream.avail_out = zip->uncompressed_buffer_size;
+	zip->bzstream.avail_out = (uint32_t)zip->uncompressed_buffer_size;
 	zip->bzstream.total_out_hi32 = 0;
 	zip->bzstream.total_out_lo32 = 0;
 
diff --git a/contrib/libarchive/libarchive/archive_write_add_filter_bzip2.c b/contrib/libarchive/libarchive/archive_write_add_filter_bzip2.c
index 7001e9c6b309..3e5c0891ae85 100644
--- a/contrib/libarchive/libarchive/archive_write_add_filter_bzip2.c
+++ b/contrib/libarchive/libarchive/archive_write_add_filter_bzip2.c
@@ -190,7 +190,7 @@ archive_compressor_bzip2_open(struct archive_write_filter *f)
 
 	memset(&data->stream, 0, sizeof(data->stream));
 	data->stream.next_out = data->compressed;
-	data->stream.avail_out = data->compressed_buffer_size;
+	data->stream.avail_out = (uint32_t)data->compressed_buffer_size;
 	f->write = archive_compressor_bzip2_write;
 
 	/* Initialize compression library */
@@ -244,7 +244,7 @@ archive_compressor_bzip2_write(struct archive_write_filter *f,
 
 	/* Compress input data to output buffer */
 	SET_NEXT_IN(data, buff);
-	data->stream.avail_in = length;
+	data->stream.avail_in = (uint32_t)length;
 	if (drive_compressor(f, data, 0))
 		return (ARCHIVE_FATAL);
 	return (ARCHIVE_OK);
@@ -313,7 +313,7 @@ drive_compressor(struct archive_write_filter *f,
 				return (ARCHIVE_FATAL);
 			}
 			data->stream.next_out = data->compressed;
-			data->stream.avail_out = data->compressed_buffer_size;
+			data->stream.avail_out = (uint32_t)data->compressed_buffer_size;
 		}
 
 		/* If there's nothing to do, we're done. */
diff --git a/contrib/libarchive/libarchive/archive_write_add_filter_lz4.c b/contrib/libarchive/libarchive/archive_write_add_filter_lz4.c
index cf19fadd5633..6ac450357d28 100644
--- a/contrib/libarchive/libarchive/archive_write_add_filter_lz4.c
+++ b/contrib/libarchive/libarchive/archive_write_add_filter_lz4.c
@@ -518,10 +518,10 @@ drive_compressor_independence(struct archive_write_filter *f, const char *p,
 	} else {
 		/* The buffer is not compressed. The compressed size was
 		 * bigger than its uncompressed size. */
-		archive_le32enc(data->out, length | 0x80000000);
+		archive_le32enc(data->out, (uint32_t)(length | 0x80000000));
 		data->out += 4;
 		memcpy(data->out, p, length);
-		outsize = length;
+		outsize = (uint32_t)length;
 	}
 	data->out += outsize;
 	if (data->block_checksum) {
@@ -603,10 +603,10 @@ drive_compressor_dependence(struct archive_write_filter *f, const char *p,
 	} else {
 		/* The buffer is not compressed. The compressed size was
 		 * bigger than its uncompressed size. */
-		archive_le32enc(data->out, length | 0x80000000);
+		archive_le32enc(data->out, (uint32_t)(length | 0x80000000));
 		data->out += 4;
 		memcpy(data->out, p, length);
-		outsize = length;
+		outsize = (uint32_t)length;
 	}
 	data->out += outsize;
 	if (data->block_checksum) {
diff --git a/contrib/libarchive/libarchive/archive_write_add_filter_zstd.c b/contrib/libarchive/libarchive/archive_write_add_filter_zstd.c
index f32258b460eb..584cfb668f05 100644
--- a/contrib/libarchive/libarchive/archive_write_add_filter_zstd.c
+++ b/contrib/libarchive/libarchive/archive_write_add_filter_zstd.c
@@ -214,7 +214,7 @@ archive_compressor_zstd_options(struct archive_write_filter *f, const char *key,
 		if (level < minimum || level > maximum) {
 			return (ARCHIVE_WARN);
 		}
-		data->compression_level = level;
+		data->compression_level = (int)level;
 		return (ARCHIVE_OK);
 	} else if (strcmp(key, "threads") == 0) {
 		intmax_t threads;
@@ -224,7 +224,7 @@ archive_compressor_zstd_options(struct archive_write_filter *f, const char *key,
 		if (threads < 0) {
 			return (ARCHIVE_WARN);
 		}
-		data->threads = threads;
+		data->threads = (int)threads;
 		return (ARCHIVE_OK);
 #if HAVE_ZSTD_H && HAVE_LIBZSTD_COMPRESSOR
 	} else if (strcmp(key, "frame-per-file") == 0) {
diff --git a/contrib/libarchive/libarchive/archive_write_disk_posix.c b/contrib/libarchive/libarchive/archive_write_disk_posix.c
index 9d52dbfb3941..aeefe93b38ef 100644
--- a/contrib/libarchive/libarchive/archive_write_disk_posix.c
+++ b/contrib/libarchive/libarchive/archive_write_disk_posix.c
@@ -1611,12 +1611,12 @@ hfs_write_data_block(struct archive_write_disk *a, const char *buff,
 			    "Seek failed");
 			return (ARCHIVE_FATAL);
 		} else if (a->offset > a->fd_offset) {
-			int64_t skip = a->offset - a->fd_offset;
+			uint64_t skip = a->offset - a->fd_offset;
 			char nullblock[1024];
 
 			memset(nullblock, 0, sizeof(nullblock));
 			while (skip > 0) {
-				if (skip > (int64_t)sizeof(nullblock))
+				if (skip > sizeof(nullblock))
 					bytes_written = hfs_write_decmpfs_block(
 					    a, nullblock, sizeof(nullblock));
 				else
@@ -1731,9 +1731,10 @@ _archive_write_disk_finish_entry(struct archive *_a)
 			else
 				r = hfs_write_data_block(
 				    a, null_d, a->file_remaining_bytes);
-			if (r < 0)
+			if (r < 0) {
 				close_file_descriptor(a);
 				return ((int)r);
+			}
 		}
 #endif
 	} else {
diff --git a/contrib/libarchive/libarchive/archive_write_set_format_7zip.c b/contrib/libarchive/libarchive/archive_write_set_format_7zip.c
index f4b34685d3d0..a5919061673d 100644
--- a/contrib/libarchive/libarchive/archive_write_set_format_7zip.c
+++ b/contrib/libarchive/libarchive/archive_write_set_format_7zip.c
@@ -1809,11 +1809,11 @@ compression_init_encoder_bzip2(struct archive *a,
 	 * of ugly hackery to convert a const * pointer to
 	 * a non-const pointer. */
 	strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
-	strm->avail_in = lastrm->avail_in;
+	strm->avail_in = (uint32_t)lastrm->avail_in;
 	strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
 	strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
 	strm->next_out = (char *)lastrm->next_out;
-	strm->avail_out = lastrm->avail_out;
+	strm->avail_out = (uint32_t)lastrm->avail_out;
 	strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
 	strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
 	if (BZ2_bzCompressInit(strm, level, 0, 30) != BZ_OK) {
@@ -1842,11 +1842,11 @@ compression_code_bzip2(struct archive *a,
 	 * of ugly hackery to convert a const * pointer to
 	 * a non-const pointer. */
 	strm->next_in = (char *)(uintptr_t)(const void *)lastrm->next_in;
-	strm->avail_in = lastrm->avail_in;
+	strm->avail_in = (uint32_t)lastrm->avail_in;
 	strm->total_in_lo32 = (uint32_t)(lastrm->total_in & 0xffffffff);
 	strm->total_in_hi32 = (uint32_t)(lastrm->total_in >> 32);
 	strm->next_out = (char *)lastrm->next_out;
-	strm->avail_out = lastrm->avail_out;
+	strm->avail_out = (uint32_t)lastrm->avail_out;
 	strm->total_out_lo32 = (uint32_t)(lastrm->total_out & 0xffffffff);
 	strm->total_out_hi32 = (uint32_t)(lastrm->total_out >> 32);
 	r = BZ2_bzCompress(strm,
diff --git a/contrib/libarchive/tar/write.c b/contrib/libarchive/tar/write.c
index b1ec470e8a30..ac35c6f7c60e 100644
--- a/contrib/libarchive/tar/write.c
+++ b/contrib/libarchive/tar/write.c
@@ -694,6 +694,8 @@ append_archive(struct bsdtar *bsdtar, struct archive *a, struct archive *ina)
 	while (ARCHIVE_OK == (e = archive_read_next_header(ina, &in_entry))) {
 		if (archive_match_excluded(bsdtar->matching, in_entry))
 			continue;
+		if(edit_pathname(bsdtar, in_entry))
+			continue;
 		if ((bsdtar->flags & OPTFLAG_INTERACTIVE) &&
 		    !yes("copy '%s'", archive_entry_pathname(in_entry)))
 			continue;
diff --git a/contrib/libarchive/unzip/CMakeLists.txt b/contrib/libarchive/unzip/CMakeLists.txt
deleted file mode 100644
index 13b983d89db7..000000000000
--- a/contrib/libarchive/unzip/CMakeLists.txt
+++ /dev/null
@@ -1,37 +0,0 @@
-############################################
-#
-# How to build bsdunzip
-#
-############################################
-IF(ENABLE_UNZIP)
-
-  SET(bsdunzip_SOURCES
-    bsdunzip.c
-    bsdunzip_platform.h
-    ../libarchive_fe/err.c
-    ../libarchive_fe/err.h
-    ../libarchive_fe/lafe_platform.h
-    ../libarchive_fe/passphrase.c
-    ../libarchive_fe/passphrase.h
-  )
-  INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../libarchive_fe)
-
-  # bsdunzip documentation
-  SET(bsdunzip_MANS bsdunzip.1)
-
-  # How to build bsdunzip
-  ADD_EXECUTABLE(bsdunzip ${bsdunzip_SOURCES})
-  IF(ENABLE_UNZIP_SHARED)
-    TARGET_LINK_LIBRARIES(bsdunzip archive ${ADDITIONAL_LIBS})
-  ELSE(ENABLE_UNZIP_SHARED)
-    TARGET_LINK_LIBRARIES(bsdunzip archive_static ${ADDITIONAL_LIBS})
-    SET_TARGET_PROPERTIES(bsdunzip PROPERTIES COMPILE_DEFINITIONS
-                                 LIBARCHIVE_STATIC)
-  ENDIF(ENABLE_UNZIP_SHARED)
-
-  # Installation rules
-  INSTALL(TARGETS bsdunzip RUNTIME DESTINATION bin)
-  INSTALL_MAN(${bsdunzip_MANS})
-ENDIF(ENABLE_UNZIP)
-
-add_subdirectory(test)
diff --git a/contrib/libarchive/unzip/bsdunzip.1 b/contrib/libarchive/unzip/bsdunzip.1
index 3c656ebc46e2..dda01e7b84d7 100644
--- a/contrib/libarchive/unzip/bsdunzip.1
+++ b/contrib/libarchive/unzip/bsdunzip.1
@@ -25,7 +25,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd January 2, 2023
+.Dd June 27, 2023
 .Dt BSDUNZIP 1
 .Os
 .Sh NAME
@@ -34,6 +34,7 @@
 .Sh SYNOPSIS
 .Nm
 .Op Fl aCcfjLlnopqtuvy
+.Op { Fl O | Fl I No } Ar encoding
 .Op Fl d Ar dir
 .Op Fl x Ar pattern
 .Op Fl P Ar password
@@ -62,6 +63,9 @@ Update existing.
 Extract only files from the zipfile if a file with the same name
 already exists on disk and is older than the former.
 Otherwise, the file is silently skipped.
+.It Fl I Ar encoding
+.It Fl O Ar encoding
+Convert filenames from the specified encoding.
 .It Fl j
 Ignore directories stored in the zipfile; instead, extract all files
 directly into the extraction directory.
@@ -123,7 +127,7 @@ Currently only
 mode 1 is supported, which lists the file names one per line.
 .It Ar [member ...]
 Optional list of members to extract from the zipfile.
-Can include patterns, e.g.
+Can include patterns, e.g.,
 .Ar 'memberdir/*'
 will extract all files and dirs below memberdir.
 .El
diff --git a/contrib/libarchive/unzip/bsdunzip.c b/contrib/libarchive/unzip/bsdunzip.c
index 469c69fd6efb..0b6506a18adc 100644
--- a/contrib/libarchive/unzip/bsdunzip.c
+++ b/contrib/libarchive/unzip/bsdunzip.c
@@ -40,6 +40,8 @@
 
 #ifdef HAVE_SYS_QUEUE_H
 #include <sys/queue.h>
+#else
+#include "la_queue.h"
 #endif
 #ifdef HAVE_SYS_STAT_H
 #include <sys/stat.h>
@@ -70,6 +72,12 @@
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
+#if ((!defined(HAVE_UTIMENSAT) && defined(HAVE_LUTIMES)) || \
+    (!defined(HAVE_FUTIMENS) && defined(HAVE_FUTIMES)))
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#endif
 
 #include <archive.h>
 #include <archive_entry.h>
@@ -82,6 +90,7 @@ 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 int		 j_opt;		/* junk directories */
 static int		 L_opt;		/* lowercase names */
 static int		 n_opt;		/* never overwrite */
@@ -628,9 +637,15 @@ extract_file(struct archive *a, struct archive_entry *e, char **path)
 	int mode;
 	struct timespec mtime;
 	struct stat sb;
-	struct timespec ts[2];
 	int fd, check, text;
 	const char *linkname;
+#if defined(HAVE_UTIMENSAT) || defined(HAVE_FUTIMENS)
+	struct timespec ts[2];
+#endif
+#if ((!defined(HAVE_UTIMENSAT) && defined(HAVE_LUTIMES)) || \
+    (!defined(HAVE_FUTIMENS) && defined(HAVE_FUTIMES)))
+	struct timeval times[2];
+#endif
 
 	mode = archive_entry_mode(e) & 0777;
 	if (mode == 0)
@@ -684,9 +699,18 @@ recheck:
 			return;
 	}
 
+#if defined(HAVE_UTIMENSAT) || defined(HAVE_FUTIMENS)
 	ts[0].tv_sec = 0;
 	ts[0].tv_nsec = UTIME_NOW;
 	ts[1] = mtime;
+#endif
+#if ((!defined(HAVE_UTIMENSAT) && defined(HAVE_LUTIMES)) || \
+    (!defined(HAVE_FUTIMENS) && defined(HAVE_FUTIMES)))
+	times[0].tv_sec = 0;
+	times[0].tv_usec = -1;
+	times[1].tv_sec = mtime.tv_sec;
+	times[1].tv_usec = mtime.tv_nsec / 1000;
+#endif
 
 	/* process symlinks */
 	linkname = archive_entry_symlink(e);
@@ -694,11 +718,19 @@ recheck:
 		if (symlink(linkname, *path) != 0)
 			error("symlink('%s')", *path);
 		info(" extracting: %s -> %s\n", *path, linkname);
+#ifdef HAVE_LCHMOD
 		if (lchmod(*path, mode) != 0)
 			warning("Cannot set mode for '%s'", *path);
+#endif
 		/* set access and modification time */
+#if defined(HAVE_UTIMENSAT)
 		if (utimensat(AT_FDCWD, *path, ts, AT_SYMLINK_NOFOLLOW) != 0)
 			warning("utimensat('%s')", *path);
+#elif defined(HAVE_LUTIMES)
+		gettimeofday(&times[0], NULL);
+		if (lutimes(*path, times) != 0)
+			warning("lutimes('%s')", *path);
+#endif
 		return;
 	}
 
@@ -716,8 +748,14 @@ recheck:
 	info("\n");
 
 	/* set access and modification time */
+#if defined(HAVE_FUTIMENS)
 	if (futimens(fd, ts) != 0)
 		error("futimens('%s')", *path);
+#elif defined(HAVE_FUTIMES)
+	gettimeofday(&times[0], NULL);
+	if (futimes(fd, times) != 0)
+		error("futimes('%s')", *path);
+#endif
 	if (close(fd) != 0)
 		error("close('%s')", *path);
 }
@@ -961,6 +999,9 @@ unzip(const char *fn)
 
 	ac(archive_read_support_format_zip(a));
 
+	if (O_arg)
+		ac(archive_read_set_format_option(a, "zip", "hdrcharset", O_arg));
+
 	if (P_arg)
 		archive_read_add_passphrase(a, P_arg);
 	else
@@ -1043,7 +1084,7 @@ usage(void)
 {
 
 	fprintf(stderr,
-"Usage: unzip [-aCcfjLlnopqtuvyZ1] [-d dir] [-x pattern] [-P password] zipfile\n"
+"Usage: unzip [-aCcfjLlnopqtuvyZ1] [{-O|-I} encoding] [-d dir] [-x pattern] [-P password] zipfile\n"
 "             [member ...]\n");
 	exit(EXIT_FAILURE);
 }
@@ -1053,8 +1094,11 @@ getopts(int argc, char *argv[])
 {
 	int opt;
 
-	optreset = optind = 1;
-	while ((opt = getopt(argc, argv, "aCcd:fjLlnopP:qtuvx:yZ1")) != -1)
+	optind = 1;
+#ifdef HAVE_GETOPT_OPTRESET
+	optreset = 1;
+#endif
+	while ((opt = getopt(argc, argv, "aCcd:fI:jLlnO:opP:qtuvx:yZ1")) != -1)
 		switch (opt) {
 		case '1':
 			Z1_opt = 1;
@@ -1074,6 +1118,10 @@ getopts(int argc, char *argv[])
 		case 'f':
 			f_opt = 1;
 			break;
+		case 'I':
+		case 'O':
+			O_arg = optarg;
+			break;
 		case 'j':
 			j_opt = 1;
 			break;
diff --git a/contrib/libarchive/unzip/bsdunzip_platform.h b/contrib/libarchive/unzip/bsdunzip_platform.h
index 5aff5f208eab..76eca4f90902 100644
--- a/contrib/libarchive/unzip/bsdunzip_platform.h
+++ b/contrib/libarchive/unzip/bsdunzip_platform.h
@@ -62,14 +62,6 @@
 #include "archive_entry.h"
 #endif
 
-#ifndef HAVE_GETOPT_OPTRESET
-/*
- * If platform doesn't use optreset for resetting getopt, declare it so
- * C source doesn't have to know this platform-specific difference
- */
-int optreset;
-#endif
-
 /* How to mark functions that don't return. */
 /* This facilitates use of some newer static code analysis tools. */
 #undef __LA_DEAD
diff --git a/contrib/libarchive/unzip/la_getline.c b/contrib/libarchive/unzip/la_getline.c
new file mode 100644
index 000000000000..79a6bc010214
--- /dev/null
+++ b/contrib/libarchive/unzip/la_getline.c
@@ -0,0 +1,99 @@
+/*	$NetBSD: getline.c,v 1.2 2014/09/16 17:23:50 christos Exp $	*/
+
+/*-
+ * Copyright (c) 2011 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Christos Zoulas.
+ *
+ * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``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 FOUNDATION OR CONTRIBUTORS
+ * 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 "bsdunzip_platform.h"
+#ifndef HAVE_GETLINE
+
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+static ssize_t
+la_getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp)
+{
+	char *ptr, *eptr;
+
+
+	if (*buf == NULL || *bufsiz == 0) {
+		*bufsiz = BUFSIZ;
+		if ((*buf = malloc(*bufsiz)) == NULL)
+			return -1;
+	}
+
+	for (ptr = *buf, eptr = *buf + *bufsiz;;) {
+		int c = fgetc(fp);
+		if (c == -1) {
+			if (feof(fp)) {
+				ssize_t diff = (ssize_t)(ptr - *buf);
+				if (diff != 0) {
+					*ptr = '\0';
+					return diff;
+				}
+			}
+			return -1;
+		}
+		*ptr++ = c;
+		if (c == delimiter) {
+			*ptr = '\0';
+			return ptr - *buf;
+		}
+		if (ptr + 2 >= eptr) {
+			char *nbuf;
+			size_t nbufsiz = *bufsiz * 2;
+			ssize_t d = ptr - *buf;
+			if ((nbuf = realloc(*buf, nbufsiz)) == NULL)
+				return -1;
+			*buf = nbuf;
+			*bufsiz = nbufsiz;
+			eptr = nbuf + nbufsiz;
+			ptr = nbuf + d;
+		}
+	}
+}
+
+ssize_t
+getline(char **buf, size_t *bufsiz, FILE *fp)
+{
+	return la_getdelim(buf, bufsiz, '\n', fp);
+}
+#endif
diff --git a/contrib/libarchive/unzip/la_queue.h b/contrib/libarchive/unzip/la_queue.h
new file mode 100644
index 000000000000..917526531b2a
--- /dev/null
+++ b/contrib/libarchive/unzip/la_queue.h
@@ -0,0 +1,840 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ *
+ * Copyright (c) 1991, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ */
+
+#ifndef _SYS_QUEUE_H_
+#define	_SYS_QUEUE_H_
+
+/*
+ * This file defines four types of data structures: singly-linked lists,
+ * singly-linked tail queues, lists and tail queues.
+ *
+ * A singly-linked list is headed by a single forward pointer. The elements
+ * are singly linked for minimum space and pointer manipulation overhead at
+ * the expense of O(n) removal for arbitrary elements. New elements can be
+ * added to the list after an existing element or at the head of the list.
+ * Elements being removed from the head of the list should use the explicit
+ * macro for this purpose for optimum efficiency. A singly-linked list may
+ * only be traversed in the forward direction.  Singly-linked lists are ideal
+ * for applications with large datasets and few or no removals or for
+ * implementing a LIFO queue.
+ *
+ * A singly-linked tail queue is headed by a pair of pointers, one to the
+ * head of the list and the other to the tail of the list. The elements are
+ * singly linked for minimum space and pointer manipulation overhead at the
+ * expense of O(n) removal for arbitrary elements. New elements can be added
+ * to the list after an existing element, at the head of the list, or at the
+ * end of the list. Elements being removed from the head of the tail queue
+ * should use the explicit macro for this purpose for optimum efficiency.
+ * A singly-linked tail queue may only be traversed in the forward direction.
+ * Singly-linked tail queues are ideal for applications with large datasets
+ * and few or no removals or for implementing a FIFO queue.
+ *
+ * A list is headed by a single forward pointer (or an array of forward
+ * pointers for a hash table header). The elements are doubly linked
+ * so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before
+ * or after an existing element or at the head of the list. A list
+ * may be traversed in either direction.
+ *
+ * A tail queue is headed by a pair of pointers, one to the head of the
+ * list and the other to the tail of the list. The elements are doubly
+ * linked so that an arbitrary element can be removed without a need to
+ * traverse the list. New elements can be added to the list before or
+ * after an existing element, at the head of the list, or at the end of
+ * the list. A tail queue may be traversed in either direction.
+ *
+ * For details on the use of these macros, see the queue(3) manual page.
+ *
+ * Below is a summary of implemented functions where:
+ *  +  means the macro is available
+ *  -  means the macro is not available
+ *  s  means the macro is available but is slow (runs in O(n) time)
+ *
+ *				SLIST	LIST	STAILQ	TAILQ
+ * _HEAD			+	+	+	+
+ * _CLASS_HEAD			+	+	+	+
+ * _HEAD_INITIALIZER		+	+	+	+
+ * _ENTRY			+	+	+	+
+ * _CLASS_ENTRY			+	+	+	+
+ * _INIT			+	+	+	+
+ * _EMPTY			+	+	+	+
+ * _FIRST			+	+	+	+
+ * _NEXT			+	+	+	+
+ * _PREV			-	+	-	+
+ * _LAST			-	-	+	+
+ * _LAST_FAST			-	-	-	+
+ * _FOREACH			+	+	+	+
+ * _FOREACH_FROM		+	+	+	+
+ * _FOREACH_SAFE		+	+	+	+
+ * _FOREACH_FROM_SAFE		+	+	+	+
+ * _FOREACH_REVERSE		-	-	-	+
+ * _FOREACH_REVERSE_FROM	-	-	-	+
+ * _FOREACH_REVERSE_SAFE	-	-	-	+
+ * _FOREACH_REVERSE_FROM_SAFE	-	-	-	+
+ * _INSERT_HEAD			+	+	+	+
+ * _INSERT_BEFORE		-	+	-	+
+ * _INSERT_AFTER		+	+	+	+
+ * _INSERT_TAIL			-	-	+	+
+ * _CONCAT			s	s	+	+
+ * _REMOVE_AFTER		+	-	+	-
+ * _REMOVE_HEAD			+	-	+	-
+ * _REMOVE			s	+	s	+
+ * _SWAP			+	+	+	+
+ */
+#ifdef QUEUE_MACRO_DEBUG
+#warn Use QUEUE_MACRO_DEBUG_TRACE and/or QUEUE_MACRO_DEBUG_TRASH
+#define	QUEUE_MACRO_DEBUG_TRACE
+#define	QUEUE_MACRO_DEBUG_TRASH
+#endif
+
+#ifdef QUEUE_MACRO_DEBUG_TRACE
+/* Store the last 2 places the queue element or head was altered */
+struct qm_trace {
+	unsigned long	 lastline;
+	unsigned long	 prevline;
+	const char	*lastfile;
+	const char	*prevfile;
+};
+
+#define	TRACEBUF	struct qm_trace trace;
+#define	TRACEBUF_INITIALIZER	{ __LINE__, 0, __FILE__, NULL } ,
+
+#define	QMD_TRACE_HEAD(head) do {					\
+	(head)->trace.prevline = (head)->trace.lastline;		\
+	(head)->trace.prevfile = (head)->trace.lastfile;		\
+	(head)->trace.lastline = __LINE__;				\
+	(head)->trace.lastfile = __FILE__;				\
+} while (0)
+
+#define	QMD_TRACE_ELEM(elem) do {					\
+	(elem)->trace.prevline = (elem)->trace.lastline;		\
+	(elem)->trace.prevfile = (elem)->trace.lastfile;		\
+	(elem)->trace.lastline = __LINE__;				\
+	(elem)->trace.lastfile = __FILE__;				\
+} while (0)
+
+#else	/* !QUEUE_MACRO_DEBUG_TRACE */
+#define	QMD_TRACE_ELEM(elem)
+#define	QMD_TRACE_HEAD(head)
+#define	TRACEBUF
+#define	TRACEBUF_INITIALIZER
+#endif	/* QUEUE_MACRO_DEBUG_TRACE */
+
+#ifdef QUEUE_MACRO_DEBUG_TRASH
+#define	QMD_SAVELINK(name, link)	void **name = (void *)&(link)
+#define	TRASHIT(x)		do {(x) = (void *)-1;} while (0)
+#define	QMD_IS_TRASHED(x)	((x) == (void *)(intptr_t)-1)
+#else	/* !QUEUE_MACRO_DEBUG_TRASH */
+#define	QMD_SAVELINK(name, link)
+#define	TRASHIT(x)
+#define	QMD_IS_TRASHED(x)	0
+#endif	/* QUEUE_MACRO_DEBUG_TRASH */
+
+#ifdef __cplusplus
+/*
+ * In C++ there can be structure lists and class lists:
+ */
+#define	QUEUE_TYPEOF(type) type
+#else
+#define	QUEUE_TYPEOF(type) struct type
+#endif
+
+/*
+ * Singly-linked List declarations.
+ */
+#define	SLIST_HEAD(name, type)						\
+struct name {								\
+	struct type *slh_first;	/* first element */			\
+}
+
+#define	SLIST_CLASS_HEAD(name, type)					\
+struct name {								\
+	class type *slh_first;	/* first element */			\
+}
+
+#define	SLIST_HEAD_INITIALIZER(head)					\
+	{ NULL }
+
+#define	SLIST_ENTRY(type)						\
+struct {								\
+	struct type *sle_next;	/* next element */			\
+}
+
+#define	SLIST_CLASS_ENTRY(type)						\
+struct {								\
+	class type *sle_next;		/* next element */		\
+}
+
+/*
+ * Singly-linked List functions.
+ */
+#if (defined(_KERNEL) && defined(INVARIANTS))
+#define	QMD_SLIST_CHECK_PREVPTR(prevp, elm) do {			\
+	if (*(prevp) != (elm))						\
+		panic("Bad prevptr *(%p) == %p != %p",			\
+		    (prevp), *(prevp), (elm));				\
+} while (0)
+#else
+#define	QMD_SLIST_CHECK_PREVPTR(prevp, elm)
+#endif
+
+#define SLIST_CONCAT(head1, head2, type, field) do {			\
+	QUEUE_TYPEOF(type) *curelm = SLIST_FIRST(head1);		\
+	if (curelm == NULL) {						\
+		if ((SLIST_FIRST(head1) = SLIST_FIRST(head2)) != NULL)	\
+			SLIST_INIT(head2);				\
+	} else if (SLIST_FIRST(head2) != NULL) {			\
*** 737 LINES SKIPPED ***