The branch stable/14 has been updated by mm:

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

commit 8774c92e32b25cb0253f1a7a0fbf5d2e6fecc4a3
Author:     Martin Matuska <[email protected]>
AuthorDate: 2024-04-29 08:15:04 +0000
Commit:     Martin Matuska <[email protected]>
CommitDate: 2024-04-30 06:47:56 +0000

    libarchive: merge from vendor branch
    
    Libarchive 3.7.4 + three fixes from master
    
    Security fixes:
     #2135 rar: Fix OOB in rar e8 filter (CVE-2024-26256)
     #2145 zip: Fix out of boundary access
     #2148 rar: Fix OOB in rar delta filter
     #2149 rar: Fix OOB in rar audio filter
    
    Important bugfixes:
     #2131 7zip: Limit amount of properties
     #2110 bsdtar: Fix error handling around strtol() usages
     #2116 passphrase: Never allow empty passwords
     #2124 rar: Fix "File CRC Error" when extracting specific rar4 archives
     #2123 xar: Avoid infinite link loop
     #2150 xar: Fix another infinite loop and expat error handling
     #2108 zip: Update AppleDouble support for directories
     #2071 zstd: Implement core detectiongit
    
    (cherry picked from commit 13d826ff947d9026f98e317e7385b22abfc0eace)
---
 contrib/libarchive/NEWS                            |  2 +
 contrib/libarchive/README.md                       |  2 +-
 contrib/libarchive/cat/cmdline.c                   | 16 +++--
 contrib/libarchive/cpio/cmdline.c                  | 16 +++--
 contrib/libarchive/libarchive/archive.h            |  6 +-
 contrib/libarchive/libarchive/archive_entry.h      |  2 +-
 contrib/libarchive/libarchive/archive_entry_acl.3  |  2 +-
 contrib/libarchive/libarchive/archive_read_disk.3  |  4 +-
 .../libarchive/archive_read_support_format_7zip.c  |  2 +
 .../libarchive/archive_read_support_format_all.c   |  2 +-
 .../libarchive/archive_read_support_format_ar.c    |  4 +-
 .../libarchive/archive_read_support_format_lha.c   |  4 +-
 .../libarchive/archive_read_support_format_mtree.c |  8 +--
 .../libarchive/archive_read_support_format_rar.c   | 30 +++++++-
 .../libarchive/archive_read_support_format_warc.c  | 10 ++-
 .../libarchive/archive_read_support_format_xar.c   |  9 +++
 .../libarchive/archive_read_support_format_zip.c   | 15 +++-
 contrib/libarchive/libarchive/archive_util.c       |  3 +-
 .../libarchive/archive_write_add_filter_zstd.c     | 23 +++++-
 .../libarchive/archive_write_disk_posix.c          |  3 +-
 .../libarchive/libarchive/archive_write_private.h  |  2 +-
 .../libarchive/archive_write_set_format_gnutar.c   |  2 +-
 .../libarchive/archive_write_set_passphrase.c      | 35 ++++-----
 .../libarchive/libarchive/libarchive_internals.3   |  2 +-
 .../test/test_read_format_xar_doublelink.c         | 55 ++++++++++++++
 .../test/test_read_format_xar_doublelink.xar.uu    | 12 ++++
 .../libarchive/test/test_write_disk_appledouble.c  | 84 ++++++++++++++++++++++
 .../test/test_write_disk_appledouble_zip.zip.uu    | 27 +++++++
 contrib/libarchive/libarchive_fe/passphrase.c      |  4 +-
 contrib/libarchive/tar/bsdtar.1                    | 15 ++--
 contrib/libarchive/tar/bsdtar.c                    | 63 ++++++++--------
 contrib/libarchive/tar/cmdline.c                   | 16 +++--
 contrib/libarchive/unzip/cmdline.c                 | 18 +++--
 contrib/libarchive/unzip/test/test_I.c             | 13 ++++
 lib/libarchive/tests/Makefile                      |  3 +
 35 files changed, 404 insertions(+), 110 deletions(-)

diff --git a/contrib/libarchive/NEWS b/contrib/libarchive/NEWS
index f4395fd1c979..ebdbb2a978ec 100644
--- a/contrib/libarchive/NEWS
+++ b/contrib/libarchive/NEWS
@@ -1,3 +1,5 @@
+Apr 26, 2024: libarchive 3.7.4 released
+
 Apr 08, 2024: libarchive 3.7.3 released
 
 Sep 12, 2023: libarchive 3.7.2 released
diff --git a/contrib/libarchive/README.md b/contrib/libarchive/README.md
index 727ed49856b6..933de6986425 100644
--- a/contrib/libarchive/README.md
+++ b/contrib/libarchive/README.md
@@ -201,7 +201,7 @@ questions we are asked about libarchive:
   In case other thread calls the same function in parallel, it might
   get interrupted by it and cause the executable to use umask=0 for the
   remaining execution.
-  This will then lead to implicitely created directories to have 777
+  This will then lead to implicitly created directories to have 777
   permissions without sticky bit.
 
 * In particular, libarchive's modules to read or write a directory
diff --git a/contrib/libarchive/cat/cmdline.c b/contrib/libarchive/cat/cmdline.c
index ea1e0eed6d0a..851b63de06e5 100644
--- a/contrib/libarchive/cat/cmdline.c
+++ b/contrib/libarchive/cat/cmdline.c
@@ -114,12 +114,18 @@ bsdcat_getopt(struct bsdcat *bsdcat)
        enum { state_start = 0, state_old_tar, state_next_word,
               state_short, state_long };
 
-       const struct bsdcat_option *popt, *match = NULL, *match2 = NULL;
-       const char *p, *long_prefix = "--";
+       const struct bsdcat_option *popt, *match, *match2;
+       const char *p, *long_prefix;
        size_t optlength;
