git: bd5e624a8614 - main - libarchive: merge from vendor branch

From: Martin Matuska <mm_at_FreeBSD.org>
Date: Tue, 13 Dec 2022 19:45:04 UTC
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 <mm@FreeBSD.org>
AuthorDate: 2022-12-13 19:21:13 +0000
Commit:     Martin Matuska <mm@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 ***