git: 80c954a926c6 - stable/15 - libarchive: merge from vendor branch

From: Martin Matuska <mm_at_FreeBSD.org>
Date: Tue, 03 Nov 2026 14:22:34 UTC
The branch stable/15 has been updated by mm:

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

commit 80c954a926c6ac4a7dda462423fd732f4ce06f40
Author:     Martin Matuska <mm@FreeBSD.org>
AuthorDate: 2026-10-31 23:39:49 +0000
Commit:     Martin Matuska <mm@FreeBSD.org>
CommitDate: 2026-11-03 14:22:05 +0000

    libarchive: merge from vendor branch
    
    libarchive 3.8.11
    
    ChangeLog:
    https://github.com/libarchive/libarchive/compare/v3.8.10...v3.8.11
    
    Obtained from:  libarchive
    Vendor commit:  03036ffa409a2aa1c5bbad35be2202641a040fda
    MFC after:      3 days
    
    (cherry picked from commit 322d4227521380a61850b3d4f2ebd2b42343a254)
---
 contrib/libarchive/NEWS                            |   2 +
 contrib/libarchive/cpio/cpio.c                     |   6 +
 .../cpio/test/test_option_o_rejected_entry.c       |  38 +++++
 contrib/libarchive/libarchive/archive.h            |   6 +-
 .../libarchive/libarchive/archive_digest_private.h |   3 -
 contrib/libarchive/libarchive/archive_entry.h      |   2 +-
 contrib/libarchive/libarchive/archive_read.c       | 146 ++++++++++++------
 .../libarchive/archive_read_append_filter.c        |  69 +++------
 .../libarchive/archive_read_data_into_fd.c         |  26 +++-
 .../libarchive/archive_read_disk_entry_from_file.c |  24 ++-
 .../libarchive/archive_read_open_filename.c        |   3 +-
 .../archive_read_support_filter_by_code.c          |   1 +
 .../libarchive/archive_read_support_filter_uu.c    |  67 +++++++-
 .../libarchive/archive_read_support_format_7zip.c  |  34 +++++
 .../libarchive/archive_read_support_format_cpio.c  |   4 +
 .../archive_read_support_format_iso9660.c          | 103 +++++++------
 .../libarchive/archive_read_support_format_mtree.c |  17 ++-
 .../libarchive/archive_read_support_format_rar.c   |   4 +-
 .../libarchive/archive_read_support_format_tar.c   |  18 ++-
 .../libarchive/archive_read_support_format_xar.c   |  19 ++-
 .../libarchive/archive_read_support_format_zip.c   |  67 ++------
 contrib/libarchive/libarchive/archive_string.c     |  25 ++-
 contrib/libarchive/libarchive/archive_write.c      |   9 +-
 .../libarchive/archive_write_add_filter.c          |   1 +
 .../archive_write_add_filter_b64encode.c           |  12 +-
 .../libarchive/archive_write_add_filter_uuencode.c |   8 +-
 .../libarchive/archive_write_add_filter_zstd.c     |  12 +-
 .../libarchive/archive_write_disk_posix.c          |   2 +-
 .../libarchive/archive_write_set_format_7zip.c     |   4 +-
 .../libarchive/archive_write_set_format_iso9660.c  |  12 +-
 .../libarchive/archive_write_set_format_pax.c      |  15 +-
 .../libarchive/archive_write_set_format_xar.c      |   6 +-
 .../libarchive/archive_write_set_format_zip.c      |   5 +-
 .../libarchive/libarchive/archive_xml_private.h    |   3 -
 .../libarchive/libarchive/test/test_archive_read.c |   2 +
 .../test/test_archive_read_append_filter.c         |  41 +++--
 .../test/test_archive_read_open_filenames.c        |  10 +-
 .../test/test_archive_write_add_filter.c           |   9 ++
 .../test/test_archive_write_add_filter_by_name.c   |   4 +
 .../test/test_archive_write_close_callback.c       | 106 +++++++++++++
 .../test/test_create_child_environment.c           |  36 +++--
 .../test/test_gnutar_filename_encoding.c           |   7 +-
 .../libarchive/test/test_open_filename.c           |  90 +++++++++++
 .../libarchive/test/test_read_data_large.c         |  93 +++++++++++
 .../libarchive/test/test_read_filter_compress.c    |  41 +++++
 ...est_read_filter_compress_multi_volume.part01.uu |   8 +
 ...est_read_filter_compress_multi_volume.part02.uu |   8 +
 ...est_read_filter_compress_multi_volume.part03.uu |   4 +
 .../libarchive/test/test_read_filter_uudecode.c    |   1 -
 .../libarchive/test/test_read_format_7zip.c        |  31 ++++
 .../test/test_read_format_7zip_chained_lzma2.7z.uu |  13 ++
 .../test/test_read_format_cpio_newc_resync.c       |  89 +++++++++++
 .../test_read_format_iso_joliet_overlong.iso.Z.uu  |  69 +++++++++
 .../test_read_format_iso_joliet_utf16be_cycle.c    |  65 ++++++++
 ...t_read_format_iso_joliet_utf16be_cycle.iso.Z.uu |  21 +++
 .../test/test_read_format_iso_rockridge_sl_leak.c  |  55 +++++++
 .../test_read_format_iso_rockridge_sl_leak.iso.uu  |  53 +++++++
 .../test/test_read_format_isojoliet_long.c         |  31 +++-
 .../libarchive/test/test_read_format_mtree.c       |  78 ++++++++++
 .../libarchive/test/test_read_format_rar.c         |  29 ++++
 .../test/test_read_format_tar_gnu_sparse_map.c     |  75 +++++++++
 ...t_read_format_tar_gnu_sparse_map_invalid.tar.uu |  72 +++++++++
 ..._read_format_tar_gnu_sparse_map_overflow.tar.uu |  72 +++++++++
 .../libarchive/test/test_read_format_xar.c         |  57 +++++++
 ...test_read_format_xar_invalid_seek_offset.xar.uu |  14 ++
 .../test/test_read_format_zip_streamable_skip.c    |  99 ++++++++++++
 .../libarchive/test/test_ustar_filename_encoding.c |   7 +-
 .../libarchive/test/test_v7tar_filename_encoding.c |   7 +-
 .../libarchive/test/test_write_disk_secure744.c    |   9 +-
 .../libarchive/test/test_write_filter_b64encode.c  |  60 ++++++++
 .../libarchive/test/test_write_filter_uuencode.c   |  48 ++++++
 .../libarchive/test/test_write_filter_zstd.c       |  17 +++
 .../test_write_format_iso9660_boot_load_size.c     |  41 +++++
 .../test/test_write_format_option_missing_value.c  |  55 +++++++
 .../test/test_write_format_pax_mac_meta.c          | 170 +++++++++++++++++++++
 .../libarchive/test/test_zip_filename_encoding.c   |   7 +-
 contrib/libarchive/libarchive_fe/lafe_fnmatch.c    |   2 +-
 contrib/libarchive/tar/creation_set.c              | 163 ++++++++------------
 contrib/libarchive/tar/subst.c                     |  38 ++---
 .../libarchive/tar/test/test_copy_data_warning.c   |  25 +++
 .../tar/test/test_copy_data_warning.lzh.uu         |  17 +++
 contrib/libarchive/tar/test/test_option_s.c        |  20 +++
 contrib/libarchive/tar/util.c                      |   6 +
 contrib/libarchive/tar/write.c                     |   6 +
 contrib/libarchive/test_utils/test_common.h        |   3 -
 contrib/libarchive/test_utils/test_main.c          |  34 +++--
 contrib/libarchive/unzip/bsdunzip.c                |  44 ++++--
 contrib/libarchive/unzip/test/test_prompt.c        |  31 ++++
 contrib/libarchive/unzip/test/test_prompt.zip.uu   |   9 ++
 contrib/libarchive/unzip/test/test_stdin.c         |  21 +++
 lib/libarchive/tests/Makefile                      |  23 ++-
 usr.bin/cpio/tests/Makefile                        |   1 +
 usr.bin/tar/tests/Makefile                         |   2 +
 usr.bin/unzip/tests/Makefile                       |   3 +
 94 files changed, 2556 insertions(+), 469 deletions(-)

