From 8bf2d2ac282a83027e42d915a6c5d6a3b41cd341 Mon Sep 17 00:00:00 2001 From: Peter Avalos Date: Mon, 16 Jun 2008 08:12:40 +0000 Subject: [PATCH] Import libarchive-2.5.4b. Requested-by: hasso --- contrib/libarchive-2/COPYING | 40 +- contrib/libarchive-2/NEWS | 74 +- contrib/libarchive-2/README | 1 + contrib/libarchive-2/libarchive/archive.h | 592 ++++++++++++ .../libarchive-2/libarchive/archive_endian.h | 14 + .../libarchive-2/libarchive/archive_entry.3 | 71 +- .../libarchive-2/libarchive/archive_entry.c | 417 ++++++--- .../libarchive-2/libarchive/archive_entry.h | 285 +++--- .../libarchive/archive_entry_link_resolver.c | 168 +++- .../libarchive/archive_entry_private.h | 30 +- .../libarchive/archive_entry_strmode.c | 5 +- .../libarchive/archive_platform.h | 3 + .../libarchive-2/libarchive/archive_read.3 | 107 ++- .../libarchive-2/libarchive/archive_read.c | 17 +- .../libarchive/archive_read_data_into_fd.c | 12 +- .../libarchive/archive_read_extract.c | 28 +- .../libarchive/archive_read_private.h | 50 +- .../archive_read_support_compression_bzip2.c | 32 +- ...archive_read_support_compression_program.c | 20 + .../archive_read_support_format_ar.c | 85 +- .../archive_read_support_format_iso9660.c | 59 +- .../archive_read_support_format_mtree.c | 849 ++++++++++++++---- .../archive_read_support_format_tar.c | 90 +- .../archive_read_support_format_zip.c | 21 +- .../libarchive-2/libarchive/archive_string.c | 263 +++++- .../libarchive-2/libarchive/archive_string.h | 31 +- .../libarchive/archive_string_sprintf.c | 12 +- .../libarchive-2/libarchive/archive_util.3 | 9 +- .../libarchive-2/libarchive/archive_util.c | 26 +- .../libarchive-2/libarchive/archive_write.3 | 50 +- .../libarchive-2/libarchive/archive_write.c | 9 +- .../libarchive/archive_write_disk.3 | 25 +- .../libarchive/archive_write_disk.c | 167 +++- .../libarchive/archive_write_private.h | 9 +- .../archive_write_set_compression_compress.c | 494 ++++++++++ .../archive_write_set_compression_program.c | 19 + .../libarchive/archive_write_set_format_ar.c | 25 +- .../archive_write_set_format_cpio.c | 6 +- .../archive_write_set_format_cpio_newc.c | 6 +- .../libarchive/archive_write_set_format_pax.c | 123 ++- .../archive_write_set_format_shar.c | 10 +- .../archive_write_set_format_ustar.c | 74 +- contrib/libarchive-2/libarchive/cpio.5 | 12 +- contrib/libarchive-2/libarchive/filter_fork.c | 5 + .../libarchive/libarchive-formats.5 | 8 + contrib/libarchive-2/libarchive/mtree.5 | 59 +- contrib/libarchive-2/libarchive/tar.5 | 12 +- contrib/libarchive-2/tar/bsdtar.1 | 88 +- contrib/libarchive-2/tar/bsdtar.c | 60 +- contrib/libarchive-2/tar/bsdtar.h | 19 +- contrib/libarchive-2/tar/matching.c | 27 +- contrib/libarchive-2/tar/read.c | 46 +- contrib/libarchive-2/tar/siginfo.c | 147 +++ contrib/libarchive-2/tar/subst.c | 275 ++++++ contrib/libarchive-2/tar/util.c | 60 +- contrib/libarchive-2/tar/write.c | 343 +++---- contrib/libarchive-2/version | 2 +- 57 files changed, 4400 insertions(+), 1191 deletions(-) create mode 100644 contrib/libarchive-2/libarchive/archive.h create mode 100644 contrib/libarchive-2/libarchive/archive_write_set_compression_compress.c create mode 100644 contrib/libarchive-2/tar/siginfo.c create mode 100644 contrib/libarchive-2/tar/subst.c diff --git a/contrib/libarchive-2/COPYING b/contrib/libarchive-2/COPYING index 6128d175fd..ec7d6c4360 100644 --- a/contrib/libarchive-2/COPYING +++ b/contrib/libarchive-2/COPYING @@ -1,7 +1,41 @@ -All of the C source code and documentation in this package is subject -to the following: +The libarchive distribution as a whole is Copyright by Tim Kientzle +and is subject to the copyright notice reproduced at the bottom of +this file. -Copyright (c) 2003-2006 Tim Kientzle +Each individual file in this distribution should have a clear +copyright/licensing statement at the beginning of the file. If any do +not, please let me know and I will rectify it. The following is +intended to summarize the copyright status of the individual files; +the actual statements in the files are controlling. + +* Except as listed below, all C sources (including .c and .h files) + and documentation files are subject to the copyright notice reproduced + at the bottom of this file. + +* The following source files are also subject in whole or in part to + a 3-clause UC Regents copyright; please read the individual source + files for details: + libarchive/archive_entry.c + libarchive/archive_read_support_compression_compress.c + libarchive/archive_write_set_compression_compress.c + libarchive/mtree.5 + tar/matching.c + +* The following source files are in the public domain: + tar/getdate.y + +* The build files---including Makefiles, configure scripts, + and auxiliary scripts used as part of the compile process---have + widely varying licensing terms. Please check individual files before + distributing them to see if those restrictions apply to you. + +I intend for all new source code to use the license below and hope over +time to replace code with other licenses with new implementations that +do use the license below. The varying licensing of the build scripts +seems to be an unavoidable mess. + + +Copyright (c) 2003-2008 All rights reserved. Redistribution and use in source and binary forms, with or without diff --git a/contrib/libarchive-2/NEWS b/contrib/libarchive-2/NEWS index 991509e47d..b7e578e290 100644 --- a/contrib/libarchive-2/NEWS +++ b/contrib/libarchive-2/NEWS @@ -1,9 +1,71 @@ -Mar 14, 2008: libarchive 2.4.14 released. This is identical to 2.4.13 - except it contains a one-line fix to the uname/gname problem - introduced by the Feb 25 UTF-8 fix. This bug makes libarchive - refuse to add a file to a pax archive if it has a valid gname - but not a valid uname. In some cases, it can also cause the - uname to be stored for the gname. + +May 25, 2008: libarchive 2.5.4b released +May 21, 2008: Joerg Sonnenberger: fix bsdtar hardlink handling for newc format + +May 21, 2008: More progress on Windows building. Thanks to "Scott" + for the Windows makefiles, thanks to Kees Zeelenberg for + code contributions. + +May 21, 2008: Fix a number of non-exploitable integer and buffer overflows, + thanks to David Remahl at Apple for pointing these out. + +May 21, 2008: Colin Percival: SIGINFO or SIGUSR1 to bsdtar prints progress info + +May 16, 2008: bsdtar's test harness no longer depends on file ordering. + This was causing spurious test failures on a lot of systems. + Thanks to Bernhard R. Link for the diagnosis. + +May 14, 2008: Joerg Sonnenberger: -s substitution support for bsdtar + +May 13, 2008: Joerg Sonnenberger: Many mtree improvements + +May 11, 2008: Joerg Sonnenberger: fix hardlink extraction when + hardlinks have different permissions from original file + +April 30, 2008: Primary libarchive work has been moved into the FreeBSD + project's Perforce repository: http://perforce.freebsd.org/ + The libarchive project can be browsed at + //depot/user/kientzle/libarchive-portable + Direct link: http://preview.tinyurl.com/46mdgr + +May 04, 2008: libarchive 2.5.3b released + * libarchive: Several fixes to link resolver to address bsdcpio crashes + * bsdcpio: -p hardlink handling fixes + * tar/pax: Ensure ustar dirnames end in '/'; be more careful about + measuring filenames when deciding what pathname fields to use + * libarchive: Mark which entry strings are set; be accurate about + distinguishing empty strings ("") from unset ones (NULL) + * tar: Don't crash reading entries with empty filenames + * libarchive_test, bsdtar_test, bsdcpio_test: Better detaults: + run all tests, delete temp dirs, summarize repeated failures + * -no-undefined to libtool for Cygwin + * libarchive_test: Skip large file tests on systems with 32-bit off_t + * iso9660: Don't bother trying to find the body of an empty file; + this works around strange behavior from some ISO9660 writers + * tar: allow -r -T to be used together + * tar: allow --format with -r or -u + * libarchive: Don't build archive.h + +May 04, 2008: Simplified building: archive.h is no longer constructed + This may require additional #if conditionals on some platforms. + +Mar 30, 2008: libarchive 2.5.1b released + +Mar 15, 2008: libarchive 2.5.0b released +Mar 15, 2008: bsdcpio now seems to correctly write hardlinks into newc, + ustar, and old cpio archives. Just a little more testing before + bsdcpio 1.0 becomes a reality. +Mar 15, 2008: I think the new linkify() interface is finally handling + all known hardlink strategies. +Mar 15, 2008: Mtree read fixes from Joerg Sonnenberger. +Mar 15, 2008: Many new bsdtar and bsdcpio options from Joerg Sonnenberger. +Mar 15, 2008: test harnesses no longer require uudecode; they + now have built-in decoding logic that decodes the reference + files as they are needed. + +Mar 14, 2008: libarchive 2.4.14 released; identical to 2.4.13 except for + a point fix for gname/uname mixup in pax format that was introduced + with the UTF-8 fixes. Feb 26, 2008: libarchive 2.4.13 released Feb 25, 2008: Handle path, linkname, gname, or uname that can't be converted diff --git a/contrib/libarchive-2/README b/contrib/libarchive-2/README index 3652503ddf..50a9d628f3 100644 --- a/contrib/libarchive-2/README +++ b/contrib/libarchive-2/README @@ -69,6 +69,7 @@ Currently, the library automatically detects and reads the following: The library can write: * gzip compression * bzip2 compression + * compress/LZW compression * POSIX ustar * POSIX pax interchange format * "restricted" pax format, which will create ustar archives except for diff --git a/contrib/libarchive-2/libarchive/archive.h b/contrib/libarchive-2/libarchive/archive.h new file mode 100644 index 0000000000..6bfe81eb24 --- /dev/null +++ b/contrib/libarchive-2/libarchive/archive.h @@ -0,0 +1,592 @@ +/*- + * 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. + * + * $FreeBSD: src/lib/libarchive/archive.h.in,v 1.49 2008/03/14 22:19:50 kientzle Exp $ + */ + +#ifndef ARCHIVE_H_INCLUDED +#define ARCHIVE_H_INCLUDED + +/* + * Note: archive.h is for use outside of libarchive; the configuration + * headers (config.h, archive_platform.h, etc.) are purely internal. + * Do NOT use HAVE_XXX configuration macros to control the behavior of + * this header! If you must conditionalize, use predefined compiler and/or + * platform macros. + */ + +#include /* Linux requires this for off_t */ +#if !defined(__WATCOMC__) && !defined(_MSC_VER) +/* Header unavailable on Watcom C or MS Visual C++. */ +#include /* int64_t, etc. */ +#endif +#include /* For FILE * */ + +/* Get appropriate definitions of standard POSIX-style types. */ +/* These should match the types used in 'struct stat' */ +#ifdef _WIN32 +#define __LA_SSIZE_T long +#define __LA_UID_T unsigned int +#define __LA_GID_T unsigned int +#else +#include /* ssize_t, uid_t, and gid_t */ +#define __LA_SSIZE_T ssize_t +#define __LA_UID_T uid_t +#define __LA_GID_T gid_t +#endif + +/* + * On Windows, define LIBARCHIVE_STATIC if you're building or using a + * .lib. The default here assumes you're building a DLL. Only + * libarchive source should ever define __LIBARCHIVE_BUILD. + */ +#if ((defined __WIN32__) || (defined _WIN32)) && (!defined LIBARCHIVE_STATIC) +# ifdef __LIBARCHIVE_BUILD +# ifdef __GNUC__ +# define __LA_DECL __attribute__((dllexport)) extern +# else +# define __LA_DECL __declspec(dllexport) +# endif +# else +# ifdef __GNUC__ +# define __LA_DECL __attribute__((dllimport)) extern +# else +# define __LA_DECL __declspec(dllimport) +# endif +# endif +#else +/* Static libraries or non-Windows needs no special declaration. */ +# define __LA_DECL +#endif + + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * The version number is provided as both a macro and a function. + * The macro identifies the installed header; the function identifies + * the library version (which may not be the same if you're using a + * dynamically-linked version of the library). Of course, if the + * header and library are very different, you should expect some + * strangeness. Don't do that. + */ + +/* + * The version number is expressed as a single integer that makes it + * easy to compare versions at build time: for version a.b.c, the + * version number is printf("%d%03d%03d",a,b,c). For example, if you + * know your application requires version 2.12.108 or later, you can + * assert that ARCHIVE_VERSION >= 2012108. + * + * This single-number format was introduced with libarchive 1.9.0 in + * the libarchive 1.x family and libarchive 2.2.4 in the libarchive + * 2.x family. The following may be useful if you really want to do + * feature detection for earlier libarchive versions (which defined + * ARCHIVE_API_VERSION and ARCHIVE_API_FEATURE instead): + * + * #ifndef ARCHIVE_VERSION_NUMBER + * #define ARCHIVE_VERSION_NUMBER \ + * (ARCHIVE_API_VERSION * 1000000 + ARCHIVE_API_FEATURE * 1000) + * #endif + */ +#define ARCHIVE_VERSION_NUMBER 2005004 +__LA_DECL int archive_version_number(void); + +/* + * Textual name/version of the library, useful for version displays. + */ +#define ARCHIVE_VERSION_STRING "libarchive 2.5.4b" +__LA_DECL const char * archive_version_string(void); + +#if ARCHIVE_VERSION_NUMBER < 3000000 +/* + * Deprecated; these are older names that will be removed in favor of + * the simpler definitions above. + */ +#define ARCHIVE_VERSION_STAMP ARCHIVE_VERSION_NUMBER +__LA_DECL int archive_version_stamp(void); +#define ARCHIVE_LIBRARY_VERSION ARCHIVE_VERSION_STRING +__LA_DECL const char * archive_version(void); +#define ARCHIVE_API_VERSION (ARCHIVE_VERSION_NUMBER / 1000000) +__LA_DECL int archive_api_version(void); +#define ARCHIVE_API_FEATURE ((ARCHIVE_VERSION_NUMBER / 1000) % 1000) +__LA_DECL int archive_api_feature(void); +#endif + +#if ARCHIVE_VERSION_NUMBER < 3000000 +/* This should never have been here in the first place. */ +/* Legacy of old tar assumptions, will be removed in libarchive 3.0. */ +#define ARCHIVE_BYTES_PER_RECORD 512 +#define ARCHIVE_DEFAULT_BYTES_PER_BLOCK 10240 +#endif + +/* Declare our basic types. */ +struct archive; +struct archive_entry; + +/* + * Error codes: Use archive_errno() and archive_error_string() + * to retrieve details. Unless specified otherwise, all functions + * that return 'int' use these codes. + */ +#define ARCHIVE_EOF 1 /* Found end of archive. */ +#define ARCHIVE_OK 0 /* Operation was successful. */ +#define ARCHIVE_RETRY (-10) /* Retry might succeed. */ +#define ARCHIVE_WARN (-20) /* Partial success. */ +/* For example, if write_header "fails", then you can't push data. */ +#define ARCHIVE_FAILED (-25) /* Current operation cannot complete. */ +/* But if write_header is "fatal," then this archive is dead and useless. */ +#define ARCHIVE_FATAL (-30) /* No more operations are possible. */ + +/* + * As far as possible, archive_errno returns standard platform errno codes. + * Of course, the details vary by platform, so the actual definitions + * here are stored in "archive_platform.h". The symbols are listed here + * for reference; as a rule, clients should not need to know the exact + * platform-dependent error code. + */ +/* Unrecognized or invalid file format. */ +/* #define ARCHIVE_ERRNO_FILE_FORMAT */ +/* Illegal usage of the library. */ +/* #define ARCHIVE_ERRNO_PROGRAMMER_ERROR */ +/* Unknown or unclassified error. */ +/* #define ARCHIVE_ERRNO_MISC */ + +/* + * Callbacks are invoked to automatically read/skip/write/open/close the + * archive. You can provide your own for complex tasks (like breaking + * archives across multiple tapes) or use standard ones built into the + * library. + */ + +/* Returns pointer and size of next block of data from archive. */ +typedef __LA_SSIZE_T archive_read_callback(struct archive *, void *_client_data, + const void **_buffer); +/* Skips at most request bytes from archive and returns the skipped amount */ +#if ARCHIVE_VERSION_NUMBER < 2000000 +typedef __LA_SSIZE_T archive_skip_callback(struct archive *, void *_client_data, + size_t request); +#else +typedef off_t archive_skip_callback(struct archive *, void *_client_data, + off_t request); +#endif +/* Returns size actually written, zero on EOF, -1 on error. */ +typedef __LA_SSIZE_T archive_write_callback(struct archive *, void *_client_data, + const void *_buffer, size_t _length); +typedef int archive_open_callback(struct archive *, void *_client_data); +typedef int archive_close_callback(struct archive *, void *_client_data); + +/* + * Codes for archive_compression. + */ +#define ARCHIVE_COMPRESSION_NONE 0 +#define ARCHIVE_COMPRESSION_GZIP 1 +#define ARCHIVE_COMPRESSION_BZIP2 2 +#define ARCHIVE_COMPRESSION_COMPRESS 3 +#define ARCHIVE_COMPRESSION_PROGRAM 4 + +/* + * Codes returned by archive_format. + * + * Top 16 bits identifies the format family (e.g., "tar"); lower + * 16 bits indicate the variant. This is updated by read_next_header. + * Note that the lower 16 bits will often vary from entry to entry. + * In some cases, this variation occurs as libarchive learns more about + * the archive (for example, later entries might utilize extensions that + * weren't necessary earlier in the archive; in this case, libarchive + * will change the format code to indicate the extended format that + * was used). In other cases, it's because different tools have + * modified the archive and so different parts of the archive + * actually have slightly different formts. (Both tar and cpio store + * format codes in each entry, so it is quite possible for each + * entry to be in a different format.) + */ +#define ARCHIVE_FORMAT_BASE_MASK 0xff0000 +#define ARCHIVE_FORMAT_CPIO 0x10000 +#define ARCHIVE_FORMAT_CPIO_POSIX (ARCHIVE_FORMAT_CPIO | 1) +#define ARCHIVE_FORMAT_CPIO_BIN_LE (ARCHIVE_FORMAT_CPIO | 2) +#define ARCHIVE_FORMAT_CPIO_BIN_BE (ARCHIVE_FORMAT_CPIO | 3) +#define ARCHIVE_FORMAT_CPIO_SVR4_NOCRC (ARCHIVE_FORMAT_CPIO | 4) +#define ARCHIVE_FORMAT_CPIO_SVR4_CRC (ARCHIVE_FORMAT_CPIO | 5) +#define ARCHIVE_FORMAT_SHAR 0x20000 +#define ARCHIVE_FORMAT_SHAR_BASE (ARCHIVE_FORMAT_SHAR | 1) +#define ARCHIVE_FORMAT_SHAR_DUMP (ARCHIVE_FORMAT_SHAR | 2) +#define ARCHIVE_FORMAT_TAR 0x30000 +#define ARCHIVE_FORMAT_TAR_USTAR (ARCHIVE_FORMAT_TAR | 1) +#define ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE (ARCHIVE_FORMAT_TAR | 2) +#define ARCHIVE_FORMAT_TAR_PAX_RESTRICTED (ARCHIVE_FORMAT_TAR | 3) +#define ARCHIVE_FORMAT_TAR_GNUTAR (ARCHIVE_FORMAT_TAR | 4) +#define ARCHIVE_FORMAT_ISO9660 0x40000 +#define ARCHIVE_FORMAT_ISO9660_ROCKRIDGE (ARCHIVE_FORMAT_ISO9660 | 1) +#define ARCHIVE_FORMAT_ZIP 0x50000 +#define ARCHIVE_FORMAT_EMPTY 0x60000 +#define ARCHIVE_FORMAT_AR 0x70000 +#define ARCHIVE_FORMAT_AR_GNU (ARCHIVE_FORMAT_AR | 1) +#define ARCHIVE_FORMAT_AR_BSD (ARCHIVE_FORMAT_AR | 2) +#define ARCHIVE_FORMAT_MTREE 0x80000 +#define ARCHIVE_FORMAT_MTREE_V1 (ARCHIVE_FORMAT_MTREE | 1) +#define ARCHIVE_FORMAT_MTREE_V2 (ARCHIVE_FORMAT_MTREE | 2) + +/*- + * Basic outline for reading an archive: + * 1) Ask archive_read_new for an archive reader object. + * 2) Update any global properties as appropriate. + * In particular, you'll certainly want to call appropriate + * archive_read_support_XXX functions. + * 3) Call archive_read_open_XXX to open the archive + * 4) Repeatedly call archive_read_next_header to get information about + * successive archive entries. Call archive_read_data to extract + * data for entries of interest. + * 5) Call archive_read_finish to end processing. + */ +__LA_DECL struct archive *archive_read_new(void); + +/* + * The archive_read_support_XXX calls enable auto-detect for this + * archive handle. They also link in the necessary support code. + * For example, if you don't want bzlib linked in, don't invoke + * support_compression_bzip2(). The "all" functions provide the + * obvious shorthand. + */ +__LA_DECL int archive_read_support_compression_all(struct archive *); +__LA_DECL int archive_read_support_compression_bzip2(struct archive *); +__LA_DECL int archive_read_support_compression_compress(struct archive *); +__LA_DECL int archive_read_support_compression_gzip(struct archive *); +__LA_DECL int archive_read_support_compression_none(struct archive *); +__LA_DECL int archive_read_support_compression_program(struct archive *, + const char *command); + +__LA_DECL int archive_read_support_format_all(struct archive *); +__LA_DECL int archive_read_support_format_ar(struct archive *); +__LA_DECL int archive_read_support_format_cpio(struct archive *); +__LA_DECL int archive_read_support_format_empty(struct archive *); +__LA_DECL int archive_read_support_format_gnutar(struct archive *); +__LA_DECL int archive_read_support_format_iso9660(struct archive *); +__LA_DECL int archive_read_support_format_mtree(struct archive *); +__LA_DECL int archive_read_support_format_tar(struct archive *); +__LA_DECL int archive_read_support_format_zip(struct archive *); + + +/* Open the archive using callbacks for archive I/O. */ +__LA_DECL int archive_read_open(struct archive *, void *_client_data, + archive_open_callback *, archive_read_callback *, + archive_close_callback *); +__LA_DECL int archive_read_open2(struct archive *, void *_client_data, + archive_open_callback *, archive_read_callback *, + archive_skip_callback *, archive_close_callback *); + +/* + * A variety of shortcuts that invoke archive_read_open() with + * canned callbacks suitable for common situations. The ones that + * accept a block size handle tape blocking correctly. + */ +/* Use this if you know the filename. Note: NULL indicates stdin. */ +__LA_DECL int archive_read_open_filename(struct archive *, + const char *_filename, size_t _block_size); +/* archive_read_open_file() is a deprecated synonym for ..._open_filename(). */ +__LA_DECL int archive_read_open_file(struct archive *, + const char *_filename, size_t _block_size); +/* Read an archive that's stored in memory. */ +__LA_DECL int archive_read_open_memory(struct archive *, + void * buff, size_t size); +/* A more involved version that is only used for internal testing. */ +__LA_DECL int archive_read_open_memory2(struct archive *a, void *buff, + size_t size, size_t read_size); +/* Read an archive that's already open, using the file descriptor. */ +__LA_DECL int archive_read_open_fd(struct archive *, int _fd, + size_t _block_size); +/* Read an archive that's already open, using a FILE *. */ +/* Note: DO NOT use this with tape drives. */ +__LA_DECL int archive_read_open_FILE(struct archive *, FILE *_file); + +/* Parses and returns next entry header. */ +__LA_DECL int archive_read_next_header(struct archive *, + struct archive_entry **); + +/* + * Retrieve the byte offset in UNCOMPRESSED data where last-read + * header started. + */ +__LA_DECL int64_t archive_read_header_position(struct archive *); + +/* Read data from the body of an entry. Similar to read(2). */ +__LA_DECL __LA_SSIZE_T archive_read_data(struct archive *, void *, size_t); +/* + * A zero-copy version of archive_read_data that also exposes the file offset + * of each returned block. Note that the client has no way to specify + * the desired size of the block. The API does guarantee that offsets will + * be strictly increasing and that returned blocks will not overlap. + */ +__LA_DECL int archive_read_data_block(struct archive *a, + const void **buff, size_t *size, off_t *offset); + +/*- + * Some convenience functions that are built on archive_read_data: + * 'skip': skips entire entry + * 'into_buffer': writes data into memory buffer that you provide + * 'into_fd': writes data to specified filedes + */ +__LA_DECL int archive_read_data_skip(struct archive *); +__LA_DECL int archive_read_data_into_buffer(struct archive *, void *buffer, + __LA_SSIZE_T len); +__LA_DECL int archive_read_data_into_fd(struct archive *, int fd); + +/*- + * Convenience function to recreate the current entry (whose header + * has just been read) on disk. + * + * This does quite a bit more than just copy data to disk. It also: + * - Creates intermediate directories as required. + * - Manages directory permissions: non-writable directories will + * be initially created with write permission enabled; when the + * archive is closed, dir permissions are edited to the values specified + * in the archive. + * - Checks hardlinks: hardlinks will not be extracted unless the + * linked-to file was also extracted within the same session. (TODO) + */ + +/* The "flags" argument selects optional behavior, 'OR' the flags you want. */ + +/* Default: Do not try to set owner/group. */ +#define ARCHIVE_EXTRACT_OWNER (0x0001) +/* Default: Do obey umask, do not restore SUID/SGID/SVTX bits. */ +#define ARCHIVE_EXTRACT_PERM (0x0002) +/* Default: Do not restore mtime/atime. */ +#define ARCHIVE_EXTRACT_TIME (0x0004) +/* Default: Replace existing files. */ +#define ARCHIVE_EXTRACT_NO_OVERWRITE (0x0008) +/* Default: Try create first, unlink only if create fails with EEXIST. */ +#define ARCHIVE_EXTRACT_UNLINK (0x0010) +/* Default: Do not restore ACLs. */ +#define ARCHIVE_EXTRACT_ACL (0x0020) +/* Default: Do not restore fflags. */ +#define ARCHIVE_EXTRACT_FFLAGS (0x0040) +/* Default: Do not restore xattrs. */ +#define ARCHIVE_EXTRACT_XATTR (0x0080) +/* Default: Do not try to guard against extracts redirected by symlinks. */ +/* Note: With ARCHIVE_EXTRACT_UNLINK, will remove any intermediate symlink. */ +#define ARCHIVE_EXTRACT_SECURE_SYMLINKS (0x0100) +/* Default: Do not reject entries with '..' as path elements. */ +#define ARCHIVE_EXTRACT_SECURE_NODOTDOT (0x0200) +/* Default: Create parent directories as needed. */ +#define ARCHIVE_EXTRACT_NO_AUTODIR (0x0400) +/* Default: Overwrite files, even if one on disk is newer. */ +#define ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER (0x0800) +/* Detect blocks of 0 and write holes instead. */ +#define ARCHIVE_EXTRACT_SPARSE (0x1000) + +__LA_DECL int archive_read_extract(struct archive *, struct archive_entry *, + int flags); +__LA_DECL int archive_read_extract2(struct archive *, struct archive_entry *, + struct archive * /* dest */); +__LA_DECL void archive_read_extract_set_progress_callback(struct archive *, + void (*_progress_func)(void *), void *_user_data); + +/* Record the dev/ino of a file that will not be written. This is + * generally set to the dev/ino of the archive being read. */ +__LA_DECL void archive_read_extract_set_skip_file(struct archive *, + dev_t, ino_t); + +/* Close the file and release most resources. */ +__LA_DECL int archive_read_close(struct archive *); +/* Release all resources and destroy the object. */ +/* Note that archive_read_finish will call archive_read_close for you. */ +#if ARCHIVE_VERSION_NUMBER >= 2000000 +__LA_DECL int archive_read_finish(struct archive *); +#else +/* Temporarily allow library to compile with either 1.x or 2.0 API. */ +/* Erroneously declared to return void in libarchive 1.x */ +__LA_DECL void archive_read_finish(struct archive *); +#endif + +/*- + * To create an archive: + * 1) Ask archive_write_new for a archive writer object. + * 2) Set any global properties. In particular, you should set + * the compression and format to use. + * 3) Call archive_write_open to open the file (most people + * will use archive_write_open_file or archive_write_open_fd, + * which provide convenient canned I/O callbacks for you). + * 4) For each entry: + * - construct an appropriate struct archive_entry structure + * - archive_write_header to write the header + * - archive_write_data to write the entry data + * 5) archive_write_close to close the output + * 6) archive_write_finish to cleanup the writer and release resources + */ +__LA_DECL struct archive *archive_write_new(void); +__LA_DECL int archive_write_set_bytes_per_block(struct archive *, + int bytes_per_block); +__LA_DECL int archive_write_get_bytes_per_block(struct archive *); +/* XXX This is badly misnamed; suggestions appreciated. XXX */ +__LA_DECL int archive_write_set_bytes_in_last_block(struct archive *, + int bytes_in_last_block); +__LA_DECL int archive_write_get_bytes_in_last_block(struct archive *); + +/* The dev/ino of a file that won't be archived. This is used + * to avoid recursively adding an archive to itself. */ +__LA_DECL int archive_write_set_skip_file(struct archive *, dev_t, ino_t); + +__LA_DECL int archive_write_set_compression_bzip2(struct archive *); +__LA_DECL int archive_write_set_compression_compress(struct archive *); +__LA_DECL int archive_write_set_compression_gzip(struct archive *); +__LA_DECL int archive_write_set_compression_none(struct archive *); +__LA_DECL int archive_write_set_compression_program(struct archive *, + const char *cmd); +/* A convenience function to set the format based on the code or name. */ +__LA_DECL int archive_write_set_format(struct archive *, int format_code); +__LA_DECL int archive_write_set_format_by_name(struct archive *, + const char *name); +/* To minimize link pollution, use one or more of the following. */ +__LA_DECL int archive_write_set_format_ar_bsd(struct archive *); +__LA_DECL int archive_write_set_format_ar_svr4(struct archive *); +__LA_DECL int archive_write_set_format_cpio(struct archive *); +__LA_DECL int archive_write_set_format_cpio_newc(struct archive *); +/* TODO: int archive_write_set_format_old_tar(struct archive *); */ +__LA_DECL int archive_write_set_format_pax(struct archive *); +__LA_DECL int archive_write_set_format_pax_restricted(struct archive *); +__LA_DECL int archive_write_set_format_shar(struct archive *); +__LA_DECL int archive_write_set_format_shar_dump(struct archive *); +__LA_DECL int archive_write_set_format_ustar(struct archive *); +__LA_DECL int archive_write_open(struct archive *, void *, + archive_open_callback *, archive_write_callback *, + archive_close_callback *); +__LA_DECL int archive_write_open_fd(struct archive *, int _fd); +__LA_DECL int archive_write_open_filename(struct archive *, const char *_file); +/* A deprecated synonym for archive_write_open_filename() */ +__LA_DECL int archive_write_open_file(struct archive *, const char *_file); +__LA_DECL int archive_write_open_FILE(struct archive *, FILE *); +/* _buffSize is the size of the buffer, _used refers to a variable that + * will be updated after each write into the buffer. */ +__LA_DECL int archive_write_open_memory(struct archive *, + void *_buffer, size_t _buffSize, size_t *_used); + +/* + * Note that the library will truncate writes beyond the size provided + * to archive_write_header or pad if the provided data is short. + */ +__LA_DECL int archive_write_header(struct archive *, + struct archive_entry *); +#if ARCHIVE_VERSION_NUMBER >= 2000000 +__LA_DECL __LA_SSIZE_T archive_write_data(struct archive *, const void *, size_t); +#else +/* Temporarily allow library to compile with either 1.x or 2.0 API. */ +/* This was erroneously declared to return "int" in libarchive 1.x. */ +__LA_DECL int archive_write_data(struct archive *, const void *, size_t); +#endif +__LA_DECL __LA_SSIZE_T archive_write_data_block(struct archive *, const void *, size_t, off_t); +__LA_DECL int archive_write_finish_entry(struct archive *); +__LA_DECL int archive_write_close(struct archive *); +#if ARCHIVE_VERSION_NUMBER >= 2000000 +__LA_DECL int archive_write_finish(struct archive *); +#else +/* Temporarily allow library to compile with either 1.x or 2.0 API. */ +/* Return value was incorrect in libarchive 1.x. */ +__LA_DECL void archive_write_finish(struct archive *); +#endif + +/*- + * To create objects on disk: + * 1) Ask archive_write_disk_new for a new archive_write_disk object. + * 2) Set any global properties. In particular, you should set + * the compression and format to use. + * 3) For each entry: + * - construct an appropriate struct archive_entry structure + * - archive_write_header to create the file/dir/etc on disk + * - archive_write_data to write the entry data + * 4) archive_write_finish to cleanup the writer and release resources + * + * In particular, you can use this in conjunction with archive_read() + * to pull entries out of an archive and create them on disk. + */ +__LA_DECL struct archive *archive_write_disk_new(void); +/* This file will not be overwritten. */ +__LA_DECL int archive_write_disk_set_skip_file(struct archive *, + dev_t, ino_t); +/* Set flags to control how the next item gets created. */ +__LA_DECL int archive_write_disk_set_options(struct archive *, + int flags); +/* + * The lookup functions are given uname/uid (or gname/gid) pairs and + * return a uid (gid) suitable for this system. These are used for + * restoring ownership and for setting ACLs. The default functions + * are naive, they just return the uid/gid. These are small, so reasonable + * for applications that don't need to preserve ownership; they + * are probably also appropriate for applications that are doing + * same-system backup and restore. + */ +/* + * The "standard" lookup functions use common system calls to lookup + * the uname/gname, falling back to the uid/gid if the names can't be + * found. They cache lookups and are reasonably fast, but can be very + * large, so they are not used unless you ask for them. In + * particular, these match the specifications of POSIX "pax" and old + * POSIX "tar". + */ +__LA_DECL int archive_write_disk_set_standard_lookup(struct archive *); +/* + * If neither the default (naive) nor the standard (big) functions suit + * your needs, you can write your own and register them. Be sure to + * include a cleanup function if you have allocated private data. + */ +__LA_DECL int archive_write_disk_set_group_lookup(struct archive *, + void * /* private_data */, + __LA_GID_T (*)(void *, const char *, __LA_GID_T), + void (* /* cleanup */)(void *)); +__LA_DECL int archive_write_disk_set_user_lookup(struct archive *, + void * /* private_data */, + __LA_UID_T (*)(void *, const char *, __LA_UID_T), + void (* /* cleanup */)(void *)); + +/* + * Accessor functions to read/set various information in + * the struct archive object: + */ +/* Bytes written after compression or read before decompression. */ +__LA_DECL int64_t archive_position_compressed(struct archive *); +/* Bytes written to compressor or read from decompressor. */ +__LA_DECL int64_t archive_position_uncompressed(struct archive *); + +__LA_DECL const char *archive_compression_name(struct archive *); +__LA_DECL int archive_compression(struct archive *); +__LA_DECL int archive_errno(struct archive *); +__LA_DECL const char *archive_error_string(struct archive *); +__LA_DECL const char *archive_format_name(struct archive *); +__LA_DECL int archive_format(struct archive *); +__LA_DECL void archive_clear_error(struct archive *); +__LA_DECL void archive_set_error(struct archive *, int _err, + const char *fmt, ...); +__LA_DECL void archive_copy_error(struct archive *dest, + struct archive *src); + +#ifdef __cplusplus +} +#endif + +/* This is meaningless outside of this header. */ +#undef __LA_DECL + +#endif /* !ARCHIVE_H_INCLUDED */ diff --git a/contrib/libarchive-2/libarchive/archive_endian.h b/contrib/libarchive-2/libarchive/archive_endian.h index 259f5de91e..61af4161c3 100644 --- a/contrib/libarchive-2/libarchive/archive_endian.h +++ b/contrib/libarchive-2/libarchive/archive_endian.h @@ -28,9 +28,23 @@ * Borrowed from FreeBSD's */ +/* Note: This is a purely internal header! */ +/* Do not use this outside of libarchive internal code! */ + #ifndef ARCHIVE_ENDIAN_H_INCLUDED #define ARCHIVE_ENDIAN_H_INCLUDED + +/* Watcom C++ doesn't support 'inline' in C code. (For any version?) */ +#if defined( __WATCOMC__ ) + #define inline +#endif + +/* Visual C++ 6.0 doesn't support 'inline' in C code. (Does VC7? VC8?) */ +#if defined(_MSC_VER) + #define inline +#endif + /* Alignment-agnostic encode/decode bytestream to/from little/big endian. */ static inline uint16_t diff --git a/contrib/libarchive-2/libarchive/archive_entry.3 b/contrib/libarchive-2/libarchive/archive_entry.3 index 6b1b270f1a..e2d4ab1177 100644 --- a/contrib/libarchive-2/libarchive/archive_entry.3 +++ b/contrib/libarchive-2/libarchive/archive_entry.3 @@ -22,9 +22,9 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $FreeBSD: src/lib/libarchive/archive_entry.3,v 1.15 2007/07/15 19:10:34 kientzle Exp $ +.\" $FreeBSD: src/lib/libarchive/archive_entry.3,v 1.17 2008/03/14 23:00:53 kientzle Exp $ .\" -.Dd December 15, 2003 +.Dd May 12, 2008 .Dt archive_entry 3 .Os .Sh NAME @@ -40,12 +40,16 @@ .Nm archive_entry_atime_nsec , .Nm archive_entry_clear , .Nm archive_entry_clone , +.Nm archive_entry_copy_fflags_text , .Nm archive_entry_copy_fflags_text_w , .Nm archive_entry_copy_gname , .Nm archive_entry_copy_gname_w , .Nm archive_entry_copy_hardlink , .Nm archive_entry_copy_hardlink_w , +.Nm archive_entry_copy_link , +.Nm archive_entry_copy_link_w , .Nm archive_entry_copy_pathname_w , +.Nm archive_entry_copy_sourcepath , .Nm archive_entry_copy_stat , .Nm archive_entry_copy_symlink , .Nm archive_entry_copy_symlink_w , @@ -93,6 +97,7 @@ .Nm archive_entry_set_uid , .Nm archive_entry_set_uname , .Nm archive_entry_size , +.Nm archive_entry_sourcepath , .Nm archive_entry_stat , .Nm archive_entry_symlink , .Nm archive_entry_uid , @@ -101,17 +106,47 @@ .Sh SYNOPSIS .In archive_entry.h .Ft void -.Fn archive_entry_acl_add_entry "struct archive_entry *" "int type" "int permset" "int tag" "int qual" "const char *name" -.Ft void -.Fn archive_entry_acl_add_entry_w "struct archive_entry *" "int type" "int permset" "int tag" "int qual" "const wchar_t *name" +.Fo archive_entry_acl_add_entry +.Fa "struct archive_entry *" +.Fa "int type" +.Fa "int permset" +.Fa "int tag" +.Fa "int qual" +.Fa "const char *name" +.Fc +.Ft void +.Fo archive_entry_acl_add_entry_w +.Fa "struct archive_entry *" +.Fa "int type" +.Fa "int permset" +.Fa "int tag" +.Fa "int qual" +.Fa "const wchar_t *name" +.Fc .Ft void .Fn archive_entry_acl_clear "struct archive_entry *" .Ft int .Fn archive_entry_acl_count "struct archive_entry *" "int type" .Ft int -.Fn archive_entry_acl_next "struct archive_entry *" "int want_type" "int *type" "int *permset" "int *tag" "int *qual" "const char **name" +.Fo archive_entry_acl_next +.Fa "struct archive_entry *" +.Fa "int want_type" +.Fa "int *type" +.Fa "int *permset" +.Fa "int *tag" +.Fa "int *qual" +.Fa "const char **name" +.Fc .Ft int -.Fn archive_entry_acl_next_w "struct archive_entry *" "int want_type" "int *type" "int *permset" "int *tag" "int *qual" "const wchar_t **name" +.Fo archive_entry_acl_next_w +.Fa "struct archive_entry *" +.Fa "int want_type" +.Fa "int *type" +.Fa "int *permset" +.Fa "int *tag" +.Fa "int *qual" +.Fa "const wchar_t **name" +.Fc .Ft int .Fn archive_entry_acl_reset "struct archive_entry *" "int want_type" .Ft const wchar_t * @@ -124,6 +159,8 @@ .Fn archive_entry_clear "struct archive_entry *" .Ft struct archive_entry * .Fn archive_entry_clone "struct archive_entry *" +.Ft const char * * +.Fn archive_entry_copy_fflags_text_w "struct archive_entry *" "const char *" .Ft const wchar_t * .Fn archive_entry_copy_fflags_text_w "struct archive_entry *" "const wchar_t *" .Ft void @@ -135,6 +172,8 @@ .Ft void .Fn archive_entry_copy_hardlink_w "struct archive_entry *" "const wchar_t *" .Ft void +.Fn archive_entry_copy_sourcepath "struct archive_entry *" "const char *" +.Ft void .Fn archive_entry_copy_pathname_w "struct archive_entry *" "const wchar_t *" .Ft void .Fn archive_entry_copy_stat "struct archive_entry *" "const struct stat *" @@ -155,7 +194,11 @@ .Ft mode_t .Fn archive_entry_filetype "struct archive_entry *" .Ft void -.Fn archive_entry_fflags "struct archive_entry *" "unsigned long *set" "unsigned long *clear" +.Fo archive_entry_fflags +.Fa "struct archive_entry *" +.Fa "unsigned long *set" +.Fa "unsigned long *clear" +.Fc .Ft const char * .Fn archive_entry_fflags_text "struct archive_entry *" .Ft void @@ -195,7 +238,11 @@ .Ft void .Fn archive_entry_set_filetype "struct archive_entry *" "unsigned int" .Ft void -.Fn archive_entry_set_fflags "struct archive_entry *" "unsigned long set" "unsigned long clear" +.Fo archive_entry_set_fflags +.Fa "struct archive_entry *" +.Fa "unsigned long set" +.Fa "unsigned long clear" +.Fc .Ft void .Fn archive_entry_set_gid "struct archive_entry *" "gid_t" .Ft void @@ -230,6 +277,8 @@ .Fn archive_entry_set_uname "struct archive_entry *" "const char *" .Ft int64_t .Fn archive_entry_size "struct archive_entry *" +.Ft const char * +.Fn archive_entry_sourcepath "struct archive_entry *" .Ft const struct stat * .Fn archive_entry_stat "struct archive_entry *" .Ft const char * @@ -336,8 +385,10 @@ will be ignored. .Pp The canonical text format is a comma-separated list of flag names. The +.Fn archive_entry_copy_fflags_text +and .Fn archive_entry_copy_fflags_text_w -function parses the provided text and sets the internal bitmap values. +functions parse the provided text and sets the internal bitmap values. This is a platform-specific operation; names that are not meaningful on the current platform will be ignored. The function returns a pointer to the start of the first name that was not diff --git a/contrib/libarchive-2/libarchive/archive_entry.c b/contrib/libarchive-2/libarchive/archive_entry.c index a6c9b4496c..210685af2b 100644 --- a/contrib/libarchive-2/libarchive/archive_entry.c +++ b/contrib/libarchive-2/libarchive/archive_entry.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_entry.c,v 1.45 2007/12/30 04:58:21 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_entry.c,v 1.51 2008/03/14 23:19:46 kientzle Exp $"); #ifdef HAVE_SYS_STAT_H #include @@ -91,15 +91,17 @@ static void aes_clean(struct aes *); static void aes_copy(struct aes *dest, struct aes *src); static const char * aes_get_mbs(struct aes *); static const wchar_t * aes_get_wcs(struct aes *); -static void aes_set_mbs(struct aes *, const char *mbs); -static void aes_copy_mbs(struct aes *, const char *mbs); +static int aes_set_mbs(struct aes *, const char *mbs); +static int aes_copy_mbs(struct aes *, const char *mbs); /* static void aes_set_wcs(struct aes *, const wchar_t *wcs); */ -static void aes_copy_wcs(struct aes *, const wchar_t *wcs); -static void aes_copy_wcs_len(struct aes *, const wchar_t *wcs, size_t); +static int aes_copy_wcs(struct aes *, const wchar_t *wcs); +static int aes_copy_wcs_len(struct aes *, const wchar_t *wcs, size_t); static char * ae_fflagstostr(unsigned long bitset, unsigned long bitclear); static const wchar_t *ae_wcstofflags(const wchar_t *stringp, unsigned long *setp, unsigned long *clrp); +static const char *ae_strtofflags(const char *stringp, + unsigned long *setp, unsigned long *clrp); static void append_entry_w(wchar_t **wp, const wchar_t *prefix, int tag, const wchar_t *wname, int perm, int id); static void append_id_w(wchar_t **wp, int id); @@ -144,173 +146,216 @@ static size_t wcslen(const wchar_t *s) #define wmemcpy(a,b,i) (wchar_t *)memcpy((a), (b), (i) * sizeof(wchar_t)) #endif - static void aes_clean(struct aes *aes) { - if (aes->aes_mbs_alloc) { - free(aes->aes_mbs_alloc); - aes->aes_mbs_alloc = NULL; - } - if (aes->aes_wcs_alloc) { - free(aes->aes_wcs_alloc); - aes->aes_wcs_alloc = NULL; + if (aes->aes_wcs) { + free((wchar_t *)(uintptr_t)aes->aes_wcs); + aes->aes_wcs = NULL; } - memset(aes, 0, sizeof(*aes)); + archive_string_free(&(aes->aes_mbs)); + archive_string_free(&(aes->aes_utf8)); + aes->aes_set = 0; } static void aes_copy(struct aes *dest, struct aes *src) { - *dest = *src; - if (src->aes_mbs != NULL) { - dest->aes_mbs_alloc = strdup(src->aes_mbs); - dest->aes_mbs = dest->aes_mbs_alloc; - if (dest->aes_mbs == NULL) - __archive_errx(1, "No memory for aes_copy()"); - } + wchar_t *wp; + + dest->aes_set = src->aes_set; + archive_string_copy(&(dest->aes_mbs), &(src->aes_mbs)); + archive_string_copy(&(dest->aes_utf8), &(src->aes_utf8)); if (src->aes_wcs != NULL) { - dest->aes_wcs_alloc = (wchar_t *)malloc((wcslen(src->aes_wcs) + 1) + wp = (wchar_t *)malloc((wcslen(src->aes_wcs) + 1) * sizeof(wchar_t)); - dest->aes_wcs = dest->aes_wcs_alloc; - if (dest->aes_wcs == NULL) + if (wp == NULL) __archive_errx(1, "No memory for aes_copy()"); - wcscpy(dest->aes_wcs_alloc, src->aes_wcs); + wcscpy(wp, src->aes_wcs); + dest->aes_wcs = wp; + } +} + +static const char * +aes_get_utf8(struct aes *aes) +{ + if (aes->aes_set & AES_SET_UTF8) + return (aes->aes_utf8.s); + if ((aes->aes_set & AES_SET_WCS) + && archive_strappend_w_utf8(&(aes->aes_utf8), aes->aes_wcs) != NULL) { + aes->aes_set |= AES_SET_UTF8; + return (aes->aes_utf8.s); } + return (NULL); } static const char * aes_get_mbs(struct aes *aes) { - if (aes->aes_mbs == NULL && aes->aes_wcs == NULL) - return NULL; - if (aes->aes_mbs == NULL && aes->aes_wcs != NULL) { - /* - * XXX Need to estimate the number of byte in the - * multi-byte form. Assume that, on average, wcs - * chars encode to no more than 3 bytes. There must - * be a better way... XXX - */ - size_t mbs_length = wcslen(aes->aes_wcs) * 3 + 64; - - aes->aes_mbs_alloc = (char *)malloc(mbs_length); - aes->aes_mbs = aes->aes_mbs_alloc; - if (aes->aes_mbs == NULL) - __archive_errx(1, "No memory for aes_get_mbs()"); - wcstombs(aes->aes_mbs_alloc, aes->aes_wcs, mbs_length - 1); - aes->aes_mbs_alloc[mbs_length - 1] = 0; + /* If we already have an MBS form, return that immediately. */ + if (aes->aes_set & AES_SET_MBS) + return (aes->aes_mbs.s); + /* If there's a WCS form, try converting with the native locale. */ + if ((aes->aes_set & AES_SET_WCS) + && archive_strappend_w_mbs(&(aes->aes_mbs), aes->aes_wcs) != NULL) { + aes->aes_set |= AES_SET_MBS; + return (aes->aes_mbs.s); } - return (aes->aes_mbs); + /* We'll use UTF-8 for MBS if all else fails. */ + return (aes_get_utf8(aes)); } static const wchar_t * aes_get_wcs(struct aes *aes) { + wchar_t *w; int r; - if (aes->aes_wcs == NULL && aes->aes_mbs == NULL) - return NULL; - if (aes->aes_wcs == NULL && aes->aes_mbs != NULL) { + /* Return WCS form if we already have it. */ + if (aes->aes_set & AES_SET_WCS) + return (aes->aes_wcs); + + if (aes->aes_set & AES_SET_MBS) { + /* Try converting MBS to WCS using native locale. */ /* * No single byte will be more than one wide character, * so this length estimate will always be big enough. */ - size_t wcs_length = strlen(aes->aes_mbs); + size_t wcs_length = aes->aes_mbs.length; - aes->aes_wcs_alloc - = (wchar_t *)malloc((wcs_length + 1) * sizeof(wchar_t)); - aes->aes_wcs = aes->aes_wcs_alloc; - if (aes->aes_wcs == NULL) + w = (wchar_t *)malloc((wcs_length + 1) * sizeof(wchar_t)); + if (w == NULL) __archive_errx(1, "No memory for aes_get_wcs()"); - r = mbstowcs(aes->aes_wcs_alloc, aes->aes_mbs, wcs_length); - aes->aes_wcs_alloc[wcs_length] = 0; - if (r == -1) { - /* Conversion failed, don't lie to our clients. */ - free(aes->aes_wcs_alloc); - aes->aes_wcs = aes->aes_wcs_alloc = NULL; + r = mbstowcs(w, aes->aes_mbs.s, wcs_length); + w[wcs_length] = 0; + if (r > 0) { + aes->aes_set |= AES_SET_WCS; + return (aes->aes_wcs = w); } + free(w); } - return (aes->aes_wcs); + + if (aes->aes_set & AES_SET_UTF8) { + /* Try converting UTF8 to WCS. */ + aes->aes_wcs = __archive_string_utf8_w(&(aes->aes_utf8)); + aes->aes_set |= AES_SET_WCS; + return (aes->aes_wcs); + } + return (NULL); } -static void +static int aes_set_mbs(struct aes *aes, const char *mbs) { - if (aes->aes_mbs_alloc) { - free(aes->aes_mbs_alloc); - aes->aes_mbs_alloc = NULL; - } - if (aes->aes_wcs_alloc) { - free(aes->aes_wcs_alloc); - aes->aes_wcs_alloc = NULL; - } - aes->aes_mbs = mbs; - aes->aes_wcs = NULL; + return (aes_copy_mbs(aes, mbs)); } -static void +static int aes_copy_mbs(struct aes *aes, const char *mbs) { - if (aes->aes_mbs_alloc) { - free(aes->aes_mbs_alloc); - aes->aes_mbs_alloc = NULL; + if (mbs == NULL) { + aes->aes_set = 0; + return (0); } - if (aes->aes_wcs_alloc) { - free(aes->aes_wcs_alloc); - aes->aes_wcs_alloc = NULL; + aes->aes_set = AES_SET_MBS; /* Only MBS form is set now. */ + archive_strcpy(&(aes->aes_mbs), mbs); + archive_string_empty(&(aes->aes_utf8)); + if (aes->aes_wcs) { + free((wchar_t *)(uintptr_t)aes->aes_wcs); + aes->aes_wcs = NULL; } - aes->aes_mbs_alloc = (char *)malloc((strlen(mbs) + 1) * sizeof(char)); - if (aes->aes_mbs_alloc == NULL) - __archive_errx(1, "No memory for aes_copy_mbs()"); - strcpy(aes->aes_mbs_alloc, mbs); - aes->aes_mbs = aes->aes_mbs_alloc; - aes->aes_wcs = NULL; + return (0); } -#if 0 -static void -aes_set_wcs(struct aes *aes, const wchar_t *wcs) +/* + * The 'update' form tries to proactively update all forms of + * this string (WCS and MBS) and returns an error if any of + * them fail. This is used by the 'pax' handler, for instance, + * to detect and report character-conversion failures early while + * still allowing clients to get potentially useful values from + * the more tolerant lazy conversions. (get_mbs and get_wcs will + * strive to give the user something useful, so you can get hopefully + * usable values even if some of the character conversions are failing.) + */ +static int +aes_update_utf8(struct aes *aes, const char *utf8) { - if (aes->aes_mbs_alloc) { - free(aes->aes_mbs_alloc); - aes->aes_mbs_alloc = NULL; + if (utf8 == NULL) { + aes->aes_set = 0; + return (1); /* Succeeded in clearing everything. */ } - if (aes->aes_wcs_alloc) { - free(aes->aes_wcs_alloc); - aes->aes_wcs_alloc = NULL; + + /* Save the UTF8 string. */ + archive_strcpy(&(aes->aes_utf8), utf8); + + /* Empty the mbs and wcs strings. */ + archive_string_empty(&(aes->aes_mbs)); + if (aes->aes_wcs) { + free((wchar_t *)(uintptr_t)aes->aes_wcs); + aes->aes_wcs = NULL; } - aes->aes_mbs = NULL; - aes->aes_wcs = wcs; + + aes->aes_set = AES_SET_UTF8; /* Only UTF8 is set now. */ + + /* TODO: We should just do a direct UTF-8 to MBS conversion + * here. That would be faster, use less space, and give the + * same information. (If a UTF-8 to MBS conversion succeeds, + * then UTF-8->WCS and Unicode->MBS conversions will both + * succeed.) */ + + /* Try converting UTF8 to WCS, return false on failure. */ + aes->aes_wcs = __archive_string_utf8_w(&(aes->aes_utf8)); + if (aes->aes_wcs == NULL) + return (0); + aes->aes_set = AES_SET_UTF8 | AES_SET_WCS; /* Both UTF8 and WCS set. */ + + /* Try converting WCS to MBS, return false on failure. */ + if (archive_strappend_w_mbs(&(aes->aes_mbs), aes->aes_wcs) == NULL) + return (0); + aes->aes_set = AES_SET_UTF8 | AES_SET_WCS | AES_SET_MBS; + + /* All conversions succeeded. */ + return (1); } -#endif -static void +static int aes_copy_wcs(struct aes *aes, const wchar_t *wcs) { - aes_copy_wcs_len(aes, wcs, wcslen(wcs)); + return aes_copy_wcs_len(aes, wcs, wcs == NULL ? 0 : wcslen(wcs)); } -static void +static int aes_copy_wcs_len(struct aes *aes, const wchar_t *wcs, size_t len) { - if (aes->aes_mbs_alloc) { - free(aes->aes_mbs_alloc); - aes->aes_mbs_alloc = NULL; + wchar_t *w; + + if (wcs == NULL) { + aes->aes_set = 0; + return (0); } - if (aes->aes_wcs_alloc) { - free(aes->aes_wcs_alloc); - aes->aes_wcs_alloc = NULL; + aes->aes_set = AES_SET_WCS; /* Only WCS form set. */ + archive_string_empty(&(aes->aes_mbs)); + archive_string_empty(&(aes->aes_utf8)); + if (aes->aes_wcs) { + free((wchar_t *)(uintptr_t)aes->aes_wcs); + aes->aes_wcs = NULL; } - aes->aes_mbs = NULL; - aes->aes_wcs_alloc = (wchar_t *)malloc((len + 1) * sizeof(wchar_t)); - if (aes->aes_wcs_alloc == NULL) + w = (wchar_t *)malloc((len + 1) * sizeof(wchar_t)); + if (w == NULL) __archive_errx(1, "No memory for aes_copy_wcs()"); - wmemcpy(aes->aes_wcs_alloc, wcs, len); - aes->aes_wcs_alloc[len] = L'\0'; - aes->aes_wcs = aes->aes_wcs_alloc; + wmemcpy(w, wcs, len); + w[len] = L'\0'; + aes->aes_wcs = w; + return (0); } +/**************************************************************************** + * + * Public Interface + * + ****************************************************************************/ + struct archive_entry * archive_entry_clear(struct archive_entry *entry) { @@ -350,6 +395,8 @@ archive_entry_clone(struct archive_entry *entry) aes_copy(&entry2->ae_hardlink, &entry->ae_hardlink); aes_copy(&entry2->ae_pathname, &entry->ae_pathname); aes_copy(&entry2->ae_symlink, &entry->ae_symlink); + entry2->ae_hardlinkset = entry->ae_hardlinkset; + entry2->ae_symlinkset = entry->ae_symlinkset; aes_copy(&entry2->ae_uname, &entry->ae_uname); /* Copy ACL data over. */ @@ -515,12 +562,16 @@ archive_entry_gname_w(struct archive_entry *entry) const char * archive_entry_hardlink(struct archive_entry *entry) { + if (!entry->ae_hardlinkset) + return (NULL); return (aes_get_mbs(&entry->ae_hardlink)); } const wchar_t * archive_entry_hardlink_w(struct archive_entry *entry) { + if (!entry->ae_hardlinkset) + return (NULL); return (aes_get_wcs(&entry->ae_hardlink)); } @@ -600,15 +651,25 @@ archive_entry_size(struct archive_entry *entry) return (entry->ae_stat.aest_size); } +const char * +archive_entry_sourcepath(struct archive_entry *entry) +{ + return (aes_get_mbs(&entry->ae_sourcepath)); +} + const char * archive_entry_symlink(struct archive_entry *entry) { + if (!entry->ae_symlinkset) + return (NULL); return (aes_get_mbs(&entry->ae_symlink)); } const wchar_t * archive_entry_symlink_w(struct archive_entry *entry) { + if (!entry->ae_symlinkset) + return (NULL); return (aes_get_wcs(&entry->ae_symlink)); } @@ -651,6 +712,15 @@ archive_entry_set_fflags(struct archive_entry *entry, entry->ae_fflags_clear = clear; } +const char * +archive_entry_copy_fflags_text(struct archive_entry *entry, + const char *flags) +{ + aes_copy_mbs(&entry->ae_fflags_text, flags); + return (ae_strtofflags(flags, + &entry->ae_fflags_set, &entry->ae_fflags_clear)); +} + const wchar_t * archive_entry_copy_fflags_text_w(struct archive_entry *entry, const wchar_t *flags) @@ -685,6 +755,12 @@ archive_entry_copy_gname_w(struct archive_entry *entry, const wchar_t *name) aes_copy_wcs(&entry->ae_gname, name); } +int +archive_entry_update_gname_utf8(struct archive_entry *entry, const char *name) +{ + return (aes_update_utf8(&entry->ae_gname, name)); +} + void archive_entry_set_ino(struct archive_entry *entry, unsigned long ino) { @@ -696,18 +772,24 @@ void archive_entry_set_hardlink(struct archive_entry *entry, const char *target) { aes_set_mbs(&entry->ae_hardlink, target); + if (target != NULL) + entry->ae_hardlinkset = 1; } void archive_entry_copy_hardlink(struct archive_entry *entry, const char *target) { aes_copy_mbs(&entry->ae_hardlink, target); + if (target != NULL) + entry->ae_hardlinkset = 1; } void archive_entry_copy_hardlink_w(struct archive_entry *entry, const wchar_t *target) { aes_copy_wcs(&entry->ae_hardlink, target); + if (target != NULL) + entry->ae_hardlinkset = 1; } void @@ -754,8 +836,7 @@ archive_entry_set_devminor(struct archive_entry *entry, dev_t m) void archive_entry_set_link(struct archive_entry *entry, const char *target) { - if (entry->ae_symlink.aes_mbs != NULL || - entry->ae_symlink.aes_wcs != NULL) + if (entry->ae_symlinkset) aes_set_mbs(&entry->ae_symlink, target); else aes_set_mbs(&entry->ae_hardlink, target); @@ -765,8 +846,7 @@ archive_entry_set_link(struct archive_entry *entry, const char *target) void archive_entry_copy_link(struct archive_entry *entry, const char *target) { - if (entry->ae_symlink.aes_mbs != NULL || - entry->ae_symlink.aes_wcs != NULL) + if (entry->ae_symlinkset) aes_copy_mbs(&entry->ae_symlink, target); else aes_copy_mbs(&entry->ae_hardlink, target); @@ -776,13 +856,21 @@ archive_entry_copy_link(struct archive_entry *entry, const char *target) void archive_entry_copy_link_w(struct archive_entry *entry, const wchar_t *target) { - if (entry->ae_symlink.aes_mbs != NULL || - entry->ae_symlink.aes_wcs != NULL) + if (entry->ae_symlinkset) aes_copy_wcs(&entry->ae_symlink, target); else aes_copy_wcs(&entry->ae_hardlink, target); } +int +archive_entry_update_link_utf8(struct archive_entry *entry, const char *target) +{ + if (entry->ae_symlinkset) + return (aes_update_utf8(&entry->ae_symlink, target)); + else + return (aes_update_utf8(&entry->ae_hardlink, target)); +} + void archive_entry_set_mode(struct archive_entry *entry, mode_t m) { @@ -823,6 +911,12 @@ archive_entry_copy_pathname_w(struct archive_entry *entry, const wchar_t *name) aes_copy_wcs(&entry->ae_pathname, name); } +int +archive_entry_update_pathname_utf8(struct archive_entry *entry, const char *name) +{ + return (aes_update_utf8(&entry->ae_pathname, name)); +} + void archive_entry_set_perm(struct archive_entry *entry, mode_t p) { @@ -862,22 +956,34 @@ archive_entry_set_size(struct archive_entry *entry, int64_t s) entry->ae_stat.aest_size = s; } +void +archive_entry_copy_sourcepath(struct archive_entry *entry, const char *path) +{ + aes_set_mbs(&entry->ae_sourcepath, path); +} + void archive_entry_set_symlink(struct archive_entry *entry, const char *linkname) { aes_set_mbs(&entry->ae_symlink, linkname); + if (linkname != NULL) + entry->ae_symlinkset = 1; } void archive_entry_copy_symlink(struct archive_entry *entry, const char *linkname) { aes_copy_mbs(&entry->ae_symlink, linkname); + if (linkname != NULL) + entry->ae_symlinkset = 1; } void archive_entry_copy_symlink_w(struct archive_entry *entry, const wchar_t *linkname) { aes_copy_wcs(&entry->ae_symlink, linkname); + if (linkname != NULL) + entry->ae_symlinkset = 1; } void @@ -905,6 +1011,12 @@ archive_entry_copy_uname_w(struct archive_entry *entry, const wchar_t *name) aes_copy_wcs(&entry->ae_uname, name); } +int +archive_entry_update_uname_utf8(struct archive_entry *entry, const char *name) +{ + return (aes_update_utf8(&entry->ae_uname, name)); +} + /* * ACL management. The following would, of course, be a lot simpler * if: 1) the last draft of POSIX.1e were a really thorough and @@ -1155,6 +1267,11 @@ archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type, entry->acl_p = entry->acl_p->next; if (entry->acl_p == NULL) { entry->acl_state = 0; + *type = 0; + *permset = 0; + *tag = 0; + *id = -1; + *name = NULL; return (ARCHIVE_EOF); /* End of ACL entries. */ } *type = entry->acl_p->type; @@ -1536,7 +1653,7 @@ archive_entry_xattr_next(struct archive_entry * entry, return (ARCHIVE_OK); } else { *name = NULL; - *name = NULL; + *value = NULL; *size = (size_t)0; return (ARCHIVE_WARN); } @@ -1739,7 +1856,7 @@ static struct flag { * Convert file flags to a comma-separated string. If no flags * are set, return the empty string. */ -char * +static char * ae_fflagstostr(unsigned long bitset, unsigned long bitclear) { char *string, *dp; @@ -1783,6 +1900,70 @@ ae_fflagstostr(unsigned long bitset, unsigned long bitclear) return (string); } +/* + * strtofflags -- + * Take string of arguments and return file flags. This + * version works a little differently than strtofflags(3). + * In particular, it always tests every token, skipping any + * unrecognized tokens. It returns a pointer to the first + * unrecognized token, or NULL if every token was recognized. + * This version is also const-correct and does not modify the + * provided string. + */ +static const char * +ae_strtofflags(const char *s, unsigned long *setp, unsigned long *clrp) +{ + const char *start, *end; + struct flag *flag; + unsigned long set, clear; + const char *failed; + + set = clear = 0; + start = s; + failed = NULL; + /* Find start of first token. */ + while (*start == '\t' || *start == ' ' || *start == ',') + start++; + while (*start != '\0') { + /* Locate end of token. */ + end = start; + while (*end != '\0' && *end != '\t' && + *end != ' ' && *end != ',') + end++; + for (flag = flags; flag->name != NULL; flag++) { + if (memcmp(start, flag->name, end - start) == 0) { + /* Matched "noXXXX", so reverse the sense. */ + clear |= flag->set; + set |= flag->clear; + break; + } else if (memcmp(start, flag->name + 2, end - start) + == 0) { + /* Matched "XXXX", so don't reverse. */ + set |= flag->set; + clear |= flag->clear; + break; + } + } + /* Ignore unknown flag names. */ + if (flag->name == NULL && failed == NULL) + failed = start; + + /* Find start of next token. */ + start = end; + while (*start == '\t' || *start == ' ' || *start == ',') + start++; + + } + + if (setp) + *setp = set; + if (clrp) + *clrp = clear; + + /* Return location of first failure. */ + return (failed); +} + /* * wcstofflags -- * Take string of arguments and return file flags. This @@ -1793,7 +1974,7 @@ ae_fflagstostr(unsigned long bitset, unsigned long bitclear) * This version is also const-correct and does not modify the * provided string. */ -const wchar_t * +static const wchar_t * ae_wcstofflags(const wchar_t *s, unsigned long *setp, unsigned long *clrp) { const wchar_t *start, *end; diff --git a/contrib/libarchive-2/libarchive/archive_entry.h b/contrib/libarchive-2/libarchive/archive_entry.h index cebd55ba8a..f8601b9ee2 100644 --- a/contrib/libarchive-2/libarchive/archive_entry.h +++ b/contrib/libarchive-2/libarchive/archive_entry.h @@ -22,16 +22,71 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/lib/libarchive/archive_entry.h,v 1.24 2007/12/30 04:58:21 kientzle Exp $ + * $FreeBSD: src/lib/libarchive/archive_entry.h,v 1.26 2008/03/14 23:00:53 kientzle Exp $ */ #ifndef ARCHIVE_ENTRY_H_INCLUDED #define ARCHIVE_ENTRY_H_INCLUDED +/* + * Note: archive_entry.h is for use outside of libarchive; the + * configuration headers (config.h, archive_platform.h, etc.) are + * purely internal. Do NOT use HAVE_XXX configuration macros to + * control the behavior of this header! If you must conditionalize, + * use predefined compiler and/or platform macros. + */ + #include #include /* for wchar_t */ #include + +/* Get appropriate definitions of standard POSIX-style types. */ +/* These should match the types used in 'struct stat' */ +#ifdef _WIN32 +#define __LA_UID_T unsigned int +#define __LA_GID_T unsigned int +#define __LA_DEV_T unsigned int +#define __LA_MODE_T unsigned short +#else #include +#define __LA_UID_T uid_t +#define __LA_GID_T gid_t +#define __LA_DEV_T dev_t +#define __LA_MODE_T mode_t +#endif + +/* + * XXX Is this defined for all Windows compilers? If so, in what + * header? It would be nice to remove the __LA_INO_T indirection and + * just use plain ino_t everywhere. Likewise for the other types just + * above. + */ +#define __LA_INO_T ino_t + + +/* + * On Windows, define LIBARCHIVE_STATIC if you're building or using a + * .lib. The default here assumes you're building a DLL. Only + * libarchive source should ever define __LIBARCHIVE_BUILD. + */ +#if ((defined __WIN32__) || (defined _WIN32)) && (!defined LIBARCHIVE_STATIC) +# ifdef __LIBARCHIVE_BUILD +# ifdef __GNUC__ +# define __LA_DECL __attribute__((dllexport)) extern +# else +# define __LA_DECL __declspec(dllexport) +# endif +# else +# ifdef __GNUC__ +# define __LA_DECL __attribute__((dllimport)) extern +# else +# define __LA_DECL __declspec(dllimport) +# endif +# endif +#else +/* Static libraries on all platforms and shared libraries on non-Windows. */ +# define __LA_DECL +#endif #ifdef __cplusplus extern "C" { @@ -40,7 +95,7 @@ extern "C" { /* * Description of an archive entry. * - * Basically, a "struct stat" with a few text fields added in. + * You can think of this as "struct stat" with some text fields added in. * * TODO: Add "comment", "charset", and possibly other entries that are * supported by "pax interchange" format. However, GNU, ustar, cpio, @@ -89,50 +144,51 @@ struct archive_entry; * Basic object manipulation */ -struct archive_entry *archive_entry_clear(struct archive_entry *); +__LA_DECL struct archive_entry *archive_entry_clear(struct archive_entry *); /* The 'clone' function does a deep copy; all of the strings are copied too. */ -struct archive_entry *archive_entry_clone(struct archive_entry *); -void archive_entry_free(struct archive_entry *); -struct archive_entry *archive_entry_new(void); +__LA_DECL struct archive_entry *archive_entry_clone(struct archive_entry *); +__LA_DECL void archive_entry_free(struct archive_entry *); +__LA_DECL struct archive_entry *archive_entry_new(void); /* * Retrieve fields from an archive_entry. */ -time_t archive_entry_atime(struct archive_entry *); -long archive_entry_atime_nsec(struct archive_entry *); -time_t archive_entry_ctime(struct archive_entry *); -long archive_entry_ctime_nsec(struct archive_entry *); -dev_t archive_entry_dev(struct archive_entry *); -dev_t archive_entry_devmajor(struct archive_entry *); -dev_t archive_entry_devminor(struct archive_entry *); -mode_t archive_entry_filetype(struct archive_entry *); -void archive_entry_fflags(struct archive_entry *, +__LA_DECL time_t archive_entry_atime(struct archive_entry *); +__LA_DECL long archive_entry_atime_nsec(struct archive_entry *); +__LA_DECL time_t archive_entry_ctime(struct archive_entry *); +__LA_DECL long archive_entry_ctime_nsec(struct archive_entry *); +__LA_DECL dev_t archive_entry_dev(struct archive_entry *); +__LA_DECL dev_t archive_entry_devmajor(struct archive_entry *); +__LA_DECL dev_t archive_entry_devminor(struct archive_entry *); +__LA_DECL __LA_MODE_T archive_entry_filetype(struct archive_entry *); +__LA_DECL void archive_entry_fflags(struct archive_entry *, unsigned long * /* set */, unsigned long * /* clear */); -const char *archive_entry_fflags_text(struct archive_entry *); -gid_t archive_entry_gid(struct archive_entry *); -const char *archive_entry_gname(struct archive_entry *); -const wchar_t *archive_entry_gname_w(struct archive_entry *); -const char *archive_entry_hardlink(struct archive_entry *); -const wchar_t *archive_entry_hardlink_w(struct archive_entry *); -ino_t archive_entry_ino(struct archive_entry *); -mode_t archive_entry_mode(struct archive_entry *); -time_t archive_entry_mtime(struct archive_entry *); -long archive_entry_mtime_nsec(struct archive_entry *); -unsigned int archive_entry_nlink(struct archive_entry *); -const char *archive_entry_pathname(struct archive_entry *); -const wchar_t *archive_entry_pathname_w(struct archive_entry *); -dev_t archive_entry_rdev(struct archive_entry *); -dev_t archive_entry_rdevmajor(struct archive_entry *); -dev_t archive_entry_rdevminor(struct archive_entry *); -int64_t archive_entry_size(struct archive_entry *); -const char *archive_entry_strmode(struct archive_entry *); -const char *archive_entry_symlink(struct archive_entry *); -const wchar_t *archive_entry_symlink_w(struct archive_entry *); -uid_t archive_entry_uid(struct archive_entry *); -const char *archive_entry_uname(struct archive_entry *); -const wchar_t *archive_entry_uname_w(struct archive_entry *); +__LA_DECL const char *archive_entry_fflags_text(struct archive_entry *); +__LA_DECL __LA_GID_T archive_entry_gid(struct archive_entry *); +__LA_DECL const char *archive_entry_gname(struct archive_entry *); +__LA_DECL const wchar_t *archive_entry_gname_w(struct archive_entry *); +__LA_DECL const char *archive_entry_hardlink(struct archive_entry *); +__LA_DECL const wchar_t *archive_entry_hardlink_w(struct archive_entry *); +__LA_DECL __LA_INO_T archive_entry_ino(struct archive_entry *); +__LA_DECL __LA_MODE_T archive_entry_mode(struct archive_entry *); +__LA_DECL time_t archive_entry_mtime(struct archive_entry *); +__LA_DECL long archive_entry_mtime_nsec(struct archive_entry *); +__LA_DECL unsigned int archive_entry_nlink(struct archive_entry *); +__LA_DECL const char *archive_entry_pathname(struct archive_entry *); +__LA_DECL const wchar_t *archive_entry_pathname_w(struct archive_entry *); +__LA_DECL dev_t archive_entry_rdev(struct archive_entry *); +__LA_DECL dev_t archive_entry_rdevmajor(struct archive_entry *); +__LA_DECL dev_t archive_entry_rdevminor(struct archive_entry *); +__LA_DECL const char *archive_entry_sourcepath(struct archive_entry *); +__LA_DECL int64_t archive_entry_size(struct archive_entry *); +__LA_DECL const char *archive_entry_strmode(struct archive_entry *); +__LA_DECL const char *archive_entry_symlink(struct archive_entry *); +__LA_DECL const wchar_t *archive_entry_symlink_w(struct archive_entry *); +__LA_DECL __LA_UID_T archive_entry_uid(struct archive_entry *); +__LA_DECL const char *archive_entry_uname(struct archive_entry *); +__LA_DECL const wchar_t *archive_entry_uname_w(struct archive_entry *); /* * Set fields in an archive_entry. @@ -141,48 +197,54 @@ const wchar_t *archive_entry_uname_w(struct archive_entry *); * In contrast, 'copy' functions do copy the object pointed to. */ -void archive_entry_set_atime(struct archive_entry *, time_t, long); -void archive_entry_set_ctime(struct archive_entry *, time_t, long); -void archive_entry_set_dev(struct archive_entry *, dev_t); -void archive_entry_set_devmajor(struct archive_entry *, dev_t); -void archive_entry_set_devminor(struct archive_entry *, dev_t); -void archive_entry_set_filetype(struct archive_entry *, unsigned int); -void archive_entry_set_fflags(struct archive_entry *, +__LA_DECL void archive_entry_set_atime(struct archive_entry *, time_t, long); +__LA_DECL void archive_entry_set_ctime(struct archive_entry *, time_t, long); +__LA_DECL void archive_entry_set_dev(struct archive_entry *, dev_t); +__LA_DECL void archive_entry_set_devmajor(struct archive_entry *, dev_t); +__LA_DECL void archive_entry_set_devminor(struct archive_entry *, dev_t); +__LA_DECL void archive_entry_set_filetype(struct archive_entry *, unsigned int); +__LA_DECL void archive_entry_set_fflags(struct archive_entry *, unsigned long /* set */, unsigned long /* clear */); /* Returns pointer to start of first invalid token, or NULL if none. */ /* Note that all recognized tokens are processed, regardless. */ -const wchar_t *archive_entry_copy_fflags_text_w(struct archive_entry *, +__LA_DECL const char *archive_entry_copy_fflags_text(struct archive_entry *, + const char *); +__LA_DECL const wchar_t *archive_entry_copy_fflags_text_w(struct archive_entry *, const wchar_t *); -void archive_entry_set_gid(struct archive_entry *, gid_t); -void archive_entry_set_gname(struct archive_entry *, const char *); -void archive_entry_copy_gname(struct archive_entry *, const char *); -void archive_entry_copy_gname_w(struct archive_entry *, const wchar_t *); -void archive_entry_set_hardlink(struct archive_entry *, const char *); -void archive_entry_copy_hardlink(struct archive_entry *, const char *); -void archive_entry_copy_hardlink_w(struct archive_entry *, const wchar_t *); -void archive_entry_set_ino(struct archive_entry *, unsigned long); -void archive_entry_set_link(struct archive_entry *, const char *); -void archive_entry_copy_link(struct archive_entry *, const char *); -void archive_entry_copy_link_w(struct archive_entry *, const wchar_t *); -void archive_entry_set_mode(struct archive_entry *, mode_t); -void archive_entry_set_mtime(struct archive_entry *, time_t, long); -void archive_entry_set_nlink(struct archive_entry *, unsigned int); -void archive_entry_set_pathname(struct archive_entry *, const char *); -void archive_entry_copy_pathname(struct archive_entry *, const char *); -void archive_entry_copy_pathname_w(struct archive_entry *, const wchar_t *); -void archive_entry_set_perm(struct archive_entry *, mode_t); -void archive_entry_set_rdev(struct archive_entry *, dev_t); -void archive_entry_set_rdevmajor(struct archive_entry *, dev_t); -void archive_entry_set_rdevminor(struct archive_entry *, dev_t); -void archive_entry_set_size(struct archive_entry *, int64_t); -void archive_entry_set_symlink(struct archive_entry *, const char *); -void archive_entry_copy_symlink(struct archive_entry *, const char *); -void archive_entry_copy_symlink_w(struct archive_entry *, const wchar_t *); -void archive_entry_set_uid(struct archive_entry *, uid_t); -void archive_entry_set_uname(struct archive_entry *, const char *); -void archive_entry_copy_uname(struct archive_entry *, const char *); -void archive_entry_copy_uname_w(struct archive_entry *, const wchar_t *); - +__LA_DECL void archive_entry_set_gid(struct archive_entry *, __LA_GID_T); +__LA_DECL void archive_entry_set_gname(struct archive_entry *, const char *); +__LA_DECL void archive_entry_copy_gname(struct archive_entry *, const char *); +__LA_DECL void archive_entry_copy_gname_w(struct archive_entry *, const wchar_t *); +__LA_DECL int archive_entry_update_gname_utf8(struct archive_entry *, const char *); +__LA_DECL void archive_entry_set_hardlink(struct archive_entry *, const char *); +__LA_DECL void archive_entry_copy_hardlink(struct archive_entry *, const char *); +__LA_DECL void archive_entry_copy_hardlink_w(struct archive_entry *, const wchar_t *); +__LA_DECL void archive_entry_set_ino(struct archive_entry *, unsigned long); +__LA_DECL void archive_entry_set_link(struct archive_entry *, const char *); +__LA_DECL void archive_entry_copy_link(struct archive_entry *, const char *); +__LA_DECL void archive_entry_copy_link_w(struct archive_entry *, const wchar_t *); +__LA_DECL int archive_entry_update_link_utf8(struct archive_entry *, const char *); +__LA_DECL void archive_entry_set_mode(struct archive_entry *, __LA_MODE_T); +__LA_DECL void archive_entry_set_mtime(struct archive_entry *, time_t, long); +__LA_DECL void archive_entry_set_nlink(struct archive_entry *, unsigned int); +__LA_DECL void archive_entry_set_pathname(struct archive_entry *, const char *); +__LA_DECL void archive_entry_copy_pathname(struct archive_entry *, const char *); +__LA_DECL void archive_entry_copy_pathname_w(struct archive_entry *, const wchar_t *); +__LA_DECL int archive_entry_update_pathname_utf8(struct archive_entry *, const char *); +__LA_DECL void archive_entry_set_perm(struct archive_entry *, __LA_MODE_T); +__LA_DECL void archive_entry_set_rdev(struct archive_entry *, dev_t); +__LA_DECL void archive_entry_set_rdevmajor(struct archive_entry *, dev_t); +__LA_DECL void archive_entry_set_rdevminor(struct archive_entry *, dev_t); +__LA_DECL void archive_entry_set_size(struct archive_entry *, int64_t); +__LA_DECL void archive_entry_copy_sourcepath(struct archive_entry *, const char *); +__LA_DECL void archive_entry_set_symlink(struct archive_entry *, const char *); +__LA_DECL void archive_entry_copy_symlink(struct archive_entry *, const char *); +__LA_DECL void archive_entry_copy_symlink_w(struct archive_entry *, const wchar_t *); +__LA_DECL void archive_entry_set_uid(struct archive_entry *, __LA_UID_T); +__LA_DECL void archive_entry_set_uname(struct archive_entry *, const char *); +__LA_DECL void archive_entry_copy_uname(struct archive_entry *, const char *); +__LA_DECL void archive_entry_copy_uname_w(struct archive_entry *, const wchar_t *); +__LA_DECL int archive_entry_update_uname_utf8(struct archive_entry *, const char *); /* * Routines to bulk copy fields to/from a platform-native "struct * stat." Libarchive used to just store a struct stat inside of each @@ -192,8 +254,8 @@ void archive_entry_copy_uname_w(struct archive_entry *, const wchar_t *); * * TODO: On Linux, provide both stat32 and stat64 versions of these functions. */ -const struct stat *archive_entry_stat(struct archive_entry *); -void archive_entry_copy_stat(struct archive_entry *, const struct stat *); +__LA_DECL const struct stat *archive_entry_stat(struct archive_entry *); +__LA_DECL void archive_entry_copy_stat(struct archive_entry *, const struct stat *); /* * ACL routines. This used to simply store and return text-format ACL @@ -241,11 +303,11 @@ void archive_entry_copy_stat(struct archive_entry *, const struct stat *); * POSIX.1e) is useful for handling archive formats that combine * default and access information in a single ACL list. */ -void archive_entry_acl_clear(struct archive_entry *); -void archive_entry_acl_add_entry(struct archive_entry *, +__LA_DECL void archive_entry_acl_clear(struct archive_entry *); +__LA_DECL void archive_entry_acl_add_entry(struct archive_entry *, int /* type */, int /* permset */, int /* tag */, int /* qual */, const char * /* name */); -void archive_entry_acl_add_entry_w(struct archive_entry *, +__LA_DECL void archive_entry_acl_add_entry_w(struct archive_entry *, int /* type */, int /* permset */, int /* tag */, int /* qual */, const wchar_t * /* name */); @@ -254,11 +316,11 @@ void archive_entry_acl_add_entry_w(struct archive_entry *, * "next" entry. The want_type parameter allows you to request only * access entries or only default entries. */ -int archive_entry_acl_reset(struct archive_entry *, int /* want_type */); -int archive_entry_acl_next(struct archive_entry *, int /* want_type */, +__LA_DECL int archive_entry_acl_reset(struct archive_entry *, int /* want_type */); +__LA_DECL int archive_entry_acl_next(struct archive_entry *, int /* want_type */, int * /* type */, int * /* permset */, int * /* tag */, int * /* qual */, const char ** /* name */); -int archive_entry_acl_next_w(struct archive_entry *, int /* want_type */, +__LA_DECL int archive_entry_acl_next_w(struct archive_entry *, int /* want_type */, int * /* type */, int * /* permset */, int * /* tag */, int * /* qual */, const wchar_t ** /* name */); @@ -275,11 +337,11 @@ int archive_entry_acl_next_w(struct archive_entry *, int /* want_type */, */ #define ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID 1024 #define ARCHIVE_ENTRY_ACL_STYLE_MARK_DEFAULT 2048 -const wchar_t *archive_entry_acl_text_w(struct archive_entry *, +__LA_DECL const wchar_t *archive_entry_acl_text_w(struct archive_entry *, int /* flags */); /* Return a count of entries matching 'want_type' */ -int archive_entry_acl_count(struct archive_entry *, int /* want_type */); +__LA_DECL int archive_entry_acl_count(struct archive_entry *, int /* want_type */); /* * Private ACL parser. This is private because it handles some @@ -294,15 +356,15 @@ int archive_entry_acl_count(struct archive_entry *, int /* want_type */); * TODO: Move this declaration out of the public header and into * a private header. Warnings above are silly. */ -int __archive_entry_acl_parse_w(struct archive_entry *, +__LA_DECL int __archive_entry_acl_parse_w(struct archive_entry *, const wchar_t *, int /* type */); /* * extended attributes */ -void archive_entry_xattr_clear(struct archive_entry *); -void archive_entry_xattr_add_entry(struct archive_entry *, +__LA_DECL void archive_entry_xattr_clear(struct archive_entry *); +__LA_DECL void archive_entry_xattr_add_entry(struct archive_entry *, const char * /* name */, const void * /* value */, size_t /* size */); @@ -311,18 +373,18 @@ void archive_entry_xattr_add_entry(struct archive_entry *, * "next" entry. */ -int archive_entry_xattr_count(struct archive_entry *); -int archive_entry_xattr_reset(struct archive_entry *); -int archive_entry_xattr_next(struct archive_entry *, +__LA_DECL int archive_entry_xattr_count(struct archive_entry *); +__LA_DECL int archive_entry_xattr_reset(struct archive_entry *); +__LA_DECL int archive_entry_xattr_next(struct archive_entry *, const char ** /* name */, const void ** /* value */, size_t *); /* - * Utility to detect hardlinks. + * Utility to match up hardlinks. * * The 'struct archive_entry_linkresolver' is a cache of archive entries * for files with multiple links. Here's how to use it: * 1. Create a lookup object with archive_entry_linkresolver_new() - * 2. Set the appropriate strategy. + * 2. Tell it the archive format you're using. * 3. Hand each archive_entry to archive_entry_linkify(). * That function will return 0, 1, or 2 entries that should * be written. @@ -344,11 +406,11 @@ int archive_entry_xattr_next(struct archive_entry *, * Note that archive_entry_size() is reset to zero if the file * body should not be written to the archive. Pay attention! */ -struct archive_entry_linkresolver; +__LA_DECL struct archive_entry_linkresolver; /* - * This machine supports three different strategies for marking - * hardlinks. The names come from the best-known + * There are three different strategies for marking hardlinks. + * The descriptions below name them after the best-known * formats that rely on each strategy: * * "Old cpio" is the simplest, it always returns any entry unmodified. @@ -357,7 +419,7 @@ struct archive_entry_linkresolver; * to detect and properly link the files as they are restored. * "tar" is also pretty simple; it caches a copy the first time it sees * any link. Subsequent appearances are modified to be hardlink - * references without any body to the first one. Used by all tar + * references to the first one without any body. Used by all tar * formats, although the newest tar formats permit the "old cpio" strategy * as well. This strategy is very simple for the dearchiver, * and reasonably straightforward for the archiver. @@ -385,28 +447,19 @@ struct archive_entry_linkresolver; * strategy requires you to rescan the archive from the beginning to * correctly extract an arbitrary link. */ -#define ARCHIVE_ENTRY_LINKIFY_LIKE_TAR 0 -#define ARCHIVE_ENTRY_LINKIFY_LIKE_OLD_CPIO 1 -#define ARCHIVE_ENTRY_LINKIFY_LIKE_NEW_CPIO 2 - -struct archive_entry_linkresolver *archive_entry_linkresolver_new(void); -void archive_entry_linkresolver_set_strategy( - struct archive_entry_linkresolver *, int /* strategy */); -void archive_entry_linkresolver_free(struct archive_entry_linkresolver *); -void archive_entry_linkify(struct archive_entry_linkresolver *, - struct archive_entry **, struct archive_entry **); -/* - * DEPRECATED: This will be removed in libarchive 3.0. It was an - * early attempt at providing library-level hardlink recognition - * support, but it only handles the tar strategy and cannot easily - * be extended, so it's being replaced with the "linkify" function. - */ -const char *archive_entry_linkresolve(struct archive_entry_linkresolver *, - struct archive_entry *); +__LA_DECL struct archive_entry_linkresolver *archive_entry_linkresolver_new(void); +__LA_DECL void archive_entry_linkresolver_set_strategy( + struct archive_entry_linkresolver *, int /* format_code */); +__LA_DECL void archive_entry_linkresolver_free(struct archive_entry_linkresolver *); +__LA_DECL void archive_entry_linkify(struct archive_entry_linkresolver *, + struct archive_entry **, struct archive_entry **); #ifdef __cplusplus } #endif +/* This is meaningless outside of this header. */ +#undef __LA_DECL + #endif /* !ARCHIVE_ENTRY_H_INCLUDED */ diff --git a/contrib/libarchive-2/libarchive/archive_entry_link_resolver.c b/contrib/libarchive-2/libarchive/archive_entry_link_resolver.c index 37131ff325..c0770c239d 100644 --- a/contrib/libarchive-2/libarchive/archive_entry_link_resolver.c +++ b/contrib/libarchive-2/libarchive/archive_entry_link_resolver.c @@ -40,6 +40,7 @@ __FBSDID("$FreeBSD: src/lib/libarchive/archive_entry_link_resolver.c,v 1.1 2007/ #include #endif +#include "archive.h" #include "archive_entry.h" /* @@ -57,6 +58,12 @@ __FBSDID("$FreeBSD: src/lib/libarchive/archive_entry_link_resolver.c,v 1.1 2007/ * below. */ +/* Users pass us a format code, we translate that into a strategy here. */ +#define ARCHIVE_ENTRY_LINKIFY_LIKE_TAR 0 +#define ARCHIVE_ENTRY_LINKIFY_LIKE_MTREE 1 +#define ARCHIVE_ENTRY_LINKIFY_LIKE_OLD_CPIO 2 +#define ARCHIVE_ENTRY_LINKIFY_LIKE_NEW_CPIO 3 + /* Initial size of link cache. */ #define links_cache_initial_size 1024 @@ -65,6 +72,7 @@ struct links_entry { struct links_entry *previous; int links; /* # links not yet seen */ int hash; + struct archive_entry *canonical; struct archive_entry *entry; }; @@ -79,8 +87,9 @@ struct archive_entry_linkresolver { static struct links_entry *find_entry(struct archive_entry_linkresolver *, struct archive_entry *); static void grow_hash(struct archive_entry_linkresolver *); -static void insert_entry(struct archive_entry_linkresolver *, +static struct links_entry *insert_entry(struct archive_entry_linkresolver *, struct archive_entry *); +static struct links_entry *next_entry(struct archive_entry_linkresolver *); struct archive_entry_linkresolver * archive_entry_linkresolver_new(void) @@ -106,49 +115,49 @@ archive_entry_linkresolver_new(void) void archive_entry_linkresolver_set_strategy(struct archive_entry_linkresolver *res, - int strategy) + int fmt) { - res->strategy = strategy; + int fmtbase = fmt & ARCHIVE_FORMAT_BASE_MASK; + + switch (fmtbase) { + case ARCHIVE_FORMAT_CPIO: + switch (fmt) { + case ARCHIVE_FORMAT_CPIO_SVR4_NOCRC: + case ARCHIVE_FORMAT_CPIO_SVR4_CRC: + res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_NEW_CPIO; + break; + default: + res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_OLD_CPIO; + break; + } + break; + case ARCHIVE_FORMAT_MTREE: + res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_MTREE; + break; + case ARCHIVE_FORMAT_TAR: + res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_TAR; + break; + default: + res->strategy = ARCHIVE_ENTRY_LINKIFY_LIKE_TAR; + break; + } } void archive_entry_linkresolver_free(struct archive_entry_linkresolver *res) { - size_t i; + struct links_entry *le; - if (res->buckets == NULL) + if (res == NULL) return; - for (i = 0; i < res->number_buckets; i++) { - while (res->buckets[i] != NULL) { - struct links_entry *lp = res->buckets[i]->next; - archive_entry_free(res->buckets[i]->entry); - free(res->buckets[i]); - res->buckets[i] = lp; - } + if (res->buckets != NULL) { + while ((le = next_entry(res)) != NULL) + archive_entry_free(le->entry); + free(res->buckets); + res->buckets = NULL; } - free(res->buckets); - res->buckets = NULL; -} - -/* Always uses tar-like semantics. */ -const char * -archive_entry_linkresolve(struct archive_entry_linkresolver *res, - struct archive_entry *entry) -{ - struct links_entry *le; - - /* If it has only one link, then we're done. */ - if (archive_entry_nlink(entry) == 1) - return (NULL); - - /* Look it up in the hash. */ - le = find_entry(res, entry); - if (le != NULL) - return (archive_entry_pathname(le->entry)); - /* If it's not there, insert it. */ - insert_entry(res, entry); - return (NULL); + free(res); } void @@ -160,6 +169,15 @@ archive_entry_linkify(struct archive_entry_linkresolver *res, *f = NULL; /* Default: Don't return a second entry. */ + if (*e == NULL) { + le = next_entry(res); + if (le != NULL) { + *e = le->entry; + le->entry = NULL; + } + return; + } + /* If it has only one link, then we're done. */ if (archive_entry_nlink(*e) == 1) return; @@ -169,8 +187,16 @@ archive_entry_linkify(struct archive_entry_linkresolver *res, le = find_entry(res, *e); if (le != NULL) { archive_entry_set_size(*e, 0); - archive_entry_set_hardlink(*e, - archive_entry_pathname(le->entry)); + archive_entry_copy_hardlink(*e, + archive_entry_pathname(le->canonical)); + } else + insert_entry(res, *e); + return; + case ARCHIVE_ENTRY_LINKIFY_LIKE_MTREE: + le = find_entry(res, *e); + if (le != NULL) { + archive_entry_copy_hardlink(*e, + archive_entry_pathname(le->canonical)); } else insert_entry(res, *e); return; @@ -180,17 +206,30 @@ archive_entry_linkify(struct archive_entry_linkresolver *res, case ARCHIVE_ENTRY_LINKIFY_LIKE_NEW_CPIO: le = find_entry(res, *e); if (le != NULL) { + /* + * Put the new entry in le, return the + * old entry from le. + */ t = *e; *e = le->entry; le->entry = t; + /* Make the old entry into a hardlink. */ archive_entry_set_size(*e, 0); - archive_entry_set_hardlink(*e, - archive_entry_pathname(le->entry)); + archive_entry_copy_hardlink(*e, + archive_entry_pathname(le->canonical)); + /* If we ran out of links, return the + * final entry as well. */ if (le->links == 0) { *f = le->entry; + le->entry = NULL; } } else { - insert_entry(res, *e); + /* + * If we haven't seen it, tuck it away + * for future use. + */ + le = insert_entry(res, *e); + le->entry = *e; *e = NULL; } return; @@ -211,6 +250,7 @@ find_entry(struct archive_entry_linkresolver *res, /* Free a held entry. */ if (res->spare != NULL) { + archive_entry_free(res->spare->canonical); archive_entry_free(res->spare->entry); free(res->spare); res->spare = NULL; @@ -228,8 +268,8 @@ find_entry(struct archive_entry_linkresolver *res, bucket = hash % res->number_buckets; for (le = res->buckets[bucket]; le != NULL; le = le->next) { if (le->hash == hash - && dev == archive_entry_dev(le->entry) - && ino == archive_entry_ino(le->entry)) { + && dev == archive_entry_dev(le->canonical) + && ino == archive_entry_ino(le->canonical)) { /* * Decrement link count each time and release * the entry if it hits zero. This saves @@ -255,7 +295,41 @@ find_entry(struct archive_entry_linkresolver *res, return (NULL); } -static void +static struct links_entry * +next_entry(struct archive_entry_linkresolver *res) +{ + struct links_entry *le; + size_t bucket; + + /* Free a held entry. */ + if (res->spare != NULL) { + archive_entry_free(res->spare->canonical); + free(res->spare); + res->spare = NULL; + } + + /* If the links cache overflowed and got flushed, don't bother. */ + if (res->buckets == NULL) + return (NULL); + + /* Look for next non-empty bucket in the links cache. */ + for (bucket = 0; bucket < res->number_buckets; bucket++) { + le = res->buckets[bucket]; + if (le != NULL) { + /* Remove it from this hash bucket. */ + if (le->next != NULL) + le->next->previous = le->previous; + res->buckets[bucket] = le->next; + res->number_entries--; + /* Defer freeing this entry. */ + res->spare = le; + return (le); + } + } + return (NULL); +} + +static struct links_entry * insert_entry(struct archive_entry_linkresolver *res, struct archive_entry *entry) { @@ -265,12 +339,9 @@ insert_entry(struct archive_entry_linkresolver *res, /* Add this entry to the links cache. */ le = malloc(sizeof(struct links_entry)); if (le == NULL) - return; - le->entry = archive_entry_clone(entry); - if (le->entry == NULL) { - free(le); - return; - } + return (NULL); + memset(le, 0, sizeof(*le)); + le->canonical = archive_entry_clone(entry); /* If the links cache is getting too full, enlarge the hash table. */ if (res->number_entries > res->number_buckets * 2) @@ -288,6 +359,7 @@ insert_entry(struct archive_entry_linkresolver *res, res->buckets[bucket] = le; le->hash = hash; le->links = archive_entry_nlink(entry) - 1; + return (le); } static void diff --git a/contrib/libarchive-2/libarchive/archive_entry_private.h b/contrib/libarchive-2/libarchive/archive_entry_private.h index 57fe29600a..f893fb982a 100644 --- a/contrib/libarchive-2/libarchive/archive_entry_private.h +++ b/contrib/libarchive-2/libarchive/archive_entry_private.h @@ -22,23 +22,31 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/lib/libarchive/archive_entry_private.h,v 1.2 2007/12/30 04:58:21 kientzle Exp $ + * $FreeBSD: src/lib/libarchive/archive_entry_private.h,v 1.3 2008/03/31 06:24:39 kientzle Exp $ */ #ifndef ARCHIVE_ENTRY_PRIVATE_H_INCLUDED #define ARCHIVE_ENTRY_PRIVATE_H_INCLUDED +#include "archive_string.h" + /* * Handle wide character (i.e., Unicode) and non-wide character * strings transparently. - * */ struct aes { - const char *aes_mbs; - char *aes_mbs_alloc; + struct archive_string aes_mbs; + struct archive_string aes_utf8; const wchar_t *aes_wcs; - wchar_t *aes_wcs_alloc; + /* Bitmap of which of the above are valid. Because we're lazy + * about malloc-ing and reusing the underlying storage, we + * can't rely on NULL pointers to indicate whether a string + * has been set. */ + int aes_set; +#define AES_SET_MBS 1 +#define AES_SET_UTF8 2 +#define AES_SET_WCS 4 }; struct ae_acl { @@ -128,8 +136,6 @@ struct archive_entry { dev_t aest_rdevminor; } ae_stat; - - /* * Use aes here so that we get transparent mbs<->wcs conversions. */ @@ -141,16 +147,24 @@ struct archive_entry { struct aes ae_pathname; /* Name of entry */ struct aes ae_symlink; /* symlink contents */ struct aes ae_uname; /* Name of owner */ + unsigned char ae_hardlinkset; + unsigned char ae_symlinkset; + + /* Not used within libarchive; useful for some clients. */ + struct aes ae_sourcepath; /* Path this entry is sourced from. */ + /* ACL support. */ struct ae_acl *acl_head; struct ae_acl *acl_p; int acl_state; /* See acl_next for details. */ wchar_t *acl_text_w; + /* extattr support. */ struct ae_xattr *xattr_head; struct ae_xattr *xattr_p; - char strmode[11]; + /* Miscellaneous. */ + char strmode[12]; }; diff --git a/contrib/libarchive-2/libarchive/archive_entry_strmode.c b/contrib/libarchive-2/libarchive/archive_entry_strmode.c index dc08d9721a..cfe6ae33ba 100644 --- a/contrib/libarchive-2/libarchive/archive_entry_strmode.c +++ b/contrib/libarchive-2/libarchive/archive_entry_strmode.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_entry_strmode.c,v 1.2 2008/02/19 05:49:02 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_entry_strmode.c,v 1.3 2008/05/23 04:57:28 cperciva Exp $"); #ifdef HAVE_SYS_STAT_H #include @@ -39,7 +39,6 @@ __FBSDID("$FreeBSD: src/lib/libarchive/archive_entry_strmode.c,v 1.2 2008/02/19 const char * archive_entry_strmode(struct archive_entry *entry) { - static const char *perms = "?rwxrwxrwx "; static const mode_t permbits[] = { 0400, 0200, 0100, 0040, 0020, 0010, 0004, 0002, 0001 }; char *bp = entry->strmode; @@ -47,7 +46,7 @@ archive_entry_strmode(struct archive_entry *entry) int i; /* Fill in a default string, then selectively override. */ - strcpy(bp, perms); + strcpy(bp, "?rwxrwxrwx "); mode = archive_entry_mode(entry); switch (archive_entry_filetype(entry)) { diff --git a/contrib/libarchive-2/libarchive/archive_platform.h b/contrib/libarchive-2/libarchive/archive_platform.h index b14ccd8206..41fd4e549d 100644 --- a/contrib/libarchive-2/libarchive/archive_platform.h +++ b/contrib/libarchive-2/libarchive/archive_platform.h @@ -36,6 +36,9 @@ #ifndef ARCHIVE_PLATFORM_H_INCLUDED #define ARCHIVE_PLATFORM_H_INCLUDED +/* archive.h and archive_entry.h require this. */ +#define __LIBARCHIVE_BUILD 1 + #ifdef _WIN32 #include "config_windows.h" #include "archive_windows.h" diff --git a/contrib/libarchive-2/libarchive/archive_read.3 b/contrib/libarchive-2/libarchive/archive_read.3 index 6daba3f3d1..dbbe1f7f1e 100644 --- a/contrib/libarchive-2/libarchive/archive_read.3 +++ b/contrib/libarchive-2/libarchive/archive_read.3 @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $FreeBSD: src/lib/libarchive/archive_read.3,v 1.35 2007/09/19 16:37:45 kientzle Exp $ +.\" $FreeBSD: src/lib/libarchive/archive_read.3,v 1.36 2008/03/10 14:45:29 jkoshy Exp $ .\" .Dd August 19, 2006 .Dt archive_read 3 @@ -56,6 +56,7 @@ .\" #endif .Nm archive_read_data_into_fd , .Nm archive_read_extract , +.Nm archive_read_extract2 , .Nm archive_read_extract_set_progress_callback , .Nm archive_read_close , .Nm archive_read_finish @@ -75,7 +76,10 @@ .Ft int .Fn archive_read_support_compression_none "struct archive *" .Ft int -.Fn archive_read_support_compression_program "struct archive *" "const char *cmd" +.Fo archive_read_support_compression_program +.Fa "struct archive *" +.Fa "const char *cmd" +.Fc .Ft int .Fn archive_read_support_format_all "struct archive *" .Ft int @@ -89,15 +93,32 @@ .Ft int .Fn archive_read_support_format_zip "struct archive *" .Ft int -.Fn archive_read_open "struct archive *" "void *client_data" "archive_open_callback *" "archive_read_callback *" "archive_close_callback *" +.Fo archive_read_open +.Fa "struct archive *" +.Fa "void *client_data" +.Fa "archive_open_callback *" +.Fa "archive_read_callback *" +.Fa "archive_close_callback *" +.Fc .Ft int -.Fn archive_read_open2 "struct archive *" "void *client_data" "archive_open_callback *" "archive_read_callback *" "archive_skip_callback *" "archive_close_callback *" +.Fo archive_read_open2 +.Fa "struct archive *" +.Fa "void *client_data" +.Fa "archive_open_callback *" +.Fa "archive_read_callback *" +.Fa "archive_skip_callback *" +.Fa "archive_close_callback *" +.Fc .Ft int .Fn archive_read_open_FILE "struct archive *" "FILE *file" .Ft int .Fn archive_read_open_fd "struct archive *" "int fd" "size_t block_size" .Ft int -.Fn archive_read_open_filename "struct archive *" "const char *filename" "size_t block_size" +.Fo archive_read_open_filename +.Fa "struct archive *" +.Fa "const char *filename" +.Fa "size_t block_size" +.Fc .Ft int .Fn archive_read_open_memory "struct archive *" "void *buff" "size_t size" .Ft int @@ -105,7 +126,12 @@ .Ft ssize_t .Fn archive_read_data "struct archive *" "void *buff" "size_t len" .Ft int -.Fn archive_read_data_block "struct archive *" "const void **buff" "size_t *len" "off_t *offset" +.Fo archive_read_data_block +.Fa "struct archive *" +.Fa "const void **buff" +.Fa "size_t *len" +.Fa "off_t *offset" +.Fc .Ft int .Fn archive_read_data_skip "struct archive *" .\" #if ARCHIVE_API_VERSION < 3 @@ -115,9 +141,23 @@ .Ft int .Fn archive_read_data_into_fd "struct archive *" "int fd" .Ft int -.Fn archive_read_extract "struct archive *" "struct archive_entry *" "int flags" +.Fo archive_read_extract +.Fa "struct archive *" +.Fa "struct archive_entry *" +.Fa "int flags" +.Fc +.Ft int +.Fo archive_read_extract2 +.Fa "struct archive *src" +.Fa "struct archive_entry *" +.Fa "struct archive *dest" +.Fc .Ft void -.Fn archive_read_extract_set_progress_callback "struct archive *" "void (*func)(void *)" "void *user_data" +.Fo archive_read_extract_set_progress_callback +.Fa "struct archive *" +.Fa "void (*func)(void *)" +.Fa "void *user_data" +.Fc .Ft int .Fn archive_read_close "struct archive *" .Ft int @@ -136,7 +176,13 @@ order they would be used: Allocates and initializes a .Tn struct archive object suitable for reading from an archive. -.It Fn archive_read_support_compression_all , Fn archive_read_support_compression_bzip2 , Fn archive_read_support_compression_compress , Fn archive_read_support_compression_gzip , Fn archive_read_support_compression_none +.It Xo +.Fn archive_read_support_compression_all , +.Fn archive_read_support_compression_bzip2 , +.Fn archive_read_support_compression_compress , +.Fn archive_read_support_compression_gzip , +.Fn archive_read_support_compression_none +.Xc Enables auto-detection code and decompression support for the specified compression. Note that @@ -150,7 +196,14 @@ Data is fed through the specified external program before being dearchived. Note that this disables automatic detection of the compression format, so it makes no sense to specify this in conjunction with any other decompression option. -.It Fn archive_read_support_format_all , Fn archive_read_support_format_cpio , Fn archive_read_support_format_empty , Fn archive_read_support_format_iso9660 , Fn archive_read_support_format_tar, Fn archive_read_support_format_zip +.It Xo +.Fn archive_read_support_format_all , +.Fn archive_read_support_format_cpio , +.Fn archive_read_support_format_empty , +.Fn archive_read_support_format_iso9660 , +.Fn archive_read_support_format_tar , +.Fn archive_read_support_format_zip +.Xc Enables support---including auto-detection code---for the specified archive format. For example, @@ -268,6 +321,22 @@ The .Va flags argument is passed unmodified to .Xr archive_write_disk_set_options 3 . +.It Fn archive_read_extract2 +This is another version of +.Fn archive_read_extract +that allows you to provide your own restore object. +In particular, this allows you to override the standard lookup functions +using +.Xr archive_write_disk_set_group_lookup 3 , +and +.Xr archive_write_disk_set_user_lookup 3 . +Note that +.Fn archive_read_extract2 +does not accept a +.Va flags +argument; you should use +.Fn archive_write_disk_set_options +to set the restore options yourself. .It Fn archive_read_extract_set_progress_callback Sets a pointer to a user-defined callback that can be used for updating progress displays during extraction. @@ -311,14 +380,26 @@ The callback functions must match the following prototypes: .Bl -item -offset indent .It .Ft typedef ssize_t -.Fn archive_read_callback "struct archive *" "void *client_data" "const void **buffer" +.Fo archive_read_callback +.Fa "struct archive *" +.Fa "void *client_data" +.Fa "const void **buffer" +.Fc .It .\" #if ARCHIVE_API_VERSION < 2 .Ft typedef int -.Fn archive_skip_callback "struct archive *" "void *client_data" "size_t request" +.Fo archive_skip_callback +.Fa "struct archive *" +.Fa "void *client_data" +.Fa "size_t request" +.Fc .\" #else .\" .Ft typedef off_t -.\" .Fn archive_skip_callback "struct archive *" "void *client_data" "off_t request" +.\" .Fo archive_skip_callback +.\" .Fa "struct archive *" +.\" .Fa "void *client_data" +.\" .Fa "off_t request" +.\" .Fc .\" #endif .It .Ft typedef int diff --git a/contrib/libarchive-2/libarchive/archive_read.c b/contrib/libarchive-2/libarchive/archive_read.c index 19be77569c..327969f418 100644 --- a/contrib/libarchive-2/libarchive/archive_read.c +++ b/contrib/libarchive-2/libarchive/archive_read.c @@ -32,7 +32,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_read.c,v 1.37 2008/01/03 17:54:26 des Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_read.c,v 1.38 2008/03/12 04:58:32 kientzle Exp $"); #ifdef HAVE_ERRNO_H #include @@ -64,25 +64,12 @@ struct archive * archive_read_new(void) { struct archive_read *a; - unsigned char *nulls; a = (struct archive_read *)malloc(sizeof(*a)); if (a == NULL) return (NULL); memset(a, 0, sizeof(*a)); a->archive.magic = ARCHIVE_READ_MAGIC; - a->bytes_per_block = ARCHIVE_DEFAULT_BYTES_PER_BLOCK; - - a->null_length = 1024; - nulls = (unsigned char *)malloc(a->null_length); - if (nulls == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate archive object 'nulls' element"); - free(a); - return (NULL); - } - memset(nulls, 0, a->null_length); - a->nulls = nulls; a->archive.state = ARCHIVE_STATE_NEW; a->entry = archive_entry_new(); @@ -660,8 +647,6 @@ archive_read_finish(struct archive *_a) (a->formats[i].cleanup)(a); } - /* Casting a pointer to int allows us to remove 'const.' */ - free((void *)(uintptr_t)(const void *)a->nulls); archive_string_free(&a->archive.error_string); if (a->entry) archive_entry_free(a->entry); diff --git a/contrib/libarchive-2/libarchive/archive_read_data_into_fd.c b/contrib/libarchive-2/libarchive/archive_read_data_into_fd.c index 664cc2c3c2..3aeef3bc2d 100644 --- a/contrib/libarchive-2/libarchive/archive_read_data_into_fd.c +++ b/contrib/libarchive-2/libarchive/archive_read_data_into_fd.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_data_into_fd.c,v 1.15 2007/04/02 00:21:46 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_data_into_fd.c,v 1.16 2008/05/23 05:01:29 cperciva Exp $"); #ifdef HAVE_SYS_TYPES_H #include @@ -64,8 +64,12 @@ archive_read_data_into_fd(struct archive *a, int fd) ARCHIVE_OK) { const char *p = buff; if (offset > output_offset) { - lseek(fd, offset - output_offset, SEEK_CUR); - output_offset = offset; + output_offset = lseek(fd, + offset - output_offset, SEEK_CUR); + if (output_offset != offset) { + archive_set_error(a, errno, "Seek error"); + return (ARCHIVE_FATAL); + } } while (size > 0) { bytes_to_write = size; @@ -74,7 +78,7 @@ archive_read_data_into_fd(struct archive *a, int fd) bytes_written = write(fd, p, bytes_to_write); if (bytes_written < 0) { archive_set_error(a, errno, "Write error"); - return (-1); + return (ARCHIVE_FATAL); } output_offset += bytes_written; total_written += bytes_written; diff --git a/contrib/libarchive-2/libarchive/archive_read_extract.c b/contrib/libarchive-2/libarchive/archive_read_extract.c index bb5add7bbd..ab01f7df3e 100644 --- a/contrib/libarchive-2/libarchive/archive_read_extract.c +++ b/contrib/libarchive-2/libarchive/archive_read_extract.c @@ -82,34 +82,40 @@ get_extract(struct archive_read *a) int archive_read_extract(struct archive *_a, struct archive_entry *entry, int flags) { - struct archive_read *a = (struct archive_read *)_a; struct extract *extract; - int r, r2; - extract = get_extract(a); + extract = get_extract((struct archive_read *)_a); if (extract == NULL) return (ARCHIVE_FATAL); + archive_write_disk_set_options(extract->ad, flags); + return (archive_read_extract2(_a, entry, extract->ad)); +} + +int +archive_read_extract2(struct archive *_a, struct archive_entry *entry, + struct archive *ad) +{ + struct archive_read *a = (struct archive_read *)_a; + int r, r2; /* Set up for this particular entry. */ - extract = a->extract; - archive_write_disk_set_options(a->extract->ad, flags); - archive_write_disk_set_skip_file(a->extract->ad, + archive_write_disk_set_skip_file(ad, a->skip_file_dev, a->skip_file_ino); - r = archive_write_header(a->extract->ad, entry); + r = archive_write_header(ad, entry); if (r < ARCHIVE_WARN) r = ARCHIVE_WARN; if (r != ARCHIVE_OK) /* If _write_header failed, copy the error. */ - archive_copy_error(&a->archive, extract->ad); + archive_copy_error(&a->archive, ad); else /* Otherwise, pour data into the entry. */ - r = copy_data(_a, a->extract->ad); - r2 = archive_write_finish_entry(a->extract->ad); + r = copy_data(_a, ad); + r2 = archive_write_finish_entry(ad); if (r2 < ARCHIVE_WARN) r2 = ARCHIVE_WARN; /* Use the first message. */ if (r2 != ARCHIVE_OK && r == ARCHIVE_OK) - archive_copy_error(&a->archive, extract->ad); + archive_copy_error(&a->archive, ad); /* Use the worst error return. */ if (r2 < r) r = r2; diff --git a/contrib/libarchive-2/libarchive/archive_read_private.h b/contrib/libarchive-2/libarchive/archive_read_private.h index 90fb7db12e..f4d0274b50 100644 --- a/contrib/libarchive-2/libarchive/archive_read_private.h +++ b/contrib/libarchive-2/libarchive/archive_read_private.h @@ -22,7 +22,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/lib/libarchive/archive_read_private.h,v 1.4 2008/01/03 17:54:26 des Exp $ + * $FreeBSD: src/lib/libarchive/archive_read_private.h,v 1.6 2008/03/15 11:09:16 kientzle Exp $ */ #ifndef ARCHIVE_READ_PRIVATE_H_INCLUDED @@ -41,10 +41,6 @@ struct archive_read { dev_t skip_file_dev; ino_t skip_file_ino; - /* Utility: Pointer to a block of nulls. */ - const unsigned char *nulls; - size_t null_length; - /* * Used by archive_read_data() to track blocks and copy * data to client buffers, filling gaps with zero bytes. @@ -58,30 +54,9 @@ struct archive_read { archive_open_callback *client_opener; archive_read_callback *client_reader; archive_skip_callback *client_skipper; - archive_write_callback *client_writer; archive_close_callback *client_closer; void *client_data; - /* - * Blocking information. Note that bytes_in_last_block is - * misleadingly named; I should find a better name. These - * control the final output from all compressors, including - * compression_none. - */ - int bytes_per_block; - int bytes_in_last_block; - - /* - * These control whether data within a gzip/bzip2 compressed - * stream gets padded or not. If pad_uncompressed is set, - * the data will be padded to a full block before being - * compressed. The pad_uncompressed_byte determines the value - * that will be used for padding. Note that these have no - * effect on compression "none." - */ - int pad_uncompressed; - int pad_uncompressed_byte; /* TODO: Support this. */ - /* File offset of beginning of most recently-read header. */ off_t header_position; @@ -118,17 +93,10 @@ struct archive_read { /* * Format detection is mostly the same as compression - * detection, with two significant differences: The bidders + * detection, with one significant difference: The bidders * use the read_ahead calls above to examine the stream rather * than having the supervisor hand them a block of data to - * examine, and the auction is repeated for every header. - * Winning bidders should set the archive_format and - * archive_format_name appropriately. Bid routines should - * check archive_format and decline to bid if the format of - * the last header was incompatible. - * - * Again, write support is considerably simpler because there's - * no need for an auction. + * examine. */ struct archive_format_descriptor { @@ -141,18 +109,6 @@ struct archive_read { } formats[8]; struct archive_format_descriptor *format; /* Active format. */ - /* - * Pointers to format-specific functions for writing. They're - * initialized by archive_write_set_format_XXX() calls. - */ - int (*format_init)(struct archive *); /* Only used on write. */ - int (*format_finish)(struct archive *); - int (*format_finish_entry)(struct archive *); - int (*format_write_header)(struct archive *, - struct archive_entry *); - ssize_t (*format_write_data)(struct archive *, - const void *buff, size_t); - /* * Various information needed by archive_extract. */ diff --git a/contrib/libarchive-2/libarchive/archive_read_support_compression_bzip2.c b/contrib/libarchive-2/libarchive/archive_read_support_compression_bzip2.c index 372eff0954..e6397df963 100644 --- a/contrib/libarchive-2/libarchive/archive_read_support_compression_bzip2.c +++ b/contrib/libarchive-2/libarchive/archive_read_support_compression_bzip2.c @@ -116,17 +116,29 @@ bid(const void *buff, size_t len) if (buffer[3] < '1' || buffer[3] > '9') return (0); bits_checked += 5; + if (len < 5) + return (bits_checked); - /* - * Research Question: Can we do any more to verify that this - * really is BZip2 format?? For 99.9% of the time, the above - * test is sufficient, but it would be nice to do a more - * thorough check. It's especially troubling that the BZip2 - * signature begins with all ASCII characters; a tar archive - * whose first filename begins with 'BZh3' would potentially - * fool this logic. (It may also be possible to guard against - * such anomalies in archive_read_support_compression_none.) - */ + /* After BZh[1-9], there must be either a data block + * which begins with 0x314159265359 or an end-of-data + * marker of 0x177245385090. */ + + if (buffer[4] == 0x31) { + /* Verify the data block signature. */ + size_t s = len; + if (s > 10) s = 10; + if (memcmp(buffer + 4, "\x31\x41\x59\x26\x53\x59", s - 4) != 0) + return (0); + bits_checked += 8 * (s - 4); + } else if (buffer[4] == 0x17) { + /* Verify the end-of-data marker. */ + size_t s = len; + if (s > 10) s = 10; + if (memcmp(buffer + 4, "\x17\x72\x45\x38\x50\x90", s - 4) != 0) + return (0); + bits_checked += 8 * (s - 4); + } else + return (0); return (bits_checked); } diff --git a/contrib/libarchive-2/libarchive/archive_read_support_compression_program.c b/contrib/libarchive-2/libarchive/archive_read_support_compression_program.c index 58b4bbddf0..206215c897 100644 --- a/contrib/libarchive-2/libarchive/archive_read_support_compression_program.c +++ b/contrib/libarchive-2/libarchive/archive_read_support_compression_program.c @@ -26,6 +26,24 @@ #include "archive_platform.h" __FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_compression_program.c,v 1.2 2007/07/20 01:28:50 kientzle Exp $"); + +/* This capability is only available on POSIX systems. */ +#if !defined(HAVE_PIPE) || !defined(HAVE_VFORK) || !defined(HAVE_FCNTL) + +/* + * On non-Posix systems, allow the program to build, but choke if + * this function is actually invoked. + */ +int +archive_read_support_compression_program(struct archive *_a, const char *cmd) +{ + archive_set_error(_a, -1, + "External compression programs not supported on this platform"); + return (ARCHIVE_FATAL); +} + +#else + #ifdef HAVE_SYS_WAIT_H # include #endif @@ -313,3 +331,5 @@ archive_decompressor_program_finish(struct archive_read *a) return (ARCHIVE_OK); } + +#endif /* !defined(HAVE_PIPE) || !defined(HAVE_VFORK) || !defined(HAVE_FCNTL) */ diff --git a/contrib/libarchive-2/libarchive/archive_read_support_format_ar.c b/contrib/libarchive-2/libarchive/archive_read_support_format_ar.c index a74791c6da..15d7e7cfd7 100644 --- a/contrib/libarchive-2/libarchive/archive_read_support_format_ar.c +++ b/contrib/libarchive-2/libarchive/archive_read_support_format_ar.c @@ -26,7 +26,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_ar.c,v 1.8 2008/02/19 05:54:24 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_ar.c,v 1.9 2008/03/12 21:10:26 kaiw Exp $"); #ifdef HAVE_SYS_STAT_H #include @@ -83,8 +83,7 @@ static int archive_read_format_ar_read_header(struct archive_read *a, struct archive_entry *e); static uint64_t ar_atol8(const char *p, unsigned char_cnt); static uint64_t ar_atol10(const char *p, unsigned char_cnt); -static int ar_parse_gnu_filename_table(struct archive_read *, struct ar *, - const void *, size_t); +static int ar_parse_gnu_filename_table(struct archive_read *a); static int ar_parse_common_header(struct ar *ar, struct archive_entry *, const char *h); @@ -167,8 +166,8 @@ archive_read_format_ar_read_header(struct archive_read *a, struct ar *ar; uint64_t number; /* Used to hold parsed numbers before validation. */ ssize_t bytes_read; - size_t bsd_name_length, entry_size; - char *p; + size_t bsd_name_length, entry_size, s; + char *p, *st; const void *b; const char *h; int r; @@ -277,22 +276,42 @@ archive_read_format_ar_read_header(struct archive_read *a, return (ARCHIVE_FATAL); } entry_size = (size_t)number; + if (entry_size == 0) { + archive_set_error(&a->archive, EINVAL, + "Invalid string table"); + return (ARCHIVE_WARN); + } + if (ar->strtab != NULL) { + archive_set_error(&a->archive, EINVAL, + "More than one string tables exist"); + return (ARCHIVE_WARN); + } + /* Read the filename table into memory. */ - bytes_read = (a->decompressor->read_ahead)(a, &b, entry_size); - if (bytes_read <= 0) - return (ARCHIVE_FATAL); - if ((size_t)bytes_read < entry_size) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Truncated input file"); + st = malloc(entry_size); + if (st == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate filename table buffer"); return (ARCHIVE_FATAL); } - /* - * Don't consume the contents, so the client will - * also get a shot at reading it. - */ + ar->strtab = st; + ar->strtab_size = entry_size; + for (s = entry_size; s > 0; s -= bytes_read) { + bytes_read = (a->decompressor->read_ahead)(a, &b, s); + if (bytes_read <= 0) + return (ARCHIVE_FATAL); + if (bytes_read > (ssize_t)s) + bytes_read = s; + memcpy(st, b, bytes_read); + st += bytes_read; + (a->decompressor->consume)(a, bytes_read); + } + /* All contents are consumed. */ + ar->entry_bytes_remaining = 0; + archive_entry_set_size(entry, ar->entry_bytes_remaining); /* Parse the filename table. */ - return (ar_parse_gnu_filename_table(a, ar, b, entry_size)); + return (ar_parse_gnu_filename_table(a)); } /* @@ -331,12 +350,16 @@ archive_read_format_ar_read_header(struct archive_read *a, /* Parse the size of the name, adjust the file size. */ number = ar_atol10(h + AR_name_offset + 3, AR_name_size - 3); - if ((off_t)number > ar->entry_bytes_remaining) { + bsd_name_length = (size_t)number; + /* Guard against the filename + trailing NUL + * overflowing a size_t and against the filename size + * being larger than the entire entry. */ + if (number > (uint64_t)(bsd_name_length + 1) + || (off_t)bsd_name_length > ar->entry_bytes_remaining) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Bad input file size"); return (ARCHIVE_FATAL); } - bsd_name_length = (size_t)number; ar->entry_bytes_remaining -= bsd_name_length; /* Adjust file size reported to client. */ archive_entry_set_size(entry, ar->entry_bytes_remaining); @@ -492,31 +515,15 @@ archive_read_format_ar_skip(struct archive_read *a) } static int -ar_parse_gnu_filename_table(struct archive_read *a, struct ar *ar, - const void *h, size_t size) +ar_parse_gnu_filename_table(struct archive_read *a) { + struct ar *ar; char *p; + size_t size; - if (ar->strtab != NULL) { - archive_set_error(&a->archive, EINVAL, - "More than one string tables exist"); - return (ARCHIVE_WARN); - } - - if (size == 0) { - archive_set_error(&a->archive, EINVAL, "Invalid string table"); - return (ARCHIVE_WARN); - } - - ar->strtab_size = size; - ar->strtab = malloc(size); - if (ar->strtab == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate string table buffer"); - return (ARCHIVE_FATAL); - } + ar = (struct ar*)(a->format->data); + size = ar->strtab_size; - (void)memcpy(ar->strtab, h, size); for (p = ar->strtab; p < ar->strtab + size - 1; ++p) { if (*p == '/') { *p++ = '\0'; diff --git a/contrib/libarchive-2/libarchive/archive_read_support_format_iso9660.c b/contrib/libarchive-2/libarchive/archive_read_support_format_iso9660.c index d333f0ccb4..e0825a36e1 100644 --- a/contrib/libarchive-2/libarchive/archive_read_support_format_iso9660.c +++ b/contrib/libarchive-2/libarchive/archive_read_support_format_iso9660.c @@ -595,8 +595,11 @@ add_entry(struct iso9660 *iso9660, struct file_info *file) struct file_info **new_pending_files; int new_size = iso9660->pending_files_allocated * 2; - if (new_size < 1024) + if (iso9660->pending_files_allocated < 1024) new_size = 1024; + /* Overflow might keep us from growing the list. */ + if (new_size <= iso9660->pending_files_allocated) + __archive_errx(1, "Out of memory"); new_pending_files = (struct file_info **)malloc(new_size * sizeof(new_pending_files[0])); if (new_pending_files == NULL) __archive_errx(1, "Out of memory"); @@ -908,6 +911,11 @@ fprintf(stderr, " *** Discarding CE data.\n"); file->ce_size = 0; } + /* Don't waste time seeking for zero-length bodies. */ + if (file->size == 0) { + file->offset = iso9660->current_position; + } + /* If CE exists, find and read it now. */ if (file->ce_offset > 0) offset = file->ce_offset; @@ -1041,51 +1049,22 @@ isodate17(const unsigned char *v) return (time_from_tm(&tm)); } -/* - * timegm() converts a struct tm to a time_t, except it isn't standard, - * so I provide my own function here that (ideally) is just a wrapper - * for timegm(). - */ static time_t time_from_tm(struct tm *t) { #if HAVE_TIMEGM + /* Use platform timegm() if available. */ return (timegm(t)); -#elif HAVE_STRUCT_TM_TM_GMTOFF - /* - * Unfortunately, timegm() isn't standard. The standard - * mktime() function is a close match, except that it uses - * local timezone instead of GMT. You can compensate for - * this by adding the timezone and DST offsets back in, at - * the cost of two calls to mktime(). - */ - mktime(t); /* Normalize the time and get the TZ offset. */ - t->tm_sec += t->tm_gmtoff; /* Try to adjust for the timezone and DST.*/ - if (t->tm_isdst) - t->tm_hour -= 1; - return (mktime(t)); /* Re-convert. */ -#elif defined(HAVE_SETENV) && defined(HAVE_UNSETENV) && defined(HAVE_TZSET) - /* No timegm() and no tm_gmtoff, let's try forcing mktime() to UTC. */ - time_t ret; - char *tz; - - /* Reset the timezone, remember the old one. */ - tz = getenv("TZ"); - setenv("TZ", "UTC 0", 1); - tzset(); - - ret = mktime(t); - - /* Restore the previous timezone. */ - if (tz) - setenv("TZ", tz, 1); - else - unsetenv("TZ"); - tzset(); - return ret; #else - /* We have no choice but to use localtime instead of UTC. */ - return (mktime(t)); + /* Else use direct calculation using POSIX assumptions. */ + /* First, fix up tm_yday based on the year/month/day. */ + mktime(t); + /* Then we can compute timegm() from first principles. */ + return (t->tm_sec + t->tm_min * 60 + t->tm_hour * 3600 + + t->tm_yday * 86400 + (t->tm_year - 70) * 31536000 + + ((t->tm_year - 69) / 4) * 86400 - + ((t->tm_year - 1) / 100) * 86400 + + ((t->tm_year + 299) / 400) * 86400); #endif } diff --git a/contrib/libarchive-2/libarchive/archive_read_support_format_mtree.c b/contrib/libarchive-2/libarchive/archive_read_support_format_mtree.c index 7db6db3377..72232ed7e0 100644 --- a/contrib/libarchive-2/libarchive/archive_read_support_format_mtree.c +++ b/contrib/libarchive-2/libarchive/archive_read_support_format_mtree.c @@ -1,5 +1,6 @@ /*- * Copyright (c) 2003-2007 Tim Kientzle + * Copyright (c) 2008 Joerg Sonnenberger * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,7 +25,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_mtree.c,v 1.2 2008/02/19 06:07:10 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_mtree.c,v 1.5 2008/05/19 18:06:48 cperciva Exp $"); #ifdef HAVE_SYS_STAT_H #include @@ -54,11 +55,29 @@ __FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_mtree.c,v 1.2 #define O_BINARY 0 #endif +#define MTREE_HAS_DEVICE 0x0001 +#define MTREE_HAS_FFLAGS 0x0002 +#define MTREE_HAS_GID 0x0004 +#define MTREE_HAS_GNAME 0x0008 +#define MTREE_HAS_MTIME 0x0010 +#define MTREE_HAS_NLINK 0x0020 +#define MTREE_HAS_PERM 0x0040 +#define MTREE_HAS_SIZE 0x0080 +#define MTREE_HAS_TYPE 0x0100 +#define MTREE_HAS_UID 0x0200 +#define MTREE_HAS_UNAME 0x0400 + +#define MTREE_HAS_OPTIONAL 0x0800 + +struct mtree_option { + struct mtree_option *next; + char *value; +}; + struct mtree_entry { struct mtree_entry *next; + struct mtree_option *options; char *name; - char *option_start; - char *option_end; char full; char used; }; @@ -76,13 +95,21 @@ struct mtree { struct mtree_entry *this_entry; struct archive_string current_dir; struct archive_string contents_name; + + struct archive_entry_linkresolver *resolver; + + off_t cur_size, cur_offset; }; static int cleanup(struct archive_read *); static int mtree_bid(struct archive_read *); +static int parse_file(struct archive_read *, struct archive_entry *, + struct mtree *, struct mtree_entry *, int *); static void parse_escapes(char *, struct mtree_entry *); -static int parse_setting(struct archive_read *, struct mtree *, - struct archive_entry *, char *, char *); +static int parse_line(struct archive_read *, struct archive_entry *, + struct mtree *, struct mtree_entry *, int *); +static int parse_keyword(struct archive_read *, struct mtree *, + struct archive_entry *, struct mtree_option *, int *); static int read_data(struct archive_read *a, const void **buff, size_t *size, off_t *offset); static ssize_t readline(struct archive_read *, struct mtree *, char **, ssize_t); @@ -91,6 +118,19 @@ static int read_header(struct archive_read *, struct archive_entry *); static int64_t mtree_atol10(char **); static int64_t mtree_atol8(char **); +static int64_t mtree_atol(char **); + +static void +free_options(struct mtree_option *head) +{ + struct mtree_option *next; + + for (; head != NULL; head = next) { + next = head->next; + free(head->value); + free(head); + } +} int archive_read_support_format_mtree(struct archive *_a) @@ -123,21 +163,20 @@ cleanup(struct archive_read *a) struct mtree_entry *p, *q; mtree = (struct mtree *)(a->format->data); + p = mtree->entries; while (p != NULL) { q = p->next; free(p->name); - /* - * Note: option_start, option_end are pointers into - * the block that p->name points to. So we should - * not try to free them! - */ + free_options(p->options); free(p); p = q; } archive_string_free(&mtree->line); archive_string_free(&mtree->current_dir); archive_string_free(&mtree->contents_name); + archive_entry_linkresolver_free(mtree->resolver); + free(mtree->buff); free(mtree); (a->format->data) = NULL; @@ -178,21 +217,205 @@ mtree_bid(struct archive_read *a) /* * The extended mtree format permits multiple lines specifying - * attributes for each file. Practically speaking, that means we have + * attributes for each file. For those entries, only the last line + * is actually used. Practically speaking, that means we have * to read the entire mtree file into memory up front. + * + * The parsing is done in two steps. First, it is decided if a line + * changes the global defaults and if it is, processed accordingly. + * Otherwise, the options of the line are merged with the current + * global options. */ +static int +add_option(struct archive_read *a, struct mtree_option **global, + const char *value, size_t len) +{ + struct mtree_option *option; + + if ((option = malloc(sizeof(*option))) == NULL) { + archive_set_error(&a->archive, errno, "Can't allocate memory"); + return (ARCHIVE_FATAL); + } + if ((option->value = malloc(len + 1)) == NULL) { + free(option); + archive_set_error(&a->archive, errno, "Can't allocate memory"); + return (ARCHIVE_FATAL); + } + memcpy(option->value, value, len); + option->value[len] = '\0'; + option->next = *global; + *global = option; + return (ARCHIVE_OK); +} + +static void +remove_option(struct mtree_option **global, const char *value, size_t len) +{ + struct mtree_option *iter, *last; + + last = NULL; + for (iter = *global; iter != NULL; last = iter, iter = iter->next) { + if (strncmp(iter->value, value, len) == 0 && + (iter->value[len] == '\0' || + iter->value[len] == '=')) + break; + } + if (iter == NULL) + return; + if (last == NULL) + *global = iter->next; + else + last->next = iter->next; + + free(iter->value); + free(iter); +} + +static int +process_global_set(struct archive_read *a, + struct mtree_option **global, const char *line) +{ + const char *next, *eq; + size_t len; + int r; + + line += 4; + for (;;) { + next = line + strspn(line, " \t\r\n"); + if (*next == '\0') + return (ARCHIVE_OK); + line = next; + next = line + strcspn(line, " \t\r\n"); + eq = strchr(line, '='); + if (eq > next) + len = next - line; + else + len = eq - line; + + remove_option(global, line, len); + r = add_option(a, global, line, next - line); + if (r != ARCHIVE_OK) + return (r); + line = next; + } +} + +static int +process_global_unset(struct archive_read *a, + struct mtree_option **global, const char *line) +{ + const char *next; + size_t len; + + line += 6; + if ((next = strchr(line, '=')) != NULL) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, + "/unset shall not contain `='"); + return ARCHIVE_FATAL; + } + + for (;;) { + next = line + strspn(line, " \t\r\n"); + if (*next == '\0') + return (ARCHIVE_OK); + line = next; + len = strcspn(line, " \t\r\n"); + + if (len == 3 && strncmp(line, "all", 3) == 0) { + free_options(*global); + *global = NULL; + } else { + remove_option(global, line, len); + } + + line += len; + } +} + +static int +process_add_entry(struct archive_read *a, struct mtree *mtree, + struct mtree_option **global, const char *line, + struct mtree_entry **last_entry) +{ + struct mtree_entry *entry; + struct mtree_option *iter; + const char *next, *eq; + size_t len; + int r; + + if ((entry = malloc(sizeof(*entry))) == NULL) { + archive_set_error(&a->archive, errno, "Can't allocate memory"); + return (ARCHIVE_FATAL); + } + entry->next = NULL; + entry->options = NULL; + entry->name = NULL; + entry->used = 0; + entry->full = 0; + + /* Add this entry to list. */ + if (*last_entry == NULL) + mtree->entries = entry; + else + (*last_entry)->next = entry; + *last_entry = entry; + + len = strcspn(line, " \t\r\n"); + if ((entry->name = malloc(len + 1)) == NULL) { + archive_set_error(&a->archive, errno, "Can't allocate memory"); + return (ARCHIVE_FATAL); + } + + memcpy(entry->name, line, len); + entry->name[len] = '\0'; + parse_escapes(entry->name, entry); + + line += len; + for (iter = *global; iter != NULL; iter = iter->next) { + r = add_option(a, &entry->options, iter->value, + strlen(iter->value)); + if (r != ARCHIVE_OK) + return (r); + } + + for (;;) { + next = line + strspn(line, " \t\r\n"); + if (*next == '\0') + return (ARCHIVE_OK); + line = next; + next = line + strcspn(line, " \t\r\n"); + eq = strchr(line, '='); + if (eq > next) + len = next - line; + else + len = eq - line; + + remove_option(&entry->options, line, len); + r = add_option(a, &entry->options, line, next - line); + if (r != ARCHIVE_OK) + return (r); + line = next; + } +} + static int read_mtree(struct archive_read *a, struct mtree *mtree) { ssize_t len; + uintmax_t counter; char *p; - struct mtree_entry *mentry; - struct mtree_entry *last_mentry = NULL; + struct mtree_option *global; + struct mtree_entry *last_entry; + int r; mtree->archive_format = ARCHIVE_FORMAT_MTREE_V1; mtree->archive_format_name = "mtree"; - for (;;) { + global = NULL; + last_entry = NULL; + r = ARCHIVE_OK; + + for (counter = 1; ; ++counter) { len = readline(a, mtree, &p, 256); if (len == 0) { mtree->this_entry = mtree->entries; @@ -210,56 +433,39 @@ read_mtree(struct archive_read *a, struct mtree *mtree) continue; if (*p == '\r' || *p == '\n' || *p == '\0') continue; - mentry = malloc(sizeof(*mentry)); - if (mentry == NULL) { - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory"); - return (ARCHIVE_FATAL); - } - memset(mentry, 0, sizeof(*mentry)); - /* Add this entry to list. */ - if (last_mentry == NULL) { - last_mentry = mtree->entries = mentry; - } else { - last_mentry->next = mentry; - } - last_mentry = mentry; + if (*p != '/') { + r = process_add_entry(a, mtree, &global, p, + &last_entry); + } else if (strncmp(p, "/set", 4) == 0) { + if (p[4] != ' ' && p[4] != '\t') + break; + r = process_global_set(a, &global, p); + } else if (strncmp(p, "/unset", 6) == 0) { + if (p[6] != ' ' && p[6] != '\t') + break; + r = process_global_unset(a, &global, p); + } else + break; - /* Copy line over onto heap. */ - mentry->name = malloc(len + 1); - if (mentry->name == NULL) { - free(mentry); - archive_set_error(&a->archive, ENOMEM, - "Can't allocate memory"); - return (ARCHIVE_FATAL); - } - strcpy(mentry->name, p); - mentry->option_end = mentry->name + len; - /* Find end of name. */ - p = mentry->name; - while (*p != ' ' && *p != '\n' && *p != '\0') - ++p; - *p++ = '\0'; - parse_escapes(mentry->name, mentry); - /* Find start of options and record it. */ - while (p < mentry->option_end && (*p == ' ' || *p == '\t')) - ++p; - mentry->option_start = p; - /* Null terminate each separate option. */ - while (++p < mentry->option_end) - if (*p == ' ' || *p == '\t' || *p == '\n') - *p = '\0'; + if (r != ARCHIVE_OK) + return r; } + + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Can't parse line %ju", counter); + return ARCHIVE_FATAL; } +/* + * Read in the entire mtree file into memory on the first request. + * Then use the next unused file to satisfy each header request. + */ static int read_header(struct archive_read *a, struct archive_entry *entry) { - struct stat st; struct mtree *mtree; - struct mtree_entry *mentry, *mentry2; - char *p, *q; - int r = ARCHIVE_OK, r1; + char *p; + int r, use_next; mtree = (struct mtree *)(a->format->data); @@ -269,6 +475,11 @@ read_header(struct archive_read *a, struct archive_entry *entry) } if (mtree->entries == NULL) { + mtree->resolver = archive_entry_linkresolver_new(); + if (mtree->resolver == NULL) + return ARCHIVE_FATAL; + archive_entry_linkresolver_set_strategy(mtree->resolver, + ARCHIVE_FORMAT_MTREE); r = read_mtree(a, mtree); if (r != ARCHIVE_OK) return (r); @@ -278,16 +489,10 @@ read_header(struct archive_read *a, struct archive_entry *entry) a->archive.archive_format_name = mtree->archive_format_name; for (;;) { - mentry = mtree->this_entry; - if (mentry == NULL) { - mtree->this_entry = NULL; + if (mtree->this_entry == NULL) return (ARCHIVE_EOF); - } - mtree->this_entry = mentry->next; - if (mentry->used) - continue; - mentry->used = 1; - if (strcmp(mentry->name, "..") == 0) { + if (strcmp(mtree->this_entry->name, "..") == 0) { + mtree->this_entry->used = 1; if (archive_strlen(&mtree->current_dir) > 0) { /* Roll back current path. */ p = mtree->current_dir.s @@ -299,122 +504,299 @@ read_header(struct archive_read *a, struct archive_entry *entry) mtree->current_dir.length = p - mtree->current_dir.s + 1; } - continue; } + if (!mtree->this_entry->used) { + use_next = 0; + r = parse_file(a, entry, mtree, mtree->this_entry, &use_next); + if (use_next == 0) + return (r); + } + mtree->this_entry = mtree->this_entry->next; + } +} - mtree->filetype = AE_IFREG; +/* + * A single file can have multiple lines contribute specifications. + * Parse as many lines as necessary, then pull additional information + * from a backing file on disk as necessary. + */ +static int +parse_file(struct archive_read *a, struct archive_entry *entry, + struct mtree *mtree, struct mtree_entry *mentry, int *use_next) +{ + const char *path; + struct stat st_storage, *st; + struct mtree_entry *mp; + struct archive_entry *sparse_entry; + int r = ARCHIVE_OK, r1, parsed_kws, mismatched_type; - /* Parse options. */ - p = mentry->option_start; - while (p < mentry->option_end) { - q = p + strlen(p); - r1 = parse_setting(a, mtree, entry, p, q); - if (r1 != ARCHIVE_OK) - r = r1; - p = q + 1; - } + mentry->used = 1; - if (mentry->full) { - archive_entry_copy_pathname(entry, mentry->name); - /* - * "Full" entries are allowed to have multiple - * lines and those lines aren't required to be - * adjacent. We don't support multiple lines - * for "relative" entries nor do we make any - * attempt to merge data from separate - * "relative" and "full" entries. (Merging - * "relative" and "full" entries would require - * dealing with pathname canonicalization, - * which is a very tricky subject.) - */ - mentry2 = mentry->next; - while (mentry2 != NULL) { - if (mentry2->full - && !mentry2->used - && strcmp(mentry->name, mentry2->name) == 0) { - /* - * Add those options as well; - * later lines override - * earlier ones. - */ - p = mentry2->option_start; - while (p < mentry2->option_end) { - q = p + strlen(p); - r1 = parse_setting(a, mtree, entry, p, q); - if (r1 != ARCHIVE_OK) - r = r1; - p = q + 1; - } - mentry2->used = 1; - } - mentry2 = mentry2->next; + /* Initialize reasonable defaults. */ + mtree->filetype = AE_IFREG; + archive_entry_set_size(entry, 0); + + /* Parse options from this line. */ + parsed_kws = 0; + r = parse_line(a, entry, mtree, mentry, &parsed_kws); + + if (mentry->full) { + archive_entry_copy_pathname(entry, mentry->name); + /* + * "Full" entries are allowed to have multiple lines + * and those lines aren't required to be adjacent. We + * don't support multiple lines for "relative" entries + * nor do we make any attempt to merge data from + * separate "relative" and "full" entries. (Merging + * "relative" and "full" entries would require dealing + * with pathname canonicalization, which is a very + * tricky subject.) + */ + for (mp = mentry->next; mp != NULL; mp = mp->next) { + if (mp->full && !mp->used + && strcmp(mentry->name, mp->name) == 0) { + /* Later lines override earlier ones. */ + mp->used = 1; + r1 = parse_line(a, entry, mtree, mp, + &parsed_kws); + if (r1 < r) + r = r1; } - } else { - /* - * Relative entries require us to construct - * the full path and possibly update the - * current directory. - */ - size_t n = archive_strlen(&mtree->current_dir); - if (n > 0) - archive_strcat(&mtree->current_dir, "/"); - archive_strcat(&mtree->current_dir, mentry->name); - archive_entry_copy_pathname(entry, mtree->current_dir.s); - if (archive_entry_filetype(entry) != AE_IFDIR) - mtree->current_dir.length = n; } - + } else { /* - * Try to open and stat the file to get the real size. - * It would be nice to avoid this here so that getting - * a listing of an mtree wouldn't require opening - * every referenced contents file. But then we - * wouldn't know the actual contents size, so I don't - * see a really viable way around this. (Also, we may - * want to someday pull other unspecified info from - * the contents file on disk.) + * Relative entries require us to construct + * the full path and possibly update the + * current directory. */ - if (archive_strlen(&mtree->contents_name) > 0) { - mtree->fd = open(mtree->contents_name.s, - O_RDONLY | O_BINARY); - if (mtree->fd < 0) { - archive_set_error(&a->archive, errno, - "Can't open content=\"%s\"", - mtree->contents_name.s); + size_t n = archive_strlen(&mtree->current_dir); + if (n > 0) + archive_strcat(&mtree->current_dir, "/"); + archive_strcat(&mtree->current_dir, mentry->name); + archive_entry_copy_pathname(entry, mtree->current_dir.s); + if (archive_entry_filetype(entry) != AE_IFDIR) + mtree->current_dir.length = n; + } + + /* + * Try to open and stat the file to get the real size + * and other file info. It would be nice to avoid + * this here so that getting a listing of an mtree + * wouldn't require opening every referenced contents + * file. But then we wouldn't know the actual + * contents size, so I don't see a really viable way + * around this. (Also, we may want to someday pull + * other unspecified info from the contents file on + * disk.) + */ + mtree->fd = -1; + if (archive_strlen(&mtree->contents_name) > 0) + path = mtree->contents_name.s; + else + path = archive_entry_pathname(entry); + + if (archive_entry_filetype(entry) == AE_IFREG || + archive_entry_filetype(entry) == AE_IFDIR) { + mtree->fd = open(path, + O_RDONLY | O_BINARY); + if (mtree->fd == -1 && + (errno != ENOENT || + archive_strlen(&mtree->contents_name) > 0)) { + archive_set_error(&a->archive, errno, + "Can't open %s", path); + r = ARCHIVE_WARN; + } + } + + st = &st_storage; + if (mtree->fd >= 0) { + if (fstat(mtree->fd, st) == -1) { + archive_set_error(&a->archive, errno, + "Could not fstat %s", path); + r = ARCHIVE_WARN; + /* If we can't stat it, don't keep it open. */ + close(mtree->fd); + mtree->fd = -1; + st = NULL; + } + } else if (lstat(path, st) == -1) { + st = NULL; + } + + /* + * If there is a contents file on disk, use that size; + * otherwise leave it as-is (it might have been set from + * the mtree size= keyword). + */ + if (st != NULL) { + mismatched_type = 0; + if ((st->st_mode & S_IFMT) == S_IFREG && + archive_entry_filetype(entry) != AE_IFREG) + mismatched_type = 1; + if ((st->st_mode & S_IFMT) == S_IFLNK && + archive_entry_filetype(entry) != AE_IFLNK) + mismatched_type = 1; + if ((st->st_mode & S_IFSOCK) == S_IFSOCK && + archive_entry_filetype(entry) != AE_IFSOCK) + mismatched_type = 1; + if ((st->st_mode & S_IFMT) == S_IFCHR && + archive_entry_filetype(entry) != AE_IFCHR) + mismatched_type = 1; + if ((st->st_mode & S_IFMT) == S_IFBLK && + archive_entry_filetype(entry) != AE_IFBLK) + mismatched_type = 1; + if ((st->st_mode & S_IFMT) == S_IFDIR && + archive_entry_filetype(entry) != AE_IFDIR) + mismatched_type = 1; + if ((st->st_mode & S_IFMT) == S_IFIFO && + archive_entry_filetype(entry) != AE_IFIFO) + mismatched_type = 1; + + if (mismatched_type) { + if ((parsed_kws & MTREE_HAS_OPTIONAL) == 0) { + archive_set_error(&a->archive, + ARCHIVE_ERRNO_MISC, + "mtree specification has different type for %s", + archive_entry_pathname(entry)); r = ARCHIVE_WARN; + } else { + *use_next = 1; } - } else { - /* If the specified path opens, use it. */ - mtree->fd = open(mtree->current_dir.s, - O_RDONLY | O_BINARY); - /* But don't fail if it's not there. */ + /* Don't hold a non-regular file open. */ + close(mtree->fd); + mtree->fd = -1; + st = NULL; + return r; } + } - /* - * If there is a contents file on disk, use that size; - * otherwise leave it as-is (it might have been set from - * the mtree size= keyword). - */ - if (mtree->fd >= 0) { - fstat(mtree->fd, &st); - archive_entry_set_size(entry, st.st_size); + if (st != NULL) { + if ((parsed_kws & MTREE_HAS_DEVICE) == 0 && + (archive_entry_filetype(entry) == AE_IFCHR || + archive_entry_filetype(entry) == AE_IFBLK)) + archive_entry_set_rdev(entry, st->st_rdev); + if ((parsed_kws & (MTREE_HAS_GID | MTREE_HAS_GNAME)) == 0) + archive_entry_set_gid(entry, st->st_gid); + if ((parsed_kws & (MTREE_HAS_UID | MTREE_HAS_UNAME)) == 0) + archive_entry_set_uid(entry, st->st_uid); + if ((parsed_kws & MTREE_HAS_MTIME) == 0) { +#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC + archive_entry_set_mtime(entry, st->st_mtime, + st->st_mtimespec.tv_nsec); +#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC + archive_entry_set_mtime(entry, st->st_mtime, + st->st_mtim.tv_nsec); +#else + archive_entry_set_mtime(entry, st->st_mtime, 0); +#endif } + if ((parsed_kws & MTREE_HAS_NLINK) == 0) + archive_entry_set_nlink(entry, st->st_nlink); + if ((parsed_kws & MTREE_HAS_PERM) == 0) + archive_entry_set_perm(entry, st->st_mode); + if ((parsed_kws & MTREE_HAS_SIZE) == 0) + archive_entry_set_size(entry, st->st_size); + archive_entry_set_ino(entry, st->st_ino); + archive_entry_set_dev(entry, st->st_dev); - return r; + archive_entry_linkify(mtree->resolver, &entry, &sparse_entry); + } else if (parsed_kws & MTREE_HAS_OPTIONAL) { + /* + * Couldn't open the entry, stat it or the on-disk type + * didn't match. If this entry is optional, just ignore it + * and read the next header entry. + */ + *use_next = 1; + return ARCHIVE_OK; } + + mtree->cur_size = archive_entry_size(entry); + mtree->offset = 0; + + return r; } +/* + * Each line contains a sequence of keywords. + */ static int -parse_setting(struct archive_read *a, struct mtree *mtree, struct archive_entry *entry, char *key, char *end) +parse_line(struct archive_read *a, struct archive_entry *entry, + struct mtree *mtree, struct mtree_entry *mp, int *parsed_kws) { - char *val; + struct mtree_option *iter; + int r = ARCHIVE_OK, r1; + for (iter = mp->options; iter != NULL; iter = iter->next) { + r1 = parse_keyword(a, mtree, entry, iter, parsed_kws); + if (r1 < r) + r = r1; + } + if ((*parsed_kws & MTREE_HAS_TYPE) == 0) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, + "Missing type keyword in mtree specification"); + return (ARCHIVE_WARN); + } + return (r); +} + +/* + * Device entries have one of the following forms: + * raw dev_t + * format,major,minor[,subdevice] + * + * Just use major and minor, no translation etc is done + * between formats. + */ +static int +parse_device(struct archive *a, struct archive_entry *entry, char *val) +{ + char *comma1, *comma2; - if (end == key) + comma1 = strchr(val, ','); + if (comma1 == NULL) { + archive_entry_set_dev(entry, mtree_atol10(&val)); return (ARCHIVE_OK); + } + ++comma1; + comma2 = strchr(comma1, ','); + if (comma1 == NULL) { + archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT, + "Malformed device attribute"); + return (ARCHIVE_WARN); + } + ++comma2; + archive_entry_set_rdevmajor(entry, mtree_atol(&comma1)); + archive_entry_set_rdevminor(entry, mtree_atol(&comma2)); + return (ARCHIVE_OK); +} + +/* + * Parse a single keyword and its value. + */ +static int +parse_keyword(struct archive_read *a, struct mtree *mtree, + struct archive_entry *entry, struct mtree_option *option, int *parsed_kws) +{ + char *val, *key; + + key = option->value; + if (*key == '\0') return (ARCHIVE_OK); + if (strcmp(key, "optional") == 0) { + *parsed_kws |= MTREE_HAS_OPTIONAL; + return (ARCHIVE_OK); + } + if (strcmp(key, "ignore") == 0) { + /* + * The mtree processing is not recursive, so + * recursion will only happen for explicitly listed + * entries. + */ + return (ARCHIVE_OK); + } + val = strchr(key, '='); if (val == NULL) { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, @@ -427,33 +809,99 @@ parse_setting(struct archive_read *a, struct mtree *mtree, struct archive_entry switch (key[0]) { case 'c': - if (strcmp(key, "content") == 0) { + if (strcmp(key, "content") == 0 + || strcmp(key, "contents") == 0) { parse_escapes(val, NULL); archive_strcpy(&mtree->contents_name, val); break; } + if (strcmp(key, "cksum") == 0) + break; + case 'd': + if (strcmp(key, "device") == 0) { + *parsed_kws |= MTREE_HAS_DEVICE; + return parse_device(&a->archive, entry, val); + } + case 'f': + if (strcmp(key, "flags") == 0) { + *parsed_kws |= MTREE_HAS_FFLAGS; + archive_entry_copy_fflags_text(entry, val); + break; + } case 'g': if (strcmp(key, "gid") == 0) { + *parsed_kws |= MTREE_HAS_GID; archive_entry_set_gid(entry, mtree_atol10(&val)); break; } if (strcmp(key, "gname") == 0) { + *parsed_kws |= MTREE_HAS_GNAME; archive_entry_copy_gname(entry, val); break; } + case 'l': + if (strcmp(key, "link") == 0) { + archive_entry_copy_symlink(entry, val); + break; + } case 'm': + if (strcmp(key, "md5") == 0 || strcmp(key, "md5digest") == 0) + break; if (strcmp(key, "mode") == 0) { - if (val[0] == '0') { + if (val[0] >= '0' && val[0] <= '9') { + *parsed_kws |= MTREE_HAS_PERM; archive_entry_set_perm(entry, mtree_atol8(&val)); - } else + } else { archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "Symbolic mode \"%s\" unsupported", val); + return ARCHIVE_WARN; + } + break; + } + case 'n': + if (strcmp(key, "nlink") == 0) { + *parsed_kws |= MTREE_HAS_NLINK; + archive_entry_set_nlink(entry, mtree_atol10(&val)); + break; + } + case 'r': + if (strcmp(key, "rmd160") == 0 || + strcmp(key, "rmd160digest") == 0) + break; + case 's': + if (strcmp(key, "sha1") == 0 || strcmp(key, "sha1digest") == 0) + break; + if (strcmp(key, "sha256") == 0 || + strcmp(key, "sha256digest") == 0) + break; + if (strcmp(key, "sha384") == 0 || + strcmp(key, "sha384digest") == 0) + break; + if (strcmp(key, "sha512") == 0 || + strcmp(key, "sha512digest") == 0) + break; + if (strcmp(key, "size") == 0) { + archive_entry_set_size(entry, mtree_atol10(&val)); break; } case 't': + if (strcmp(key, "tags") == 0) { + /* + * Comma delimited list of tags. + * Ignore the tags for now, but the interface + * should be extended to allow inclusion/exclusion. + */ + break; + } + if (strcmp(key, "time") == 0) { + *parsed_kws |= MTREE_HAS_MTIME; + archive_entry_set_mtime(entry, mtree_atol10(&val), 0); + break; + } if (strcmp(key, "type") == 0) { + *parsed_kws |= MTREE_HAS_TYPE; switch (val[0]) { case 'b': if (strcmp(val, "block") == 0) { @@ -493,16 +941,14 @@ parse_setting(struct archive_read *a, struct mtree *mtree, struct archive_entry archive_entry_set_filetype(entry, mtree->filetype); break; } - if (strcmp(key, "time") == 0) { - archive_entry_set_mtime(entry, mtree_atol10(&val), 0); - break; - } case 'u': if (strcmp(key, "uid") == 0) { + *parsed_kws |= MTREE_HAS_UID; archive_entry_set_uid(entry, mtree_atol10(&val)); break; } if (strcmp(key, "uname") == 0) { + *parsed_kws |= MTREE_HAS_UNAME; archive_entry_copy_uname(entry, val); break; } @@ -517,6 +963,7 @@ parse_setting(struct archive_read *a, struct mtree *mtree, struct archive_entry static int read_data(struct archive_read *a, const void **buff, size_t *size, off_t *offset) { + size_t bytes_to_read; ssize_t bytes_read; struct mtree *mtree; @@ -534,11 +981,16 @@ read_data(struct archive_read *a, const void **buff, size_t *size, off_t *offset archive_set_error(&a->archive, ENOMEM, "Can't allocate memory"); } + return (ARCHIVE_FATAL); } *buff = mtree->buff; *offset = mtree->offset; - bytes_read = read(mtree->fd, mtree->buff, mtree->buffsize); + if ((off_t)mtree->buffsize > mtree->cur_size - mtree->offset) + bytes_to_read = mtree->cur_size - mtree->offset; + else + bytes_to_read = mtree->buffsize; + bytes_read = read(mtree->fd, mtree->buff, bytes_to_read); if (bytes_read < 0) { archive_set_error(&a->archive, errno, "Can't read"); return (ARCHIVE_WARN); @@ -548,7 +1000,7 @@ read_data(struct archive_read *a, const void **buff, size_t *size, off_t *offset return (ARCHIVE_EOF); } mtree->offset += bytes_read; - *size = (size_t)bytes_read; + *size = bytes_read; return (ARCHIVE_OK); } @@ -576,6 +1028,13 @@ parse_escapes(char *src, struct mtree_entry *mentry) char *dest = src; char c; + /* + * The current directory is somewhat special, it should be archived + * only once as it will confuse extraction otherwise. + */ + if (strcmp(src, ".") == 0) + mentry->full = 1; + while (*src != '\0') { c = *src++; if (c == '/' && mentry != NULL) @@ -657,6 +1116,66 @@ mtree_atol10(char **p) return (sign < 0) ? -l : l; } +/* + * Note that this implementation does not (and should not!) obey + * locale settings; you cannot simply substitute strtol here, since + * it does obey locale. + */ +static int64_t +mtree_atol16(char **p) +{ + int64_t l, limit, last_digit_limit; + int base, digit, sign; + + base = 16; + limit = INT64_MAX / base; + last_digit_limit = INT64_MAX % base; + + if (**p == '-') { + sign = -1; + ++(*p); + } else + sign = 1; + + l = 0; + if (**p >= '0' && **p <= '9') + digit = **p - '0'; + else if (**p >= 'a' && **p <= 'f') + digit = **p - 'a' + 10; + else if (**p >= 'A' && **p <= 'F') + digit = **p - 'A' + 10; + else + digit = -1; + while (digit >= 0 && digit < base) { + if (l > limit || (l == limit && digit > last_digit_limit)) { + l = UINT64_MAX; /* Truncate on overflow. */ + break; + } + l = (l * base) + digit; + if (**p >= '0' && **p <= '9') + digit = **p - '0'; + else if (**p >= 'a' && **p <= 'f') + digit = **p - 'a' + 10; + else if (**p >= 'A' && **p <= 'F') + digit = **p - 'A' + 10; + else + digit = -1; + } + return (sign < 0) ? -l : l; +} + +static int64_t +mtree_atol(char **p) +{ + if (**p != '0') + return mtree_atol10(p); + if ((*p)[1] == 'x' || (*p)[1] == 'X') { + *p += 2; + return mtree_atol16(p); + } + return mtree_atol8(p); +} + /* * Returns length of line (including trailing newline) * or negative on error. 'start' argument is updated to diff --git a/contrib/libarchive-2/libarchive/archive_read_support_format_tar.c b/contrib/libarchive-2/libarchive/archive_read_support_format_tar.c index 26b2abbe57..6d7f048a40 100644 --- a/contrib/libarchive-2/libarchive/archive_read_support_format_tar.c +++ b/contrib/libarchive-2/libarchive/archive_read_support_format_tar.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_tar.c,v 1.65 2008/01/31 07:41:45 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_tar.c,v 1.67 2008/03/15 01:43:58 kientzle Exp $"); #ifdef HAVE_ERRNO_H #include @@ -145,6 +145,8 @@ struct sparse_block { struct tar { struct archive_string acl_text; struct archive_string entry_pathname; + /* For "GNU.sparse.name" and other similar path extensions. */ + struct archive_string entry_pathname_override; struct archive_string entry_linkpath; struct archive_string entry_uname; struct archive_string entry_gname; @@ -272,6 +274,7 @@ archive_read_format_tar_cleanup(struct archive_read *a) gnu_clear_sparse_list(tar); archive_string_free(&tar->acl_text); archive_string_free(&tar->entry_pathname); + archive_string_free(&tar->entry_pathname_override); archive_string_free(&tar->entry_linkpath); archive_string_free(&tar->entry_uname); archive_string_free(&tar->entry_gname); @@ -714,7 +717,7 @@ archive_block_is_null(const unsigned char *p) { unsigned i; - for (i = 0; i < ARCHIVE_BYTES_PER_RECORD / sizeof(*p); i++) + for (i = 0; i < 512; i++) if (*p++) return (0); return (1); @@ -1174,7 +1177,6 @@ pax_header(struct archive_read *a, struct tar *tar, size_t attr_length, l, line_length; char *line, *p; char *key, *value; - wchar_t *wp; int err, err2; attr_length = strlen(attr); @@ -1182,6 +1184,7 @@ pax_header(struct archive_read *a, struct tar *tar, archive_string_empty(&(tar->entry_gname)); archive_string_empty(&(tar->entry_linkpath)); archive_string_empty(&(tar->entry_pathname)); + archive_string_empty(&(tar->entry_pathname_override)); archive_string_empty(&(tar->entry_uname)); err = ARCHIVE_OK; while (attr_length > 0) { @@ -1257,11 +1260,13 @@ pax_header(struct archive_read *a, struct tar *tar, if (tar->pax_hdrcharset_binary) archive_entry_copy_gname(entry, value); else { - wp = utf8_decode(tar, value, strlen(value)); - if (wp == NULL) - archive_entry_copy_gname(entry, value); - else - archive_entry_copy_gname_w(entry, wp); + if (!archive_entry_update_gname_utf8(entry, value)) { + err = ARCHIVE_WARN; + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Gname in pax header can't " + "be converted to current locale."); + } } } if (archive_strlen(&(tar->entry_linkpath)) > 0) { @@ -1269,23 +1274,40 @@ pax_header(struct archive_read *a, struct tar *tar, if (tar->pax_hdrcharset_binary) archive_entry_copy_link(entry, value); else { - wp = utf8_decode(tar, value, strlen(value)); - if (wp == NULL) - archive_entry_copy_link(entry, value); - else - archive_entry_copy_link_w(entry, wp); + if (!archive_entry_update_link_utf8(entry, value)) { + err = ARCHIVE_WARN; + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Linkname in pax header can't " + "be converted to current locale."); + } } } - if (archive_strlen(&(tar->entry_pathname)) > 0) { + /* + * Some extensions (such as the GNU sparse file extensions) + * deliberately store a synthetic name under the regular 'path' + * attribute and the real file name under a different attribute. + * Since we're supposed to not care about the order, we + * have no choice but to store all of the various filenames + * we find and figure it all out afterwards. This is the + * figuring out part. + */ + value = NULL; + if (archive_strlen(&(tar->entry_pathname_override)) > 0) + value = tar->entry_pathname_override.s; + else if (archive_strlen(&(tar->entry_pathname)) > 0) value = tar->entry_pathname.s; + if (value != NULL) { if (tar->pax_hdrcharset_binary) archive_entry_copy_pathname(entry, value); else { - wp = utf8_decode(tar, value, strlen(value)); - if (wp == NULL) - archive_entry_copy_pathname(entry, value); - else - archive_entry_copy_pathname_w(entry, wp); + if (!archive_entry_update_pathname_utf8(entry, value)) { + err = ARCHIVE_WARN; + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Pathname in pax header can't be " + "converted to current locale."); + } } } if (archive_strlen(&(tar->entry_uname)) > 0) { @@ -1293,11 +1315,13 @@ pax_header(struct archive_read *a, struct tar *tar, if (tar->pax_hdrcharset_binary) archive_entry_copy_uname(entry, value); else { - wp = utf8_decode(tar, value, strlen(value)); - if (wp == NULL) - archive_entry_copy_uname(entry, value); - else - archive_entry_copy_uname_w(entry, wp); + if (!archive_entry_update_uname_utf8(entry, value)) { + err = ARCHIVE_WARN; + archive_set_error(&a->archive, + ARCHIVE_ERRNO_FILE_FORMAT, + "Uname in pax header can't " + "be converted to current locale."); + } } } return (err); @@ -1407,11 +1431,13 @@ pax_attribute(struct tar *tar, struct archive_entry *entry, tar->sparse_gnu_pending = 1; } if (strcmp(key, "GNU.sparse.name") == 0) { - wp = utf8_decode(tar, value, strlen(value)); - if (wp != NULL) - archive_entry_copy_pathname_w(entry, wp); - else - archive_entry_copy_pathname(entry, value); + /* + * The real filename; when storing sparse + * files, GNU tar puts a synthesized name into + * the regular 'path' attribute in an attempt + * to limit confusion. ;-) + */ + archive_strcpy(&(tar->entry_pathname_override), value); } if (strcmp(key, "GNU.sparse.realsize") == 0) { tar->realsize = tar_atol10(value, strlen(value)); @@ -1447,9 +1473,7 @@ pax_attribute(struct tar *tar, struct archive_entry *entry, archive_entry_set_rdevminor(entry, tar_atol10(value, strlen(value))); } else if (strcmp(key, "SCHILY.fflags")==0) { - wp = utf8_decode(tar, value, strlen(value)); - /* TODO: if (wp == NULL) */ - archive_entry_copy_fflags_text_w(entry, wp); + archive_entry_copy_fflags_text(entry, value); } else if (strcmp(key, "SCHILY.dev")==0) { archive_entry_set_dev(entry, tar_atol10(value, strlen(value))); @@ -2279,7 +2303,7 @@ base64_decode(const char *s, size_t len, size_t *out_len) /* Allocate enough space to hold the entire output. */ /* Note that we may not use all of this... */ - out = (char *)malloc((len * 3 + 3) / 4); + out = (char *)malloc(len - len / 4 + 1); if (out == NULL) { *out_len = 0; return (NULL); diff --git a/contrib/libarchive-2/libarchive/archive_read_support_format_zip.c b/contrib/libarchive-2/libarchive/archive_read_support_format_zip.c index 09e7411be8..a105297ad4 100644 --- a/contrib/libarchive-2/libarchive/archive_read_support_format_zip.c +++ b/contrib/libarchive-2/libarchive/archive_read_support_format_zip.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_zip.c,v 1.21 2008/02/26 07:17:47 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_zip.c,v 1.22 2008/02/27 06:05:59 kientzle Exp $"); #ifdef HAVE_ERRNO_H #include @@ -743,7 +743,7 @@ archive_read_format_zip_read_data_skip(struct archive_read *a) { struct zip *zip; const void *buff = NULL; - ssize_t bytes_avail; + off_t bytes_skipped; zip = (struct zip *)(a->format->data); @@ -766,19 +766,10 @@ archive_read_format_zip_read_data_skip(struct archive_read *a) * If the length is at the beginning, we can skip the * compressed data much more quickly. */ - while (zip->entry_bytes_remaining > 0) { - bytes_avail = (a->decompressor->read_ahead)(a, &buff, 1); - if (bytes_avail <= 0) { - archive_set_error(&a->archive, - ARCHIVE_ERRNO_FILE_FORMAT, - "Truncated ZIP file body"); - return (ARCHIVE_FATAL); - } - if (bytes_avail > zip->entry_bytes_remaining) - bytes_avail = zip->entry_bytes_remaining; - (a->decompressor->consume)(a, bytes_avail); - zip->entry_bytes_remaining -= bytes_avail; - } + bytes_skipped = (a->decompressor->skip)(a, zip->entry_bytes_remaining); + if (bytes_skipped < 0) + return (ARCHIVE_FATAL); + /* This entry is finished and done. */ zip->end_of_entry_cleanup = zip->end_of_entry = 1; return (ARCHIVE_OK); diff --git a/contrib/libarchive-2/libarchive/archive_string.c b/contrib/libarchive-2/libarchive/archive_string.c index 7e43b360a4..7c378deead 100644 --- a/contrib/libarchive-2/libarchive/archive_string.c +++ b/contrib/libarchive-2/libarchive/archive_string.c @@ -37,6 +37,17 @@ __FBSDID("$FreeBSD: src/lib/libarchive/archive_string.c,v 1.11 2007/07/15 19:13: #ifdef HAVE_STRING_H #include #endif +#ifdef HAVE_WCHAR_H +#include +#endif + +#ifdef __sgi +/* + * The following prototype is missing on IRXI, + * even though the function is implemented in libc. + */ +size_t wcrtomb(char *, wchar_t, mbstate_t *); +#endif #include "archive_private.h" #include "archive_string.h" @@ -55,11 +66,15 @@ __archive_string_append(struct archive_string *as, const char *p, size_t s) void __archive_string_copy(struct archive_string *dest, struct archive_string *src) { - if (__archive_string_ensure(dest, src->length + 1) == NULL) - __archive_errx(1, "Out of memory"); - memcpy(dest->s, src->s, src->length); - dest->length = src->length; - dest->s[dest->length] = 0; + if (src->length == 0) + dest->length = 0; + else { + if (__archive_string_ensure(dest, src->length + 1) == NULL) + __archive_errx(1, "Out of memory"); + memcpy(dest->s, src->s, src->length); + dest->length = src->length; + dest->s[dest->length] = 0; + } } void @@ -67,21 +82,52 @@ __archive_string_free(struct archive_string *as) { as->length = 0; as->buffer_length = 0; - if (as->s != NULL) + if (as->s != NULL) { free(as->s); + as->s = NULL; + } } /* Returns NULL on any allocation failure. */ struct archive_string * __archive_string_ensure(struct archive_string *as, size_t s) { + /* If buffer is already big enough, don't reallocate. */ if (as->s && (s <= as->buffer_length)) return (as); + /* + * Growing the buffer at least exponentially ensures that + * append operations are always linear in the number of + * characters appended. Using a smaller growth rate for + * larger buffers reduces memory waste somewhat at the cost of + * a larger constant factor. + */ if (as->buffer_length < 32) + /* Start with a minimum 32-character buffer. */ as->buffer_length = 32; - while (as->buffer_length < s) + else if (as->buffer_length < 8192) + /* Buffers under 8k are doubled for speed. */ as->buffer_length *= 2; + else { + /* Buffers 8k and over grow by at least 25% each time. */ + size_t old_length = as->buffer_length; + as->buffer_length = (as->buffer_length * 5) / 4; + /* Be safe: If size wraps, release buffer and return NULL. */ + if (as->buffer_length < old_length) { + free(as->s); + as->s = NULL; + return (NULL); + } + } + /* + * The computation above is a lower limit to how much we'll + * grow the buffer. In any case, we have to grow it enough to + * hold the request. + */ + if (as->buffer_length < s) + as->buffer_length = s; + /* Now we can reallocate the buffer. */ as->s = (char *)realloc(as->s, as->buffer_length); if (as->s == NULL) return (NULL); @@ -124,3 +170,206 @@ __archive_strappend_int(struct archive_string *as, int d, int base) __archive_strappend_char(as, digits[d % base]); return (as); } + +/* + * Home-grown wcrtomb for UTF-8. + */ +static size_t +my_wcrtomb_utf8(char *p, wchar_t wc, mbstate_t *s) +{ + (void)s; /* UNUSED */ + + if (p == NULL) + return (0); + if (wc <= 0x7f) { + p[0] = (char)wc; + return (1); + } + if (wc <= 0x7ff) { + p[0] = 0xc0 | ((wc >> 6) & 0x1f); + p[1] = 0x80 | (wc & 0x3f); + return (2); + } + if (wc <= 0xffff) { + p[0] = 0xe0 | ((wc >> 12) & 0x0f); + p[1] = 0x80 | ((wc >> 6) & 0x3f); + p[2] = 0x80 | (wc & 0x3f); + return (3); + } + if (wc <= 0x1fffff) { + p[0] = 0xf0 | ((wc >> 18) & 0x07); + p[1] = 0x80 | ((wc >> 12) & 0x3f); + p[2] = 0x80 | ((wc >> 6) & 0x3f); + p[3] = 0x80 | (wc & 0x3f); + return (4); + } + /* Unicode has no codes larger than 0x1fffff. */ + /* + * Awkward point: UTF-8 <-> wchar_t conversions + * can actually fail. + */ + return ((size_t)-1); +} + +static int +my_wcstombs(struct archive_string *as, const wchar_t *w, + size_t (*func)(char *, wchar_t, mbstate_t *)) +{ + size_t n; + char *p; + mbstate_t shift_state; + char buff[256]; + + /* + * Convert one wide char at a time into 'buff', whenever that + * fills, append it to the string. + */ + p = buff; + wcrtomb(NULL, L'\0', &shift_state); + while (*w != L'\0') { + /* Flush the buffer when we have <=16 bytes free. */ + /* (No encoding has a single character >16 bytes.) */ + if ((size_t)(p - buff) >= (size_t)(sizeof(buff) - 16)) { + *p = '\0'; + archive_strcat(as, buff); + p = buff; + } + n = (*func)(p, *w++, &shift_state); + if (n == (size_t)-1) + return (-1); + p += n; + } + *p = '\0'; + archive_strcat(as, buff); + return (0); +} + +/* + * Translates a wide character string into UTF-8 and appends + * to the archive_string. Note: returns NULL if conversion fails. + */ +struct archive_string * +__archive_strappend_w_utf8(struct archive_string *as, const wchar_t *w) +{ + if (my_wcstombs(as, w, my_wcrtomb_utf8)) + return (NULL); + return (as); +} + +/* + * Translates a wide character string into current locale character set + * and appends to the archive_string. Note: returns NULL if conversion + * fails. + * + * TODO: use my_wcrtomb_utf8 if !HAVE_WCRTOMB (add configure logic first!) + */ +struct archive_string * +__archive_strappend_w_mbs(struct archive_string *as, const wchar_t *w) +{ + if (my_wcstombs(as, w, wcrtomb)) + return (NULL); + return (as); +} + + +/* + * Home-grown mbrtowc for UTF-8. Some systems lack UTF-8 + * (or even lack mbrtowc()) and we need UTF-8 support for pax + * format. So please don't replace this with a call to the + * standard mbrtowc() function! + */ +static size_t +my_mbrtowc_utf8(wchar_t *pwc, const char *s, size_t n, mbstate_t *ps) +{ + int ch; + + /* + * This argument is here to make the prototype identical to the + * standard mbrtowc(), so I can build generic string processors + * that just accept a pointer to a suitable mbrtowc() function. + */ + (void)ps; /* UNUSED */ + + /* Standard behavior: a NULL value for 's' just resets shift state. */ + if (s == NULL) + return (0); + /* If length argument is zero, don't look at the first character. */ + if (n <= 0) + return ((size_t)-2); + + /* + * Decode 1-4 bytes depending on the value of the first byte. + */ + ch = (unsigned char)*s; + if (ch == 0) { + return (0); /* Standard: return 0 for end-of-string. */ + } + if ((ch & 0x80) == 0) { + *pwc = ch & 0x7f; + return (1); + } + if ((ch & 0xe0) == 0xc0) { + if (n < 2) + return ((size_t)-2); + if ((s[1] & 0xc0) != 0x80) return (size_t)-1; + *pwc = ((ch & 0x1f) << 6) | (s[1] & 0x3f); + return (2); + } + if ((ch & 0xf0) == 0xe0) { + if (n < 3) + return ((size_t)-2); + if ((s[1] & 0xc0) != 0x80) return (size_t)-1; + if ((s[2] & 0xc0) != 0x80) return (size_t)-1; + *pwc = ((ch & 0x0f) << 12) + | ((s[1] & 0x3f) << 6) + | (s[2] & 0x3f); + return (3); + } + if ((ch & 0xf8) == 0xf0) { + if (n < 4) + return ((size_t)-2); + if ((s[1] & 0xc0) != 0x80) return (size_t)-1; + if ((s[2] & 0xc0) != 0x80) return (size_t)-1; + if ((s[3] & 0xc0) != 0x80) return (size_t)-1; + *pwc = ((ch & 0x07) << 18) + | ((s[1] & 0x3f) << 12) + | ((s[2] & 0x3f) << 6) + | (s[3] & 0x3f); + return (4); + } + /* Invalid first byte. */ + return ((size_t)-1); +} + +/* + * Return a wide-character string by converting this archive_string + * from UTF-8. + */ +wchar_t * +__archive_string_utf8_w(struct archive_string *as) +{ + wchar_t *ws, *dest; + const char *src; + size_t n; + int err; + + ws = (wchar_t *)malloc((as->length + 1) * sizeof(wchar_t)); + if (ws == NULL) + __archive_errx(1, "Out of memory"); + err = 0; + dest = ws; + src = as->s; + while (*src != '\0') { + n = my_mbrtowc_utf8(dest, src, 8, NULL); + if (n == 0) + break; + if (n == (size_t)-1 || n == (size_t)-2) { + free(ws); + return (NULL); + } + dest++; + src += n; + } + *dest++ = L'\0'; + return (ws); +} diff --git a/contrib/libarchive-2/libarchive/archive_string.h b/contrib/libarchive-2/libarchive/archive_string.h index 596db9a148..61e70777f1 100644 --- a/contrib/libarchive-2/libarchive/archive_string.h +++ b/contrib/libarchive-2/libarchive/archive_string.h @@ -22,7 +22,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/lib/libarchive/archive_string.h,v 1.9 2007/05/29 01:00:19 kientzle Exp $ + * $FreeBSD: src/lib/libarchive/archive_string.h,v 1.10 2008/03/14 22:00:09 kientzle Exp $ * */ @@ -33,6 +33,9 @@ #ifdef HAVE_STRING_H #include #endif +#ifdef HAVE_WCHAR_H +#include +#endif /* * Basic resizable/reusable string support a la Java's "StringBuffer." @@ -60,16 +63,22 @@ struct archive_string * __archive_strappend_char(struct archive_string *, char); #define archive_strappend_char __archive_strappend_char -/* Append a char to an archive_string using UTF8. */ -struct archive_string * -__archive_strappend_char_UTF8(struct archive_string *, int); -#define archive_strappend_char_UTF8 __archive_strappend_char_UTF8 - /* Append an integer in the specified base (2 <= base <= 16). */ struct archive_string * __archive_strappend_int(struct archive_string *as, int d, int base); #define archive_strappend_int __archive_strappend_int +/* Convert a wide-char string to UTF-8 and append the result. */ +struct archive_string * +__archive_strappend_w_utf8(struct archive_string *, const wchar_t *); +#define archive_strappend_w_utf8 __archive_strappend_w_utf8 + +/* Convert a wide-char string to current locale and append the result. */ +/* Returns NULL if conversion fails. */ +struct archive_string * +__archive_strappend_w_mbs(struct archive_string *, const wchar_t *); +#define archive_strappend_w_mbs __archive_strappend_w_mbs + /* Basic append operation. */ struct archive_string * __archive_string_append(struct archive_string *as, const char *p, size_t s); @@ -95,7 +104,7 @@ __archive_strncat(struct archive_string *, const char *, size_t); /* Copy a C string to an archive_string, resizing as necessary. */ #define archive_strcpy(as,p) \ - ((as)->length = 0, __archive_string_append((as), (p), strlen(p))) + ((as)->length = 0, __archive_string_append((as), (p), p == NULL ? 0 : strlen(p))) /* Copy a C string to an archive_string with limit, resizing as necessary. */ #define archive_strncpy(as,p,l) \ @@ -116,4 +125,12 @@ void __archive_string_vsprintf(struct archive_string *, const char *, va_list); #define archive_string_vsprintf __archive_string_vsprintf +void __archive_string_sprintf(struct archive_string *, const char *, ...); +#define archive_string_sprintf __archive_string_sprintf + +/* Allocates a fresh buffer and converts as (assumed to be UTF-8) into it. + * Returns NULL if conversion failed in any way. */ +wchar_t *__archive_string_utf8_w(struct archive_string *as); + + #endif diff --git a/contrib/libarchive-2/libarchive/archive_string_sprintf.c b/contrib/libarchive-2/libarchive/archive_string_sprintf.c index 763e75dcd8..6f77a36a1b 100644 --- a/contrib/libarchive-2/libarchive/archive_string_sprintf.c +++ b/contrib/libarchive-2/libarchive/archive_string_sprintf.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_string_sprintf.c,v 1.9 2007/07/15 19:13:59 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_string_sprintf.c,v 1.10 2008/03/14 22:00:09 kientzle Exp $"); /* * The use of printf()-family functions can be troublesome @@ -44,6 +44,16 @@ __FBSDID("$FreeBSD: src/lib/libarchive/archive_string_sprintf.c,v 1.9 2007/07/15 #include "archive_string.h" #include "archive_private.h" +void +__archive_string_sprintf(struct archive_string *as, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + archive_string_vsprintf(as, fmt, ap); + va_end(ap); +} + /* * Like 'vsprintf', but ensures the target is big enough, resizing if * necessary. diff --git a/contrib/libarchive-2/libarchive/archive_util.3 b/contrib/libarchive-2/libarchive/archive_util.3 index b8a030e493..b315c55e51 100644 --- a/contrib/libarchive-2/libarchive/archive_util.3 +++ b/contrib/libarchive-2/libarchive/archive_util.3 @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $FreeBSD: src/lib/libarchive/archive_util.3,v 1.7 2007/05/29 01:00:19 kientzle Exp $ +.\" $FreeBSD: src/lib/libarchive/archive_util.3,v 1.8 2008/03/10 14:44:40 jkoshy Exp $ .\" .Dd January 8, 2005 .Dt archive_util 3 @@ -57,7 +57,12 @@ .Ft const char * .Fn archive_format_name "struct archive *" .Ft void -.Fn archive_set_error "struct archive *" "int error_code" "const char *fmt" "..." +.Fo archive_set_error +.Fa "struct archive *" +.Fa "int error_code" +.Fa "const char *fmt" +.Fa "..." +.Fc .Sh DESCRIPTION These functions provide access to various information about the .Tn struct archive diff --git a/contrib/libarchive-2/libarchive/archive_util.c b/contrib/libarchive-2/libarchive/archive_util.c index 413199a360..55dd1fa10c 100644 --- a/contrib/libarchive-2/libarchive/archive_util.c +++ b/contrib/libarchive-2/libarchive/archive_util.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_util.c,v 1.16 2007/12/30 04:58:21 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_util.c,v 1.17 2008/03/14 22:31:57 kientzle Exp $"); #ifdef HAVE_SYS_TYPES_H #include @@ -38,29 +38,49 @@ __FBSDID("$FreeBSD: src/lib/libarchive/archive_util.c,v 1.16 2007/12/30 04:58:21 #include "archive.h" #include "archive_private.h" +#include "archive_string.h" +#if ARCHIVE_VERSION_NUMBER < 3000000 +/* These disappear in libarchive 3.0 */ +/* Deprecated. */ int archive_api_feature(void) { return (ARCHIVE_API_FEATURE); } +/* Deprecated. */ int archive_api_version(void) { return (ARCHIVE_API_VERSION); } +/* Deprecated synonym for archive_version_number() */ int archive_version_stamp(void) { - return (ARCHIVE_VERSION_STAMP); + return (archive_version_number()); } +/* Deprecated synonym for archive_version_string() */ const char * archive_version(void) { - return (ARCHIVE_LIBRARY_VERSION); + return (archive_version_string()); +} +#endif + +int +archive_version_number(void) +{ + return (ARCHIVE_VERSION_NUMBER); +} + +const char * +archive_version_string(void) +{ + return (ARCHIVE_VERSION_STRING); } int diff --git a/contrib/libarchive-2/libarchive/archive_write.3 b/contrib/libarchive-2/libarchive/archive_write.3 index c07b6b570e..fff84f7cdd 100644 --- a/contrib/libarchive-2/libarchive/archive_write.3 +++ b/contrib/libarchive-2/libarchive/archive_write.3 @@ -22,9 +22,9 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $FreeBSD: src/lib/libarchive/archive_write.3,v 1.22 2007/05/29 01:00:19 kientzle Exp $ +.\" $FreeBSD: src/lib/libarchive/archive_write.3,v 1.23 2008/03/10 14:44:41 jkoshy Exp $ .\" -.Dd August 19, 2006 +.Dd May 11, 2008 .Dt archive_write 3 .Os .Sh NAME @@ -39,6 +39,7 @@ .Nm archive_write_set_bytes_per_block , .Nm archive_write_set_bytes_in_last_block , .Nm archive_write_set_compression_bzip2 , +.Nm archive_write_set_compression_compress , .Nm archive_write_set_compression_gzip , .Nm archive_write_set_compression_none , .Nm archive_write_set_compression_program , @@ -66,11 +67,16 @@ .Ft int .Fn archive_write_set_compression_bzip2 "struct archive *" .Ft int +.Fn archive_write_set_compression_compress "struct archive *" +.Ft int .Fn archive_write_set_compression_gzip "struct archive *" .Ft int .Fn archive_write_set_compression_none "struct archive *" .Ft int -.Fn archive_write_set_compression_program "struct archive *" "const char * cmd" +.Fo archive_write_set_compression_program +.Fa "struct archive *" +.Fa "const char * cmd" +.Fc .Ft int .Fn archive_write_set_format_cpio "struct archive *" .Ft int @@ -84,7 +90,13 @@ .Ft int .Fn archive_write_set_format_ustar "struct archive *" .Ft int -.Fn archive_write_open "struct archive *" "void *client_data" "archive_open_callback *" "archive_write_callback *" "archive_close_callback *" +.Fo archive_write_open +.Fa "struct archive *" +.Fa "void *client_data" +.Fa "archive_open_callback *" +.Fa "archive_write_callback *" +.Fa "archive_close_callback *" +.Fc .Ft int .Fn archive_write_open_fd "struct archive *" "int fd" .Ft int @@ -92,7 +104,12 @@ .Ft int .Fn archive_write_open_filename "struct archive *" "const char *filename" .Ft int -.Fn archive_write_open_memory "struct archive *" "void *buffer" "size_t bufferSize" "size_t *outUsed" +.Fo archive_write_open_memory +.Fa "struct archive *" +.Fa "void *buffer" +.Fa "size_t bufferSize" +.Fa "size_t *outUsed" +.Fc .Ft int .Fn archive_write_header "struct archive *" "struct archive_entry *" .Ft ssize_t @@ -150,7 +167,14 @@ functions, this function can be called after the archive is opened. .It Fn archive_write_get_bytes_in_last_block Retrieve the currently-set value for last block size. A value of -1 here indicates that the library should use default values. -.It Fn archive_write_set_format_cpio , Fn archive_write_set_format_pax , Fn archive_write_set_format_pax_restricted , Fn archive_write_set_format_shar , Fn archive_write_set_format_shar_binary , Fn archive_write_set_format_ustar +.It Xo +.Fn archive_write_set_format_cpio , +.Fn archive_write_set_format_pax , +.Fn archive_write_set_format_pax_restricted , +.Fn archive_write_set_format_shar , +.Fn archive_write_set_format_shar_binary , +.Fn archive_write_set_format_ustar +.Xc Sets the format that will be used for the archive. The library can write POSIX octet-oriented cpio format archives, @@ -174,7 +198,12 @@ filenames, linknames, uids, sizes, etc. is the library default; this is the same as pax format, but suppresses the pax extended header for most normal files. In most cases, this will result in ordinary ustar archives. -.It Fn archive_write_set_compression_bzip2 , Fn archive_write_set_compression_gzip , Fn archive_write_set_compression_none +.It Xo +.Fn archive_write_set_compression_bzip2 , +.Fn archive_write_set_compression_compress , +.Fn archive_write_set_compression_gzip , +.Fn archive_write_set_compression_none +.Xc The resulting archive will be compressed as specified. Note that the compressed output is always properly blocked. .It Fn archive_write_set_compression_program @@ -310,7 +339,12 @@ to register an error code and message and return .Bl -item -offset indent .It .Ft typedef ssize_t -.Fn archive_write_callback "struct archive *" "void *client_data" "void *buffer" "size_t length" +.Fo archive_write_callback +.Fa "struct archive *" +.Fa "void *client_data" +.Fa "void *buffer" +.Fa "size_t length" +.Fc .El .Pp The write callback is invoked whenever the library diff --git a/contrib/libarchive-2/libarchive/archive_write.c b/contrib/libarchive-2/libarchive/archive_write.c index 2977063979..1a3ddc9a5e 100644 --- a/contrib/libarchive-2/libarchive/archive_write.c +++ b/contrib/libarchive-2/libarchive/archive_write.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_write.c,v 1.26 2007/05/29 01:00:19 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_write.c,v 1.27 2008/03/14 23:09:02 kientzle Exp $"); /* * This file contains the "essential" portions of the write API, that @@ -97,7 +97,12 @@ archive_write_new(void) a->archive.magic = ARCHIVE_WRITE_MAGIC; a->archive.state = ARCHIVE_STATE_NEW; a->archive.vtable = archive_write_vtable(); - a->bytes_per_block = ARCHIVE_DEFAULT_BYTES_PER_BLOCK; + /* + * The value 10240 here matches the traditional tar default, + * but is otherwise arbitrary. + * TODO: Set the default block size from the format selected. + */ + a->bytes_per_block = 10240; a->bytes_in_last_block = -1; /* Default */ /* Initialize a block of nulls for padding purposes. */ diff --git a/contrib/libarchive-2/libarchive/archive_write_disk.3 b/contrib/libarchive-2/libarchive/archive_write_disk.3 index 880a399b94..f71d7d5485 100644 --- a/contrib/libarchive-2/libarchive/archive_write_disk.3 +++ b/contrib/libarchive-2/libarchive/archive_write_disk.3 @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $FreeBSD: src/lib/libarchive/archive_write_disk.3,v 1.1 2007/03/03 07:37:36 kientzle Exp $ +.\" $FreeBSD: src/lib/libarchive/archive_write_disk.3,v 1.2 2008/03/10 14:44:41 jkoshy Exp $ .\" .Dd March 2, 2007 .Dt archive_write_disk 3 @@ -49,11 +49,21 @@ .Ft int .Fn archive_write_disk_set_skip_file "struct archive *" "dev_t" "ino_t" .Ft int -.Fn archive_write_disk_set_group_lookup "struct archive *" "void *" "gid_t (*)(void *, const char *gname, gid_t gid)" "void (*cleanup)(void *)" +.Fo archive_write_disk_set_group_lookup +.Fa "struct archive *" +.Fa "void *" +.Fa "gid_t (*)(void *, const char *gname, gid_t gid)" +.Fa "void (*cleanup)(void *)" +.Fc .Ft int .Fn archive_write_disk_set_standard_lookup "struct archive *" .Ft int -.Fn archive_write_disk_set_user_lookup "struct archive *" "void *" "uid_t (*)(void *, const char *uname, uid_t uid)" "void (*cleanup)(void *)" +.Fo archive_write_disk_set_user_lookup +.Fa "struct archive *" +.Fa "void *" +.Fa "uid_t (*)(void *, const char *uname, uid_t uid)" +.Fa "void (*cleanup)(void *)" +.Fc .Ft int .Fn archive_write_header "struct archive *" "struct archive_entry *" .Ft ssize_t @@ -160,7 +170,14 @@ Note that paths ending in .Pa .. always cause an error, regardless of this flag. .El -.It Fn archive_write_disk_set_group_lookup , Fn archive_write_disk_set_user_lookup +.It Cm ARCHIVE_EXTRACT_SPARSE +Scan data for blocks of NUL bytes and try to recreate them with holes. +This results in sparse files, independent of whether the archive format +supports or uses them. +.It Xo +.Fn archive_write_disk_set_group_lookup , +.Fn archive_write_disk_set_user_lookup +.Xc The .Tn struct archive_entry objects contain both names and ids that can be used to identify users diff --git a/contrib/libarchive-2/libarchive/archive_write_disk.c b/contrib/libarchive-2/libarchive/archive_write_disk.c index dfb6d35aec..8010c1330e 100644 --- a/contrib/libarchive-2/libarchive/archive_write_disk.c +++ b/contrib/libarchive-2/libarchive/archive_write_disk.c @@ -25,7 +25,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_disk.c,v 1.22 2008/02/19 05:39:35 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_disk.c,v 1.24 2008/03/15 04:20:50 kientzle Exp $"); #ifdef HAVE_SYS_TYPES_H #include @@ -187,6 +187,8 @@ struct archive_write_disk { /* UID/GID to use in restoring this entry. */ uid_t uid; gid_t gid; + /* Last offset written to disk. */ + off_t last_offset; }; /* @@ -242,6 +244,31 @@ static int _archive_write_finish_entry(struct archive *); static ssize_t _archive_write_data(struct archive *, const void *, size_t); static ssize_t _archive_write_data_block(struct archive *, const void *, size_t, off_t); +static int +_archive_write_disk_lazy_stat(struct archive_write_disk *a) +{ + if (a->pst != NULL) { + /* Already have stat() data available. */ + return (ARCHIVE_OK); + } +#ifdef HAVE_FSTAT + if (a->fd >= 0 && fstat(a->fd, &a->st) == 0) { + a->pst = &a->st; + return (ARCHIVE_OK); + } +#endif + /* + * XXX At this point, symlinks should not be hit, otherwise + * XXX a race occured. Do we want to check explicitly for that? + */ + if (lstat(a->name, &a->st) == 0) { + a->pst = &a->st; + return (ARCHIVE_OK); + } + archive_set_error(&a->archive, errno, "Couldn't stat file"); + return (ARCHIVE_WARN); +} + static struct archive_vtable * archive_write_disk_vtable(void) { @@ -294,7 +321,7 @@ _archive_write_header(struct archive *_a, struct archive_entry *entry) archive_clear_error(&a->archive); if (a->archive.state & ARCHIVE_STATE_DATA) { r = _archive_write_finish_entry(&a->archive); - if (r != ARCHIVE_OK) + if (r == ARCHIVE_FATAL) return (r); } @@ -308,6 +335,7 @@ _archive_write_header(struct archive *_a, struct archive_entry *entry) } a->entry = archive_entry_clone(entry); a->fd = -1; + a->last_offset = 0; a->offset = 0; a->uid = a->user_uid; a->mode = archive_entry_mode(a->entry); @@ -463,6 +491,7 @@ _archive_write_data_block(struct archive *_a, { struct archive_write_disk *a = (struct archive_write_disk *)_a; ssize_t bytes_written = 0; + ssize_t block_size, bytes_to_write; int r = ARCHIVE_OK; __archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, @@ -473,31 +502,53 @@ _archive_write_data_block(struct archive *_a, } archive_clear_error(&a->archive); - /* Seek if necessary to the specified offset. */ - if (offset != a->offset) { - if (lseek(a->fd, offset, SEEK_SET) < 0) { - archive_set_error(&a->archive, errno, "Seek failed"); - return (ARCHIVE_WARN); - } - a->offset = offset; + if (a->flags & ARCHIVE_EXTRACT_SPARSE) { + if ((r = _archive_write_disk_lazy_stat(a)) != ARCHIVE_OK) + return (r); + block_size = a->pst->st_blksize; + } else + block_size = -1; + + if ((off_t)(offset + size) > a->filesize) { + size = (size_t)(a->filesize - a->offset); + archive_set_error(&a->archive, 0, + "Write request too large"); + r = ARCHIVE_WARN; } /* Write the data. */ - while (size > 0 && a->offset < a->filesize) { - if ((off_t)(a->offset + size) > a->filesize) { - size = (size_t)(a->filesize - a->offset); - archive_set_error(&a->archive, errno, - "Write request too large"); - r = ARCHIVE_WARN; - } + while (size > 0) { + if (block_size != -1) { + const char *buf; + + for (buf = buff; size; ++buf, --size, ++offset) { + if (*buf != '\0') + break; + } + if (size == 0) + break; + bytes_to_write = block_size - offset % block_size; + buff = buf; + } else + bytes_to_write = size; + /* Seek if necessary to the specified offset. */ + if (offset != a->last_offset) { + if (lseek(a->fd, offset, SEEK_SET) < 0) { + archive_set_error(&a->archive, errno, "Seek failed"); + return (ARCHIVE_FATAL); + } + } bytes_written = write(a->fd, buff, size); if (bytes_written < 0) { archive_set_error(&a->archive, errno, "Write failed"); return (ARCHIVE_WARN); } + buff = (const char *)buff + bytes_written; size -= bytes_written; - a->offset += bytes_written; + offset += bytes_written; + a->last_offset = a->offset = offset; } + a->offset = offset; return (r); } @@ -505,7 +556,6 @@ static ssize_t _archive_write_data(struct archive *_a, const void *buff, size_t size) { struct archive_write_disk *a = (struct archive_write_disk *)_a; - off_t offset; int r; __archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC, @@ -513,11 +563,10 @@ _archive_write_data(struct archive *_a, const void *buff, size_t size) if (a->fd < 0) return (ARCHIVE_OK); - offset = a->offset; r = _archive_write_data_block(_a, buff, size, a->offset); if (r < ARCHIVE_OK) return (r); - return (a->offset - offset); + return size; } static int @@ -533,6 +582,34 @@ _archive_write_finish_entry(struct archive *_a) return (ARCHIVE_OK); archive_clear_error(&a->archive); + if (a->last_offset != a->filesize && a->fd >= 0) { + if (ftruncate(a->fd, a->filesize) == -1 && + a->filesize == 0) { + archive_set_error(&a->archive, errno, + "File size could not be restored"); + return (ARCHIVE_FAILED); + } + /* + * Explicitly stat the file as some platforms might not + * implement the XSI option to extend files via ftruncate. + */ + a->pst = NULL; + if ((ret = _archive_write_disk_lazy_stat(a)) != ARCHIVE_OK) + return (ret); + if (a->st.st_size != a->filesize) { + const char nul = '\0'; + if (lseek(a->fd, a->st.st_size - 1, SEEK_SET) < 0) { + archive_set_error(&a->archive, errno, "Seek failed"); + return (ARCHIVE_FATAL); + } + if (write(a->fd, &nul, 1) < 0) { + archive_set_error(&a->archive, errno, + "Write to restore size failed"); + return (ARCHIVE_FATAL); + } + } + } + /* Restore metadata. */ /* @@ -723,11 +800,13 @@ restore_entry(struct archive_write_disk *a) * object isn't a dir. */ if (unlink(a->name) == 0) { - /* We removed it, we're done. */ + /* We removed it, reset cached stat. */ + a->pst = NULL; } else if (errno == ENOENT) { /* File didn't exist, that's just as good. */ } else if (rmdir(a->name) == 0) { /* It was a dir, but now it's gone. */ + a->pst = NULL; } else { /* We tried, but couldn't get rid of it. */ archive_set_error(&a->archive, errno, @@ -768,6 +847,7 @@ restore_entry(struct archive_write_disk *a) "Can't remove already-existing dir"); return (ARCHIVE_WARN); } + a->pst = NULL; /* Try again. */ en = create_filesystem_object(a); } else if (en == EEXIST) { @@ -807,6 +887,7 @@ restore_entry(struct archive_write_disk *a) "Can't unlink already-existing object"); return (ARCHIVE_WARN); } + a->pst = NULL; /* Try again. */ en = create_filesystem_object(a); } else if (!S_ISDIR(a->mode)) { @@ -866,8 +947,18 @@ create_filesystem_object(struct archive_write_disk *a) * New cpio and pax formats allow hardlink entries * to carry data, so we may have to open the file * for hardlink entries. + * + * If the hardlink was successfully created and + * the archive doesn't have carry data for it, + * consider it to be non-authoritive for meta data. + * This is consistent with GNU tar and BSD pax. + * If the hardlink does carry data, let the last + * archive entry decide ownership. */ - if (r == 0 && a->filesize > 0) { + if (r == 0 && a->filesize == 0) { + a->todo = 0; + a->deferred = 0; + } if (r == 0 && a->filesize > 0) { a->fd = open(a->name, O_WRONLY | O_TRUNC | O_BINARY); if (a->fd < 0) r = errno; @@ -1167,7 +1258,7 @@ check_symlinks(struct archive_write_disk *a) struct stat st; /* - * Gaurd against symlink tricks. Reject any archive entry whose + * Guard against symlink tricks. Reject any archive entry whose * destination would be altered by a symlink. */ /* Whatever we checked last time doesn't need to be re-checked. */ @@ -1203,6 +1294,7 @@ check_symlinks(struct archive_write_disk *a) pn[0] = c; return (ARCHIVE_WARN); } + a->pst = NULL; /* * Even if we did remove it, a warning * is in order. The warning is silly, @@ -1226,6 +1318,7 @@ check_symlinks(struct archive_write_disk *a) pn[0] = c; return (ARCHIVE_WARN); } + a->pst = NULL; } else { archive_set_error(&a->archive, 0, "Cannot extract through symlink %s", @@ -1608,19 +1701,8 @@ set_mode(struct archive_write_disk *a, int mode) * process, since systems sometimes set GID from * the enclosing dir or based on ACLs. */ - if (a->pst != NULL) { - /* Already have stat() data available. */ -#ifdef HAVE_FSTAT - } else if (fd >= 0 && fstat(fd, &a->st) == 0) { - a->pst = &a->st; -#endif - } else if (stat(a->name, &a->st) == 0) { - a->pst = &a->st; - } else { - archive_set_error(&a->archive, errno, - "Couldn't stat file"); - return (ARCHIVE_WARN); - } + if ((r = _archive_write_disk_lazy_stat(a)) != ARCHIVE_OK) + return (r); if (a->pst->st_gid != a->gid) { mode &= ~ S_ISGID; if (a->flags & ARCHIVE_EXTRACT_OWNER) { @@ -1783,6 +1865,8 @@ static int set_fflags_platform(struct archive_write_disk *a, int fd, const char *name, mode_t mode, unsigned long set, unsigned long clear) { + int r; + (void)mode; /* UNUSED */ if (set == 0 && clear == 0) return (ARCHIVE_OK); @@ -1793,15 +1877,8 @@ set_fflags_platform(struct archive_write_disk *a, int fd, const char *name, * about the correct approach if we're overwriting an existing * file that already has flags on it. XXX */ - if (fd >= 0 && fstat(fd, &a->st) == 0) - a->pst = &a->st; - else if (lstat(name, &a->st) == 0) - a->pst = &a->st; - else { - archive_set_error(&a->archive, errno, - "Couldn't stat file"); - return (ARCHIVE_WARN); - } + if ((r = _archive_write_disk_lazy_stat(a)) != ARCHIVE_OK) + return (r); a->st.st_flags &= ~clear; a->st.st_flags |= set; diff --git a/contrib/libarchive-2/libarchive/archive_write_private.h b/contrib/libarchive-2/libarchive/archive_write_private.h index 82935f4627..55c24ad96c 100644 --- a/contrib/libarchive-2/libarchive/archive_write_private.h +++ b/contrib/libarchive-2/libarchive/archive_write_private.h @@ -22,7 +22,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/lib/libarchive/archive_write_private.h,v 1.2 2007/05/29 01:00:19 kientzle Exp $ + * $FreeBSD: src/lib/libarchive/archive_write_private.h,v 1.3 2008/03/15 11:04:45 kientzle Exp $ */ #ifndef ARCHIVE_WRITE_PRIVATE_H_INCLUDED @@ -81,13 +81,6 @@ struct archive_write { int (*write)(struct archive_write *, const void *, size_t); } compressor; - /* - * Again, write support is considerably simpler because there's - * no need for an auction. - */ - int archive_format; - const char *archive_format_name; - /* * Pointers to format-specific functions for writing. They're * initialized by archive_write_set_format_XXX() calls. diff --git a/contrib/libarchive-2/libarchive/archive_write_set_compression_compress.c b/contrib/libarchive-2/libarchive/archive_write_set_compression_compress.c new file mode 100644 index 0000000000..f913a23c53 --- /dev/null +++ b/contrib/libarchive-2/libarchive/archive_write_set_compression_compress.c @@ -0,0 +1,494 @@ +/*- + * Copyright (c) 2008 Joerg Sonnenberger + * 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. + */ + +/*- + * Copyright (c) 1985, 1986, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Diomidis Spinellis and James A. Woods, derived from original + * work by Spencer Thomas and Joseph Orost. + * + * 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. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "archive_platform.h" + +__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_compression_compress.c,v 1.1 2008/03/14 20:35:37 kientzle Exp $"); + +#ifdef HAVE_ERRNO_H +#include +#endif +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif + +#include "archive.h" +#include "archive_private.h" +#include "archive_write_private.h" + +#define HSIZE 69001 /* 95% occupancy */ +#define HSHIFT 8 /* 8 - trunc(log2(HSIZE / 65536)) */ +#define CHECK_GAP 10000 /* Ratio check interval. */ + +#define MAXCODE(bits) ((1 << (bits)) - 1) + +/* + * the next two codes should not be changed lightly, as they must not + * lie within the contiguous general code space. + */ +#define FIRST 257 /* First free entry. */ +#define CLEAR 256 /* Table clear output code. */ + +struct private_data { + off_t in_count, out_count, checkpoint; + + int code_len; /* Number of bits/code. */ + int cur_maxcode; /* Maximum code, given n_bits. */ + int max_maxcode; /* Should NEVER generate this code. */ + int hashtab [HSIZE]; + unsigned short codetab [HSIZE]; + int first_free; /* First unused entry. */ + int compress_ratio; + + int cur_code, cur_fcode; + + int bit_offset; + unsigned char bit_buf; + + unsigned char *compressed; + size_t compressed_buffer_size; + size_t compressed_offset; +}; + +static int archive_compressor_compress_finish(struct archive_write *); +static int archive_compressor_compress_init(struct archive_write *); +static int archive_compressor_compress_write(struct archive_write *, + const void *, size_t); + +/* + * Allocate, initialize and return a archive object. + */ +int +archive_write_set_compression_compress(struct archive *_a) +{ + struct archive_write *a = (struct archive_write *)_a; + __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC, + ARCHIVE_STATE_NEW, "archive_write_set_compression_compress"); + a->compressor.init = &archive_compressor_compress_init; + a->archive.compression_code = ARCHIVE_COMPRESSION_COMPRESS; + a->archive.compression_name = "compress"; + return (ARCHIVE_OK); +} + +/* + * Setup callback. + */ +static int +archive_compressor_compress_init(struct archive_write *a) +{ + int ret; + struct private_data *state; + + a->archive.compression_code = ARCHIVE_COMPRESSION_COMPRESS; + a->archive.compression_name = "compress"; + + if (a->bytes_per_block < 4) { + archive_set_error(&a->archive, EINVAL, + "Can't write Compress header as single block"); + return (ARCHIVE_FATAL); + } + + if (a->client_opener != NULL) { + ret = (a->client_opener)(&a->archive, a->client_data); + if (ret != ARCHIVE_OK) + return (ret); + } + + state = (struct private_data *)malloc(sizeof(*state)); + if (state == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate data for compression"); + return (ARCHIVE_FATAL); + } + memset(state, 0, sizeof(*state)); + + state->compressed_buffer_size = a->bytes_per_block; + state->compressed = malloc(state->compressed_buffer_size); + + if (state->compressed == NULL) { + archive_set_error(&a->archive, ENOMEM, + "Can't allocate data for compression buffer"); + free(state); + return (ARCHIVE_FATAL); + } + + a->compressor.write = archive_compressor_compress_write; + a->compressor.finish = archive_compressor_compress_finish; + + state->max_maxcode = 0x10000; /* Should NEVER generate this code. */ + state->in_count = 0; /* Length of input. */ + state->bit_buf = 0; + state->bit_offset = 0; + state->out_count = 3; /* Includes 3-byte header mojo. */ + state->compress_ratio = 0; + state->checkpoint = CHECK_GAP; + state->code_len = 9; + state->cur_maxcode = MAXCODE(state->code_len); + state->first_free = FIRST; + + memset(state->hashtab, 0xff, sizeof(state->hashtab)); + + /* Prime output buffer with a gzip header. */ + state->compressed[0] = 0x1f; /* Compress */ + state->compressed[1] = 0x9d; + state->compressed[2] = 0x90; /* Block mode, 16bit max */ + state->compressed_offset = 3; + + a->compressor.data = state; + return (0); +} + +/*- + * Output the given code. + * Inputs: + * code: A n_bits-bit integer. If == -1, then EOF. This assumes + * that n_bits =< (long)wordsize - 1. + * Outputs: + * Outputs code to the file. + * Assumptions: + * Chars are 8 bits long. + * Algorithm: + * Maintain a BITS character long buffer (so that 8 codes will + * fit in it exactly). Use the VAX insv instruction to insert each + * code in turn. When the buffer fills up empty it and start over. + */ + +static unsigned char rmask[9] = + {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff}; + +static int +output_byte(struct archive_write *a, unsigned char c) +{ + struct private_data *state = a->compressor.data; + ssize_t bytes_written; + + state->compressed[state->compressed_offset++] = c; + ++state->out_count; + + if (state->compressed_buffer_size == state->compressed_offset) { + bytes_written = (a->client_writer)(&a->archive, + a->client_data, + state->compressed, state->compressed_buffer_size); + if (bytes_written <= 0) + return ARCHIVE_FATAL; + a->archive.raw_position += bytes_written; + state->compressed_offset = 0; + } + + return ARCHIVE_OK; +} + +static int +output_code(struct archive_write *a, int ocode) +{ + struct private_data *state = a->compressor.data; + int bits, ret, clear_flg, bit_offset; + + clear_flg = ocode == CLEAR; + bits = state->code_len; + + /* + * Since ocode is always >= 8 bits, only need to mask the first + * hunk on the left. + */ + bit_offset = state->bit_offset % 8; + state->bit_buf |= (ocode << bit_offset) & 0xff; + output_byte(a, state->bit_buf); + + bits = state->code_len - (8 - bit_offset); + ocode >>= 8 - bit_offset; + /* Get any 8 bit parts in the middle (<=1 for up to 16 bits). */ + if (bits >= 8) { + output_byte(a, ocode & 0xff); + ocode >>= 8; + bits -= 8; + } + /* Last bits. */ + state->bit_offset += state->code_len; + state->bit_buf = ocode & rmask[bits]; + if (state->bit_offset == state->code_len * 8) + state->bit_offset = 0; + + /* + * If the next entry is going to be too big for the ocode size, + * then increase it, if possible. + */ + if (clear_flg || state->first_free > state->cur_maxcode) { + /* + * Write the whole buffer, because the input side won't + * discover the size increase until after it has read it. + */ + if (state->bit_offset > 0) { + while (state->bit_offset < state->code_len * 8) { + ret = output_byte(a, state->bit_buf); + if (ret != ARCHIVE_OK) + return ret; + state->bit_offset += 8; + state->bit_buf = 0; + } + } + state->bit_buf = 0; + state->bit_offset = 0; + + if (clear_flg) { + state->code_len = 9; + state->cur_maxcode = MAXCODE(state->code_len); + } else { + state->code_len++; + if (state->code_len == 16) + state->cur_maxcode = state->max_maxcode; + else + state->cur_maxcode = MAXCODE(state->code_len); + } + } + + return (ARCHIVE_OK); +} + +static int +output_flush(struct archive_write *a) +{ + struct private_data *state = a->compressor.data; + int ret; + + /* At EOF, write the rest of the buffer. */ + if (state->bit_offset % 8) { + state->code_len = (state->bit_offset % 8 + 7) / 8; + ret = output_byte(a, state->bit_buf); + if (ret != ARCHIVE_OK) + return ret; + } + + return (ARCHIVE_OK); +} + +/* + * Write data to the compressed stream. + */ +static int +archive_compressor_compress_write(struct archive_write *a, const void *buff, + size_t length) +{ + struct private_data *state; + int i; + int ratio; + int c, disp, ret; + const unsigned char *bp; + + state = (struct private_data *)a->compressor.data; + if (a->client_writer == NULL) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, + "No write callback is registered? " + "This is probably an internal programming error."); + return (ARCHIVE_FATAL); + } + + if (length == 0) + return ARCHIVE_OK; + + bp = buff; + + if (state->in_count == 0) { + state->cur_code = *bp++; + ++state->in_count; + --length; + } + + while (length--) { + c = *bp++; + state->in_count++; + state->cur_fcode = (c << 16) + state->cur_code; + i = ((c << HSHIFT) ^ state->cur_code); /* Xor hashing. */ + + if (state->hashtab[i] == state->cur_fcode) { + state->cur_code = state->codetab[i]; + continue; + } + if (state->hashtab[i] < 0) /* Empty slot. */ + goto nomatch; + /* Secondary hash (after G. Knott). */ + if (i == 0) + disp = 1; + else + disp = HSIZE - i; + probe: + if ((i -= disp) < 0) + i += HSIZE; + + if (state->hashtab[i] == state->cur_fcode) { + state->cur_code = state->codetab[i]; + continue; + } + if (state->hashtab[i] >= 0) + goto probe; + nomatch: + ret = output_code(a, state->cur_code); + if (ret != ARCHIVE_OK) + return ret; + state->cur_code = c; + if (state->first_free < state->max_maxcode) { + state->codetab[i] = state->first_free++; /* code -> hashtable */ + state->hashtab[i] = state->cur_fcode; + continue; + } + if (state->in_count < state->checkpoint) + continue; + + state->checkpoint = state->in_count + CHECK_GAP; + + if (state->in_count <= 0x007fffff) + ratio = state->in_count * 256 / state->out_count; + else if ((ratio = state->out_count / 256) == 0) + ratio = 0x7fffffff; + else + ratio = state->in_count / ratio; + + if (ratio > state->compress_ratio) + state->compress_ratio = ratio; + else { + state->compress_ratio = 0; + memset(state->hashtab, 0xff, sizeof(state->hashtab)); + state->first_free = FIRST; + ret = output_code(a, CLEAR); + if (ret != ARCHIVE_OK) + return ret; + } + } + + return (ARCHIVE_OK); +} + + +/* + * Finish the compression... + */ +static int +archive_compressor_compress_finish(struct archive_write *a) +{ + ssize_t block_length, target_block_length, bytes_written; + int ret; + struct private_data *state; + unsigned tocopy; + + state = (struct private_data *)a->compressor.data; + ret = 0; + if (a->client_writer == NULL) { + archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER, + "No write callback is registered? " + "This is probably an internal programming error."); + ret = ARCHIVE_FATAL; + goto cleanup; + } + + /* By default, always pad the uncompressed data. */ + if (a->pad_uncompressed) { + while (state->in_count % a->bytes_per_block != 0) { + tocopy = a->bytes_per_block - + (state->in_count % a->bytes_per_block); + if (tocopy > a->null_length) + tocopy = a->null_length; + ret = archive_compressor_compress_write(a, a->nulls, + tocopy); + if (ret != ARCHIVE_OK) + goto cleanup; + } + } + + ret = output_code(a, state->cur_code); + if (ret != ARCHIVE_OK) + goto cleanup; + ret = output_flush(a); + if (ret != ARCHIVE_OK) + goto cleanup; + + /* Optionally, pad the final compressed block. */ + block_length = state->compressed_offset; + + /* Tricky calculation to determine size of last block. */ + if (a->bytes_in_last_block <= 0) + /* Default or Zero: pad to full block */ + target_block_length = a->bytes_per_block; + else + /* Round length to next multiple of bytes_in_last_block. */ + target_block_length = a->bytes_in_last_block * + ( (block_length + a->bytes_in_last_block - 1) / + a->bytes_in_last_block); + if (target_block_length > a->bytes_per_block) + target_block_length = a->bytes_per_block; + if (block_length < target_block_length) { + memset(state->compressed + state->compressed_offset, 0, + target_block_length - block_length); + block_length = target_block_length; + } + + /* Write the last block */ + bytes_written = (a->client_writer)(&a->archive, a->client_data, + state->compressed, block_length); + if (bytes_written <= 0) + ret = ARCHIVE_FATAL; + else + a->archive.raw_position += bytes_written; + +cleanup: + free(state->compressed); + free(state); + return (ret); +} diff --git a/contrib/libarchive-2/libarchive/archive_write_set_compression_program.c b/contrib/libarchive-2/libarchive/archive_write_set_compression_program.c index fc1481dbcd..b8b20c86cf 100644 --- a/contrib/libarchive-2/libarchive/archive_write_set_compression_program.c +++ b/contrib/libarchive-2/libarchive/archive_write_set_compression_program.c @@ -27,6 +27,23 @@ __FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_compression_program.c,v 1.1 2007/05/29 01:00:19 kientzle Exp $"); +/* This capability is only available on POSIX systems. */ +#if !defined(HAVE_PIPE) || !defined(HAVE_VFORK) || !defined(HAVE_FCNTL) + +/* + * On non-Posix systems, allow the program to build, but choke if + * this function is actually invoked. + */ +int +archive_write_set_compression_program(struct archive *_a, const char *cmd) +{ + archive_set_error(_a, -1, + "External compression programs not supported on this platform"); + return (ARCHIVE_FATAL); +} + +#else + #ifdef HAVE_SYS_WAIT_H # include #endif @@ -320,3 +337,5 @@ cleanup: free(state); return (ret); } + +#endif /* !defined(HAVE_PIPE) || !defined(HAVE_VFORK) || !defined(HAVE_FCNTL) */ diff --git a/contrib/libarchive-2/libarchive/archive_write_set_format_ar.c b/contrib/libarchive-2/libarchive/archive_write_set_format_ar.c index 2e77f1bd89..1731844d33 100644 --- a/contrib/libarchive-2/libarchive/archive_write_set_format_ar.c +++ b/contrib/libarchive-2/libarchive/archive_write_set_format_ar.c @@ -26,7 +26,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_ar.c,v 1.5 2008/01/31 08:11:01 kaiw Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_ar.c,v 1.6 2008/03/15 11:04:45 kientzle Exp $"); #ifdef HAVE_ERRNO_H #include @@ -87,8 +87,8 @@ archive_write_set_format_ar_bsd(struct archive *_a) struct archive_write *a = (struct archive_write *)_a; int r = archive_write_set_format_ar(a); if (r == ARCHIVE_OK) { - a->archive_format = ARCHIVE_FORMAT_AR_BSD; - a->archive_format_name = "ar (BSD)"; + a->archive.archive_format = ARCHIVE_FORMAT_AR_BSD; + a->archive.archive_format_name = "ar (BSD)"; } return (r); } @@ -99,8 +99,8 @@ archive_write_set_format_ar_svr4(struct archive *_a) struct archive_write *a = (struct archive_write *)_a; int r = archive_write_set_format_ar(a); if (r == ARCHIVE_OK) { - a->archive_format = ARCHIVE_FORMAT_AR_GNU; - a->archive_format_name = "ar (GNU/SVR4)"; + a->archive.archive_format = ARCHIVE_FORMAT_AR_GNU; + a->archive.archive_format_name = "ar (GNU/SVR4)"; } return (r); } @@ -142,12 +142,15 @@ archive_write_ar_header(struct archive_write *a, struct archive_entry *entry) struct ar_w *ar; const char *pathname; const char *filename; + int64_t size; ret = 0; append_fn = 0; ar = (struct ar_w *)a->format_data; ar->is_strtab = 0; filename = NULL; + size = archive_entry_size(entry); + /* * Reject files with empty name. @@ -204,7 +207,7 @@ archive_write_ar_header(struct archive_write *a, struct archive_entry *entry) return (ARCHIVE_WARN); } - if (a->archive_format == ARCHIVE_FORMAT_AR_GNU) { + if (a->archive.archive_format == ARCHIVE_FORMAT_AR_GNU) { /* * SVR4/GNU variant use a "/" to mark then end of the filename, * make it possible to have embedded spaces in the filename. @@ -261,7 +264,7 @@ archive_write_ar_header(struct archive_write *a, struct archive_entry *entry) return (ARCHIVE_WARN); } } - } else if (a->archive_format == ARCHIVE_FORMAT_AR_BSD) { + } else if (a->archive.archive_format == ARCHIVE_FORMAT_AR_BSD) { /* * BSD variant: for any file name which is more than * 16 chars or contains one or more embedded space(s), the @@ -285,8 +288,7 @@ archive_write_ar_header(struct archive_write *a, struct archive_entry *entry) return (ARCHIVE_WARN); } append_fn = 1; - archive_entry_set_size(entry, - archive_entry_size(entry) + strlen(filename)); + size += strlen(filename); } } @@ -322,8 +324,7 @@ stat: } size: - if (format_decimal(archive_entry_size(entry), buff + AR_size_offset, - AR_size_size)) { + if (format_decimal(size, buff + AR_size_offset, AR_size_size)) { archive_set_error(&a->archive, ERANGE, "File size out of range"); return (ARCHIVE_WARN); @@ -333,7 +334,7 @@ size: if (ret != ARCHIVE_OK) return (ret); - ar->entry_bytes_remaining = archive_entry_size(entry); + ar->entry_bytes_remaining = size; ar->entry_padding = ar->entry_bytes_remaining % 2; if (append_fn > 0) { diff --git a/contrib/libarchive-2/libarchive/archive_write_set_format_cpio.c b/contrib/libarchive-2/libarchive/archive_write_set_format_cpio.c index 45cb4e74b6..61042999ef 100644 --- a/contrib/libarchive-2/libarchive/archive_write_set_format_cpio.c +++ b/contrib/libarchive-2/libarchive/archive_write_set_format_cpio.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_cpio.c,v 1.13 2007/12/30 04:58:22 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_cpio.c,v 1.14 2008/03/15 11:04:45 kientzle Exp $"); #ifdef HAVE_ERRNO_H #include @@ -97,8 +97,8 @@ archive_write_set_format_cpio(struct archive *_a) a->format_finish_entry = archive_write_cpio_finish_entry; a->format_finish = archive_write_cpio_finish; a->format_destroy = archive_write_cpio_destroy; - a->archive_format = ARCHIVE_FORMAT_CPIO_POSIX; - a->archive_format_name = "POSIX cpio"; + a->archive.archive_format = ARCHIVE_FORMAT_CPIO_POSIX; + a->archive.archive_format_name = "POSIX cpio"; return (ARCHIVE_OK); } diff --git a/contrib/libarchive-2/libarchive/archive_write_set_format_cpio_newc.c b/contrib/libarchive-2/libarchive/archive_write_set_format_cpio_newc.c index d11176c1c1..b5a2a02841 100644 --- a/contrib/libarchive-2/libarchive/archive_write_set_format_cpio_newc.c +++ b/contrib/libarchive-2/libarchive/archive_write_set_format_cpio_newc.c @@ -25,7 +25,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_cpio_newc.c,v 1.3 2008/01/23 05:43:25 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_cpio_newc.c,v 1.4 2008/03/15 11:04:45 kientzle Exp $"); #ifdef HAVE_ERRNO_H #include @@ -102,8 +102,8 @@ archive_write_set_format_cpio_newc(struct archive *_a) a->format_finish_entry = archive_write_newc_finish_entry; a->format_finish = archive_write_newc_finish; a->format_destroy = archive_write_newc_destroy; - a->archive_format = ARCHIVE_FORMAT_CPIO_SVR4_NOCRC; - a->archive_format_name = "SVR4 cpio nocrc"; + a->archive.archive_format = ARCHIVE_FORMAT_CPIO_SVR4_NOCRC; + a->archive.archive_format_name = "SVR4 cpio nocrc"; return (ARCHIVE_OK); } diff --git a/contrib/libarchive-2/libarchive/archive_write_set_format_pax.c b/contrib/libarchive-2/libarchive/archive_write_set_format_pax.c index a1bd688115..89f89bc9f5 100644 --- a/contrib/libarchive-2/libarchive/archive_write_set_format_pax.c +++ b/contrib/libarchive-2/libarchive/archive_write_set_format_pax.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_pax.c,v 1.42 2007/12/30 04:58:22 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_pax.c,v 1.46 2008/03/15 11:04:45 kientzle Exp $"); #ifdef HAVE_ERRNO_H #include @@ -85,8 +85,8 @@ archive_write_set_format_pax_restricted(struct archive *_a) struct archive_write *a = (struct archive_write *)_a; int r; r = archive_write_set_format_pax(&a->archive); - a->archive_format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED; - a->archive_format_name = "restricted POSIX pax interchange"; + a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED; + a->archive.archive_format_name = "restricted POSIX pax interchange"; return (r); } @@ -116,8 +116,8 @@ archive_write_set_format_pax(struct archive *_a) a->format_finish = archive_write_pax_finish; a->format_destroy = archive_write_pax_destroy; a->format_finish_entry = archive_write_pax_finish_entry; - a->archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE; - a->archive_format_name = "POSIX pax interchange"; + a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE; + a->archive.archive_format_name = "POSIX pax interchange"; return (ARCHIVE_OK); } @@ -386,7 +386,7 @@ archive_write_pax_header(struct archive_write *a, const char *p; char *t; const wchar_t *wp; - const char *suffix_start; + const char *suffix; int need_extension, r, ret; struct pax *pax; const char *hdrcharset = NULL; @@ -496,34 +496,73 @@ archive_write_pax_header(struct archive_write *a, if (hdrcharset != NULL) add_pax_attr(&(pax->pax_header), "hdrcharset", hdrcharset); - /* - * Determining whether or not the name is too big is ugly - * because of the rules for dividing names between 'name' and - * 'prefix' fields. Here, I pick out the longest possible - * suffix, then test whether the remaining prefix is too long. - */ - if (strlen(path) <= 100) /* Short enough for just 'name' field */ - suffix_start = path; /* Record a zero-length prefix */ - else - /* Find the largest suffix that fits in 'name' field. */ - suffix_start = strchr(path + strlen(path) - 100 - 1, '/'); /* * If name is too long, or has non-ASCII characters, add * 'path' to pax extended attrs. (Note that an unconvertible * name must have non-ASCII characters.) */ - if (suffix_start == NULL || suffix_start - path > 155 - || path_w == NULL || has_non_ASCII(path_w)) { - if (path_w == NULL || hdrcharset != NULL) + if (path == NULL) { + /* We don't have a narrow version, so we have to store + * the wide version. */ + add_pax_attr_w(&(pax->pax_header), "path", path_w); + archive_entry_set_pathname(entry_main, "@WidePath"); + need_extension = 1; + } else if (has_non_ASCII(path_w)) { + /* We have non-ASCII characters. */ + if (path_w == NULL || hdrcharset != NULL) { /* Can't do UTF-8, so store it raw. */ add_pax_attr(&(pax->pax_header), "path", path); - else - add_pax_attr_w(&(pax->pax_header), "path", path_w); + } else { + /* Store UTF-8 */ + add_pax_attr_w(&(pax->pax_header), + "path", path_w); + } archive_entry_set_pathname(entry_main, build_ustar_entry_name(ustar_entry_name, path, strlen(path), NULL)); need_extension = 1; + } else { + /* We have an all-ASCII path; we'd like to just store + * it in the ustar header if it will fit. Yes, this + * duplicates some of the logic in + * write_set_format_ustar.c + */ + if (strlen(path) <= 100) { + /* Fits in the old 100-char tar name field. */ + } else { + /* Find largest suffix that will fit. */ + /* Note: strlen() > 100, so strlen() - 100 - 1 >= 0 */ + suffix = strchr(path + strlen(path) - 100 - 1, '/'); + /* Don't attempt an empty prefix. */ + if (suffix == path) + suffix = strchr(suffix + 1, '/'); + /* We can put it in the ustar header if it's + * all ASCII and it's either <= 100 characters + * or can be split at a '/' into a prefix <= + * 155 chars and a suffix <= 100 chars. (Note + * the strchr() above will return NULL exactly + * when the path can't be split.) + */ + if (suffix == NULL /* Suffix > 100 chars. */ + || suffix[1] == '\0' /* empty suffix */ + || suffix - path > 155) /* Prefix > 155 chars */ + { + if (path_w == NULL || hdrcharset != NULL) { + /* Can't do UTF-8, so store it raw. */ + add_pax_attr(&(pax->pax_header), + "path", path); + } else { + /* Store UTF-8 */ + add_pax_attr_w(&(pax->pax_header), + "path", path_w); + } + archive_entry_set_pathname(entry_main, + build_ustar_entry_name(ustar_entry_name, + path, strlen(path), NULL)); + need_extension = 1; + } + } } if (linkpath != NULL) { @@ -701,7 +740,7 @@ archive_write_pax_header(struct archive_write *a, * already set (we're already generating an extended header, so * may as well include these). */ - if (a->archive_format != ARCHIVE_FORMAT_TAR_PAX_RESTRICTED || + if (a->archive.archive_format != ARCHIVE_FORMAT_TAR_PAX_RESTRICTED || need_extension) { if (archive_entry_mtime(entry_main) < 0 || @@ -764,7 +803,7 @@ archive_write_pax_header(struct archive_write *a, * Pax-restricted does not store data for hardlinks, in order * to improve compatibility with ustar. */ - if (a->archive_format != ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE && + if (a->archive.archive_format != ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE && hardlink != NULL) archive_entry_set_size(entry_main, 0); @@ -1060,7 +1099,13 @@ build_ustar_entry_name(char *dest, const char *src, size_t src_length, /* * The ustar header for the pax extended attributes must have a - * reasonable name: SUSv3 suggests 'dirname'/PaxHeader/'filename' + * reasonable name: SUSv3 requires 'dirname'/PaxHeader.'pid'/'filename' + * where 'pid' is the PID of the archiving process. Unfortunately, + * that makes testing a pain since the output varies for each run, + * so I'm sticking with the simpler 'dirname'/PaxHeader/'filename' + * for now. (Someday, I'll make this settable. Then I can use the + * SUS recommendation as default and test harnesses can override it + * to get predictable results.) * * Joerg Schilling has argued that this is unnecessary because, in * practice, if the pax extended attributes get extracted as regular @@ -1071,19 +1116,14 @@ build_ustar_entry_name(char *dest, const char *src, size_t src_length, * recommendation, but I'm not entirely convinced. I'm also * uncomfortable with the fact that "/tmp" is a Unix-ism. * - * GNU tar uses 'dirname'/PaxHeader./'filename', where the PID is - * the PID of the archiving process. This seems unnecessarily complex - * to me, as I don't see much value to separating the headers from - * extracting multiple versions of an archive. - * - * The following routine implements the SUSv3 recommendation, and is - * much simpler because build_ustar_entry_name() above already does - * most of the work (we just need to give it an extra path element to - * insert and handle a few pathological cases). + * The following routine leverages build_ustar_entry_name() above and + * so is simpler than you might think. It just needs to provide the + * additional path element and handle a few pathological cases). */ static char * build_pax_attribute_name(char *dest, const char *src) { + char buff[64]; const char *p; /* Handle the null filename case. */ @@ -1122,8 +1162,19 @@ build_pax_attribute_name(char *dest, const char *src) return (dest); } + /* + * TODO: Push this string into the 'pax' structure to avoid + * recomputing it every time. That will also open the door + * to having clients override it. + */ +#if HAVE_GETPID && 0 /* Disable this for now; see above comment. */ + sprintf(buff, "PaxHeader.%d", getpid()); +#else + /* If the platform can't fetch the pid, don't include it. */ + strcpy(buff, "PaxHeader"); +#endif /* General case: build a ustar-compatible name adding "/PaxHeader/". */ - build_ustar_entry_name(dest, src, p - src, "PaxHeader"); + build_ustar_entry_name(dest, src, p - src, buff); return (dest); } @@ -1203,6 +1254,8 @@ archive_write_pax_data(struct archive_write *a, const void *buff, size_t s) static int has_non_ASCII(const wchar_t *wp) { + if (wp == NULL) + return (1); while (*wp != L'\0' && *wp < 128) wp++; return (*wp != L'\0'); diff --git a/contrib/libarchive-2/libarchive/archive_write_set_format_shar.c b/contrib/libarchive-2/libarchive/archive_write_set_format_shar.c index f26ba028ea..b5d16e09d1 100644 --- a/contrib/libarchive-2/libarchive/archive_write_set_format_shar.c +++ b/contrib/libarchive-2/libarchive/archive_write_set_format_shar.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_shar.c,v 1.18 2007/05/29 01:00:19 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_shar.c,v 1.19 2008/03/15 11:04:45 kientzle Exp $"); #ifdef HAVE_ERRNO_H #include @@ -113,8 +113,8 @@ archive_write_set_format_shar(struct archive *_a) a->format_destroy = archive_write_shar_destroy; a->format_write_data = archive_write_shar_data_sed; a->format_finish_entry = archive_write_shar_finish_entry; - a->archive_format = ARCHIVE_FORMAT_SHAR_BASE; - a->archive_format_name = "shar"; + a->archive.archive_format = ARCHIVE_FORMAT_SHAR_BASE; + a->archive.archive_format_name = "shar"; return (ARCHIVE_OK); } @@ -134,8 +134,8 @@ archive_write_set_format_shar_dump(struct archive *_a) shar = (struct shar *)a->format_data; shar->dump = 1; a->format_write_data = archive_write_shar_data_uuencode; - a->archive_format = ARCHIVE_FORMAT_SHAR_DUMP; - a->archive_format_name = "shar dump"; + a->archive.archive_format = ARCHIVE_FORMAT_SHAR_DUMP; + a->archive.archive_format_name = "shar dump"; return (ARCHIVE_OK); } diff --git a/contrib/libarchive-2/libarchive/archive_write_set_format_ustar.c b/contrib/libarchive-2/libarchive/archive_write_set_format_ustar.c index a7d26c9057..970fee8db1 100644 --- a/contrib/libarchive-2/libarchive/archive_write_set_format_ustar.c +++ b/contrib/libarchive-2/libarchive/archive_write_set_format_ustar.c @@ -24,7 +24,7 @@ */ #include "archive_platform.h" -__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_ustar.c,v 1.25 2007/12/30 04:58:22 kientzle Exp $"); +__FBSDID("$FreeBSD: src/lib/libarchive/archive_write_set_format_ustar.c,v 1.26 2008/03/15 11:04:45 kientzle Exp $"); #ifdef HAVE_ERRNO_H @@ -186,8 +186,8 @@ archive_write_set_format_ustar(struct archive *_a) a->format_finish = archive_write_ustar_finish; a->format_destroy = archive_write_ustar_destroy; a->format_finish_entry = archive_write_ustar_finish_entry; - a->archive_format = ARCHIVE_FORMAT_TAR_USTAR; - a->archive_format_name = "POSIX ustar"; + a->archive.archive_format = ARCHIVE_FORMAT_TAR_USTAR; + a->archive.archive_format_name = "POSIX ustar"; return (ARCHIVE_OK); } @@ -195,7 +195,7 @@ static int archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry) { char buff[512]; - int ret; + int ret, ret2; struct ustar *ustar; ustar = (struct ustar *)a->format_data; @@ -206,7 +206,7 @@ archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry) !(archive_entry_filetype(entry) == AE_IFREG)) archive_entry_set_size(entry, 0); - if (AE_IFDIR == archive_entry_mode(entry)) { + if (AE_IFDIR == archive_entry_filetype(entry)) { const char *p; char *t; /* @@ -229,15 +229,17 @@ archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry) } ret = __archive_write_format_header_ustar(a, buff, entry, -1, 1); - if (ret != ARCHIVE_OK) - return (ret); - ret = (a->compressor.write)(a, buff, 512); - if (ret != ARCHIVE_OK) + if (ret < ARCHIVE_WARN) return (ret); + ret2 = (a->compressor.write)(a, buff, 512); + if (ret2 < ARCHIVE_WARN) + return (ret2); + if (ret2 < ret) + ret = ret2; ustar->entry_bytes_remaining = archive_entry_size(entry); ustar->entry_padding = 0x1ff & (-(int64_t)ustar->entry_bytes_remaining); - return (ARCHIVE_OK); + return (ret); } /* @@ -282,27 +284,33 @@ __archive_write_format_header_ustar(struct archive_write *a, char h[512], /* Store in two pieces, splitting at a '/'. */ p = strchr(pp + strlen(pp) - USTAR_name_size - 1, '/'); /* - * If the separator we found is the first '/', find - * the next one. (This is a pathological case that - * occurs for paths of exactly 101 bytes that start with - * '/'; it occurs because the separating '/' is not - * stored explicitly and the reconstruction assumes that - * an empty prefix means there is no '/' separator.) + * Look for the next '/' if we chose the first character + * as the separator. (ustar format doesn't permit + * an empty prefix.) */ if (p == pp) p = strchr(p + 1, '/'); - /* - * If there is no path separator, or the prefix or - * remaining name are too large, return an error. - */ + /* Fail if the name won't fit. */ if (!p) { + /* No separator. */ + archive_set_error(&a->archive, ENAMETOOLONG, + "Pathname too long"); + ret = ARCHIVE_FAILED; + } else if (p[1] == '\0') { + /* + * The only feasible separator is a final '/'; + * this would result in a non-empty prefix and + * an empty name, which POSIX doesn't + * explicity forbid, but it just feels wrong. + */ archive_set_error(&a->archive, ENAMETOOLONG, "Pathname too long"); - ret = ARCHIVE_WARN; + ret = ARCHIVE_FAILED; } else if (p > pp + USTAR_prefix_size) { + /* Prefix is too long. */ archive_set_error(&a->archive, ENAMETOOLONG, "Pathname too long"); - ret = ARCHIVE_WARN; + ret = ARCHIVE_FAILED; } else { /* Copy prefix and remainder to appropriate places */ memcpy(h + USTAR_prefix_offset, pp, p - pp); @@ -320,7 +328,7 @@ __archive_write_format_header_ustar(struct archive_write *a, char h[512], if (copy_length > USTAR_linkname_size) { archive_set_error(&a->archive, ENAMETOOLONG, "Link contents too long"); - ret = ARCHIVE_WARN; + ret = ARCHIVE_FAILED; copy_length = USTAR_linkname_size; } memcpy(h + USTAR_linkname_offset, p, copy_length); @@ -332,7 +340,7 @@ __archive_write_format_header_ustar(struct archive_write *a, char h[512], if (copy_length > USTAR_uname_size) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Username too long"); - ret = ARCHIVE_WARN; + ret = ARCHIVE_FAILED; copy_length = USTAR_uname_size; } memcpy(h + USTAR_uname_offset, p, copy_length); @@ -344,7 +352,7 @@ __archive_write_format_header_ustar(struct archive_write *a, char h[512], if (strlen(p) > USTAR_gname_size) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Group name too long"); - ret = ARCHIVE_WARN; + ret = ARCHIVE_FAILED; copy_length = USTAR_gname_size; } memcpy(h + USTAR_gname_offset, p, copy_length); @@ -352,28 +360,28 @@ __archive_write_format_header_ustar(struct archive_write *a, char h[512], if (format_number(archive_entry_mode(entry) & 07777, h + USTAR_mode_offset, USTAR_mode_size, USTAR_mode_max_size, strict)) { archive_set_error(&a->archive, ERANGE, "Numeric mode too large"); - ret = ARCHIVE_WARN; + ret = ARCHIVE_FAILED; } if (format_number(archive_entry_uid(entry), h + USTAR_uid_offset, USTAR_uid_size, USTAR_uid_max_size, strict)) { archive_set_error(&a->archive, ERANGE, "Numeric user ID too large"); - ret = ARCHIVE_WARN; + ret = ARCHIVE_FAILED; } if (format_number(archive_entry_gid(entry), h + USTAR_gid_offset, USTAR_gid_size, USTAR_gid_max_size, strict)) { archive_set_error(&a->archive, ERANGE, "Numeric group ID too large"); - ret = ARCHIVE_WARN; + ret = ARCHIVE_FAILED; } if (format_number(archive_entry_size(entry), h + USTAR_size_offset, USTAR_size_size, USTAR_size_max_size, strict)) { archive_set_error(&a->archive, ERANGE, "File size out of range"); - ret = ARCHIVE_WARN; + ret = ARCHIVE_FAILED; } if (format_number(archive_entry_mtime(entry), h + USTAR_mtime_offset, USTAR_mtime_size, USTAR_mtime_max_size, strict)) { archive_set_error(&a->archive, ERANGE, "File modification time too large"); - ret = ARCHIVE_WARN; + ret = ARCHIVE_FAILED; } if (archive_entry_filetype(entry) == AE_IFBLK @@ -382,14 +390,14 @@ __archive_write_format_header_ustar(struct archive_write *a, char h[512], USTAR_rdevmajor_size, USTAR_rdevmajor_max_size, strict)) { archive_set_error(&a->archive, ERANGE, "Major device number too large"); - ret = ARCHIVE_WARN; + ret = ARCHIVE_FAILED; } if (format_number(archive_entry_rdevminor(entry), h + USTAR_rdevminor_offset, USTAR_rdevminor_size, USTAR_rdevminor_max_size, strict)) { archive_set_error(&a->archive, ERANGE, "Minor device number too large"); - ret = ARCHIVE_WARN; + ret = ARCHIVE_FAILED; } } @@ -409,7 +417,7 @@ __archive_write_format_header_ustar(struct archive_write *a, char h[512], archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT, "tar format cannot archive this (mode=0%lo)", (unsigned long)archive_entry_mode(entry)); - ret = ARCHIVE_WARN; + ret = ARCHIVE_FAILED; } } diff --git a/contrib/libarchive-2/libarchive/cpio.5 b/contrib/libarchive-2/libarchive/cpio.5 index 9dbdc6d840..8f024c546a 100644 --- a/contrib/libarchive-2/libarchive/cpio.5 +++ b/contrib/libarchive-2/libarchive/cpio.5 @@ -149,7 +149,7 @@ followed by the least-significant 16 bits. Each of the two 16 bit values are stored in machine-native byte order. .It Va namesize The number of bytes in the pathname that follows the header. -This count includes the trailing NULL byte. +This count includes the trailing NUL byte. .It Va filesize The size of the file. Note that this archive format is limited to @@ -162,8 +162,8 @@ above for a description of the storage of four-byte integers. The pathname immediately follows the fixed header. If the .Cm namesize -is odd, an additional NULL byte is added after the pathname. -The file data is then appended, padded with NULL +is odd, an additional NUL byte is added after the pathname. +The file data is then appended, padded with NUL bytes to an even length. .Pp Hardlinked files are not given special treatment; @@ -202,7 +202,7 @@ Unlike the old binary format, there is no additional padding after the pathname or file contents. If the files being archived are themselves entirely ASCII, then the resulting archive will be entirely ASCII, except for the -NULL byte that terminates the name field. +NUL byte that terminates the name field. .Ss New ASCII Format The "new" ASCII format uses 8-byte hexadecimal fields for all numbers and separates device numbers into separate fields @@ -237,7 +237,7 @@ This field is always set to zero by writers and ignored by readers. See the next section for more details. .El .Pp -The pathname is followed by NULL bytes so that the total size +The pathname is followed by NUL bytes so that the total size of the fixed header plus pathname is a multiple of four. Likewise, the file data is padded to a multiple of four bytes. Note that this format supports only 4 gigabyte files (unlike the @@ -322,4 +322,4 @@ by SCO under their license. The character format was adopted as part of .St -p1003.1-88 . -XXX when did "newc" appear? Who invented it? When did HP come out with their variant? When did Sun introduce ACLs and extended attributes? XXX \ No newline at end of file +XXX when did "newc" appear? Who invented it? When did HP come out with their variant? When did Sun introduce ACLs and extended attributes? XXX diff --git a/contrib/libarchive-2/libarchive/filter_fork.c b/contrib/libarchive-2/libarchive/filter_fork.c index 8cad9e2f09..3c2d829d05 100644 --- a/contrib/libarchive-2/libarchive/filter_fork.c +++ b/contrib/libarchive-2/libarchive/filter_fork.c @@ -25,6 +25,9 @@ #include "archive_platform.h" +/* This capability is only available on POSIX systems. */ +#if defined(HAVE_PIPE) && defined(HAVE_VFORK) && defined(HAVE_FCNTL) + __FBSDID("$FreeBSD: src/lib/libarchive/filter_fork.c,v 1.2 2007/12/30 04:58:22 kientzle Exp $"); #if defined(HAVE_POLL) @@ -137,3 +140,5 @@ __archive_check_child(int in, int out) sleep(1); #endif } + +#endif /* defined(HAVE_PIPE) && defined(HAVE_VFORK) && defined(HAVE_FCNTL) */ diff --git a/contrib/libarchive-2/libarchive/libarchive-formats.5 b/contrib/libarchive-2/libarchive/libarchive-formats.5 index 0346d8f5af..f570935c82 100644 --- a/contrib/libarchive-2/libarchive/libarchive-formats.5 +++ b/contrib/libarchive-2/libarchive/libarchive-formats.5 @@ -259,6 +259,14 @@ There are two common variants: the GNU format derived from SVR4, and the BSD format, which first appeared in 4.4BSD. Libarchive provides read and write support for both variants. +.Ss mtree +Libarchive can read files in +.Xr mtree 5 +format. This format is not a true archive format, but rather a description +of a file hierarchy. When requested, libarchive obtains the contents of +the files described by the +.Xr mtree 5 +format from files on disk instead. .Sh SEE ALSO .Xr ar 1 , .Xr cpio 1 , diff --git a/contrib/libarchive-2/libarchive/mtree.5 b/contrib/libarchive-2/libarchive/mtree.5 index 613de6a5da..b6637d6f55 100644 --- a/contrib/libarchive-2/libarchive/mtree.5 +++ b/contrib/libarchive-2/libarchive/mtree.5 @@ -33,12 +33,12 @@ .Os .Sh NAME .Nm mtree -.Nd format of mtree dir heirarchy files +.Nd format of mtree dir hierarchy files .Sh DESCRIPTION The .Nm format is a textual format that describes a collection of filesystem objects. -Such files are typically used to create or verify directory heirarchies. +Such files are typically used to create or verify directory hierarchies. .Ss General Format An .Nm @@ -121,7 +121,7 @@ separated by whitespace. .Ss Keywords After the filename, a full or relative entry consists of zero or more whitespace-separated keyword definitions. -Each such definitions consists of a key from the following +Each such definition consists of a key from the following list immediately followed by an '=' sign and a value. Software programs reading mtree files should warn about @@ -135,8 +135,7 @@ the .Xr cksum 1 utility. .It Cm contents -The full pathname of a file whose contents should be -compared to the contents of this file. +The full pathname of a file that holds the contents of this file. .It Cm flags The file flags as a symbolic name. See @@ -145,17 +144,36 @@ for information on these names. If no flags are to be set the string .Dq none may be used to override the current default. -.It Cm ignore -Ignore any file hierarchy below this file. .It Cm gid The file group as a numeric value. .It Cm gname The file group as a symbolic name. +.It Cm ignore +Ignore any file hierarchy below this file. +.It Cm link +The target of the symbolic link when type=link. .It Cm md5 The MD5 message digest of the file. .It Cm md5digest A synonym for .Cm md5 . +.It Cm mode +The current file's permissions as a numeric (octal) or symbolic +value. +.It Cm nlink +The number of hard links the file is expected to have. +.It Cm nochange +Make sure this file or directory exists but otherwise ignore all attributes. +.It Cm ripemd160digest +The +.Tn RIPEMD160 +message digest of the file. +.It Cm rmd160 +A synonym for +.Cm ripemd160digest . +.It Cm rmd160digest +A synonym for +.Cm ripemd160digest . .It Cm sha1 The .Tn FIPS @@ -174,31 +192,8 @@ message digest of the file. .It Cm sha256digest A synonym for .Cm sha256 . -.It Cm ripemd160digest -The -.Tn RIPEMD160 -message digest of the file. -.It Cm rmd160 -A synonym for -.Cm ripemd160digest . -.It Cm rmd160digest -A synonym for -.Cm ripemd160digest . -.It Cm mode -The current file's permissions as a numeric (octal) or symbolic -value. -.It Cm nlink -The number of hard links the file is expected to have. -.It Cm nochange -Make sure this file or directory exists but otherwise ignore all attributes. -.It Cm uid -The file owner as a numeric value. -.It Cm uname -The file owner as a symbolic name. .It Cm size The size, in bytes, of the file. -.It Cm link -The file the symbolic link is expected to reference. .It Cm time The last modification time of the file. .It Cm type @@ -220,6 +215,10 @@ symbolic link .It Cm socket socket .El +.It Cm uid +The file owner as a numeric value. +.It Cm uname +The file owner as a symbolic name. .El .Pp .Sh SEE ALSO diff --git a/contrib/libarchive-2/libarchive/tar.5 b/contrib/libarchive-2/libarchive/tar.5 index ab39df3338..c873a938f4 100644 --- a/contrib/libarchive-2/libarchive/tar.5 +++ b/contrib/libarchive-2/libarchive/tar.5 @@ -221,7 +221,7 @@ field with several new type values: .Bl -tag -width indent -compact .It Dq 0 Regular file. -NULL should be treated as a synonym, for compatibility purposes. +NUL should be treated as a synonym, for compatibility purposes. .It Dq 1 Hard link. .It Dq 2 @@ -258,7 +258,7 @@ by readers. .It Va magic Contains the magic value .Dq ustar -followed by a NULL byte to indicate that this is a POSIX standard archive. +followed by a NUL byte to indicate that this is a POSIX standard archive. Full compliance requires the uname and gname fields be properly set. .It Va version Version. @@ -285,7 +285,7 @@ character to the regular name field to obtain the full pathname. .El .Pp Note that all unused bytes must be set to -.Dv NULL . +.Dv NUL . .Pp Field termination is specified slightly differently by POSIX than by previous implementations. @@ -295,14 +295,14 @@ The and .Va gname fields must have a trailing -.Dv NULL . +.Dv NUL . The .Va pathname , .Va linkname , and .Va prefix fields must have a trailing -.Dv NULL +.Dv NUL unless they fill the entire field. (In particular, it is possible to store a 256-character pathname if it happens to have a @@ -310,7 +310,7 @@ happens to have a as the 156th character.) POSIX requires numeric fields to be zero-padded in the front, and allows them to be terminated with either space or -.Dv NULL +.Dv NUL characters. .Pp Currently, most tar implementations comply with the ustar diff --git a/contrib/libarchive-2/tar/bsdtar.1 b/contrib/libarchive-2/tar/bsdtar.1 index ec22160d99..542b0f3f50 100644 --- a/contrib/libarchive-2/tar/bsdtar.1 +++ b/contrib/libarchive-2/tar/bsdtar.1 @@ -22,9 +22,9 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.\" $FreeBSD: src/usr.bin/tar/bsdtar.1,v 1.37 2008/01/22 07:23:44 kientzle Exp $ +.\" $FreeBSD: src/usr.bin/tar/bsdtar.1,v 1.42 2008/05/17 15:55:29 cperciva Exp $ .\" -.Dd April 13, 2004 +.Dd May 15, 2008 .Dt BSDTAR 1 .Os .Sh NAME @@ -147,13 +147,19 @@ but before extracting entries from the archive. .It Fl -check-links ( Fl W Cm check-links ) (c and r modes only) Issue a warning message unless all links to each file are archived. +.It Fl -chroot ( Fl W Cm chroot ) +(x mode only) +.Fn chroot +to the current directory after processing any +.Fl C +options and before extracting any files. .It Fl -exclude Ar pattern ( Fl W Cm exclude Ns = Ns Ar pattern ) Do not process files or directories that match the specified pattern. Note that exclusions take precedence over patterns or filenames specified on the command line. .It Fl -format Ar format ( Fl W Cm format Ns = Ns Ar format ) -(c mode only) +(c, r, u mode only) Use the specified format for the created archive. Supported formats include .Dq cpio , @@ -164,6 +170,8 @@ and Other formats may also be supported; see .Xr libarchive-formats 5 for more information about currently-supported formats. +In r and u modes, when extending an existing archive, the format specified +here must be compatible with the format of the existing archive on disk. .It Fl f Ar file Read the archive from or write the archive to the specified file. The filename can be @@ -174,15 +182,6 @@ If not specified, the default tape device will be used. .Fx , the default tape device is .Pa /dev/sa0 . ) -.It Fl -fast-read ( Fl W Cm fast-read ) -(x and t mode only) -Extract or list only the first archive entry that matches each pattern -or filename operand. -Exit as soon as each specified pattern or filename has been matched. -By default, the archive is always read to the very end, since -there can be multiple entries with the same name and, by convention, -later entries overwrite earlier entries. -This option is provided as a performance optimization. .It Fl H (c and r mode only) Symbolic links named on the command line will be followed; the @@ -226,6 +225,10 @@ automatically when reading archives. Do not overwrite existing files. In particular, if a file appears more than once in an archive, later copies will not overwrite earlier copies. +.It Fl -keep-newer-files ( Fl W Cm keep-newer-files ) +(x mode only) +Do not overwrite existing files that are newer than the +versions appearing in the archive being extracted. .It Fl L (c and r mode only) All symbolic links will be followed. @@ -275,6 +278,10 @@ This is often used to read filenames output by the .Fl print0 option to .Xr find 1 . +.It Fl -numeric-owner +(x mode only) +Ignore symbolic user and group names when restoring archives to disk, +only numeric uid and gid values will be obeyed. .It Fl O (x, t modes only) In extract (-x) mode, files will be written to standard out rather than @@ -282,7 +289,7 @@ being extracted to disk. In list (-t) mode, the file listing will be written to stderr rather than the usual stdout. .It Fl o -(x mode only) +(x mode) Use the user and group of the user running the program rather than those specified in the archive. Note that this has no significance unless @@ -291,6 +298,10 @@ is specified, and the program is being run by the root user. In this case, the file modes and flags from the archive will be restored, but ACLs or owner information in the archive will be discarded. +.It Fl o +(c, r, u mode) +A synonym for +.Fl -format Ar ustar .It Fl -one-file-system ( Fl W Cm one-file-system ) (c, r, and u modes) Do not cross mount points. @@ -319,12 +330,43 @@ If is being run by root, the default is to restore the owner unless the .Fl o option is also specified. +.It Fl q ( Fl -fast-read ) +(x and t mode only) +Extract or list only the first archive entry that matches each pattern +or filename operand. +Exit as soon as each specified pattern or filename has been matched. +By default, the archive is always read to the very end, since +there can be multiple entries with the same name and, by convention, +later entries overwrite earlier entries. +This option is provided as a performance optimization. +.It Fl S +(x mode only) +Extract files as sparse files. +For every block on disk, check first if it contains only NULL bytes and seek +over it otherwise. +This works similiar to the conv=sparse option of dd. .It Fl -strip-components Ar count ( Fl W Cm strip-components Ns = Ns Ar count ) (x and t mode only) Remove the specified number of leading path elements. Pathnames with fewer elements will be silently skipped. Note that the pathname is edited after checking inclusion/exclusion patterns but before security checks. +.It Fl s Ar pattern +Modify file or archive member names according to +.Pa pattern . +The pattern has the format /old/new/[gps]. +old is a basic regular expression. +If it doesn't apply, the pattern is skipped. +new is the replacement string of the matched part. +~ is substituted with the match, \1 to \9 with the content of +the corresponding captured group. +The optional trailing g specifies that matching should continue +after the matched part and stopped on the first unmatched pattern. +The optional trailing s specifies that the pattern applies to the value +of symbolic links. +The optional trailing p specifies that after a successful substitution +the original path name and the new path name should be printed to +standard error. .It Fl T Ar filename In x or t mode, .Nm @@ -405,6 +447,15 @@ Note that, unlike other .Nm tar implementations, this implementation recognizes gzip compression automatically when reading archives. +.It Fl Z +(c mode only) +Compress the resulting archive with +.Xr compress 1 . +In extract or list modes, this option is ignored. +Note that, unlike other +.Nm tar +implementations, this implementation recognizes compress compression +automatically when reading archives. .El .Sh ENVIRONMENT The following environment variables affect the execution of @@ -487,6 +538,16 @@ directory and add .Pa foo2 to the output archive. .Pp +An input file in +.Xr mtree 5 +format can be used to create an output archive with arbitrary ownership, +permissions, or names that differ from existing data on disk: +.Pp +.Dl $ cat input.mtree +.Dl usr/bin uid=0 gid=0 mode=0755 type=dir +.Dl usr/bin/ls uid=0 gid=0 mode=0755 type=file content=myls +.Dl $ tar -cvf output.tar @input.mtree +.Pp The .Fl -newer and @@ -628,6 +689,7 @@ an archive while preserving any absolute pathnames, components, or symlinks to other directories. .Sh SEE ALSO .Xr bzip2 1 , +.Xr compress 1 , .Xr cpio 1 , .Xr gzip 1 , .Xr mt 1 , diff --git a/contrib/libarchive-2/tar/bsdtar.c b/contrib/libarchive-2/tar/bsdtar.c index fbc66c1d73..2491dda6bc 100644 --- a/contrib/libarchive-2/tar/bsdtar.c +++ b/contrib/libarchive-2/tar/bsdtar.c @@ -24,7 +24,7 @@ */ #include "bsdtar_platform.h" -__FBSDID("$FreeBSD: src/usr.bin/tar/bsdtar.c,v 1.79 2008/01/22 07:23:44 kientzle Exp $"); +__FBSDID("$FreeBSD: src/usr.bin/tar/bsdtar.c,v 1.90 2008/05/19 18:38:01 cperciva Exp $"); #ifdef HAVE_SYS_PARAM_H #include @@ -118,7 +118,7 @@ static void version(void); * non-option. Otherwise, GNU getopt() permutes the arguments and * screws up -C processing. */ -static const char *tar_opts = "+Bb:C:cf:HhI:jkLlmnOoPprtT:UuvW:wX:xyZz"; +static const char *tar_opts = "+Bb:C:cf:HhI:jkLlmnOoPprts:ST:UuvW:wX:xyZz"; /* * Most of these long options are deliberately not documented. They @@ -136,12 +136,13 @@ static const char *tar_opts = "+Bb:C:cf:HhI:jkLlmnOoPprtT:UuvW:wX:xyZz"; /* Fake short equivalents for long options that otherwise lack them. */ enum { - OPTION_CHECK_LINKS=1, + OPTION_CHECK_LINKS = 1, + OPTION_CHROOT, OPTION_EXCLUDE, - OPTION_FAST_READ, OPTION_FORMAT, OPTION_HELP, OPTION_INCLUDE, + OPTION_KEEP_NEWER_FILES, OPTION_NEWER_CTIME, OPTION_NEWER_CTIME_THAN, OPTION_NEWER_MTIME, @@ -150,6 +151,7 @@ enum { OPTION_NO_SAME_OWNER, OPTION_NO_SAME_PERMISSIONS, OPTION_NULL, + OPTION_NUMERIC_OWNER, OPTION_ONE_FILE_SYSTEM, OPTION_POSIX, OPTION_STRIP_COMPONENTS, @@ -171,6 +173,8 @@ static const struct option tar_longopts[] = { { "bzip2", no_argument, NULL, 'j' }, { "cd", required_argument, NULL, 'C' }, { "check-links", no_argument, NULL, OPTION_CHECK_LINKS }, + { "chroot", no_argument, NULL, OPTION_CHROOT }, + { "compress", no_argument, NULL, 'Z' }, { "confirmation", no_argument, NULL, 'w' }, { "create", no_argument, NULL, 'c' }, { "dereference", no_argument, NULL, 'L' }, @@ -178,7 +182,7 @@ static const struct option tar_longopts[] = { { "exclude", required_argument, NULL, OPTION_EXCLUDE }, { "exclude-from", required_argument, NULL, 'X' }, { "extract", no_argument, NULL, 'x' }, - { "fast-read", no_argument, NULL, OPTION_FAST_READ }, + { "fast-read", no_argument, NULL, 'q' }, { "file", required_argument, NULL, 'f' }, { "files-from", required_argument, NULL, 'T' }, { "format", required_argument, NULL, OPTION_FORMAT }, @@ -187,6 +191,8 @@ static const struct option tar_longopts[] = { { "help", no_argument, NULL, OPTION_HELP }, { "include", required_argument, NULL, OPTION_INCLUDE }, { "interactive", no_argument, NULL, 'w' }, + { "insecure", no_argument, NULL, 'P' }, + { "keep-newer-files", no_argument, NULL, OPTION_KEEP_NEWER_FILES }, { "keep-old-files", no_argument, NULL, 'k' }, { "list", no_argument, NULL, 't' }, { "modification-time", no_argument, NULL, 'm' }, @@ -202,6 +208,7 @@ static const struct option tar_longopts[] = { { "no-same-owner", no_argument, NULL, OPTION_NO_SAME_OWNER }, { "no-same-permissions",no_argument, NULL, OPTION_NO_SAME_PERMISSIONS }, { "null", no_argument, NULL, OPTION_NULL }, + { "numeric-owner", no_argument, NULL, OPTION_NUMERIC_OWNER }, { "one-file-system", no_argument, NULL, OPTION_ONE_FILE_SYSTEM }, { "posix", no_argument, NULL, OPTION_POSIX }, { "preserve-permissions", no_argument, NULL, 'p' }, @@ -210,6 +217,7 @@ static const struct option tar_longopts[] = { { "strip-components", required_argument, NULL, OPTION_STRIP_COMPONENTS }, { "to-stdout", no_argument, NULL, 'O' }, { "totals", no_argument, NULL, OPTION_TOTALS }, + { "uncompress", no_argument, NULL, 'Z' }, { "unlink", no_argument, NULL, 'U' }, { "unlink-first", no_argument, NULL, 'U' }, { "update", no_argument, NULL, 'u' }, @@ -321,6 +329,9 @@ main(int argc, char **argv) case OPTION_CHECK_LINKS: /* GNU tar */ bsdtar->option_warn_links = 1; break; + case OPTION_CHROOT: /* NetBSD */ + bsdtar->option_chroot = 1; + break; case OPTION_EXCLUDE: /* GNU tar */ if (exclude(bsdtar, optarg)) bsdtar_errc(bsdtar, 1, 0, @@ -334,9 +345,6 @@ main(int argc, char **argv) if (strcmp(bsdtar->filename, "-") == 0) bsdtar->filename = NULL; break; - case OPTION_FAST_READ: /* GNU tar */ - bsdtar->option_fast_read = 1; - break; case 'H': /* BSD convention */ bsdtar->symlink_mode = 'H'; break; @@ -388,6 +396,9 @@ main(int argc, char **argv) case 'k': /* GNU tar */ bsdtar->extract_flags |= ARCHIVE_EXTRACT_NO_OVERWRITE; break; + case OPTION_KEEP_NEWER_FILES: /* GNU tar */ + bsdtar->extract_flags |= ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER; + break; case 'L': /* BSD convention */ bsdtar->symlink_mode = 'L'; break; @@ -451,6 +462,9 @@ main(int argc, char **argv) case OPTION_NULL: /* GNU tar */ bsdtar->option_null++; break; + case OPTION_NUMERIC_OWNER: /* GNU tar */ + bsdtar->option_numeric_owner++; + break; case 'O': /* GNU tar */ bsdtar->option_stdout = 1; break; @@ -484,9 +498,23 @@ main(int argc, char **argv) case OPTION_POSIX: /* GNU tar */ bsdtar->create_format = "pax"; break; + case 'q': /* FreeBSD GNU tar --fast-read, NetBSD -q */ + bsdtar->option_fast_read = 1; + break; case 'r': /* SUSv2 */ set_mode(bsdtar, opt); break; + case 'S': /* NetBSD pax-as-tar */ + bsdtar->extract_flags |= ARCHIVE_EXTRACT_SPARSE; + break; + case 's': /* NetBSD pax-as-tar */ +#if HAVE_REGEX_H + add_substitution(bsdtar, optarg); +#else + bsdtar_warnc(bsdtar, 0, "-s is not supported by this version of bsdtar"); + usage(bsdtar); +#endif + break; case OPTION_STRIP_COMPONENTS: /* GNU tar 1.15 */ bsdtar->strip_components = atoi(optarg); break; @@ -625,17 +653,13 @@ main(int argc, char **argv) only_mode(bsdtar, "--check-links", "cr"); /* Check other parameters only permitted in certain modes. */ - if (bsdtar->create_compression == 'Z' && bsdtar->mode == 'c') { - bsdtar_warnc(bsdtar, 0, ".Z compression not supported"); - usage(bsdtar); - } if (bsdtar->create_compression != '\0') { strcpy(buff, "-?"); buff[1] = bsdtar->create_compression; only_mode(bsdtar, buff, "cxt"); } if (bsdtar->create_format != NULL) - only_mode(bsdtar, "--format", "c"); + only_mode(bsdtar, "--format", "cru"); if (bsdtar->symlink_mode != '\0') { strcpy(buff, "-?"); buff[1] = bsdtar->symlink_mode; @@ -666,6 +690,10 @@ main(int argc, char **argv) } cleanup_exclusions(bsdtar); +#if HAVE_REGEX_H + cleanup_substitution(bsdtar); +#endif + if (bsdtar->return_value != 0) bsdtar_warnc(bsdtar, 0, "Error exit delayed from previous errors."); @@ -718,8 +746,8 @@ rewrite_argv(struct bsdtar *bsdtar, int *argc, char **src_argv, const char *p; char *src, *dest; - if (src_argv[0] == NULL || - src_argv[1] == NULL || src_argv[1][0] == '-') + if (src_argv[0] == NULL || src_argv[1] == NULL || + src_argv[1][0] == '-' || src_argv[1][0] == '\0') return (src_argv); *argc += strlen(src_argv[1]) - 1; @@ -785,7 +813,7 @@ version(void) printf("bsdtar %s - %s\n", BSDTAR_VERSION_STRING, archive_version()); - exit(1); + exit(0); } static const char *long_help_msg = diff --git a/contrib/libarchive-2/tar/bsdtar.h b/contrib/libarchive-2/tar/bsdtar.h index fb10678702..9d4733c504 100644 --- a/contrib/libarchive-2/tar/bsdtar.h +++ b/contrib/libarchive-2/tar/bsdtar.h @@ -22,7 +22,7 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * - * $FreeBSD: src/usr.bin/tar/bsdtar.h,v 1.29 2008/01/02 00:21:27 kientzle Exp $ + * $FreeBSD: src/usr.bin/tar/bsdtar.h,v 1.32 2008/05/22 21:08:36 cperciva Exp $ */ #include "bsdtar_platform.h" @@ -57,6 +57,7 @@ struct bsdtar { char create_compression; /* j, y, or z */ const char *compress_program; char option_absolute_paths; /* -P */ + char option_chroot; /* --chroot */ char option_dont_traverse_mounts; /* --one-file-system */ char option_fast_read; /* --fast-read */ char option_honor_nodump; /* --nodump */ @@ -64,6 +65,7 @@ struct bsdtar { char option_no_owner; /* -o */ char option_no_subdirs; /* -n */ char option_null; /* --null */ + char option_numeric_owner; /* --numeric-owner */ char option_stdout; /* -O */ char option_totals; /* --totals */ char option_unlink_first; /* -U */ @@ -89,12 +91,14 @@ struct bsdtar { * Data for various subsystems. Full definitions are located in * the file where they are used. */ + struct archive_entry_linkresolver *resolver; struct archive_dir *archive_dir; /* for write.c */ struct name_cache *gname_cache; /* for write.c */ - struct links_cache *links_cache; /* for write.c */ struct matching *matching; /* for matching.c */ struct security *security; /* for read.c */ struct name_cache *uname_cache; /* for write.c */ + struct siginfo_data *siginfo; /* for siginfo.c */ + struct substitution *substitution; /* for subst.c */ }; void bsdtar_errc(struct bsdtar *, int _eval, int _code, @@ -113,12 +117,23 @@ int process_lines(struct bsdtar *bsdtar, const char *pathname, int (*process)(struct bsdtar *, const char *)); void safe_fprintf(FILE *, const char *fmt, ...); void set_chdir(struct bsdtar *, const char *newdir); +void siginfo_init(struct bsdtar *); +void siginfo_setinfo(struct bsdtar *, const char * oper, + const char * path, int64_t size); +void siginfo_printinfo(struct bsdtar *, off_t progress); +void siginfo_done(struct bsdtar *); void tar_mode_c(struct bsdtar *bsdtar); void tar_mode_r(struct bsdtar *bsdtar); void tar_mode_t(struct bsdtar *bsdtar); void tar_mode_u(struct bsdtar *bsdtar); void tar_mode_x(struct bsdtar *bsdtar); int unmatched_inclusions(struct bsdtar *bsdtar); +int unmatched_inclusions_warn(struct bsdtar *bsdtar, const char *msg); void usage(struct bsdtar *); int yes(const char *fmt, ...); +#if HAVE_REGEX_H +void add_substitution(struct bsdtar *, const char *); +int apply_substitution(struct bsdtar *, const char *, char **, int); +void cleanup_substitution(struct bsdtar *); +#endif diff --git a/contrib/libarchive-2/tar/matching.c b/contrib/libarchive-2/tar/matching.c index f0ca0c9abb..59be17b9a3 100644 --- a/contrib/libarchive-2/tar/matching.c +++ b/contrib/libarchive-2/tar/matching.c @@ -24,7 +24,7 @@ */ #include "bsdtar_platform.h" -__FBSDID("$FreeBSD: src/usr.bin/tar/matching.c,v 1.11 2007/03/11 10:36:42 kientzle Exp $"); +__FBSDID("$FreeBSD: src/usr.bin/tar/matching.c,v 1.12 2008/03/18 06:18:49 kientzle Exp $"); #ifdef HAVE_ERRNO_H #include @@ -157,7 +157,7 @@ excluded(struct bsdtar *bsdtar, const char *pathname) */ if (match->matches == 0) { match->matches++; - matching->inclusions_unmatched_count++; + matching->inclusions_unmatched_count--; return (0); } /* @@ -259,6 +259,29 @@ unmatched_inclusions(struct bsdtar *bsdtar) } +int +unmatched_inclusions_warn(struct bsdtar *bsdtar, const char *msg) +{ + struct matching *matching; + struct match *p; + + matching = bsdtar->matching; + if (matching == NULL) + return (0); + + p = matching->inclusions; + while (p != NULL) { + if (p->matches == 0) { + bsdtar->return_value = 1; + bsdtar_warnc(bsdtar, 0, "%s: %s", + p->pattern, msg); + } + p = p->next; + } + return (matching->inclusions_unmatched_count); +} + + #if defined(HAVE_FNMATCH) && defined(HAVE_FNM_LEADING_DIR) diff --git a/contrib/libarchive-2/tar/read.c b/contrib/libarchive-2/tar/read.c index edda317b6a..e1905b2486 100644 --- a/contrib/libarchive-2/tar/read.c +++ b/contrib/libarchive-2/tar/read.c @@ -24,7 +24,7 @@ */ #include "bsdtar_platform.h" -__FBSDID("$FreeBSD: src/usr.bin/tar/read.c,v 1.35 2008/01/02 00:21:27 kientzle Exp $"); +__FBSDID("$FreeBSD: src/usr.bin/tar/read.c,v 1.37 2008/05/18 06:24:47 cperciva Exp $"); #ifdef HAVE_SYS_TYPES_H #include @@ -77,12 +77,28 @@ void tar_mode_t(struct bsdtar *bsdtar) { read_archive(bsdtar, 't'); + unmatched_inclusions_warn(bsdtar, "Not found in archive"); } void tar_mode_x(struct bsdtar *bsdtar) { + /* We want to catch SIGINFO and SIGUSR1. */ + siginfo_init(bsdtar); + read_archive(bsdtar, 'x'); + + unmatched_inclusions_warn(bsdtar, "Not found in archive"); + /* Restore old SIGINFO + SIGUSR1 handlers. */ + siginfo_done(bsdtar); +} + +static void +progress_func(void * cookie) +{ + struct bsdtar * bsdtar = cookie; + + siginfo_printinfo(bsdtar, 0); } /* @@ -118,6 +134,23 @@ read_archive(struct bsdtar *bsdtar, char mode) archive_error_string(a)); do_chdir(bsdtar); + + if (mode == 'x') { + /* Set an extract callback so that we can handle SIGINFO. */ + archive_read_extract_set_progress_callback(a, progress_func, + bsdtar); + } + + if (mode == 'x' && bsdtar->option_chroot) { +#if HAVE_CHROOT + if (chroot(".") != 0) + bsdtar_errc(bsdtar, 1, errno, "Can't chroot to \".\""); +#else + bsdtar_errc(bsdtar, 1, 0, + "chroot isn't supported on this platform"); +#endif + } + for (;;) { /* Support --fast-read option */ if (bsdtar->option_fast_read && @@ -139,6 +172,11 @@ read_archive(struct bsdtar *bsdtar, char mode) if (r == ARCHIVE_FATAL) break; + if (bsdtar->option_numeric_owner) { + archive_entry_set_uname(entry, NULL); + archive_entry_set_gname(entry, NULL); + } + /* * Exclude entries that are too old. */ @@ -227,6 +265,12 @@ read_archive(struct bsdtar *bsdtar, char mode) archive_entry_pathname(entry)); fflush(stderr); } + + /* Tell the SIGINFO-handler code what we're doing. */ + siginfo_setinfo(bsdtar, "extracting", + archive_entry_pathname(entry), 0); + siginfo_printinfo(bsdtar, 0); + if (bsdtar->option_stdout) r = archive_read_data_into_fd(a, 1); else diff --git a/contrib/libarchive-2/tar/siginfo.c b/contrib/libarchive-2/tar/siginfo.c new file mode 100644 index 0000000000..249ee34a93 --- /dev/null +++ b/contrib/libarchive-2/tar/siginfo.c @@ -0,0 +1,147 @@ +/*- + * Copyright 2008 Colin Percival + * 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: src/usr.bin/tar/siginfo.c,v 1.2 2008/05/22 21:08:36 cperciva Exp $"); + +#include +#include +#include +#include +#include + +#include "bsdtar.h" + +/* Is there a pending SIGINFO or SIGUSR1? */ +static volatile sig_atomic_t siginfo_received = 0; + +struct siginfo_data { + /* What sort of operation are we doing? */ + char * oper; + + /* What path are we handling? */ + char * path; + + /* How large is the archive entry? */ + int64_t size; + + /* Old signal handlers. */ +#ifdef SIGINFO + void (*siginfo_old)(int); +#endif + void (*sigusr1_old)(int); +}; + +static void siginfo_handler(int sig); + +/* Handler for SIGINFO / SIGUSR1. */ +static void +siginfo_handler(int sig) +{ + + (void)sig; /* UNUSED */ + + /* Record that SIGINFO or SIGUSR1 has been received. */ + siginfo_received = 1; +} + +void +siginfo_init(struct bsdtar *bsdtar) +{ + + /* Allocate space for internal structure. */ + if ((bsdtar->siginfo = malloc(sizeof(struct siginfo_data))) == NULL) + bsdtar_errc(bsdtar, 1, errno, "malloc failed"); + + /* Set the strings to NULL so that free() is safe. */ + bsdtar->siginfo->path = bsdtar->siginfo->oper = NULL; + +#ifdef SIGINFO + /* We want to catch SIGINFO, if it exists. */ + bsdtar->siginfo->siginfo_old = signal(SIGINFO, siginfo_handler); +#endif + /* ... and treat SIGUSR1 the same way as SIGINFO. */ + bsdtar->siginfo->sigusr1_old = signal(SIGUSR1, siginfo_handler); +} + +void +siginfo_setinfo(struct bsdtar *bsdtar, const char * oper, const char * path, + int64_t size) +{ + + /* Free old operation and path strings. */ + free(bsdtar->siginfo->oper); + free(bsdtar->siginfo->path); + + /* Duplicate strings and store entry size. */ + if ((bsdtar->siginfo->oper = strdup(oper)) == NULL) + bsdtar_errc(bsdtar, 1, errno, "Cannot strdup"); + if ((bsdtar->siginfo->path = strdup(path)) == NULL) + bsdtar_errc(bsdtar, 1, errno, "Cannot strdup"); + bsdtar->siginfo->size = size; +} + +void +siginfo_printinfo(struct bsdtar *bsdtar, off_t progress) +{ + + /* If there's a signal to handle and we know what we're doing... */ + if ((siginfo_received == 1) && + (bsdtar->siginfo->path != NULL) && + (bsdtar->siginfo->oper != NULL)) { + if (bsdtar->verbose) + fprintf(stderr, "\n"); + if (bsdtar->siginfo->size > 0) { + safe_fprintf(stderr, "%s %s (%ju / %" PRId64 ")", + bsdtar->siginfo->oper, bsdtar->siginfo->path, + (uintmax_t)progress, bsdtar->siginfo->size); + } else { + safe_fprintf(stderr, "%s %s", + bsdtar->siginfo->oper, bsdtar->siginfo->path); + } + if (!bsdtar->verbose) + fprintf(stderr, "\n"); + siginfo_received = 0; + } +} + +void +siginfo_done(struct bsdtar *bsdtar) +{ + +#ifdef SIGINFO + /* Restore old SIGINFO handler. */ + signal(SIGINFO, bsdtar->siginfo->siginfo_old); +#endif + /* And the old SIGUSR1 handler, too. */ + signal(SIGUSR1, bsdtar->siginfo->sigusr1_old); + + /* Free strings. */ + free(bsdtar->siginfo->path); + free(bsdtar->siginfo->oper); + + /* Free internal data structure. */ + free(bsdtar->siginfo); +} diff --git a/contrib/libarchive-2/tar/subst.c b/contrib/libarchive-2/tar/subst.c new file mode 100644 index 0000000000..9fcd4d95fc --- /dev/null +++ b/contrib/libarchive-2/tar/subst.c @@ -0,0 +1,275 @@ +/*- + * Copyright (c) 2008 Joerg Sonnenberger + * 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$"); + +#if HAVE_REGEX_H +#include "bsdtar.h" + +#include +#include +#include +#include + +struct subst_rule { + struct subst_rule *next; + regex_t re; + char *result; + int global:1, print:1, symlink:1; +}; + +struct substitution { + struct subst_rule *first_rule, *last_rule; +}; + +static void +init_substitution(struct bsdtar *bsdtar) +{ + struct substitution *subst; + + bsdtar->substitution = subst = malloc(sizeof(*subst)); + if (subst == NULL) + bsdtar_errc(bsdtar, 1, errno, "Out of memory"); + subst->first_rule = subst->last_rule = NULL; +} + +void +add_substitution(struct bsdtar *bsdtar, const char *rule_text) +{ + struct subst_rule *rule; + struct substitution *subst; + const char *end_pattern, *start_subst; + char *pattern; + int r; + + if ((subst = bsdtar->substitution) == NULL) { + init_substitution(bsdtar); + subst = bsdtar->substitution; + } + + rule = malloc(sizeof(*rule)); + if (rule == NULL) + bsdtar_errc(bsdtar, 1, errno, "Out of memory"); + rule->next = NULL; + + if (subst->last_rule == NULL) + subst->first_rule = rule; + else + subst->last_rule->next = rule; + subst->last_rule = rule; + + if (*rule_text == '\0') + bsdtar_errc(bsdtar, 1, 0, "Empty replacement string"); + end_pattern = strchr(rule_text + 1, *rule_text); + if (end_pattern == NULL) + bsdtar_errc(bsdtar, 1, 0, "Invalid replacement string"); + + pattern = malloc(end_pattern - rule_text); + if (pattern == NULL) + bsdtar_errc(bsdtar, 1, errno, "Out of memory"); + memcpy(pattern, rule_text + 1, end_pattern - rule_text - 1); + pattern[end_pattern - rule_text - 1] = '\0'; + + if ((r = regcomp(&rule->re, pattern, REG_BASIC)) != 0) { + char buf[80]; + regerror(r, &rule->re, buf, sizeof(buf)); + bsdtar_errc(bsdtar, 1, 0, "Invalid regular expression: %s", buf); + } + free(pattern); + + start_subst = end_pattern + 1; + end_pattern = strchr(start_subst, *rule_text); + if (end_pattern == NULL) + bsdtar_errc(bsdtar, 1, 0, "Invalid replacement string"); + + rule->result = malloc(end_pattern - start_subst + 1); + if (rule->result == NULL) + bsdtar_errc(bsdtar, 1, errno, "Out of memory"); + memcpy(rule->result, start_subst, end_pattern - start_subst); + rule->result[end_pattern - start_subst] = '\0'; + + rule->global = 0; + rule->print = 0; + rule->symlink = 0; + + while (*++end_pattern) { + switch (*end_pattern) { + case 'g': + case 'G': + rule->global = 1; + break; + case 'p': + case 'P': + rule->print = 1; + break; + case 's': + case 'S': + rule->symlink = 1; + break; + default: + bsdtar_errc(bsdtar, 1, 0, "Invalid replacement flag %c", *end_pattern); + } + } +} + +static void +realloc_strncat(struct bsdtar *bsdtar, char **str, const char *append, size_t len) +{ + char *new_str; + size_t old_len; + + if (*str == NULL) + old_len = 0; + else + old_len = strlen(*str); + + new_str = malloc(old_len + len + 1); + if (new_str == NULL) + bsdtar_errc(bsdtar, 1, errno, "Out of memory"); + memcpy(new_str, *str, old_len); + memcpy(new_str + old_len, append, len); + new_str[old_len + len] = '\0'; + free(*str); + *str = new_str; +} + +static void +realloc_strcat(struct bsdtar *bsdtar, char **str, const char *append) +{ + char *new_str; + size_t old_len; + + if (*str == NULL) + old_len = 0; + else + old_len = strlen(*str); + + new_str = malloc(old_len + strlen(append) + 1); + if (new_str == NULL) + bsdtar_errc(bsdtar, 1, errno, "Out of memory"); + memcpy(new_str, *str, old_len); + strcpy(new_str + old_len, append); + free(*str); + *str = new_str; +} + +int +apply_substitution(struct bsdtar *bsdtar, const char *name, char **result, int symlink_only) +{ + const char *path = name; + regmatch_t matches[10]; + size_t i, j; + struct subst_rule *rule; + struct substitution *subst; + int c, got_match, print_match; + + *result = NULL; + + if ((subst = bsdtar->substitution) == NULL) + return 0; + + got_match = 0; + print_match = 0; + + for (rule = subst->first_rule; rule != NULL; rule = rule->next) { + if (symlink_only && !rule->symlink) + continue; + if (regexec(&rule->re, name, 10, matches, 0)) + break; + + got_match = 1; + print_match |= rule->print; + realloc_strncat(bsdtar, result, name, matches[0].rm_so); + + for (i = 0, j = 0; rule->result[i] != '\0'; ++i) { + if (rule->result[i] == '~') { + realloc_strncat(bsdtar, result, rule->result + j, i - j); + realloc_strncat(bsdtar, result, name, matches[0].rm_eo); + j = i + 1; + continue; + } + if (rule->result[i] != '\\') + continue; + + ++i; + c = rule->result[i]; + switch (c) { + case '~': + case '\\': + realloc_strncat(bsdtar, result, rule->result + j, i - j - 1); + j = i; + break; + case '1' ... '9': + realloc_strncat(bsdtar, result, rule->result + j, i - j - 1); + if ((size_t)(c - '0') > (size_t)(rule->re.re_nsub)) { + free(*result); + *result = NULL; + return -1; + } + realloc_strncat(bsdtar, result, name + matches[c - '0'].rm_so, matches[c - '0'].rm_eo - matches[c - '0'].rm_so); + j = i + 1; + break; + default: + /* Just continue; */ + break; + } + + } + + realloc_strcat(bsdtar, result, rule->result + j); + + name += matches[0].rm_eo; + + if (!rule->global) + break; + } + + if (got_match) + realloc_strcat(bsdtar, result, name); + + if (print_match) + fprintf(stderr, "%s >> %s\n", path, *result); + + return got_match; +} + +void +cleanup_substitution(struct bsdtar *bsdtar) +{ + struct subst_rule *rule; + struct substitution *subst; + + if ((subst = bsdtar->substitution) == NULL) + return; + + while ((rule = subst->first_rule) != NULL) { + subst->first_rule = rule->next; + free(rule->result); + free(rule); + } + free(subst); +} +#endif /* HAVE_REGEX_H */ diff --git a/contrib/libarchive-2/tar/util.c b/contrib/libarchive-2/tar/util.c index 68ff8d8f5e..1d50dcd801 100644 --- a/contrib/libarchive-2/tar/util.c +++ b/contrib/libarchive-2/tar/util.c @@ -178,7 +178,7 @@ yes(const char *fmt, ...) fprintf(stderr, " (y/N)? "); fflush(stderr); - l = read(2, buff, sizeof(buff)); + l = read(2, buff, sizeof(buff) - 1); if (l <= 0) return (0); buff[l] = 0; @@ -215,7 +215,7 @@ process_lines(struct bsdtar *bsdtar, const char *pathname, { FILE *f; char *buff, *buff_end, *line_start, *line_end, *p; - size_t buff_length, bytes_read, bytes_wanted; + size_t buff_length, new_buff_length, bytes_read, bytes_wanted; int separator; int ret; @@ -262,7 +262,12 @@ process_lines(struct bsdtar *bsdtar, const char *pathname, line_start = buff; } else { /* Line is too big; enlarge the buffer. */ - p = realloc(buff, buff_length *= 2); + new_buff_length = buff_length * 2; + if (new_buff_length <= buff_length) + bsdtar_errc(bsdtar, 1, ENOMEM, + "Line too long in %s", pathname); + buff_length = new_buff_length; + p = realloc(buff, buff_length); if (p == NULL) bsdtar_errc(bsdtar, 1, ENOMEM, "Line too long in %s", pathname); @@ -351,10 +356,51 @@ int edit_pathname(struct bsdtar *bsdtar, struct archive_entry *entry) { const char *name = archive_entry_pathname(entry); +#if HAVE_REGEX_H + char *subst_name; +#endif + int r; + +#if HAVE_REGEX_H + r = apply_substitution(bsdtar, name, &subst_name, 0); + if (r == -1) { + bsdtar_warnc(bsdtar, 0, "Invalid substituion, skipping entry"); + return 1; + } + if (r == 1) { + archive_entry_copy_pathname(entry, subst_name); + free(subst_name); + if (*subst_name == '\0') + return -1; + name = archive_entry_pathname(entry); + } + + if (archive_entry_hardlink(entry)) { + r = apply_substitution(bsdtar, archive_entry_hardlink(entry), &subst_name, 1); + if (r == -1) { + bsdtar_warnc(bsdtar, 0, "Invalid substituion, skipping entry"); + return 1; + } + if (r == 1) { + archive_entry_copy_hardlink(entry, subst_name); + free(subst_name); + } + } + if (archive_entry_symlink(entry) != NULL) { + r = apply_substitution(bsdtar, archive_entry_symlink(entry), &subst_name, 1); + if (r == -1) { + bsdtar_warnc(bsdtar, 0, "Invalid substituion, 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) { - int r = bsdtar->strip_components; + if ((r = bsdtar->strip_components) > 0) { const char *p = name; while (r > 0) { @@ -368,6 +414,10 @@ edit_pathname(struct bsdtar *bsdtar, struct archive_entry *entry) return (1); } } + while (*name == '/') + ++name; + if (*name == '\0') + return (1); } /* Strip redundant leading '/' characters. */ diff --git a/contrib/libarchive-2/tar/write.c b/contrib/libarchive-2/tar/write.c index 3b8cc51585..432612ac7a 100644 --- a/contrib/libarchive-2/tar/write.c +++ b/contrib/libarchive-2/tar/write.c @@ -24,7 +24,7 @@ */ #include "bsdtar_platform.h" -__FBSDID("$FreeBSD: src/usr.bin/tar/write.c,v 1.64 2008/02/19 05:27:17 kientzle Exp $"); +__FBSDID("$FreeBSD: src/usr.bin/tar/write.c,v 1.69 2008/05/23 05:07:22 cperciva Exp $"); #ifdef HAVE_SYS_TYPES_H #include @@ -87,9 +87,6 @@ __FBSDID("$FreeBSD: src/usr.bin/tar/write.c,v 1.64 2008/02/19 05:27:17 kientzle static const char * const NO_NAME = "(noname)"; -/* Initial size of link cache. */ -#define links_cache_initial_size 1024 - struct archive_dir_entry { struct archive_dir_entry *next; time_t mtime_sec; @@ -101,21 +98,6 @@ struct archive_dir { struct archive_dir_entry *head, *tail; }; -struct links_cache { - unsigned long number_entries; - size_t number_buckets; - struct links_entry **buckets; -}; - -struct links_entry { - struct links_entry *next; - struct links_entry *previous; - int links; - dev_t dev; - ino_t ino; - char *name; -}; - struct name_cache { int probes; int hits; @@ -139,13 +121,10 @@ static int archive_names_from_file_helper(struct bsdtar *bsdtar, static int copy_file_data(struct bsdtar *bsdtar, struct archive *a, struct archive *ina); static void create_cleanup(struct bsdtar *); -static void free_buckets(struct bsdtar *, struct links_cache *); static void free_cache(struct name_cache *cache); static const char * lookup_gname(struct bsdtar *bsdtar, gid_t gid); static int lookup_gname_helper(struct bsdtar *bsdtar, const char **name, id_t gid); -static void lookup_hardlink(struct bsdtar *, - struct archive_entry *entry, const struct stat *); static const char * lookup_uname(struct bsdtar *bsdtar, uid_t uid); static int lookup_uname_helper(struct bsdtar *bsdtar, const char **name, id_t uid); @@ -160,6 +139,8 @@ static void write_archive(struct archive *, struct bsdtar *); static void write_entry(struct bsdtar *, struct archive *, const struct stat *, const char *pathname, const char *accpath); +static void write_entry_backend(struct bsdtar *, struct archive *, + struct archive_entry *, int); static int write_file_data(struct bsdtar *, struct archive *, int fd); static void write_hierarchy(struct bsdtar *, struct archive *, @@ -174,6 +155,9 @@ tar_mode_c(struct bsdtar *bsdtar) if (*bsdtar->argv == NULL && bsdtar->names_from_file == NULL) bsdtar_errc(bsdtar, 1, 0, "no files or directories specified"); + /* We want to catch SIGINFO and SIGUSR1. */ + siginfo_init(bsdtar); + a = archive_write_new(); /* Support any format that the library supports. */ @@ -220,6 +204,9 @@ tar_mode_c(struct bsdtar *bsdtar) archive_write_set_compression_gzip(a); break; #endif + case 'Z': + archive_write_set_compression_compress(a); + break; default: bsdtar_errc(bsdtar, 1, 0, "Unrecognized compression option -%c", @@ -239,6 +226,9 @@ tar_mode_c(struct bsdtar *bsdtar) } archive_write_finish(a); + + /* Restore old SIGINFO + SIGUSR1 handlers. */ + siginfo_done(bsdtar); } /* @@ -257,6 +247,9 @@ tar_mode_r(struct bsdtar *bsdtar) /* Sanity-test some arguments and the file. */ test_for_append(bsdtar); + /* We want to catch SIGINFO and SIGUSR1. */ + siginfo_init(bsdtar); + format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED; bsdtar->fd = open(bsdtar->filename, O_RDWR | O_CREAT, 0666); @@ -355,6 +348,9 @@ tar_mode_u(struct bsdtar *bsdtar) /* Sanity-test some arguments and the file. */ test_for_append(bsdtar); + /* We want to catch SIGINFO and SIGUSR1. */ + siginfo_init(bsdtar); + bsdtar->fd = open(bsdtar->filename, O_RDWR); if (bsdtar->fd < 0) bsdtar_errc(bsdtar, 1, errno, @@ -439,6 +435,12 @@ static void write_archive(struct archive *a, struct bsdtar *bsdtar) { const char *arg; + struct archive_entry *entry, *sparse_entry; + + if ((bsdtar->resolver = archive_entry_linkresolver_new()) == NULL) + bsdtar_errc(bsdtar, 1, 0, "cannot create link resolver"); + archive_entry_linkresolver_set_strategy(bsdtar->resolver, + archive_format(a)); if (bsdtar->names_from_file != NULL) archive_names_from_file(bsdtar, a); @@ -471,6 +473,16 @@ write_archive(struct archive *a, struct bsdtar *bsdtar) bsdtar->argv++; } + entry = NULL; + archive_entry_linkify(bsdtar->resolver, &entry, &sparse_entry); + while (entry != NULL) { + int fd = -1; + write_entry_backend(bsdtar, a, entry, fd); + archive_entry_free(entry); + entry = NULL; + archive_entry_linkify(bsdtar->resolver, &entry, &sparse_entry); + } + create_cleanup(bsdtar); if (archive_write_close(a)) { bsdtar_warnc(bsdtar, 0, "%s", archive_error_string(a)); @@ -571,6 +583,10 @@ append_archive(struct bsdtar *bsdtar, struct archive *a, struct archive *ina) if (bsdtar->verbose) safe_fprintf(stderr, "a %s", archive_entry_pathname(in_entry)); + siginfo_setinfo(bsdtar, "copying", + archive_entry_pathname(in_entry), + archive_entry_size(in_entry)); + siginfo_printinfo(bsdtar, 0); e = archive_write_header(a, in_entry); if (e != ARCHIVE_OK) { @@ -584,9 +600,12 @@ append_archive(struct bsdtar *bsdtar, struct archive *a, struct archive *ina) if (e == ARCHIVE_FATAL) exit(1); - if (e >= ARCHIVE_WARN) - if (copy_file_data(bsdtar, a, ina)) + if (e >= ARCHIVE_WARN) { + if (archive_entry_size(in_entry) == 0) + archive_read_data_skip(ina); + else if (copy_file_data(bsdtar, a, ina)) exit(1); + } if (bsdtar->verbose) fprintf(stderr, "\n"); @@ -603,14 +622,18 @@ copy_file_data(struct bsdtar *bsdtar, struct archive *a, struct archive *ina) char buff[64*1024]; ssize_t bytes_read; ssize_t bytes_written; + off_t progress = 0; bytes_read = archive_read_data(ina, buff, sizeof(buff)); while (bytes_read > 0) { + siginfo_printinfo(bsdtar, progress); + bytes_written = archive_write_data(a, buff, bytes_read); if (bytes_written < bytes_read) { bsdtar_warnc(bsdtar, 0, "%s", archive_error_string(a)); return (-1); } + progress += bytes_written; bytes_read = archive_read_data(ina, buff, sizeof(buff)); } @@ -773,6 +796,54 @@ write_hierarchy(struct bsdtar *bsdtar, struct archive *a, const char *path) tree_close(tree); } +/* + * Backend for write_entry. + */ +static void +write_entry_backend(struct bsdtar *bsdtar, struct archive *a, + struct archive_entry *entry, int fd) +{ + int e; + + if (fd == -1 && archive_entry_size(entry) > 0) { + const char *pathname = archive_entry_sourcepath(entry); + fd = open(pathname, O_RDONLY); + if (fd == -1) { + if (!bsdtar->verbose) + bsdtar_warnc(bsdtar, errno, + "%s: could not open file", pathname); + else + fprintf(stderr, ": %s", strerror(errno)); + return; + } + } + + e = archive_write_header(a, entry); + if (e != ARCHIVE_OK) { + if (!bsdtar->verbose) + bsdtar_warnc(bsdtar, 0, "%s: %s", + archive_entry_pathname(entry), + archive_error_string(a)); + else + fprintf(stderr, ": %s", archive_error_string(a)); + } + + if (e == ARCHIVE_FATAL) + exit(1); + + /* + * If we opened a file earlier, write it out now. Note that + * the format handler might have reset the size field to zero + * to inform us that the archive body won't get stored. In + * that case, just skip the write. + */ + if (e >= ARCHIVE_WARN && fd >= 0 && archive_entry_size(entry) > 0) { + if (write_file_data(bsdtar, a, fd)) + exit(1); + close(fd); + } +} + /* * Add a single filesystem object to the archive. */ @@ -780,9 +851,8 @@ static void write_entry(struct bsdtar *bsdtar, struct archive *a, const struct stat *st, const char *pathname, const char *accpath) { - struct archive_entry *entry; - int e; - int fd; + struct archive_entry *entry, *sparse_entry; + int fd; #ifdef __linux int r; unsigned long stflags; @@ -793,6 +863,7 @@ write_entry(struct bsdtar *bsdtar, struct archive *a, const struct stat *st, entry = archive_entry_new(); archive_entry_set_pathname(entry, pathname); + archive_entry_copy_sourcepath(entry, accpath); /* * Rewrite the pathname to be archived. If rewrite @@ -808,9 +879,6 @@ write_entry(struct bsdtar *bsdtar, struct archive *a, const struct stat *st, if (!new_enough(bsdtar, archive_entry_pathname(entry), st)) goto abort; - if (!S_ISDIR(st->st_mode) && (st->st_nlink > 1)) - lookup_hardlink(bsdtar, entry, st); - /* Display entry as we process it. This format is required by SUSv2. */ if (bsdtar->verbose) safe_fprintf(stderr, "a %s", archive_entry_pathname(entry)); @@ -857,48 +925,25 @@ write_entry(struct bsdtar *bsdtar, struct archive *a, const struct stat *st, setup_acls(bsdtar, entry, accpath); setup_xattrs(bsdtar, entry, accpath); - /* - * If it's a regular file (and non-zero in size) make sure we - * can open it before we start to write. In particular, note - * that we can always archive a zero-length file, even if we - * can't read it. - */ - if (S_ISREG(st->st_mode) && st->st_size > 0) { - fd = open(accpath, O_RDONLY); - if (fd < 0) { - if (!bsdtar->verbose) - bsdtar_warnc(bsdtar, errno, "%s: could not open file", pathname); - else - fprintf(stderr, ": %s", strerror(errno)); - goto cleanup; - } - } - /* Non-regular files get archived with zero size. */ if (!S_ISREG(st->st_mode)) archive_entry_set_size(entry, 0); - e = archive_write_header(a, entry); - if (e != ARCHIVE_OK) { - if (!bsdtar->verbose) - bsdtar_warnc(bsdtar, 0, "%s: %s", pathname, - archive_error_string(a)); - else - fprintf(stderr, ": %s", archive_error_string(a)); - } + /* Record what we're doing, for the benefit of SIGINFO / SIGUSR1. */ + siginfo_setinfo(bsdtar, "adding", archive_entry_pathname(entry), + archive_entry_size(entry)); + archive_entry_linkify(bsdtar->resolver, &entry, &sparse_entry); - if (e == ARCHIVE_FATAL) - exit(1); + /* Handle SIGINFO / SIGUSR1 request if one was made. */ + siginfo_printinfo(bsdtar, 0); - /* - * If we opened a file earlier, write it out now. Note that - * the format handler might have reset the size field to zero - * to inform us that the archive body won't get stored. In - * that case, just skip the write. - */ - if (e >= ARCHIVE_WARN && fd >= 0 && archive_entry_size(entry) > 0) - if (write_file_data(bsdtar, a, fd)) - exit(1); + while (entry != NULL) { + write_entry_backend(bsdtar, a, entry, fd); + fd = -1; + archive_entry_free(entry); + entry = sparse_entry; + sparse_entry = NULL; + } cleanup: if (bsdtar->verbose) @@ -908,8 +953,7 @@ abort: if (fd >= 0) close(fd); - if (entry != NULL) - archive_entry_free(entry); + archive_entry_free(entry); } @@ -920,12 +964,15 @@ write_file_data(struct bsdtar *bsdtar, struct archive *a, int fd) char buff[64*1024]; ssize_t bytes_read; ssize_t bytes_written; + off_t progress = 0; /* XXX TODO: Allocate buffer on heap and store pointer to * it in bsdtar structure; arrange cleanup as well. XXX */ bytes_read = read(fd, buff, sizeof(buff)); while (bytes_read > 0) { + siginfo_printinfo(bsdtar, progress); + bytes_written = archive_write_data(a, buff, bytes_read); if (bytes_written < 0) { /* Write failed; this is bad */ @@ -938,6 +985,7 @@ write_file_data(struct bsdtar *bsdtar, struct archive *a, int fd) "Truncated write; file may have grown while being archived."); return (0); } + progress += bytes_written; bytes_read = read(fd, buff, sizeof(buff)); } return 0; @@ -947,169 +995,12 @@ write_file_data(struct bsdtar *bsdtar, struct archive *a, int fd) static void create_cleanup(struct bsdtar *bsdtar) { - /* Free inode->pathname map used for hardlink detection. */ - if (bsdtar->links_cache != NULL) { - free_buckets(bsdtar, bsdtar->links_cache); - free(bsdtar->links_cache); - bsdtar->links_cache = NULL; - } - free_cache(bsdtar->uname_cache); bsdtar->uname_cache = NULL; free_cache(bsdtar->gname_cache); bsdtar->gname_cache = NULL; } - -static void -free_buckets(struct bsdtar *bsdtar, struct links_cache *links_cache) -{ - size_t i; - - if (links_cache->buckets == NULL) - return; - - for (i = 0; i < links_cache->number_buckets; i++) { - while (links_cache->buckets[i] != NULL) { - struct links_entry *lp = links_cache->buckets[i]->next; - if (bsdtar->option_warn_links) - bsdtar_warnc(bsdtar, 0, "Missing links to %s", - links_cache->buckets[i]->name); - if (links_cache->buckets[i]->name != NULL) - free(links_cache->buckets[i]->name); - free(links_cache->buckets[i]); - links_cache->buckets[i] = lp; - } - } - free(links_cache->buckets); - links_cache->buckets = NULL; -} - -static void -lookup_hardlink(struct bsdtar *bsdtar, struct archive_entry *entry, - const struct stat *st) -{ - struct links_cache *links_cache; - struct links_entry *le, **new_buckets; - int hash; - size_t i, new_size; - - /* If necessary, initialize the links cache. */ - links_cache = bsdtar->links_cache; - if (links_cache == NULL) { - bsdtar->links_cache = malloc(sizeof(struct links_cache)); - if (bsdtar->links_cache == NULL) - bsdtar_errc(bsdtar, 1, ENOMEM, - "No memory for hardlink detection."); - links_cache = bsdtar->links_cache; - memset(links_cache, 0, sizeof(struct links_cache)); - links_cache->number_buckets = links_cache_initial_size; - links_cache->buckets = malloc(links_cache->number_buckets * - sizeof(links_cache->buckets[0])); - if (links_cache->buckets == NULL) { - bsdtar_errc(bsdtar, 1, ENOMEM, - "No memory for hardlink detection."); - } - for (i = 0; i < links_cache->number_buckets; i++) - links_cache->buckets[i] = NULL; - } - - /* If the links cache overflowed and got flushed, don't bother. */ - if (links_cache->buckets == NULL) - return; - - /* If the links cache is getting too full, enlarge the hash table. */ - if (links_cache->number_entries > links_cache->number_buckets * 2) - { - new_size = links_cache->number_buckets * 2; - new_buckets = malloc(new_size * sizeof(struct links_entry *)); - - if (new_buckets != NULL) { - memset(new_buckets, 0, - new_size * sizeof(struct links_entry *)); - for (i = 0; i < links_cache->number_buckets; i++) { - while (links_cache->buckets[i] != NULL) { - /* Remove entry from old bucket. */ - le = links_cache->buckets[i]; - links_cache->buckets[i] = le->next; - - /* Add entry to new bucket. */ - hash = (le->dev ^ le->ino) % new_size; - - if (new_buckets[hash] != NULL) - new_buckets[hash]->previous = - le; - le->next = new_buckets[hash]; - le->previous = NULL; - new_buckets[hash] = le; - } - } - free(links_cache->buckets); - links_cache->buckets = new_buckets; - links_cache->number_buckets = new_size; - } else { - free_buckets(bsdtar, links_cache); - bsdtar_warnc(bsdtar, ENOMEM, - "No more memory for recording hard links"); - bsdtar_warnc(bsdtar, 0, - "Remaining links will be dumped as full files"); - } - } - - /* Try to locate this entry in the links cache. */ - hash = ( st->st_dev ^ st->st_ino ) % links_cache->number_buckets; - for (le = links_cache->buckets[hash]; le != NULL; le = le->next) { - if (le->dev == st->st_dev && le->ino == st->st_ino) { - archive_entry_copy_hardlink(entry, le->name); - - /* - * Decrement link count each time and release - * the entry if it hits zero. This saves - * memory and is necessary for proper -l - * implementation. - */ - if (--le->links <= 0) { - if (le->previous != NULL) - le->previous->next = le->next; - if (le->next != NULL) - le->next->previous = le->previous; - if (le->name != NULL) - free(le->name); - if (links_cache->buckets[hash] == le) - links_cache->buckets[hash] = le->next; - links_cache->number_entries--; - free(le); - } - - return; - } - } - - /* Add this entry to the links cache. */ - le = malloc(sizeof(struct links_entry)); - if (le != NULL) - le->name = strdup(archive_entry_pathname(entry)); - if ((le == NULL) || (le->name == NULL)) { - free_buckets(bsdtar, links_cache); - bsdtar_warnc(bsdtar, ENOMEM, - "No more memory for recording hard links"); - bsdtar_warnc(bsdtar, 0, - "Remaining hard links will be dumped as full files"); - if (le != NULL) - free(le); - return; - } - if (links_cache->buckets[hash] != NULL) - links_cache->buckets[hash]->previous = le; - links_cache->number_entries++; - le->next = links_cache->buckets[hash]; - le->previous = NULL; - links_cache->buckets[hash] = le; - le->dev = st->st_dev; - le->ino = st->st_ino; - le->links = st->st_nlink - 1; -} - #ifdef HAVE_POSIX_ACL static void setup_acl(struct bsdtar *bsdtar, struct archive_entry *entry, const char *accpath, @@ -1531,7 +1422,7 @@ test_for_append(struct bsdtar *bsdtar) { struct stat s; - if (*bsdtar->argv == NULL) + if (*bsdtar->argv == NULL && bsdtar->names_from_file == NULL) bsdtar_errc(bsdtar, 1, 0, "no files or directories specified"); if (bsdtar->filename == NULL) bsdtar_errc(bsdtar, 1, 0, "Cannot append to stdout."); diff --git a/contrib/libarchive-2/version b/contrib/libarchive-2/version index b29b92020a..bd20368be5 100644 --- a/contrib/libarchive-2/version +++ b/contrib/libarchive-2/version @@ -1 +1 @@ -2.4.17 \ No newline at end of file +2005004b -- 2.41.0