-       int opt = '?';
-       int required = 0;
+       int opt;
+       int required;
 
+again:
+       match = NULL;
+       match2 = NULL;
+       long_prefix = "--";
+       opt = '?';
+       required = 0;
        bsdcat->argument = NULL;
 
        /* First time through, initialize everything. */
@@ -172,7 +178,7 @@ bsdcat_getopt(struct bsdcat *bsdcat)
                if (opt == '\0') {
                        /* End of this group; recurse to get next option. */
                        bsdcat->getopt_state = state_next_word;
-                       return bsdcat_getopt(bsdcat);
+                       goto again;
                }
 
                /* Does this option take an argument? */
diff --git a/contrib/libarchive/cpio/cmdline.c 
b/contrib/libarchive/cpio/cmdline.c
index 312d762c8f46..ab25492ede48 100644
--- a/contrib/libarchive/cpio/cmdline.c
+++ b/contrib/libarchive/cpio/cmdline.c
@@ -114,12 +114,18 @@ cpio_getopt(struct cpio *cpio)
        static int state = state_start;
        static char *opt_word;
 
-       const struct option *popt, *match = NULL, *match2 = NULL;
-       const char *p, *long_prefix = "--";
+       const struct option *popt, *match, *match2;
+       const char *p, *long_prefix;
        size_t optlength;
-       int opt = '?';
-       int required = 0;
+       int opt;
+       int required;
 
+again:
+       match = NULL;
+       match2 = NULL;
+       long_prefix = "--";
+       opt = '?';
+       required = 0;
        cpio->argument = NULL;
 
        /* First time through, initialize everything. */
@@ -169,7 +175,7 @@ cpio_getopt(struct cpio *cpio)
                if (opt == '\0') {
                        /* End of this group; recurse to get next option. */
                        state = state_next_word;
-                       return cpio_getopt(cpio);
+                       goto again;
                }
 
                /* Does this option take an argument? */
diff --git a/contrib/libarchive/libarchive/archive.h 
b/contrib/libarchive/libarchive/archive.h
index 2e3a9f31cd33..fd4dd20fad13 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 3007003
+#define        ARCHIVE_VERSION_NUMBER 3007004
 
 #include <sys/stat.h>
 #include <stddef.h>  /* for wchar_t */
@@ -155,7 +155,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.3"
+#define        ARCHIVE_VERSION_ONLY_STRING "3.7.4"
 #define        ARCHIVE_VERSION_STRING "libarchive " ARCHIVE_VERSION_ONLY_STRING
 __LA_DECL const char * archive_version_string(void);
 
@@ -895,7 +895,7 @@ __LA_DECL int archive_write_set_options(struct archive *_a,
                            const char *opts);
 
 /*
- * Set a encryption passphrase.
+ * Set an encryption passphrase.
  */
 __LA_DECL int archive_write_set_passphrase(struct archive *_a, const char *p);
 __LA_DECL int archive_write_set_passphrase_callback(struct archive *,
diff --git a/contrib/libarchive/libarchive/archive_entry.h 
b/contrib/libarchive/libarchive/archive_entry.h
index df9cb765f7e8..1c59ded7c911 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 3007003
+#define        ARCHIVE_VERSION_NUMBER 3007004
 
 /*
  * Note: archive_entry.h is for use outside of libarchive; the
diff --git a/contrib/libarchive/libarchive/archive_entry_acl.3 
b/contrib/libarchive/libarchive/archive_entry_acl.3
index 50dd642c20c6..4d0d8b50ed07 100644
--- a/contrib/libarchive/libarchive/archive_entry_acl.3
+++ b/contrib/libarchive/libarchive/archive_entry_acl.3
@@ -383,7 +383,7 @@ Prefix each default ACL entry with the word
 The mask and other ACLs don not contain a double colon.
 .El
 .Pp
-The following flags are effecive only on NFSv4 ACL:
+The following flags are effective only on NFSv4 ACL:
 .Bl -tag -offset indent -compact -width ARCHIV
 .It Dv ARCHIVE_ENTRY_ACL_STYLE_COMPACT
 Do not output minus characters for unset permissions and flags in NFSv4 ACL
diff --git a/contrib/libarchive/libarchive/archive_read_disk.3 
b/contrib/libarchive/libarchive/archive_read_disk.3
index 7cde3c232713..990c1514c4d5 100644
--- a/contrib/libarchive/libarchive/archive_read_disk.3
+++ b/contrib/libarchive/libarchive/archive_read_disk.3
@@ -288,11 +288,11 @@ calls. If matched based on calls to
 .Tn archive_match_time_excluded ,
 or
 .Tn archive_match_owner_excluded ,
-then the callback function specified by the _excluded_func parameter will 
execute. This function will recieve data provided to the fourth parameter, void 
*_client_data.
+then the callback function specified by the _excluded_func parameter will 
execute. This function will receive data provided to the fourth parameter, void 
*_client_data.
 .It Fn archive_read_disk_set_metadata_filter_callback
 Allows the caller to set a callback function during calls to
 .Xr archive_read_header 3
-to filter out metadata for each entry. The callback function recieves the
+to filter out metadata for each entry. The callback function receives the
 .Tn struct archive
 object, void* custom filter data, and the 
 .Tn struct archive_entry .
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_7zip.c 
b/contrib/libarchive/libarchive/archive_read_support_format_7zip.c
index 92495e628f9a..7e465935c902 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_7zip.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_7zip.c
@@ -2037,6 +2037,8 @@ read_Folder(struct archive_read *a, struct _7z_folder *f)
                        if (parse_7zip_uint64(
                            a, &(f->coders[i].propertiesSize)) < 0)
                                return (-1);
+                       if (UMAX_ENTRY < f->coders[i].propertiesSize)
+                               return (-1);
                        if ((p = header_bytes(
                            a, (size_t)f->coders[i].propertiesSize)) == NULL)
                                return (-1);
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_all.c 
b/contrib/libarchive/libarchive/archive_read_support_format_all.c
index 5a4e1ab675a5..3b53c9ad5f57 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_all.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_all.c
@@ -67,7 +67,7 @@ archive_read_support_format_all(struct archive *a)
         * increase the chance that a high bid from someone else will
         * make it unnecessary for these to do anything at all.
         */
-       /* These three have potentially large look-ahead. */
+       /* These have potentially large look-ahead. */
        archive_read_support_format_7zip(a);
        archive_read_support_format_cab(a);
        archive_read_support_format_rar(a);
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_ar.c 
b/contrib/libarchive/libarchive/archive_read_support_format_ar.c
index ca8effb0b0ee..6f1be8591fef 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_ar.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_ar.c
@@ -270,7 +270,7 @@ _ar_read_header(struct archive_read *a, struct 
archive_entry *entry,
                }
                if (ar->strtab != NULL) {
                        archive_set_error(&a->archive, EINVAL,
-                           "More than one string tables exist");
+                           "More than one string table exists");
                        return (ARCHIVE_FATAL);
                }
 