diff --git a/contrib/libarchive/NEWS b/contrib/libarchive/NEWS
index e0dc5f5c110a..e9fbd32bee84 100644
--- a/contrib/libarchive/NEWS
+++ b/contrib/libarchive/NEWS
@@ -1,3 +1,5 @@
+Oct 30, 2026: libarchive 3.8.11 released
+
 Oct 14, 2026: libarchive 3.8.10 released
 
 Jul 28, 2026: libarchive 3.8.9 released
diff --git a/contrib/libarchive/cpio/cpio.c b/contrib/libarchive/cpio/cpio.c
index 9ba153d82770..4310c83ad9b4 100644
--- a/contrib/libarchive/cpio/cpio.c
+++ b/contrib/libarchive/cpio/cpio.c
@@ -886,6 +886,8 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry)
 
 	if (r == ARCHIVE_FATAL)
 		exit(1);
+	if (r == ARCHIVE_FAILED)
+		cpio->return_value = 1;
 
 	if (r >= ARCHIVE_WARN && archive_entry_size(entry) > 0 && fd >= 0) {
 		static char buff[16384];
@@ -906,6 +908,10 @@ entry_to_archive(struct cpio *cpio, struct archive_entry *entry)
 			}
 			bytes_read = read(fd, buff, sizeof(buff));
 		}
+		if (bytes_read < 0) {
+			lafe_warnc(errno, "%s: read error", srcpath);
+			cpio->return_value = 1;
+		}
 	}
 
 	fd = restore_time(cpio, entry, srcpath, fd);
