diff options
Diffstat (limited to 'archivers/libarchive/files/libarchive')
44 files changed, 3481 insertions, 911 deletions
diff --git a/archivers/libarchive/files/libarchive/archive.h b/archivers/libarchive/files/libarchive/archive.h new file mode 100644 index 00000000000..6bfe81eb24a --- /dev/null +++ b/archivers/libarchive/files/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 <sys/types.h> /* Linux requires this for off_t */ +#if !defined(__WATCOMC__) && !defined(_MSC_VER) +/* Header unavailable on Watcom C or MS Visual C++. */ +#include <inttypes.h> /* int64_t, etc. */ +#endif +#include <stdio.h> /* 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 <unistd.h> /* 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/archivers/libarchive/files/libarchive/archive_endian.h b/archivers/libarchive/files/libarchive/archive_endian.h index 259f5de91ea..61af4161c37 100644 --- a/archivers/libarchive/files/libarchive/archive_endian.h +++ b/archivers/libarchive/files/libarchive/archive_endian.h @@ -28,9 +28,23 @@ * Borrowed from FreeBSD's <sys/endian.h> */ +/* 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/archivers/libarchive/files/libarchive/archive_entry.3 b/archivers/libarchive/files/libarchive/archive_entry.3 index 8d96de1fbf4..e2d4ab11770 100644 --- a/archivers/libarchive/files/libarchive/archive_entry.3 +++ b/archivers/libarchive/files/libarchive/archive_entry.3 @@ -24,7 +24,7 @@ .\" .\" $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,6 +40,7 @@ .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 , @@ -48,6 +49,7 @@ .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 , @@ -95,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 , @@ -156,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 @@ -167,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 *" @@ -270,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 * @@ -376,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/archivers/libarchive/files/libarchive/archive_entry.c b/archivers/libarchive/files/libarchive/archive_entry.c index acc57291d45..210685af2b3 100644 --- a/archivers/libarchive/files/libarchive/archive_entry.c +++ b/archivers/libarchive/files/libarchive/archive_entry.c @@ -155,6 +155,7 @@ aes_clean(struct aes *aes) } archive_string_free(&(aes->aes_mbs)); archive_string_free(&(aes->aes_utf8)); + aes->aes_set = 0; } static void @@ -162,6 +163,7 @@ aes_copy(struct aes *dest, struct aes *src) { 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)); @@ -178,25 +180,28 @@ aes_copy(struct aes *dest, struct aes *src) static const char * aes_get_utf8(struct aes *aes) { - if (aes->aes_utf8.s == NULL || aes->aes_utf8.length == 0) { - if (aes->aes_wcs == NULL) - return (NULL); - if (archive_strappend_w_utf8(&(aes->aes_utf8), aes->aes_wcs) == NULL) - return (NULL); + 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 (aes->aes_utf8.s); + return (NULL); } static const char * aes_get_mbs(struct aes *aes) { /* If we already have an MBS form, return that immediately. */ - if (aes->aes_mbs.s != NULL && aes->aes_mbs.length != 0) + 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_wcs != NULL - && archive_strappend_w_mbs(&(aes->aes_mbs), aes->aes_wcs) != NULL) + 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); + } /* We'll use UTF-8 for MBS if all else fails. */ return (aes_get_utf8(aes)); } @@ -208,10 +213,10 @@ aes_get_wcs(struct aes *aes) int r; /* Return WCS form if we already have it. */ - if (aes->aes_wcs != NULL) + if (aes->aes_set & AES_SET_WCS) return (aes->aes_wcs); - if (aes->aes_mbs.s != NULL && aes->aes_mbs.length > 0) { + 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, @@ -224,14 +229,17 @@ aes_get_wcs(struct aes *aes) __archive_errx(1, "No memory for aes_get_wcs()"); r = mbstowcs(w, aes->aes_mbs.s, wcs_length); w[wcs_length] = 0; - if (r > 0) + if (r > 0) { + aes->aes_set |= AES_SET_WCS; return (aes->aes_wcs = w); + } free(w); } - if (aes->aes_utf8.s != NULL && aes->aes_utf8.length > 0) { + 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); @@ -246,6 +254,11 @@ aes_set_mbs(struct aes *aes, const char *mbs) static int aes_copy_mbs(struct aes *aes, const char *mbs) { + if (mbs == NULL) { + aes->aes_set = 0; + return (0); + } + 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) { @@ -268,6 +281,11 @@ aes_copy_mbs(struct aes *aes, const char *mbs) static int aes_update_utf8(struct aes *aes, const char *utf8) { + if (utf8 == NULL) { + aes->aes_set = 0; + return (1); /* Succeeded in clearing everything. */ + } + /* Save the UTF8 string. */ archive_strcpy(&(aes->aes_utf8), utf8); @@ -278,18 +296,24 @@ aes_update_utf8(struct aes *aes, const char *utf8) aes->aes_wcs = NULL; } - /* TODO: We should just do a UTF-8 to MBS conversion here. - * That would be faster, use less space, and give the same - * information. */ + 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); @@ -298,7 +322,7 @@ aes_update_utf8(struct aes *aes, const char *utf8) static int aes_copy_wcs(struct aes *aes, const wchar_t *wcs) { - return aes_copy_wcs_len(aes, wcs, wcslen(wcs)); + return aes_copy_wcs_len(aes, wcs, wcs == NULL ? 0 : wcslen(wcs)); } static int @@ -306,6 +330,11 @@ aes_copy_wcs_len(struct aes *aes, const wchar_t *wcs, size_t len) { wchar_t *w; + if (wcs == NULL) { + aes->aes_set = 0; + return (0); + } + 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) { @@ -623,6 +652,12 @@ archive_entry_size(struct archive_entry *entry) } 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) @@ -922,6 +957,12 @@ archive_entry_set_size(struct archive_entry *entry, int64_t 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); @@ -1889,13 +1930,13 @@ ae_strtofflags(const char *s, unsigned long *setp, unsigned long *clrp) while (*end != '\0' && *end != '\t' && *end != ' ' && *end != ',') end++; - for (flag = flags; flag->wname != NULL; flag++) { - if (memcmp(start, flag->wname, end - start) == 0) { + 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->wname + 2, end - start) + } else if (memcmp(start, flag->name + 2, end - start) == 0) { /* Matched "XXXX", so don't reverse. */ set |= flag->set; @@ -1904,7 +1945,7 @@ ae_strtofflags(const char *s, unsigned long *setp, unsigned long *clrp) } } /* Ignore unknown flag names. */ - if (flag->wname == NULL && failed == NULL) + if (flag->name == NULL && failed == NULL) failed = start; /* Find start of next token. */ diff --git a/archivers/libarchive/files/libarchive/archive_entry.h b/archivers/libarchive/files/libarchive/archive_entry.h index ba2255e220b..f8601b9ee28 100644 --- a/archivers/libarchive/files/libarchive/archive_entry.h +++ b/archivers/libarchive/files/libarchive/archive_entry.h @@ -28,6 +28,14 @@ #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 <sys/types.h> #include <stddef.h> /* for wchar_t */ #include <time.h> @@ -37,19 +45,26 @@ #ifdef _WIN32 #define __LA_UID_T unsigned int #define __LA_GID_T unsigned int -#define __LA_INO_T unsigned int #define __LA_DEV_T unsigned int #define __LA_MODE_T unsigned short #else #include <unistd.h> #define __LA_UID_T uid_t #define __LA_GID_T gid_t -#define __LA_INO_T ino_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. @@ -69,7 +84,7 @@ # endif # endif #else -/* Static libraries and shared libraries on non-Windows. */ +/* Static libraries on all platforms and shared libraries on non-Windows. */ # define __LA_DECL #endif @@ -80,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, @@ -139,40 +154,41 @@ __LA_DECL struct archive_entry *archive_entry_new(void); * Retrieve fields from an 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 *, +__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 */); -__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 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 *); +__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. @@ -220,6 +236,7 @@ __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 *); diff --git a/archivers/libarchive/files/libarchive/archive_entry_link_resolver.c b/archivers/libarchive/files/libarchive/archive_entry_link_resolver.c index 0df9ff92e68..c0770c239de 100644 --- a/archivers/libarchive/files/libarchive/archive_entry_link_resolver.c +++ b/archivers/libarchive/files/libarchive/archive_entry_link_resolver.c @@ -60,8 +60,9 @@ __FBSDID("$FreeBSD: src/lib/libarchive/archive_entry_link_resolver.c,v 1.1 2007/ /* 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_OLD_CPIO 1 -#define ARCHIVE_ENTRY_LINKIFY_LIKE_NEW_CPIO 2 +#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 @@ -130,6 +131,9 @@ archive_entry_linkresolver_set_strategy(struct archive_entry_linkresolver *res, 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; @@ -144,6 +148,9 @@ archive_entry_linkresolver_free(struct archive_entry_linkresolver *res) { struct links_entry *le; + if (res == NULL) + return; + if (res->buckets != NULL) { while ((le = next_entry(res)) != NULL) archive_entry_free(le->entry); @@ -164,8 +171,10 @@ archive_entry_linkify(struct archive_entry_linkresolver *res, if (*e == NULL) { le = next_entry(res); - if (le != NULL) + if (le != NULL) { *e = le->entry; + le->entry = NULL; + } return; } @@ -178,7 +187,15 @@ 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_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); @@ -198,12 +215,14 @@ archive_entry_linkify(struct archive_entry_linkresolver *res, le->entry = t; /* Make the old entry into a hardlink. */ archive_entry_set_size(*e, 0); - archive_entry_set_hardlink(*e, + 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) + if (le->links == 0) { *f = le->entry; + le->entry = NULL; + } } else { /* * If we haven't seen it, tuck it away @@ -232,6 +251,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; } @@ -248,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 @@ -320,7 +340,8 @@ insert_entry(struct archive_entry_linkresolver *res, le = malloc(sizeof(struct links_entry)); if (le == NULL) return (NULL); - le->entry = entry; + 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) @@ -338,7 +359,6 @@ insert_entry(struct archive_entry_linkresolver *res, res->buckets[bucket] = le; le->hash = hash; le->links = archive_entry_nlink(entry) - 1; - le->canonical = archive_entry_clone(entry); return (le); } diff --git a/archivers/libarchive/files/libarchive/archive_entry_private.h b/archivers/libarchive/files/libarchive/archive_entry_private.h index d8dd9b6b70d..f893fb982ae 100644 --- a/archivers/libarchive/files/libarchive/archive_entry_private.h +++ b/archivers/libarchive/files/libarchive/archive_entry_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_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 @@ -33,13 +33,20 @@ /* * Handle wide character (i.e., Unicode) and non-wide character * strings transparently. - * */ struct aes { struct archive_string aes_mbs; struct archive_string aes_utf8; const wchar_t *aes_wcs; + /* 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 { @@ -129,8 +136,6 @@ struct archive_entry { dev_t aest_rdevminor; } ae_stat; - - /* * Use aes here so that we get transparent mbs<->wcs conversions. */ @@ -145,15 +150,21 @@ struct archive_entry { 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/archivers/libarchive/files/libarchive/archive_entry_strmode.c b/archivers/libarchive/files/libarchive/archive_entry_strmode.c index dc08d9721a6..cfe6ae33baa 100644 --- a/archivers/libarchive/files/libarchive/archive_entry_strmode.c +++ b/archivers/libarchive/files/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 <sys/stat.h> @@ -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/archivers/libarchive/files/libarchive/archive_read.3 b/archivers/libarchive/files/libarchive/archive_read.3 index e15c904a712..dbbe1f7f1e6 100644 --- a/archivers/libarchive/files/libarchive/archive_read.3 +++ b/archivers/libarchive/files/libarchive/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 @@ -145,6 +146,12 @@ .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 .Fo archive_read_extract_set_progress_callback .Fa "struct archive *" @@ -314,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. diff --git a/archivers/libarchive/files/libarchive/archive_read_data_into_fd.c b/archivers/libarchive/files/libarchive/archive_read_data_into_fd.c index 664cc2c3c24..3aeef3bc2da 100644 --- a/archivers/libarchive/files/libarchive/archive_read_data_into_fd.c +++ b/archivers/libarchive/files/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 <sys/types.h> @@ -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/archivers/libarchive/files/libarchive/archive_read_extract.c b/archivers/libarchive/files/libarchive/archive_read_extract.c index bb5add7bbdc..ab01f7df3e2 100644 --- a/archivers/libarchive/files/libarchive/archive_read_extract.c +++ b/archivers/libarchive/files/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/archivers/libarchive/files/libarchive/archive_read_support_compression_bzip2.c b/archivers/libarchive/files/libarchive/archive_read_support_compression_bzip2.c index 372eff09541..e6397df9634 100644 --- a/archivers/libarchive/files/libarchive/archive_read_support_compression_bzip2.c +++ b/archivers/libarchive/files/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/archivers/libarchive/files/libarchive/archive_read_support_compression_program.c b/archivers/libarchive/files/libarchive/archive_read_support_compression_program.c index 58b4bbddf0b..206215c897c 100644 --- a/archivers/libarchive/files/libarchive/archive_read_support_compression_program.c +++ b/archivers/libarchive/files/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 <sys/wait.h> #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/archivers/libarchive/files/libarchive/archive_read_support_format_ar.c b/archivers/libarchive/files/libarchive/archive_read_support_format_ar.c index f6e4cc7e2ab..15d7e7cfd72 100644 --- a/archivers/libarchive/files/libarchive/archive_read_support_format_ar.c +++ b/archivers/libarchive/files/libarchive/archive_read_support_format_ar.c @@ -350,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); diff --git a/archivers/libarchive/files/libarchive/archive_read_support_format_iso9660.c b/archivers/libarchive/files/libarchive/archive_read_support_format_iso9660.c index d333f0ccb4e..e0825a36e1a 100644 --- a/archivers/libarchive/files/libarchive/archive_read_support_format_iso9660.c +++ b/archivers/libarchive/files/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 - /* <sigh> 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/archivers/libarchive/files/libarchive/archive_read_support_format_mtree.c b/archivers/libarchive/files/libarchive/archive_read_support_format_mtree.c index f1980e6bd10..72232ed7e03 100644 --- a/archivers/libarchive/files/libarchive/archive_read_support_format_mtree.c +++ b/archivers/libarchive/files/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.4 2008/03/15 11:02:47 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 <sys/stat.h> @@ -54,11 +55,29 @@ __FBSDID("$FreeBSD: src/lib/libarchive/archive_read_support_format_mtree.c,v 1.4 #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; }; @@ -77,18 +96,20 @@ struct mtree { 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 *); + struct mtree *, struct mtree_entry *, int *); static void parse_escapes(char *, struct mtree_entry *); static int parse_line(struct archive_read *, struct archive_entry *, - struct mtree *, struct mtree_entry *); + struct mtree *, struct mtree_entry *, int *); static int parse_keyword(struct archive_read *, struct mtree *, - struct archive_entry *, char *, char *); + 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); @@ -97,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) @@ -129,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; @@ -184,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; @@ -216,46 +433,27 @@ 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; } /* @@ -267,7 +465,7 @@ read_header(struct archive_read *a, struct archive_entry *entry) { struct mtree *mtree; char *p; - int r; + int r, use_next; mtree = (struct mtree *)(a->format->data); @@ -277,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); @@ -303,8 +506,10 @@ read_header(struct archive_read *a, struct archive_entry *entry) } } if (!mtree->this_entry->used) { - r = parse_file(a, entry, mtree, mtree->this_entry); - return (r); + 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; } @@ -317,11 +522,13 @@ read_header(struct archive_read *a, struct archive_entry *entry) */ static int parse_file(struct archive_read *a, struct archive_entry *entry, - struct mtree *mtree, struct mtree_entry *mentry) + struct mtree *mtree, struct mtree_entry *mentry, int *use_next) { - struct stat st; + const char *path; + struct stat st_storage, *st; struct mtree_entry *mp; - int r = ARCHIVE_OK, r1; + struct archive_entry *sparse_entry; + int r = ARCHIVE_OK, r1, parsed_kws, mismatched_type; mentry->used = 1; @@ -330,7 +537,8 @@ parse_file(struct archive_read *a, struct archive_entry *entry, archive_entry_set_size(entry, 0); /* Parse options from this line. */ - r = parse_line(a, entry, mtree, mentry); + parsed_kws = 0; + r = parse_line(a, entry, mtree, mentry, &parsed_kws); if (mentry->full) { archive_entry_copy_pathname(entry, mentry->name); @@ -349,7 +557,8 @@ parse_file(struct archive_read *a, struct archive_entry *entry, && strcmp(mentry->name, mp->name) == 0) { /* Later lines override earlier ones. */ mp->used = 1; - r1 = parse_line(a, entry, mtree, mp); + r1 = parse_line(a, entry, mtree, mp, + &parsed_kws); if (r1 < r) r = r1; } @@ -381,49 +590,126 @@ parse_file(struct archive_read *a, struct archive_entry *entry, * disk.) */ mtree->fd = -1; - if (archive_strlen(&mtree->contents_name) > 0) { - mtree->fd = open(mtree->contents_name.s, + 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 < 0) { + if (mtree->fd == -1 && + (errno != ENOENT || + archive_strlen(&mtree->contents_name) > 0)) { archive_set_error(&a->archive, errno, - "Can't open content=\"%s\"", - mtree->contents_name.s); + "Can't open %s", path); r = ARCHIVE_WARN; } - } else if (archive_entry_filetype(entry) == AE_IFREG) { - mtree->fd = open(archive_entry_pathname(entry), - O_RDONLY | O_BINARY); } - /* - * 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). - */ + st = &st_storage; if (mtree->fd >= 0) { - if (fstat(mtree->fd, &st) != 0) { + if (fstat(mtree->fd, st) == -1) { archive_set_error(&a->archive, errno, - "could not stat %s", - archive_entry_pathname(entry)); + "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; - } else if ((st.st_mode & S_IFMT) != S_IFREG) { - archive_set_error(&a->archive, errno, - "%s is not a regular file", - archive_entry_pathname(entry)); - r = ARCHIVE_WARN; + 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; + } /* Don't hold a non-regular file open. */ close(mtree->fd); mtree->fd = -1; - } else { - archive_entry_set_size(entry, st.st_size); - archive_entry_set_ino(entry, st.st_ino); - archive_entry_set_dev(entry, st.st_dev); - archive_entry_set_nlink(entry, st.st_nlink); + st = NULL; + return r; } } + + 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); + + 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; @@ -435,36 +721,82 @@ parse_file(struct archive_read *a, struct archive_entry *entry, */ static int parse_line(struct archive_read *a, struct archive_entry *entry, - struct mtree *mtree, struct mtree_entry *mp) + struct mtree *mtree, struct mtree_entry *mp, int *parsed_kws) { - char *p, *q; + struct mtree_option *iter; int r = ARCHIVE_OK, r1; - p = mp->option_start; - while (p < mp->option_end) { - q = p + strlen(p); - r1 = parse_keyword(a, mtree, entry, p, q); + for (iter = mp->options; iter != NULL; iter = iter->next) { + r1 = parse_keyword(a, mtree, entry, iter, parsed_kws); if (r1 < r) r = r1; - p = q + 1; + } + 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; + + 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, char *key, char *end) + struct archive_entry *entry, struct mtree_option *option, int *parsed_kws) { - char *val; + char *val, *key; + + key = option->value; - if (end == key) - return (ARCHIVE_OK); 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, @@ -483,38 +815,93 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, 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_set_link(entry, val); + 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) { @@ -554,16 +941,14 @@ parse_keyword(struct archive_read *a, struct mtree *mtree, 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; } @@ -596,6 +981,7 @@ 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; @@ -642,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) @@ -724,6 +1117,66 @@ mtree_atol10(char **p) } /* + * 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 * point to first character of line. diff --git a/archivers/libarchive/files/libarchive/archive_read_support_format_tar.c b/archivers/libarchive/files/libarchive/archive_read_support_format_tar.c index 147ec0b2795..6d7f048a40d 100644 --- a/archivers/libarchive/files/libarchive/archive_read_support_format_tar.c +++ b/archivers/libarchive/files/libarchive/archive_read_support_format_tar.c @@ -2303,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/archivers/libarchive/files/libarchive/archive_string.c b/archivers/libarchive/files/libarchive/archive_string.c index e308c480bba..7c378deead4 100644 --- a/archivers/libarchive/files/libarchive/archive_string.c +++ b/archivers/libarchive/files/libarchive/archive_string.c @@ -41,6 +41,14 @@ __FBSDID("$FreeBSD: src/lib/libarchive/archive_string.c,v 1.11 2007/07/15 19:13: #include <wchar.h> #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" diff --git a/archivers/libarchive/files/libarchive/archive_windows.c b/archivers/libarchive/files/libarchive/archive_windows.c new file mode 100644 index 00000000000..1f4d273dabb --- /dev/null +++ b/archivers/libarchive/files/libarchive/archive_windows.c @@ -0,0 +1,188 @@ +/*- + * Copyright (c) 2003-2007 Kees Zeelenberg + * 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$ + */ + +/* + * A set of compatibility glue for building libarchive on Windows platforms. + * + * Originally created as "libarchive-nonposix.c" by Kees Zeelenberg + * for the GnuWin32 project, trimmed significantly by Tim Kientzle. + * + * Much of the original file was unnecessary for libarchive, because + * many of the features it emulated were not strictly necessary for + * libarchive. I hope for this to shrink further as libarchive + * internals are gradually reworked to sit more naturally on both + * POSIX and Windows. Any ideas for this are greatly appreciated. + * + * The biggest remaining issue is the dev/ino emulation; libarchive + * has a couple of public APIs that rely on dev/ino uniquely + * identifying a file. This doesn't match well with Windows. I'm + * considering alternative APIs. + */ + +#ifdef _WIN32 + +#include <errno.h> +#include <stddef.h> +#include <sys/utime.h> +#include <sys/stat.h> +#include <process.h> +#include <stdlib.h> +#include <windows.h> +#include "archive_platform.h" + +/* Make a link to FROM called TO. */ +int link (from, to) + const char *from; + const char *to; +{ + int res; + + if (from == NULL || to == NULL) { + set_errno (EINVAL); + return -1; + } + + if (!_access (from, F_OK)) + res = CopyFile (from, to, FALSE); + else { + /* from doesn not exist; try to prepend it with the dirname of to */ + char *fullfrompath, *slash, *todir; + todir = strdup (to); + if (!todir) + return -1; + slash = strrchr(todir, '/'); + if (slash) + *slash = '\0'; + fullfrompath = malloc (strlen (from) + strlen (todir) + 2); + if (!fullfrompath) + return -1; + strcpy (fullfrompath, todir); + strcat (fullfrompath, "/"); + strcat (fullfrompath, from); + if (todir) + free (todir); + if (_access (fullfrompath, R_OK)) + return -1; + res = CopyFile (fullfrompath, to, FALSE); + if (fullfrompath) + free (fullfrompath); + } + + if (res == 0) { + set_errno (EINVAL); + return -1; + } + return 0; +} + +/* Make a symbolic link to FROM called TO. */ +int symlink (from, to) + const char *from; + const char *to; +{ + return link (from, to); +} + +static int get_dev_ino (HANDLE hFile, dev_t *dev, ino_t *ino) +{ +/* dev_t: short (2 bytes); ino_t: unsigned int (4 bytes) */ +#define LODWORD(l) ((DWORD)((DWORDLONG)(l))) +#define HIDWORD(l) ((DWORD)(((DWORDLONG)(l)>>32)&0xFFFFFFFF)) +#define MAKEDWORDLONG(a,b) ((DWORDLONG)(((DWORD)(a))|(((DWORDLONG)((DWORD)(b)))<<32))) + +#define INOSIZE (8*sizeof(ino_t)) /* 32 */ +//#define DEVSIZE (8*sizeof(dev_t)) /* 16 */ +#define SEQNUMSIZE (16) + + BY_HANDLE_FILE_INFORMATION FileInformation; + uint64_t ino64, FileReferenceNumber ; + ino_t resino; + dev_t resdev; + DWORD VolumeSerialNumber; + + *ino = 0; + *dev = 0; + if (hFile == INVALID_HANDLE_VALUE) /* file cannot be opened */ + return 0; + ZeroMemory (&FileInformation, sizeof(FileInformation)); + if (!GetFileInformationByHandle (hFile, &FileInformation)) /* cannot obtain FileInformation */ + return 0; + ino64 = (uint64_t) MAKEDWORDLONG ( + FileInformation.nFileIndexLow, FileInformation.nFileIndexHigh); + FileReferenceNumber = ino64 & ((~(0ULL)) >> SEQNUMSIZE); /* remove sequence number */ + /* transform 64-bits ino into 32-bits by hashing */ + resino = (ino_t) ( + ( (LODWORD(FileReferenceNumber)) ^ ((LODWORD(FileReferenceNumber)) >> INOSIZE) ) +// ^ +// ( (HIDWORD(FileReferenceNumber)) ^ ((HIDWORD(FileReferenceNumber)) >> INOSIZE) ) + ); + *ino = resino; + VolumeSerialNumber = FileInformation.dwVolumeSerialNumber; + //resdev = (unsigned short) ( (LOWORD(VolumeSerialNumber)) ^ ((HIWORD(VolumeSerialNumber)) >> DEVSIZE) ); + resdev = (dev_t) VolumeSerialNumber; + *dev = resdev; +//printf ("get_dev_ino: dev = %d; ino = %u\n", resdev, resino); + return 0; +} + +int get_dev_ino_fd (int fd, dev_t *dev, ino_t *ino) +{ + HANDLE hFile; + hFile = (HANDLE) _get_osfhandle (fd); + return get_dev_ino (hFile, dev, ino); +} + +int get_dev_ino_filename (char *path, dev_t *dev, ino_t *ino) +{ + HANDLE hFile; + int res; + if (!path || !*path) /* path = NULL */ + return 0; + if (_access (path, F_OK)) /* path does not exist */ + return -1; +/* obtain handle to file "name"; FILE_FLAG_BACKUP_SEMANTICS is used to open directories */ + hFile = CreateFile (path, 0, 0, NULL, OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS | FILE_ATTRIBUTE_READONLY, + NULL); + res = get_dev_ino (hFile, dev, ino); + CloseHandle (hFile); + return res; +} + +int fstati64 (int fd, struct _stati64 *st) +{ + int res; + res = _fstati64 (fd, st); + if (res < 0) + return -1; + if (st->st_ino == 0) + res = get_dev_ino_fd (fd, &st->st_dev, &st->st_ino); +// printf ("fstat: dev = %u; ino = %u\n", st->st_dev, st->st_ino); + return res; +} + +#endif /* _WIN32 */ diff --git a/archivers/libarchive/files/libarchive/archive_windows.h b/archivers/libarchive/files/libarchive/archive_windows.h new file mode 100644 index 00000000000..9bc21e4de8f --- /dev/null +++ b/archivers/libarchive/files/libarchive/archive_windows.h @@ -0,0 +1,152 @@ +/*- + * Copyright (c) 2003-2006 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 + * in this position and unchanged. + * 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$ + */ + +#ifndef LIBARCHIVE_NONPOSIX_H_INCLUDED +#define LIBARCHIVE_NONPOSIX_H_INCLUDED + +/* Start of configuration for native Win32 */ + +#include <errno.h> +#define set_errno(val) ((errno)=val) +#include <io.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <process.h> +#include <direct.h> + +#define EFTYPE 7 +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 + +/* TODO: Fix the code, don't suppress the warnings. */ +#pragma warning(disable:4244) /* 'conversion' conversion from 'type1' to 'type2', possible loss of data */ +#pragma warning(disable:4146) /* unary minus operator applied to unsigned type, result still unsigned */ +#pragma warning(disable:4996) /* 'function': was declared deprecated */ +#pragma warning(disable:4267) /* Conversion, possible loss of data */ + +/* Basic definitions for system and integer types. */ +#ifndef _SSIZE_T_ +# define SSIZE_MAX LONG_MAX +#define _SSIZE_T_ +#endif /* _SSIZE_T_ */ + +#ifndef NULL +#ifdef __cplusplus +#define NULL 0 +#else +#define NULL ((void *)0) +#endif +#endif + +/* Replacement for major/minor/makedev. */ +#define major(x) ((int)(0x00ff & ((x) >> 8))) +#define minor(x) ((int)(0xffff00ff & (x))) +#define makedev(maj,min) ((0xff00 & ((maj)<<8))|(0xffff00ff & (min))) + +#define EFTYPE 7 +#ifndef STDERR_FILENO +#define STDERR_FILENO 2 +#endif /* STDERR_FILENO */ + +/* Alias the Windows _function to the POSIX equivalent. */ +#define chdir _chdir +#define chmod _chmod +#define close _close +#define fileno _fileno +#define fstat _fstat +#define lseek _lseek +#define open _open +#define stat _stat +#define mkdir(d,m) _mkdir(d) +#define mktemp _mktemp +#define read _read +#define rmdir _rmdir +#define strdup _strdup +#define tzset _tzset +#define umask _umask +#define write _write + +#define O_RDONLY _O_RDONLY +#define O_WRONLY _O_WRONLY +#define O_TRUNC _O_TRUNC +#define O_CREAT _O_CREAT +#define O_EXCL _O_EXCL + +#define S_ISUID 0004000 +#define S_ISGID 0002000 +#define S_ISVTX 0001000 + +#define S_IFMT 0170000 +#define S_IFDIR _S_IFDIR +#define S_IFREG _S_IFREG + +#define S_ISDIR(m) (((m) & 0170000) == _S_IFDIR) /* directory */ +#define S_ISCHR(m) (((m) & 0170000) == _S_IFCHR) /* char special */ +#define S_ISREG(m) (((m) & 0170000) == _S_IFREG) /* regular file */ + +/* Windows doesn't have the following, so they're trivial. */ +#define S_ISBLK(m) (0) /* block special */ +#define S_ISFIFO(m) (0) /* fifo or socket */ +#define S_ISLNK(m) (0) /* Symbolic link */ +#define S_ISSOCK(m) (0) /* Socket */ + +/* replace stat and seek by their large-file equivalents */ +#undef stat +#define stat _stati64 +#undef fstat +#define fstat _fstati64 + +#undef lseek +#define lseek _lseeki64 +#define lseek64 _lseeki64 +#define tell _telli64 +#define tell64 _telli64 + +#ifdef __MINGW32__ +# define fseek fseeko64 +# define fseeko fseeko64 +# define ftell ftello64 +# define ftello ftello64 +# define ftell64 ftello64 +#endif /* __MINGW32__ */ + +/* End of Win32 definitions. */ + +#ifdef __cplusplus +extern "C" { +#endif + +extern int link (const char *from, const char *to); +extern int symlink (const char *from, const char *to); + +#ifdef __cplusplus +} +#endif + +#endif /* LIBARCHIVE_NONPOSIX_H_INCLUDED */ diff --git a/archivers/libarchive/files/libarchive/archive_write.3 b/archivers/libarchive/files/libarchive/archive_write.3 index 253b39e7826..fff84f7cddc 100644 --- a/archivers/libarchive/files/libarchive/archive_write.3 +++ b/archivers/libarchive/files/libarchive/archive_write.3 @@ -24,7 +24,7 @@ .\" .\" $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,6 +67,8 @@ .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 *" @@ -197,6 +200,7 @@ the pax extended header for most normal files. In most cases, this will result in ordinary ustar archives. .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 diff --git a/archivers/libarchive/files/libarchive/archive_write_disk.3 b/archivers/libarchive/files/libarchive/archive_write_disk.3 index 5d836e105e3..f71d7d54854 100644 --- a/archivers/libarchive/files/libarchive/archive_write_disk.3 +++ b/archivers/libarchive/files/libarchive/archive_write_disk.3 @@ -170,6 +170,10 @@ Note that paths ending in .Pa .. always cause an error, regardless of this flag. .El +.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 diff --git a/archivers/libarchive/files/libarchive/archive_write_disk.c b/archivers/libarchive/files/libarchive/archive_write_disk.c index 620beac48ed..8010c1330ea 100644 --- a/archivers/libarchive/files/libarchive/archive_write_disk.c +++ b/archivers/libarchive/files/libarchive/archive_write_disk.c @@ -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; @@ -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 (a->fd >= 0 && fstat(a->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/archivers/libarchive/files/libarchive/archive_write_set_compression_program.c b/archivers/libarchive/files/libarchive/archive_write_set_compression_program.c index fc1481dbcd9..b8b20c86cf9 100644 --- a/archivers/libarchive/files/libarchive/archive_write_set_compression_program.c +++ b/archivers/libarchive/files/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 <sys/wait.h> #endif @@ -320,3 +337,5 @@ cleanup: free(state); return (ret); } + +#endif /* !defined(HAVE_PIPE) || !defined(HAVE_VFORK) || !defined(HAVE_FCNTL) */ diff --git a/archivers/libarchive/files/libarchive/archive_write_set_format_ar.c b/archivers/libarchive/files/libarchive/archive_write_set_format_ar.c index 313d0b390f9..1731844d339 100644 --- a/archivers/libarchive/files/libarchive/archive_write_set_format_ar.c +++ b/archivers/libarchive/files/libarchive/archive_write_set_format_ar.c @@ -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. @@ -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/archivers/libarchive/files/libarchive/archive_write_set_format_pax.c b/archivers/libarchive/files/libarchive/archive_write_set_format_pax.c index 585989fd79b..89f89bc9f54 100644 --- a/archivers/libarchive/files/libarchive/archive_write_set_format_pax.c +++ b/archivers/libarchive/files/libarchive/archive_write_set_format_pax.c @@ -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; @@ -508,35 +508,60 @@ archive_write_pax_header(struct archive_write *a, add_pax_attr_w(&(pax->pax_header), "path", path_w); archive_entry_set_pathname(entry_main, "@WidePath"); need_extension = 1; - } else { - /* We have a narrow path; we first need to decide - * if we can just put it in the ustar header. */ - suffix_start = path; /* Start with a zero-length prefix. */ - if (strlen(path) > 100) { - /* Find largest suffix that will fit. */ - suffix_start = strchr(path + strlen(path) - 100 - 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 { + /* Store UTF-8 */ + add_pax_attr_w(&(pax->pax_header), + "path", path_w); } - /* 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.) + 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 (has_non_ASCII(path_w) || suffix_start == NULL - || suffix_start - path > 155) { - /* Path is either too long or has non-ASCII 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); + 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; } - archive_entry_set_pathname(entry_main, - build_ustar_entry_name(ustar_entry_name, - path, strlen(path), NULL)); - need_extension = 1; } } diff --git a/archivers/libarchive/files/libarchive/archive_write_set_format_ustar.c b/archivers/libarchive/files/libarchive/archive_write_set_format_ustar.c index c2c0011aee2..970fee8db1b 100644 --- a/archivers/libarchive/files/libarchive/archive_write_set_format_ustar.c +++ b/archivers/libarchive/files/libarchive/archive_write_set_format_ustar.c @@ -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/archivers/libarchive/files/libarchive/config_freebsd.h b/archivers/libarchive/files/libarchive/config_freebsd.h index 97127a19be8..3d5e821612f 100644 --- a/archivers/libarchive/files/libarchive/config_freebsd.h +++ b/archivers/libarchive/files/libarchive/config_freebsd.h @@ -51,6 +51,7 @@ #define HAVE_FCHFLAGS 1 #define HAVE_FCHMOD 1 #define HAVE_FCHOWN 1 +#define HAVE_FCNTL 1 #define HAVE_FCNTL_H 1 #define HAVE_FSEEKO 1 #define HAVE_FSTAT 1 @@ -70,6 +71,7 @@ #define HAVE_MKDIR 1 #define HAVE_MKFIFO 1 #define HAVE_MKNOD 1 +#define HAVE_PIPE 1 #define HAVE_POLL 1 #define HAVE_POLL_H 1 #define HAVE_PWD_H 1 @@ -102,6 +104,7 @@ #define HAVE_UTIME 1 #define HAVE_UTIMES 1 #define HAVE_UTIME_H 1 +#define HAVE_VFORK 1 #define HAVE_WCHAR_H 1 #define HAVE_WCSCPY 1 #define HAVE_WCSLEN 1 diff --git a/archivers/libarchive/files/libarchive/config_windows.h b/archivers/libarchive/files/libarchive/config_windows.h index 64eb15f3317..0ccb2f1b166 100644 --- a/archivers/libarchive/files/libarchive/config_windows.h +++ b/archivers/libarchive/files/libarchive/config_windows.h @@ -1,510 +1,688 @@ -/* config.h. Generated from config.h.in by configure. */ -/* config.h.in. Generated from configure.ac by autoheader. */ -#ifndef CONFIG_H_INCLUDED -#define CONFIG_H_INCLUDED - -/* Version number of bsdcpio */ -#define BSDCPIO_VERSION_STRING "0.9.9" - -/* Version number of bsdtar */ -#define BSDTAR_VERSION_STRING "2.5.0" - -/* Define to 1 if you have the `acl_create_entry' function. */ -/* #undef HAVE_ACL_CREATE_ENTRY */ - -/* Define to 1 if you have the `acl_get_perm' function. */ -/* #undef HAVE_ACL_GET_PERM */ - -/* Define to 1 if you have the `acl_get_perm_np' function. */ -/* #undef HAVE_ACL_GET_PERM_NP */ - -/* Define to 1 if you have the `acl_init' function. */ -/* #undef HAVE_ACL_INIT */ - -/* Define to 1 if the system has the type `acl_permset_t'. */ -/* #undef HAVE_ACL_PERMSET_T */ - -/* Define to 1 if you have the `acl_set_fd' function. */ -/* #undef HAVE_ACL_SET_FD */ - -/* Define to 1 if you have the `acl_set_fd_np' function. */ -/* #undef HAVE_ACL_SET_FD_NP */ - -/* Define to 1 if you have the `acl_set_file' function. */ -/* #undef HAVE_ACL_SET_FILE */ - -/* True for systems with POSIX ACL support */ -/* #undef HAVE_ACL_USER */ - -/* Define to 1 if you have the <attr/xattr.h> header file. */ -/* #undef HAVE_ATTR_XATTR_H */ - -/* Define to 1 if you have the <bzlib.h> header file. */ -/* #undef HAVE_BZLIB_H */ - -/* Define to 1 if you have the `chflags' function. */ -/* #undef HAVE_CHFLAGS */ - -/* Define to 1 if you have the `chown' function. */ -/* #undef HAVE_CHOWN */ - -/* Define to 1 if you have the declaration of `INT64_MAX', and to 0 if you - don't. */ -/* #undef HAVE_DECL_INT64_MAX */ - -/* Define to 1 if you have the declaration of `INT64_MIN', and to 0 if you - don't. */ -/* #undef HAVE_DECL_INT64_MIN */ - -/* Define to 1 if you have the declaration of `optarg', and to 0 if you don't. - */ -/* #undef HAVE_DECL_OPTARG */ - -/* Define to 1 if you have the declaration of `optind', and to 0 if you don't. - */ -/* #undef HAVE_DECL_OPTIND */ - -/* Define to 1 if you have the declaration of `SIZE_MAX', and to 0 if you - don't. */ -#if defined(_MSC_VER) && _MSC_VER >= 1400 -#define HAVE_DECL_SIZE_MAX 1 -#else -/* #undef HAVE_DECL_SIZE_MAX */ -#endif - -/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you - don't. */ -/* #undef HAVE_DECL_STRERROR_R */ - -/* Define to 1 if you have the declaration of `UINT32_MAX', and to 0 if you - don't. */ -/* #undef HAVE_DECL_UINT32_MAX */ - -/* Define to 1 if you have the declaration of `UINT64_MAX', and to 0 if you - don't. */ -/* #undef HAVE_DECL_UINT64_MAX */ - -/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'. - */ -/* #undef HAVE_DIRENT_H */ - -/* Define to 1 if you have the <dlfcn.h> header file. */ -/* #undef HAVE_DLFCN_H */ - -/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ -/* #undef HAVE_DOPRNT */ - -/* Define to 1 if nl_langinfo supports D_MD_ORDER */ -/* #undef HAVE_D_MD_ORDER */ - -/* A possible errno value for invalid file format errors */ -#define HAVE_EFTYPE 1 - -/* A possible errno value for invalid file format errors */ -#define HAVE_EILSEQ 1 - -/* Define to 1 if you have the <errno.h> header file. */ -#define HAVE_ERRNO_H 1 - -/* Define to 1 if you have the <ext2fs/ext2_fs.h> header file. */ -/* #undef HAVE_EXT2FS_EXT2_FS_H */ - -/* Define to 1 if you have the `fchdir' function. */ -/* #undef HAVE_FCHDIR */ - -/* Define to 1 if you have the `fchflags' function. */ -/* #undef HAVE_FCHFLAGS */ - -/* Define to 1 if you have the `fchmod' function. */ -/* #undef HAVE_FCHMOD */ - -/* Define to 1 if you have the `fchown' function. */ -/* #undef HAVE_FCHOWN */ - -/* Define to 1 if you have the <fcntl.h> header file. */ -#define HAVE_FCNTL_H 1 - -/* Define to 1 if your system has a working POSIX `fnmatch' function. */ -/* #undef HAVE_FNMATCH */ - -/* Define to 1 if fnmatch(3) supports the FNM_LEADING_DIR flag */ -/* #undef HAVE_FNM_LEADING_DIR */ - -/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */ -/* #undef HAVE_FSEEKO */ - -/* Define to 1 if you have the `fsetxattr' function. */ -/* #undef HAVE_FSETXATTR */ - -/* Define to 1 if you have the `ftruncate' function. */ -/* #undef HAVE_FTRUNCATE */ - -/* Define to 1 if you have the `futimes' function. */ -/* #undef HAVE_FUTIMES */ - -/* Define to 1 if you have the `geteuid' function. */ -/* #undef HAVE_GETEUID */ - -/* Define to 1 if you have the `getopt_long' function. */ -/* #undef HAVE_GETOPT_LONG */ - -/* Define to 1 if you have the `getxattr' function. */ -/* #undef HAVE_GETXATTR */ - -/* Define to 1 if you have the <grp.h> header file. */ -/* #undef HAVE_GRP_H */ - -/* Define to 1 if the system has the type `intmax_t'. */ -/* #undef HAVE_INTMAX_T */ - -/* Define to 1 if you have the <inttypes.h> header file. */ -/* #undef HAVE_INTTYPES_H */ - -/* Define to 1 if you have the <langinfo.h> header file. */ -/* #undef HAVE_LANGINFO_H */ - -/* Define to 1 if you have the `lchflags' function. */ -/* #undef HAVE_LCHFLAGS */ - -/* Define to 1 if you have the `lchmod' function. */ -/* #undef HAVE_LCHMOD */ - -/* Define to 1 if you have the `lchown' function. */ -/* #undef HAVE_LCHOWN */ - -/* Define to 1 if you have the `lgetxattr' function. */ -/* #undef HAVE_LGETXATTR */ - -/* Define to 1 if you have the `acl' library (-lacl). */ -/* #undef HAVE_LIBACL */ - -/* Define to 1 if you have the `attr' library (-lattr). */ -/* #undef HAVE_LIBATTR */ - -/* Define to 1 if you have the `bz2' library (-lbz2). */ -/* #undef HAVE_LIBBZ2 */ - -/* Define to 1 if you have the `z' library (-lz). */ -/* #undef HAVE_LIBZ */ - -/* Define to 1 if you have the <limits.h> header file. */ -#define HAVE_LIMITS_H 1 - -/* Define to 1 if you have the <linux/ext2_fs.h> header file. */ -/* #undef HAVE_LINUX_EXT2_FS_H */ - -/* Define to 1 if you have the <linux/fs.h> header file. */ -/* #undef HAVE_LINUX_FS_H */ - -/* Define to 1 if you have the `listxattr' function. */ -/* #undef HAVE_LISTXATTR */ - -/* Define to 1 if you have the `llistxattr' function. */ -/* #undef HAVE_LLISTXATTR */ - -/* Define to 1 if you have the <locale.h> header file. */ -#define HAVE_LOCALE_H 1 - -/* Define to 1 if the system has the type `long long int'. */ -#define HAVE_LONG_LONG_INT 1 - -/* Define to 1 if you have the `lsetxattr' function. */ -/* #undef HAVE_LSETXATTR */ - -/* Define to 1 if `lstat' has the bug that it succeeds when given the - zero-length file name argument. */ -/* #undef HAVE_LSTAT_EMPTY_STRING_BUG */ - -/* Define to 1 if you have the `lutimes' function. */ -/* #undef HAVE_LUTIMES */ - -/* Define to 1 if you have the `memmove' function. */ -#define HAVE_MEMMOVE 1 - -/* Define to 1 if you have the <memory.h> header file. */ -#define HAVE_MEMORY_H 1 - -/* Define to 1 if you have the `memset' function. */ -#define HAVE_MEMSET 1 - -/* Define to 1 if you have the `mkdir' function. */ -#define HAVE_MKDIR 1 - -/* Define to 1 if you have the `mkfifo' function. */ -/* #undef HAVE_MKFIFO */ - -/* Define to 1 if you have the `mknod' function. */ -/* #undef HAVE_MKNOD */ - -/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */ -/* #undef HAVE_NDIR_H */ - -/* Define to 1 if you have the `nl_langinfo' function. */ -/* #undef HAVE_NL_LANGINFO */ - -/* Define to 1 if you have the <paths.h> header file. */ -/* #undef HAVE_PATHS_H */ - -/* Define to 1 if you have the `poll' function. */ -/* #undef HAVE_POLL */ - -/* Define to 1 if you have the <poll.h> header file. */ -/* #undef HAVE_POLL_H */ - -/* Define to 1 if you have the <pwd.sh.h> header file. */ -/* #undef HAVE_PWD_H */ - -/* Define to 1 if you have the `select' function. */ -/* #undef HAVE_SELECT */ - -/* Define to 1 if you have the `setlocale' function. */ -#define HAVE_SETLOCALE 1 - -/* Define to 1 if `stat' has the bug that it succeeds when given the - zero-length file name argument. */ -/* #undef HAVE_STAT_EMPTY_STRING_BUG */ - -/* Define to 1 if you have the <stdarg.h> header file. */ -#define HAVE_STDARG_H 1 - -/* Define to 1 if you have the <stdint.h> header file. */ -/* #undef HAVE_STDINT_H */ - -/* Define to 1 if you have the <stdlib.h> header file. */ -#define HAVE_STDLIB_H 1 - -/* Define to 1 if you have the `strchr' function. */ -#define HAVE_STRCHR 1 - -/* Define to 1 if you have the `strdup' function. */ -#define HAVE_STRDUP 1 - -/* Define to 1 if you have the `strerror' function. */ -#define HAVE_STRERROR 1 - -/* Define to 1 if you have the `strerror_r' function. */ -/* #undef HAVE_STRERROR_R */ - -/* Define to 1 if you have the `strftime' function. */ -#define HAVE_STRFTIME 1 - -/* Define to 1 if you have the <strings.h> header file. */ -#define HAVE_STRINGS_H 1 - -/* Define to 1 if you have the <string.h> header file. */ -#define HAVE_STRING_H 1 - -/* Define to 1 if you have the `strrchr' function. */ -#define HAVE_STRRCHR 1 - -/* Define to 1 if `st_mtimespec.tv_nsec' is member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC */ - -/* Define to 1 if `st_mtim.tv_nsec' is member of `struct stat'. */ -/* #undef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC */ - -/* Define to 1 if `st_rdev' is member of `struct stat'. */ -#define HAVE_STRUCT_STAT_ST_RDEV 1 - -/* Define to 1 if `tm_gmtoff' is member of `struct tm'. */ -/* #undef HAVE_STRUCT_TM_TM_GMTOFF */ - -/* Define to 1 if you have the <sys/acl.h> header file. */ -/* #undef HAVE_SYS_ACL_H */ - -/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'. - */ -/* #undef HAVE_SYS_DIR_H */ - -/* Define to 1 if you have the <sys/ioctl.h> header file. */ -/* #undef HAVE_SYS_IOCTL_H */ - -/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'. - */ -/* #undef HAVE_SYS_NDIR_H */ - -/* Define to 1 if you have the <sys/param.h> header file. */ -/* #undef HAVE_SYS_PARAM_H */ - -/* Define to 1 if you have the <sys/poll.h> header file. */ -/* #undef HAVE_SYS_POLL_H */ - -/* Define to 1 if you have the <sys/select.h> header file. */ -/* #undef HAVE_SYS_SELECT_H */ - -/* Define to 1 if you have the <sys/stat.h> header file. */ -#define HAVE_SYS_STAT_H 1 - -/* Define to 1 if you have the <sys/time.h> header file. */ -/* #undef HAVE_SYS_TIME_H */ - -/* Define to 1 if you have the <sys/types.h> header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define to 1 if you have the <sys/utime.h> header file. */ -#define HAVE_SYS_UTIME_H 1 - -/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */ -/* #undef HAVE_SYS_WAIT_H */ - -/* Define to 1 if you have the `timegm' function. */ -/* #undef HAVE_TIMEGM */ - -/* Define to 1 if you have the <time.h> header file. */ -#define HAVE_TIME_H 1 - -/* Define to 1 if the system has the type `uintmax_t'. */ -/* #undef HAVE_UINTMAX_T */ - -/* Define to 1 if you have the <unistd.h> header file. */ -/* #undef HAVE_UNISTD_H */ - -/* Define to 1 if the system has the type `unsigned long long'. */ -#define HAVE_UNSIGNED_LONG_LONG 1 - -/* Define to 1 if the system has the type `unsigned long long int'. */ -#define HAVE_UNSIGNED_LONG_LONG_INT 1 - -/* Define to 1 if you have the `utime' function. */ -#define HAVE_UTIME 1 - -/* Define to 1 if you have the `utimes' function. */ -/* #undef HAVE_UTIMES */ - -/* Define to 1 if you have the <utime.h> header file. */ -/* #undef HAVE_UTIME_H */ - -/* Define to 1 if you have the `vprintf' function. */ -#define HAVE_VPRINTF 1 - -/* Define to 1 if you have the <wchar.h> header file. */ -#define HAVE_WCHAR_H 1 - -/* Define to 1 if you have the `wcscpy' function. */ -#define HAVE_WCSCPY 1 - -/* Define to 1 if you have the `wcslen' function. */ -#define HAVE_WCSLEN 1 - -/* Define to 1 if you have the `wmemcmp' function. */ -/* #undef HAVE_WMEMCMP */ - -/* Define to 1 if you have the `wmemcpy' function. */ -/* #undef HAVE_WMEMCPY */ - -/* Define to 1 if you have the <zlib.h> header file. */ -/* #undef HAVE_ZLIB_H */ - -/* Version number of libarchive as a single integer */ -#define LIBARCHIVE_VERSION_NUMBER "2005000" - -/* Version number of libarchive */ -#define LIBARCHIVE_VERSION_STRING "2.5.0b" - -/* Define to 1 if `lstat' dereferences a symlink specified with a trailing - slash. */ -/* #undef LSTAT_FOLLOWS_SLASHED_SYMLINK */ - -/* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>. - */ -/* #undef MAJOR_IN_MKDEV */ - -/* Define to 1 if `major', `minor', and `makedev' are declared in - <sysmacros.h>. */ -/* #undef MAJOR_IN_SYSMACROS */ - -/* Define to 1 if your C compiler doesn't accept -c and -o together. */ -/* #undef NO_MINUS_C_MINUS_O */ - -/* Name of package */ -#define PACKAGE "libarchive" - -/* Define to the address where bug reports for this package should be sent. */ -#define PACKAGE_BUGREPORT "kientzle@freebsd.org" - -/* Define to the full name of this package. */ -#define PACKAGE_NAME "libarchive" - -/* Define to the full name and version of this package. */ -#define PACKAGE_STRING "libarchive 2.4.12" - -/* Define to the one symbol short name of this package. */ -#define PACKAGE_TARNAME "libarchive" - -/* Define to the version of this package. */ -#define PACKAGE_VERSION "2.4.12" - -/* Define to 1 if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define to 1 if strerror_r returns char *. */ -/* #undef STRERROR_R_CHAR_P */ - -/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */ -#define TIME_WITH_SYS_TIME 1 - -/* Version number of package */ -#define VERSION "2.4.12" - -/* Number of bits in a file offset, on hosts where this is settable. */ -/* #undef _FILE_OFFSET_BITS */ - -/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */ -/* #undef _LARGEFILE_SOURCE */ - -/* Define for large files, on AIX-style hosts. */ -/* #undef _LARGE_FILES */ - -/* Define for Solaris 2.5.1 so the uint64_t typedef from <sys/synch.h>, - <pthread.h>, or <semaphore.h> is not used. If the typedef was allowed, the - #define below would cause a syntax error. */ -/* #undef _UINT64_T */ - -/* Define to empty if `const' does not conform to ANSI C. */ -/* #undef const */ - -/* Define to `int' if <sys/types.h> doesn't define. */ -#define gid_t int - -/* Define to `unsigned long' if <sys/types.h> does not define. */ -#define id_t int - -/* Define to the type of a signed integer type of width exactly 64 bits if - such a type exists and the standard includes do not define it. */ -#define int64_t long long - -/* Define to the widest signed integer type if <stdint.h> and <inttypes.h> do - not define. */ -#define intmax_t long long - -/* Define to `int' if <sys/types.h> does not define. */ -#define mode_t unsigned short - -/* Define to `long long' if <sys/types.h> does not define. */ -/* #undef off_t */ - -/* Define to `unsigned int' if <sys/types.h> does not define. */ -/* #undef size_t */ - -/* Define to `int' if <sys/types.h> doesn't define. */ -#define uid_t int - -/* Define to the type of an unsigned integer type of width exactly 64 bits if - such a type exists and the standard includes do not define it. */ -#define uint64_t unsigned long long - -/* Define to the widest unsigned integer type if <stdint.h> and <inttypes.h> - do not define. */ -#define uintmax_t unsigned long long - -/* Define to `unsigned int' if <sys/types.h> does not define. */ -/* #undef uintptr_t */ - -/* Define to `unsigned int' if <sys/types.h> does not define. */ -#define pid_t unsigned int - -#define uint32_t unsigned long -#define uint16_t unsigned short -#define ssize_t long - -#endif /* CONFIG_H_INCLUDED */ +/* config.h. Generated from config.h.in by configure. */
+/* config.h.in. Generated from configure.ac by autoheader. */
+#ifndef CONFIG_H_INCLUDED
+#define CONFIG_H_INCLUDED
+
+
+///////////////////////////////////////////////////////////////////////////
+// Check for Watcom and Microsoft Visual C compilers (WIN32 only) ///////
+///////////////////////////////////////////////////////////////////////////
+#if defined(__WIN32__) || defined(_WIN32) || defined(__WIN32)
+ #define IS_WIN32 1
+
+ #if defined(__TURBOC__) || defined(__BORLANDC__) /* Borland compilers */
+ #elif defined( __WATCOMC__ ) || defined(__WATCOMCPP__) /* Watcom compilers */
+ #define IS_WATCOM 1
+ /* Define to 1 if __INT64 is defined */
+ #define HAVE___INT64 1
+
+ /* Define to 1 if UID should be unsigned */
+ #define USE_UNSIGNED_UID 1
+
+ /* Define to 1 if UID should be unsigned */
+ #define USE_UNSIGNED_GID 1
+
+ #elif defined(__IBMC__) || defined(__IBMCPP__) /* IBM compilers */
+ #elif defined( __SC__ ) /* Symantec C++ compilers */
+ #elif defined( M_I86 ) && defined( MSDOS ) /* Microsoft DOS/Win 16 compilers */
+ #elif defined( _M_IX86 ) || defined( _68K_ ) /* Microsoft Win32 compilers */
+ #define IS_VISUALC 1
+ /* Define to 1 if __INT64 is defined */
+ #define HAVE___INT64 1
+ #else
+ #endif
+
+#endif
+///////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////
+
+/* Define to 1 if you have the `acl_create_entry' function. */
+/* #undef HAVE_ACL_CREATE_ENTRY */
+
+/* Define to 1 if you have the `acl_get_perm' function. */
+/* #undef HAVE_ACL_GET_PERM */
+
+/* Define to 1 if you have the `acl_get_perm_np' function. */
+/* #undef HAVE_ACL_GET_PERM_NP */
+
+/* Define to 1 if you have the `acl_init' function. */
+/* #undef HAVE_ACL_INIT */
+
+/* Define to 1 if the system has the type `acl_permset_t'. */
+/* #undef HAVE_ACL_PERMSET_T */
+
+/* Define to 1 if you have the `acl_set_fd' function. */
+/* #undef HAVE_ACL_SET_FD */
+
+/* Define to 1 if you have the `acl_set_fd_np' function. */
+/* #undef HAVE_ACL_SET_FD_NP */
+
+/* Define to 1 if you have the `acl_set_file' function. */
+/* #undef HAVE_ACL_SET_FILE */
+
+/* True for systems with POSIX ACL support */
+/* #undef HAVE_ACL_USER */
+
+/* Define to 1 if you have the <attr/xattr.h> header file. */
+/* #undef HAVE_ATTR_XATTR_H */
+
+/* Define to 1 if you have the <bzlib.h> header file. */
+/* #undef HAVE_BZLIB_H */
+
+/* Define to 1 if you have the `chflags' function. */
+/* #undef HAVE_CHFLAGS */
+
+/* Define to 1 if you have the `chown' function. */
+/* #undef HAVE_CHOWN */
+
+/* Define to 1 if you have the declaration of `INT64_MAX', and to 0 if you
+ don't. */
+/* #undef HAVE_DECL_INT64_MAX */
+
+/* Define to 1 if you have the declaration of `INT64_MIN', and to 0 if you
+ don't. */
+/* #undef HAVE_DECL_INT64_MIN */
+
+/* Define to 1 if you have the declaration of `optarg', and to 0 if you don't.
+ */
+/* #undef HAVE_DECL_OPTARG */
+
+/* Define to 1 if you have the declaration of `optind', and to 0 if you don't.
+ */
+/* #undef HAVE_DECL_OPTIND */
+
+/* Define to 1 if you have the declaration of `SIZE_MAX', and to 0 if you
+ don't. */
+/* #undef HAVE_DECL_SIZE_MAX */
+
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+#define HAVE_DECL_SIZE_MAX 1
+#endif
+
+/* Define to 1 if you have the declaration of `strerror_r', and to 0 if you
+ don't. */
+/* #undef HAVE_DECL_STRERROR_R */
+
+/* Define to 1 if you have the declaration of `UINT32_MAX', and to 0 if you
+ don't. */
+/* #undef HAVE_DECL_UINT32_MAX */
+
+/* Define to 1 if you have the declaration of `UINT64_MAX', and to 0 if you
+ don't. */
+/* #undef HAVE_DECL_UINT64_MAX */
+
+/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'.
+ */
+/* #undef HAVE_DIRENT_H */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+/* #undef HAVE_DLFCN_H */
+
+/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
+/* #undef HAVE_DOPRNT */
+
+/* Define to 1 if nl_langinfo supports D_MD_ORDER */
+/* #undef HAVE_D_MD_ORDER */
+
+/* A possible errno value for invalid file format errors */
+#if ((IS_WATCOM) || (IS_VISUALC))
+#define HAVE_EFTYPE 0
+#else
+#define HAVE_EFTYPE 1
+#endif
+
+/* A possible errno value for invalid file format errors */
+#define HAVE_EILSEQ 1
+
+/* Define to 1 if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the <ext2fs/ext2_fs.h> header file. */
+/* #undef HAVE_EXT2FS_EXT2_FS_H */
+
+/* Define to 1 if you have the `fchdir' function. */
+/* #undef HAVE_FCHDIR */
+
+/* Define to 1 if you have the `fchflags' function. */
+/* #undef HAVE_FCHFLAGS */
+
+/* Define to 1 if you have the `fchmod' function. */
+/* #undef HAVE_FCHMOD */
+
+/* Define to 1 if you have the `fchown' function. */
+/* #undef HAVE_FCHOWN */
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+/* #undef HAVE_FCNTL_H 1 */
+
+/* Define to 1 if you have the fcntl() function. */
+/* #undef HAVE_FCNTL_FN */
+
+/* Define to 1 if your system has a working POSIX `fnmatch' function. */
+/* #undef HAVE_FNMATCH */
+
+/* Define to 1 if fnmatch(3) supports the FNM_LEADING_DIR flag */
+/* #undef HAVE_FNM_LEADING_DIR */
+
+/* Define to 1 if fseeko (and presumably ftello) exists and is declared. */
+/* #undef HAVE_FSEEKO */
+
+/* Define to 1 if you have the `fsetxattr' function. */
+/* #undef HAVE_FSETXATTR */
+
+/* Define to 1 if you have the `ftruncate' function. */
+/* #undef HAVE_FTRUNCATE */
+
+/* Define to 1 if you have the `futimes' function. */
+/* #undef HAVE_FUTIMES */
+
+/* Define to 1 if you have the `geteuid' function. */
+/* #undef HAVE_GETEUID */
+
+/* Define to 1 if you have the `getopt_long' function. */
+/* #undef HAVE_GETOPT_LONG */
+
+/* Define to 1 if you have the `getxattr' function. */
+/* #undef HAVE_GETXATTR */
+
+/* Define to 1 if you have the <grp.h> header file. */
+/* #undef HAVE_GRP_H */
+
+/* Define to 1 if the system has the type `intmax_t'. */
+/* #undef HAVE_INTMAX_T */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+/* #undef HAVE_INTTYPES_H */
+
+/* Define to 1 if you have the <langinfo.h> header file. */
+/* #undef HAVE_LANGINFO_H */
+
+/* Define to 1 if you have the `lchflags' function. */
+/* #undef HAVE_LCHFLAGS */
+
+/* Define to 1 if you have the `lchmod' function. */
+/* #undef HAVE_LCHMOD */
+
+/* Define to 1 if you have the `lchown' function. */
+/* #undef HAVE_LCHOWN */
+
+/* Define to 1 if you have the `lgetxattr' function. */
+/* #undef HAVE_LGETXATTR */
+
+/* Define to 1 if you have the `acl' library (-lacl). */
+/* #undef HAVE_LIBACL */
+
+/* Define to 1 if you have the `attr' library (-lattr). */
+/* #undef HAVE_LIBATTR */
+
+/* Define to 1 if you have the `bz2' library (-lbz2). */
+/* #undef HAVE_LIBBZ2 */
+
+/* Define to 1 if you have the `z' library (-lz). */
+/* #undef HAVE_LIBZ */
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define to 1 if you have the <linux/ext2_fs.h> header file. */
+/* #undef HAVE_LINUX_EXT2_FS_H */
+
+/* Define to 1 if you have the <linux/fs.h> header file. */
+/* #undef HAVE_LINUX_FS_H */
+
+/* Define to 1 if you have the `listxattr' function. */
+/* #undef HAVE_LISTXATTR */
+
+/* Define to 1 if you have the `llistxattr' function. */
+/* #undef HAVE_LLISTXATTR */
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if the system has the type `long long int'. */
+#define HAVE_LONG_LONG_INT 1
+
+/* Define to 1 if you have the `lsetxattr' function. */
+/* #undef HAVE_LSETXATTR */
+
+/* Define to 1 if `lstat' has the bug that it succeeds when given the
+ zero-length file name argument. */
+/* #undef HAVE_LSTAT_EMPTY_STRING_BUG */
+
+/* Define to 1 if you have the `lutimes' function. */
+/* #undef HAVE_LUTIMES */
+
+/* Define to 1 if you have the `memmove' function. */
+#define HAVE_MEMMOVE 1
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the `memset' function. */
+#define HAVE_MEMSET 1
+
+/* Define to 1 if you have the `mkdir' function. */
+#define HAVE_MKDIR 1
+
+/* Define to 1 if you have the `mkfifo' function. */
+/* #undef HAVE_MKFIFO */
+
+/* Define to 1 if you have the `mknod' function. */
+/* #undef HAVE_MKNOD */
+
+/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
+/* #undef HAVE_NDIR_H */
+
+/* Define to 1 if you have the `nl_langinfo' function. */
+/* #undef HAVE_NL_LANGINFO */
+
+/* Define to 1 if you have the <paths.h> header file. */
+/* #undef HAVE_PATHS_H */
+
+/* Define to 1 if you have the `poll' function. */
+/* #undef HAVE_POLL */
+
+/* Define to 1 if you have the <poll.h> header file. */
+/* #undef HAVE_POLL_H */
+
+/* Define to 1 if you have the <pwd.sh.h> header file. */
+/* #undef HAVE_PWD_H */
+
+/* Define to 1 if you have the `select' function. */
+/* #undef HAVE_SELECT */
+
+/* Define to 1 if you have the `setlocale' function. */
+#define HAVE_SETLOCALE 1
+
+/* Define to 1 if `stat' has the bug that it succeeds when given the
+ zero-length file name argument. */
+/* #undef HAVE_STAT_EMPTY_STRING_BUG */
+
+/* Define to 1 if you have the <stdarg.h> header file. */
+#define HAVE_STDARG_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+/* #undef HAVE_STDINT_H */
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strchr' function. */
+#define HAVE_STRCHR 1
+
+/* Define to 1 if you have the `strdup' function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the `strerror' function. */
+#define HAVE_STRERROR 1
+
+/* Define to 1 if you have the `strerror_r' function. */
+/* #undef HAVE_STRERROR_R */
+
+/* Define to 1 if you have the `strftime' function. */
+#define HAVE_STRFTIME 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strrchr' function. */
+#define HAVE_STRRCHR 1
+
+/* Define to 1 if `st_mtimespec.tv_nsec' is member of `struct stat'. */
+/* #undef HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC */
+
+/* Define to 1 if `st_mtim.tv_nsec' is member of `struct stat'. */
+/* #undef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC */
+
+/* Define to 1 if `st_rdev' is member of `struct stat'. */
+#define HAVE_STRUCT_STAT_ST_RDEV 1
+
+/* Define to 1 if `tm_gmtoff' is member of `struct tm'. */
+/* #undef HAVE_STRUCT_TM_TM_GMTOFF */
+
+/* Define to 1 if you have the <sys/acl.h> header file. */
+/* #undef HAVE_SYS_ACL_H */
+
+/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'.
+ */
+/* #undef HAVE_SYS_DIR_H */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+/* #undef HAVE_SYS_IOCTL_H */
+
+/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'.
+ */
+/* #undef HAVE_SYS_NDIR_H */
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+/* #undef HAVE_SYS_PARAM_H */
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+/* #undef HAVE_SYS_POLL_H */
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+/* #undef HAVE_SYS_SELECT_H */
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+/* #undef HAVE_SYS_TIME_H */
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+#define HAVE_SYS_UTIME_H 1
+
+/* Define to 1 if you have <sys/wait.h> that is POSIX.1 compatible. */
+/* #undef HAVE_SYS_WAIT_H */
+
+/* Define to 1 if you have the `timegm' function. */
+/* #undef HAVE_TIMEGM */
+
+/* Define to 1 if you have the <time.h> header file. */
+#define HAVE_TIME_H 1
+
+/* Define to 1 if the system has the type `uintmax_t'. */
+/* #undef HAVE_UINTMAX_T */
+
+/* Define to 1 if you have the <unistd.h> header file. */
+/* #undef HAVE_UNISTD_H */
+
+/* Define to 1 if the system has the type `unsigned long long'. */
+#define HAVE_UNSIGNED_LONG_LONG 1
+
+/* Define to 1 if the system has the type `unsigned long long int'. */
+#define HAVE_UNSIGNED_LONG_LONG_INT 1
+
+/* Define to 1 if you have the `utime' function. */
+#define HAVE_UTIME 1
+
+/* Define to 1 if you have the `utimes' function. */
+/* #undef HAVE_UTIMES */
+
+/* Define to 1 if you have the <utime.h> header file. */
+/* #undef HAVE_UTIME_H */
+
+/* Define to 1 if you have the `vprintf' function. */
+#define HAVE_VPRINTF 1
+
+/* Define to 1 if you have the <wchar.h> header file. */
+#define HAVE_WCHAR_H 1
+
+/* Define to 1 if you have the `wcscpy' function. */
+#define HAVE_WCSCPY 1
+
+/* Define to 1 if you have the `wcslen' function. */
+#define HAVE_WCSLEN 1
+
+/* Define to 1 if you have the `wmemcmp' function. */
+/* #undef HAVE_WMEMCMP */
+
+/* Define to 1 if you have the `wmemcpy' function. */
+/* #undef HAVE_WMEMCPY */
+
+/* Define to 1 if you have the <zlib.h> header file. */
+#define HAVE_ZLIB_H 1
+
+/* Version number of libarchive as a single integer */
+#define LIBARCHIVE_VERSION_NUMBER "2005000"
+
+/* Version number of libarchive */
+#define LIBARCHIVE_VERSION_STRING "2.5.0b"
+
+/* Define to 1 if `lstat' dereferences a symlink specified with a trailing
+ slash. */
+/* #undef LSTAT_FOLLOWS_SLASHED_SYMLINK */
+
+/* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>.
+ */
+/* #undef MAJOR_IN_MKDEV */
+
+/* Define to 1 if `major', `minor', and `makedev' are declared in
+ <sysmacros.h>. */
+/* #undef MAJOR_IN_SYSMACROS */
+
+/* Define to 1 if your C compiler doesn't accept -c and -o together. */
+/* #undef NO_MINUS_C_MINUS_O */
+
+/* Name of package */
+#define PACKAGE "libarchive"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "kientzle@freebsd.org"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "libarchive"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "libarchive 2.4.12"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "libarchive"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "2.4.12"
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if strerror_r returns char *. */
+/* #undef STRERROR_R_CHAR_P */
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Version number of package */
+#define VERSION "2.4.12"
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define to 1 to make fseeko visible on some hosts (e.g. glibc 2.2). */
+/* #undef _LARGEFILE_SOURCE */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* Define for Solaris 2.5.1 so the uint64_t typedef from <sys/synch.h>,
+ <pthread.h>, or <semaphore.h> is not used. If the typedef was allowed, the
+ #define below would cause a syntax error. */
+/* #undef _UINT64_T */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#if (USE_UNSIGNED_GID)
+#define gid_t unsigned int
+#else
+#define gid_t int
+#endif
+
+/* Define to `unsigned long' if <sys/types.h> does not define. */
+#define id_t int
+
+/* Define to the type of a signed integer type of width exactly 64 bits if
+ such a type exists and the standard includes do not define it. */
+#if (HAVE___INT64)
+typedef __int64 int64_t;
+#else
+#define int64_t long long
+#endif
+
+/* Define to the widest signed integer type if <stdint.h> and <inttypes.h> do
+ not define. */
+#if (HAVE___INT64)
+typedef __int64 intmax_t;
+#else
+#define intmax_t long long
+#endif
+
+/* Define to `int' if <sys/types.h> does not define. */
+#define mode_t unsigned short
+
+/* Define to `long long' if <sys/types.h> does not define. */
+/* #undef off_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#if (USE_UNSIGNED_UID)
+#define uid_t unsigned int
+#else
+#define uid_t int
+#endif
+
+/* Define to the type of an unsigned integer type of width exactly 64 bits if
+ such a type exists and the standard includes do not define it. */
+#if (HAVE___INT64)
+typedef unsigned __int64 uint64_t;
+#else
+#define uint64_t unsigned long long
+#endif
+
+/* Define to the widest unsigned integer type if <stdint.h> and <inttypes.h>
+ do not define. */
+#if (HAVE___INT64)
+typedef unsigned __int64 uintmax_t;
+#else
+#define uintmax_t unsigned long long
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef uintptr_t */
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+#define pid_t unsigned int
+
+#define uint32_t unsigned long
+#define uint16_t unsigned short
+#define ssize_t long
+
+
+///////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////
+#if (IS_VISUALC)
+ #include <io.h>
+ #include <stdlib.h> //brings in NULL
+ #include <sys/stat.h> //brings in S_IFMT(), etc...
+
+ #define HAVE_UINTPTR 0
+
+ #if !defined(STDIN_FILENO)
+ #define STDIN_FILENO 0
+ #endif
+
+ #if !defined(STDOUT_FILENO)
+ #define STDOUT_FILENO 1
+ #endif
+
+ #if !defined(STDERR_FILENO)
+ #define STDERR_FILENO 2
+ #endif
+
+ /* Define to 1 if ino_t is defined (possibly in sys/types.h) */
+ #define HAVE_INO_T 1
+
+ #define S_IFFIFO _S_IFIFO
+
+ #define S_ISBLK( m ) 0
+ #define S_ISFIFO( m ) (((m) & S_IFMT) == S_IFFIFO)
+ #define S_ISCHR( m ) (((m) & S_IFMT) == S_IFCHR)
+ #define S_ISDIR( m ) (((m) & S_IFMT) == S_IFDIR)
+ #define S_ISREG( m ) (((m) & S_IFMT) == S_IFREG)
+ #define S_ISUID 0004000
+ #define S_ISGID 0002000
+ #define S_ISVTX 0001000
+
+ //NOT SURE IF O_NONBLOCK is OK here but at least the 0x0004 flag is not used by anything else...
+ #define O_NONBLOCK 0x0004 /* Non-blocking I/O. */
+ //#define O_NDELAY O_NONBLOCK
+
+ #define lstat _stat
+
+ /* Symbolic constants for the access() function */
+ #if !defined(F_OK)
+ #define R_OK 4 /* Test for read permission */
+ #define W_OK 2 /* Test for write permission */
+ #define X_OK 1 /* Test for execute permission */
+ #define F_OK 0 /* Test for existence of file */
+ #endif
+
+#endif
+
+//////////////////////////////////////////////////////////////////////////
+#if (IS_WATCOM)
+ #include <io.h> //brings in STDERR/OUT/IN_FILENO, dup(), dup2(), close(), write(), etc...
+ #include <process.h> //brings in execlp() and _exit()
+ #include <stdlib.h> //brings in NULL
+ #include <sys/stat.h>
+
+ /* Define to 1 if ino_t is defined (possibly in sys/types.h) */
+ #define HAVE_INO_T 1
+
+ //NOT SURE IF O_NONBLOCK is OK here but at least the 0x0004 flag is not used by anything else...
+ #define O_NONBLOCK 0x0004 /* Non-blocking I/O. */
+ //#define O_NDELAY O_NONBLOCK
+
+ //Prototypes for functions which we'll define in archive_windows.c
+ extern unsigned int sleep (unsigned int seconds);
+
+ #define lstat _stat
+#endif
+
+
+//////////////////////////////////////////////////////////////////////////
+#if !(HAVE_UINTPTR)
+ typedef unsigned int *uintptr_t;
+ #if defined(HAVE_UINTPTR)
+ #undef HAVE_UINTPTR
+ #endif
+ #define HAVE_UINTPTR 1
+#endif
+
+#if !defined(SSIZE_MAX)
+ //#define _POSIX_SSIZE_MAX 32767
+ #if defined(_POSIX_SSIZE_MAX)
+ #define SSIZE_MAX _POSIX_SSIZE_MAX
+ #else
+ #define SSIZE_MAX ((ssize_t)((size_t)-1 >> 1))
+ #endif
+#endif
+
+#if !(HAVE_FCNTL_FN)
+ #define F_SETFL 4 /* Set file status flags. */
+
+ #if defined(HAVE_FCNTL_FN)
+ #undef HAVE_FCNTL_FN
+ #endif
+ #define HAVE_FCNTL_FN 1
+#endif
+
+ #define _S_IFLNK 0xA000 /* symbolic link */
+ #if !defined(_S_IFMT)
+ #define _S_IFMT S_IFMT
+ #endif
+
+ #define _S_ISLNK(m) (((m) & _S_IFMT) == _S_IFLNK)
+ #define S_ISLNK(m) _S_ISLNK(m)
+
+
+/* Replacement for major/minor/makedev. */
+#if !(MAJOR_IN_MKDEV) && !(MAJOR_IN_SYSMACROS)
+ #define major(x) ((int)(0x00ff & ((x) >> 8)))
+ #define minor(x) ((int)(0xffff00ff & (x)))
+ #define makedev(maj,min) ((0xff00 & ((maj)<<8))|(0xffff00ff & (min)))
+#endif
+
+#define set_errno(val) ((errno)=val)
+
+
+#endif /* CONFIG_H_INCLUDED */
diff --git a/archivers/libarchive/files/libarchive/filter_fork.c b/archivers/libarchive/files/libarchive/filter_fork.c index 8cad9e2f098..3c2d829d052 100644 --- a/archivers/libarchive/files/libarchive/filter_fork.c +++ b/archivers/libarchive/files/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/archivers/libarchive/files/libarchive/libarchive-formats.5 b/archivers/libarchive/files/libarchive/libarchive-formats.5 index 0346d8f5aff..f570935c824 100644 --- a/archivers/libarchive/files/libarchive/libarchive-formats.5 +++ b/archivers/libarchive/files/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/archivers/libarchive/files/libarchive/mtree.5 b/archivers/libarchive/files/libarchive/mtree.5 index 2341626d877..b6637d6f55e 100644 --- a/archivers/libarchive/files/libarchive/mtree.5 +++ b/archivers/libarchive/files/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 @@ -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 @@ -152,7 +151,7 @@ The file group as a symbolic name. .It Cm ignore Ignore any file hierarchy below this file. .It Cm link -The file the symbolic link is expected to reference. +The target of the symbolic link when type=link. .It Cm md5 The MD5 message digest of the file. .It Cm md5digest diff --git a/archivers/libarchive/files/libarchive/test/list.h b/archivers/libarchive/files/libarchive/test/list.h index 94f9fc11a39..278821ad974 100644 --- a/archivers/libarchive/files/libarchive/test/list.h +++ b/archivers/libarchive/files/libarchive/test/list.h @@ -31,6 +31,7 @@ DEFINE_TEST(test_read_format_isorr_bz2) DEFINE_TEST(test_read_format_mtree) DEFINE_TEST(test_read_format_pax_bz2) DEFINE_TEST(test_read_format_tar) +DEFINE_TEST(test_read_format_tar_empty_filename) DEFINE_TEST(test_read_format_tbz) DEFINE_TEST(test_read_format_tgz) DEFINE_TEST(test_read_format_tz) @@ -41,6 +42,7 @@ DEFINE_TEST(test_read_position) DEFINE_TEST(test_read_truncated) DEFINE_TEST(test_tar_filenames) DEFINE_TEST(test_tar_large) +DEFINE_TEST(test_ustar_filenames) DEFINE_TEST(test_write_compress) DEFINE_TEST(test_write_compress_program) DEFINE_TEST(test_write_disk) @@ -55,4 +57,5 @@ DEFINE_TEST(test_write_format_cpio_odc) DEFINE_TEST(test_write_format_shar_empty) DEFINE_TEST(test_write_format_tar) DEFINE_TEST(test_write_format_tar_empty) +DEFINE_TEST(test_write_format_tar_ustar) DEFINE_TEST(test_write_open_memory) diff --git a/archivers/libarchive/files/libarchive/test/main.c b/archivers/libarchive/files/libarchive/test/main.c index 71493321510..6e6ca6c8da1 100644 --- a/archivers/libarchive/files/libarchive/test/main.c +++ b/archivers/libarchive/files/libarchive/test/main.c @@ -63,10 +63,14 @@ extern char *optarg; extern int optind; #endif -/* Default is to crash and try to force a core dump on failure. */ -static int dump_on_failure = 1; +/* Enable core dump on failure. */ +static int dump_on_failure = 0; +/* Default is to remove temp dirs for successful tests. */ +static int keep_temp_files = 0; /* Default is to print some basic information about each test. */ static int quiet_flag = 0; +/* Default is to summarize repeated failures. */ +static int verbose = 0; /* Cumulative count of component failures. */ static int failures = 0; /* Cumulative count of skipped component tests. */ @@ -242,7 +246,7 @@ test_assert(const char *file, int line, int value, const char *condition, void * return (value); } failures ++; - if (previous_failures(file, line)) + if (!verbose && previous_failures(file, line)) return (value); fprintf(stderr, "%s:%d: Assertion failed\n", file, line); fprintf(stderr, " Condition: %s\n", condition); @@ -261,7 +265,7 @@ test_assert_equal_int(const char *file, int line, return (1); } failures ++; - if (previous_failures(file, line)) + if (!verbose && previous_failures(file, line)) return (0); fprintf(stderr, "%s:%d: Assertion failed: Ints not equal\n", file, line); @@ -313,16 +317,16 @@ test_assert_equal_string(const char *file, int line, return (1); } failures ++; - if (previous_failures(file, line)) + if (!verbose && previous_failures(file, line)) return (0); fprintf(stderr, "%s:%d: Assertion failed: Strings not equal\n", file, line); fprintf(stderr, " %s = ", e1); strdump(v1); - fprintf(stderr, "\n"); + fprintf(stderr, " (length %d)\n", v1 == NULL ? 0 : strlen(v1)); fprintf(stderr, " %s = ", e2); strdump(v2); - fprintf(stderr, "\n"); + fprintf(stderr, " (length %d)\n", v2 == NULL ? 0 : strlen(v2)); report_failure(extra); return (0); } @@ -371,7 +375,7 @@ test_assert_equal_wstring(const char *file, int line, return (1); } failures ++; - if (previous_failures(file, line)) + if (!verbose && previous_failures(file, line)) return (0); fprintf(stderr, "%s:%d: Assertion failed: Unicode strings not equal\n", file, line); @@ -441,7 +445,7 @@ test_assert_equal_mem(const char *file, int line, return (1); } failures ++; - if (previous_failures(file, line)) + if (!verbose && previous_failures(file, line)) return (0); fprintf(stderr, "%s:%d: Assertion failed: memory not equal\n", file, line); @@ -473,12 +477,13 @@ test_assert_empty_file(const char *f1fmt, ...) if (stat(f1, &st) != 0) { fprintf(stderr, "%s:%d: Could not stat: %s\n", test_filename, test_line, f1); report_failure(NULL); + return (0); } if (st.st_size == 0) return (1); failures ++; - if (previous_failures(test_filename, test_line)) + if (!verbose && previous_failures(test_filename, test_line)) return (0); fprintf(stderr, "%s:%d: File not empty: %s\n", test_filename, test_line, f1); @@ -525,7 +530,7 @@ test_assert_equal_file(const char *f1, const char *f2pattern, ...) break; } failures ++; - if (previous_failures(test_filename, test_line)) + if (!verbose && previous_failures(test_filename, test_line)) return (0); fprintf(stderr, "%s:%d: Files are not identical\n", test_filename, test_line); @@ -696,6 +701,12 @@ static int test_run(int i, const char *tmpdir) (*tests[i].func)(); /* Summarize the results of this test. */ summarize(); + /* If there were no failures, we can remove the work dir. */ + if (failures == failures_before) { + if (!keep_temp_files && chdir(tmpdir) == 0) { + systemf("rm -rf %s", tests[i].name); + } + } /* Return appropriate status. */ return (failures == failures_before ? 0 : 1); } @@ -709,8 +720,9 @@ static void usage(const char *program) printf("Default is to run all tests.\n"); printf("Otherwise, specify the numbers of the tests you wish to run.\n"); printf("Options:\n"); - printf(" -k Keep running after failures.\n"); - printf(" Default: Core dump after any failure.\n"); + printf(" -d Dump core after any failure, for debugging.\n"); + printf(" -k Keep all temp files.\n"); + printf(" Default: temp files for successful tests deleted.\n"); #ifdef PROGRAM printf(" -p <path> Path to executable to be tested.\n"); printf(" Default: path taken from " ENVBASE " environment variable.\n"); @@ -718,6 +730,7 @@ static void usage(const char *program) printf(" -q Quiet.\n"); printf(" -r <dir> Path to dir containing reference files.\n"); printf(" Default: Current directory.\n"); + printf(" -v Verbose.\n"); printf("Available tests:\n"); for (i = 0; i < limit; i++) printf(" %d: %s\n", i, tests[i].name); @@ -810,9 +823,9 @@ int main(int argc, char **argv) testprog = getenv(ENVBASE); #endif - /* Allow -k to be controlled through the environment. */ - if (getenv(ENVBASE "_KEEP_GOING") != NULL) - dump_on_failure = 0; + /* Allow -d to be controlled through the environment. */ + if (getenv(ENVBASE "_DEBUG") != NULL) + dump_on_failure = 1; /* Get the directory holding test files from environment. */ refdir = getenv(ENVBASE "_TEST_FILES"); @@ -820,10 +833,13 @@ int main(int argc, char **argv) /* * Parse options. */ - while ((opt = getopt(argc, argv, "kp:qr:")) != -1) { + while ((opt = getopt(argc, argv, "dkp:qr:v")) != -1) { switch (opt) { + case 'd': + dump_on_failure = 1; + break; case 'k': - dump_on_failure = 0; + keep_temp_files = 1; break; case 'p': #ifdef PROGRAM @@ -838,6 +854,9 @@ int main(int argc, char **argv) case 'r': refdir = optarg; break; + case 'v': + verbose = 1; + break; case '?': default: usage(progname); @@ -886,6 +905,7 @@ int main(int argc, char **argv) --p; *p = '\0'; } + systemf("rm %s/refdir", tmpdir); } /* @@ -941,5 +961,9 @@ int main(int argc, char **argv) free(refdir_alloc); + /* If the final tmpdir is empty, we can remove it. */ + /* This should be the usual case when all tests succeed. */ + rmdir(tmpdir); + return (tests_failed); } diff --git a/archivers/libarchive/files/libarchive/test/test_entry.c b/archivers/libarchive/files/libarchive/test/test_entry.c index 8386d98926e..5ed3278c60b 100644 --- a/archivers/libarchive/files/libarchive/test/test_entry.c +++ b/archivers/libarchive/files/libarchive/test/test_entry.c @@ -232,6 +232,11 @@ DEFINE_TEST(test_entry) assertEqualString(archive_entry_fflags_text(e), "uappnd,nouchg,nodump,noopaque,uunlnk"); /* TODO: Test archive_entry_copy_fflags_text_w() */ + /* Test archive_entry_copy_fflags_text() */ + archive_entry_copy_fflags_text(e, "nouappnd, nouchg, dump,uunlnk"); + archive_entry_fflags(e, &set, &clear); + assertEqualInt(16, set); + assertEqualInt(7, clear); #endif /* See test_acl_basic.c for tests of ACL set/get consistency. */ diff --git a/archivers/libarchive/files/libarchive/test/test_read_format_mtree.c b/archivers/libarchive/files/libarchive/test/test_read_format_mtree.c index e5165d31fbe..b2fdbb88349 100644 --- a/archivers/libarchive/files/libarchive/test/test_read_format_mtree.c +++ b/archivers/libarchive/files/libarchive/test/test_read_format_mtree.c @@ -32,18 +32,18 @@ static unsigned char archive[] = { "dir type=dir\n" " file\\040with\\040space type=file uid=18\n" " ..\n" - "file\\04with\\040space\n" + "file\\04with\\040space type=file\n" "dir2 type=dir\n" " dir3a type=dir\n" - " indir3a\n" + " indir3a type=file\n" "dir2/fullindir2 type=file mode=0777\n" " ..\n" - " indir2\n" + " indir2 type=file\n" " dir3b type=dir\n" - " indir3b\n" + " indir3b type=file\n" " ..\n" " ..\n" - "notindir\n" + "notindir type=file\n" "dir2/fullindir2 mode=0644\n" }; diff --git a/archivers/libarchive/files/libarchive/test/test_read_format_tar_empty_filename.c b/archivers/libarchive/files/libarchive/test/test_read_format_tar_empty_filename.c new file mode 100644 index 00000000000..d9ba69bd93c --- /dev/null +++ b/archivers/libarchive/files/libarchive/test/test_read_format_tar_empty_filename.c @@ -0,0 +1,66 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" +__FBSDID("$FreeBSD$"); + +/* + * Tar entries with empty filenames are unusual, but shouldn't crash us. + */ +DEFINE_TEST(test_read_format_tar_empty_filename) +{ + char name[] = "test_read_format_tar_empty_filename.tar"; + struct archive_entry *ae; + struct archive *a; + + assert((a = archive_read_new()) != NULL); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_compression_all(a)); + assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a)); + extract_reference_file(name); + assertEqualIntA(a, ARCHIVE_OK, archive_read_open_filename(a, name, 10240)); + + /* Read first entry. */ + assertEqualIntA(a, ARCHIVE_OK, archive_read_next_header(a, &ae)); + assertEqualString("", archive_entry_pathname(ae)); + assertEqualInt(1208628157, archive_entry_mtime(ae)); + assertEqualInt(1000, archive_entry_uid(ae)); + assertEqualString("tim", archive_entry_uname(ae)); + assertEqualInt(0, archive_entry_gid(ae)); + assertEqualString("wheel", archive_entry_gname(ae)); + assertEqualInt(040775, archive_entry_mode(ae)); + + /* Verify the end-of-archive. */ + assertEqualIntA(a, ARCHIVE_EOF, archive_read_next_header(a, &ae)); + + /* Verify that the format detection worked. */ + assertEqualInt(archive_compression(a), ARCHIVE_COMPRESSION_NONE); + assertEqualInt(archive_format(a), ARCHIVE_FORMAT_TAR_USTAR); + + assertEqualInt(ARCHIVE_OK, archive_read_close(a)); +#if ARCHIVE_API_VERSION > 1 + assertEqualInt(ARCHIVE_OK, archive_read_finish(a)); +#else + archive_read_finish(a); +#endif +} diff --git a/archivers/libarchive/files/libarchive/test/test_read_format_tar_empty_filename.tar.uu b/archivers/libarchive/files/libarchive/test/test_read_format_tar_empty_filename.tar.uu new file mode 100644 index 00000000000..7a34c82ca6b --- /dev/null +++ b/archivers/libarchive/files/libarchive/test/test_read_format_tar_empty_filename.tar.uu @@ -0,0 +1,38 @@ +begin 644 test_compat_tar_1.tar +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M`````````````#`P,#<W-2``,#`Q-S4P(``P,#`P,#`@`#`P,#`P,#`P,#`P +M(#$Q,#`R-#,Q-C<U(#`Q,3`P,0`@-0`````````````````````````````` +M```````````````````````````````````````````````````````````` +M``````````````````````````````````````````!U<W1A<@`P,'1I;0`` +M````````````````````````````````````=VAE96P````````````````` +M```````````````````P,#`P,#`@`#`P,#`P,"`````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +M```````````````````````````````````````````````````````````` +&```````` +` +end diff --git a/archivers/libarchive/files/libarchive/test/test_tar_filenames.c b/archivers/libarchive/files/libarchive/test/test_tar_filenames.c index 8b83b527733..9b98448e4a7 100644 --- a/archivers/libarchive/files/libarchive/test/test_tar_filenames.c +++ b/archivers/libarchive/files/libarchive/test/test_tar_filenames.c @@ -40,19 +40,22 @@ test_filename(const char *prefix, int dlen, int flen) struct archive_entry *ae; struct archive *a; size_t used; - size_t prefix_length = 0; - unsigned i = 0; + char *p; + int i; + p = filename; if (prefix) { strcpy(filename, prefix); - i = prefix_length = strlen(prefix); + p += strlen(p); } - for (; i < prefix_length + dlen; i++) - filename[i] = 'a'; - filename[i++] = '/'; - for (; i < prefix_length + dlen + flen + 1; i++) - filename[i] = 'b'; - filename[i++] = '\0'; + if (dlen > 0) { + for (i = 0; i < dlen; i++) + *p++ = 'a'; + *p++ = '/'; + } + for (i = 0; i < flen; i++) + *p++ = 'b'; + *p = '\0'; strcpy(dirname, filename); @@ -160,15 +163,22 @@ DEFINE_TEST(test_tar_filenames) int dlen, flen; /* Repeat the following for a variety of dir/file lengths. */ - for (dlen = 40; dlen < 60; dlen++) { - for (flen = 40; flen < 60; flen++) { + for (dlen = 45; dlen < 55; dlen++) { + for (flen = 45; flen < 55; flen++) { + test_filename(NULL, dlen, flen); + test_filename("/", dlen, flen); + } + } + + for (dlen = 0; dlen < 140; dlen += 10) { + for (flen = 98; flen < 102; flen++) { test_filename(NULL, dlen, flen); test_filename("/", dlen, flen); } } for (dlen = 140; dlen < 160; dlen++) { - for (flen = 90; flen < 110; flen++) { + for (flen = 95; flen < 105; flen++) { test_filename(NULL, dlen, flen); test_filename("/", dlen, flen); } diff --git a/archivers/libarchive/files/libarchive/test/test_tar_large.c b/archivers/libarchive/files/libarchive/test/test_tar_large.c index c675ac1ee04..a05b49f6ab5 100644 --- a/archivers/libarchive/files/libarchive/test/test_tar_large.c +++ b/archivers/libarchive/files/libarchive/test/test_tar_large.c @@ -242,6 +242,11 @@ DEFINE_TEST(test_tar_large) archive_entry_copy_pathname(ae, namebuff); archive_entry_set_mode(ae, S_IFREG | 0755); filesize = tests[i]; + + if (filesize < 0) { + skipping("32-bit off_t doesn't permit testing of very large files."); + return; + } archive_entry_set_size(ae, filesize); assertA(0 == archive_write_header(a, ae)); diff --git a/archivers/libarchive/files/libarchive/test/test_ustar_filenames.c b/archivers/libarchive/files/libarchive/test/test_ustar_filenames.c new file mode 100644 index 00000000000..88b4b2c4ac4 --- /dev/null +++ b/archivers/libarchive/files/libarchive/test/test_ustar_filenames.c @@ -0,0 +1,183 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" +__FBSDID("$FreeBSD$"); + +/* + * Exercise various lengths of filenames in ustar archives. + */ + +static void +test_filename(const char *prefix, int dlen, int flen) +{ + char buff[8192]; + char filename[400]; + char dirname[400]; + struct archive_entry *ae; + struct archive *a; + size_t used; + int separator = 0; + int i = 0; + + if (prefix != NULL) { + strcpy(filename, prefix); + i = strlen(prefix); + } + if (dlen > 0) { + for (; i < dlen; i++) + filename[i] = 'a'; + filename[i++] = '/'; + separator = 1; + } + for (; i < dlen + flen + separator; i++) + filename[i] = 'b'; + filename[i++] = '\0'; + + strcpy(dirname, filename); + + /* Create a new archive in memory. */ + assert((a = archive_write_new()) != NULL); + assertA(0 == archive_write_set_format_ustar(a)); + assertA(0 == archive_write_set_compression_none(a)); + assertA(0 == archive_write_set_bytes_per_block(a,0)); + assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &used)); + + /* + * Write a file to it. + */ + assert((ae = archive_entry_new()) != NULL); + archive_entry_copy_pathname(ae, filename); + archive_entry_set_mode(ae, S_IFREG | 0755); + failure("dlen=%d, flen=%d", dlen, flen); + if (flen > 100) { + assertEqualIntA(a, ARCHIVE_FAILED, archive_write_header(a, ae)); + } else { + assertEqualIntA(a, 0, archive_write_header(a, ae)); + } + archive_entry_free(ae); + + /* + * Write a dir to it (without trailing '/'). + */ + assert((ae = archive_entry_new()) != NULL); + archive_entry_copy_pathname(ae, dirname); + archive_entry_set_mode(ae, S_IFDIR | 0755); + failure("dlen=%d, flen=%d", dlen, flen); + if (flen >= 100) { + assertEqualIntA(a, ARCHIVE_FAILED, archive_write_header(a, ae)); + } else { + assertEqualIntA(a, 0, archive_write_header(a, ae)); + } + archive_entry_free(ae); + + /* Tar adds a '/' to directory names. */ + strcat(dirname, "/"); + + /* + * Write a dir to it (with trailing '/'). + */ + assert((ae = archive_entry_new()) != NULL); + archive_entry_copy_pathname(ae, dirname); + archive_entry_set_mode(ae, S_IFDIR | 0755); + failure("dlen=%d, flen=%d", dlen, flen); + if (flen >= 100) { + assertEqualIntA(a, ARCHIVE_FAILED, archive_write_header(a, ae)); + } else { + assertEqualIntA(a, 0, archive_write_header(a, ae)); + } + archive_entry_free(ae); + + /* Close out the archive. */ + assertA(0 == archive_write_close(a)); + assertA(0 == archive_write_finish(a)); + + /* + * Now, read the data back. + */ + assert((a = archive_read_new()) != NULL); + assertA(0 == archive_read_support_format_all(a)); + assertA(0 == archive_read_support_compression_all(a)); + assertA(0 == archive_read_open_memory(a, buff, used)); + + if (flen <= 100) { + /* Read the file and check the filename. */ + assertA(0 == archive_read_next_header(a, &ae)); + failure("dlen=%d, flen=%d", dlen, flen); + assertEqualString(filename, archive_entry_pathname(ae)); + assertEqualInt((S_IFREG | 0755), archive_entry_mode(ae)); + } + + /* + * Read the two dirs and check the names. + * + * Both dirs should read back with the same name, since + * tar should add a trailing '/' to any dir that doesn't + * already have one. + */ + if (flen <= 99) { + assertA(0 == archive_read_next_header(a, &ae)); + assert((S_IFDIR | 0755) == archive_entry_mode(ae)); + failure("dlen=%d, flen=%d", dlen, flen); + assertEqualString(dirname, archive_entry_pathname(ae)); + } + + if (flen <= 99) { + assertA(0 == archive_read_next_header(a, &ae)); + assert((S_IFDIR | 0755) == archive_entry_mode(ae)); + assertEqualString(dirname, archive_entry_pathname(ae)); + } + + /* Verify the end of the archive. */ + failure("This fails if entries were written that should not have been written. dlen=%d, flen=%d", dlen, flen); + assertEqualInt(1, archive_read_next_header(a, &ae)); + assert(0 == archive_read_close(a)); + assert(0 == archive_read_finish(a)); +} + +DEFINE_TEST(test_ustar_filenames) +{ + int dlen, flen; + + /* Try a bunch of different file/dir lengths that add up + * to just a little less or a little more than 100 bytes. + * This exercises the code that splits paths between ustar + * filename and prefix fields. + */ + for (dlen = 5; dlen < 70; dlen += 5) { + for (flen = 100 - dlen - 5; flen < 100 - dlen + 5; flen++) { + test_filename(NULL, dlen, flen); + test_filename("/", dlen, flen); + } + } + + /* Probe the 100-char limit for paths with no '/'. */ + for (flen = 90; flen < 110; flen++) { + test_filename(NULL, 0, flen); + test_filename("/", dlen, flen); + } + + /* XXXX TODO Probe the 100-char limit with a dir prefix. */ + /* XXXX TODO Probe the 255-char total limit. */ +} diff --git a/archivers/libarchive/files/libarchive/test/test_write_disk_hardlink.c b/archivers/libarchive/files/libarchive/test/test_write_disk_hardlink.c index b21c44b2384..0729c38a114 100644 --- a/archivers/libarchive/files/libarchive/test/test_write_disk_hardlink.c +++ b/archivers/libarchive/files/libarchive/test/test_write_disk_hardlink.c @@ -29,6 +29,10 @@ __FBSDID("$FreeBSD: src/lib/libarchive/test/test_write_disk_hardlink.c,v 1.1 200 /* * Exercise hardlink recreation. + * + * File permissions are chosen so that the authoritive entry + * has the correct permission and the non-authoritive versions + * are just writeable files. */ DEFINE_TEST(test_write_disk_hardlink) { @@ -64,7 +68,7 @@ DEFINE_TEST(test_write_disk_hardlink) /* Link. */ assert((ae = archive_entry_new()) != NULL); archive_entry_copy_pathname(ae, "link1b"); - archive_entry_set_mode(ae, S_IFREG | 0755); + archive_entry_set_mode(ae, S_IFREG | 0600); archive_entry_set_size(ae, 0); archive_entry_copy_hardlink(ae, "link1a"); assertEqualIntA(ad, 0, archive_write_header(ad, ae)); @@ -80,7 +84,7 @@ DEFINE_TEST(test_write_disk_hardlink) /* Regular file. */ assert((ae = archive_entry_new()) != NULL); archive_entry_copy_pathname(ae, "link2a"); - archive_entry_set_mode(ae, S_IFREG | 0755); + archive_entry_set_mode(ae, S_IFREG | 0600); archive_entry_set_size(ae, sizeof(data)); assertEqualIntA(ad, 0, archive_write_header(ad, ae)); assertEqualInt(sizeof(data), archive_write_data(ad, data, sizeof(data))); @@ -106,10 +110,14 @@ DEFINE_TEST(test_write_disk_hardlink) /* Regular file. */ assert((ae = archive_entry_new()) != NULL); archive_entry_copy_pathname(ae, "link3a"); - archive_entry_set_mode(ae, S_IFREG | 0755); + archive_entry_set_mode(ae, S_IFREG | 0600); archive_entry_set_size(ae, 0); assertEqualIntA(ad, 0, archive_write_header(ad, ae)); - assertEqualInt(0, archive_write_data(ad, data, sizeof(data))); +#if ARCHIVE_VERSION_NUMBER < 3000000 + assertEqualInt(ARCHIVE_WARN, archive_write_data(ad, data, 1)); +#else + assertEqualInt(-1, archive_write_data(ad, data, 1)); +#endif assertEqualIntA(ad, 0, archive_write_finish_entry(ad)); archive_entry_free(ae); diff --git a/archivers/libarchive/files/libarchive/test/test_write_format_ar.c b/archivers/libarchive/files/libarchive/test/test_write_format_ar.c index 6c7a4462a90..4bb84a6a615 100644 --- a/archivers/libarchive/files/libarchive/test/test_write_format_ar.c +++ b/archivers/libarchive/files/libarchive/test/test_write_format_ar.c @@ -30,7 +30,7 @@ __FBSDID("$FreeBSD: src/lib/libarchive/test/test_write_format_ar.c,v 1.6 2008/03 char buff[4096]; char buff2[64]; -static unsigned char strtab[] = "abcdefghijklmn.o/\nggghhhjjjrrrttt.o/\niiijjjdddsssppp.o/\n"; +static char strtab[] = "abcdefghijklmn.o/\nggghhhjjjrrrttt.o/\niiijjjdddsssppp.o/\n"; DEFINE_TEST(test_write_format_ar) { @@ -162,6 +162,7 @@ DEFINE_TEST(test_write_format_ar) archive_entry_set_filetype(ae, AE_IFREG); archive_entry_set_size(ae, 5); assertA(0 == archive_write_header(a, ae)); + assertA(5 == archive_entry_size(ae)); assertA(5 == archive_write_data(a, "12345", 7)); archive_entry_free(ae); diff --git a/archivers/libarchive/files/libarchive/test/test_write_format_tar_ustar.c b/archivers/libarchive/files/libarchive/test/test_write_format_tar_ustar.c new file mode 100644 index 00000000000..53eb07cf7d9 --- /dev/null +++ b/archivers/libarchive/files/libarchive/test/test_write_format_tar_ustar.c @@ -0,0 +1,342 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "test.h" +__FBSDID("$FreeBSD$"); + +static int +is_null(const char *p, size_t l) +{ + while (l > 0) { + if (*p != '\0') + return (0); + --l; + ++p; + } + return (1); +} + +/* Verify the contents, then erase them to NUL bytes. */ +/* Tar requires all "unused" bytes be set to NUL; this allows us + * to easily verify that by invoking is_null() over the entire header + * after verifying each field. */ +#define myAssertEqualMem(a,b,s) assertEqualMem(a, b, s); memset(a, 0, s) + +/* + * Detailed verification that 'ustar' archives are written with + * the correct format. + */ +DEFINE_TEST(test_write_format_tar_ustar) +{ + struct archive *a; + struct archive_entry *entry; + char *buff, *e; + size_t buffsize = 100000; + size_t used; + int i; + char f99[100]; + char f100[101]; + char f256[257]; + + for (i = 0; i < 99; ++i) + f99[i] = 'a' + i % 26; + f99[99] = '\0'; + + for (i = 0; i < 100; ++i) + f100[i] = 'A' + i % 26; + f100[100] = '\0'; + + for (i = 0; i < 256; ++i) + f256[i] = 'A' + i % 26; + f256[155] = '/'; + f256[256] = '\0'; + + buff = malloc(buffsize); + + /* Create a new archive in memory. */ + assert((a = archive_write_new()) != NULL); + assertEqualIntA(a, 0, archive_write_set_format_ustar(a)); + assertEqualIntA(a, 0, archive_write_set_compression_none(a)); + assertEqualIntA(a, 0, archive_write_open_memory(a, buff, buffsize, &used)); + + /* + * Add various files to it. + * TODO: Extend this to cover more filetypes. + */ + + /* "file" with 10 bytes of content */ + assert((entry = archive_entry_new()) != NULL); + archive_entry_set_mtime(entry, 1, 10); + archive_entry_set_pathname(entry, "file"); + archive_entry_set_mode(entry, S_IFREG | 0664); + archive_entry_set_size(entry, 10); + archive_entry_set_uid(entry, 80); + archive_entry_set_gid(entry, 90); + archive_entry_set_dev(entry, 12); + archive_entry_set_ino(entry, 89); + archive_entry_set_nlink(entry, 2); + assertEqualIntA(a, 0, archive_write_header(a, entry)); + archive_entry_free(entry); + assertEqualIntA(a, 10, archive_write_data(a, "1234567890", 10)); + + /* Hardlink to "file" with 10 bytes of content */ + assert((entry = archive_entry_new()) != NULL); + archive_entry_set_mtime(entry, 1, 10); + archive_entry_set_pathname(entry, "linkfile"); + archive_entry_set_mode(entry, S_IFREG | 0664); + /* TODO: Put this back and fix the bug. */ + /* archive_entry_set_size(entry, 10); */ + archive_entry_set_uid(entry, 80); + archive_entry_set_gid(entry, 90); + archive_entry_set_dev(entry, 12); + archive_entry_set_ino(entry, 89); + archive_entry_set_nlink(entry, 2); + assertEqualIntA(a, 0, archive_write_header(a, entry)); + archive_entry_free(entry); + /* Write of data to dir should fail == zero bytes get written. */ + assertEqualIntA(a, 0, archive_write_data(a, "1234567890", 10)); + + /* "dir" */ + assert((entry = archive_entry_new()) != NULL); + archive_entry_set_mtime(entry, 2, 20); + archive_entry_set_pathname(entry, "dir"); + archive_entry_set_mode(entry, S_IFDIR | 0775); + archive_entry_set_size(entry, 10); + archive_entry_set_nlink(entry, 2); + assertEqualIntA(a, 0, archive_write_header(a, entry)); + archive_entry_free(entry); + /* Write of data to dir should fail == zero bytes get written. */ + assertEqualIntA(a, 0, archive_write_data(a, "1234567890", 10)); + + /* "symlink" pointing to "file" */ + assert((entry = archive_entry_new()) != NULL); + archive_entry_set_mtime(entry, 3, 30); + archive_entry_set_pathname(entry, "symlink"); + archive_entry_set_mode(entry, S_IFLNK | 0664); + archive_entry_set_symlink(entry,"file"); + archive_entry_set_size(entry, 0); + archive_entry_set_uid(entry, 88); + archive_entry_set_gid(entry, 98); + archive_entry_set_dev(entry, 12); + archive_entry_set_ino(entry, 90); + archive_entry_set_nlink(entry, 1); + assertEqualIntA(a, 0, archive_write_header(a, entry)); + archive_entry_free(entry); + /* Write of data to symlink should fail == zero bytes get written. */ + assertEqualIntA(a, 0, archive_write_data(a, "1234567890", 10)); + + /* file with 99-char filename. */ + assert((entry = archive_entry_new()) != NULL); + archive_entry_set_mtime(entry, 1, 10); + archive_entry_set_pathname(entry, f99); + archive_entry_set_mode(entry, S_IFREG | 0664); + archive_entry_set_size(entry, 0); + archive_entry_set_uid(entry, 82); + archive_entry_set_gid(entry, 93); + archive_entry_set_dev(entry, 102); + archive_entry_set_ino(entry, 7); + archive_entry_set_nlink(entry, 1); + assertEqualIntA(a, 0, archive_write_header(a, entry)); + archive_entry_free(entry); + + /* file with 100-char filename. */ + assert((entry = archive_entry_new()) != NULL); + archive_entry_set_mtime(entry, 1, 10); + archive_entry_set_pathname(entry, f100); + archive_entry_set_mode(entry, S_IFREG | 0664); + archive_entry_set_size(entry, 0); + archive_entry_set_uid(entry, 82); + archive_entry_set_gid(entry, 93); + archive_entry_set_dev(entry, 102); + archive_entry_set_ino(entry, 7); + archive_entry_set_nlink(entry, 1); + assertEqualIntA(a, 0, archive_write_header(a, entry)); + archive_entry_free(entry); + + /* file with 256-char filename. */ + assert((entry = archive_entry_new()) != NULL); + archive_entry_set_mtime(entry, 1, 10); + archive_entry_set_pathname(entry, f256); + archive_entry_set_mode(entry, S_IFREG | 0664); + archive_entry_set_size(entry, 0); + archive_entry_set_uid(entry, 82); + archive_entry_set_gid(entry, 93); + archive_entry_set_dev(entry, 102); + archive_entry_set_ino(entry, 7); + archive_entry_set_nlink(entry, 1); + assertEqualIntA(a, 0, archive_write_header(a, entry)); + archive_entry_free(entry); + + assert(0 == archive_write_finish(a)); + + /* + * Verify the archive format. + */ + e = buff; + + /* "file" */ + myAssertEqualMem(e + 0, "file", 5); /* Filename */ + myAssertEqualMem(e + 100, "000664 ", 8); /* mode */ + myAssertEqualMem(e + 108, "000120 ", 8); /* uid */ + myAssertEqualMem(e + 116, "000132 ", 8); /* gid */ + myAssertEqualMem(e + 124, "00000000012 ", 12); /* size */ + myAssertEqualMem(e + 136, "00000000001 ", 12); /* mtime */ + myAssertEqualMem(e + 148, "010034\0 ", 8); /* checksum */ + myAssertEqualMem(e + 156, "0", 1); /* linkflag */ + myAssertEqualMem(e + 157, "", 1); /* linkname */ + myAssertEqualMem(e + 257, "ustar\000000", 8); /* signature/version */ + myAssertEqualMem(e + 265, "", 1); /* uname */ + myAssertEqualMem(e + 297, "", 1); /* gname */ + myAssertEqualMem(e + 329, "000000 ", 8); /* devmajor */ + myAssertEqualMem(e + 337, "000000 ", 8); /* devminor */ + myAssertEqualMem(e + 345, "", 1); /* prefix */ + assert(is_null(e + 0, 512)); + myAssertEqualMem(e + 512, "1234567890", 10); + assert(is_null(e + 512, 512)); + e += 1024; + + /* hardlink to "file" */ + myAssertEqualMem(e + 0, "linkfile", 9); /* Filename */ + myAssertEqualMem(e + 100, "000664 ", 8); /* mode */ + myAssertEqualMem(e + 108, "000120 ", 8); /* uid */ + myAssertEqualMem(e + 116, "000132 ", 8); /* gid */ + myAssertEqualMem(e + 124, "00000000000 ", 12); /* size */ + myAssertEqualMem(e + 136, "00000000001 ", 12); /* mtime */ + myAssertEqualMem(e + 148, "010707\0 ", 8); /* checksum */ + myAssertEqualMem(e + 156, "0", 1); /* linkflag */ + myAssertEqualMem(e + 157, "", 1); /* linkname */ + myAssertEqualMem(e + 257, "ustar\000000", 8); /* signature/version */ + myAssertEqualMem(e + 265, "", 1); /* uname */ + myAssertEqualMem(e + 297, "", 1); /* gname */ + myAssertEqualMem(e + 329, "000000 ", 8); /* devmajor */ + myAssertEqualMem(e + 337, "000000 ", 8); /* devminor */ + myAssertEqualMem(e + 345, "", 1); /* prefix */ + assert(is_null(e + 0, 512)); + e += 512; + + /* "dir" */ + myAssertEqualMem(e + 0, "dir/", 4); /* Filename */ + myAssertEqualMem(e + 100, "000775 ", 8); /* mode */ + myAssertEqualMem(e + 108, "000000 ", 8); /* uid */ + myAssertEqualMem(e + 116, "000000 ", 8); /* gid */ + myAssertEqualMem(e + 124, "00000000000 ", 12); /* size */ + myAssertEqualMem(e + 136, "00000000002 ", 12); /* mtime */ + myAssertEqualMem(e + 148, "007747\0 ", 8); /* checksum */ + myAssertEqualMem(e + 156, "5", 1); /* typeflag */ + myAssertEqualMem(e + 157, "", 1); /* linkname */ + myAssertEqualMem(e + 257, "ustar\000000", 8); /* signature/version */ + myAssertEqualMem(e + 265, "", 1); /* uname */ + myAssertEqualMem(e + 297, "", 1); /* gname */ + myAssertEqualMem(e + 329, "000000 ", 8); /* devmajor */ + myAssertEqualMem(e + 337, "000000 ", 8); /* devminor */ + myAssertEqualMem(e + 345, "", 1); /* prefix */ + assert(is_null(e + 0, 512)); + e += 512; + + /* "symlink" pointing to "file" */ + myAssertEqualMem(e + 0, "symlink", 8); /* Filename */ + myAssertEqualMem(e + 100, "000664 ", 8); /* mode */ + myAssertEqualMem(e + 108, "000130 ", 8); /* uid */ + myAssertEqualMem(e + 116, "000142 ", 8); /* gid */ + myAssertEqualMem(e + 124, "00000000000 ", 12); /* size */ + myAssertEqualMem(e + 136, "00000000003 ", 12); /* mtime */ + myAssertEqualMem(e + 148, "011446\0 ", 8); /* checksum */ + myAssertEqualMem(e + 156, "2", 1); /* linkflag */ + myAssertEqualMem(e + 157, "file", 5); /* linkname */ + myAssertEqualMem(e + 257, "ustar\000000", 8); /* signature/version */ + myAssertEqualMem(e + 265, "", 1); /* uname */ + myAssertEqualMem(e + 297, "", 1); /* gname */ + myAssertEqualMem(e + 329, "000000 ", 8); /* devmajor */ + myAssertEqualMem(e + 337, "000000 ", 8); /* devminor */ + myAssertEqualMem(e + 345, "", 1); /* prefix */ + assert(is_null(e + 0, 512)); + e += 512; + + /* File with 99-char filename */ + myAssertEqualMem(e + 0, f99, 100); /* Filename */ + myAssertEqualMem(e + 100, "000664 ", 8); /* mode */ + myAssertEqualMem(e + 108, "000122 ", 8); /* uid */ + myAssertEqualMem(e + 116, "000135 ", 8); /* gid */ + myAssertEqualMem(e + 124, "00000000000 ", 12); /* size */ + myAssertEqualMem(e + 136, "00000000001 ", 12); /* mtime */ + myAssertEqualMem(e + 148, "034242\0 ", 8); /* checksum */ + myAssertEqualMem(e + 156, "0", 1); /* linkflag */ + myAssertEqualMem(e + 157, "", 1); /* linkname */ + myAssertEqualMem(e + 257, "ustar\000000", 8); /* signature/version */ + myAssertEqualMem(e + 265, "", 1); /* uname */ + myAssertEqualMem(e + 297, "", 1); /* gname */ + myAssertEqualMem(e + 329, "000000 ", 8); /* devmajor */ + myAssertEqualMem(e + 337, "000000 ", 8); /* devminor */ + myAssertEqualMem(e + 345, "", 1); /* prefix */ + assert(is_null(e + 0, 512)); + e += 512; + + /* File with 100-char filename */ + myAssertEqualMem(e + 0, f100, 100); /* Filename */ + myAssertEqualMem(e + 100, "000664 ", 8); /* mode */ + myAssertEqualMem(e + 108, "000122 ", 8); /* uid */ + myAssertEqualMem(e + 116, "000135 ", 8); /* gid */ + myAssertEqualMem(e + 124, "00000000000 ", 12); /* size */ + myAssertEqualMem(e + 136, "00000000001 ", 12); /* mtime */ + myAssertEqualMem(e + 148, "026230\0 ", 8); /* checksum */ + myAssertEqualMem(e + 156, "0", 1); /* linkflag */ + myAssertEqualMem(e + 157, "", 1); /* linkname */ + myAssertEqualMem(e + 257, "ustar\000000", 8); /* signature/version */ + myAssertEqualMem(e + 265, "", 1); /* uname */ + myAssertEqualMem(e + 297, "", 1); /* gname */ + myAssertEqualMem(e + 329, "000000 ", 8); /* devmajor */ + myAssertEqualMem(e + 337, "000000 ", 8); /* devminor */ + myAssertEqualMem(e + 345, "", 1); /* prefix */ + assert(is_null(e + 0, 512)); + e += 512; + + /* File with 256-char filename */ + myAssertEqualMem(e + 0, f256 + 156, 100); /* Filename */ + myAssertEqualMem(e + 100, "000664 ", 8); /* mode */ + myAssertEqualMem(e + 108, "000122 ", 8); /* uid */ + myAssertEqualMem(e + 116, "000135 ", 8); /* gid */ + myAssertEqualMem(e + 124, "00000000000 ", 12); /* size */ + myAssertEqualMem(e + 136, "00000000001 ", 12); /* mtime */ + myAssertEqualMem(e + 148, "055570\0 ", 8); /* checksum */ + myAssertEqualMem(e + 156, "0", 1); /* linkflag */ + myAssertEqualMem(e + 157, "", 1); /* linkname */ + myAssertEqualMem(e + 257, "ustar\000000", 8); /* signature/version */ + myAssertEqualMem(e + 265, "", 1); /* uname */ + myAssertEqualMem(e + 297, "", 1); /* gname */ + myAssertEqualMem(e + 329, "000000 ", 8); /* devmajor */ + myAssertEqualMem(e + 337, "000000 ", 8); /* devminor */ + myAssertEqualMem(e + 345, f256, 155); /* prefix */ + assert(is_null(e + 0, 512)); + e += 512; + + /* TODO: Verify other types of entries. */ + + /* Last entry is end-of-archive marker. */ + assert(is_null(e, 1024)); + e += 1024; + + assertEqualInt(used, e - buff); + + free(buff); +} |