@@ -515,7 +515,7 @@ archive_read_format_ar_read_data(struct archive_read *a,
                if (ar->entry_padding) {
                        if (skipped >= 0) {
                                archive_set_error(&a->archive, 
ARCHIVE_ERRNO_MISC,
-                                       "Truncated ar archive- failed consuming 
padding");
+                                       "Truncated ar archive - failed 
consuming padding");
                        }
                        return (ARCHIVE_FATAL);
                }
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_lha.c 
b/contrib/libarchive/libarchive/archive_read_support_format_lha.c
index 1c64b2900b8e..4d6290ac33bb 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_lha.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_lha.c
@@ -1693,7 +1693,7 @@ archive_read_format_lha_cleanup(struct archive_read *a)
  * example.
  *   1. a symbolic-name is 'aaa/bb/cc'
  *   2. a filename is 'xxx/bbb'
- *  then a archived pathname is 'xxx/bbb|aaa/bb/cc'
+ *  then an archived pathname is 'xxx/bbb|aaa/bb/cc'
  */
 static int
 lha_parse_linkname(struct archive_wstring *linkname,
@@ -2385,7 +2385,7 @@ lzh_decode_blocks(struct lzh_stream *strm, int last)
                                        return (100);
                                }
 
-                               /* lzh_br_read_ahead() always try to fill the
+                               /* lzh_br_read_ahead() always tries to fill the
                                 * cache buffer up. In specific situation we
                                 * are close to the end of the data, the cache
                                 * buffer will not be full and thus we have to
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_mtree.c 
b/contrib/libarchive/libarchive/archive_read_support_format_mtree.c
index 630cff6e3999..6971228eefad 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_mtree.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_mtree.c
@@ -416,8 +416,8 @@ next_line(struct archive_read *a,
 }
 
 /*
- * Compare characters with a mtree keyword.
- * Returns the length of a mtree keyword if matched.
+ * Compare characters with an mtree keyword.
+ * Returns the length of an mtree keyword if matched.
  * Returns 0 if not matched.
  */
 static int
@@ -515,7 +515,7 @@ bid_keyword(const char *p,  ssize_t len)
 
 /*
  * Test whether there is a set of mtree keywords.
- * Returns the number of keyword.
+ * Returns the number of keywords.
  * Returns -1 if we got incorrect sequence.
  * This function expects a set of "<space characters>keyword=value".
  * When "unset" is specified, expects a set of "<space characters>keyword".
@@ -760,7 +760,7 @@ detect_form(struct archive_read *a, int *is_form_d)
                                        multiline = 1;
                                else {
                                        /* We've got plenty of correct lines
-                                        * to assume that this file is a mtree
+                                        * to assume that this file is an mtree
                                         * format. */
                                        if (++entry_cnt >= MAX_BID_ENTRY)
                                                break;
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_rar.c 
b/contrib/libarchive/libarchive/archive_read_support_format_rar.c
index 99a11d170074..4fc6626cacfd 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_rar.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_rar.c
@@ -2176,6 +2176,19 @@ read_data_compressed(struct archive_read *a, const void 
**buff, size_t *size,
     {
       start = rar->offset;
       end = start + rar->dictionary_size;
+
+      /* We don't want to overflow the window and overwrite data that we write
+       * at 'start'. Therefore, reduce the end length by the maximum match 
size,
+       * which is 260 bytes. You can compute this maximum by looking at the
+       * definition of 'expand', in particular when 'symbol >= 271'. */
+      /* NOTE: It's possible for 'dictionary_size' to be less than this 260
+       * value, however that will only be the case when 'unp_size' is small,
+       * which should only happen when the entry size is small and there's no
+       * risk of overflowing the buffer */
+      if (rar->dictionary_size > 260) {
+        end -= 260;
+      }
+
       if (rar->filters.filterstart < end) {
         end = rar->filters.filterstart;
       }
@@ -3599,7 +3612,15 @@ execute_filter_delta(struct rar_filter *filter, struct 
rar_virtual_machine *vm)
   {
     uint8_t lastbyte = 0;
     for (idx = i; idx < length; idx += numchannels)
+    {
+      /*
+       * The src block should not overlap with the dst block.
+       * If so it would be better to consider this archive is broken.
+       */
+      if (src >= dst)
+        return 0;
       lastbyte = dst[idx] = lastbyte - *src++;
+    }
   }
 
   filter->filteredblockaddress = length;
@@ -3615,7 +3636,7 @@ execute_filter_e8(struct rar_filter *filter, struct 
rar_virtual_machine *vm, siz
   uint32_t filesize = 0x1000000;
   uint32_t i;
 
-  if (length > PROGRAM_WORK_SIZE || length < 4)
+  if (length > PROGRAM_WORK_SIZE || length <= 4)
     return 0;
 
   for (i = 0; i <= length - 5; i++)
@@ -3701,6 +3722,13 @@ execute_filter_audio(struct rar_filter *filter, struct 
rar_virtual_machine *vm)
     memset(&state, 0, sizeof(state));
     for (j = i; j < length; j += numchannels)
     {
+      /*
+       * The src block should not overlap with the dst block.
+       * If so it would be better to consider this archive is broken.
+       */
+      if (src >= dst)
+        return 0;
+
       int8_t delta = (int8_t)*src++;
       uint8_t predbyte, byte;
       int prederror;
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_warc.c 
b/contrib/libarchive/libarchive/archive_read_support_format_warc.c
index c49d44eba5e5..fcec5bc4cbb9 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_warc.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_warc.c
@@ -215,6 +215,7 @@ _warc_rdhdr(struct archive_read *a, struct archive_entry 
*entry)
        const char *buf;
        ssize_t nrd;
        const char *eoh;
+       char *tmp;
        /* for the file name, saves some strndup()'ing */
        warc_string_t fnam;
        /* warc record type, not that we really use it a lot */
@@ -321,7 +322,14 @@ start_over:
                 * malloc()+free() roundtrip */
                if (fnam.len + 1U > w->pool.len) {
                        w->pool.len = ((fnam.len + 64U) / 64U) * 64U;
-                       w->pool.str = realloc(w->pool.str, w->pool.len);
+                       tmp = realloc(w->pool.str, w->pool.len);
+                       if (tmp == NULL) {
+                               archive_set_error(
+                                       &a->archive, ENOMEM,
+                                       "Out of memory");
+                               return (ARCHIVE_FATAL);
+                       }
+                       w->pool.str = tmp;
                }
                memcpy(w->pool.str, fnam.str, fnam.len);
                w->pool.str[fnam.len] = '\0';
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_xar.c 
b/contrib/libarchive/libarchive/archive_read_support_format_xar.c
index fd63594373cb..cefb36410e77 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_xar.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_xar.c
@@ -2055,6 +2055,12 @@ xml_start(struct archive_read *a, const char *name, 
struct xmlattr_list *list)
                            attr = attr->next) {
                                if (strcmp(attr->name, "link") != 0)
                                        continue;
+                               if (xar->file->hdnext != NULL || 
xar->file->link != 0 ||
+                                   xar->file == xar->hdlink_orgs) {
+                                       archive_set_error(&a->archive, 
ARCHIVE_ERRNO_MISC,
+                                           "File with multiple link 
attributes");
+                                       return (ARCHIVE_FATAL);
+                               }
                                if (strcmp(attr->value, "original") == 0) {
                                        xar->file->hdnext = xar->hdlink_orgs;
                                        xar->hdlink_orgs = xar->file;
@@ -3251,6 +3257,9 @@ expat_start_cb(void *userData, const XML_Char *name, 
const XML_Char **atts)
        struct xmlattr_list list;
        int r;
 
+       if (ud->state != ARCHIVE_OK)
+               return;
+
        r = expat_xmlattr_setup(a, &list, atts);
        if (r == ARCHIVE_OK)
                r = xml_start(a, (const char *)name, &list);
diff --git a/contrib/libarchive/libarchive/archive_read_support_format_zip.c 
b/contrib/libarchive/libarchive/archive_read_support_format_zip.c
index 212bfff9fa7b..c9759eaf9a89 100644
--- a/contrib/libarchive/libarchive/archive_read_support_format_zip.c
+++ b/contrib/libarchive/libarchive/archive_read_support_format_zip.c
@@ -1393,7 +1393,7 @@ check_authentication_code(struct archive_read *a, const 
void *_p)
  *  [CRC32] [compressed low] [compressed high] [uncompressed low] 
[uncompressed high] [other PK marker]
  * ```
  * Since the 32-bit and 64-bit compressed sizes both match, the
- * actualy size must fit in 32 bits, which implies the high-order
+ * actual size must fit in 32 bits, which implies the high-order
  * word of the compressed size is zero.  So we know the uncompressed
  * low word is zero, which again implies that if we accept the shorter
  * format, there will not be a valid PK marker following it.
@@ -4083,6 +4083,17 @@ slurp_central_directory(struct archive_read *a, struct 
archive_entry* entry,
                        } else {
                                /* Generate resource fork name to find its
                                 * resource file at zip->tree_rsrc. */
+
+                               /* If this is an entry ending with slash,
+                                * make the resource for name slash-less
+                                * as the actual resource fork doesn't end with 
'/'.
+                                */
+                               size_t tmp_length = filename_length;
+                               if (tmp_length > 0 && name[tmp_length - 1] == 
'/') {
+                                       tmp_length--;
+                                       r = rsrc_basename(name, tmp_length);
+                               }
+
                                archive_strcpy(&(zip_entry->rsrcname),
                                    "__MACOSX/");
                                archive_strncat(&(zip_entry->rsrcname),
@@ -4090,7 +4101,7 @@ slurp_central_directory(struct archive_read *a, struct 
archive_entry* entry,
                                archive_strcat(&(zip_entry->rsrcname), "._");
                                archive_strncat(&(zip_entry->rsrcname),
                                    name + (r - name),
-                                   filename_length - (r - name));
+                                   tmp_length - (r - name));
                                /* Register an entry to RB tree to sort it by
                                 * file offset. */
                                __archive_rb_tree_insert_node(&zip->tree,
diff --git a/contrib/libarchive/libarchive/archive_util.c 
b/contrib/libarchive/libarchive/archive_util.c
index 32d4bd40988c..7b918fef04b8 100644
--- a/contrib/libarchive/libarchive/archive_util.c
+++ b/contrib/libarchive/libarchive/archive_util.c
@@ -255,10 +255,9 @@ __archive_mktempx(const char *tmpdir, wchar_t *template)
 #endif
        fd = -1;
        ws = NULL;
+       archive_string_init(&temp_name);
 
        if (template == NULL) {
-               archive_string_init(&temp_name);
-
                /* Get a temporary directory. */
                if (tmpdir == NULL) {
                        size_t l;
diff --git a/contrib/libarchive/libarchive/archive_write_add_filter_zstd.c 
b/contrib/libarchive/libarchive/archive_write_add_filter_zstd.c
index 94249accd08b..7ea3d18c9b76 100644
--- a/contrib/libarchive/libarchive/archive_write_add_filter_zstd.c
+++ b/contrib/libarchive/libarchive/archive_write_add_filter_zstd.c
@@ -29,6 +29,9 @@
 #ifdef HAVE_ERRNO_H
 #include <errno.h>
 #endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
 #ifdef HAVE_STDINT_H
 #include <stdint.h>
 #endif
@@ -38,6 +41,9 @@
 #ifdef HAVE_STRING_H
 #include <string.h>
 #endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
 #ifdef HAVE_ZSTD_H
 #include <zstd.h>
 #endif
@@ -190,6 +196,7 @@ string_to_number(const char *string, intmax_t *numberp)
        return (ARCHIVE_OK);
 }
 
+#if HAVE_ZSTD_H && HAVE_ZSTD_compressStream
 static int
 string_to_size(const char *string, size_t *numberp)
 {
@@ -224,6 +231,7 @@ string_to_size(const char *string, size_t *numberp)
        *numberp = (size_t)(number << shift);
        return (ARCHIVE_OK);
 }
+#endif
 
 /*
  * Set write options.
@@ -264,7 +272,20 @@ archive_compressor_zstd_options(struct 
archive_write_filter *f, const char *key,
                if (string_to_number(value, &threads) != ARCHIVE_OK) {
                        return (ARCHIVE_WARN);
                }
-               if (threads < 0) {
+
+#if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
+               if (threads == 0) {
+                       threads = sysconf(_SC_NPROCESSORS_ONLN);
+               }
+#elif !defined(__CYGWIN__) && defined(_WIN32_WINNT) && \
+    _WIN32_WINNT >= 0x0601 /* _WIN32_WINNT_WIN7 */
+               if (threads == 0) {
+                       DWORD winCores = GetActiveProcessorCount(
+                           ALL_PROCESSOR_GROUPS);
+                       threads = (intmax_t)winCores;
+               }
+#endif
+               if (threads < 0 || threads > INT_MAX) {
                        return (ARCHIVE_WARN);
                }
                data->threads = (int)threads;
diff --git a/contrib/libarchive/libarchive/archive_write_disk_posix.c 
b/contrib/libarchive/libarchive/archive_write_disk_posix.c
index f671bc6db747..d69c77ea0517 100644
--- a/contrib/libarchive/libarchive/archive_write_disk_posix.c
+++ b/contrib/libarchive/libarchive/archive_write_disk_posix.c
@@ -4427,7 +4427,8 @@ fixup_appledouble(struct archive_write_disk *a, const 
char *pathname)
 #else
                la_stat(datafork.s, &st) == -1 ||
 #endif
-           (st.st_mode & AE_IFMT) != AE_IFREG)
+           (((st.st_mode & AE_IFMT) != AE_IFREG) &&
+               ((st.st_mode & AE_IFMT) != AE_IFDIR)))
                goto skip_appledouble;
 
        /*
diff --git a/contrib/libarchive/libarchive/archive_write_private.h 
b/contrib/libarchive/libarchive/archive_write_private.h
index abd5a8ddcd85..f259ccb16546 100644
--- a/contrib/libarchive/libarchive/archive_write_private.h
+++ b/contrib/libarchive/libarchive/archive_write_private.h
@@ -158,7 +158,7 @@ int __archive_write_program_write(struct 
archive_write_filter *,
            struct archive_write_program_data *, const void *, size_t);
 
 /*
- * Get a encryption passphrase.
+ * Get an encryption passphrase.
  */
 const char * __archive_write_get_passphrase(struct archive_write *a);
 #endif
diff --git a/contrib/libarchive/libarchive/archive_write_set_format_gnutar.c 
b/contrib/libarchive/libarchive/archive_write_set_format_gnutar.c
index 92b06c5f5fb4..a88350b87411 100644
--- a/contrib/libarchive/libarchive/archive_write_set_format_gnutar.c
+++ b/contrib/libarchive/libarchive/archive_write_set_format_gnutar.c
@@ -387,7 +387,7 @@ archive_write_gnutar_header(struct archive_write *a,
        if (r != 0) {
                if (errno == ENOMEM) {
                        archive_set_error(&a->archive, ENOMEM,
-                           "Can't allocate memory for Pathame");
+                           "Can't allocate memory for pathname");
                        ret = ARCHIVE_FATAL;
                        goto exit_write_header;
                }
diff --git a/contrib/libarchive/libarchive/archive_write_set_passphrase.c 
b/contrib/libarchive/libarchive/archive_write_set_passphrase.c
index 977fc4a9ee6b..f871c8e2f810 100644
--- a/contrib/libarchive/libarchive/archive_write_set_passphrase.c
+++ b/contrib/libarchive/libarchive/archive_write_set_passphrase.c
@@ -30,14 +30,9 @@
 #endif
 #include "archive_write_private.h"
 
-int
-archive_write_set_passphrase(struct archive *_a, const char *p)
+static int
+set_passphrase(struct archive_write *a, const char *p)
 {
-       struct archive_write *a = (struct archive_write *)_a;
-
-       archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW,
-               "archive_write_set_passphrase");
-
        if (p == NULL || p[0] == '\0') {
                archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
                    "Empty passphrase is unacceptable");
@@ -54,6 +49,18 @@ archive_write_set_passphrase(struct archive *_a, const char 
*p)
 }
 
 
+int
+archive_write_set_passphrase(struct archive *_a, const char *p)
+{
+       struct archive_write *a = (struct archive_write *)_a;
+
+       archive_check_magic(_a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW,
+               "archive_write_set_passphrase");
+
+       return (set_passphrase(a, p));
+}
+
+
 int
 archive_write_set_passphrase_callback(struct archive *_a, void *client_data,
     archive_passphrase_callback *cb)
@@ -80,15 +87,9 @@ __archive_write_get_passphrase(struct archive_write *a)
                const char *p;
                p = a->passphrase_callback(&a->archive,
                    a->passphrase_client_data);
-               if (p != NULL) {
-                       a->passphrase = strdup(p);
-                       if (a->passphrase == NULL) {
-                               archive_set_error(&a->archive, ENOMEM,
-                                   "Can't allocate data for passphrase");
-                               return (NULL);
-                       }
-                       return (a->passphrase);
-               }
+               set_passphrase(a, p);
+               a->passphrase_callback = NULL;
+               a->passphrase_client_data = NULL;
        }
-       return (NULL);
+       return (a->passphrase);
 }
diff --git a/contrib/libarchive/libarchive/libarchive_internals.3 
b/contrib/libarchive/libarchive/libarchive_internals.3
index d4696f648292..2978b48c3e97 100644
--- a/contrib/libarchive/libarchive/libarchive_internals.3
+++ b/contrib/libarchive/libarchive/libarchive_internals.3
@@ -124,7 +124,7 @@ to read the entire file into memory at once and return the
 entire file to libarchive as a single block;
 other clients may begin asynchronous I/O operations for the
 next block on each request.
-.Ss Decompresssion Layer
+.Ss Decompression Layer
 The decompression layer not only handles decompression,
 it also buffers data so that the format handlers see a
 much nicer I/O model.
diff --git 
a/contrib/libarchive/libarchive/test/test_read_format_xar_doublelink.c 
b/contrib/libarchive/libarchive/test/test_read_format_xar_doublelink.c
new file mode 100644
index 000000000000..78d6626a09bf
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_xar_doublelink.c
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 2024 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.
+ */
+#include "test.h"
+
+#define __LIBARCHIVE_BUILD
+
+DEFINE_TEST(test_read_format_xar_doublelink)
+{
+       const char *refname = "test_read_format_xar_doublelink.xar";
+       struct archive *a;
+       struct archive_entry *ae;
+
+       extract_reference_file(refname);
+
+       /* Verify with seeking reader. */
+       assert((a = archive_read_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+        if(ARCHIVE_OK != archive_read_support_format_xar(a)) {
+                skipping("XAR format unsupported");
+                assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+                return;
+        }
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, refname,
+           10240));
+
+       assertA(ARCHIVE_FATAL == archive_read_next_header(a, &ae));
+       assertEqualString(archive_error_string(a),
+               "File with multiple link attributes");
+       assert(archive_errno(a) != 0);
+
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+       assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+}
diff --git 
a/contrib/libarchive/libarchive/test/test_read_format_xar_doublelink.xar.uu 
b/contrib/libarchive/libarchive/test/test_read_format_xar_doublelink.xar.uu
new file mode 100644
index 000000000000..7aa638a86e7c
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_read_format_xar_doublelink.xar.uu
@@ -0,0 +1,12 @@
+begin 664 test_read_format_xar_doublelink.xar
+M>&%R(0`<``$````````!0`````````/7`````7B<[9/!<L(@%$7W?@7#/H60
+MU'0R!'?]`KOICDF>D3&``]'1?GT!-1U;;:=[5[G<=WB0=P>^..@![<%Y94V#
+M\R>*$9C6=LKT#7Y;OF8O>"%F_""=F"$^VC9\$&\=R#'LR$:E03#*RHR6&2N6
+MM*KIO,YS3JZ1M&D-[<;O-/+C<8`&^[7,<:P@;E<K#Z.@G)Q5<KWZB,TY22*V
+M()<>:;52`R#5A6N?VQ@9CHIN.#_IY(['+:!!F4V#K5.],G+`8BU=%SU.8OF?
+MH#*V`U%5K"@9)Z=5*G2P5RT8*YY+3J9%*ND(T?D\%/3$[U0G<DK#+T9ULCPX
+MH75PHDA6/U']A>J=W6T3=E+);&^E4=0%?0^#N\00;G(;8U7`]!<F?\'D%"J)
+MX[Y.@WU/@]U)(_\SACO$8_X_YA_&$]\F)^FE?@)<4AJ<B%QTTZN3JTL:$,<5
+<`XH;(KD-Q0=XG.V3P7+"(!1%]WX%PSZ%D-1T,@``
+`
+end
diff --git a/contrib/libarchive/libarchive/test/test_write_disk_appledouble.c 
b/contrib/libarchive/libarchive/test/test_write_disk_appledouble.c
index 3265a94d2fed..8de6c8b50413 100644
--- a/contrib/libarchive/libarchive/test/test_write_disk_appledouble.c
+++ b/contrib/libarchive/libarchive/test/test_write_disk_appledouble.c
@@ -236,3 +236,87 @@ DEFINE_TEST(test_write_disk_appledouble)
        assertEqualFile("hfscmp/file3", "nocmp/file3");
 #endif
 }
+
+/* Test writing apple doubles to disk from zip format */
+DEFINE_TEST(test_write_disk_appledouble_zip)
+{
+#if !defined(__APPLE__) || !defined(UF_COMPRESSED) || 
!defined(HAVE_SYS_XATTR_H)\
+       || !defined(HAVE_ZLIB_H)
+       skipping("MacOS-specific AppleDouble test");
+#else
+       const char *refname = "test_write_disk_appledouble_zip.zip";
+       struct archive *ad, *a;
+       struct archive_entry *ae;
+       struct stat st;
+
+       extract_reference_file(refname);
+
+       /*
+        * Extract an archive to disk.
+        */
+       assert((ad = archive_write_disk_new()) != NULL);
+       assertEqualIntA(ad, ARCHIVE_OK,
+           archive_write_disk_set_standard_lookup(ad));
+       assertEqualIntA(ad, ARCHIVE_OK,
+           archive_write_disk_set_options(ad,
+               ARCHIVE_EXTRACT_TIME |
+               ARCHIVE_EXTRACT_SECURE_SYMLINKS |
+               ARCHIVE_EXTRACT_SECURE_NODOTDOT));
+
+       assert((a = archive_read_new()) != NULL);
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a,
+           refname, 512 * 20));
+
+       /* Skip The top level directory */
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+       assertEqualString("apple_double_dir/", archive_entry_pathname(ae));
+
+       /* Extract apple_double_test */
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+       assertEqualString("apple_double_dir/apple_double_dir_test/", 
archive_entry_pathname(ae));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_extract2(a, ae, ad));
+
+       /* Extract ._apple_double_dir_test which will be merged into 
apple_double_dir_test as metadata. */
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+       assertEqualString("apple_double_dir/._apple_double_dir_test", 
archive_entry_pathname(ae));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_extract2(a, ae, ad));
+
+       /* Extract test_file */
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+       assertEqualString("apple_double_dir/test_file", 
archive_entry_pathname(ae));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_extract2(a, ae, ad));
+
+       /* Extract ._test_file which will be merged into test_file as metadata. 
*/
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae));
+       assertEqualString("apple_double_dir/._test_file", 
archive_entry_pathname(ae));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_extract2(a, ae, ad));
+
+       assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae));
+       assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
+       assertEqualInt(ARCHIVE_OK, archive_read_free(a));
+       assertEqualIntA(ad, ARCHIVE_OK, archive_write_free(ad));
+
+       /* Test test_file */
+       assertEqualInt(0, stat("apple_double_dir/test_file", &st));
+       assertFileSize("apple_double_dir/test_file", 5);
+       failure("'%s' should have Resource Fork", "test_file");
+       assertEqualInt(1, has_xattr("apple_double_dir/test_file", 
"com.apple.ResourceFork"));
+
+       /* Test apple_double_dir_test */
+       failure("'%s' should have quarantine xattr", "apple_double_dir_test");
+       assertEqualInt(1, has_xattr("apple_double_dir/apple_double_dir_test", 
"com.apple.quarantine"));
+
+       /* Test ._test_file. */
+       failure("'apple_double_dir/._test_file' should be merged and removed");
+       assertFileNotExists("apple_double_dir/._test_file");
+
+       /* Test ._apple_double_dir_test */
+       failure("'apple_double_dir/._._apple_double_dir_test' should be merged 
and removed");
+       assertFileNotExists("apple_double_dir/._apple_double_dir_test");
+
+       assertChdir("..");
+
+#endif
+}
diff --git 
a/contrib/libarchive/libarchive/test/test_write_disk_appledouble_zip.zip.uu 
b/contrib/libarchive/libarchive/test/test_write_disk_appledouble_zip.zip.uu
new file mode 100644
index 000000000000..5ab67533d559
--- /dev/null
+++ b/contrib/libarchive/libarchive/test/test_write_disk_appledouble_zip.zip.uu
@@ -0,0 +1,27 @@
+begin 644 test_write_disk_appledouble_zip.zip
+M4$L#!`H```````MM?%@````````````````1`!``87!P;&5?9&]U8FQE7V1I
+M<B]56`P`O=4%9K75!6;U`10`4$L#!`H```````MM?%@````````````````G
+M`!``87!P;&5?9&]U8FQE7V1I<B]A<'!L95]D;W5B;&5?9&ER7W1E<W0O55@,
+M`+W5!6:UU05F]0$4`%!+`P04``@`"``+;7Q8````````````````*``0`&%P
+M<&QE7V1O=6)L95]D:7(O+E]A<'!L95]D;W5B;&5?9&ER7W1E<W156`P`O=4%
+M9K75!6;U`10`8V`58V=@8F#P34Q6\`]6B%"``I`8`R<0&P%Q!1"#^*L8B`*.
+M(2%!4"9(QPP@%D)3PH@0%TW.S]5++"C(2=4K+$TL2LPKR<Q+92C4-S"P,+8V
+M@`)K:P8`4$L'"!2N=6M7````J@```%!+`P04``@`"`!93GQ8````````````
+M````&@`0`&%P<&QE7V1O=6)L95]D:7(O=&5S=%]F:6QE55@,`+'5!6;IGP5F
+M]0$4`"M)+2[A`@!02P<(QC6Y.P<````%````4$L#!!0`"``(`%E.?%@`````
+M```````````<`!``87!P;&5?9&]U8FQE7V1I<B\N7W1E<W1?9FEL9558#`"Q
+MU05FZ9\%9O4!%`!C8!5C9V!B8/!-3%;P#U:(4(`"D!@#)Q`;`;$;$(/X%4#,
+MQT`0.(:$!$&9%5",`8I2B_-+BY)3%=+RB[*Y`%!+!P@HPLP3/@```(8```!0
+M2P$"%0,*```````+;7Q8````````````````$0`,``````````!`[4$`````
+M87!P;&5?9&]U8FQE7V1I<B]56`@`O=4%9K75!6902P$"%0,*```````+;7Q8
+M````````````````)P`,``````````!`[4$_````87!P;&5?9&]U8FQE7V1I
+M<B]A<'!L95]D;W5B;&5?9&ER7W1E<W0O55@(`+W5!6:UU05F4$L!`A4#%``(
+M``@`"VU\6!2N=6M7````J@```"@`#```````````0*2!E````&%P<&QE7V1O
+M=6)L95]D:7(O+E]A<'!L95]D;W5B;&5?9&ER7W1E<W156`@`O=4%9K75!690
+M2P$"%0,4``@`"`!93GQ8QC6Y.P<````%````&@`,``````````!`I(%1`0``
+M87!P;&5?9&]U8FQE7V1I<B]T97-T7V9I;&556`@`L=4%9NF?!6902P$"%0,4
+M``@`"`!93GQ8*,+,$SX```"&````'``,``````````!`I(&P`0``87!P;&5?
+M9&]U8FQE7V1I<B\N7W1E<W1?9FEL9558"`"QU05FZ9\%9E!+!08`````!0`%
++`+@!``!(`@``````
+`
+end
diff --git a/contrib/libarchive/libarchive_fe/passphrase.c 
b/contrib/libarchive/libarchive_fe/passphrase.c
index 9d95d527067b..90fef32d254c 100644
--- a/contrib/libarchive/libarchive_fe/passphrase.c
+++ b/contrib/libarchive/libarchive_fe/passphrase.c
@@ -76,6 +76,7 @@
 
 
 #if defined(_WIN32) && !defined(__CYGWIN__)
+#include <string.h>
 #include <windows.h>
 
 static char *
@@ -113,8 +114,7 @@ readpassphrase(const char *prompt, char *buf, size_t 
bufsiz, int flags)
        WriteFile(hStdout, "\r\n", 2, NULL, NULL);
        buf[rbytes] = '\0';
        /* Remove trailing carriage return(s). */
-       if (rbytes > 2 && buf[rbytes - 2] == '\r' && buf[rbytes - 1] == '\n')
-               buf[rbytes - 2] = '\0';
+       buf[strcspn(buf, "\r\n")] = '\0';
 
        return (buf);
 }
diff --git a/contrib/libarchive/tar/bsdtar.1 b/contrib/libarchive/tar/bsdtar.1
index e570d2a48a01..fe9ec9504674 100644
--- a/contrib/libarchive/tar/bsdtar.1
+++ b/contrib/libarchive/tar/bsdtar.1
@@ -23,7 +23,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd March 1, 2024
+.Dd April 23, 2024
 .Dt TAR 1
 .Os
 .Sh NAME
@@ -644,14 +644,13 @@ A decimal integer from 4 to 7 specifying the lz4 
compression block size
 .It Cm lz4:block-dependence
 Use the previous block of the block being compressed for
 a compression dictionary to improve compression ratio.
-.It Cm zstd:compression-level
-A decimal integer specifying the zstd compression level. Supported values 
depend
+.It Cm zstd:compression-level Ns = Ns Ar N
+A decimal integer specifying the zstd compression level.
+Supported values depend
 on the library version, common values are from 1 to 22.
-.It Cm zstd:threads
-Specify the number of worker threads to use.
-Setting threads to a special value 0 makes
-.Xr zstd 1
-use as many threads as there are CPU cores on the system.
+.It Cm zstd:threads Ns = Ns Ar N
+Specify the number of worker threads to use, or 0 to use as many
+threads as there are CPU cores in the system.
 .It Cm zstd:frame-per-file
 Start a new compression frame at the beginning of each file in the
 archive.
diff --git a/contrib/libarchive/tar/bsdtar.c b/contrib/libarchive/tar/bsdtar.c
index b070e0faeb66..42baab2861bd 100644
--- a/contrib/libarchive/tar/bsdtar.c
+++ b/contrib/libarchive/tar/bsdtar.c
@@ -157,6 +157,7 @@ main(int argc, char **argv)
        char                    *tptr, *uptr;
        char                     possible_help_request;
        char                     buff[16];
+       long                     l;
 
        /*
         * Use a pointer for consistency, but stack-allocated storage
@@ -301,16 +302,15 @@ main(int argc, char **argv)
                        /* libarchive doesn't need this; just ignore it. */
                        break;
                case 'b': /* SUSv2 */
-                       errno = 0;
                        tptr = NULL;
-                       t = (int)strtol(bsdtar->argument, &tptr, 10);
-                       if (errno || t <= 0 || t > 8192 ||
+                       l = strtol(bsdtar->argument, &tptr, 10);
+                       if (l <= 0 || l > 8192L ||
                            *(bsdtar->argument) == '\0' || tptr == NULL ||
                            *tptr != '\0') {
                                lafe_errc(1, 0, "Invalid or out of range "
                                    "(1..8192) argument to -b");
                        }
-                       bsdtar->bytes_per_block = 512 * t;
+                       bsdtar->bytes_per_block = 512 * (int)l;
                        /* Explicit -b forces last block size. */
                        bsdtar->bytes_in_last_block = bsdtar->bytes_per_block;
                        break;
@@ -369,44 +369,42 @@ main(int argc, char **argv)
                        bsdtar->filename = bsdtar->argument;
                        break;
*** 261 LINES SKIPPED ***

Reply via email to