diff --git a/contrib/libarchive/cpio/test/test_option_o_rejected_entry.c b/contrib/libarchive/cpio/test/test_option_o_rejected_entry.c
new file mode 100644
index 000000000000..2e13032a8eb6
--- /dev/null
+++ b/contrib/libarchive/cpio/test/test_option_o_rejected_entry.c
@@ -0,0 +1,38 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2026 Martin Mirchev
+ * All rights reserved.
+ */
+#include "test.h"
+
+/*
+ * If the archive format cannot store an entry, bsdcpio -o warns and omits
+ * the entry; the exit status must report that the archive is incomplete.
+ */
+DEFINE_TEST(test_option_o_rejected_entry)
+{
+	char name[121];
+	char filelist[sizeof(name) + 8];
+	int r;
+
+	/* A file name of 120 characters does not fit a ustar header. */
+	memset(name, 'f', sizeof(name) - 1);
+	name[sizeof(name) - 1] = '\0';
+
+	assertMakeFile("small", 0644, "hello");
+	assertMakeFile(name, 0644, "x");
+	snprintf(filelist, sizeof(filelist), "small\n%s\n", name);
+	assertMakeFile("filelist", 0644, filelist);
+
+	r = systemf("%s -o -H ustar <filelist >archive.out 2>archive.err",
+	    testprog);
+	failure("The omitted entry must be reported in the exit status");
+	assert(r != 0);
+	assertNonEmptyFile("archive.err");
+
+	/* The other entry is still written. */
+	r = systemf("%s -it <archive.out >list.out 2>list.err", testprog);
+	assertEqualInt(r, 0);
+	assertTextFileContents("small\n", "list.out");
+}
diff --git a/contrib/libarchive/libarchive/archive.h b/contrib/libarchive/libarchive/archive.h
index 19b316a40b73..2c1390828ca2 100644
--- a/contrib/libarchive/libarchive/archive.h
+++ b/contrib/libarchive/libarchive/archive.h
@@ -34,7 +34,7 @@
  * assert that ARCHIVE_VERSION_NUMBER >= 2012108.
  */
 /* Note: Compiler will complain if this does not match archive_entry.h! */
-#define	ARCHIVE_VERSION_NUMBER 3008010
+#define	ARCHIVE_VERSION_NUMBER 3008011
 
 #include <sys/stat.h>
 #include <stddef.h>  /* for wchar_t */
@@ -177,7 +177,7 @@ __LA_DECL int		archive_version_number(void);
 /*
  * Textual name/version of the library, useful for version displays.
  */
-#define	ARCHIVE_VERSION_ONLY_STRING "3.8.10"
+#define	ARCHIVE_VERSION_ONLY_STRING "3.8.11"
 #define	ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
 __LA_DECL const char *	archive_version_string(void);
 
@@ -323,6 +323,7 @@ typedef const char *archive_passphrase_callback(struct archive *,
 #define	ARCHIVE_FILTER_GRZIP	12
 #define	ARCHIVE_FILTER_LZ4	13
 #define	ARCHIVE_FILTER_ZSTD	14
+#define	ARCHIVE_FILTER_B64	15
 
 #if ARCHIVE_VERSION_NUMBER < 4000000
 #define	ARCHIVE_COMPRESSION_NONE	ARCHIVE_FILTER_NONE
@@ -336,6 +337,7 @@ typedef const char *archive_passphrase_callback(struct archive *,
 #define	ARCHIVE_COMPRESSION_RPM		ARCHIVE_FILTER_RPM
 #define	ARCHIVE_COMPRESSION_LZIP	ARCHIVE_FILTER_LZIP
 #define	ARCHIVE_COMPRESSION_LRZIP	ARCHIVE_FILTER_LRZIP
+#define	ARCHIVE_COMPRESSION_B64		ARCHIVE_FILTER_B64
 #endif
 
 /*
diff --git a/contrib/libarchive/libarchive/archive_digest_private.h b/contrib/libarchive/libarchive/archive_digest_private.h
index 032bd8c20427..cd2956e6ce36 100644
--- a/contrib/libarchive/libarchive/archive_digest_private.h
+++ b/contrib/libarchive/libarchive/archive_digest_private.h
@@ -30,9 +30,6 @@
 #ifndef __LIBARCHIVE_BUILD
 #error This header is only to be used internally to libarchive.
 #endif
-#ifndef __LIBARCHIVE_CONFIG_H_INCLUDED
-#error "Should have include config.h first!"
-#endif
 
 /*
  * Crypto support in various Operating Systems:
diff --git a/contrib/libarchive/libarchive/archive_entry.h b/contrib/libarchive/libarchive/archive_entry.h
index 50e10a1e33a2..ce9626a68e7d 100644
--- a/contrib/libarchive/libarchive/archive_entry.h
+++ b/contrib/libarchive/libarchive/archive_entry.h
@@ -28,7 +28,7 @@
 #define	ARCHIVE_ENTRY_H_INCLUDED
 
 /* Note: Compiler will complain if this does not match archive.h! */
-#define	ARCHIVE_VERSION_NUMBER 3008010
+#define	ARCHIVE_VERSION_NUMBER 3008011
 
 /*
  * Note: archive_entry.h is for use outside of libarchive; the
diff --git a/contrib/libarchive/libarchive/archive_read.c b/contrib/libarchive/libarchive/archive_read.c
index 2f006fb96da9..6235d66d99e3 100644
--- a/contrib/libarchive/libarchive/archive_read.c
+++ b/contrib/libarchive/libarchive/archive_read.c
@@ -378,7 +378,7 @@ archive_read_set_callback_data2(struct archive *_a, void *client_data,
 		return ARCHIVE_FATAL;
 	}
 	a->client.dataset[iindex].data = client_data;
-	a->client.dataset[iindex].begin_position = -1;
+	a->client.dataset[iindex].begin_position = 0;
 	a->client.dataset[iindex].total_size = -1;
 	return ARCHIVE_OK;
 }
@@ -422,11 +422,11 @@ archive_read_add_callback_data(struct archive *_a, void *client_data,
 
 	for (i = a->client.nodes - 1; i > iindex; i--) {
 		a->client.dataset[i].data = a->client.dataset[i-1].data;
-		a->client.dataset[i].begin_position = -1;
+		a->client.dataset[i].begin_position = 0;
 		a->client.dataset[i].total_size = -1;
 	}
 	a->client.dataset[iindex].data = client_data;
-	a->client.dataset[iindex].begin_position = -1;
+	a->client.dataset[iindex].begin_position = 0;
 	a->client.dataset[iindex].total_size = -1;
 	return ARCHIVE_OK;
 }
@@ -454,7 +454,7 @@ int
 archive_read_open1(struct archive *_a)
 {
 	struct archive_read *a = (struct archive_read *)_a;
-	struct archive_read_filter *f, *tmp;
+	struct archive_read_filter *f;
 	int slot, e = ARCHIVE_OK;
 
 	archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
@@ -510,11 +510,41 @@ archive_read_open1(struct archive *_a)
 	}
 	else
 	{
+		size_t count;
+		struct archive_read_filter *f2;
+
 		/* Need to add "NONE" type filter at the end of the filter chain */
-		tmp = a->filter;
-		while (tmp->upstream)
-			tmp = tmp->upstream;
-		tmp->upstream = f;
+		count = 1;
+		for (f2 = a->filter; f2->upstream != NULL; f2 = f2->upstream)
+			count++;
+		f2->upstream = f;
+
+		while (count-- > 0) {
+			struct archive_read_filter_bidder *bidder;
+			size_t i;
+			int r;
+
+			f2 = a->filter;
+			for (i = 0; i < count; i++)
+				f2 = f2->upstream;
+			bidder = f2->bidder;
+
+			r = (bidder->vtable->bid)(bidder, f2->upstream);
+			if (r < 0) {
+				archive_set_error(&a->archive,
+				    ARCHIVE_ERRNO_FILE_FORMAT,
+				    "Registered filter does not match");
+				close_filters(a);
+				a->archive.state = ARCHIVE_STATE_FATAL;
+				return (ARCHIVE_FATAL);
+			}
+			r = (bidder->vtable->init)(f2);
+			if (r != ARCHIVE_OK) {
+				close_filters(a);
+				a->archive.state = ARCHIVE_STATE_FATAL;
+				return (ARCHIVE_FATAL);
+			}
+		}
 	}
 
 	if (!a->format)
@@ -541,8 +571,6 @@ archive_read_open1(struct archive *_a)
 
 	a->archive.state = ARCHIVE_STATE_HEADER;
 
-	/* Ensure libarchive starts from the first node in a multivolume set */
-	client_switch_proxy(f, 0);
 	return (e);
 }
 
