Index: head/lib/libarchive/Makefile =================================================================== --- head/lib/libarchive/Makefile (revision 166386) +++ head/lib/libarchive/Makefile (revision 166387) @@ -1,205 +1,206 @@ # $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= 1.3.1 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= 3 CFLAGS+= -DPACKAGE_NAME=\"lib${LIB}\" CFLAGS+= -DPACKAGE_VERSION=\"${VERSION}\" 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_buffer.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_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_write.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_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 \ 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_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+= libarchive.3 archive.3 .include Index: head/lib/libarchive/archive.h.in =================================================================== --- head/lib/libarchive/archive.h.in (revision 166386) +++ head/lib/libarchive/archive.h.in (revision 166387) @@ -1,390 +1,392 @@ /*- * 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 * */ #include /* For ssize_t and size_t */ #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 */ #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. */ #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. */ #define ARCHIVE_FORMAT_BASE_MASK 0xff0000U #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 /*- * 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_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. */ /* TODO: The 'Default' comments here are not quite correct; clean this up. */ #define ARCHIVE_EXTRACT_OWNER (1) /* Default: owner/group not restored */ #define ARCHIVE_EXTRACT_PERM (2) /* Default: restore perm only for reg file*/ #define ARCHIVE_EXTRACT_TIME (4) /* Default: mod time not restored */ #define ARCHIVE_EXTRACT_NO_OVERWRITE (8) /* Default: Replace files on disk */ #define ARCHIVE_EXTRACT_UNLINK (16) /* Default: don't unlink existing files */ #define ARCHIVE_EXTRACT_ACL (32) /* Default: don't restore ACLs */ #define ARCHIVE_EXTRACT_FFLAGS (64) /* Default: don't restore fflags */ #define ARCHIVE_EXTRACT_XATTR (128) /* Default: don't restore xattrs */ 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. */ void archive_read_finish(struct archive *); /*- * 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_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 *); /* TODO: should be ssize_t, but that might require .so version bump? */ int archive_write_data(struct archive *, const void *, size_t); int archive_write_finish_entry(struct archive *); int archive_write_close(struct archive *); void archive_write_finish(struct archive *); /* * 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_set_error(struct archive *, int _err, const char *fmt, ...); #ifdef __cplusplus } #endif #endif /* !ARCHIVE_H_INCLUDED */ Index: head/lib/libarchive/archive_read.3 =================================================================== --- head/lib/libarchive/archive_read.3 (revision 166386) +++ head/lib/libarchive/archive_read.3 (revision 166387) @@ -1,541 +1,555 @@ .\" 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 AND CONTRIBUTORS ``AS IS'' AND .\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE .\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE .\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE .\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL .\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS .\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) .\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT .\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" .\" $FreeBSD$ .\" .Dd August 19, 2006 .Dt archive_read 3 .Os .Sh NAME .Nm archive_read_new , .Nm archive_read_support_compression_all , .Nm archive_read_support_compression_bzip2 , .Nm archive_read_support_compression_compress , .Nm archive_read_support_compression_gzip , .Nm archive_read_support_compression_none , .Nm archive_read_support_format_all , .Nm archive_read_support_format_cpio , +.Nm archive_read_support_format_empty , .Nm archive_read_support_format_iso9660 , .Nm archive_read_support_format_tar , .Nm archive_read_support_format_zip , .Nm archive_read_open , .Nm archive_read_open2 , .Nm archive_read_open_fd , .Nm archive_read_open_FILE , .Nm archive_read_open_filename , .Nm archive_read_open_memory , .Nm archive_read_next_header , .Nm archive_read_data , .Nm archive_read_data_block , .Nm archive_read_data_skip , .Nm archive_read_data_into_buffer , .Nm archive_read_data_into_fd , .Nm archive_read_extract , .Nm archive_read_extract_set_progress_callback , .Nm archive_read_close , .Nm archive_read_finish .Nd functions for reading streaming archives .Sh SYNOPSIS .In archive.h .Ft struct archive * .Fn archive_read_new "void" .Ft int .Fn archive_read_support_compression_all "struct archive *" .Ft int .Fn archive_read_support_compression_bzip2 "struct archive *" .Ft int .Fn archive_read_support_compression_compress "struct archive *" .Ft int .Fn archive_read_support_compression_gzip "struct archive *" .Ft int .Fn archive_read_support_compression_none "struct archive *" .Ft int .Fn archive_read_support_format_all "struct archive *" .Ft int .Fn archive_read_support_format_cpio "struct archive *" .Ft int +.Fn archive_read_support_format_empty "struct archive *" +.Ft int .Fn archive_read_support_format_iso9660 "struct archive *" .Ft int .Fn archive_read_support_format_tar "struct archive *" .Ft int .Fn archive_read_support_format_zip "struct archive *" .Ft int .Fn archive_read_open "struct archive *" "void *client_data" "archive_open_callback *" "archive_read_callback *" "archive_close_callback *" .Ft int .Fn archive_read_open2 "struct archive *" "void *client_data" "archive_open_callback *" "archive_read_callback *" "archive_skip_callback *" "archive_close_callback *" .Ft int .Fn archive_read_open_FILE "struct archive *" "FILE *file" .Ft int .Fn archive_read_open_fd "struct archive *" "int fd" "size_t block_size" .Ft int .Fn archive_read_open_filename "struct archive *" "const char *filename" "size_t block_size" .Ft int .Fn archive_read_open_memory "struct archive *" "void *buff" "size_t size" .Ft int .Fn archive_read_next_header "struct archive *" "struct archive_entry **" .Ft ssize_t .Fn archive_read_data "struct archive *" "void *buff" "size_t len" .Ft int .Fn archive_read_data_block "struct archive *" "const void **buff" "size_t *len" "off_t *offset" .Ft int .Fn archive_read_data_skip "struct archive *" .Ft int .Fn archive_read_data_into_buffer "struct archive *" "void *" "ssize_t len" .Ft int .Fn archive_read_data_into_fd "struct archive *" "int fd" .Ft int .Fn archive_read_extract "struct archive *" "struct archive_entry *" "int flags" .Ft void .Fn archive_read_extract_set_progress_callback "struct archive *" "void (*func)(void *)" "void *user_data" .Ft int .Fn archive_read_close "struct archive *" .Ft void .Fn archive_read_finish "struct archive *" .Sh DESCRIPTION These functions provide a complete API for reading streaming archives. The general process is to first create the .Tn struct archive object, set options, initialize the reader, iterate over the archive headers and associated data, then close the archive and release all resources. The following summary describes the functions in approximately the order they would be used: .Bl -tag -compact -width indent .It Fn archive_read_new Allocates and initializes a .Tn struct archive object suitable for reading from an archive. .It Fn archive_read_support_compression_all , Fn archive_read_support_compression_bzip2 , Fn archive_read_support_compression_compress , Fn archive_read_support_compression_gzip , Fn archive_read_support_compression_none Enables auto-detection code and decompression support for the specified compression. Note that .Dq none is always enabled by default. For convenience, .Fn archive_read_support_compression_all enables all available decompression code. -.It Fn archive_read_support_format_all , Fn archive_read_support_format_cpio , Fn archive_read_support_format_iso9660 , Fn archive_read_support_format_tar, Fn archive_read_support_format_zip +.It Fn archive_read_support_format_all , Fn archive_read_support_format_cpio , Fn archive_read_support_format_empty , Fn archive_read_support_format_iso9660 , Fn archive_read_support_format_tar, Fn archive_read_support_format_zip Enables support---including auto-detection code---for the specified archive format. For example, .Fn archive_read_support_format_tar enables support for a variety of standard tar formats, old-style tar, ustar, pax interchange format, and many common variants. For convenience, .Fn archive_read_support_format_all enables support for all available formats. Note that there is no default. .It Fn archive_read_open The same as .Fn archive_read_open2 , except that the skip callback is assumed to be .Dv NULL . .It Fn archive_read_open2 Freeze the settings, open the archive, and prepare for reading entries. This is the most generic version of this call, which accepts four callback functions. Most clients will want to use .Fn archive_read_open_filename , .Fn archive_read_open_FILE , .Fn archive_read_open_fd , or .Fn archive_read_open_memory instead. The library invokes the client-provided functions to obtain raw bytes from the archive. .It Fn archive_read_open_FILE Like .Fn archive_read_open , except that it accepts a .Ft "FILE *" pointer. This function should not be used with tape drives or other devices that require strict I/O blocking. .It Fn archive_read_open_fd Like .Fn archive_read_open , except that it accepts a file descriptor and block size rather than a set of function pointers. Note that the file descriptor will not be automatically closed at end-of-archive. This function is safe for use with tape drives or other blocked devices. .It Fn archive_read_open_file This is a deprecated synonym for .Fn archive_read_open_filename . .It Fn archive_read_open_filename Like .Fn archive_read_open , except that it accepts a simple filename and a block size. A NULL filename represents standard input. This function is safe for use with tape drives or other blocked devices. .It Fn archive_read_open_memory Like .Fn archive_read_open , except that it accepts a pointer and size of a block of memory containing the archive data. .It Fn archive_read_next_header Read the header for the next entry and return a pointer to a .Tn struct archive_entry . .It Fn archive_read_data Read data associated with the header just read. Internally, this is a convenience function that calls .Fn archive_read_data_block and fills any gaps with nulls so that callers see a single continuous stream of data. .It Fn archive_read_data_block Return the next available block of data for this entry. Unlike .Fn archive_read_data , the .Fn archive_read_data_block function avoids copying data and allows you to correctly handle sparse files, as supported by some archive formats. The library guarantees that offsets will increase and that blocks will not overlap. Note that the blocks returned from this function can be much larger than the block size read from disk, due to compression and internal buffer optimizations. .It Fn archive_read_data_skip A convenience function that repeatedly calls .Fn archive_read_data_block to skip all of the data for this archive entry. .It Fn archive_read_data_into_buffer A convenience function that repeatedly calls .Fn archive_read_data_block to copy the entire entry into the client-supplied buffer. Note that the client is responsible for sizing the buffer appropriately. .It Fn archive_read_data_into_fd A convenience function that repeatedly calls .Fn archive_read_data_block to copy the entire entry to the provided file descriptor. .It Fn archive_read_extract_set_skip_file This function records the device and inode numbers of a file that should not be restored. This is a convenience that prevents .Fn archive_read_extract from restoring a file over the archive itself. .It Fn archive_read_extract A convenience function that recreates the specified object on disk and reads the entry data into that object. The filename, permissions, and other critical information are taken from the provided .Va archive_entry object. The .Va flags argument modifies how the object is recreated. It consists of a bitwise OR of one or more of the following values: .Bl -tag -compact -width "indent" .It Cm ARCHIVE_EXTRACT_OWNER The user and group IDs should be set on the restored file. By default, the user and group IDs are not restored. .It Cm ARCHIVE_EXTRACT_PERM The permissions (mode bits) should be restored for all objects. By default, permissions are only restored for regular files. .It Cm ARCHIVE_EXTRACT_TIME The timestamps (mtime, ctime, and atime) should be restored. By default, they are ignored. Note that restoring of atime is not currently supported. .It Cm ARCHIVE_EXTRACT_NO_OVERWRITE Existing files on disk will not be overwritten. By default, existing regular files are truncated and overwritten; existing directories will have their permissions updated; other pre-existing objects are unlinked and recreated from scratch. .It Cm ARCHIVE_EXTRACT_UNLINK Existing files on disk will be unlinked and recreated from scratch. By default, existing files are truncated and rewritten, but the file is not recreated. In particular, the default behavior does not break existing hard links. .It Cm ARCHIVE_EXTRACT_ACL Attempt to restore ACLs. By default, extended ACLs are ignored. .It Cm ARCHIVE_EXTRACT_FFLAGS Attempt to restore extended file flags. By default, file flags are ignored. .El Note that not all attributes are set immediately; some attributes are cached in memory and written to disk only when the archive is closed. (For example, read-only directories are initially created writable so that files within those directories can be restored. The final permissions are set when the archive is closed.) .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. The progress function will be invoked during the extraction of large regular files. The progress function will be invoked with the pointer provided to this call. Generally, the data pointed to should include a reference to the archive object and the archive_entry object so that various statistics can be retrieved for the progress display. .It Fn archive_read_close Complete the archive and invoke the close callback. .It Fn archive_read_finish Invokes .Fn archive_read_close if it was not invoked manually, then release all resources. .El .Pp Note that the library determines most of the relevant information about the archive by inspection. In particular, it automatically detects .Xr gzip 1 or .Xr bzip2 1 compression and transparently performs the appropriate decompression. It also automatically detects the archive format. .Pp A complete description of the .Tn struct archive and .Tn struct archive_entry objects can be found in the overview manual page for .Xr libarchive 3 . .Sh CLIENT CALLBACKS The callback functions must match the following prototypes: .Bl -item -offset indent .It .Ft typedef ssize_t .Fn archive_read_callback "struct archive *" "void *client_data" "const void **buffer" .It .\" #if ARCHIVE_API_VERSION < 2 .Ft typedef int .Fn archive_skip_callback "struct archive *" "void *client_data" "size_t request" .\" #else .\" .Ft typedef off_t .\" .Fn archive_skip_callback "struct archive *" "void *client_data" "off_t request" .\" #endif .It .Ft typedef int .Fn archive_open_callback "struct archive *" "void *client_data" .It .Ft typedef int .Fn archive_close_callback "struct archive *" "void *client_data" .El .Pp The open callback is invoked by .Fn archive_open . It should return .Cm ARCHIVE_OK if the underlying file or data source is successfully opened. If the open fails, it should call .Fn archive_set_error to register an error code and message and return .Cm ARCHIVE_FATAL . .Pp The read callback is invoked whenever the library requires raw bytes from the archive. The read callback should read data into a buffer, set the .Li const void **buffer argument to point to the available data, and return a count of the number of bytes available. The library will invoke the read callback again only after it has consumed this data. The library imposes no constraints on the size of the data blocks returned. On end-of-file, the read callback should return zero. On error, the read callback should invoke .Fn archive_set_error to register an error code and message and return -1. .Pp The skip callback is invoked when the library wants to ignore a block of data. The return value is the number of bytes actually skipped, which may differ from the request. If the callback cannot skip data, it should return zero. If the skip callback is not provided (the function pointer is .Dv NULL ), the library will invoke the read function instead and simply discard the result. A skip callback can provide significant performance gains when reading uncompressed archives from slow disk drives or other media that can skip quickly. .Pp The close callback is invoked by archive_close when the archive processing is complete. The callback should return .Cm ARCHIVE_OK on success. On failure, the callback should invoke .Fn archive_set_error to register an error code and message and return .Cm ARCHIVE_FATAL. .Sh EXAMPLE The following illustrates basic usage of the library. In this example, the callback functions are simply wrappers around the standard .Xr open 2 , .Xr read 2 , and .Xr close 2 system calls. .Bd -literal -offset indent void list_archive(const char *name) { struct mydata *mydata; struct archive *a; struct archive_entry *entry; mydata = malloc(sizeof(struct mydata)); a = archive_read_new(); mydata->name = name; archive_read_support_compression_all(a); archive_read_support_format_all(a); archive_read_open(a, mydata, myopen, myread, myclose); while (archive_read_next_header(a, &entry) == ARCHIVE_OK) { printf("%s\\n",archive_entry_pathname(entry)); archive_read_data_skip(a); } archive_read_finish(a); free(mydata); } ssize_t myread(struct archive *a, void *client_data, const void **buff) { struct mydata *mydata = client_data; *buff = mydata->buff; return (read(mydata->fd, mydata->buff, 10240)); } int myopen(struct archive *a, void *client_data) { struct mydata *mydata = client_data; mydata->fd = open(mydata->name, O_RDONLY); return (mydata->fd >= 0 ? ARCHIVE_OK : ARCHIVE_FATAL); } int myclose(struct archive *a, void *client_data) { struct mydata *mydata = client_data; if (mydata->fd > 0) close(mydata->fd); return (ARCHIVE_OK); } .Ed .Sh RETURN VALUES Most functions return zero on success, non-zero on error. The possible return codes include: .Cm ARCHIVE_OK (the operation succeeded), .Cm ARCHIVE_WARN (the operation succeeded but a non-critical error was encountered), .Cm ARCHIVE_EOF (end-of-archive was encountered), .Cm ARCHIVE_RETRY (the operation failed but can be retried), and .Cm ARCHIVE_FATAL (there was a fatal error; the archive should be closed immediately). Detailed error codes and textual descriptions are available from the .Fn archive_errno and .Fn archive_error_string functions. .Pp .Fn archive_read_new returns a pointer to a freshly allocated .Tn struct archive object. It returns .Dv NULL on error. .Pp .Fn archive_read_data returns a count of bytes actually read or zero at the end of the entry. On error, a value of .Cm ARCHIVE_FATAL , .Cm ARCHIVE_WARN , or .Cm ARCHIVE_RETRY is returned and an error code and textual description can be retrieved from the .Fn archive_errno and .Fn archive_error_string functions. .Pp The library expects the client callbacks to behave similarly. If there is an error, you can use .Fn archive_set_error to set an appropriate error code and description, then return one of the non-zero values above. (Note that the value eventually returned to the client may not be the same; many errors that are not critical at the level of basic I/O can prevent the archive from being properly read, thus most I/O errors eventually cause .Cm ARCHIVE_FATAL to be returned.) .\" .Sh ERRORS .Sh SEE ALSO .Xr tar 1 , .Xr archive 3 , .Xr archive_util 3 , .Xr tar 5 .Sh HISTORY The .Nm libarchive library first appeared in .Fx 5.3 . .Sh AUTHORS .An -nosplit The .Nm libarchive library was written by .An Tim Kientzle Aq kientzle@acm.org . .Sh BUGS Directories are actually extracted in two distinct phases. Directories are created during .Fn archive_read_extract , but final permissions are not set until .Fn archive_read_close . This separation is necessary to correctly handle borderline cases such as a non-writable directory containing files, but can cause unexpected results. In particular, directory permissions are not fully restored until the archive is closed. If you use .Xr chdir 2 to change the current directory between calls to .Fn archive_read_extract or before calling .Fn archive_read_close , you may confuse the permission-setting logic with the result that directory permissions are restored incorrectly. +.Pp +Many traditional archiver programs treat +empty files as valid empty archives. +For example, many implementations of +.Xr tar 1 +allow you to append entries to an empty file. +Of course, it is impossible to determine the format of an empty file +by inspecting the contents, so this library treats empty files as +having a special +.Dq empty +format. Index: head/lib/libarchive/archive_read.c =================================================================== --- head/lib/libarchive/archive_read.c (revision 166386) +++ head/lib/libarchive/archive_read.c (revision 166387) @@ -1,647 +1,637 @@ /*- * 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. */ /* * This file contains the "essential" portions of the read API, that * is, stuff that will probably always be used by any client that * actually needs to read an archive. Optional pieces have been, as * far as possible, separated out into separate files to avoid * needlessly bloating statically-linked clients. */ #include "archive_platform.h" __FBSDID("$FreeBSD$"); #ifdef HAVE_ERRNO_H #include #endif #include #ifdef HAVE_STDLIB_H #include #endif #ifdef HAVE_STRING_H #include #endif #ifdef HAVE_UNISTD_H #include #endif #include "archive.h" #include "archive_entry.h" #include "archive_private.h" static int choose_decompressor(struct archive *, const void*, size_t); static int choose_format(struct archive *); /* * Allocate, initialize and return a struct archive object. */ struct archive * archive_read_new(void) { struct archive *a; unsigned char *nulls; a = (struct archive *)malloc(sizeof(*a)); if (a == NULL) { archive_set_error(a, ENOMEM, "Can't allocate archive object"); return (NULL); } memset(a, 0, sizeof(*a)); a->user_uid = geteuid(); a->magic = ARCHIVE_READ_MAGIC; a->bytes_per_block = ARCHIVE_DEFAULT_BYTES_PER_BLOCK; a->null_length = 1024; nulls = (unsigned char *)malloc(a->null_length); if (nulls == NULL) { archive_set_error(a, ENOMEM, "Can't allocate archive object 'nulls' element"); free(a); return (NULL); } memset(nulls, 0, a->null_length); a->nulls = nulls; a->state = ARCHIVE_STATE_NEW; a->entry = archive_entry_new(); /* We always support uncompressed archives. */ archive_read_support_compression_none((struct archive*)a); return (a); } /* * Record the do-not-extract-to file. This belongs in archive_read_extract.c. */ void archive_read_extract_set_skip_file(struct archive *a, dev_t d, ino_t i) { __archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_ANY, "archive_read_extract_set_skip_file"); a->skip_file_dev = d; a->skip_file_ino = i; } /* * Open the archive */ int archive_read_open(struct archive *a, void *client_data, archive_open_callback *client_opener, archive_read_callback *client_reader, archive_close_callback *client_closer) { /* Old archive_read_open() is just a thin shell around * archive_read_open2. */ return archive_read_open2(a, client_data, client_opener, client_reader, NULL, client_closer); } int archive_read_open2(struct archive *a, void *client_data, archive_open_callback *client_opener, archive_read_callback *client_reader, archive_skip_callback *client_skipper, archive_close_callback *client_closer) { const void *buffer; ssize_t bytes_read; int high_bidder; int e; __archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_open"); if (client_reader == NULL) __archive_errx(1, "No reader function provided to archive_read_open"); /* * Set these NULL initially. If the open or initial read fails, * we'll leave them NULL to indicate that the file is invalid. * (In particular, this helps ensure that the closer doesn't * get called more than once.) */ a->client_opener = NULL; a->client_reader = NULL; a->client_skipper = NULL; a->client_closer = NULL; a->client_data = NULL; /* Open data source. */ if (client_opener != NULL) { e =(client_opener)(a, client_data); if (e != 0) { /* If the open failed, call the closer to clean up. */ if (client_closer) (client_closer)(a, client_data); return (e); } } /* Read first block now for format detection. */ bytes_read = (client_reader)(a, client_data, &buffer); if (bytes_read < 0) { /* If the first read fails, close before returning error. */ if (client_closer) (client_closer)(a, client_data); /* client_reader should have already set error information. */ return (ARCHIVE_FATAL); } - /* An empty archive is a serious error. */ - if (bytes_read == 0) { - archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT, - "Empty input file"); - /* Close the empty file. */ - if (client_closer) - (client_closer)(a, client_data); - return (ARCHIVE_FATAL); - } - /* Now that the client callbacks have worked, remember them. */ a->client_opener = client_opener; /* Do we need to remember this? */ a->client_reader = client_reader; a->client_skipper = client_skipper; a->client_closer = client_closer; a->client_data = client_data; /* Select a decompression routine. */ high_bidder = choose_decompressor(a, buffer, bytes_read); if (high_bidder < 0) return (ARCHIVE_FATAL); /* Initialize decompression routine with the first block of data. */ e = (a->decompressors[high_bidder].init)(a, buffer, bytes_read); if (e == ARCHIVE_OK) a->state = ARCHIVE_STATE_HEADER; return (e); } /* * Allow each registered decompression routine to bid on whether it * wants to handle this stream. Return index of winning bidder. */ static int choose_decompressor(struct archive *a, const void *buffer, size_t bytes_read) { int decompression_slots, i, bid, best_bid, best_bid_slot; decompression_slots = sizeof(a->decompressors) / sizeof(a->decompressors[0]); best_bid = -1; best_bid_slot = -1; for (i = 0; i < decompression_slots; i++) { if (a->decompressors[i].bid) { bid = (a->decompressors[i].bid)(buffer, bytes_read); if ((bid > best_bid) || (best_bid_slot < 0)) { best_bid = bid; best_bid_slot = i; } } } /* * There were no bidders; this is a serious programmer error * and demands a quick and definitive abort. */ if (best_bid_slot < 0) __archive_errx(1, "No decompressors were registered; you " "must call at least one " "archive_read_support_compression_XXX function in order " "to successfully read an archive."); /* * There were bidders, but no non-zero bids; this means we can't * support this stream. */ if (best_bid < 1) { archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT, "Unrecognized archive format"); return (ARCHIVE_FATAL); } return (best_bid_slot); } /* * Read header of next entry. */ int archive_read_next_header(struct archive *a, struct archive_entry **entryp) { struct archive_entry *entry; int slot, ret; __archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, "archive_read_next_header"); *entryp = NULL; entry = a->entry; archive_entry_clear(entry); archive_string_empty(&a->error_string); /* * If client didn't consume entire data, skip any remainder * (This is especially important for GNU incremental directories.) */ if (a->state == ARCHIVE_STATE_DATA) { ret = archive_read_data_skip(a); if (ret == ARCHIVE_EOF) { archive_set_error(a, EIO, "Premature end-of-file."); a->state = ARCHIVE_STATE_FATAL; return (ARCHIVE_FATAL); } if (ret != ARCHIVE_OK) return (ret); } /* Record start-of-header. */ a->header_position = a->file_position; slot = choose_format(a); if (slot < 0) { a->state = ARCHIVE_STATE_FATAL; return (ARCHIVE_FATAL); } a->format = &(a->formats[slot]); a->pformat_data = &(a->format->format_data); ret = (a->format->read_header)(a, entry); /* * EOF and FATAL are persistent at this layer. By * modifying the state, we guarantee that future calls to * read a header or read data will fail. */ switch (ret) { case ARCHIVE_EOF: a->state = ARCHIVE_STATE_EOF; break; case ARCHIVE_OK: a->state = ARCHIVE_STATE_DATA; break; case ARCHIVE_WARN: a->state = ARCHIVE_STATE_DATA; break; case ARCHIVE_RETRY: break; case ARCHIVE_FATAL: a->state = ARCHIVE_STATE_FATAL; break; } *entryp = entry; a->read_data_output_offset = 0; a->read_data_remaining = 0; return (ret); } /* * Allow each registered format to bid on whether it wants to handle * the next entry. Return index of winning bidder. */ static int choose_format(struct archive *a) { int slots; int i; int bid, best_bid; int best_bid_slot; slots = sizeof(a->formats) / sizeof(a->formats[0]); best_bid = -1; best_bid_slot = -1; /* Set up a->format and a->pformat_data for convenience of bidders. */ a->format = &(a->formats[0]); for (i = 0; i < slots; i++, a->format++) { if (a->format->bid) { a->pformat_data = &(a->format->format_data); bid = (a->format->bid)(a); if (bid == ARCHIVE_FATAL) return (ARCHIVE_FATAL); if ((bid > best_bid) || (best_bid_slot < 0)) { best_bid = bid; best_bid_slot = i; } } } /* * There were no bidders; this is a serious programmer error * and demands a quick and definitive abort. */ if (best_bid_slot < 0) __archive_errx(1, "No formats were registered; you must " "invoke at least one archive_read_support_format_XXX " "function in order to successfully read an archive."); /* * There were bidders, but no non-zero bids; this means we * can't support this stream. */ if (best_bid < 1) { archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT, "Unrecognized archive format"); return (ARCHIVE_FATAL); } return (best_bid_slot); } /* * Return the file offset (within the uncompressed data stream) where * the last header started. */ int64_t archive_read_header_position(struct archive *a) { return (a->header_position); } /* * Read data from an archive entry, using a read(2)-style interface. * This is a convenience routine that just calls * archive_read_data_block and copies the results into the client * buffer, filling any gaps with zero bytes. Clients using this * API can be completely ignorant of sparse-file issues; sparse files * will simply be padded with nulls. * * DO NOT intermingle calls to this function and archive_read_data_block * to read a single entry body. */ ssize_t archive_read_data(struct archive *a, void *buff, size_t s) { char *dest; size_t bytes_read; size_t len; int r; bytes_read = 0; dest = (char *)buff; while (s > 0) { if (a->read_data_remaining <= 0) { r = archive_read_data_block(a, (const void **)&a->read_data_block, &a->read_data_remaining, &a->read_data_offset); if (r == ARCHIVE_EOF) return (bytes_read); /* * Error codes are all negative, so the status * return here cannot be confused with a valid * byte count. (ARCHIVE_OK is zero.) */ if (r < ARCHIVE_OK) return (r); } if (a->read_data_offset < a->read_data_output_offset) { archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT, "Encountered out-of-order sparse blocks"); return (ARCHIVE_RETRY); } /* Compute the amount of zero padding needed. */ if (a->read_data_output_offset + (off_t)s < a->read_data_offset) { len = s; } else if (a->read_data_output_offset < a->read_data_offset) { len = a->read_data_offset - a->read_data_output_offset; } else len = 0; /* Add zeroes. */ memset(dest, 0, len); s -= len; a->read_data_output_offset += len; dest += len; bytes_read += len; /* Copy data if there is any space left. */ if (s > 0) { len = a->read_data_remaining; if (len > s) len = s; memcpy(dest, a->read_data_block, len); s -= len; a->read_data_block += len; a->read_data_remaining -= len; a->read_data_output_offset += len; a->read_data_offset += len; dest += len; bytes_read += len; } } return (bytes_read); } /* * Skip over all remaining data in this entry. */ int archive_read_data_skip(struct archive *a) { int r; const void *buff; size_t size; off_t offset; __archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA, "archive_read_data_skip"); if (a->format->read_data_skip != NULL) r = (a->format->read_data_skip)(a); else { while ((r = archive_read_data_block(a, &buff, &size, &offset)) == ARCHIVE_OK) ; } if (r == ARCHIVE_EOF) r = ARCHIVE_OK; a->state = ARCHIVE_STATE_HEADER; return (r); } /* * Read the next block of entry data from the archive. * This is a zero-copy interface; the client receives a pointer, * size, and file offset of the next available block of data. * * Returns ARCHIVE_OK if the operation is successful, ARCHIVE_EOF if * the end of entry is encountered. */ int archive_read_data_block(struct archive *a, const void **buff, size_t *size, off_t *offset) { __archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_DATA, "archive_read_data_block"); if (a->format->read_data == NULL) { archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER, "Internal error: " "No format_read_data_block function registered"); return (ARCHIVE_FATAL); } return (a->format->read_data)(a, buff, size, offset); } /* * Close the file and release most resources. * * Be careful: client might just call read_new and then read_finish. * Don't assume we actually read anything or performed any non-trivial * initialization. */ int archive_read_close(struct archive *a) { int r = ARCHIVE_OK, r1 = ARCHIVE_OK; __archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_ANY, "archive_read_close"); a->state = ARCHIVE_STATE_CLOSED; /* Call cleanup functions registered by optional components. */ if (a->cleanup_archive_extract != NULL) r = (a->cleanup_archive_extract)(a); /* TODO: Finish the format processing. */ /* Close the input machinery. */ if (a->compression_finish != NULL) { r1 = (a->compression_finish)(a); if (r1 < r) r = r1; } return (r); } /* * Release memory and other resources. */ void archive_read_finish(struct archive *a) { int i; int slots; __archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_ANY, "archive_read_finish"); if (a->state != ARCHIVE_STATE_CLOSED) archive_read_close(a); /* Cleanup format-specific data. */ slots = sizeof(a->formats) / sizeof(a->formats[0]); for (i = 0; i < slots; i++) { a->pformat_data = &(a->formats[i].format_data); if (a->formats[i].cleanup) (a->formats[i].cleanup)(a); } /* Casting a pointer to int allows us to remove 'const.' */ free((void *)(uintptr_t)(const void *)a->nulls); archive_string_free(&a->error_string); if (a->entry) archive_entry_free(a->entry); a->magic = 0; free(a); } /* * Used internally by read format handlers to register their bid and * initialization functions. */ int __archive_read_register_format(struct archive *a, void *format_data, int (*bid)(struct archive *), int (*read_header)(struct archive *, struct archive_entry *), int (*read_data)(struct archive *, const void **, size_t *, off_t *), int (*read_data_skip)(struct archive *), int (*cleanup)(struct archive *)) { int i, number_slots; __archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "__archive_read_register_format"); number_slots = sizeof(a->formats) / sizeof(a->formats[0]); for (i = 0; i < number_slots; i++) { if (a->formats[i].bid == bid) return (ARCHIVE_WARN); /* We've already installed */ if (a->formats[i].bid == NULL) { a->formats[i].bid = bid; a->formats[i].read_header = read_header; a->formats[i].read_data = read_data; a->formats[i].read_data_skip = read_data_skip; a->formats[i].cleanup = cleanup; a->formats[i].format_data = format_data; return (ARCHIVE_OK); } } __archive_errx(1, "Not enough slots for format registration"); return (ARCHIVE_FATAL); /* Never actually called. */ } /* * Used internally by decompression routines to register their bid and * initialization functions. */ int __archive_read_register_compression(struct archive *a, int (*bid)(const void *, size_t), int (*init)(struct archive *, const void *, size_t)) { int i, number_slots; __archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "__archive_read_register_compression"); number_slots = sizeof(a->decompressors) / sizeof(a->decompressors[0]); for (i = 0; i < number_slots; i++) { if (a->decompressors[i].bid == bid) return (ARCHIVE_OK); /* We've already installed */ if (a->decompressors[i].bid == NULL) { a->decompressors[i].bid = bid; a->decompressors[i].init = init; return (ARCHIVE_OK); } } __archive_errx(1, "Not enough slots for compression registration"); return (ARCHIVE_FATAL); /* Never actually executed. */ } Index: head/lib/libarchive/archive_read_support_format_all.c =================================================================== --- head/lib/libarchive/archive_read_support_format_all.c (revision 166386) +++ head/lib/libarchive/archive_read_support_format_all.c (revision 166387) @@ -1,39 +1,40 @@ /*- * 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$"); #include "archive.h" int archive_read_support_format_all(struct archive *a) { archive_read_support_format_cpio(a); + archive_read_support_format_empty(a); archive_read_support_format_iso9660(a); archive_read_support_format_tar(a); archive_read_support_format_zip(a); return (ARCHIVE_OK); } Index: head/lib/libarchive/archive_read_support_format_empty.c =================================================================== --- head/lib/libarchive/archive_read_support_format_empty.c (nonexistent) +++ head/lib/libarchive/archive_read_support_format_empty.c (revision 166387) @@ -0,0 +1,90 @@ +/*- + * 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$"); + +#include "archive.h" +#include "archive_entry.h" +#include "archive_private.h" + +static int archive_read_format_empty_bid(struct archive *); +static int archive_read_format_empty_read_data(struct archive *, + const void **, size_t *, off_t *); +static int archive_read_format_empty_read_header(struct archive *, + struct archive_entry *); +int +archive_read_support_format_empty(struct archive *a) +{ + int r; + + r = __archive_read_register_format(a, + NULL, + archive_read_format_empty_bid, + archive_read_format_empty_read_header, + archive_read_format_empty_read_data, + NULL, + NULL); + + return (r); +} + + +static int +archive_read_format_empty_bid(struct archive *a) +{ + int bytes_read; + const void *h; + + bytes_read = (a->compression_read_ahead)(a, &h, 1); + if (bytes_read > 0) + return (-1); + return (1); +} + +static int +archive_read_format_empty_read_header(struct archive *a, + struct archive_entry *entry) +{ + (void)a; /* UNUSED */ + (void)entry; /* UNUSED */ + + a->archive_format = ARCHIVE_FORMAT_EMPTY; + a->archive_format_name = "Empty file"; + + return (ARCHIVE_EOF); +} + +static int +archive_read_format_empty_read_data(struct archive *a, + const void **buff, size_t *size, off_t *offset) +{ + (void)a; /* UNUSED */ + (void)buff; /* UNUSED */ + (void)size; /* UNUSED */ + (void)offset; /* UNUSED */ + + return (ARCHIVE_EOF); +} Property changes on: head/lib/libarchive/archive_read_support_format_empty.c ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property