Index: head/lib/libarchive/Makefile =================================================================== --- head/lib/libarchive/Makefile (revision 168739) +++ head/lib/libarchive/Makefile (revision 168740) @@ -1,221 +1,222 @@ # $FreeBSD$ LIB= archive DPADD= ${LIBBZ2} ${LIBZ} LDADD= -lbz2 -lz # The libarchive version stamp. # Version is three numbers: # Major: Bumped ONLY when API/ABI breakage happens (see SHLIB_MAJOR) # Minor: Bumped when significant new features are added # Revision: Bumped on any notable change VERSION= 2.0.30 ARCHIVE_API_MAJOR!= echo ${VERSION} | sed -e 's/[^0-9]/./g' -e 's/\..*//' ARCHIVE_API_MINOR!= echo ${VERSION} | sed -e 's/[^0-9]/./g' -e 's/[0-9]*\.//' -e 's/\..*//' # FreeBSD SHLIB_MAJOR value is managed as part of the FreeBSD system. # It has no real relation to the version number above. SHLIB_MAJOR= 4 CFLAGS+= -DPACKAGE_NAME=\"lib${LIB}\" CFLAGS+= -DPACKAGE_VERSION=\"${VERSION}\" CFLAGS+= -DPLATFORM_CONFIG_H=\"config_freebsd.h\" CFLAGS+= -I${.OBJDIR} WARNS?= 6 # Headers to be installed in /usr/include INCS= archive.h archive_entry.h # Build archive.h from archive.h.in by substituting version information. # Note: FreeBSD has inttypes.h, so enable that include in archive.h.in archive.h: archive.h.in Makefile cat ${.CURDIR}/archive.h.in | \ sed 's/@VERSION@/${VERSION}/g' | \ sed 's/@SHLIB_MAJOR@/${SHLIB_MAJOR}/g' | \ sed 's/@ARCHIVE_API_MAJOR@/${ARCHIVE_API_MAJOR}/g' | \ sed 's/@ARCHIVE_API_MINOR@/${ARCHIVE_API_MINOR}/g' | \ sed 's|@ARCHIVE_H_INCLUDE_INTTYPES_H@|#include /* For int64_t */|g' | \ cat > archive.h # archive.h needs to be cleaned CLEANFILES+= archive.h # Sources to be compiled. SRCS= archive.h \ archive_check_magic.c \ archive_entry.c \ archive_read.c \ archive_read_data_into_fd.c \ archive_read_extract.c \ archive_read_open_fd.c \ archive_read_open_file.c \ archive_read_open_filename.c \ archive_read_open_memory.c \ archive_read_support_compression_all.c \ archive_read_support_compression_bzip2.c \ archive_read_support_compression_compress.c \ archive_read_support_compression_gzip.c \ archive_read_support_compression_none.c \ archive_read_support_format_all.c \ + archive_read_support_format_ar.c \ archive_read_support_format_cpio.c \ archive_read_support_format_empty.c \ archive_read_support_format_iso9660.c \ archive_read_support_format_tar.c \ archive_read_support_format_zip.c \ archive_string.c \ archive_string_sprintf.c \ archive_util.c \ archive_virtual.c \ archive_write.c \ archive_write_disk.c \ archive_write_disk_set_standard_lookup.c \ archive_write_open_fd.c \ archive_write_open_file.c \ archive_write_open_filename.c \ archive_write_open_memory.c \ archive_write_set_compression_bzip2.c \ archive_write_set_compression_gzip.c \ archive_write_set_compression_none.c \ archive_write_set_format.c \ archive_write_set_format_ar.c \ archive_write_set_format_by_name.c \ archive_write_set_format_cpio.c \ archive_write_set_format_pax.c \ archive_write_set_format_shar.c \ archive_write_set_format_ustar.c # Man pages to be installed. MAN= archive_entry.3 \ archive_read.3 \ archive_util.3 \ archive_write.3 \ archive_write_disk.3 \ libarchive.3 \ libarchive-formats.5 \ tar.5 # Symlink the man pages under each function name. MLINKS+= archive_entry.3 archive_entry_acl_add_entry.3 MLINKS+= archive_entry.3 archive_entry_acl_add_entry_w.3 MLINKS+= archive_entry.3 archive_entry_acl_clear.3 MLINKS+= archive_entry.3 archive_entry_acl_count.3 MLINKS+= archive_entry.3 archive_entry_acl_next.3 MLINKS+= archive_entry.3 archive_entry_acl_next_w.3 MLINKS+= archive_entry.3 archive_entry_acl_reset.3 MLINKS+= archive_entry.3 archive_entry_acl_text_w.3 MLINKS+= archive_entry.3 archive_entry_clear.3 MLINKS+= archive_entry.3 archive_entry_clone.3 MLINKS+= archive_entry.3 archive_entry_copy_fflags_text_w.3 MLINKS+= archive_entry.3 archive_entry_copy_gname_w.3 MLINKS+= archive_entry.3 archive_entry_copy_hardlink_w.3 MLINKS+= archive_entry.3 archive_entry_copy_pathname_w.3 MLINKS+= archive_entry.3 archive_entry_copy_stat.3 MLINKS+= archive_entry.3 archive_entry_copy_symlink_w.3 MLINKS+= archive_entry.3 archive_entry_copy_uname_w.3 MLINKS+= archive_entry.3 archive_entry_fflags.3 MLINKS+= archive_entry.3 archive_entry_fflags_text.3 MLINKS+= archive_entry.3 archive_entry_free.3 MLINKS+= archive_entry.3 archive_entry_gid.3 MLINKS+= archive_entry.3 archive_entry_gname.3 MLINKS+= archive_entry.3 archive_entry_gname_w.3 MLINKS+= archive_entry.3 archive_entry_hardlink.3 MLINKS+= archive_entry.3 archive_entry_ino.3 MLINKS+= archive_entry.3 archive_entry_mode.3 MLINKS+= archive_entry.3 archive_entry_mtime.3 MLINKS+= archive_entry.3 archive_entry_mtime_nsec.3 MLINKS+= archive_entry.3 archive_entry_new.3 MLINKS+= archive_entry.3 archive_entry_pathname.3 MLINKS+= archive_entry.3 archive_entry_pathname_w.3 MLINKS+= archive_entry.3 archive_entry_rdev.3 MLINKS+= archive_entry.3 archive_entry_rdevmajor.3 MLINKS+= archive_entry.3 archive_entry_rdevminor.3 MLINKS+= archive_entry.3 archive_entry_set_fflags.3 MLINKS+= archive_entry.3 archive_entry_set_gid.3 MLINKS+= archive_entry.3 archive_entry_set_gname.3 MLINKS+= archive_entry.3 archive_entry_set_hardlink.3 MLINKS+= archive_entry.3 archive_entry_set_link.3 MLINKS+= archive_entry.3 archive_entry_set_mode.3 MLINKS+= archive_entry.3 archive_entry_set_pathname.3 MLINKS+= archive_entry.3 archive_entry_set_rdevmajor.3 MLINKS+= archive_entry.3 archive_entry_set_rdevminor.3 MLINKS+= archive_entry.3 archive_entry_set_size.3 MLINKS+= archive_entry.3 archive_entry_set_symlink.3 MLINKS+= archive_entry.3 archive_entry_set_uid.3 MLINKS+= archive_entry.3 archive_entry_set_uname.3 MLINKS+= archive_entry.3 archive_entry_size.3 MLINKS+= archive_entry.3 archive_entry_stat.3 MLINKS+= archive_entry.3 archive_entry_symlink.3 MLINKS+= archive_entry.3 archive_entry_uid.3 MLINKS+= archive_entry.3 archive_entry_uname.3 MLINKS+= archive_entry.3 archive_entry_uname_w.3 MLINKS+= archive_read.3 archive_read_data.3 MLINKS+= archive_read.3 archive_read_data_block.3 MLINKS+= archive_read.3 archive_read_data_into_buffer.3 MLINKS+= archive_read.3 archive_read_data_into_fd.3 MLINKS+= archive_read.3 archive_read_data_skip.3 MLINKS+= archive_read.3 archive_read_extract.3 MLINKS+= archive_read.3 archive_read_extract_set_progress_callback.3 MLINKS+= archive_read.3 archive_read_extract_set_skip_file.3 MLINKS+= archive_read.3 archive_read_finish.3 MLINKS+= archive_read.3 archive_read_new.3 MLINKS+= archive_read.3 archive_read_next_header.3 MLINKS+= archive_read.3 archive_read_open.3 MLINKS+= archive_read.3 archive_read_open2.3 MLINKS+= archive_read.3 archive_read_open_FILE.3 MLINKS+= archive_read.3 archive_read_open_fd.3 MLINKS+= archive_read.3 archive_read_open_file.3 MLINKS+= archive_read.3 archive_read_open_filename.3 MLINKS+= archive_read.3 archive_read_open_memory.3 MLINKS+= archive_read.3 archive_read_support_compression_all.3 MLINKS+= archive_read.3 archive_read_support_compression_bzip2.3 MLINKS+= archive_read.3 archive_read_support_compression_compress.3 MLINKS+= archive_read.3 archive_read_support_compression_gzip.3 MLINKS+= archive_read.3 archive_read_support_compression_none.3 MLINKS+= archive_read.3 archive_read_support_format_all.3 MLINKS+= archive_read.3 archive_read_support_format_cpio.3 MLINKS+= archive_read.3 archive_read_support_format_iso9660.3 MLINKS+= archive_read.3 archive_read_support_format_tar.3 MLINKS+= archive_read.3 archive_read_support_format_zip.3 MLINKS+= archive_util.3 archive_clear_error.3 MLINKS+= archive_util.3 archive_compression.3 MLINKS+= archive_util.3 archive_compression_name.3 MLINKS+= archive_util.3 archive_errno.3 MLINKS+= archive_util.3 archive_error_string.3 MLINKS+= archive_util.3 archive_format.3 MLINKS+= archive_util.3 archive_format_name.3 MLINKS+= archive_util.3 archive_set_error.3 MLINKS+= archive_write.3 archive_write_data.3 MLINKS+= archive_write.3 archive_write_finish.3 MLINKS+= archive_write.3 archive_write_finish_entry.3 MLINKS+= archive_write.3 archive_write_get_bytes_in_last_block.3 MLINKS+= archive_write.3 archive_write_get_bytes_per_block.3 MLINKS+= archive_write.3 archive_write_header.3 MLINKS+= archive_write.3 archive_write_new.3 MLINKS+= archive_write.3 archive_write_open.3 MLINKS+= archive_write.3 archive_write_open_FILE.3 MLINKS+= archive_write.3 archive_write_open_fd.3 MLINKS+= archive_write.3 archive_write_open_file.3 MLINKS+= archive_write.3 archive_write_open_filename.3 MLINKS+= archive_write.3 archive_write_open_memory.3 MLINKS+= archive_write.3 archive_write_set_bytes_in_last_block.3 MLINKS+= archive_write.3 archive_write_set_bytes_per_block.3 MLINKS+= archive_write.3 archive_write_set_callbacks.3 MLINKS+= archive_write.3 archive_write_set_compression_bzip2.3 MLINKS+= archive_write.3 archive_write_set_compression_gzip.3 MLINKS+= archive_write.3 archive_write_set_format_pax.3 MLINKS+= archive_write.3 archive_write_set_format_shar.3 MLINKS+= archive_write.3 archive_write_set_format_ustar.3 MLINKS+= archive_write_disk.3 archive_write_disk_new.3 MLINKS+= archive_write_disk.3 archive_write_disk_set_group_lookup.3 MLINKS+= archive_write_disk.3 archive_write_disk_set_options.3 MLINKS+= archive_write_disk.3 archive_write_disk_set_skip_file.3 MLINKS+= archive_write_disk.3 archive_write_disk_set_standard_lookup.3 MLINKS+= archive_write_disk.3 archive_write_disk_set_user_lookup.3 MLINKS+= libarchive.3 archive.3 test: cd ${.CURDIR}/test && make test .include Index: head/lib/libarchive/archive.h.in =================================================================== --- head/lib/libarchive/archive.h.in (revision 168739) +++ head/lib/libarchive/archive.h.in (revision 168740) @@ -1,502 +1,502 @@ /*- * 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$ */ #ifndef ARCHIVE_H_INCLUDED #define ARCHIVE_H_INCLUDED /* * This header file corresponds to: * Library version @VERSION@ * Shared library version @SHLIB_MAJOR@ */ #include /* Linux requires this for off_t */ @ARCHIVE_H_INCLUDE_INTTYPES_H@ #include /* For FILE * */ #ifndef _WIN32 #include /* For ssize_t and size_t */ #else typedef long ssize_t; typedef unsigned int uid_t; typedef unsigned int gid_t; typedef unsigned short mode_t; #endif #ifdef __cplusplus extern "C" { #endif /* * If ARCHIVE_API_VERSION != archive_api_version(), then the library you * were linked with is using an incompatible API to the one you were * compiled with. This is almost certainly a fatal problem. * * ARCHIVE_API_FEATURE is incremented with each significant feature * addition, so you can test (at compile or run time) if a particular * feature is implemented. It's no big deal if ARCHIVE_API_FEATURE != * archive_api_feature(), as long as both are high enough to include * the features you're relying on. Specific values of FEATURE are * documented here: * * 1 - Version tests are available. * 2 - archive_{read,write}_close available separately from _finish. * 3 - open_memory, open_memory2, open_FILE, open_fd available * 5 - archive_write_disk interface available */ #define ARCHIVE_API_VERSION @ARCHIVE_API_MAJOR@ int archive_api_version(void); #define ARCHIVE_API_FEATURE @ARCHIVE_API_MINOR@ int archive_api_feature(void); /* Textual name/version of the library. */ #define ARCHIVE_LIBRARY_VERSION "libarchive @VERSION@" const char * archive_version(void); #define ARCHIVE_BYTES_PER_RECORD 512 #define ARCHIVE_DEFAULT_BYTES_PER_BLOCK 10240 /* 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. */ #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 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_API_VERSION < 2 typedef 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 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 /* * 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_SVR4 (ARCHIVE_FORMAT_AR | 1) +#define ARCHIVE_FORMAT_AR_GNU (ARCHIVE_FORMAT_AR | 1) #define ARCHIVE_FORMAT_AR_BSD (ARCHIVE_FORMAT_AR | 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. */ 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. */ int archive_read_support_compression_all(struct archive *); int archive_read_support_compression_bzip2(struct archive *); int archive_read_support_compression_compress(struct archive *); int archive_read_support_compression_gzip(struct archive *); int archive_read_support_compression_none(struct archive *); int archive_read_support_format_all(struct archive *); int archive_read_support_format_ar(struct archive *); int archive_read_support_format_cpio(struct archive *); int archive_read_support_format_empty(struct archive *); int archive_read_support_format_gnutar(struct archive *); int archive_read_support_format_iso9660(struct archive *); int archive_read_support_format_tar(struct archive *); int archive_read_support_format_zip(struct archive *); /* Open the archive using callbacks for archive I/O. */ int archive_read_open(struct archive *, void *_client_data, archive_open_callback *, archive_read_callback *, archive_close_callback *); 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. */ 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(). */ int archive_read_open_file(struct archive *, const char *_filename, size_t _block_size); /* Read an archive that's stored in memory. */ int archive_read_open_memory(struct archive *, void * buff, size_t size); /* A more involved version that is only used for internal testing. */ 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. */ 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. */ int archive_read_open_FILE(struct archive *, FILE *_file); /* Parses and returns next entry header. */ int archive_read_next_header(struct archive *, struct archive_entry **); /* * Retrieve the byte offset in UNCOMPRESSED data where last-read * header started. */ int64_t archive_read_header_position(struct archive *); /* Read data from the body of an entry. Similar to read(2). */ 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. */ 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 */ int archive_read_data_skip(struct archive *); int archive_read_data_into_buffer(struct archive *, void *buffer, ssize_t len); 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 (1) /* Default: Do obey umask, do not restore SUID/SGID/SVTX bits. */ #define ARCHIVE_EXTRACT_PERM (2) /* Default: Do not restore mtime/atime. */ #define ARCHIVE_EXTRACT_TIME (4) /* Default: Replace existing files. */ #define ARCHIVE_EXTRACT_NO_OVERWRITE (8) /* Default: Try create first, unlink only if create fails with EEXIST. */ #define ARCHIVE_EXTRACT_UNLINK (16) /* Default: Do not restore ACLs. */ #define ARCHIVE_EXTRACT_ACL (32) /* Default: Do not restore fflags. */ #define ARCHIVE_EXTRACT_FFLAGS (64) /* Default: Do not restore xattrs. */ #define ARCHIVE_EXTRACT_XATTR (128) /* 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 (256) /* Default: Do not reject entries with '..' as path elements. */ #define ARCHIVE_EXTRACT_SECURE_NODOTDOT (512) int archive_read_extract(struct archive *, struct archive_entry *, int flags); 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. */ void archive_read_extract_set_skip_file(struct archive *, dev_t, ino_t); /* Close the file and release most resources. */ 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_API_VERSION > 1 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 */ 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 */ struct archive *archive_write_new(void); int archive_write_set_bytes_per_block(struct archive *, int bytes_per_block); int archive_write_get_bytes_per_block(struct archive *); /* XXX This is badly misnamed; suggestions appreciated. XXX */ int archive_write_set_bytes_in_last_block(struct archive *, int bytes_in_last_block); 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. */ int archive_write_set_skip_file(struct archive *, dev_t, ino_t); int archive_write_set_compression_bzip2(struct archive *); int archive_write_set_compression_gzip(struct archive *); int archive_write_set_compression_none(struct archive *); /* A convenience function to set the format based on the code or name. */ int archive_write_set_format(struct archive *, int format_code); int archive_write_set_format_by_name(struct archive *, const char *name); /* To minimize link pollution, use one or more of the following. */ int archive_write_set_format_ar_bsd(struct archive *); int archive_write_set_format_ar_svr4(struct archive *); int archive_write_set_format_cpio(struct archive *); /* TODO: int archive_write_set_format_old_tar(struct archive *); */ int archive_write_set_format_pax(struct archive *); int archive_write_set_format_pax_restricted(struct archive *); int archive_write_set_format_shar(struct archive *); int archive_write_set_format_shar_dump(struct archive *); int archive_write_set_format_ustar(struct archive *); int archive_write_open(struct archive *, void *, archive_open_callback *, archive_write_callback *, archive_close_callback *); int archive_write_open_fd(struct archive *, int _fd); int archive_write_open_filename(struct archive *, const char *_file); /* A deprecated synonym for archive_write_open_filename() */ int archive_write_open_file(struct archive *, const char *_file); 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. */ 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. */ int archive_write_header(struct archive *, struct archive_entry *); #if ARCHIVE_API_VERSION > 1 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. */ int archive_write_data(struct archive *, const void *, size_t); #endif ssize_t archive_write_data_block(struct archive *, const void *, size_t, off_t); int archive_write_finish_entry(struct archive *); int archive_write_close(struct archive *); #if ARCHIVE_API_VERSION > 1 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. */ 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. */ struct archive *archive_write_disk_new(void); /* This file will not be overwritten. */ int archive_write_disk_set_skip_file(struct archive *, dev_t, ino_t); /* Set flags to control how the next item gets created. */ 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". */ 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. */ int archive_write_disk_set_group_lookup(struct archive *, void *private_data, gid_t (*loookup)(void *, const char *gname, gid_t gid), void (*cleanup)(void *)); int archive_write_disk_set_user_lookup(struct archive *, void *private_data, uid_t (*)(void *, const char *uname, uid_t uid), void (*cleanup)(void *)); /* * Accessor functions to read/set various information in * the struct archive object: */ /* Bytes written after compression or read before decompression. */ int64_t archive_position_compressed(struct archive *); /* Bytes written to compressor or read from decompressor. */ int64_t archive_position_uncompressed(struct archive *); const char *archive_compression_name(struct archive *); int archive_compression(struct archive *); int archive_errno(struct archive *); const char *archive_error_string(struct archive *); const char *archive_format_name(struct archive *); int archive_format(struct archive *); void archive_clear_error(struct archive *); void archive_set_error(struct archive *, int _err, const char *fmt, ...); #ifdef __cplusplus } #endif #endif /* !ARCHIVE_H_INCLUDED */ Index: head/lib/libarchive/archive_read_support_format_ar.c =================================================================== --- head/lib/libarchive/archive_read_support_format_ar.c (revision 168739) +++ head/lib/libarchive/archive_read_support_format_ar.c (revision 168740) @@ -1,617 +1,607 @@ /*- * Copyright (c) 2007 Kai Wang * Copyright (c) 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 * 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. */ #include "archive_platform.h" __FBSDID("$FreeBSD$"); +#ifdef HAVE_SYS_STAT_H +#include +#endif #ifdef HAVE_ERRNO_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #include "archive.h" #include "archive_entry.h" #include "archive_private.h" #include "archive_read_private.h" struct ar { int bid; off_t entry_bytes_remaining; off_t entry_offset; off_t entry_padding; char *strtab; size_t strtab_size; }; /* * Define structure of the "ar" header. */ #define AR_name_offset 0 #define AR_name_size 16 #define AR_date_offset 16 #define AR_date_size 12 #define AR_uid_offset 28 #define AR_uid_size 6 #define AR_gid_offset 34 #define AR_gid_size 6 #define AR_mode_offset 40 #define AR_mode_size 8 #define AR_size_offset 48 #define AR_size_size 10 #define AR_fmag_offset 58 #define AR_fmag_size 2 -/* - * "ar" magic numbers. - */ -#define ARMAG "!\n" -#define SARMAG 8 /* strlen(ARMAG); */ -#define AR_EFMT1 "#1/" -#define SAR_EFMT1 3 /* strlen(AR_EFMT1); */ -#define ARFMAG "`\n" -#define SARFMAG 2 /* strlen(ARFMAG); */ - #define isdigit(x) (x) >= '0' && (x) <= '9' static int archive_read_format_ar_bid(struct archive_read *a); static int archive_read_format_ar_cleanup(struct archive_read *a); static int archive_read_format_ar_read_data(struct archive_read *a, const void **buff, size_t *size, off_t *offset); static int archive_read_format_ar_skip(struct archive_read *a); static int archive_read_format_ar_read_header(struct archive_read *a, struct archive_entry *e); -static int64_t ar_atol8(const char *p, unsigned char_cnt); -static int64_t ar_atol10(const char *p, unsigned char_cnt); -static int ar_parse_string_table(struct archive_read *, struct ar *, +static uint64_t ar_atol8(const char *p, unsigned char_cnt); +static uint64_t ar_atol10(const char *p, unsigned char_cnt); +static int ar_parse_gnu_filename_table(struct archive_read *, struct ar *, const void *, size_t); +static int ar_parse_common_header(struct ar *ar, struct archive_entry *, + const char *h); -/* - * ANSI C99 defines constants for these, but not everyone supports - * those constants, so I define a couple of static variables here and - * compute the values. These calculations should be portable to any - * 2s-complement architecture. - */ -#ifdef UINT64_MAX -static const uint64_t max_uint64 = UINT64_MAX; -#else -static const uint64_t max_uint64 = ~(uint64_t)0; -#endif -#ifdef INT64_MAX -static const int64_t max_int64 = INT64_MAX; -#else -static const int64_t max_int64 = (int64_t)((~(uint64_t)0) >> 1); -#endif -#ifdef INT64_MIN -static const int64_t min_int64 = INT64_MIN; -#else -static const int64_t min_int64 = (int64_t)(~((~(uint64_t)0) >> 1)); -#endif - int archive_read_support_format_ar(struct archive *_a) { struct archive_read *a = (struct archive_read *)_a; struct ar *ar; int r; ar = (struct ar *)malloc(sizeof(*ar)); if (ar == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate ar data"); return (ARCHIVE_FATAL); } memset(ar, 0, sizeof(*ar)); ar->bid = -1; ar->strtab = NULL; r = __archive_read_register_format(a, ar, archive_read_format_ar_bid, archive_read_format_ar_read_header, archive_read_format_ar_read_data, archive_read_format_ar_skip, archive_read_format_ar_cleanup); if (r != ARCHIVE_OK) { free(ar); return (r); } return (ARCHIVE_OK); } static int archive_read_format_ar_cleanup(struct archive_read *a) { struct ar *ar; ar = (struct ar *)*(a->pformat_data); free(ar->strtab); free(ar); *(a->pformat_data) = NULL; return (ARCHIVE_OK); } static int archive_read_format_ar_bid(struct archive_read *a) { struct ar *ar; ssize_t bytes_read; const void *h; if (a->archive.archive_format != 0 && (a->archive.archive_format & ARCHIVE_FORMAT_BASE_MASK) != ARCHIVE_FORMAT_AR) return(0); ar = (struct ar *)*(a->pformat_data); if (ar->bid > 0) return (ar->bid); - bytes_read = (a->compression_read_ahead)(a, &h, SARMAG); - if (bytes_read < SARMAG) - return (-1); - /* - * Verify the global header. + * Verify the 8-byte file signature. * TODO: Do we need to check more than this? */ - if (strncmp((const char*)h, ARMAG, SARMAG) == 0) { - ar->bid = SARMAG; + bytes_read = (a->compression_read_ahead)(a, &h, 8); + if (bytes_read < 8) + return (-1); + if (strncmp((const char*)h, "!\n", 8) == 0) { + ar->bid = 64; return (ar->bid); } return (-1); } static int archive_read_format_ar_read_header(struct archive_read *a, struct archive_entry *entry) { - int r; - size_t bsd_append; - ssize_t bytes; - int64_t nval; - size_t tab_size; - char *fname, *p; + char filename[AR_name_size + 1]; struct ar *ar; + uint64_t number; /* Used to hold parsed numbers before validation. */ + ssize_t bytes_read; + size_t bsd_name_length, entry_size; + char *p; const void *b; const char *h; + int r; - bsd_append = 0; + ar = (struct ar*)*(a->pformat_data); - if (!a->archive.archive_format) { - a->archive.archive_format = ARCHIVE_FORMAT_AR; - a->archive.archive_format_name = "Unix Archiver"; - } - if (a->archive.file_position == 0) { /* * We are now at the beginning of the archive, * so we need first consume the ar global header. */ - (a->compression_read_consume)(a, SARMAG); + (a->compression_read_consume)(a, 8); + /* Set a default format code for now. */ + a->archive.archive_format = ARCHIVE_FORMAT_AR; } - /* Read 60-byte header */ - bytes = (a->compression_read_ahead)(a, &b, 60); - if (bytes < 60) { - /* - * We just encountered an incomplete ar file, - * though the _bid function accepted it. - */ + /* Read the header for the next file entry. */ + bytes_read = (a->compression_read_ahead)(a, &b, 60); + if (bytes_read < 60) { + /* Broken header. */ return (ARCHIVE_EOF); } (a->compression_read_consume)(a, 60); - h = (const char *)b; - /* Consistency check */ - if (strncmp(h + AR_fmag_offset, ARFMAG, SARFMAG) != 0) { + /* Verify the magic signature on the file header. */ + if (strncmp(h + AR_fmag_offset, "`\n", 2) != 0) { archive_set_error(&a->archive, EINVAL, "Consistency check failed"); return (ARCHIVE_WARN); } - ar = (struct ar*)*(a->pformat_data); + /* Copy filename into work buffer. */ + strncpy(filename, h + AR_name_offset, AR_name_size); + filename[AR_name_size] = '\0'; - if (strncmp(h + AR_name_offset, "//", 2) == 0) { + /* + * Guess the format variant based on the filename. + */ + if (a->archive.archive_format == ARCHIVE_FORMAT_AR) { + /* We don't already know the variant, so let's guess. */ /* - * An archive member with ar_name "//" is an archive - * string table. + * Biggest clue is presence of '/': GNU starts special + * filenames with '/', appends '/' as terminator to + * non-special names, so anything with '/' should be + * GNU except for BSD long filenames. */ - nval = ar_atol10(h + AR_size_offset, AR_size_size); - if (nval < 0 || nval > SIZE_MAX) { + if (strncmp(filename, "#1/", 3) == 0) + a->archive.archive_format = ARCHIVE_FORMAT_AR_BSD; + else if (strchr(filename, '/') != NULL) + a->archive.archive_format = ARCHIVE_FORMAT_AR_GNU; + else if (strncmp(filename, "__.SYMDEF", 9) == 0) + a->archive.archive_format = ARCHIVE_FORMAT_AR_BSD; + /* + * XXX Do GNU/SVR4 'ar' programs ever omit trailing '/' + * if name exactly fills 16-byte field? If so, we + * can't assume entries without '/' are BSD. XXX + */ + } + + /* Update format name from the code. */ + if (a->archive.archive_format == ARCHIVE_FORMAT_AR_GNU) + a->archive.archive_format_name = "ar (GNU/SVR4)"; + else if (a->archive.archive_format == ARCHIVE_FORMAT_AR_BSD) + a->archive.archive_format_name = "ar (BSD)"; + else + a->archive.archive_format_name = "ar"; + + /* + * Remove trailing spaces from the filename. GNU and BSD + * variants both pad filename area out with spaces. + * This will only be wrong if GNU/SVR4 'ar' implementations + * omit trailing '/' for 16-char filenames and we have + * a 16-char filename that ends in ' '. + */ + p = filename + AR_name_size - 1; + while (p >= filename && *p == ' ') { + *p = '\0'; + p--; + } + + /* + * Remove trailing slash unless first character is '/'. + * (BSD entries never end in '/', so this will only trim + * GNU-format entries. GNU special entries start with '/' + * and are not terminated in '/', so we don't trim anything + * that starts with '/'.) + */ + if (filename[0] != '/' && *p == '/') + *p = '\0'; + + /* + * '//' is the GNU filename table. + * Later entries can refer to names in this table. + */ + if (strcmp(filename, "//") == 0) { + /* This must come before any call to _read_ahead. */ + ar_parse_common_header(ar, entry, h); + archive_entry_copy_pathname(entry, filename); + archive_entry_set_mode(entry, + S_IFREG | (archive_entry_mode(entry) & 0777)); + /* Get the size of the filename table. */ + number = ar_atol10(h + AR_size_offset, AR_size_size); + if (number > SIZE_MAX) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "String table too large"); + "Filename table too large"); return (ARCHIVE_FATAL); } - tab_size = (size_t)nval; - bytes = (a->compression_read_ahead)(a, &b, tab_size); - if (bytes <= 0) + entry_size = (size_t)number; + /* Read the filename table into memory. */ + bytes_read = (a->compression_read_ahead)(a, &b, entry_size); + if (bytes_read <= 0) return (ARCHIVE_FATAL); - if (bytes < nval) { + if ((size_t)bytes_read < entry_size) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Truncated input file"); return (ARCHIVE_FATAL); } + /* + * Don't consume the contents, so the client will + * also get a shot at reading it. + */ - r = ar_parse_string_table(a, ar, b, tab_size); - if (r == ARCHIVE_OK) { - /* - * Archive string table only have ar_name and ar_size fileds - * in its header. - */ - archive_entry_copy_pathname(entry, "//"); - h = (const char *)b; - nval = ar_atol10(h + AR_size_offset, AR_size_size); - archive_entry_set_size(entry, nval); - - ar->entry_offset = 0; - ar->entry_bytes_remaining = nval; - ar->entry_padding = ar->entry_bytes_remaining % 2; - } - return (r); + /* Parse the filename table. */ + return (ar_parse_gnu_filename_table(a, ar, b, entry_size)); } - if (h[AR_name_offset] == '/' && isdigit(h[AR_name_offset + 1])) { + /* + * GNU variant handles long filenames by storing / + * to indicate a name stored in the filename table. + */ + if (filename[0] == '/' && isdigit(filename[1])) { + number = ar_atol10(h + AR_name_offset + 1, AR_name_size - 1); /* - * Archive member is common format with SVR4/GNU variant. - * "/" followed by one or more digit(s) in the ar_name - * filed indicates an index to the string table. + * If we can't look up the real name, warn and return + * the entry with the wrong name. */ - if (ar->strtab == NULL) { + if (ar->strtab == NULL || number > ar->strtab_size) { archive_set_error(&a->archive, EINVAL, - "String table does not exist"); + "Can't find long filename for entry"); + archive_entry_copy_pathname(entry, filename); + /* Parse the time, owner, mode, size fields. */ + ar_parse_common_header(ar, entry, h); return (ARCHIVE_WARN); } - nval = ar_atol10(h + AR_name_offset + 1, AR_name_size - 1); - if (nval < 0 || nval > ar->strtab_size) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "String table overflow"); - return (ARCHIVE_FATAL); - } - archive_entry_copy_pathname(entry, &ar->strtab[(size_t)nval]); - goto remain; + archive_entry_copy_pathname(entry, &ar->strtab[(size_t)number]); + /* Parse the time, owner, mode, size fields. */ + return (ar_parse_common_header(ar, entry, h)); } - if (strncmp(h + AR_name_offset, AR_EFMT1, SAR_EFMT1) == 0) { - /* - * Archive member is common format with BSD variant. - * AR_EFMT1 is followed by one or more digit(s) indicating - * the length of the real filename which is appended - * to the header. - */ - nval = ar_atol10(h + AR_name_offset + SAR_EFMT1, - AR_name_size - SAR_EFMT1); - if (nval < 0 || nval >= SIZE_MAX) { + /* + * BSD handles long filenames by storing "#1/" followed by the + * length of filename as a decimal number, then prepends the + * the filename to the file contents. + */ + if (strncmp(filename, "#1/", 3) == 0) { + /* Parse the time, owner, mode, size fields. */ + /* This must occur before _read_ahead is called again. */ + ar_parse_common_header(ar, entry, h); + + /* 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) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Bad input file size"); return (ARCHIVE_FATAL); } - bsd_append = (size_t)nval; - bytes = (a->compression_read_ahead)(a, &b, bsd_append); - if (bytes <= 0) + 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); + + /* Read the long name into memory. */ + bytes_read = (a->compression_read_ahead)(a, &b, bsd_name_length); + if (bytes_read <= 0) return (ARCHIVE_FATAL); - if (bytes < nval) { + if ((size_t)bytes_read < bsd_name_length) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Truncated input file"); return (ARCHIVE_FATAL); } + (a->compression_read_consume)(a, bsd_name_length); - (a->compression_read_consume)(a, bsd_append); - - fname = (char *)malloc(bsd_append + 1); - if (fname == NULL) { + /* Store it in the entry. */ + p = (char *)malloc(bsd_name_length + 1); + if (p == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate fname buffer"); return (ARCHIVE_FATAL); } - strncpy(fname, b, bsd_append); - fname[bsd_append] = '\0'; - archive_entry_copy_pathname(entry, fname); - free(fname); - fname = NULL; - - goto remain; + strncpy(p, b, bsd_name_length); + p[bsd_name_length] = '\0'; + archive_entry_copy_pathname(entry, p); + free(p); + return (ARCHIVE_OK); } /* - * "/" followed by one or more spaces indicate a - * SVR4/GNU archive symbol table. - * + * "/" is the SVR4/GNU archive symbol table. */ - if (strncmp(h + AR_name_offset, "/ ", 2) == 0) { + if (strcmp(filename, "/") == 0) { archive_entry_copy_pathname(entry, "/"); - goto remain; + /* Parse the time, owner, mode, size fields. */ + r = ar_parse_common_header(ar, entry, h); + /* Force the file type to a regular file. */ + archive_entry_set_mode(entry, + S_IFREG | (archive_entry_mode(entry) & 0777)); + return (r); } + /* - * "__.SYMDEF" indicates a BSD archive symbol table. + * "__.SYMDEF" is a BSD archive symbol table. */ - if (strncmp(h + AR_name_offset, "__.SYMDEF", 9) == 0) { - archive_entry_copy_pathname(entry, "__.SYMDEF"); - goto remain; + if (strcmp(filename, "__.SYMDEF") == 0) { + archive_entry_copy_pathname(entry, filename); + /* Parse the time, owner, mode, size fields. */ + return (ar_parse_common_header(ar, entry, h)); } /* - * Otherwise, the ar_name fields stores the real - * filename. - * SVR4/GNU variant append a '/' to mark the end of - * filename, while BSD variant use a space. + * Otherwise, this is a standard entry. The filename + * has already been trimmed as much as possible, based + * on our current knowledge of the format. */ - fname = (char *)malloc(AR_name_size + 1); - strncpy(fname, h + AR_name_offset, AR_name_size); - fname[AR_name_size] = '\0'; + archive_entry_copy_pathname(entry, filename); + return (ar_parse_common_header(ar, entry, h)); +} - if ((p = strchr(fname, '/')) != NULL) { - /* SVR4/GNU format */ - *p = '\0'; - archive_entry_copy_pathname(entry, fname); - free(fname); - fname = NULL; - goto remain; - } +static int +ar_parse_common_header(struct ar *ar, struct archive_entry *entry, + const char *h) +{ + uint64_t n; - /* BSD format */ - if ((p = strchr(fname, ' ')) != NULL) - *p = '\0'; - archive_entry_copy_pathname(entry, fname); - free(fname); - fname = NULL; - -remain: /* Copy remaining header */ archive_entry_set_mtime(entry, (time_t)ar_atol10(h + AR_date_offset, AR_date_size), 0L); archive_entry_set_uid(entry, (uid_t)ar_atol10(h + AR_uid_offset, AR_uid_size)); archive_entry_set_gid(entry, (gid_t)ar_atol10(h + AR_gid_offset, AR_gid_size)); archive_entry_set_mode(entry, (mode_t)ar_atol8(h + AR_mode_offset, AR_mode_size)); - nval = ar_atol10(h + AR_size_offset, AR_size_size); + n = ar_atol10(h + AR_size_offset, AR_size_size); ar->entry_offset = 0; - ar->entry_padding = nval % 2; - - /* - * For BSD variant, we should subtract the length of - * the appended filename string from ar_size to get the - * real file size. But remember we should do this only - * after we had calculated the padding. - */ - if (bsd_append > nval) { - archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, - "Truncated input file"); - return (ARCHIVE_FATAL); - } - if (bsd_append > 0) - nval -= bsd_append; - - archive_entry_set_size(entry, nval); - ar->entry_bytes_remaining = nval; - + ar->entry_padding = n % 2; + archive_entry_set_size(entry, n); + ar->entry_bytes_remaining = n; return (ARCHIVE_OK); } static int archive_read_format_ar_read_data(struct archive_read *a, const void **buff, size_t *size, off_t *offset) { ssize_t bytes_read; struct ar *ar; ar = (struct ar *)*(a->pformat_data); if (ar->entry_bytes_remaining > 0) { bytes_read = (a->compression_read_ahead)(a, buff, 1); if (bytes_read == 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Truncated ar archive"); return (ARCHIVE_FATAL); } if (bytes_read < 0) return (ARCHIVE_FATAL); - /* XXX I don't get this. */ if (bytes_read > ar->entry_bytes_remaining) bytes_read = (ssize_t)ar->entry_bytes_remaining; *size = bytes_read; *offset = ar->entry_offset; ar->entry_offset += bytes_read; ar->entry_bytes_remaining -= bytes_read; (a->compression_read_consume)(a, (size_t)bytes_read); return (ARCHIVE_OK); } else { while (ar->entry_padding > 0) { bytes_read = (a->compression_read_ahead)(a, buff, 1); if (bytes_read <= 0) return (ARCHIVE_FATAL); if (bytes_read > ar->entry_padding) bytes_read = (ssize_t)ar->entry_padding; (a->compression_read_consume)(a, (size_t)bytes_read); ar->entry_padding -= bytes_read; } *buff = NULL; *size = 0; *offset = ar->entry_offset; return (ARCHIVE_EOF); } } static int archive_read_format_ar_skip(struct archive_read *a) { off_t bytes_skipped; struct ar* ar; int r = ARCHIVE_OK; const void *b; /* Dummy variables */ size_t s; off_t o; ar = (struct ar *)*(a->pformat_data); if (a->compression_skip == NULL) { while (r == ARCHIVE_OK) r = archive_read_format_ar_read_data(a, &b, &s, &o); return (r); } bytes_skipped = (a->compression_skip)(a, ar->entry_bytes_remaining + ar->entry_padding); if (bytes_skipped < 0) return (ARCHIVE_FATAL); ar->entry_bytes_remaining = 0; ar->entry_padding = 0; return (ARCHIVE_OK); } static int -ar_parse_string_table(struct archive_read *a, struct ar *ar, +ar_parse_gnu_filename_table(struct archive_read *a, struct ar *ar, const void *h, size_t size) { char *p; if (ar->strtab != NULL) { archive_set_error(&a->archive, EINVAL, "More than one string tables exist"); return (ARCHIVE_WARN); } if (size == 0) { archive_set_error(&a->archive, EINVAL, "Invalid string table"); return (ARCHIVE_WARN); } ar->strtab_size = size; ar->strtab = malloc(size); if (ar->strtab == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate string table buffer"); return (ARCHIVE_FATAL); } (void)memcpy(ar->strtab, h, size); for (p = ar->strtab; p < ar->strtab + size - 1; ++p) { if (*p == '/') { *p++ = '\0'; if (*p != '\n') goto bad_string_table; *p = '\0'; } } /* * Sanity check, last two chars must be `/\n' or '\n\n', * depending on whether the string table is padded by a '\n' * (string table produced by GNU ar always has a even size). */ if (p != ar->strtab + size && *p != '\n') goto bad_string_table; /* Enforce zero termination. */ ar->strtab[size - 1] = '\0'; return (ARCHIVE_OK); bad_string_table: archive_set_error(&a->archive, EINVAL, "Invalid string table"); free(ar->strtab); ar->strtab = NULL; return (ARCHIVE_WARN); } -static int64_t +static uint64_t ar_atol8(const char *p, unsigned char_cnt) { - int64_t l, limit, last_digit_limit; - int digit, sign, base; + static const uint64_t max_uint64 = ~(uint64_t)0; + uint64_t l, limit, last_digit_limit; + unsigned int digit, base; base = 8; - limit = max_int64 / base; - last_digit_limit = max_int64 % base; + limit = max_uint64 / base; + last_digit_limit = max_uint64 % base; - while (*p == ' ' || *p == '\t') + while ((*p == ' ' || *p == '\t') && char_cnt-- > 0) p++; - if (*p == '-') { - sign = -1; - p++; - } else - sign = 1; l = 0; digit = *p - '0'; - while (digit >= 0 && digit < base && char_cnt-- > 0) { + while (*p >= '0' && digit < base && char_cnt-- > 0) { if (l>limit || (l == limit && digit > last_digit_limit)) { l = max_uint64; /* Truncate on overflow. */ break; } l = (l * base) + digit; digit = *++p - '0'; } - return (sign < 0) ? -l : l; + return (l); } -/* - * XXX This is not really correct for negative numbers, - * as min_int64_t can never be returned. That one is unused BTW. - */ -static int64_t +static uint64_t ar_atol10(const char *p, unsigned char_cnt) { - int64_t l, limit, last_digit_limit; - int base, digit, sign; + static const uint64_t max_uint64 = ~(uint64_t)0; + uint64_t l, limit, last_digit_limit; + unsigned int base, digit; base = 10; - limit = max_int64 / base; - last_digit_limit = max_int64 % base; + limit = max_uint64 / base; + last_digit_limit = max_uint64 % base; - while (*p == ' ' || *p == '\t') + while ((*p == ' ' || *p == '\t') && char_cnt-- > 0) p++; - if (*p == '-') { - sign = -1; - p++; - } else - sign = 1; - l = 0; digit = *p - '0'; - while (digit >= 0 && digit < base && char_cnt-- > 0) { + while (*p >= '0' && digit < base && char_cnt-- > 0) { if (l > limit || (l == limit && digit > last_digit_limit)) { l = max_uint64; /* Truncate on overflow. */ break; } l = (l * base) + digit; digit = *++p - '0'; } - return (sign < 0) ? -l : l; + return (l); } Index: head/lib/libarchive/archive_write_set_format_ar.c =================================================================== --- head/lib/libarchive/archive_write_set_format_ar.c (revision 168739) +++ head/lib/libarchive/archive_write_set_format_ar.c (revision 168740) @@ -1,492 +1,492 @@ /*- * Copyright (c) 2007 Kai Wang * Copyright (c) 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 * 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. */ #include "archive_platform.h" __FBSDID("$FreeBSD$"); #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_ERRNO_H #include #endif #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #include "archive.h" #include "archive_entry.h" #include "archive_private.h" #include "archive_write_private.h" struct ar_w { uint64_t entry_bytes_remaining; uint64_t entry_padding; int is_strtab; int has_strtab; char *strtab; }; /* * Define structure of the "ar" header. */ #define AR_name_offset 0 #define AR_name_size 16 #define AR_date_offset 16 #define AR_date_size 12 #define AR_uid_offset 28 #define AR_uid_size 6 #define AR_gid_offset 34 #define AR_gid_size 6 #define AR_mode_offset 40 #define AR_mode_size 8 #define AR_size_offset 48 #define AR_size_size 10 #define AR_fmag_offset 58 #define AR_fmag_size 2 /* * "ar" magic numbers. */ #define ARMAG "!\n" #define SARMAG 8 /* strlen(ARMAG); */ #define AR_EFMT1 "#1/" #define SAR_EFMT1 3 /* strlen(AR_EFMT1); */ #define ARFMAG "`\n" #define SARFMAG 2 /* strlen(ARFMAG); */ static int __archive_write_set_format_ar(struct archive_write *); static int archive_write_ar_header(struct archive_write *, struct archive_entry *); static ssize_t archive_write_ar_data(struct archive_write *, const void *buff, size_t s); static int archive_write_ar_destroy(struct archive_write *); static int archive_write_ar_finish_entry(struct archive_write *); static int format_octal(int64_t v, char *p, int s); static int format_decimal(int64_t v, char *p, int s); int archive_write_set_format_ar_bsd(struct archive *_a) { struct archive_write *a = (struct archive_write *)_a; int r = __archive_write_set_format_ar(a); if (r == ARCHIVE_OK) { a->archive_format = ARCHIVE_FORMAT_AR_BSD; a->archive_format_name = "ar (BSD)"; } return (r); } int archive_write_set_format_ar_svr4(struct archive *_a) { struct archive_write *a = (struct archive_write *)_a; int r = __archive_write_set_format_ar(a); if (r == ARCHIVE_OK) { - a->archive_format = ARCHIVE_FORMAT_AR_SVR4; + a->archive_format = ARCHIVE_FORMAT_AR_GNU; a->archive_format_name = "ar (GNU/SVR4)"; } return (r); } /* * Generic initialization. */ static int __archive_write_set_format_ar(struct archive_write *a) { struct ar_w *ar; /* If someone else was already registered, unregister them. */ if (a->format_destroy != NULL) (a->format_destroy)(a); ar = (struct ar_w *)malloc(sizeof(*ar)); if (ar == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate ar data"); return (ARCHIVE_FATAL); } memset(ar, 0, sizeof(*ar)); a->format_data = ar; a->format_write_header = archive_write_ar_header; a->format_write_data = archive_write_ar_data; a->format_finish = NULL; a->format_destroy = archive_write_ar_destroy; a->format_finish_entry = archive_write_ar_finish_entry; return (ARCHIVE_OK); } static int archive_write_ar_header(struct archive_write *a, struct archive_entry *entry) { int ret, append_fn; char buff[60]; char *ss, *se; struct ar_w *ar; const char *pp; const struct stat *st; ret = 0; append_fn = 0; ar = (struct ar_w *)a->format_data; ar->is_strtab = 0; if (a->archive.file_position == 0) { /* * We are now at the beginning of the archive, * so we need first write the ar global header. */ (a->compression_write)(a, ARMAG, SARMAG); } memset(buff, ' ', 60); strncpy(&buff[AR_fmag_offset], ARFMAG, SARFMAG); pp = archive_entry_pathname(entry); if (strcmp(pp, "/") == 0 ) { /* Entry is archive symbol table in GNU format */ buff[AR_name_offset] = '/'; goto stat; } if (strcmp(pp, "__.SYMDEF") == 0) { /* Entry is archive symbol table in BSD format */ strncpy(buff + AR_name_offset, "__.SYMDEF", 9); goto stat; } if (strcmp(pp, "//") == 0) { /* * Entry is archive string table, inform that we should * collect strtab in next _data call. */ ar->is_strtab = 1; buff[AR_name_offset] = buff[AR_name_offset + 1] = '/'; /* * For archive string table, only ar_size filed should * be set. */ goto size; } /* Otherwise, entry is a normal archive member. */ - if (a->archive_format == ARCHIVE_FORMAT_AR_SVR4) { + if (a->archive_format == ARCHIVE_FORMAT_AR_GNU) { /* * SVR4/GNU variant use a "/" to mark then end of the filename, * make it possible to have embedded spaces in the filename. * So, the longest filename here (without extension) is * actually 15 bytes. */ if (strlen(pp) <= 15) { strncpy(&buff[AR_name_offset], pp, strlen(pp)); buff[AR_name_offset + strlen(pp)] = '/'; } else { /* * For filename longer than 15 bytes, GNU variant * makes use of a string table and instead stores the * offset of the real filename to in the ar_name field. * The string table should have been written before. */ if (ar->has_strtab <= 0) { archive_set_error(&a->archive, EINVAL, "Can't find string table"); return (ARCHIVE_WARN); } se = (char *)malloc(strlen(pp) + 3); if (se == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate filename buffer"); return (ARCHIVE_FATAL); } strncpy(se, pp, strlen(pp)); strcpy(se + strlen(pp), "/\n"); ss = strstr(ar->strtab, se); free(se); if (ss == NULL) { archive_set_error(&a->archive, EINVAL, "Invalid string table"); return (ARCHIVE_WARN); } /* * GNU variant puts "/" followed by digits into * ar_name field. These digits indicates the real * filename string's offset to the string table. */ buff[AR_name_offset] = '/'; if (format_decimal(ss - ar->strtab, buff + AR_name_offset + 1, AR_name_size - 1)) { archive_set_error(&a->archive, ERANGE, "string table offset too large"); return (ARCHIVE_WARN); } } } else if (a->archive_format == ARCHIVE_FORMAT_AR_BSD) { /* * BSD variant: for any file name which is more than * 16 chars or contains one or more embedded space(s), the * string "#1/" followed by the ASCII length of the name is * put into the ar_name field. The file size (stored in the * ar_size field) is incremented by the length of the name. * The name is then written immediately following the * archive header. */ if (strlen(pp) <= 16 && strchr(pp, ' ') == NULL) { strncpy(&buff[AR_name_offset], pp, strlen(pp)); buff[AR_name_offset + strlen(pp)] = ' '; } else { strncpy(buff + AR_name_offset, AR_EFMT1, SAR_EFMT1); if (format_decimal(strlen(pp), buff + AR_name_offset + SAR_EFMT1, AR_name_size - SAR_EFMT1)) { archive_set_error(&a->archive, ERANGE, "File name too long"); return (ARCHIVE_WARN); } append_fn = 1; archive_entry_set_size(entry, archive_entry_size(entry) + strlen(pp)); } } stat: st = archive_entry_stat(entry); if (format_decimal(st->st_mtime, buff + AR_date_offset, AR_date_size)) { archive_set_error(&a->archive, ERANGE, "File modification time too large"); return (ARCHIVE_WARN); } if (format_decimal(st->st_uid, buff + AR_uid_offset, AR_uid_size)) { archive_set_error(&a->archive, ERANGE, "Numeric user ID too large"); return (ARCHIVE_WARN); } if (format_decimal(st->st_gid, buff + AR_gid_offset, AR_gid_size)) { archive_set_error(&a->archive, ERANGE, "Numeric group ID too large"); return (ARCHIVE_WARN); } if (format_octal(st->st_mode, buff + AR_mode_offset, AR_mode_size)) { archive_set_error(&a->archive, ERANGE, "Numeric mode too large"); return (ARCHIVE_WARN); } size: if (format_decimal(archive_entry_size(entry), buff + AR_size_offset, AR_size_size)) { archive_set_error(&a->archive, ERANGE, "File size out of range"); return (ARCHIVE_WARN); } ret = (a->compression_write)(a, buff, 60); if (ret != ARCHIVE_OK) return (ret); ar->entry_bytes_remaining = archive_entry_size(entry); ar->entry_padding = ar->entry_bytes_remaining % 2; if (append_fn > 0) { ret = (a->compression_write)(a, pp, strlen(pp)); if (ret != ARCHIVE_OK) return (ret); ar->entry_bytes_remaining -= strlen(pp); } return (ARCHIVE_OK); } static ssize_t archive_write_ar_data(struct archive_write *a, const void *buff, size_t s) { struct ar_w *ar; int ret; ar = (struct ar_w *)a->format_data; if (s > ar->entry_bytes_remaining) s = ar->entry_bytes_remaining; if (ar->is_strtab > 0) { if (ar->has_strtab > 0) { archive_set_error(&a->archive, EINVAL, "More than one string tables exist"); return (ARCHIVE_WARN); } ar->strtab = (char *)malloc(s); if (ar->strtab == NULL) { archive_set_error(&a->archive, ENOMEM, "Can't allocate strtab buffer"); return (ARCHIVE_FATAL); } strncpy(ar->strtab, buff, s); ar->has_strtab = 1; } ret = (a->compression_write)(a, buff, s); if (ret != ARCHIVE_OK) return (ret); ar->entry_bytes_remaining -= s; return (s); } static int archive_write_ar_destroy(struct archive_write *a) { struct ar_w *ar; ar = (struct ar_w *)a->format_data; if (ar->has_strtab > 0) { free(ar->strtab); ar->strtab = NULL; } free(ar); a->format_data = NULL; return (ARCHIVE_OK); } static int archive_write_ar_finish_entry(struct archive_write *a) { struct ar_w *ar; int ret; ar = (struct ar_w *)a->format_data; if (ar->entry_bytes_remaining != 0) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Entry remaining bytes larger than 0"); return (ARCHIVE_WARN); } if (ar->entry_padding == 0) { return (ARCHIVE_OK); } if (ar->entry_padding != 1) { archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Padding wrong size: %d should be 1 or 0", ar->entry_padding); return (ARCHIVE_WARN); } ret = (a->compression_write)(a, "\n", 1); return (ret); } /* * Format a number into the specified field using base-8. * NB: This version is slightly different from the one in * _ustar.c */ static int format_octal(int64_t v, char *p, int s) { int len; char *h; len = s; h = p; /* Octal values can't be negative, so use 0. */ if (v < 0) { while (len-- > 0) *p++ = '0'; return (-1); } p += s; /* Start at the end and work backwards. */ do { *--p = (char)('0' + (v & 7)); v >>= 3; } while (--s > 0 && v > 0); if (v == 0) { memmove(h, p, len - s); p = h + len - s; while (s-- > 0) *p++ = ' '; return (0); } /* If it overflowed, fill field with max value. */ while (len-- > 0) *p++ = '7'; return (-1); } /* * Format a number into the specified field using base-10. */ static int format_decimal(int64_t v, char *p, int s) { int len; char *h; len = s; h = p; /* Negative values in ar header are meaningless , so use 0. */ if (v < 0) { while (len-- > 0) *p++ = '0'; return (-1); } p += s; do { *--p = (char)('0' + (v % 10)); v /= 10; } while (--s > 0 && v > 0); if (v == 0) { memmove(h, p, len - s); p = h + len - s; while (s-- > 0) *p++ = ' '; return (0); } /* If it overflowed, fill field with max value. */ while (len-- > 0) *p++ = '9'; return (-1); } Index: head/lib/libarchive/archive_write_set_format_by_name.c =================================================================== --- head/lib/libarchive/archive_write_set_format_by_name.c (revision 168739) +++ head/lib/libarchive/archive_write_set_format_by_name.c (revision 168740) @@ -1,68 +1,72 @@ /*- * 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 "archive_platform.h" __FBSDID("$FreeBSD$"); #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_ERRNO_H #include #endif #ifdef HAVE_STRING_H #include #endif #include "archive.h" #include "archive_private.h" /* A table that maps names to functions. */ static struct { const char *name; int (*setter)(struct archive *); } names[] = { + { "arbsd", archive_write_set_format_ar_bsd }, + { "ar", archive_write_set_format_ar_bsd }, + { "argnu", archive_write_set_format_ar_svr4 }, + { "arsvr4", archive_write_set_format_ar_svr4 }, { "cpio", archive_write_set_format_cpio }, { "pax", archive_write_set_format_pax }, { "posix", archive_write_set_format_pax }, { "shar", archive_write_set_format_shar }, { "shardump", archive_write_set_format_shar_dump }, { "ustar", archive_write_set_format_ustar }, { NULL, NULL } }; int archive_write_set_format_by_name(struct archive *a, const char *name) { int i; for (i = 0; names[i].name != NULL; i++) { if (strcmp(name, names[i].name) == 0) return ((names[i].setter)(a)); } archive_set_error(a, EINVAL, "No such format '%s'", name); return (ARCHIVE_FATAL); } Index: head/lib/libarchive/test/test_read_format_ar.c =================================================================== --- head/lib/libarchive/test/test_read_format_ar.c (revision 168739) +++ head/lib/libarchive/test/test_read_format_ar.c (revision 168740) @@ -1,104 +1,115 @@ /*- * Copyright (c) 2007 Kai Wang * Copyright (c) 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 * 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. */ #include "test.h" __FBSDID("$FreeBSD$"); /* * This "archive" is created by "GNU ar". Here we try to verify * our GNU format handling functionality. */ static unsigned char archive[] = { '!','<','a','r','c','h','>',10,'/','/',' ',' ',' ',' ',' ',' ',' ', ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ', ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ', ' ',' ',' ',' ',' ','4','0',' ',' ',' ',' ',' ',' ',' ',' ','`',10, 'y','y','y','t','t','t','s','s','s','a','a','a','f','f','f','.','o', '/',10,'h','h','h','h','j','j','j','j','k','k','k','k','l','l','l', 'l','.','o','/',10,10,'/','0',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ', ' ',' ',' ',' ','1','1','7','5','4','6','5','6','5','2',' ',' ','1', '0','0','1',' ',' ','0',' ',' ',' ',' ',' ','1','0','0','6','4','4', ' ',' ','8',' ',' ',' ',' ',' ',' ',' ',' ',' ','`',10,'5','5','6', '6','7','7','8','8','g','g','h','h','.','o','/',' ',' ',' ',' ',' ', ' ',' ',' ',' ','1','1','7','5','4','6','5','6','6','8',' ',' ','1', '0','0','1',' ',' ','0',' ',' ',' ',' ',' ','1','0','0','6','4','4', ' ',' ','4',' ',' ',' ',' ',' ',' ',' ',' ',' ','`',10,'3','3','3', '3','/','1','9',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ', '1','1','7','5','4','6','5','7','1','3',' ',' ','1','0','0','1',' ', ' ','0',' ',' ',' ',' ',' ','1','0','0','6','4','4',' ',' ','9',' ', ' ',' ',' ',' ',' ',' ',' ',' ','`',10,'9','8','7','6','5','4','3', '2','1',10}; char buff[64]; DEFINE_TEST(test_read_format_ar) { struct archive_entry *ae; struct archive *a; assert((a = archive_read_new()) != NULL); assertA(0 == archive_read_support_compression_all(a)); assertA(0 == archive_read_support_format_all(a)); assertA(0 == archive_read_open_memory(a, archive, sizeof(archive))); - /* First we meet the string table */ + /* Filename table. */ assertA(0 == archive_read_next_header(a, &ae)); - assertA(archive_compression(a) == ARCHIVE_COMPRESSION_NONE); - assertA(archive_format(a) == ARCHIVE_FORMAT_AR); assert(0 == strcmp("//", archive_entry_pathname(ae))); - assert(40 == archive_entry_size(ae)); - assertA(40 == archive_read_data(a, buff, 45)); + assertEqualInt(0, archive_entry_mtime(ae)); + assertEqualInt(0, archive_entry_uid(ae)); + assertEqualInt(0, archive_entry_gid(ae)); + assertEqualInt(40, archive_entry_size(ae)); + assertEqualIntA(a, 40, archive_read_data(a, buff, 50)); + assert(0 == memcmp(buff, "yyytttsssaaafff.o/\nhhhhjjjjkkkkllll.o/\n\n", 40)); /* First Entry */ assertA(0 == archive_read_next_header(a, &ae)); assert(0 == strcmp("yyytttsssaaafff.o", archive_entry_pathname(ae))); + assertEqualInt(1175465652, archive_entry_mtime(ae)); + assertEqualInt(1001, archive_entry_uid(ae)); + assertEqualInt(0, archive_entry_gid(ae)); assert(8 == archive_entry_size(ae)); assertA(8 == archive_read_data(a, buff, 10)); assert(0 == memcmp(buff, "55667788", 8)); /* Second Entry */ assertA(0 == archive_read_next_header(a, &ae)); assert(0 == strcmp("gghh.o", archive_entry_pathname(ae))); + assertEqualInt(1175465668, archive_entry_mtime(ae)); + assertEqualInt(1001, archive_entry_uid(ae)); + assertEqualInt(0, archive_entry_gid(ae)); assert(4 == archive_entry_size(ae)); assertA(4 == archive_read_data(a, buff, 10)); assert(0 == memcmp(buff, "3333", 4)); /* Third Entry */ assertA(0 == archive_read_next_header(a, &ae)); assert(0 == strcmp("hhhhjjjjkkkkllll.o", archive_entry_pathname(ae))); + assertEqualInt(1175465713, archive_entry_mtime(ae)); + assertEqualInt(1001, archive_entry_uid(ae)); + assertEqualInt(0, archive_entry_gid(ae)); assert(9 == archive_entry_size(ae)); assertA(9 == archive_read_data(a, buff, 9)); assert(0 == memcmp(buff, "987654321", 9)); /* Test EOF */ assertA(1 == archive_read_next_header(a, &ae)); assert(0 == archive_read_close(a)); #if ARCHIVE_API_VERSION > 1 assert(0 == archive_read_finish(a)); #else archive_read_finish(a); #endif } Index: head/lib/libarchive/test/test_write_format_ar.c =================================================================== --- head/lib/libarchive/test/test_write_format_ar.c (revision 168739) +++ head/lib/libarchive/test/test_write_format_ar.c (revision 168740) @@ -1,173 +1,174 @@ /*- * Copyright (c) 2007 Kai Wang * Copyright (c) 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 * 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. */ #include "test.h" __FBSDID("$FreeBSD$"); char buff[4096]; char buff2[64]; static unsigned char strtab[] = "abcdefghijklmn.o/\nggghhhjjjrrrttt.o/\n\n"; DEFINE_TEST(test_write_format_ar) { struct archive_entry *ae; struct archive* a; size_t used; /* * First we try to create a SVR4/GNU format archive. */ assert((a = archive_write_new()) != NULL); assertA(0 == archive_write_set_format_ar_svr4(a)); assertA(0 == archive_write_set_compression_none(a)); assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &used)); - /* write the string table */ + /* write the filename table */ assert((ae = archive_entry_new()) != NULL); archive_entry_copy_pathname(ae, "//"); archive_entry_set_size(ae, strlen(strtab)); assertA(0 == archive_write_header(a, ae)); assertA(strlen(strtab) == archive_write_data(a, strtab, strlen(strtab))); archive_entry_free(ae); /* write entries */ assert((ae = archive_entry_new()) != NULL); archive_entry_set_mtime(ae, 1, 0); assert(1 == archive_entry_mtime(ae)); archive_entry_set_mode(ae, S_IFREG | 0755); assert((S_IFREG | 0755) == archive_entry_mode(ae)); archive_entry_copy_pathname(ae, "abcdefghijklmn.o"); archive_entry_set_size(ae, 8); assertA(0 == archive_write_header(a, ae)); assertA(8 == archive_write_data(a, "87654321", 15)); archive_entry_free(ae); assert((ae = archive_entry_new()) != NULL); archive_entry_copy_pathname(ae, "ggghhhjjjrrrttt.o"); archive_entry_set_size(ae, 7); assertA(0 == archive_write_header(a, ae)); assertA(7 == archive_write_data(a, "7777777", 7)); archive_entry_free(ae); archive_write_close(a); #if ARCHIVE_API_VERSION > 1 assert(0 == archive_write_finish(a)); #elif archive_write_finish(a); #endif /* * 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)); assertA(0 == archive_read_next_header(a, &ae)); + assertEqualInt(0, archive_entry_mtime(ae)); assert(0 == strcmp("//", archive_entry_pathname(ae))); - assert(strlen(strtab) == archive_entry_size(ae)); - assertA(strlen(strtab) == archive_read_data(a, buff2, strlen(strtab))); + assertEqualInt(strlen(strtab), archive_entry_size(ae)); + assertEqualIntA(a, strlen(strtab), archive_read_data(a, buff2, 100)); assert(0 == memcmp(buff2, strtab, strlen(strtab))); assertA(0 == archive_read_next_header(a, &ae)); assert(1 == archive_entry_mtime(ae)); assert(0 == strcmp("abcdefghijklmn.o", archive_entry_pathname(ae))); assert(8 == archive_entry_size(ae)); assertA(8 == archive_read_data(a, buff2, 10)); assert(0 == memcmp(buff2, "87654321", 8)); assert(0 == archive_read_next_header(a, &ae)); assert(0 == strcmp("ggghhhjjjrrrttt.o", archive_entry_pathname(ae))); assert(7 == archive_entry_size(ae)); assertA(7 == archive_read_data(a, buff2, 11)); assert(0 == memcmp(buff2, "7777777", 7)); assert(0 == archive_read_close(a)); #if ARCHIVE_API_VERSION > 1 assert(0 == archive_read_finish(a)); #else archive_read_finish(a); #endif /* * Then, we try to create a BSD format archive. */ assert((a = archive_write_new()) != NULL); assertA(0 == archive_write_set_format_ar_bsd(a)); assertA(0 == archive_write_set_compression_none(a)); assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &used)); /* write a entry need long name extension */ assert((ae = archive_entry_new()) != NULL); archive_entry_copy_pathname(ae, "ttttyyyyuuuuiiii.o"); archive_entry_set_size(ae, 5); assertA(0 == archive_write_header(a, ae)); assertA(5 == archive_write_data(a, "12345", 7)); archive_entry_free(ae); /* write a entry with a short name */ assert((ae = archive_entry_new()) != NULL); archive_entry_copy_pathname(ae, "ttyy.o"); archive_entry_set_size(ae, 6); assertA(0 == archive_write_header(a, ae)); assertA(6 == archive_write_data(a, "555555", 7)); archive_entry_free(ae); archive_write_close(a); #if ARCHIVE_API_VERSION > 1 assert(0 == archive_write_finish(a)); #elif archive_write_finish(a); #endif /* 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)); assert(0 == archive_read_next_header(a, &ae)); assert(0 == strcmp("ttttyyyyuuuuiiii.o", archive_entry_pathname(ae))); - assert(5 == archive_entry_size(ae)); + assertEqualInt(5, archive_entry_size(ae)); assertA(5 == archive_read_data(a, buff2, 10)); assert(0 == memcmp(buff2, "12345", 5)); assert(0 == archive_read_next_header(a, &ae)); assert(0 == strcmp("ttyy.o", archive_entry_pathname(ae))); assert(6 == archive_entry_size(ae)); assertA(6 == archive_read_data(a, buff2, 10)); assert(0 == memcmp(buff2, "555555", 6)); /* Test EOF */ assertA(1 == archive_read_next_header(a, &ae)); assert(0 == archive_read_close(a)); #if ARCHIVE_API_VERSION > 1 assert(0 == archive_read_finish(a)); #else archive_read_finish(a); #endif }