@@ -1692,6 +1720,44 @@ advance_file_pointer(struct archive_read_filter *f, int64_t request)
 	}
 }
 
+static int64_t
+get_archive_size(struct archive_read_filter *f)
+{
+	struct archive_read_client *client = &(f->archive->client);
+	int64_t size;
+	unsigned int cursor;
+
+	/* Try to calculate size without switching client objects. */
+	size = 0;
+	for (cursor = 0; cursor < client->nodes; cursor++) {
+		int64_t total_size = client->dataset[cursor].total_size;
+
+		if (total_size < 0)
+			break;
+		if (archive_ckd_add_i64(&size, size, total_size))
+			return (ARCHIVE_FATAL);
+	}
+
+	/* Seek through remaining client objects to calculate size. */
+	for (; cursor < client->nodes; cursor++) {
+		int64_t r;
+
+		client->dataset[cursor].begin_position = size;
+		r = client_switch_proxy(f, cursor);
+		if (r != ARCHIVE_OK)
+			return (r);
+		r = client_seek_proxy(f, 0, SEEK_END);
+		if (r < 0)
+			return (r);
+		client->dataset[cursor].total_size = r;
+		if (archive_ckd_add_i64(&size, size, r))
+			return (ARCHIVE_FATAL);
+		f->position = size;
+	}
+
+	return (size);
+}
+
 /**
  * Returns ARCHIVE_FAILED if seeking isn't supported.
  */
