The branch main has been updated by mm:

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

commit bd5e624a861433dee76fe00a8acedc9564425332
Merge: 8d0ed56646f0 b5a00e61e90d
Author:     Martin Matuska <m...@freebsd.org>
AuthorDate: 2022-12-13 19:21:13 +0000
Commit:     Martin Matuska <m...@freebsd.org>
CommitDate: 2022-12-13 19:21:13 +0000

    libarchive: merge from vendor branch
    
    Libarchive 3.6.2
    
    Important bug fixes:
      rar5 reader: fix possible garbled output with bsdtar -O (#1745)
      mtree reader: support reading mtree files with tabs (#1783)
      various small fixes for issues found by CodeQL
    
    MFC after:      2 weeks
    PR:             286306 (exp-run)

 contrib/libarchive/NEWS                            |  2 +
 contrib/libarchive/README.md                       |  5 ++
 contrib/libarchive/cpio/test/test_option_t.c       | 24 +++++-
 contrib/libarchive/libarchive/archive.h            |  6 +-
 contrib/libarchive/libarchive/archive_digest.c     | 16 ++--
 contrib/libarchive/libarchive/archive_entry.c      | 14 ++++
 contrib/libarchive/libarchive/archive_entry.h      |  4 +-
 contrib/libarchive/libarchive/archive_hmac.c       | 29 ++++++++
 .../libarchive/libarchive/archive_hmac_private.h   |  7 ++
 contrib/libarchive/libarchive/archive_platform.h   |  3 +-
 .../libarchive/archive_read_disk_posix.c           |  7 +-
 .../libarchive/archive_read_support_filter_lz4.c   |  6 ++
 .../libarchive/archive_read_support_filter_lzop.c  |  2 +
 .../libarchive/archive_read_support_filter_xz.c    |  2 +
 .../libarchive/archive_read_support_format_7zip.c  |  8 +-
 .../libarchive/archive_read_support_format_cab.c   |  6 +-
 .../archive_read_support_format_iso9660.c          |  2 +-
 .../libarchive/archive_read_support_format_lha.c   |  6 +-
 .../libarchive/archive_read_support_format_mtree.c | 24 ++++--
 .../libarchive/archive_read_support_format_rar.c   | 10 +++
 .../libarchive/archive_read_support_format_rar5.c  |  9 +++
 .../libarchive/archive_read_support_format_tar.c   | 20 ++++-
 .../libarchive/archive_read_support_format_xar.c   |  4 +
 contrib/libarchive/libarchive/archive_string.c     |  6 +-
 contrib/libarchive/libarchive/archive_write.c      |  8 ++
 .../libarchive/archive_write_disk_posix.c          |  4 +-
 contrib/libarchive/libarchive/archive_write_open.3 |  1 +
 .../libarchive/archive_write_set_format_pax.c      |  2 +-
 contrib/libarchive/libarchive/filter_fork_posix.c  |  2 +-
 .../libarchive/test/test_acl_platform_nfs4.c       |  4 +-
 .../libarchive/test/test_archive_api_feature.c     |  2 +-
 .../libarchive/test/test_archive_match_time.c      | 30 ++++++++
 .../test/test_archive_string_conversion.c          |  1 +
 .../libarchive/test/test_read_format_mtree.c       | 30 ++++++++
 .../libarchive/test/test_read_format_rar5.c        | 43 ++++++++---
 .../test/test_read_format_tar_invalid_pax_size.c   | 53 +++++++++++++
 .../test_read_format_tar_invalid_pax_size.tar.uu   | 38 ++++++++++
 .../libarchive/test/test_read_truncated_filter.c   |  4 +-
 .../libarchive/libarchive/test/test_sparse_basic.c |  4 +-
 .../libarchive/libarchive/test/test_tar_large.c    |  4 +-
 .../libarchive/test/test_write_disk_secure744.c    |  2 +-
 .../libarchive/test/test_write_filter_b64encode.c  |  8 +-
 .../libarchive/test/test_write_filter_bzip2.c      | 12 +--
 .../libarchive/test/test_write_filter_compress.c   |  4 +-
 .../libarchive/test/test_write_filter_gzip.c       | 12 +--
 .../libarchive/test/test_write_filter_lrzip.c      |  4 +-
 .../libarchive/test/test_write_filter_lz4.c        | 16 ++--
 .../libarchive/test/test_write_filter_lzip.c       | 12 +--
 .../libarchive/test/test_write_filter_lzma.c       | 12 +--
 .../libarchive/test/test_write_filter_lzop.c       | 12 +--
 .../libarchive/test/test_write_filter_uuencode.c   |  8 +-
 .../libarchive/test/test_write_filter_xz.c         | 12 +--
 .../libarchive/test/test_write_filter_zstd.c       | 12 +--
 .../test/test_write_format_zip_compression_store.c | 23 +++++-
 .../libarchive/test/test_write_format_zip_file.c   | 21 +++++-
 .../test/test_write_format_zip_file_zip64.c        | 21 +++++-
 .../libarchive/test/test_write_format_zip_large.c  |  4 +-
 contrib/libarchive/tar/bsdtar.1                    |  2 +-
 contrib/libarchive/tar/subst.c                     |  1 +
 contrib/libarchive/tar/test/test_copy.c            | 20 ++---
 contrib/libarchive/tar/test/test_option_b.c        |  8 +-
 contrib/libarchive/tar/util.c                      | 21 +++---
 contrib/libarchive/test_utils/test_main.c          | 87 ++++++++++++++--------
 lib/libarchive/tests/Makefile                      |  2 +
 64 files changed, 610 insertions(+), 178 deletions(-)

diff --cc contrib/libarchive/README.md
index d5ef70c2191d,000000000000..404076237871
mode 100644,000000..100644
--- a/contrib/libarchive/README.md
+++ b/contrib/libarchive/README.md
@@@ -1,227 -1,0 +1,232 @@@
 +# Welcome to libarchive!
 +
 +The libarchive project develops a portable, efficient C library that
 +can read and write streaming archives in a variety of formats.  It
 +also includes implementations of the common `tar`, `cpio`, and `zcat`
 +command-line tools that use the libarchive library.
 +
 +## Questions?  Issues?
 +
 +* http://www.libarchive.org is the home for ongoing
 +  libarchive development, including documentation,
 +  and links to the libarchive mailing lists.
 +* To report an issue, use the issue tracker at
 +  https://github.com/libarchive/libarchive/issues
 +* To submit an enhancement to libarchive, please
 +  submit a pull request via GitHub: 
https://github.com/libarchive/libarchive/pulls
 +
 +## Contents of the Distribution
 +
 +This distribution bundle includes the following major components:
 +
 +* **libarchive**: a library for reading and writing streaming archives
 +* **tar**: the 'bsdtar' program is a full-featured 'tar' implementation built 
on libarchive
 +* **cpio**: the 'bsdcpio' program is a different interface to essentially the 
same functionality
 +* **cat**: the 'bsdcat' program is a simple replacement tool for zcat, bzcat, 
xzcat, and such
 +* **examples**: Some small example programs that you may find useful.
 +* **examples/minitar**: a compact sample demonstrating use of libarchive.
 +* **contrib**:  Various items sent to me by third parties; please contact the 
authors with any questions.
 +
 +The top-level directory contains the following information files:
 +
 +* **NEWS** - highlights of recent changes
 +* **COPYING** - what you can do with this
 +* **INSTALL** - installation instructions
 +* **README** - this file
 +* **CMakeLists.txt** - input for "cmake" build tool, see INSTALL
 +* **configure** - configuration script, see INSTALL for details.  If your 
copy of the source lacks a `configure` script, you can try to construct it by 
running the script in `build/autogen.sh` (or use `cmake`).
 +
 +The following files in the top-level directory are used by the 'configure' 
script:
++
 +* `Makefile.am`, `aclocal.m4`, `configure.ac` - used to build this 
distribution, only needed by maintainers
 +* `Makefile.in`, `config.h.in` - templates used by configure script
 +
 +## Documentation
 +
 +In addition to the informational articles and documentation
 +in the online [libarchive 
Wiki](https://github.com/libarchive/libarchive/wiki),
 +the distribution also includes a number of manual pages:
 +
 + * bsdtar.1 explains the use of the bsdtar program
 + * bsdcpio.1 explains the use of the bsdcpio program
 + * bsdcat.1 explains the use of the bsdcat program
 + * libarchive.3 gives an overview of the library as a whole
 + * archive_read.3, archive_write.3, archive_write_disk.3, and
 +   archive_read_disk.3 provide detailed calling sequences for the read
 +   and write APIs
 + * archive_entry.3 details the "struct archive_entry" utility class
 + * archive_internals.3 provides some insight into libarchive's
 +   internal structure and operation.
 + * libarchive-formats.5 documents the file formats supported by the library
 + * cpio.5, mtree.5, and tar.5 provide detailed information about these
 +   popular archive formats, including hard-to-find details about
 +   modern cpio and tar variants.
 +
 +The manual pages above are provided in the 'doc' directory in
 +a number of different formats.
 +
 +You should also read the copious comments in `archive.h` and the
 +source code for the sample programs for more details.  Please let us
 +know about any errors or omissions you find.
 +
 +## Supported Formats
 +
 +Currently, the library automatically detects and reads the following formats:
++
 +  * Old V7 tar archives
 +  * POSIX ustar
 +  * GNU tar format (including GNU long filenames, long link names, and sparse 
files)
 +  * Solaris 9 extended tar format (including ACLs)
 +  * POSIX pax interchange format
 +  * POSIX octet-oriented cpio
 +  * SVR4 ASCII cpio
 +  * Binary cpio (big-endian or little-endian)
 +  * PWB binary cpio
 +  * ISO9660 CD-ROM images (with optional Rockridge or Joliet extensions)
 +  * ZIP archives (with uncompressed or "deflate" compressed entries, 
including support for encrypted Zip archives)
 +  * ZIPX archives (with support for bzip2, ppmd8, lzma and xz compressed 
entries)
 +  * GNU and BSD 'ar' archives
 +  * 'mtree' format
 +  * 7-Zip archives
 +  * Microsoft CAB format
 +  * LHA and LZH archives
 +  * RAR and RAR 5.0 archives (with some limitations due to RAR's proprietary 
status)
 +  * XAR archives
 +
 +The library also detects and handles any of the following before evaluating 
the archive:
++
 +  * uuencoded files
 +  * files with RPM wrapper
 +  * gzip compression
 +  * bzip2 compression
 +  * compress/LZW compression
 +  * lzma, lzip, and xz compression
 +  * lz4 compression
 +  * lzop compression
 +  * zstandard compression
 +
 +The library can create archives in any of the following formats:
++
 +  * POSIX ustar
 +  * POSIX pax interchange format
 +  * "restricted" pax format, which will create ustar archives except for
 +    entries that require pax extensions (for long filenames, ACLs, etc).
 +  * Old GNU tar format
 +  * Old V7 tar format
 +  * POSIX octet-oriented cpio
 +  * SVR4 "newc" cpio
 +  * Binary cpio (little-endian)
 +  * PWB binary cpio
 +  * shar archives
 +  * ZIP archives (with uncompressed or "deflate" compressed entries)
 +  * GNU and BSD 'ar' archives
 +  * 'mtree' format
 +  * ISO9660 format
 +  * 7-Zip archives
 +  * XAR archives
 +
 +When creating archives, the result can be filtered with any of the following:
++
 +  * uuencode
 +  * gzip compression
 +  * bzip2 compression
 +  * compress/LZW compression
 +  * lzma, lzip, and xz compression
 +  * lz4 compression
 +  * lzop compression
 +  * zstandard compression
 +
 +## Notes about the Library Design
 +
 +The following notes address many of the most common
 +questions we are asked about libarchive:
 +
 +* This is a heavily stream-oriented system.  That means that
 +  it is optimized to read or write the archive in a single
 +  pass from beginning to end.  For example, this allows
 +  libarchive to process archives too large to store on disk
 +  by processing them on-the-fly as they are read from or
 +  written to a network or tape drive.  This also makes
 +  libarchive useful for tools that need to produce
 +  archives on-the-fly (such as webservers that provide
 +  archived contents of a users account).
 +
 +* In-place modification and random access to the contents
 +  of an archive are not directly supported.  For some formats,
 +  this is not an issue: For example, tar.gz archives are not
 +  designed for random access.  In some other cases, libarchive
 +  can re-open an archive and scan it from the beginning quickly
 +  enough to provide the needed abilities even without true
 +  random access.  Of course, some applications do require true
 +  random access; those applications should consider alternatives
 +  to libarchive.
 +
 +* The library is designed to be extended with new compression and
 +  archive formats.  The only requirement is that the format be
 +  readable or writable as a stream and that each archive entry be
 +  independent.  There are articles on the libarchive Wiki explaining
 +  how to extend libarchive.
 +
 +* On read, compression and format are always detected automatically.
 +
 +* The same API is used for all formats; it should be very
 +  easy for software using libarchive to transparently handle
 +  any of libarchive's archiving formats.
 +
 +* Libarchive's automatic support for decompression can be used
 +  without archiving by explicitly selecting the "raw" and "empty"
 +  formats.
 +
 +* I've attempted to minimize static link pollution.  If you don't
 +  explicitly invoke a particular feature (such as support for a
 +  particular compression or format), it won't get pulled in to
 +  statically-linked programs.  In particular, if you don't explicitly
 +  enable a particular compression or decompression support, you won't
 +  need to link against the corresponding compression or decompression
 +  libraries.  This also reduces the size of statically-linked
 +  binaries in environments where that matters.
 +
 +* The library is generally _thread safe_ depending on the platform:
 +  it does not define any global variables of its own.  However, some
 +  platforms do not provide fully thread-safe versions of key C library
 +  functions.  On those platforms, libarchive will use the non-thread-safe
 +  functions.  Patches to improve this are of great interest to us.
 +
 +* In particular, libarchive's modules to read or write a directory
 +  tree do use `chdir()` to optimize the directory traversals.  This
 +  can cause problems for programs that expect to do disk access from
 +  multiple threads.  Of course, those modules are completely
 +  optional and you can use the rest of libarchive without them.
 +
 +* The library is _not_ thread aware, however.  It does no locking
 +  or thread management of any kind.  If you create a libarchive
 +  object and need to access it from multiple threads, you will
 +  need to provide your own locking.
 +
 +* On read, the library accepts whatever blocks you hand it.
 +  Your read callback is free to pass the library a byte at a time
 +  or mmap the entire archive and give it to the library at once.
 +  On write, the library always produces correctly-blocked output.
 +
 +* The object-style approach allows you to have multiple archive streams
 +  open at once.  bsdtar uses this in its "@archive" extension.
 +
 +* The archive itself is read/written using callback functions.
 +  You can read an archive directly from an in-memory buffer or
 +  write it to a socket, if you wish.  There are some utility
 +  functions to provide easy-to-use "open file," etc, capabilities.
 +
 +* The read/write APIs are designed to allow individual entries
 +  to be read or written to any data source:  You can create
 +  a block of data in memory and add it to a tar archive without
 +  first writing a temporary file.  You can also read an entry from
 +  an archive and write the data directly to a socket.  If you want
 +  to read/write entries to disk, there are convenience functions to
 +  make this especially easy.
 +
 +* Note: The "pax interchange format" is a POSIX standard extended tar
 +  format that should be used when the older _ustar_ format is not
 +  appropriate.  It has many advantages over other tar formats
 +  (including the legacy GNU tar format) and is widely supported by
 +  current tar implementations.
 +
diff --cc 
contrib/libarchive/libarchive/test/test_read_format_tar_invalid_pax_size.c
index 000000000000,0a03cb677593..0a03cb677593
mode 000000,100644..100644
--- a/contrib/libarchive/libarchive/test/test_read_format_tar_invalid_pax_size.c
+++ b/contrib/libarchive/libarchive/test/test_read_format_tar_invalid_pax_size.c
diff --cc 
contrib/libarchive/libarchive/test/test_read_format_tar_invalid_pax_size.tar.uu
index 000000000000,71309eab2cb3..71309eab2cb3
mode 000000,100644..100644
--- 
a/contrib/libarchive/libarchive/test/test_read_format_tar_invalid_pax_size.tar.uu
+++ 
b/contrib/libarchive/libarchive/test/test_read_format_tar_invalid_pax_size.tar.uu
diff --cc contrib/libarchive/tar/util.c
index 9d59e1a65b26,000000000000..231c53e2cf6b
mode 100644,000000..100644
--- a/contrib/libarchive/tar/util.c
+++ b/contrib/libarchive/tar/util.c
@@@ -1,770 -1,0 +1,771 @@@
 +/*-
 + * Copyright (c) 2003-2007 Tim Kientzle
 + * All rights reserved.
 + *
 + * Redistribution and use in source and binary forms, with or without
 + * modification, are permitted provided that the following conditions
 + * are met:
 + * 1. Redistributions of source code must retain the above copyright
 + *    notice, this list of conditions and the following disclaimer.
 + * 2. Redistributions in binary form must reproduce the above copyright
 + *    notice, this list of conditions and the following disclaimer in the
 + *    documentation and/or other materials provided with the distribution.
 + *
 + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
 + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
 + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 + */
 +
 +#include "bsdtar_platform.h"
 +__FBSDID("$FreeBSD$");
 +
 +#ifdef HAVE_SYS_STAT_H
 +#include <sys/stat.h>
 +#endif
 +#ifdef HAVE_SYS_TYPES_H
 +#include <sys/types.h>  /* Linux doesn't define mode_t, etc. in sys/stat.h. */
 +#endif
 +#include <ctype.h>
 +#ifdef HAVE_ERRNO_H
 +#include <errno.h>
 +#endif
 +#ifdef HAVE_IO_H
 +#include <io.h>
 +#endif
 +#ifdef HAVE_STDARG_H
 +#include <stdarg.h>
 +#endif
 +#ifdef HAVE_STDINT_H
 +#include <stdint.h>
 +#endif
 +#include <stdio.h>
 +#ifdef HAVE_STDLIB_H
 +#include <stdlib.h>
 +#endif
 +#ifdef HAVE_STRING_H
 +#include <string.h>
 +#endif
 +#ifdef HAVE_WCTYPE_H
 +#include <wctype.h>
 +#else
 +/* If we don't have wctype, we need to hack up some version of iswprint(). */
 +#define       iswprint isprint
 +#endif
 +
 +#include "bsdtar.h"
 +#include "err.h"
 +#include "passphrase.h"
 +
- static size_t bsdtar_expand_char(char *, size_t, char);
++static size_t bsdtar_expand_char(char *, size_t, size_t, char);
 +static const char *strip_components(const char *path, int elements);
 +
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +#define       read _read
 +#endif
 +
 +/* TODO:  Hack up a version of mbtowc for platforms with no wide
 + * character support at all.  I think the following might suffice,
 + * but it needs careful testing.
 + * #if !HAVE_MBTOWC
 + * #define    mbtowc(wcp, p, n) ((*wcp = *p), 1)
 + * #endif
 + */
 +
 +/*
 + * Print a string, taking care with any non-printable characters.
 + *
 + * Note that we use a stack-allocated buffer to receive the formatted
 + * string if we can.  This is partly performance (avoiding a call to
 + * malloc()), partly out of expedience (we have to call vsnprintf()
 + * before malloc() anyway to find out how big a buffer we need; we may
 + * as well point that first call at a small local buffer in case it
 + * works), but mostly for safety (so we can use this to print messages
 + * about out-of-memory conditions).
 + */
 +
 +void
 +safe_fprintf(FILE *f, const char *fmt, ...)
 +{
 +      char fmtbuff_stack[256]; /* Place to format the printf() string. */
 +      char outbuff[256]; /* Buffer for outgoing characters. */
 +      char *fmtbuff_heap; /* If fmtbuff_stack is too small, we use malloc */
 +      char *fmtbuff;  /* Pointer to fmtbuff_stack or fmtbuff_heap. */
 +      int fmtbuff_length;
 +      int length, n;
 +      va_list ap;
 +      const char *p;
 +      unsigned i;
 +      wchar_t wc;
 +      char try_wc;
 +
 +      /* Use a stack-allocated buffer if we can, for speed and safety. */
 +      fmtbuff_heap = NULL;
 +      fmtbuff_length = sizeof(fmtbuff_stack);
 +      fmtbuff = fmtbuff_stack;
 +
 +      /* Try formatting into the stack buffer. */
 +      va_start(ap, fmt);
 +      length = vsnprintf(fmtbuff, fmtbuff_length, fmt, ap);
 +      va_end(ap);
 +
 +      /* If the result was too large, allocate a buffer on the heap. */
 +      while (length < 0 || length >= fmtbuff_length) {
 +              if (length >= fmtbuff_length)
 +                      fmtbuff_length = length+1;
 +              else if (fmtbuff_length < 8192)
 +                      fmtbuff_length *= 2;
 +              else if (fmtbuff_length < 1000000)
 +                      fmtbuff_length += fmtbuff_length / 4;
 +              else {
 +                      length = fmtbuff_length;
 +                      fmtbuff_heap[length-1] = '\0';
 +                      break;
 +              }
 +              free(fmtbuff_heap);
 +              fmtbuff_heap = malloc(fmtbuff_length);
 +
 +              /* Reformat the result into the heap buffer if we can. */
 +              if (fmtbuff_heap != NULL) {
 +                      fmtbuff = fmtbuff_heap;
 +                      va_start(ap, fmt);
 +                      length = vsnprintf(fmtbuff, fmtbuff_length, fmt, ap);
 +                      va_end(ap);
 +              } else {
 +                      /* Leave fmtbuff pointing to the truncated
 +                       * string in fmtbuff_stack. */
 +                      fmtbuff = fmtbuff_stack;
 +                      length = sizeof(fmtbuff_stack) - 1;
 +                      break;
 +              }
 +      }
 +
 +      /* Note: mbrtowc() has a cleaner API, but mbtowc() seems a bit
 +       * more portable, so we use that here instead. */
 +      if (mbtowc(NULL, NULL, 1) == -1) { /* Reset the shift state. */
 +              /* mbtowc() should never fail in practice, but
 +               * handle the theoretical error anyway. */
 +              free(fmtbuff_heap);
 +              return;
 +      }
 +
 +      /* Write data, expanding unprintable characters. */
 +      p = fmtbuff;
 +      i = 0;
 +      try_wc = 1;
 +      while (*p != '\0') {
 +
 +              /* Convert to wide char, test if the wide
 +               * char is printable in the current locale. */
 +              if (try_wc && (n = mbtowc(&wc, p, length)) != -1) {
 +                      length -= n;
 +                      if (iswprint(wc) && wc != L'\\') {
 +                              /* Printable, copy the bytes through. */
 +                              while (n-- > 0)
 +                                      outbuff[i++] = *p++;
 +                      } else {
 +                              /* Not printable, format the bytes. */
 +                              while (n-- > 0)
 +                                      i += (unsigned)bsdtar_expand_char(
-                                           outbuff, i, *p++);
++                                          outbuff, sizeof(outbuff), i, *p++);
 +                      }
 +              } else {
 +                      /* After any conversion failure, don't bother
 +                       * trying to convert the rest. */
-                       i += (unsigned)bsdtar_expand_char(outbuff, i, *p++);
++                      i += (unsigned)bsdtar_expand_char(outbuff, 
sizeof(outbuff), i, *p++);
 +                      try_wc = 0;
 +              }
 +
 +              /* If our output buffer is full, dump it and keep going. */
 +              if (i > (sizeof(outbuff) - 128)) {
 +                      outbuff[i] = '\0';
 +                      fprintf(f, "%s", outbuff);
 +                      i = 0;
 +              }
 +      }
 +      outbuff[i] = '\0';
 +      fprintf(f, "%s", outbuff);
 +
 +      /* If we allocated a heap-based formatting buffer, free it now. */
 +      free(fmtbuff_heap);
 +}
 +
 +/*
 + * Render an arbitrary sequence of bytes into printable ASCII characters.
 + */
 +static size_t
- bsdtar_expand_char(char *buff, size_t offset, char c)
++bsdtar_expand_char(char *buff, size_t buffsize, size_t offset, char c)
 +{
 +      size_t i = offset;
 +
 +      if (isprint((unsigned char)c) && c != '\\')
 +              buff[i++] = c;
 +      else {
 +              buff[i++] = '\\';
 +              switch (c) {
 +              case '\a': buff[i++] = 'a'; break;
 +              case '\b': buff[i++] = 'b'; break;
 +              case '\f': buff[i++] = 'f'; break;
 +              case '\n': buff[i++] = 'n'; break;
 +#if '\r' != '\n'
 +              /* On some platforms, \n and \r are the same. */
 +              case '\r': buff[i++] = 'r'; break;
 +#endif
 +              case '\t': buff[i++] = 't'; break;
 +              case '\v': buff[i++] = 'v'; break;
 +              case '\\': buff[i++] = '\\'; break;
 +              default:
-                       sprintf(buff + i, "%03o", 0xFF & (int)c);
++                      snprintf(buff + i, buffsize - i, "%03o", 0xFF & (int)c);
 +                      i += 3;
 +              }
 +      }
 +
 +      return (i - offset);
 +}
 +
 +int
 +yes(const char *fmt, ...)
 +{
 +      char buff[32];
 +      char *p;
 +      ssize_t l;
 +
 +      va_list ap;
 +      va_start(ap, fmt);
 +      vfprintf(stderr, fmt, ap);
 +      va_end(ap);
 +      fprintf(stderr, " (y/N)? ");
 +      fflush(stderr);
 +
 +      l = read(2, buff, sizeof(buff) - 1);
 +      if (l < 0) {
 +        fprintf(stderr, "Keyboard read failed\n");
 +        exit(1);
 +      }
 +      if (l == 0)
 +              return (0);
 +      buff[l] = 0;
 +
 +      for (p = buff; *p != '\0'; p++) {
 +              if (isspace((unsigned char)*p))
 +                      continue;
 +              switch(*p) {
 +              case 'y': case 'Y':
 +                      return (1);
 +              case 'n': case 'N':
 +                      return (0);
 +              default:
 +                      return (0);
 +              }
 +      }
 +
 +      return (0);
 +}
 +
 +/*-
 + * The logic here for -C <dir> attempts to avoid
 + * chdir() as long as possible.  For example:
 + * "-C /foo -C /bar file"          needs chdir("/bar") but not chdir("/foo")
 + * "-C /foo -C bar file"           needs chdir("/foo/bar")
 + * "-C /foo -C bar /file1"         does not need chdir()
 + * "-C /foo -C bar /file1 file2"   needs chdir("/foo/bar") before file2
 + *
 + * The only correct way to handle this is to record a "pending" chdir
 + * request and combine multiple requests intelligently until we
 + * need to process a non-absolute file.  set_chdir() adds the new dir
 + * to the pending list; do_chdir() actually executes any pending chdir.
 + *
 + * This way, programs that build tar command lines don't have to worry
 + * about -C with non-existent directories; such requests will only
 + * fail if the directory must be accessed.
 + *
 + */
 +void
 +set_chdir(struct bsdtar *bsdtar, const char *newdir)
 +{
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +      if (newdir[0] == '/' || newdir[0] == '\\' ||
 +          /* Detect this type, for example, "C:\" or "C:/" */
 +          (((newdir[0] >= 'a' && newdir[0] <= 'z') ||
 +            (newdir[0] >= 'A' && newdir[0] <= 'Z')) &&
 +          newdir[1] == ':' && (newdir[2] == '/' || newdir[2] == '\\'))) {
 +#else
 +      if (newdir[0] == '/') {
 +#endif
 +              /* The -C /foo -C /bar case; dump first one. */
 +              free(bsdtar->pending_chdir);
 +              bsdtar->pending_chdir = NULL;
 +      }
 +      if (bsdtar->pending_chdir == NULL)
 +              /* Easy case: no previously-saved dir. */
 +              bsdtar->pending_chdir = strdup(newdir);
 +      else {
 +              /* The -C /foo -C bar case; concatenate */
 +              char *old_pending = bsdtar->pending_chdir;
 +              size_t old_len = strlen(old_pending);
-               bsdtar->pending_chdir = malloc(old_len + strlen(newdir) + 2);
++        size_t new_len = old_len + strlen(newdir) + 2;
++              bsdtar->pending_chdir = malloc(new_len);
 +              if (old_pending[old_len - 1] == '/')
 +                      old_pending[old_len - 1] = '\0';
 +              if (bsdtar->pending_chdir != NULL)
-                       sprintf(bsdtar->pending_chdir, "%s/%s",
++                      snprintf(bsdtar->pending_chdir, new_len, "%s/%s",
 +                          old_pending, newdir);
 +              free(old_pending);
 +      }
 +      if (bsdtar->pending_chdir == NULL)
 +              lafe_errc(1, errno, "No memory");
 +}
 +
 +void
 +do_chdir(struct bsdtar *bsdtar)
 +{
 +      if (bsdtar->pending_chdir == NULL)
 +              return;
 +
 +      if (chdir(bsdtar->pending_chdir) != 0) {
 +              lafe_errc(1, 0, "could not chdir to '%s'\n",
 +                  bsdtar->pending_chdir);
 +      }
 +      free(bsdtar->pending_chdir);
 +      bsdtar->pending_chdir = NULL;
 +}
 +
 +static const char *
 +strip_components(const char *p, int elements)
 +{
 +      /* Skip as many elements as necessary. */
 +      while (elements > 0) {
 +              switch (*p++) {
 +              case '/':
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +              case '\\': /* Support \ path sep on Windows ONLY. */
 +#endif
 +                      elements--;
 +                      break;
 +              case '\0':
 +                      /* Path is too short, skip it. */
 +                      return (NULL);
 +              }
 +      }
 +
 +      /* Skip any / characters.  This handles short paths that have
 +       * additional / termination.  This also handles the case where
 +       * the logic above stops in the middle of a duplicate //
 +       * sequence (which would otherwise get converted to an
 +       * absolute path). */
 +      for (;;) {
 +              switch (*p) {
 +              case '/':
 +#if defined(_WIN32) && !defined(__CYGWIN__)
 +              case '\\': /* Support \ path sep on Windows ONLY. */
 +#endif
 +                      ++p;
 +                      break;
 +              case '\0':
 +                      return (NULL);
 +              default:
 +                      return (p);
 +              }
 +      }
 +}
 +
 +static void
 +warn_strip_leading_char(struct bsdtar *bsdtar, const char *c)
 +{
 +      if (!bsdtar->warned_lead_slash) {
 +              lafe_warnc(0,
 +                         "Removing leading '%c' from member names",
 +                         c[0]);
 +              bsdtar->warned_lead_slash = 1;
 +      }
 +}
 +
 +static void
 +warn_strip_drive_letter(struct bsdtar *bsdtar)
 +{
 +      if (!bsdtar->warned_lead_slash) {
 +              lafe_warnc(0,
 +                         "Removing leading drive letter from "
 +                         "member names");
 +              bsdtar->warned_lead_slash = 1;
 +      }
 +}
 +
 +/*
 + * Convert absolute path to non-absolute path by skipping leading
 + * absolute path prefixes.
 + */
 +static const char*
 +strip_absolute_path(struct bsdtar *bsdtar, const char *p)
 +{
 +      const char *rp;
 +
 +      /* Remove leading "//./" or "//?/" or "//?/UNC/"
 +       * (absolute path prefixes used by Windows API) */
 +      if ((p[0] == '/' || p[0] == '\\') &&
 +          (p[1] == '/' || p[1] == '\\') &&
 +          (p[2] == '.' || p[2] == '?') &&
 +          (p[3] == '/' || p[3] == '\\'))
 +      {
 +              if (p[2] == '?' &&
 +                  (p[4] == 'U' || p[4] == 'u') &&
 +                  (p[5] == 'N' || p[5] == 'n') &&
 +                  (p[6] == 'C' || p[6] == 'c') &&
 +                  (p[7] == '/' || p[7] == '\\'))
 +                      p += 8;
 +              else
 +                      p += 4;
 +              warn_strip_drive_letter(bsdtar);
 +      }
 +
 +      /* Remove multiple leading slashes and Windows drive letters. */
 +      do {
 +              rp = p;
 +              if (((p[0] >= 'a' && p[0] <= 'z') ||
 +                   (p[0] >= 'A' && p[0] <= 'Z')) &&
 +                  p[1] == ':') {
 +                      p += 2;
 +                      warn_strip_drive_letter(bsdtar);
 +              }
 +
 +              /* Remove leading "/../", "/./", "//", etc. */
 +              while (p[0] == '/' || p[0] == '\\') {
 +                      if (p[1] == '.' &&
 +                          p[2] == '.' &&
 +                          (p[3] == '/' || p[3] == '\\')) {
 +                              p += 3; /* Remove "/..", leave "/" for next 
pass. */
 +                      } else if (p[1] == '.' &&
 +                                 (p[2] == '/' || p[2] == '\\')) {
 +                              p += 2; /* Remove "/.", leave "/" for next 
pass. */
 +                      } else
 +                              p += 1; /* Remove "/". */
 +                      warn_strip_leading_char(bsdtar, rp);
 +              }
 +      } while (rp != p);
 +
 +      return (p);
 +}
 +
 +/*
 + * Handle --strip-components and any future path-rewriting options.
 + * Returns non-zero if the pathname should not be extracted.
 + *
 + * Note: The rewrites are applied uniformly to pathnames and hardlink
 + * names but not to symlink bodies.  This is deliberate: Symlink
 + * bodies are not necessarily filenames.  Even when they are, they
 + * need to be interpreted relative to the directory containing them,
 + * so simple rewrites like this are rarely appropriate.
 + *
 + * TODO: Support pax-style regex path rewrites.
 + */
 +int
 +edit_pathname(struct bsdtar *bsdtar, struct archive_entry *entry)
 +{
 +      const char *name = archive_entry_pathname(entry);
 +      const char *original_name = name;
 +      const char *hardlinkname = archive_entry_hardlink(entry);
 +      const char *original_hardlinkname = hardlinkname;
 +#if defined(HAVE_REGEX_H) || defined(HAVE_PCREPOSIX_H)
 +      char *subst_name;
 +      int r;
 +
 +      /* Apply user-specified substitution to pathname. */
 +      r = apply_substitution(bsdtar, name, &subst_name, 0, 0);
 +      if (r == -1) {
 +              lafe_warnc(0, "Invalid substitution, skipping entry");
 +              return 1;
 +      }
 +      if (r == 1) {
 +              archive_entry_copy_pathname(entry, subst_name);
 +              if (*subst_name == '\0') {
 +                      free(subst_name);
 +                      return -1;
 +              } else
 +                      free(subst_name);
 +              name = archive_entry_pathname(entry);
 +              original_name = name;
 +      }
 +
 +      /* Apply user-specified substitution to hardlink target. */
 +      if (hardlinkname != NULL) {
 +              r = apply_substitution(bsdtar, hardlinkname, &subst_name, 0, 1);
 +              if (r == -1) {
 +                      lafe_warnc(0, "Invalid substitution, skipping entry");
 +                      return 1;
 +              }
 +              if (r == 1) {
 +                      archive_entry_copy_hardlink(entry, subst_name);
 +                      free(subst_name);
 +              }
 +              hardlinkname = archive_entry_hardlink(entry);
 +              original_hardlinkname = hardlinkname;
 +      }
 +
 +      /* Apply user-specified substitution to symlink body. */
 +      if (archive_entry_symlink(entry) != NULL) {
 +              r = apply_substitution(bsdtar, archive_entry_symlink(entry), 
&subst_name, 1, 0);
 +              if (r == -1) {
 +                      lafe_warnc(0, "Invalid substitution, skipping entry");
 +                      return 1;
 +              }
 +              if (r == 1) {
 +                      archive_entry_copy_symlink(entry, subst_name);
 +                      free(subst_name);
 +              }
 +      }
 +#endif
 +
 +      /* Strip leading dir names as per --strip-components option. */
 +      if (bsdtar->strip_components > 0) {
 +              name = strip_components(name, bsdtar->strip_components);
 +              if (name == NULL)
 +                      return (1);
 +
 +              if (hardlinkname != NULL) {
 +                      hardlinkname = strip_components(hardlinkname,
 +                          bsdtar->strip_components);
 +                      if (hardlinkname == NULL)
 +                              return (1);
 +              }
 +      }
 +
 +      if ((bsdtar->flags & OPTFLAG_ABSOLUTE_PATHS) == 0) {
 +              /* By default, don't write or restore absolute pathnames. */
 +              name = strip_absolute_path(bsdtar, name);
 +              if (*name == '\0')
 +                      name = ".";
 +
 +              if (hardlinkname != NULL) {
 +                      hardlinkname = strip_absolute_path(bsdtar, 
hardlinkname);
 +                      if (*hardlinkname == '\0')
 +                              return (1);
 +              }
 +      } else {
 +              /* Strip redundant leading '/' characters. */
 +              while (name[0] == '/' && name[1] == '/')
 +                      name++;
 +      }
 +
 +      /* Replace name in archive_entry. */
 +      if (name != original_name) {
 +              archive_entry_copy_pathname(entry, name);
 +      }
 +      if (hardlinkname != original_hardlinkname) {
 +              archive_entry_copy_hardlink(entry, hardlinkname);
 +      }
 +      return (0);
 +}
 +
 +/*
 + * It would be nice to just use printf() for formatting large numbers,
 + * but the compatibility problems are quite a headache.  Hence the
 + * following simple utility function.
 + */
 +const char *
 +tar_i64toa(int64_t n0)
 +{
 +      static char buff[24];
 +      uint64_t n = n0 < 0 ? -n0 : n0;
 +      char *p = buff + sizeof(buff);
 +
 +      *--p = '\0';
 +      do {
 +              *--p = '0' + (int)(n % 10);
 +      } while (n /= 10);
 +      if (n0 < 0)
 +              *--p = '-';
 +      return p;
 +}
 +
 +/*
 + * Like strcmp(), but try to be a little more aware of the fact that
 + * we're comparing two paths.  Right now, it just handles leading
 + * "./" and trailing '/' specially, so that "a/b/" == "./a/b"
 + *
 + * TODO: Make this better, so that "./a//b/./c/" == "a/b/c"
 + * TODO: After this works, push it down into libarchive.
 + * TODO: Publish the path normalization routines in libarchive so
 + * that bsdtar can normalize paths and use fast strcmp() instead
 + * of this.
 + *
 + * Note: This is currently only used within write.c, so should
 + * not handle \ path separators.
 + */
 +
 +int
 +pathcmp(const char *a, const char *b)
 +{
 +      /* Skip leading './' */
 +      if (a[0] == '.' && a[1] == '/' && a[2] != '\0')
 +              a += 2;
 +      if (b[0] == '.' && b[1] == '/' && b[2] != '\0')
 +              b += 2;
 +      /* Find the first difference, or return (0) if none. */
 +      while (*a == *b) {
 +              if (*a == '\0')
 +                      return (0);
 +              a++;
 +              b++;
 +      }
 +      /*
 +       * If one ends in '/' and the other one doesn't,
 +       * they're the same.
 +       */
 +      if (a[0] == '/' && a[1] == '\0' && b[0] == '\0')
 +              return (0);
 +      if (a[0] == '\0' && b[0] == '/' && b[1] == '\0')
 +              return (0);
 +      /* They're really different, return the correct sign. */
 +      return (*(const unsigned char *)a - *(const unsigned char *)b);
 +}
 +
 +#define PPBUFF_SIZE 1024
 +const char *
 +passphrase_callback(struct archive *a, void *_client_data)
 +{
 +      struct bsdtar *bsdtar = (struct bsdtar *)_client_data;
 +      (void)a; /* UNUSED */
 +
 +      if (bsdtar->ppbuff == NULL) {
 +              bsdtar->ppbuff = malloc(PPBUFF_SIZE);
 +              if (bsdtar->ppbuff == NULL)
*** 813 LINES SKIPPED ***

Reply via email to