@@ -1706,9 +1772,8 @@ __archive_read_filter_seek(struct archive_read_filter *f, int64_t offset,
     int whence)
 {
 	struct archive_read_client *client;
-	int64_t r;
+	int64_t old_position, r;
 	unsigned int cursor, old_cursor;
-	int sought = 0;
 
 	if (f->closed || f->fatal)
 		return (ARCHIVE_FATAL);
@@ -1717,6 +1782,7 @@ __archive_read_filter_seek(struct archive_read_filter *f, int64_t offset,
 
 	client = &(f->archive->client);
 	old_cursor = client->cursor;
+	old_position = f->position;
 
 	switch (whence) {
 	case SEEK_CUR:
@@ -1727,8 +1793,7 @@ __archive_read_filter_seek(struct archive_read_filter *f, int64_t offset,
 		cursor = 0;
 		while (1)
 		{
-			if (client->dataset[cursor].begin_position < 0 ||
-			    client->dataset[cursor].total_size < 0 ||
+			if (client->dataset[cursor].total_size < 0 ||
 			    client->dataset[cursor].begin_position +
 			      client->dataset[cursor].total_size > offset ||
 			    cursor + 1 >= client->nodes)
@@ -1741,10 +1806,14 @@ __archive_read_filter_seek(struct archive_read_filter *f, int64_t offset,
 			r = client_switch_proxy(f, cursor);
 			if (r != ARCHIVE_OK)
 				goto clear_buffer;
-			if ((r = client_seek_proxy(f, 0, SEEK_END)) < 0)
-				goto clear_buffer;
-			sought = 1;
-			client->dataset[cursor].total_size = r;
+			if (client->dataset[cursor].total_size < 0) {
+				if ((r = client_seek_proxy(f,
+				    0, SEEK_END)) < 0)
+					goto clear_buffer;
+				client->dataset[cursor].total_size = r;
+				f->position = r +
+				    client->dataset[cursor].begin_position;
+			}
 			if (client->dataset[cursor].begin_position +
 			    client->dataset[cursor].total_size > offset ||
 			    cursor + 1 >= client->nodes)
@@ -1761,34 +1830,13 @@ __archive_read_filter_seek(struct archive_read_filter *f, int64_t offset,
 		}
 		if ((r = client_seek_proxy(f, offset, SEEK_SET)) < 0)
 			goto clear_buffer;
-		sought = 1;
 		break;
 
 	case SEEK_END:
-		cursor = 0;
-		while (1) {
-			if (client->dataset[cursor].begin_position < 0 ||
-			    client->dataset[cursor].total_size < 0 ||
-			    cursor + 1 >= client->nodes)
-				break;
-			r = client->dataset[cursor].begin_position +
-				client->dataset[cursor].total_size;
-			client->dataset[++cursor].begin_position = r;
-		}
-		while (1) {
-			r = client_switch_proxy(f, cursor);
-			if (r != ARCHIVE_OK)
-				goto clear_buffer;
-			if ((r = client_seek_proxy(f, 0, SEEK_END)) < 0)
-				goto clear_buffer;
-			sought = 1;
-			client->dataset[cursor].total_size = r;
-			r = client->dataset[cursor].begin_position +
-				client->dataset[cursor].total_size;
-			if (cursor + 1 >= client->nodes)
-				break;
-			client->dataset[++cursor].begin_position = r;
-		}
+		r = get_archive_size(f);
+		if (r < 0)
+			goto clear_buffer;
+		cursor = client->nodes - 1;
 		while (1) {
 			if (r + offset >=
 			    client->dataset[cursor].begin_position)
@@ -1806,16 +1854,17 @@ __archive_read_filter_seek(struct archive_read_filter *f, int64_t offset,
 		r = client_seek_proxy(f, offset, SEEK_SET);
 		if (r < ARCHIVE_OK)
 			goto clear_buffer;
-		sought = 1;
 		break;
 
 	default:
 		return (ARCHIVE_FATAL);
 	}
 	r += client->dataset[cursor].begin_position;
+	f->position = r;
 
 clear_buffer:
-	if (r == ARCHIVE_FAILED && !sought && old_cursor == client->cursor) {
+	if (r == ARCHIVE_FAILED &&
+	    old_cursor == client->cursor && old_position == f->position) {
 		/* Seek failed without moving position: keep buffer */
 		return (r);
 	}
@@ -1839,11 +1888,12 @@ clear_buffer:
 	*/
 	f->avail = f->client_avail = 0;
 	f->next = f->buffer;
-	if (r >= 0) {
-		f->position = r;
+	if (r >= 0)
 		f->end_of_file = 0;
-	} else
+	else {
+		f->position = -1;
 		f->fatal = 1;
+	}
 
 	return r;
 }
diff --git a/contrib/libarchive/libarchive/archive_read_append_filter.c b/contrib/libarchive/libarchive/archive_read_append_filter.c
index 5cc8ff55d6b0..d03f1a8b5332 100644
--- a/contrib/libarchive/libarchive/archive_read_append_filter.c
+++ b/contrib/libarchive/libarchive/archive_read_append_filter.c
@@ -47,6 +47,28 @@ get_last_bidder(struct archive_read *a)
   return a->bidders + (i - 1);
 }
 
+static int
+archive_read_append_filter_last_bidder(struct archive *_a)
+{
+  struct archive_read *a = (struct archive_read *)_a;
+  struct archive_read_filter_bidder *b;
+  struct archive_read_filter *f;
+
+  f = calloc(1, sizeof(*f));
+  if (f == NULL)
+  {
+    archive_set_error(&a->archive, ENOMEM, "Out of memory");
+    return (ARCHIVE_FATAL);
+  }
+  b = get_last_bidder(a);
+  f->bidder = b;
+  f->archive = a;
+  f->upstream = a->filter;
+  a->filter = f;
+  a->bypass_filter_bidding = 1;
+  return (ARCHIVE_OK);
+}
+
 int
 archive_read_append_filter(struct archive *_a, int code)
 {
@@ -82,6 +104,7 @@ archive_read_append_filter(struct archive *_a, int code)
     case ARCHIVE_FILTER_XZ:
       r1 = archive_read_support_filter_xz(_a);
       break;
+    case ARCHIVE_FILTER_B64:
     case ARCHIVE_FILTER_UU:
       r1 = archive_read_support_filter_uu(_a);
       break;
@@ -114,28 +137,9 @@ archive_read_append_filter(struct archive *_a, int code)
 
   if (r1 > ARCHIVE_FATAL && code != ARCHIVE_FILTER_NONE)
   {
-    struct archive_read_filter_bidder *b;
-    struct archive_read_filter *f;
-
-    f = calloc(1, sizeof(*f));
-    if (f == NULL)
-    {
-      archive_set_error(&a->archive, ENOMEM, "Out of memory");
-      return (ARCHIVE_FATAL);
-    }
-    b = get_last_bidder(a);
-    f->bidder = b;
-    f->archive = a;
-    f->upstream = a->filter;
-    a->filter = f;
-    r2 = (b->vtable->init)(a->filter);
-    if (r2 != ARCHIVE_OK) {
-      __archive_read_free_filters(a);
-      return (ARCHIVE_FATAL);
-    }
+    r2 = archive_read_append_filter_last_bidder(_a);
   }
 
-  a->bypass_filter_bidding = 1;
   return (r1 < r2) ? r1 : r2;
 }
 
@@ -149,32 +153,9 @@ int
 archive_read_append_filter_program_signature(struct archive *_a,
   const char *cmd, const void *signature, size_t signature_len)
 {
-  struct archive_read *a = (struct archive_read *)_a;
-  struct archive_read_filter_bidder *b;
-  struct archive_read_filter *f;
-  int r;
-
   if (archive_read_support_filter_program_signature(_a, cmd, signature,
     signature_len) != (ARCHIVE_OK))
     return (ARCHIVE_FATAL);
 
-  f = calloc(1, sizeof(*f));
-  if (f == NULL)
-  {
-    archive_set_error(&a->archive, ENOMEM, "Out of memory");
-    return (ARCHIVE_FATAL);
-  }
-  b = get_last_bidder(a);
-  f->bidder = b;
-  f->archive = a;
-  f->upstream = a->filter;
-  a->filter = f;
-  r = (b->vtable->init)(a->filter);
-  if (r != ARCHIVE_OK) {
-    __archive_read_free_filters(a);
-    return (ARCHIVE_FATAL);
-  }
-
-  a->bypass_filter_bidding = 1;
-  return r;
+  return (archive_read_append_filter_last_bidder(_a));
 }
diff --git a/contrib/libarchive/libarchive/archive_read_data_into_fd.c b/contrib/libarchive/libarchive/archive_read_data_into_fd.c
index b63fbf9236a6..8eee19f769a4 100644
--- a/contrib/libarchive/libarchive/archive_read_data_into_fd.c
+++ b/contrib/libarchive/libarchive/archive_read_data_into_fd.c
@@ -31,6 +31,9 @@
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
 #endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
 #ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
@@ -86,11 +89,30 @@ pad_to(struct archive *a, int fd, int can_lseek,
 	return (ARCHIVE_OK);
 }
 
+static int
+lseek_available(int fd)
+{
+	struct stat st;
+	int ret;
+
+	/* Support holes only with regular files. */
+	ret = (fstat(fd, &st) == 0) && S_ISREG(st.st_mode);
+#ifdef HAVE_FCNTL
+	if (ret) {
+		int flags = fcntl(fd, F_GETFL);
+
+		/* O_APPEND defeats lseek's sparse file purpose. */
+		if (flags != -1 && flags & O_APPEND)
+			ret = 0;
+	}
+#endif
+
+	return (ret);
+}
 
 int
 archive_read_data_into_fd(struct archive *a, int fd)
 {
-	struct stat st;
 	int r, r2;
 	const void *buff;
 	size_t size, bytes_to_write;
@@ -107,7 +129,7 @@ archive_read_data_into_fd(struct archive *a, int fd)
 
 	declared_size = ((struct archive_read *)a)->entry_bytes_declared;
 
-	can_lseek = (fstat(fd, &st) == 0) && S_ISREG(st.st_mode);
+	can_lseek = lseek_available(fd);
 	if (can_lseek) {
 		fd_offset = lseek(fd, 0, SEEK_CUR);
 		if (fd_offset == -1)
diff --git a/contrib/libarchive/libarchive/archive_read_disk_entry_from_file.c b/contrib/libarchive/libarchive/archive_read_disk_entry_from_file.c
index c4ad595fa4d8..7bd023401eb3 100644
--- a/contrib/libarchive/libarchive/archive_read_disk_entry_from_file.c
+++ b/contrib/libarchive/libarchive/archive_read_disk_entry_from_file.c
@@ -486,7 +486,17 @@ setup_xattr(struct archive_read_disk *a,
 		return (ARCHIVE_WARN);
 	}
 
-	if (size > 0 && (value = malloc(size)) == NULL) {
+	/*
+	 * Do not query an empty value again: if it has grown in the
+	 * meantime, the second call would return the new size without
+	 * storing anything.
+	 */
+	if (size == 0) {
+		archive_entry_xattr_add_entry(entry, name, "", 0);
+		return (ARCHIVE_OK);
+	}
+
+	if ((value = malloc(size)) == NULL) {
 		archive_set_error(&a->archive, errno, "Out of memory");
 		return (ARCHIVE_FATAL);
 	}
@@ -682,7 +692,17 @@ setup_xattr(struct archive_read_disk *a, struct archive_entry *entry,
 		return (ARCHIVE_WARN);
 	}
 
-	if (size > 0 && (value = malloc(size)) == NULL) {
+	/*
+	 * Do not query an empty value again: if it has grown in the
+	 * meantime, the second call would return the new size without
+	 * storing anything.
+	 */
+	if (size == 0) {
+		archive_entry_xattr_add_entry(entry, fullname, "", 0);
+		return (ARCHIVE_OK);
+	}
+
+	if ((value = malloc(size)) == NULL) {
 		archive_set_error(&a->archive, errno, "Out of memory");
 		return (ARCHIVE_FATAL);
 	}
diff --git a/contrib/libarchive/libarchive/archive_read_open_filename.c b/contrib/libarchive/libarchive/archive_read_open_filename.c
index 91f64b694a0c..2c442eb12050 100644
--- a/contrib/libarchive/libarchive/archive_read_open_filename.c
+++ b/contrib/libarchive/libarchive/archive_read_open_filename.c
@@ -583,7 +583,6 @@ file_seek(struct archive *a, void *client_data, int64_t request, int whence)
 	if (r >= 0)
 		return r;
 
-	/* If the input is corrupted or truncated, fail. */
 err:
 	if (mine->filename_type == FNT_STDIN)
 		archive_set_error(a, errno, "Error seeking in stdin");
@@ -593,7 +592,7 @@ err:
 	else
 		archive_set_error(a, errno, "Error seeking in '%ls'",
 		    mine->filename.w);
-	return (ARCHIVE_FATAL);
+	return (ARCHIVE_FAILED);
 }
 
 static int
diff --git a/contrib/libarchive/libarchive/archive_read_support_filter_by_code.c b/contrib/libarchive/libarchive/archive_read_support_filter_by_code.c
index 4c8b6cb59c2a..6c184218404c 100644
--- a/contrib/libarchive/libarchive/archive_read_support_filter_by_code.c
+++ b/contrib/libarchive/libarchive/archive_read_support_filter_by_code.c
@@ -47,6 +47,7 @@ archive_read_support_filter_by_code(struct archive *a, int filter_code)
 		return archive_read_support_filter_lzma(a);
 	case ARCHIVE_FILTER_XZ:
 		return archive_read_support_filter_xz(a);
+	case ARCHIVE_FILTER_B64:
 	case ARCHIVE_FILTER_UU:
 		return archive_read_support_filter_uu(a);
 	case ARCHIVE_FILTER_RPM:
diff --git a/contrib/libarchive/libarchive/archive_read_support_filter_uu.c b/contrib/libarchive/libarchive/archive_read_support_filter_uu.c
index 364a3a041660..26b0929e3e40 100644
--- a/contrib/libarchive/libarchive/archive_read_support_filter_uu.c
+++ b/contrib/libarchive/libarchive/archive_read_support_filter_uu.c
@@ -44,6 +44,11 @@
 /* Maximum lookahead during bid phase */
 #define MAX_LINE_LENGTH 128*1024 /* in bytes */
 
+struct uu_bidder {
+	int		code;
+	const char	*name;
+};
+
 struct uu {
 	unsigned char	*out_buff;
 #define OUT_BUFF_SIZE	(64 * 1024)
@@ -61,6 +66,7 @@ struct uu {
 static int	uudecode_bidder_bid(struct archive_read_filter_bidder *,
 		    struct archive_read_filter *f);
 static int	uudecode_bidder_init(struct archive_read_filter *);
+static void	uudecode_bidder_free(struct archive_read_filter_bidder *);
 
 static int	uudecode_read_header(struct archive_read_filter *,
 		    struct archive_entry *entry);
@@ -81,15 +87,27 @@ static const struct archive_read_filter_bidder_vtable
 uudecode_bidder_vtable = {
 	.bid = uudecode_bidder_bid,
 	.init = uudecode_bidder_init,
+	.free = uudecode_bidder_free
 };
 
 int
 archive_read_support_filter_uu(struct archive *_a)
 {
 	struct archive_read *a = (struct archive_read *)_a;
+	struct uu_bidder *data;
 
-	return __archive_read_register_bidder(a, NULL,
-			&uudecode_bidder_vtable);
+	data = calloc(1, sizeof(*data));
+	if (data == NULL) {
+		archive_set_error(_a, ENOMEM, "Can't allocate memory");
+		return ARCHIVE_FATAL;
+	}
+
+	if (__archive_read_register_bidder(a, data,
+			&uudecode_bidder_vtable) != ARCHIVE_OK) {
+		free(data);
+		return (ARCHIVE_FATAL);
+	}
+	return (ARCHIVE_OK);
 }
 
 static const unsigned char uuchar[256] = {
@@ -214,6 +232,17 @@ read_line_ahead(struct archive_read_filter *f, ssize_t parsed,
 			line = b + start;
 			*len = p - line;
 			*unconsumed = *len + nl;
+
+			/* Only ASCII lines are valid. */
+			while (p > line) {
+				unsigned char c = *--p;
+
+				if (c < 0x20 || c > 0x7F) {
+					*len = 0;
+					*unconsumed = 0;
+					return (NULL);
+				}
+			}
 		} else {
 			/* Keep offset for check of possibly missing \n in \r\n. */
 			if (step != 1)
@@ -276,6 +305,7 @@ static int
 uudecode_bidder_bid(struct archive_read_filter_bidder *b,
     struct archive_read_filter *f)
 {
+	struct uu_bidder *data = b->data;
 	const unsigned char *p;
 	size_t l;
 	int firstline;
@@ -329,9 +359,14 @@ uudecode_bidder_bid(struct archive_read_filter_bidder *b,
 		}
 		offset += unconsumed;
 		p = read_line_ahead(f, 0, offset, &len, &unconsumed);
-		if (p != NULL && uuchar[*p])
+		if (p != NULL && uuchar[*p]) {
+			data->code = ARCHIVE_FILTER_UU;
+			data->name = "uu";
 			return (firstline+30);
+		}
 	} else if (l == 13) {
+		int bid = 0;
+
 		/* "begin-base64 " */
 		while (len > 0) {
 			if (!base64[*p++])
@@ -339,9 +374,19 @@ uudecode_bidder_bid(struct archive_read_filter_bidder *b,
 			len--;
 		}
 		if (len == 0)
-			return (firstline+30);
+			bid = firstline + 30;
 		if (len == 4 && memcmp(p, "====", 4) == 0)
-			return (firstline+40);
+			bid = firstline + 40;
+		if (bid > 0) {
+#if ARCHIVE_VERSION_NUMBER < 4000000
+			data->code = ARCHIVE_FILTER_UU;
+			data->name = "uu";
+#else
+			data->code = ARCHIVE_FILTER_B64;
+			data->name = "b64";
+#endif
+			return (bid);
+		}
 	}
 
 	return (0);
@@ -357,11 +402,12 @@ uudecode_reader_vtable = {
 static int
 uudecode_bidder_init(struct archive_read_filter *f)
 {
+	struct uu_bidder *data = f->bidder->data;
 	struct uu *uu;
 	void *out_buff;
 
-	f->code = ARCHIVE_FILTER_UU;
-	f->name = "uu";
+	f->code = data->code;
+	f->name = data->name;
 
 	uu = calloc(1, sizeof(*uu));
 	out_buff = malloc(OUT_BUFF_SIZE);
@@ -383,6 +429,13 @@ uudecode_bidder_init(struct archive_read_filter *f)
 	return (ARCHIVE_OK);
 }
 
+static void
+uudecode_bidder_free(struct archive_read_filter_bidder *b)
+{
+	free(b->data);
+	b->data = NULL;
+}
+
 static int
 uudecode_read_header(struct archive_read_filter *f, struct archive_entry *entry)
 {
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_7zip.c b/contrib/libarchive/libarchive/archive_read_support_format_7zip.c
index 254e4a50a3d7..1d1c6217936b 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_7zip.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_7zip.c
@@ -3944,6 +3944,22 @@ read_stream(struct archive_read *a, const void **buff, size_t size,
 	return (get_uncompressed_data(a, buff, size, minimum));
 }
 
+/* Returns the name of a compressor codec, or NULL if not a compressor. */
+static const char *
+compressor_name(int64_t codec)
+{
+	switch (codec) {
+	case _7Z_COPY:    return ("Copy");
+	case _7Z_LZMA:    return ("LZMA");
+	case _7Z_LZMA2:   return ("LZMA2");
+	case _7Z_DEFLATE: return ("Deflate");
+	case _7Z_BZ2:     return ("BZip2");
+	case _7Z_PPMD:    return ("PPMd");
+	case _7Z_ZSTD:    return ("Zstd");
+	default:          return (NULL);
+	}
+}
+
 static int
 setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
     int header)
@@ -4006,6 +4022,24 @@ setup_decode_folder(struct archive_read *a, struct _7z_folder *folder,
 		return (header ? ARCHIVE_FATAL : ARCHIVE_FAILED);
 	}
 
+	/*
+	 * 7-Zip can be asked to chain two compressors in one folder
+	 * (e.g. -m0=LZMA2 -m1=LZMA2). This is slow and gains nothing.
+	 * Our decoder intentionally only supports a compressor
+	 * followed by an optional filter.
+	 */
+	if (folder->numCoders == 2 && !found_bcj2 &&
+	    compressor_name(folder->coders[0].codec) != NULL &&
+	    compressor_name(folder->coders[1].codec) != NULL) {
+		archive_set_error(&(a->archive),
+		    ARCHIVE_ERRNO_MISC,
+		    "The %s is compressed twice with chained compressors "
+		    "(%s and %s), which is not supported", cname,
+		    compressor_name(folder->coders[0].codec),
+		    compressor_name(folder->coders[1].codec));
+		return (header ? ARCHIVE_FATAL : ARCHIVE_FAILED);
+	}
+
 	/*
 	 * Initialize a stream reader.
 	 */
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_cpio.c b/contrib/libarchive/libarchive/archive_read_support_format_cpio.c
index 9dba42218114..eb1ae982477a 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_cpio.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_cpio.c
@@ -581,6 +581,10 @@ find_newc_header(struct archive_read *a)
 				}
 				p += 2;
 				break;
+			case '7':
+				/* A header may start two bytes on. */
+				p += 2;
+				break;
 			case '0':
 				p++;
 				break;
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_iso9660.c b/contrib/libarchive/libarchive/archive_read_support_format_iso9660.c
index 35f4c781bfae..2d95457061b7 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_iso9660.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_iso9660.c
@@ -388,9 +388,9 @@ static int	archive_read_format_iso9660_read_data(struct archive_read *,
 static int	archive_read_format_iso9660_read_data_skip(struct archive_read *);
 static int	archive_read_format_iso9660_read_header(struct archive_read *,
 		    struct archive_entry *);
-static const char *build_pathname(struct archive_string *, struct file_info *, int);
+static int	build_pathname(struct archive_string *, struct file_info *, int);
 static int	build_pathname_utf16be(unsigned char *, size_t, size_t *,
-		    struct file_info *);
+		    struct file_info *, int);
 #if DEBUG
 static void	dump_isodirrec(FILE *, const unsigned char *isodirrec);
 #endif
@@ -432,6 +432,7 @@ static void	parse_rockridge_TF1(struct file_info *,
*** 3986 LINES SKIPPED ***