summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorkientzle <kientzle@FreeBSD.org>2007-03-03 07:37:37 +0000
committerkientzle <kientzle@FreeBSD.org>2007-03-03 07:37:37 +0000
commit1a60578adb6be1f7da9ed95f38cf52c20be13591 (patch)
tree1b026213a337089af577dee3ed6d194ee1b87d88 /lib
parent56746aa8e0ffff51b371e72446368d6dbbe6b4ba (diff)
downloadFreeBSD-src-1a60578adb6be1f7da9ed95f38cf52c20be13591.zip
FreeBSD-src-1a60578adb6be1f7da9ed95f38cf52c20be13591.tar.gz
libarchive 2.0
* libarchive_test program exercises many of the core features * Refactored old "read_extract" into new "archive_write_disk", which uses archive_write methods to put entries onto disk. In particular, you can now use archive_write_disk to create objects on disk without having an archive available. * Pushed some security checks from bsdtar down into libarchive, where they can be better optimized. * Rearchitected the logic for creating objects on disk to reduce the number of system calls. Several common cases now use a minimum number of system calls. * Virtualized some internal interfaces to provide a clearer separation of read and write handling and make it simpler to override key methods. * New "empty" format reader. * Corrected return types (this ABI breakage required the "2.0" version bump) * Many bug fixes.
Diffstat (limited to 'lib')
-rw-r--r--lib/libarchive/Makefile18
-rw-r--r--lib/libarchive/README14
-rw-r--r--lib/libarchive/archive.h.in124
-rw-r--r--lib/libarchive/archive_entry.33
-rw-r--r--lib/libarchive/archive_private.h204
-rw-r--r--lib/libarchive/archive_read.397
-rw-r--r--lib/libarchive/archive_read.c168
-rw-r--r--lib/libarchive/archive_read_data_into_fd.c2
-rw-r--r--lib/libarchive/archive_read_extract.c1617
-rw-r--r--lib/libarchive/archive_read_private.h188
-rw-r--r--lib/libarchive/archive_read_support_compression_bzip2.c70
-rw-r--r--lib/libarchive/archive_read_support_compression_compress.c54
-rw-r--r--lib/libarchive/archive_read_support_compression_gzip.c74
-rw-r--r--lib/libarchive/archive_read_support_compression_none.c54
-rw-r--r--lib/libarchive/archive_read_support_format_cpio.c62
-rw-r--r--lib/libarchive/archive_read_support_format_empty.c20
-rw-r--r--lib/libarchive/archive_read_support_format_iso9660.c46
-rw-r--r--lib/libarchive/archive_read_support_format_tar.c151
-rw-r--r--lib/libarchive/archive_read_support_format_zip.c108
-rw-r--r--lib/libarchive/archive_util.36
-rw-r--r--lib/libarchive/archive_util.c6
-rw-r--r--lib/libarchive/archive_virtual.c81
-rw-r--r--lib/libarchive/archive_write.313
-rw-r--r--lib/libarchive/archive_write.c154
-rw-r--r--lib/libarchive/archive_write_disk.3358
-rw-r--r--lib/libarchive/archive_write_disk.c1929
-rw-r--r--lib/libarchive/archive_write_disk_private.h34
-rw-r--r--lib/libarchive/archive_write_disk_set_standard_lookup.c212
-rw-r--r--lib/libarchive/archive_write_private.h177
-rw-r--r--lib/libarchive/archive_write_set_compression_bzip2.c69
-rw-r--r--lib/libarchive/archive_write_set_compression_gzip.c74
-rw-r--r--lib/libarchive/archive_write_set_compression_none.c59
-rw-r--r--lib/libarchive/archive_write_set_format_cpio.c44
-rw-r--r--lib/libarchive/archive_write_set_format_pax.c62
-rw-r--r--lib/libarchive/archive_write_set_format_shar.c54
-rw-r--r--lib/libarchive/archive_write_set_format_ustar.c89
-rw-r--r--lib/libarchive/test/Makefile67
-rw-r--r--lib/libarchive/test/README46
-rw-r--r--lib/libarchive/test/main.c168
-rw-r--r--lib/libarchive/test/test.h89
-rw-r--r--lib/libarchive/test/test_archive_api_feature.c33
-rw-r--r--lib/libarchive/test/test_bad_fd.c41
-rw-r--r--lib/libarchive/test/test_read_data_large.c116
-rw-r--r--lib/libarchive/test/test_read_extract.c177
-rw-r--r--lib/libarchive/test/test_read_format_cpio_bin.c64
-rw-r--r--lib/libarchive/test/test_read_format_cpio_bin_Z.c53
-rw-r--r--lib/libarchive/test/test_read_format_cpio_bin_bz2.c54
-rw-r--r--lib/libarchive/test/test_read_format_cpio_bin_gz.c53
-rw-r--r--lib/libarchive/test/test_read_format_cpio_odc.c68
-rw-r--r--lib/libarchive/test/test_read_format_cpio_svr4_gzip.c54
-rw-r--r--lib/libarchive/test/test_read_format_cpio_svr4c_Z.c56
-rw-r--r--lib/libarchive/test/test_read_format_empty.c49
-rw-r--r--lib/libarchive/test/test_read_format_gtar_gz.c54
-rw-r--r--lib/libarchive/test/test_read_format_iso_gz.c73
-rw-r--r--lib/libarchive/test/test_read_format_isorr_bz2.c180
-rw-r--r--lib/libarchive/test/test_read_format_pax_bz2.c62
-rw-r--r--lib/libarchive/test/test_read_format_tar.c93
-rw-r--r--lib/libarchive/test/test_read_format_tbz.c55
-rw-r--r--lib/libarchive/test/test_read_format_tgz.c54
-rw-r--r--lib/libarchive/test/test_read_format_tz.c56
-rw-r--r--lib/libarchive/test/test_read_format_zip.c54
-rw-r--r--lib/libarchive/test/test_read_large.c93
-rw-r--r--lib/libarchive/test/test_read_position.c74
-rw-r--r--lib/libarchive/test/test_read_truncated.c148
-rw-r--r--lib/libarchive/test/test_write_disk.c92
-rw-r--r--lib/libarchive/test/test_write_disk_perms.c324
-rw-r--r--lib/libarchive/test/test_write_disk_secure.c140
-rw-r--r--lib/libarchive/test/test_write_format_cpio_empty.c76
-rw-r--r--lib/libarchive/test/test_write_format_shar_empty.c59
-rw-r--r--lib/libarchive/test/test_write_format_tar.c111
-rw-r--r--lib/libarchive/test/test_write_format_tar_empty.c84
-rw-r--r--lib/libarchive/test/test_write_open_memory.c75
72 files changed, 7206 insertions, 2434 deletions
diff --git a/lib/libarchive/Makefile b/lib/libarchive/Makefile
index 3c4170d..f5a37e9 100644
--- a/lib/libarchive/Makefile
+++ b/lib/libarchive/Makefile
@@ -9,14 +9,14 @@ LDADD= -lbz2 -lz
# 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
+VERSION= 2.0.20
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
+SHLIB_MAJOR= 4
CFLAGS+= -DPACKAGE_NAME=\"lib${LIB}\"
CFLAGS+= -DPACKAGE_VERSION=\"${VERSION}\"
@@ -67,7 +67,10 @@ SRCS= archive.h \
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 \
@@ -87,6 +90,7 @@ MAN= archive_entry.3 \
archive_read.3 \
archive_util.3 \
archive_write.3 \
+ archive_write_disk.3 \
libarchive.3 \
libarchive-formats.5 \
tar.5
@@ -173,6 +177,7 @@ 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
@@ -201,6 +206,15 @@ 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 <bsd.lib.mk>
diff --git a/lib/libarchive/README b/lib/libarchive/README
index 1380b4a..3157108 100644
--- a/lib/libarchive/README
+++ b/lib/libarchive/README
@@ -6,16 +6,16 @@ This is all under a BSD license. Use, enjoy, but don't blame me if it breaks!
Documentation:
* libarchive.3 gives an overview of the library as a whole
- * archive_read.3 and archive_write.3 provide detailed calling
- sequences for the read and write APIs
+ * archive_read.3, archive_write.3, and archive_write_disk.3 provide
+ detailed calling sequences for the read and write APIs
* archive_entry.3 details the "struct archive_entry" utility class
* libarchive-formats.5 documents the file formats supported by the library
* tar.5 provides some detailed information about a variety of different
"tar" formats.
You should also read the copious comments in "archive.h" and the source
-code for the sample "bsdtar" program for more details. Please let me know
-about any errors or omissions you find.
+code for the sample "bsdtar" and "minitar" programs for more details.
+Please let me know about any errors or omissions you find.
Currently, the library automatically detects and reads the following:
* gzip compression
@@ -84,8 +84,10 @@ Notes:
a block of data in memory and add it to a tar archive without
first writing a temporary file. You can also read an entry from
an archive and write the data directly to a socket. If you want
- to read/write entries to disk, there are convenience functions to
- make this especially easy.
+ to read/write entries to disk, the archive_write_disk interface
+ treats a directory as if it were an archive so you can copy
+ from archive->disk using the same code you use for archive->archive
+ transfers.
* Note: "pax interchange format" is really an extended tar format,
despite what the name says.
diff --git a/lib/libarchive/archive.h.in b/lib/libarchive/archive.h.in
index cdcc21f..6ba6e9e 100644
--- a/lib/libarchive/archive.h.in
+++ b/lib/libarchive/archive.h.in
@@ -37,7 +37,14 @@
#include <sys/types.h> /* Linux requires this for off_t */
@ARCHIVE_H_INCLUDE_INTTYPES_H@
#include <stdio.h> /* For FILE * */
+#ifndef _WIN32
#include <unistd.h> /* 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" {
@@ -59,6 +66,7 @@ extern "C" {
* 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);
@@ -138,8 +146,17 @@ typedef int archive_close_callback(struct archive *, void *_client_data);
* 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 0xff0000U
+#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)
@@ -274,15 +291,28 @@ int archive_read_data_into_fd(struct archive *, int fd);
*/
/* 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 */
+
+/* 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);
@@ -298,7 +328,13 @@ void archive_read_extract_set_skip_file(struct archive *,
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:
@@ -362,11 +398,76 @@ int archive_write_open_memory(struct archive *,
*/
int archive_write_header(struct archive *,
struct archive_entry *);
-/* TODO: should be ssize_t, but that might require .so version bump? */
+#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
@@ -383,6 +484,7 @@ 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
diff --git a/lib/libarchive/archive_entry.3 b/lib/libarchive/archive_entry.3
index 796bf2e..8205c11 100644
--- a/lib/libarchive/archive_entry.3
+++ b/lib/libarchive/archive_entry.3
@@ -46,6 +46,7 @@
.Nm archive_entry_copy_hardlink_w ,
.Nm archive_entry_copy_pathname_w ,
.Nm archive_entry_copy_stat ,
+.Nm archive_entry_copy_symlink ,
.Nm archive_entry_copy_symlink_w ,
.Nm archive_entry_copy_uname_w ,
.Nm archive_entry_dev ,
@@ -124,6 +125,8 @@
.Ft void
.Fn archive_entry_copy_stat "struct archive_entry *" "const struct stat *"
.Ft void
+.Fn archive_entry_copy_symlink "struct archive_entry *" "const char *"
+.Ft void
.Fn archive_entry_copy_symlink_w "struct archive_entry *" "const wchar_t *"
.Ft void
.Fn archive_entry_copy_uname_w "struct archive_entry *" "const wchar_t *"
diff --git a/lib/libarchive/archive_private.h b/lib/libarchive/archive_private.h
index 6e6867a..a6b7fd6 100644
--- a/lib/libarchive/archive_private.h
+++ b/lib/libarchive/archive_private.h
@@ -33,6 +33,28 @@
#define ARCHIVE_WRITE_MAGIC (0xb0c5c0deU)
#define ARCHIVE_READ_MAGIC (0xdeb0c5U)
+#define ARCHIVE_WRITE_DISK_MAGIC (0xc001b0c5U)
+
+#define ARCHIVE_STATE_ANY 0xFFFFU
+#define ARCHIVE_STATE_NEW 1U
+#define ARCHIVE_STATE_HEADER 2U
+#define ARCHIVE_STATE_DATA 4U
+#define ARCHIVE_STATE_DATA_END 8U
+#define ARCHIVE_STATE_EOF 0x10U
+#define ARCHIVE_STATE_CLOSED 0x20U
+#define ARCHIVE_STATE_FATAL 0x8000U
+
+struct archive_vtable {
+ int (*archive_write_close)(struct archive *);
+ int (*archive_write_finish)(struct archive *);
+ int (*archive_write_header)(struct archive *,
+ struct archive_entry *);
+ int (*archive_write_finish_entry)(struct archive *);
+ ssize_t (*archive_write_data)(struct archive *,
+ const void *, size_t);
+ ssize_t (*archive_write_data_block)(struct archive *,
+ const void *, size_t, off_t);
+};
struct archive {
/*
@@ -44,202 +66,34 @@ struct archive {
unsigned magic;
unsigned state;
- struct archive_entry *entry;
- uid_t user_uid; /* UID of current user. */
-
- /* Dev/ino of the archive being read/written. */
- dev_t skip_file_dev;
- ino_t skip_file_ino;
-
- /* Utility: Pointer to a block of nulls. */
- const unsigned char *nulls;
- size_t null_length;
-
/*
- * Used by archive_read_data() to track blocks and copy
- * data to client buffers, filling gaps with zero bytes.
+ * Some public API functions depend on the "real" type of the
+ * archive object.
*/
- const char *read_data_block;
- off_t read_data_offset;
- off_t read_data_output_offset;
- size_t read_data_remaining;
+ struct archive_vtable *vtable;
- /* Callbacks to open/read/write/close archive stream. */
- archive_open_callback *client_opener;
- archive_read_callback *client_reader;
- archive_skip_callback *client_skipper;
- archive_write_callback *client_writer;
- archive_close_callback *client_closer;
- void *client_data;
-
- /*
- * Blocking information. Note that bytes_in_last_block is
- * misleadingly named; I should find a better name. These
- * control the final output from all compressors, including
- * compression_none.
- */
- int bytes_per_block;
- int bytes_in_last_block;
+ int archive_format;
+ const char *archive_format_name;
- /*
- * These control whether data within a gzip/bzip2 compressed
- * stream gets padded or not. If pad_uncompressed is set,
- * the data will be padded to a full block before being
- * compressed. The pad_uncompressed_byte determines the value
- * that will be used for padding. Note that these have no
- * effect on compression "none."
- */
- int pad_uncompressed;
- int pad_uncompressed_byte; /* TODO: Support this. */
+ int compression_code; /* Currently active compression. */
+ const char *compression_name;
/* Position in UNCOMPRESSED data stream. */
off_t file_position;
/* Position in COMPRESSED data stream. */
off_t raw_position;
- /* File offset of beginning of most recently-read header. */
- off_t header_position;
-
- /*
- * Detection functions for decompression: bid functions are
- * given a block of data from the beginning of the stream and
- * can bid on whether or not they support the data stream.
- * General guideline: bid the number of bits that you actually
- * test, e.g., 16 if you test a 2-byte magic value. The
- * highest bidder will have their init function invoked, which
- * can set up pointers to specific handlers.
- *
- * On write, the client just invokes an archive_write_set function
- * which sets up the data here directly.
- */
- int compression_code; /* Currently active compression. */
- const char *compression_name;
- struct {
- int (*bid)(const void *buff, size_t);
- int (*init)(struct archive *, const void *buff, size_t);
- } decompressors[4];
- /* Read/write data stream (with compression). */
- void *compression_data; /* Data for (de)compressor. */
- int (*compression_init)(struct archive *); /* Initialize. */
- int (*compression_finish)(struct archive *);
- int (*compression_write)(struct archive *, const void *, size_t);
- /*
- * Read uses a peek/consume I/O model: the decompression code
- * returns a pointer to the requested block and advances the
- * file position only when requested by a consume call. This
- * reduces copying and also simplifies look-ahead for format
- * detection.
- */
- ssize_t (*compression_read_ahead)(struct archive *,
- const void **, size_t request);
- ssize_t (*compression_read_consume)(struct archive *, size_t);
- off_t (*compression_skip)(struct archive *, off_t);
-
- /*
- * Format detection is mostly the same as compression
- * detection, with two significant differences: The bidders
- * use the read_ahead calls above to examine the stream rather
- * than having the supervisor hand them a block of data to
- * examine, and the auction is repeated for every header.
- * Winning bidders should set the archive_format and
- * archive_format_name appropriately. Bid routines should
- * check archive_format and decline to bid if the format of
- * the last header was incompatible.
- *
- * Again, write support is considerably simpler because there's
- * no need for an auction.
- */
- int archive_format;
- const char *archive_format_name;
-
- struct archive_format_descriptor {
- 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 *);
- void *format_data; /* Format-specific data for readers. */
- } formats[8];
- struct archive_format_descriptor *format; /* Active format. */
-
- /*
- * Storage for format-specific data. Note that there can be
- * multiple format readers active at one time, so we need to
- * allow for multiple format readers to have their data
- * available. The pformat_data slot here is the solution: on
- * read, it is guaranteed to always point to a void* variable
- * that the format can use.
- */
- void **pformat_data; /* Pointer to current format_data. */
- void *format_data; /* Used by writers. */
-
- /*
- * Pointers to format-specific functions for writing. They're
- * initialized by archive_write_set_format_XXX() calls.
- */
- int (*format_init)(struct archive *); /* Only used on write. */
- int (*format_finish)(struct archive *);
- int (*format_finish_entry)(struct archive *);
- int (*format_write_header)(struct archive *,
- struct archive_entry *);
- ssize_t (*format_write_data)(struct archive *,
- const void *buff, size_t);
-
- /*
- * Various information needed by archive_extract.
- */
- struct extract *extract;
- void (*extract_progress)(void *);
- void *extract_progress_user_data;
- int (*cleanup_archive_extract)(struct archive *);
int archive_error_number;
const char *error;
struct archive_string error_string;
};
-
-#define ARCHIVE_STATE_ANY 0xFFFFU
-#define ARCHIVE_STATE_NEW 1U
-#define ARCHIVE_STATE_HEADER 2U
-#define ARCHIVE_STATE_DATA 4U
-#define ARCHIVE_STATE_EOF 8U
-#define ARCHIVE_STATE_CLOSED 0x10U
-#define ARCHIVE_STATE_FATAL 0x8000U
-
/* Check magic value and state; exit if it isn't valid. */
void __archive_check_magic(struct archive *, unsigned magic,
unsigned state, const char *func);
-
-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 __archive_read_register_compression(struct archive *a,
- int (*bid)(const void *, size_t),
- int (*init)(struct archive *, const void *, size_t));
-
void __archive_errx(int retvalue, const char *msg);
#define err_combine(a,b) ((a) < (b) ? (a) : (b))
-
-/*
- * Utility function to format a USTAR header into a buffer. If
- * "strict" is set, this tries to create the absolutely most portable
- * version of a ustar header. If "strict" is set to 0, then it will
- * relax certain requirements.
- *
- * Generally, format-specific declarations don't belong in this
- * header; this is a rare example of a function that is shared by
- * two very similar formats (ustar and pax).
- */
-int
-__archive_write_format_header_ustar(struct archive *, char buff[512],
- struct archive_entry *, int tartype, int strict);
-
#endif
diff --git a/lib/libarchive/archive_read.3 b/lib/libarchive/archive_read.3
index f968238..46be4d4 100644
--- a/lib/libarchive/archive_read.3
+++ b/lib/libarchive/archive_read.3
@@ -113,7 +113,7 @@
.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
+.Ft int
.Fn archive_read_finish "struct archive *"
.Sh DESCRIPTION
These functions provide a complete API for reading streaming archives.
@@ -148,7 +148,7 @@ 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.
+Only empty archives are supported by default.
.It Fn archive_read_open
The same as
.Fn archive_read_open2 ,
@@ -233,58 +233,27 @@ Note that the client is responsible for sizing the buffer appropriately.
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
+.It Fn archive_read_extract , Fn archive_read_extract_set_skip_file
+A convenience function that wraps the corresponding
+.Xr archive_write_disk 3
+interfaces.
+The first call to
.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.
+creates a restore object using
+.Xr archive_write_disk_new 3
+and
+.Xr archive_write_disk_set_standard_lookup 3 ,
+then transparently invokes
+.Xr archive_write_disk_set_options 3 ,
+.Xr archive_write_header 3 ,
+.Xr archive_write_data 3 ,
+and
+.Xr archive_write_finish_entry 3
+to create the entry on disk and copy data into it.
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.)
+argument is passed unmodified to
+.Xr archiv_write_disk_set_options 3 .
.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.
@@ -300,6 +269,12 @@ Complete the archive and invoke the close callback.
Invokes
.Fn archive_read_close
if it was not invoked manually, then release all resources.
+Note: In libarchive 1.x, this function was declared to return
+.Ft void ,
+which made it impossible to detect certain errors when
+.Fn archive_read_close
+was invoked implicitly from this function.
+The declaration is corrected beginning with libarchive 2.0.
.El
.Pp
Note that the library determines most of the relevant information about
@@ -523,26 +498,6 @@ The
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
diff --git a/lib/libarchive/archive_read.c b/lib/libarchive/archive_read.c
index 8574483..c92b20c 100644
--- a/lib/libarchive/archive_read.c
+++ b/lib/libarchive/archive_read.c
@@ -51,9 +51,10 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_entry.h"
#include "archive_private.h"
+#include "archive_read_private.h"
-static int choose_decompressor(struct archive *, const void*, size_t);
-static int choose_format(struct archive *);
+static int choose_decompressor(struct archive_read *, const void*, size_t);
+static int choose_format(struct archive_read *);
/*
* Allocate, initialize and return a struct archive object.
@@ -61,44 +62,45 @@ static int choose_format(struct archive *);
struct archive *
archive_read_new(void)
{
- struct archive *a;
+ struct archive_read *a;
unsigned char *nulls;
- a = (struct archive *)malloc(sizeof(*a));
+ a = (struct archive_read *)malloc(sizeof(*a));
if (a == NULL)
return (NULL);
memset(a, 0, sizeof(*a));
-
- a->user_uid = geteuid();
- a->magic = ARCHIVE_READ_MAGIC;
+ a->archive.magic = ARCHIVE_READ_MAGIC;
a->bytes_per_block = ARCHIVE_DEFAULT_BYTES_PER_BLOCK;
a->null_length = 1024;
nulls = (unsigned char *)malloc(a->null_length);
if (nulls == NULL) {
- archive_set_error(a, ENOMEM, "Can't allocate archive object 'nulls' element");
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate archive object 'nulls' element");
free(a);
return (NULL);
}
memset(nulls, 0, a->null_length);
a->nulls = nulls;
- a->state = ARCHIVE_STATE_NEW;
+ a->archive.state = ARCHIVE_STATE_NEW;
a->entry = archive_entry_new();
/* We always support uncompressed archives. */
- archive_read_support_compression_none((struct archive*)a);
+ archive_read_support_compression_none(&a->archive);
- return (a);
+ return (&a->archive);
}
/*
* 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_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");
+ struct archive_read *a = (struct archive_read *)_a;
+ __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;
}
@@ -119,18 +121,19 @@ archive_read_open(struct archive *a, void *client_data,
}
int
-archive_read_open2(struct archive *a, void *client_data,
+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)
{
+ struct archive_read *a = (struct archive_read *)_a;
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");
+ __archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "archive_read_open");
if (client_reader == NULL)
__archive_errx(1,
@@ -150,22 +153,22 @@ archive_read_open2(struct archive *a, void *client_data,
/* Open data source. */
if (client_opener != NULL) {
- e =(client_opener)(a, client_data);
+ e =(client_opener)(&a->archive, client_data);
if (e != 0) {
/* If the open failed, call the closer to clean up. */
if (client_closer)
- (client_closer)(a, client_data);
+ (client_closer)(&a->archive, client_data);
return (e);
}
}
/* Read first block now for format detection. */
- bytes_read = (client_reader)(a, client_data, &buffer);
+ bytes_read = (client_reader)(&a->archive, 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_closer)(&a->archive, client_data);
/* client_reader should have already set error information. */
return (ARCHIVE_FATAL);
}
@@ -186,7 +189,7 @@ archive_read_open2(struct archive *a, void *client_data,
e = (a->decompressors[high_bidder].init)(a, buffer, bytes_read);
if (e == ARCHIVE_OK)
- a->state = ARCHIVE_STATE_HEADER;
+ a->archive.state = ARCHIVE_STATE_HEADER;
return (e);
}
@@ -196,7 +199,8 @@ archive_read_open2(struct archive *a, void *client_data,
* wants to handle this stream. Return index of winning bidder.
*/
static int
-choose_decompressor(struct archive *a, const void *buffer, size_t bytes_read)
+choose_decompressor(struct archive_read *a,
+ const void *buffer, size_t bytes_read)
{
int decompression_slots, i, bid, best_bid, best_bid_slot;
@@ -231,7 +235,7 @@ choose_decompressor(struct archive *a, const void *buffer, size_t bytes_read)
* support this stream.
*/
if (best_bid < 1) {
- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Unrecognized archive format");
return (ARCHIVE_FATAL);
}
@@ -243,28 +247,30 @@ choose_decompressor(struct archive *a, const void *buffer, size_t bytes_read)
* Read header of next entry.
*/
int
-archive_read_next_header(struct archive *a, struct archive_entry **entryp)
+archive_read_next_header(struct archive *_a, struct archive_entry **entryp)
{
+ struct archive_read *a = (struct archive_read *)_a;
struct archive_entry *entry;
int slot, ret;
- __archive_check_magic(a, ARCHIVE_READ_MAGIC,
- ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA, "archive_read_next_header");
+ __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);
+ archive_clear_error(&a->archive);
/*
* 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 (a->archive.state == ARCHIVE_STATE_DATA) {
+ ret = archive_read_data_skip(&a->archive);
if (ret == ARCHIVE_EOF) {
- archive_set_error(a, EIO, "Premature end-of-file.");
- a->state = ARCHIVE_STATE_FATAL;
+ archive_set_error(&a->archive, EIO, "Premature end-of-file.");
+ a->archive.state = ARCHIVE_STATE_FATAL;
return (ARCHIVE_FATAL);
}
if (ret != ARCHIVE_OK)
@@ -272,11 +278,11 @@ archive_read_next_header(struct archive *a, struct archive_entry **entryp)
}
/* Record start-of-header. */
- a->header_position = a->file_position;
+ a->header_position = a->archive.file_position;
slot = choose_format(a);
if (slot < 0) {
- a->state = ARCHIVE_STATE_FATAL;
+ a->archive.state = ARCHIVE_STATE_FATAL;
return (ARCHIVE_FATAL);
}
a->format = &(a->formats[slot]);
@@ -290,18 +296,18 @@ archive_read_next_header(struct archive *a, struct archive_entry **entryp)
*/
switch (ret) {
case ARCHIVE_EOF:
- a->state = ARCHIVE_STATE_EOF;
+ a->archive.state = ARCHIVE_STATE_EOF;
break;
case ARCHIVE_OK:
- a->state = ARCHIVE_STATE_DATA;
+ a->archive.state = ARCHIVE_STATE_DATA;
break;
case ARCHIVE_WARN:
- a->state = ARCHIVE_STATE_DATA;
+ a->archive.state = ARCHIVE_STATE_DATA;
break;
case ARCHIVE_RETRY:
break;
case ARCHIVE_FATAL:
- a->state = ARCHIVE_STATE_FATAL;
+ a->archive.state = ARCHIVE_STATE_FATAL;
break;
}
@@ -316,7 +322,7 @@ archive_read_next_header(struct archive *a, struct archive_entry **entryp)
* the next entry. Return index of winning bidder.
*/
static int
-choose_format(struct archive *a)
+choose_format(struct archive_read *a)
{
int slots;
int i;
@@ -356,7 +362,7 @@ choose_format(struct archive *a)
* can't support this stream.
*/
if (best_bid < 1) {
- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Unrecognized archive format");
return (ARCHIVE_FATAL);
}
@@ -369,8 +375,11 @@ choose_format(struct archive *a)
* the last header started.
*/
int64_t
-archive_read_header_position(struct archive *a)
+archive_read_header_position(struct archive *_a)
{
+ struct archive_read *a = (struct archive_read *)_a;
+ __archive_check_magic(_a, ARCHIVE_READ_MAGIC,
+ ARCHIVE_STATE_ANY, "archive_read_header_position");
return (a->header_position);
}
@@ -386,8 +395,9 @@ archive_read_header_position(struct archive *a)
* to read a single entry body.
*/
ssize_t
-archive_read_data(struct archive *a, void *buff, size_t s)
+archive_read_data(struct archive *_a, void *buff, size_t s)
{
+ struct archive_read *a = (struct archive_read *)_a;
char *dest;
size_t bytes_read;
size_t len;
@@ -398,7 +408,7 @@ archive_read_data(struct archive *a, void *buff, size_t s)
while (s > 0) {
if (a->read_data_remaining <= 0) {
- r = archive_read_data_block(a,
+ r = archive_read_data_block(&a->archive,
(const void **)&a->read_data_block,
&a->read_data_remaining,
&a->read_data_offset);
@@ -414,7 +424,7 @@ archive_read_data(struct archive *a, void *buff, size_t s)
}
if (a->read_data_offset < a->read_data_output_offset) {
- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Encountered out-of-order sparse blocks");
return (ARCHIVE_RETRY);
}
@@ -459,19 +469,22 @@ archive_read_data(struct archive *a, void *buff, size_t s)
* Skip over all remaining data in this entry.
*/
int
-archive_read_data_skip(struct archive *a)
+archive_read_data_skip(struct archive *_a)
{
+ struct archive_read *a = (struct archive_read *)_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");
+ __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))
+ while ((r = archive_read_data_block(&a->archive,
+ &buff, &size, &offset))
== ARCHIVE_OK)
;
}
@@ -479,7 +492,7 @@ archive_read_data_skip(struct archive *a)
if (r == ARCHIVE_EOF)
r = ARCHIVE_OK;
- a->state = ARCHIVE_STATE_HEADER;
+ a->archive.state = ARCHIVE_STATE_HEADER;
return (r);
}
@@ -492,13 +505,15 @@ archive_read_data_skip(struct archive *a)
* the end of entry is encountered.
*/
int
-archive_read_data_block(struct archive *a,
+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");
+ struct archive_read *a = (struct archive_read *)_a;
+ __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,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"Internal error: "
"No format_read_data_block function registered");
return (ARCHIVE_FATAL);
@@ -515,12 +530,14 @@ archive_read_data_block(struct archive *a,
* initialization.
*/
int
-archive_read_close(struct archive *a)
+archive_read_close(struct archive *_a)
{
+ struct archive_read *a = (struct archive_read *)_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;
+ __archive_check_magic(&a->archive, ARCHIVE_READ_MAGIC,
+ ARCHIVE_STATE_ANY, "archive_read_close");
+ a->archive.state = ARCHIVE_STATE_CLOSED;
/* Call cleanup functions registered by optional components. */
if (a->cleanup_archive_extract != NULL)
@@ -541,15 +558,23 @@ archive_read_close(struct archive *a)
/*
* Release memory and other resources.
*/
+#if ARCHIVE_API_VERSION > 1
+int
+#else
+/* Temporarily allow library to compile with either 1.x or 2.0 API. */
void
-archive_read_finish(struct archive *a)
+#endif
+archive_read_finish(struct archive *_a)
{
+ struct archive_read *a = (struct archive_read *)_a;
int i;
int slots;
+ int r = ARCHIVE_OK;
- __archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_ANY, "archive_read_finish");
- if (a->state != ARCHIVE_STATE_CLOSED)
- archive_read_close(a);
+ __archive_check_magic(_a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_ANY,
+ "archive_read_finish");
+ if (a->archive.state != ARCHIVE_STATE_CLOSED)
+ r = archive_read_close(&a->archive);
/* Cleanup format-specific data. */
slots = sizeof(a->formats) / sizeof(a->formats[0]);
@@ -561,11 +586,14 @@ archive_read_finish(struct archive *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);
+ archive_string_free(&a->archive.error_string);
if (a->entry)
archive_entry_free(a->entry);
- a->magic = 0;
+ a->archive.magic = 0;
free(a);
+#if ARCHIVE_API_VERSION > 1
+ return (r);
+#endif
}
/*
@@ -573,17 +601,19 @@ archive_read_finish(struct archive *a)
* initialization functions.
*/
int
-__archive_read_register_format(struct archive *a,
+__archive_read_register_format(struct archive_read *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 (*bid)(struct archive_read *),
+ int (*read_header)(struct archive_read *, struct archive_entry *),
+ int (*read_data)(struct archive_read *, const void **, size_t *, off_t *),
+ int (*read_data_skip)(struct archive_read *),
+ int (*cleanup)(struct archive_read *))
{
int i, number_slots;
- __archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "__archive_read_register_format");
+ __archive_check_magic(&a->archive,
+ ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
+ "__archive_read_register_format");
number_slots = sizeof(a->formats) / sizeof(a->formats[0]);
@@ -610,13 +640,15 @@ __archive_read_register_format(struct archive *a,
* initialization functions.
*/
int
-__archive_read_register_compression(struct archive *a,
+__archive_read_register_compression(struct archive_read *a,
int (*bid)(const void *, size_t),
- int (*init)(struct archive *, const void *, size_t))
+ int (*init)(struct archive_read *, const void *, size_t))
{
int i, number_slots;
- __archive_check_magic(a, ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW, "__archive_read_register_compression");
+ __archive_check_magic(&a->archive,
+ ARCHIVE_READ_MAGIC, ARCHIVE_STATE_NEW,
+ "__archive_read_register_compression");
number_slots = sizeof(a->decompressors) / sizeof(a->decompressors[0]);
diff --git a/lib/libarchive/archive_read_data_into_fd.c b/lib/libarchive/archive_read_data_into_fd.c
index 4b4669e..028baf6 100644
--- a/lib/libarchive/archive_read_data_into_fd.c
+++ b/lib/libarchive/archive_read_data_into_fd.c
@@ -80,8 +80,6 @@ archive_read_data_into_fd(struct archive *a, int fd)
total_written += bytes_written;
p += bytes_written;
size -= bytes_written;
- if (a->extract_progress != NULL)
- (*a->extract_progress)(a->extract_progress_user_data);
}
}
diff --git a/lib/libarchive/archive_read_extract.c b/lib/libarchive/archive_read_extract.c
index ef2e2b5..29586da 100644
--- a/lib/libarchive/archive_read_extract.c
+++ b/lib/libarchive/archive_read_extract.c
@@ -78,1590 +78,125 @@ __FBSDID("$FreeBSD$");
#endif
#include "archive.h"
-#include "archive_string.h"
-#include "archive_entry.h"
#include "archive_private.h"
-
-struct fixup_entry {
- struct fixup_entry *next;
- mode_t mode;
- int64_t mtime;
- int64_t atime;
- unsigned long mtime_nanos;
- unsigned long atime_nanos;
- unsigned long fflags_set;
- int fixup; /* bitmask of what needs fixing */
- char *name;
-};
-
-#define FIXUP_MODE 1
-#define FIXUP_TIMES 2
-#define FIXUP_FFLAGS 4
-
-struct bucket {
- char *name;
- int hash;
- id_t id;
-};
+#include "archive_read_private.h"
+#include "archive_write_disk_private.h"
struct extract {
- mode_t umask;
- mode_t default_dir_mode_initial;
- mode_t default_dir_mode_final;
- struct archive_string create_parent_dir;
- struct fixup_entry *fixup_list;
- struct fixup_entry *current_fixup;
-
- struct bucket ucache[127];
- struct bucket gcache[127];
+ struct archive *ad; /* archive_write_disk object */
- /*
- * Cached stat data from disk for the current entry.
- * If this is valid, pst points to st. Otherwise,
- * pst is null.
- */
- struct stat st;
- struct stat *pst;
+ /* Progress function invoked during extract. */
+ void (*extract_progress)(void *);
+ void *extract_progress_user_data;
};
-/* Default mode for dirs created automatically (will be modified by umask). */
-#define DEFAULT_DIR_MODE 0777
-/*
- * Mode to use for newly-created dirs during extraction; the correct
- * mode will be set at the end of the extraction.
- */
-#define MINIMUM_DIR_MODE 0700
-#define MAXIMUM_DIR_MODE 0775
-
-static int archive_extract_cleanup(struct archive *);
-static int create_extract(struct archive *a);
-static int extract_block_device(struct archive *,
- struct archive_entry *, int);
-static int extract_char_device(struct archive *,
- struct archive_entry *, int);
-static int extract_device(struct archive *,
- struct archive_entry *, int flags, mode_t mode);
-static int extract_dir(struct archive *, struct archive_entry *, int);
-static int extract_fifo(struct archive *, struct archive_entry *, int);
-static int extract_file(struct archive *, struct archive_entry *, int);
-static int extract_hard_link(struct archive *, struct archive_entry *, int);
-static int extract_symlink(struct archive *, struct archive_entry *, int);
-static unsigned int hash(const char *);
-static gid_t lookup_gid(struct archive *, const char *uname, gid_t);
-static uid_t lookup_uid(struct archive *, const char *uname, uid_t);
-static int create_dir(struct archive *, const char *, int flags);
-static int create_dir_mutable(struct archive *, char *, int flags);
-static int create_dir_recursive(struct archive *, char *, int flags);
-static int create_parent_dir(struct archive *, const char *, int flags);
-static int create_parent_dir_mutable(struct archive *, char *, int flags);
-static int restore_metadata(struct archive *, int fd,
- struct archive_entry *, int flags);
-#ifdef HAVE_POSIX_ACL
-static int set_acl(struct archive *, int fd, struct archive_entry *,
- acl_type_t, int archive_entry_acl_type, const char *tn);
-#endif
-static int set_acls(struct archive *, int fd, struct archive_entry *);
-static int set_xattrs(struct archive *, int fd, struct archive_entry *);
-static int set_fflags(struct archive *, int fd, const char *name, mode_t,
- unsigned long fflags_set, unsigned long fflags_clear);
-static int set_ownership(struct archive *, int fd, struct archive_entry *,
- int flags);
-static int set_perm(struct archive *, int fd, struct archive_entry *,
- int mode, int flags);
-static int set_time(struct archive *, int fd, struct archive_entry *, int);
-static struct fixup_entry *sort_dir_list(struct fixup_entry *p);
-
+static int archive_read_extract_cleanup(struct archive_read *);
+static int copy_data(struct archive *ar, struct archive *aw);
+static struct extract *get_extract(struct archive_read *);
-/*
- * Extract this entry to disk.
- *
- * TODO: Validate hardlinks. According to the standards, we're
- * supposed to check each extracted hardlink and squawk if it refers
- * to a file that we didn't restore. I'm not entirely convinced this
- * is a good idea, but more importantly: Is there any way to validate
- * hardlinks without keeping a complete list of filenames from the
- * entire archive?? Ugh.
- *
- */
-int
-archive_read_extract(struct archive *a, struct archive_entry *entry, int flags)
+static struct extract *
+get_extract(struct archive_read *a)
{
- mode_t mode;
- struct extract *extract;
- int ret;
- int restore_pwd;
- char *original_filename;
-
+ /* If we haven't initialized, do it now. */
+ /* This also sets up a lot of global state. */
if (a->extract == NULL) {
- ret = create_extract(a);
- if (ret)
- return (ret);
- }
- extract = a->extract;
- extract->pst = NULL;
- extract->current_fixup = NULL;
- restore_pwd = -1;
- original_filename = NULL;
-
- /* The following is not possible without fchdir. <sigh> */
-#ifdef HAVE_FCHDIR
- /*
- * If pathname is longer than PATH_MAX, record starting directory
- * and chdir to a suitable intermediate dir.
- */
- if (strlen(archive_entry_pathname(entry)) > PATH_MAX) {
- char *intdir, *tail;
-
- restore_pwd = open(".", O_RDONLY);
- if (restore_pwd < 0) {
- archive_set_error(a, errno,
- "Unable to restore long pathname");
- return (ARCHIVE_WARN);
+ a->extract = (struct extract *)malloc(sizeof(*a->extract));
+ if (a->extract == NULL) {
+ archive_set_error(&a->archive, ENOMEM, "Can't extract");
+ return (NULL);
}
-
- /*
- * Yes, the copy here is necessary because we edit
- * the pathname in-place to create intermediate dirnames.
- */
- original_filename = strdup(archive_entry_pathname(entry));
-
- /*
- * "intdir" points to the initial dir section we're going
- * to remove, "tail" points to the remainder of the path.
- */
- intdir = tail = original_filename;
- while (strlen(tail) > PATH_MAX) {
- intdir = tail;
-
- /* Locate a dir prefix shorter than PATH_MAX. */
- tail = intdir + PATH_MAX - 8;
- while (tail > intdir && *tail != '/')
- tail--;
- if (tail <= intdir) {
- archive_set_error(a, EPERM,
- "Path element too long");
- ret = ARCHIVE_WARN;
- goto cleanup;
- }
-
- /* Create intdir and chdir to it. */
- *tail = '\0'; /* Terminate dir portion */
- ret = create_dir(a, intdir, flags);
- if (ret == ARCHIVE_OK && chdir(intdir) != 0) {
- archive_set_error(a, errno, "Couldn't chdir");
- ret = ARCHIVE_WARN;
- }
- *tail = '/'; /* Restore the / we removed. */
- if (ret != ARCHIVE_OK)
- goto cleanup;
- tail++;
- }
- archive_entry_set_pathname(entry, tail);
- }
-#endif
-
- if (stat(archive_entry_pathname(entry), &extract->st) == 0)
- extract->pst = &extract->st;
- extract->umask = umask(0); /* Set the umask to zero, record old one. */
-
- if (extract->pst != NULL &&
- extract->pst->st_dev == a->skip_file_dev &&
- extract->pst->st_ino == a->skip_file_ino) {
- archive_set_error(a, 0, "Refusing to overwrite archive");
- ret = ARCHIVE_WARN;
- } else if (archive_entry_hardlink(entry) != NULL)
- ret = extract_hard_link(a, entry, flags);
- else {
- mode = archive_entry_mode(entry);
- switch (mode & S_IFMT) {
- default:
- /* Fall through, as required by POSIX. */
- case S_IFREG:
- ret = extract_file(a, entry, flags);
- break;
- case S_IFLNK: /* Symlink */
- ret = extract_symlink(a, entry, flags);
- break;
- case S_IFCHR:
- ret = extract_char_device(a, entry, flags);
- break;
- case S_IFBLK:
- ret = extract_block_device(a, entry, flags);
- break;
- case S_IFDIR:
- ret = extract_dir(a, entry, flags);
- break;
- case S_IFIFO:
- ret = extract_fifo(a, entry, flags);
- break;
+ a->extract->ad = archive_write_disk_new();
+ if (a->extract->ad == NULL) {
+ archive_set_error(&a->archive, ENOMEM, "Can't extract");
+ return (NULL);
}
+ archive_write_disk_set_standard_lookup(a->extract->ad);
+ a->cleanup_archive_extract = archive_read_extract_cleanup;
}
- umask(extract->umask); /* Restore umask. */
-
-cleanup:
-#ifdef HAVE_FCHDIR
- /* If we changed directory above, restore it here. */
- if (restore_pwd >= 0 && original_filename != NULL) {
- fchdir(restore_pwd);
- close(restore_pwd);
- archive_entry_copy_pathname(entry, original_filename);
- free(original_filename);
- }
-#endif
-
- return (ret);
+ return (a->extract);
}
-
-static int
-create_extract(struct archive *a)
+int
+archive_read_extract(struct archive *_a, struct archive_entry *entry, int flags)
{
+ struct archive_read *a = (struct archive_read *)_a;
struct extract *extract;
+ int r, r2;
- extract = (struct extract *)malloc(sizeof(*extract));
- if (extract == NULL) {
- archive_set_error(a, ENOMEM, "Can't extract");
+ extract = get_extract(a);
+ if (extract == NULL)
return (ARCHIVE_FATAL);
- }
- a->cleanup_archive_extract = archive_extract_cleanup;
- memset(extract, 0, sizeof(*extract));
- umask(extract->umask = umask(0)); /* Read the current umask. */
- /* Final permission for default dirs. */
- extract->default_dir_mode_final
- = DEFAULT_DIR_MODE & ~extract->umask;
- /* Temporary permission for default dirs during extract. */
- extract->default_dir_mode_initial
- = extract->default_dir_mode_final;
- extract->default_dir_mode_initial |= MINIMUM_DIR_MODE;
- extract->default_dir_mode_initial &= MAXIMUM_DIR_MODE;
- /* If the two permissions above are different, then
- * the "final" permissions will be applied in the
- * post-extract fixup pass. */
- a->extract = extract;
- return (ARCHIVE_OK);
-}
-
-/*
- * Cleanup function for archive_extract. Mostly, this involves processing
- * the fixup list, which is used to address a number of problems:
- * * Dir permissions might prevent us from restoring a file in that
- * dir, so we restore the dir 0700 first, then correct the
- * mode at the end.
- * * Similarly, the act of restoring a file touches the directory
- * and changes the timestamp on the dir, so we have to touch-up dir
- * timestamps at the end as well.
- * * Some file flags can interfere with the restore by, for example,
- * preventing the creation of hardlinks to those files.
- *
- * Note that tar/cpio do not require that archives be in a particular
- * order; there is no way to know when the last file has been restored
- * within a directory, so there's no way to optimize the memory usage
- * here by fixing up the directory any earlier than the
- * end-of-archive.
- *
- * XXX TODO: Directory ACLs should be restored here, for the same
- * reason we set directory perms here. XXX
- *
- * Registering this function (rather than calling it explicitly by
- * name from archive_read_finish) reduces static link pollution, since
- * applications that don't use this API won't get this file linked in.
- */
-static int
-archive_extract_cleanup(struct archive *a)
-{
- struct fixup_entry *next, *p;
- struct extract *extract;
-
- /* Sort dir list so directories are fixed up in depth-first order. */
- extract = a->extract;
- p = sort_dir_list(extract->fixup_list);
-
- while (p != NULL) {
- extract->pst = NULL; /* Mark stat cache as out-of-date. */
- if (p->fixup & FIXUP_TIMES) {
- struct timeval times[2];
- times[1].tv_sec = p->mtime;
- times[1].tv_usec = p->mtime_nanos / 1000;
- times[0].tv_sec = p->atime;
- times[0].tv_usec = p->atime_nanos / 1000;
- utimes(p->name, times);
- }
- if (p->fixup & FIXUP_MODE)
- chmod(p->name, p->mode);
-
- if (p->fixup & FIXUP_FFLAGS)
- set_fflags(a, -1, p->name, p->mode, p->fflags_set, 0);
-
- next = p->next;
- free(p->name);
- free(p);
- p = next;
- }
- extract->fixup_list = NULL;
- archive_string_free(&extract->create_parent_dir);
- free(a->extract);
- a->extract = NULL;
- return (ARCHIVE_OK);
-}
-
-/*
- * Simple O(n log n) merge sort to order the fixup list. In
- * particular, we want to restore dir timestamps depth-first.
- */
-static struct fixup_entry *
-sort_dir_list(struct fixup_entry *p)
-{
- struct fixup_entry *a, *b, *t;
-
- if (p == NULL)
- return (NULL);
- /* A one-item list is already sorted. */
- if (p->next == NULL)
- return (p);
-
- /* Step 1: split the list. */
- t = p;
- a = p->next->next;
- while (a != NULL) {
- /* Step a twice, t once. */
- a = a->next;
- if (a != NULL)
- a = a->next;
- t = t->next;
- }
- /* Now, t is at the mid-point, so break the list here. */
- b = t->next;
- t->next = NULL;
- a = p;
-
- /* Step 2: Recursively sort the two sub-lists. */
- a = sort_dir_list(a);
- b = sort_dir_list(b);
-
- /* Step 3: Merge the returned lists. */
- /* Pick the first element for the merged list. */
- if (strcmp(a->name, b->name) > 0) {
- t = p = a;
- a = a->next;
- } else {
- t = p = b;
- b = b->next;
- }
-
- /* Always put the later element on the list first. */
- while (a != NULL && b != NULL) {
- if (strcmp(a->name, b->name) > 0) {
- t->next = a;
- a = a->next;
- } else {
- t->next = b;
- b = b->next;
- }
- t = t->next;
- }
-
- /* Only one list is non-empty, so just splice it on. */
- if (a != NULL)
- t->next = a;
- if (b != NULL)
- t->next = b;
-
- return (p);
-}
-
-/*
- * Returns a new, initialized fixup entry.
- *
- * TODO: Reduce the memory requirements for this list by using a tree
- * structure rather than a simple list of names.
- */
-static struct fixup_entry *
-new_fixup(struct archive *a, const char *pathname)
-{
- struct extract *extract;
- struct fixup_entry *fe;
-
- extract = a->extract;
- fe = (struct fixup_entry *)malloc(sizeof(struct fixup_entry));
- if (fe == NULL)
- return (NULL);
- fe->next = extract->fixup_list;
- extract->fixup_list = fe;
- fe->fixup = 0;
- fe->name = strdup(pathname);
- return (fe);
-}
-
-/*
- * Returns a fixup structure for the current entry.
- */
-static struct fixup_entry *
-current_fixup(struct archive *a, const char *pathname)
-{
- struct extract *extract;
-
- extract = a->extract;
- if (extract->current_fixup == NULL)
- extract->current_fixup = new_fixup(a, pathname);
- return (extract->current_fixup);
-}
-
-static int
-extract_file(struct archive *a, struct archive_entry *entry, int flags)
-{
- struct extract *extract;
- const char *name;
- mode_t mode;
- int fd, r, r2;
-
- extract = a->extract;
- name = archive_entry_pathname(entry);
- mode = archive_entry_mode(entry) & 0777;
- r = ARCHIVE_OK;
-
- /*
- * If we're not supposed to overwrite pre-existing files,
- * use O_EXCL. Otherwise, use O_TRUNC.
- */
- if (flags & (ARCHIVE_EXTRACT_UNLINK | ARCHIVE_EXTRACT_NO_OVERWRITE))
- fd = open(name, O_WRONLY | O_CREAT | O_EXCL, mode);
- else
- fd = open(name, O_WRONLY | O_CREAT | O_TRUNC, mode);
-
- /* Try removing a pre-existing file. */
- if (fd < 0 && !(flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) {
- unlink(name);
- fd = open(name, O_WRONLY | O_CREAT | O_EXCL, mode);
- }
-
- /* Might be a non-existent parent dir; try fixing that. */
- if (fd < 0) {
- create_parent_dir(a, name, flags);
- fd = open(name, O_WRONLY | O_CREAT | O_EXCL, mode);
- }
- if (fd < 0) {
- archive_set_error(a, errno, "Can't open '%s'", name);
- return (ARCHIVE_WARN);
- }
- r = archive_read_data_into_fd(a, fd);
- extract->pst = NULL; /* Cached stat data no longer valid. */
- r2 = restore_metadata(a, fd, entry, flags);
- close(fd);
- return (err_combine(r, r2));
-}
-
-static int
-extract_dir(struct archive *a, struct archive_entry *entry, int flags)
-{
- struct extract *extract;
- struct fixup_entry *fe;
- char *path, *p;
- mode_t restore_mode, final_mode;
- extract = a->extract;
- extract->pst = NULL; /* Invalidate cached stat data. */
-
- /* Copy path to mutable storage. */
- archive_strcpy(&(extract->create_parent_dir),
- archive_entry_pathname(entry));
- path = extract->create_parent_dir.s;
-
- if (*path == '\0') {
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "Invalid empty pathname");
- return (ARCHIVE_WARN);
- }
-
- /* Deal with any troublesome trailing path elements. */
- /* TODO: Someday, generalize this to remove '//' or '/./' from
- * the middle of paths. But, it should not compress '..' from
- * the middle of paths. It's a feature that restoring
- * "a/../b" creates both 'a' and 'b' directories. */
- for (;;) {
- /* Locate last element. */
- p = strrchr(path, '/');
- if (p != NULL)
- p++;
- else
- p = path;
- /* Trim trailing '/' unless that's the entire path. */
- if (p[0] == '\0' && p - 1 > path) {
- p[-1] = '\0';
- continue;
- }
- /* Trim trailing '.' unless that's the entire path. */
- if (p > path && p[0] == '.' && p[1] == '\0') {
- p[0] = '\0';
- continue;
- }
- /* Just exit on trailing '..'. */
- if (p[0] == '.' && p[1] == '.' && p[2] == '\0') {
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "Can't restore directory '..'");
- return (ARCHIVE_WARN);
- }
- break;
- }
-
- final_mode = archive_entry_mode(entry) &
- (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO);
- if ((flags & ARCHIVE_EXTRACT_PERM) == 0)
- final_mode &= ~extract->umask;
- /* Constrain the permissions in effect during the restore. */
- restore_mode = final_mode;
- restore_mode |= MINIMUM_DIR_MODE;
- restore_mode &= MAXIMUM_DIR_MODE;
-
- if (mkdir(path, restore_mode) == 0)
- goto success;
-
- if (extract->pst == NULL && stat(path, &extract->st) == 0)
- extract->pst = &extract->st;
-
- if (extract->pst != NULL) {
- extract->pst = &extract->st;
- /* If dir already exists, don't reset permissions. */
- if (S_ISDIR(extract->pst->st_mode))
- return (ARCHIVE_OK);
- /* It exists but isn't a dir. */
- if ((flags & ARCHIVE_EXTRACT_UNLINK))
- unlink(path);
- } else {
- /* Doesn't already exist; try building the parent path. */
- if (create_parent_dir_mutable(a, path, flags) != ARCHIVE_OK)
- return (ARCHIVE_WARN);
- }
-
- /* One final attempt to create the dir. */
- if (mkdir(path, restore_mode) != 0) {
- archive_set_error(a, errno, "Can't create directory");
- return (ARCHIVE_WARN);
- }
-
-success:
- /* Add this dir to the fixup list. */
- if (final_mode != restore_mode) {
- fe = current_fixup(a, path);
- fe->fixup |= FIXUP_MODE;
- fe->mode = final_mode;
- }
- if (flags & ARCHIVE_EXTRACT_TIME) {
- fe = current_fixup(a, path);
- fe->fixup |= FIXUP_TIMES;
- fe->mtime = archive_entry_mtime(entry);
- fe->mtime_nanos = archive_entry_mtime_nsec(entry);
- fe->atime = archive_entry_atime(entry);
- fe->atime_nanos = archive_entry_atime_nsec(entry);
- }
- return (restore_metadata(a, -1, entry, flags));
-}
-
-
-/*
- * Create the parent of the specified path. Copy the provided
- * path into mutable storage first.
- */
-static int
-create_parent_dir(struct archive *a, const char *path, int flags)
-{
- int r;
-
- /* Copy path to mutable storage. */
- archive_strcpy(&(a->extract->create_parent_dir), path);
- r = create_parent_dir_mutable(a, a->extract->create_parent_dir.s, flags);
- return (r);
-}
-
-/*
- * Like create_parent_dir, but creates the dir actually requested, not
- * the parent.
- */
-static int
-create_dir(struct archive *a, const char *path, int flags)
-{
- int r;
- /* Copy path to mutable storage. */
- archive_strcpy(&(a->extract->create_parent_dir), path);
- r = create_dir_mutable(a, a->extract->create_parent_dir.s, flags);
- return (r);
-}
-
-/*
- * Create the parent directory of the specified path, assuming path
- * is already in mutable storage.
- */
-static int
-create_parent_dir_mutable(struct archive *a, char *path, int flags)
-{
- char *slash;
- int r;
-
- /* Remove tail element to obtain parent name. */
- slash = strrchr(path, '/');
- if (slash == NULL)
- return (ARCHIVE_OK);
- *slash = '\0';
- r = create_dir_mutable(a, path, flags);
- *slash = '/';
- return (r);
-}
-
-/*
- * Create the specified dir, assuming path is already in
- * mutable storage.
- */
-static int
-create_dir_mutable(struct archive *a, char *path, int flags)
-{
- int r;
-
- r = create_dir_recursive(a, path, flags);
+ /* Set up for this particular entry. */
+ extract = a->extract;
+ archive_write_disk_set_options(a->extract->ad, flags);
+ archive_write_disk_set_skip_file(a->extract->ad,
+ a->skip_file_dev, a->skip_file_ino);
+ r = archive_write_header(a->extract->ad, entry);
+ if (r == ARCHIVE_OK)
+ /* If there's an FD, pour data into it. */
+ r = copy_data(_a, a->extract->ad);
+ if (r != ARCHIVE_OK)
+ archive_set_error(&a->archive,
+ archive_errno(extract->ad),
+ "%s", archive_error_string(extract->ad));
+ r2 = archive_write_finish_entry(a->extract->ad);
+ /* Use the first message. */
+ if (r2 != ARCHIVE_OK && r == ARCHIVE_OK)
+ archive_set_error(&a->archive,
+ archive_errno(extract->ad),
+ "%s", archive_error_string(extract->ad));
+ /* Use the worst error return. */
+ if (r2 < r)
+ r = r2;
return (r);
}
-/*
- * Create the specified dir, recursing to create parents as necessary.
- *
- * Returns ARCHIVE_OK if the path exists when we're done here.
- * Otherwise, returns ARCHIVE_WARN.
- */
-static int
-create_dir_recursive(struct archive *a, char *path, int flags)
-{
- struct stat st;
- struct extract *extract;
- struct fixup_entry *le;
- char *slash, *base;
- int r;
-
- extract = a->extract;
- r = ARCHIVE_OK;
-
- /* Check for special names and just skip them. */
- slash = strrchr(path, '/');
- base = strrchr(path, '/');
- if (slash == NULL)
- base = path;
- else
- base = slash + 1;
-
- if (base[0] == '\0' ||
- (base[0] == '.' && base[1] == '\0') ||
- (base[0] == '.' && base[1] == '.' && base[2] == '\0')) {
- /* Don't bother trying to create null path, '.', or '..'. */
- if (slash != NULL) {
- *slash = '\0';
- r = create_dir_recursive(a, path, flags);
- *slash = '/';
- return (r);
- }
- return (ARCHIVE_OK);
- }
-
- /*
- * Yes, this should be stat() and not lstat(). Using lstat()
- * here loses the ability to extract through symlinks. Also note
- * that this should not use the extract->st cache.
- */
- if (stat(path, &st) == 0) {
- if (S_ISDIR(st.st_mode))
- return (ARCHIVE_OK);
- if ((flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) {
- archive_set_error(a, EEXIST,
- "Can't create directory '%s'", path);
- return (ARCHIVE_WARN);
- }
- if (unlink(path) != 0) {
- archive_set_error(a, errno,
- "Can't create directory '%s': "
- "Conflicting file cannot be removed");
- return (ARCHIVE_WARN);
- }
- } else if (errno != ENOENT && errno != ENOTDIR) {
- /* Stat failed? */
- archive_set_error(a, errno, "Can't test directory '%s'", path);
- return (ARCHIVE_WARN);
- } else if (slash != NULL) {
- *slash = '\0';
- r = create_dir_recursive(a, path, flags);
- *slash = '/';
- if (r != ARCHIVE_OK)
- return (r);
- }
-
- if (mkdir(path, extract->default_dir_mode_initial) == 0) {
- if (extract->default_dir_mode_initial
- != extract->default_dir_mode_final) {
- le = new_fixup(a, path);
- le->fixup |= FIXUP_MODE;
- le->mode = extract->default_dir_mode_final;
- }
- return (ARCHIVE_OK);
- }
-
- /*
- * Without the following check, a/b/../b/c/d fails at the
- * second visit to 'b', so 'd' can't be created. Note that we
- * don't add it to the fixup list here, as it's already been
- * added.
- */
- if (stat(path, &st) == 0 && S_ISDIR(st.st_mode))
- return (ARCHIVE_OK);
-
- archive_set_error(a, errno, "Failed to create dir '%s'", path);
- return (ARCHIVE_WARN);
-}
-
-static int
-extract_hard_link(struct archive *a, struct archive_entry *entry, int flags)
-{
- struct extract *extract;
- int r;
- const char *pathname;
- const char *linkname;
-
- extract = a->extract;
- pathname = archive_entry_pathname(entry);
- linkname = archive_entry_hardlink(entry);
-
- /* Just remove any pre-existing file with this name. */
- if (!(flags & ARCHIVE_EXTRACT_NO_OVERWRITE))
- unlink(pathname);
-
- r = link(linkname, pathname);
- extract->pst = NULL; /* Invalidate cached stat data. */
-
- if (r != 0) {
- /* Might be a non-existent parent dir; try fixing that. */
- create_parent_dir(a, pathname, flags);
- r = link(linkname, pathname);
- }
-
- if (r != 0) {
- /* XXX Better error message here XXX */
- archive_set_error(a, errno,
- "Can't restore hardlink to '%s'", linkname);
- return (ARCHIVE_WARN);
- }
-
- /* Set ownership, time, permission information. */
- r = restore_metadata(a, -1, entry, flags);
- return (r);
-}
-
-static int
-extract_symlink(struct archive *a, struct archive_entry *entry, int flags)
-{
- struct extract *extract;
- int r;
- const char *pathname;
- const char *linkname;
-
- extract = a->extract;
- pathname = archive_entry_pathname(entry);
- linkname = archive_entry_symlink(entry);
-
- /* Just remove any pre-existing file with this name. */
- if (!(flags & ARCHIVE_EXTRACT_NO_OVERWRITE))
- unlink(pathname);
-
- r = symlink(linkname, pathname);
- extract->pst = NULL; /* Invalidate cached stat data. */
-
- if (r != 0) {
- /* Might be a non-existent parent dir; try fixing that. */
- create_parent_dir(a, pathname, flags);
- r = symlink(linkname, pathname);
- }
-
- if (r != 0) {
- /* XXX Better error message here XXX */
- archive_set_error(a, errno,
- "Can't restore symlink to '%s'", linkname);
- return (ARCHIVE_WARN);
- }
-
- r = restore_metadata(a, -1, entry, flags);
- return (r);
-}
-
-static int
-extract_device(struct archive *a, struct archive_entry *entry,
- int flags, mode_t mode)
+void
+archive_read_extract_set_progress_callback(struct archive *_a,
+ void (*progress_func)(void *), void *user_data)
{
- struct extract *extract;
- int r;
-
- extract = a->extract;
- /* Just remove any pre-existing file with this name. */
- if (!(flags & ARCHIVE_EXTRACT_NO_OVERWRITE))
- unlink(archive_entry_pathname(entry));
-
- r = mknod(archive_entry_pathname(entry), mode,
- archive_entry_rdev(entry));
- extract->pst = NULL; /* Invalidate cached stat data. */
-
- /* Might be a non-existent parent dir; try fixing that. */
- if (r != 0 && errno == ENOENT) {
- create_parent_dir(a, archive_entry_pathname(entry), flags);
- r = mknod(archive_entry_pathname(entry), mode,
- archive_entry_rdev(entry));
- }
-
- if (r != 0) {
- archive_set_error(a, errno, "Can't restore device node");
- return (ARCHIVE_WARN);
+ struct archive_read *a = (struct archive_read *)_a;
+ struct extract *extract = get_extract(a);
+ if (extract != NULL) {
+ extract->extract_progress = progress_func;
+ extract->extract_progress_user_data = user_data;
}
-
- r = restore_metadata(a, -1, entry, flags);
- return (r);
-}
-
-static int
-extract_char_device(struct archive *a, struct archive_entry *entry, int flags)
-{
- mode_t mode;
-
- mode = (archive_entry_mode(entry) & ~S_IFMT) | S_IFCHR;
- return (extract_device(a, entry, flags, mode));
}
static int
-extract_block_device(struct archive *a, struct archive_entry *entry, int flags)
+copy_data(struct archive *ar, struct archive *aw)
{
- mode_t mode;
-
- mode = (archive_entry_mode(entry) & ~S_IFMT) | S_IFBLK;
- return (extract_device(a, entry, flags, mode));
-}
-
-static int
-extract_fifo(struct archive *a, struct archive_entry *entry, int flags)
-{
- struct extract *extract;
int r;
+ const void *buff;
+ size_t size;
+ off_t offset;
- extract = a->extract;
- /* Just remove any pre-existing file with this name. */
- if (!(flags & ARCHIVE_EXTRACT_NO_OVERWRITE))
- unlink(archive_entry_pathname(entry));
-
- r = mkfifo(archive_entry_pathname(entry),
- archive_entry_mode(entry));
- extract->pst = NULL; /* Invalidate cached stat data. */
-
- /* Might be a non-existent parent dir; try fixing that. */
- if (r != 0 && errno == ENOENT) {
- create_parent_dir(a, archive_entry_pathname(entry), flags);
- r = mkfifo(archive_entry_pathname(entry),
- archive_entry_mode(entry));
- }
-
- if (r != 0) {
- archive_set_error(a, errno, "Can't restore fifo");
- return (ARCHIVE_WARN);
- }
-
- r = restore_metadata(a, -1, entry, flags);
- return (r);
-}
-
-static int
-restore_metadata(struct archive *a, int fd, struct archive_entry *entry, int flags)
-{
- int r, r2;
-
- r = set_ownership(a, fd, entry, flags);
- r2 = set_time(a, fd, entry, flags);
- r = err_combine(r, r2);
- r2 = set_perm(a, fd, entry, archive_entry_mode(entry), flags);
- return (err_combine(r, r2));
-}
-
-static int
-set_ownership(struct archive *a, int fd,
- struct archive_entry *entry, int flags)
-{
- uid_t uid;
- gid_t gid;
-
- /* Not changed. */
- if ((flags & ARCHIVE_EXTRACT_OWNER) == 0)
- return (ARCHIVE_OK);
-
- uid = lookup_uid(a, archive_entry_uname(entry),
- archive_entry_uid(entry));
- gid = lookup_gid(a, archive_entry_gname(entry),
- archive_entry_gid(entry));
-
- /* If we know we can't change it, don't bother trying. */
- if (a->user_uid != 0 && a->user_uid != uid)
- return (ARCHIVE_OK);
-
-#ifdef HAVE_FCHOWN
- if (fd >= 0 && fchown(fd, uid, gid) == 0)
- return (ARCHIVE_OK);
-#endif
-
-#ifdef HAVE_LCHOWN
- if (lchown(archive_entry_pathname(entry), uid, gid))
-#else
- if (!S_ISLNK(archive_entry_mode(entry))
- && chown(archive_entry_pathname(entry), uid, gid) != 0)
-#endif
- {
- archive_set_error(a, errno,
- "Can't set user=%d/group=%d for %s", uid, gid,
- archive_entry_pathname(entry));
- return (ARCHIVE_WARN);
- }
- return (ARCHIVE_OK);
-}
-
-static int
-set_time(struct archive *a, int fd, struct archive_entry *entry, int flags)
-{
- const struct stat *st;
- struct timeval times[2];
-
- (void)a; /* UNUSED */
- st = archive_entry_stat(entry);
-
- if ((flags & ARCHIVE_EXTRACT_TIME) == 0)
- return (ARCHIVE_OK);
- /* It's a waste of time to mess with dir timestamps here. */
- if (S_ISDIR(archive_entry_mode(entry)))
- return (ARCHIVE_OK);
-
- times[1].tv_sec = st->st_mtime;
- times[1].tv_usec = ARCHIVE_STAT_MTIME_NANOS(st) / 1000;
-
- times[0].tv_sec = st->st_atime;
- times[0].tv_usec = ARCHIVE_STAT_ATIME_NANOS(st) / 1000;
-
-#ifdef HAVE_FUTIMES
- if (fd >= 0 && futimes(fd, times) == 0)
- return (ARCHIVE_OK);
-#endif
-
-#ifdef HAVE_LUTIMES
- if (lutimes(archive_entry_pathname(entry), times) != 0) {
-#else
- if ((archive_entry_mode(entry) & S_IFMT) != S_IFLNK &&
- utimes(archive_entry_pathname(entry), times) != 0) {
-#endif
- archive_set_error(a, errno, "Can't update time for %s",
- archive_entry_pathname(entry));
- return (ARCHIVE_WARN);
- }
-
- /*
- * Note: POSIX does not provide a portable way to restore ctime.
- * (Apart from resetting the system clock, which is distasteful.)
- * So, any restoration of ctime will necessarily be OS-specific.
- */
-
- /* XXX TODO: Can FreeBSD restore ctime? XXX */
-
- return (ARCHIVE_OK);
-}
-
-static int
-set_perm(struct archive *a, int fd, struct archive_entry *entry,
- int mode, int flags)
-{
- struct extract *extract;
- struct fixup_entry *le;
- const char *name;
- unsigned long set, clear;
- int r;
- int critical_flags;
-
- extract = a->extract;
-
- /* Obey umask unless ARCHIVE_EXTRACT_PERM. */
- if ((flags & ARCHIVE_EXTRACT_PERM) == 0)
- mode &= ~extract->umask; /* Enforce umask. */
- name = archive_entry_pathname(entry);
-
- if (mode & (S_ISUID | S_ISGID)) {
- if (extract->pst != NULL) {
- /* Already have stat() data available. */
-#ifdef HAVE_FSTAT
- } else if (fd >= 0 && fstat(fd, &extract->st) == 0) {
- extract->pst = &extract->st;
-#endif
- } else if (stat(name, &extract->st) == 0) {
- extract->pst = &extract->st;
- } else {
- archive_set_error(a, errno,
- "Couldn't stat file");
- return (ARCHIVE_WARN);
- }
-
- /*
- * TODO: Use the uid/gid looked up in set_ownership
- * above rather than the uid/gid stored in the entry.
- */
- if (extract->pst->st_uid != archive_entry_uid(entry))
- mode &= ~ S_ISUID;
- if (extract->pst->st_gid != archive_entry_gid(entry))
- mode &= ~ S_ISGID;
- }
-
- if (S_ISLNK(archive_entry_mode(entry))) {
-#ifdef HAVE_LCHMOD
- /*
- * If this is a symlink, use lchmod(). If the
- * platform doesn't support lchmod(), just skip it as
- * permissions on symlinks are actually ignored on
- * most platforms.
- */
- if (lchmod(name, mode) != 0) {
- archive_set_error(a, errno, "Can't set permissions");
- return (ARCHIVE_WARN);
- }
-#endif
- } else if (!S_ISDIR(archive_entry_mode(entry))) {
- /*
- * If it's not a symlink and not a dir, then use
- * fchmod() or chmod(), depending on whether we have
- * an fd. Dirs get their perms set during the
- * post-extract fixup, which is handled elsewhere.
- */
-#ifdef HAVE_FCHMOD
- if (fd >= 0) {
- if (fchmod(fd, mode) != 0) {
- archive_set_error(a, errno,
- "Can't set permissions");
- return (ARCHIVE_WARN);
- }
- } else
-#endif
- /* If this platform lacks fchmod(), then
- * we'll just use chmod(). */
- if (chmod(name, mode) != 0) {
- archive_set_error(a, errno,
- "Can't set permissions");
- return (ARCHIVE_WARN);
- }
- }
-
- if (flags & ARCHIVE_EXTRACT_ACL) {
- r = set_acls(a, fd, entry);
+ for (;;) {
+ r = archive_read_data_block(ar, &buff, &size, &offset);
+ if (r == ARCHIVE_EOF)
+ return (ARCHIVE_OK);
if (r != ARCHIVE_OK)
return (r);
- }
-
- if (flags & ARCHIVE_EXTRACT_XATTR) {
- r = set_xattrs(a, fd, entry);
+ r = archive_write_data_block(aw, buff, size, offset);
if (r != ARCHIVE_OK)
return (r);
}
-
- /*
- * Make 'critical_flags' hold all file flags that can't be
- * immediately restored. For example, on BSD systems,
- * SF_IMMUTABLE prevents hardlinks from being created, so
- * should not be set until after any hardlinks are created. To
- * preserve some semblance of portability, this uses #ifdef
- * extensively. Ugly, but it works.
- *
- * Yes, Virginia, this does create a security race. It's mitigated
- * somewhat by the practice of creating dirs 0700 until the extract
- * is done, but it would be nice if we could do more than that.
- * People restoring critical file systems should be wary of
- * other programs that might try to muck with files as they're
- * being restored.
- */
- /* Hopefully, the compiler will optimize this mess into a constant. */
- critical_flags = 0;
-#ifdef SF_IMMUTABLE
- critical_flags |= SF_IMMUTABLE;
-#endif
-#ifdef UF_IMMUTABLE
- critical_flags |= UF_IMMUTABLE;
-#endif
-#ifdef SF_APPEND
- critical_flags |= SF_APPEND;
-#endif
-#ifdef UF_APPEND
- critical_flags |= UF_APPEND;
-#endif
-#ifdef EXT2_APPEND_FL
- critical_flags |= EXT2_APPEND_FL;
-#endif
-#ifdef EXT2_IMMUTABLE_FL
- critical_flags |= EXT2_IMMUTABLE_FL;
-#endif
-
- if (flags & ARCHIVE_EXTRACT_FFLAGS) {
- archive_entry_fflags(entry, &set, &clear);
-
- /*
- * The first test encourages the compiler to eliminate
- * all of this if it's not necessary.
- */
- if ((critical_flags != 0) && (set & critical_flags)) {
- le = current_fixup(a, archive_entry_pathname(entry));
- le->fixup |= FIXUP_FFLAGS;
- le->fflags_set = set;
- /* Store the mode if it's not already there. */
- if ((le->fixup & FIXUP_MODE) == 0)
- le->mode = mode;
- } else {
- r = set_fflags(a, fd, archive_entry_pathname(entry),
- mode, set, clear);
- if (r != ARCHIVE_OK)
- return (r);
- }
- }
- return (ARCHIVE_OK);
-}
-
-
-#if ( defined(HAVE_LCHFLAGS) || defined(HAVE_CHFLAGS) || defined(HAVE_FCHFLAGS) ) && !defined(__linux)
-static int
-set_fflags(struct archive *a, int fd, const char *name, mode_t mode,
- unsigned long set, unsigned long clear)
-{
- struct extract *extract;
-
- extract = a->extract;
- if (set == 0 && clear == 0)
- return (ARCHIVE_OK);
-
- (void)mode; /* UNUSED */
- /*
- * XXX Is the stat here really necessary? Or can I just use
- * the 'set' flags directly? In particular, I'm not sure
- * about the correct approach if we're overwriting an existing
- * file that already has flags on it. XXX
- */
- if (extract->pst != NULL) {
- /* Already have stat() data available. */
- } else if (fd >= 0 && fstat(fd, &extract->st) == 0)
- extract->pst = &extract->st;
- else if (stat(name, &extract->st) == 0)
- extract->pst = &extract->st;
- else {
- archive_set_error(a, errno,
- "Couldn't stat file");
- return (ARCHIVE_WARN);
- }
-
- extract->st.st_flags &= ~clear;
- extract->st.st_flags |= set;
-#ifdef HAVE_FCHFLAGS
- /* If platform has fchflags() and we were given an fd, use it. */
- if (fd >= 0 && fchflags(fd, extract->st.st_flags) == 0)
- return (ARCHIVE_OK);
-#endif
- /*
- * If we can't use the fd to set the flags, we'll use the
- * pathname to set flags. We prefer lchflags() but will use
- * chflags() if we must.
- */
-#ifdef HAVE_LCHFLAGS
- if (lchflags(name, extract->st.st_flags) == 0)
- return (ARCHIVE_OK);
-#elif defined(HAVE_CHFLAGS)
- if (chflags(name, extract->st.st_flags) == 0)
- return (ARCHIVE_OK);
-#endif
- archive_set_error(a, errno,
- "Failed to set file flags");
- return (ARCHIVE_WARN);
-}
-
-#elif defined(__linux) && defined(EXT2_IOC_GETFLAGS) && defined(EXT2_IOC_SETFLAGS)
-
-/*
- * Linux has flags too, but uses ioctl() to access them instead of
- * having a separate chflags() system call.
- */
-static int
-set_fflags(struct archive *a, int fd, const char *name, mode_t mode,
- unsigned long set, unsigned long clear)
-{
- struct extract *extract;
- int ret;
- int myfd = fd;
- unsigned long newflags, oldflags;
- unsigned long sf_mask = 0;
-
- extract = a->extract;
- if (set == 0 && clear == 0)
- return (ARCHIVE_OK);
- /* Only regular files and dirs can have flags. */
- if (!S_ISREG(mode) && !S_ISDIR(mode))
- return (ARCHIVE_OK);
-
- /* If we weren't given an fd, open it ourselves. */
- if (myfd < 0)
- myfd = open(name, O_RDONLY|O_NONBLOCK);
- if (myfd < 0)
- return (ARCHIVE_OK);
-
- /*
- * Linux has no define for the flags that are only settable by
- * the root user. This code may seem a little complex, but
- * there seem to be some Linux systems that lack these
- * defines. (?) The code below degrades reasonably gracefully
- * if sf_mask is incomplete.
- */
-#ifdef EXT2_IMMUTABLE_FL
- sf_mask |= EXT2_IMMUTABLE_FL;
-#endif
-#ifdef EXT2_APPEND_FL
- sf_mask |= EXT2_APPEND_FL;
-#endif
- /*
- * XXX As above, this would be way simpler if we didn't have
- * to read the current flags from disk. XXX
- */
- ret = ARCHIVE_OK;
- /* Try setting the flags as given. */
- if (ioctl(myfd, EXT2_IOC_GETFLAGS, &oldflags) >= 0) {
- newflags = (oldflags & ~clear) | set;
- if (ioctl(myfd, EXT2_IOC_SETFLAGS, &newflags) >= 0)
- goto cleanup;
- if (errno != EPERM)
- goto fail;
- }
- /* If we couldn't set all the flags, try again with a subset. */
- if (ioctl(myfd, EXT2_IOC_GETFLAGS, &oldflags) >= 0) {
- newflags &= ~sf_mask;
- oldflags &= sf_mask;
- newflags |= oldflags;
- if (ioctl(myfd, EXT2_IOC_SETFLAGS, &newflags) >= 0)
- goto cleanup;
- }
- /* We couldn't set the flags, so report the failure. */
-fail:
- archive_set_error(a, errno,
- "Failed to set file flags");
- ret = ARCHIVE_WARN;
-cleanup:
- if (fd < 0)
- close(myfd);
- return (ret);
-}
-
-#else /* Not HAVE_CHFLAGS && Not __linux */
-
-/*
- * Of course, some systems have neither BSD chflags() nor Linux' flags
- * support through ioctl().
- */
-static int
-set_fflags(struct archive *a, int fd, const char *name, mode_t mode,
- unsigned long set, unsigned long clear)
-{
- (void)a;
- (void)fd;
- (void)name;
- (void)mode;
- (void)set;
- (void)clear;
- return (ARCHIVE_OK);
-}
-
-#endif /* __linux */
-
-#ifndef HAVE_POSIX_ACL
-/* Default empty function body to satisfy mainline code. */
-static int
-set_acls(struct archive *a, int fd, struct archive_entry *entry)
-{
- (void)a;
- (void)fd;
- (void)entry;
-
- return (ARCHIVE_OK);
-}
-
-#else
-
-/*
- * XXX TODO: What about ACL types other than ACCESS and DEFAULT?
- */
-static int
-set_acls(struct archive *a, int fd, struct archive_entry *entry)
-{
- int ret;
-
- ret = set_acl(a, fd, entry, ACL_TYPE_ACCESS,
- ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access");
- if (ret != ARCHIVE_OK)
- return (ret);
- ret = set_acl(a, fd, entry, ACL_TYPE_DEFAULT,
- ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default");
- return (ret);
-}
-
-
-static int
-set_acl(struct archive *a, int fd, struct archive_entry *entry,
- acl_type_t acl_type, int ae_requested_type, const char *tname)
-{
- acl_t acl;
- acl_entry_t acl_entry;
- acl_permset_t acl_permset;
- int ret;
- int ae_type, ae_permset, ae_tag, ae_id;
- uid_t ae_uid;
- gid_t ae_gid;
- const char *ae_name;
- int entries;
- const char *name;
-
- ret = ARCHIVE_OK;
- entries = archive_entry_acl_reset(entry, ae_requested_type);
- if (entries == 0)
- return (ARCHIVE_OK);
- acl = acl_init(entries);
- while (archive_entry_acl_next(entry, ae_requested_type, &ae_type,
- &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) {
- acl_create_entry(&acl, &acl_entry);
-
- switch (ae_tag) {
- case ARCHIVE_ENTRY_ACL_USER:
- acl_set_tag_type(acl_entry, ACL_USER);
- ae_uid = lookup_uid(a, ae_name, ae_id);
- acl_set_qualifier(acl_entry, &ae_uid);
- break;
- case ARCHIVE_ENTRY_ACL_GROUP:
- acl_set_tag_type(acl_entry, ACL_GROUP);
- ae_gid = lookup_gid(a, ae_name, ae_id);
- acl_set_qualifier(acl_entry, &ae_gid);
- break;
- case ARCHIVE_ENTRY_ACL_USER_OBJ:
- acl_set_tag_type(acl_entry, ACL_USER_OBJ);
- break;
- case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
- acl_set_tag_type(acl_entry, ACL_GROUP_OBJ);
- break;
- case ARCHIVE_ENTRY_ACL_MASK:
- acl_set_tag_type(acl_entry, ACL_MASK);
- break;
- case ARCHIVE_ENTRY_ACL_OTHER:
- acl_set_tag_type(acl_entry, ACL_OTHER);
- break;
- default:
- /* XXX */
- break;
- }
-
- acl_get_permset(acl_entry, &acl_permset);
- acl_clear_perms(acl_permset);
- if (ae_permset & ARCHIVE_ENTRY_ACL_EXECUTE)
- acl_add_perm(acl_permset, ACL_EXECUTE);
- if (ae_permset & ARCHIVE_ENTRY_ACL_WRITE)
- acl_add_perm(acl_permset, ACL_WRITE);
- if (ae_permset & ARCHIVE_ENTRY_ACL_READ)
- acl_add_perm(acl_permset, ACL_READ);
- }
-
- name = archive_entry_pathname(entry);
-
- /* Try restoring the ACL through 'fd' if we can. */
-#if HAVE_ACL_SET_FD
- if (fd >= 0 && acl_type == ACL_TYPE_ACCESS && acl_set_fd(fd, acl) == 0)
- ret = ARCHIVE_OK;
- else
-#else
-#if HAVE_ACL_SET_FD_NP
- if (fd >= 0 && acl_set_fd_np(fd, acl, acl_type) == 0)
- ret = ARCHIVE_OK;
- else
-#endif
-#endif
- if (acl_set_file(name, acl_type, acl) != 0) {
- archive_set_error(a, errno, "Failed to set %s acl", tname);
- ret = ARCHIVE_WARN;
- }
- acl_free(acl);
- return (ret);
}
-#endif
-#if HAVE_LSETXATTR
/*
- * Restore extended attributes - Linux implementation
+ * Cleanup function for archive_extract.
*/
static int
-set_xattrs(struct archive *a, int fd, struct archive_entry *entry)
+archive_read_extract_cleanup(struct archive_read *a)
{
- static int warning_done = 0;
int ret = ARCHIVE_OK;
- int i = archive_entry_xattr_reset(entry);
- while (i--) {
- const char *name;
- const void *value;
- size_t size;
- archive_entry_xattr_next(entry, &name, &value, &size);
- if (name != NULL &&
- strncmp(name, "xfsroot.", 8) != 0 &&
- strncmp(name, "system.", 7) != 0) {
- int e;
-#if HAVE_FSETXATTR
- if (fd >= 0)
- e = fsetxattr(fd, name, value, size, 0);
- else
+#if ARCHIVE_API_VERSION > 1
+ ret =
#endif
- {
- e = lsetxattr(archive_entry_pathname(entry),
- name, value, size, 0);
- }
- if (e == -1) {
- if (errno == ENOTSUP) {
- if (!warning_done) {
- warning_done = 1;
- archive_set_error(a, errno,
- "Cannot restore extended "
- "attributes on this file "
- "system");
- }
- } else
- archive_set_error(a, errno,
- "Failed to set extended attribute");
- ret = ARCHIVE_WARN;
- }
- } else {
- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
- "Invalid extended attribute encountered");
- ret = ARCHIVE_WARN;
- }
- }
+ archive_write_finish(a->extract->ad);
+ free(a->extract);
+ a->extract = NULL;
return (ret);
}
-#else
-/*
- * Restore extended attributes - stub implementation for unsupported systems
- */
-static int
-set_xattrs(struct archive *a, int fd, struct archive_entry *entry)
-{
- static int warning_done = 0;
- (void)a; /* UNUSED */
- (void)fd; /* UNUSED */
-
- /* If there aren't any extended attributes, then it's okay not
- * to extract them, otherwise, issue a single warning. */
- if (archive_entry_xattr_count(entry) != 0 && !warning_done) {
- warning_done = 1;
- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
- "Cannot restore extended attributes on this system");
- return (ARCHIVE_WARN);
- }
- /* Warning was already emitted; suppress further warnings. */
- return (ARCHIVE_OK);
-}
-#endif
-
-/*
- * The following routines do some basic caching of uname/gname
- * lookups. All such lookups go through these routines, including ACL
- * conversions. Even a small cache here provides an enormous speedup,
- * especially on systems using NIS, LDAP, or a similar networked
- * directory system.
- *
- * TODO: Provide an API for clients to override these routines.
- */
-static gid_t
-lookup_gid(struct archive *a, const char *gname, gid_t gid)
-{
- struct group *grent;
- struct extract *extract;
- int h;
- struct bucket *b;
- int cache_size;
-
- extract = a->extract;
- cache_size = sizeof(extract->gcache) / sizeof(extract->gcache[0]);
-
- /* If no gname, just use the gid provided. */
- if (gname == NULL || *gname == '\0')
- return (gid);
-
- /* Try to find gname in the cache. */
- h = hash(gname);
- b = &extract->gcache[h % cache_size ];
- if (b->name != NULL && b->hash == h && strcmp(gname, b->name) == 0)
- return ((gid_t)b->id);
-
- /* Free the cache slot for a new entry. */
- if (b->name != NULL)
- free(b->name);
- b->name = strdup(gname);
- /* Note: If strdup fails, that's okay; we just won't cache. */
- b->hash = h;
- grent = getgrnam(gname);
- if (grent != NULL)
- gid = grent->gr_gid;
- b->id = gid;
-
- return (gid);
-}
-
-static uid_t
-lookup_uid(struct archive *a, const char *uname, uid_t uid)
-{
- struct passwd *pwent;
- struct extract *extract;
- int h;
- struct bucket *b;
- int cache_size;
-
- extract = a->extract;
- cache_size = sizeof(extract->ucache) / sizeof(extract->ucache[0]);
-
- /* If no uname, just use the uid provided. */
- if (uname == NULL || *uname == '\0')
- return (uid);
-
- /* Try to find uname in the cache. */
- h = hash(uname);
- b = &extract->ucache[h % cache_size ];
- if (b->name != NULL && b->hash == h && strcmp(uname, b->name) == 0)
- return ((uid_t)b->id);
-
- /* Free the cache slot for a new entry. */
- if (b->name != NULL)
- free(b->name);
- b->name = strdup(uname);
- /* Note: If strdup fails, that's okay; we just won't cache. */
- b->hash = h;
- pwent = getpwnam(uname);
- if (pwent != NULL)
- uid = pwent->pw_uid;
- b->id = uid;
-
- return (uid);
-}
-
-static unsigned int
-hash(const char *p)
-{
- /* A 32-bit version of Peter Weinberger's (PJW) hash algorithm,
- as used by ELF for hashing function names. */
- unsigned g, h = 0;
- while (*p != '\0') {
- h = ( h << 4 ) + *p++;
- if (( g = h & 0xF0000000 )) {
- h ^= g >> 24;
- h &= 0x0FFFFFFF;
- }
- }
- return h;
-}
-
-void
-archive_read_extract_set_progress_callback(struct archive *a,
- void (*progress_func)(void *), void *user_data)
-{
- a->extract_progress = progress_func;
- a->extract_progress_user_data = user_data;
-}
diff --git a/lib/libarchive/archive_read_private.h b/lib/libarchive/archive_read_private.h
new file mode 100644
index 0000000..7789919
--- /dev/null
+++ b/lib/libarchive/archive_read_private.h
@@ -0,0 +1,188 @@
+/*-
+ * 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_READ_PRIVATE_H_INCLUDED
+#define ARCHIVE_READ_PRIVATE_H_INCLUDED
+
+#include "archive.h"
+#include "archive_string.h"
+#include "archive_private.h"
+
+struct archive_read {
+ struct archive archive;
+
+ struct archive_entry *entry;
+
+ /* Dev/ino of the archive being read/written. */
+ dev_t skip_file_dev;
+ ino_t skip_file_ino;
+
+ /* Utility: Pointer to a block of nulls. */
+ const unsigned char *nulls;
+ size_t null_length;
+
+ /*
+ * Used by archive_read_data() to track blocks and copy
+ * data to client buffers, filling gaps with zero bytes.
+ */
+ const char *read_data_block;
+ off_t read_data_offset;
+ off_t read_data_output_offset;
+ size_t read_data_remaining;
+
+ /* Callbacks to open/read/write/close archive stream. */
+ archive_open_callback *client_opener;
+ archive_read_callback *client_reader;
+ archive_skip_callback *client_skipper;
+ archive_write_callback *client_writer;
+ archive_close_callback *client_closer;
+ void *client_data;
+
+ /*
+ * Blocking information. Note that bytes_in_last_block is
+ * misleadingly named; I should find a better name. These
+ * control the final output from all compressors, including
+ * compression_none.
+ */
+ int bytes_per_block;
+ int bytes_in_last_block;
+
+ /*
+ * These control whether data within a gzip/bzip2 compressed
+ * stream gets padded or not. If pad_uncompressed is set,
+ * the data will be padded to a full block before being
+ * compressed. The pad_uncompressed_byte determines the value
+ * that will be used for padding. Note that these have no
+ * effect on compression "none."
+ */
+ int pad_uncompressed;
+ int pad_uncompressed_byte; /* TODO: Support this. */
+
+ /* File offset of beginning of most recently-read header. */
+ off_t header_position;
+
+ /*
+ * Detection functions for decompression: bid functions are
+ * given a block of data from the beginning of the stream and
+ * can bid on whether or not they support the data stream.
+ * General guideline: bid the number of bits that you actually
+ * test, e.g., 16 if you test a 2-byte magic value. The
+ * highest bidder will have their init function invoked, which
+ * can set up pointers to specific handlers.
+ *
+ * On write, the client just invokes an archive_write_set function
+ * which sets up the data here directly.
+ */
+ struct {
+ int (*bid)(const void *buff, size_t);
+ int (*init)(struct archive_read *, const void *buff, size_t);
+ } decompressors[4];
+ /* Read/write data stream (with compression). */
+ void *compression_data; /* Data for (de)compressor. */
+ int (*compression_init)(struct archive_read *); /* Initialize. */
+ int (*compression_finish)(struct archive_read *);
+ int (*compression_write)(struct archive_read *, const void *, size_t);
+ /*
+ * Read uses a peek/consume I/O model: the decompression code
+ * returns a pointer to the requested block and advances the
+ * file position only when requested by a consume call. This
+ * reduces copying and also simplifies look-ahead for format
+ * detection.
+ */
+ ssize_t (*compression_read_ahead)(struct archive_read *,
+ const void **, size_t request);
+ ssize_t (*compression_read_consume)(struct archive_read *, size_t);
+ off_t (*compression_skip)(struct archive_read *, off_t);
+
+ /*
+ * Format detection is mostly the same as compression
+ * detection, with two significant differences: The bidders
+ * use the read_ahead calls above to examine the stream rather
+ * than having the supervisor hand them a block of data to
+ * examine, and the auction is repeated for every header.
+ * Winning bidders should set the archive_format and
+ * archive_format_name appropriately. Bid routines should
+ * check archive_format and decline to bid if the format of
+ * the last header was incompatible.
+ *
+ * Again, write support is considerably simpler because there's
+ * no need for an auction.
+ */
+
+ struct archive_format_descriptor {
+ int (*bid)(struct archive_read *);
+ int (*read_header)(struct archive_read *, struct archive_entry *);
+ int (*read_data)(struct archive_read *, const void **, size_t *, off_t *);
+ int (*read_data_skip)(struct archive_read *);
+ int (*cleanup)(struct archive_read *);
+ void *format_data; /* Format-specific data for readers. */
+ } formats[8];
+ struct archive_format_descriptor *format; /* Active format. */
+
+ /*
+ * Storage for format-specific data. Note that there can be
+ * multiple format readers active at one time, so we need to
+ * allow for multiple format readers to have their data
+ * available. The pformat_data slot here is the solution: on
+ * read, it is guaranteed to always point to a void* variable
+ * that the format can use.
+ */
+ void **pformat_data; /* Pointer to current format_data. */
+ void *format_data; /* Used by writers. */
+
+ /*
+ * Pointers to format-specific functions for writing. They're
+ * initialized by archive_write_set_format_XXX() calls.
+ */
+ int (*format_init)(struct archive *); /* Only used on write. */
+ int (*format_finish)(struct archive *);
+ int (*format_finish_entry)(struct archive *);
+ int (*format_write_header)(struct archive *,
+ struct archive_entry *);
+ ssize_t (*format_write_data)(struct archive *,
+ const void *buff, size_t);
+
+ /*
+ * Various information needed by archive_extract.
+ */
+ struct extract *extract;
+ int (*cleanup_archive_extract)(struct archive_read *);
+};
+
+int __archive_read_register_format(struct archive_read *a,
+ void *format_data,
+ int (*bid)(struct archive_read *),
+ int (*read_header)(struct archive_read *, struct archive_entry *),
+ int (*read_data)(struct archive_read *, const void **, size_t *, off_t *),
+ int (*read_data_skip)(struct archive_read *),
+ int (*cleanup)(struct archive_read *));
+
+int __archive_read_register_compression(struct archive_read *a,
+ int (*bid)(const void *, size_t),
+ int (*init)(struct archive_read *, const void *, size_t));
+
+#endif
diff --git a/lib/libarchive/archive_read_support_compression_bzip2.c b/lib/libarchive/archive_read_support_compression_bzip2.c
index 307da68..969387e 100644
--- a/lib/libarchive/archive_read_support_compression_bzip2.c
+++ b/lib/libarchive/archive_read_support_compression_bzip2.c
@@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_private.h"
+#include "archive_read_private.h"
#if HAVE_BZLIB_H
struct private_data {
@@ -56,19 +57,20 @@ struct private_data {
int64_t total_out;
};
-static int finish(struct archive *);
-static ssize_t read_ahead(struct archive *, const void **, size_t);
-static ssize_t read_consume(struct archive *, size_t);
-static int drive_decompressor(struct archive *a, struct private_data *);
+static int finish(struct archive_read *);
+static ssize_t read_ahead(struct archive_read *, const void **, size_t);
+static ssize_t read_consume(struct archive_read *, size_t);
+static int drive_decompressor(struct archive_read *a, struct private_data *);
#endif
/* These two functions are defined even if we lack bzlib. See below. */
static int bid(const void *, size_t);
-static int init(struct archive *, const void *, size_t);
+static int init(struct archive_read *, const void *, size_t);
int
-archive_read_support_compression_bzip2(struct archive *a)
+archive_read_support_compression_bzip2(struct archive *_a)
{
+ struct archive_read *a = (struct archive_read *)_a;
return (__archive_read_register_compression(a, bid, init));
}
@@ -152,19 +154,19 @@ init(struct archive *a, const void *buff, size_t n)
* Setup the callbacks.
*/
static int
-init(struct archive *a, const void *buff, size_t n)
+init(struct archive_read *a, const void *buff, size_t n)
{
struct private_data *state;
int ret;
- a->compression_code = ARCHIVE_COMPRESSION_BZIP2;
- a->compression_name = "bzip2";
+ a->archive.compression_code = ARCHIVE_COMPRESSION_BZIP2;
+ a->archive.compression_name = "bzip2";
state = (struct private_data *)malloc(sizeof(*state));
if (state == NULL) {
- archive_set_error(a, ENOMEM,
+ archive_set_error(&a->archive, ENOMEM,
"Can't allocate data for %s decompression",
- a->compression_name);
+ a->archive.compression_name);
return (ARCHIVE_FATAL);
}
memset(state, 0, sizeof(*state));
@@ -176,9 +178,9 @@ init(struct archive *a, const void *buff, size_t n)
state->stream.avail_out = state->uncompressed_buffer_size;
if (state->uncompressed_buffer == NULL) {
- archive_set_error(a, ENOMEM,
+ archive_set_error(&a->archive, ENOMEM,
"Can't allocate %s decompression buffers",
- a->compression_name);
+ a->archive.compression_name);
free(state);
return (ARCHIVE_FATAL);
}
@@ -215,25 +217,26 @@ init(struct archive *a, const void *buff, size_t n)
}
/* Library setup failed: Clean up. */
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "Internal error initializing %s library", a->compression_name);
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Internal error initializing %s library",
+ a->archive.compression_name);
free(state->uncompressed_buffer);
free(state);
/* Override the error message if we know what really went wrong. */
switch (ret) {
case BZ_PARAM_ERROR:
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Internal error initializing compression library: "
"invalid setup parameter");
break;
case BZ_MEM_ERROR:
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Internal error initializing compression library: "
"out of memory");
break;
case BZ_CONFIG_ERROR:
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Internal error initializing compression library: "
"mis-compiled library");
break;
@@ -247,7 +250,7 @@ init(struct archive *a, const void *buff, size_t n)
* as necessary.
*/
static ssize_t
-read_ahead(struct archive *a, const void **p, size_t min)
+read_ahead(struct archive_read *a, const void **p, size_t min)
{
struct private_data *state;
int read_avail, was_avail, ret;
@@ -255,7 +258,7 @@ read_ahead(struct archive *a, const void **p, size_t min)
state = (struct private_data *)a->compression_data;
was_avail = -1;
if (!a->client_reader) {
- archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"No read callback is registered? "
"This is probably an internal programming error.");
return (ARCHIVE_FATAL);
@@ -289,12 +292,12 @@ read_ahead(struct archive *a, const void **p, size_t min)
* Mark a previously-returned block of data as read.
*/
static ssize_t
-read_consume(struct archive *a, size_t n)
+read_consume(struct archive_read *a, size_t n)
{
struct private_data *state;
state = (struct private_data *)a->compression_data;
- a->file_position += n;
+ a->archive.file_position += n;
state->read_next += n;
if (state->read_next > state->stream.next_out)
__archive_errx(1, "Request to consume too many "
@@ -306,7 +309,7 @@ read_consume(struct archive *a, size_t n)
* Clean up the decompressor.
*/
static int
-finish(struct archive *a)
+finish(struct archive_read *a)
{
struct private_data *state;
int ret;
@@ -317,8 +320,9 @@ finish(struct archive *a)
case BZ_OK:
break;
default:
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "Failed to clean up %s compressor", a->compression_name);
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Failed to clean up %s compressor",
+ a->archive.compression_name);
ret = ARCHIVE_FATAL;
}
@@ -327,7 +331,7 @@ finish(struct archive *a)
a->compression_data = NULL;
if (a->client_closer != NULL)
- (a->client_closer)(a, a->client_data);
+ (a->client_closer)(&a->archive, a->client_data);
return (ret);
}
@@ -337,7 +341,7 @@ finish(struct archive *a)
* blocks as necessary.
*/
static int
-drive_decompressor(struct archive *a, struct private_data *state)
+drive_decompressor(struct archive_read *a, struct private_data *state)
{
ssize_t ret;
int decompressed, total_decompressed;
@@ -346,7 +350,7 @@ drive_decompressor(struct archive *a, struct private_data *state)
total_decompressed = 0;
for (;;) {
if (state->stream.avail_in == 0) {
- ret = (a->client_reader)(a, a->client_data,
+ ret = (a->client_reader)(&a->archive, a->client_data,
(const void **)&state->stream.next_in);
if (ret < 0) {
/*
@@ -356,12 +360,12 @@ drive_decompressor(struct archive *a, struct private_data *state)
goto fatal;
}
if (ret == 0 && total_decompressed == 0) {
- archive_set_error(a, EIO,
+ archive_set_error(&a->archive, EIO,
"Premature end of %s compressed data",
- a->compression_name);
+ a->archive.compression_name);
return (ARCHIVE_FATAL);
}
- a->raw_position += ret;
+ a->archive.raw_position += ret;
state->stream.avail_in = ret;
}
@@ -393,8 +397,8 @@ drive_decompressor(struct archive *a, struct private_data *state)
/* Return a fatal error. */
fatal:
- archive_set_error(a, ARCHIVE_ERRNO_MISC, "%s decompression failed",
- a->compression_name);
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "%s decompression failed", a->archive.compression_name);
return (ARCHIVE_FATAL);
}
diff --git a/lib/libarchive/archive_read_support_compression_compress.c b/lib/libarchive/archive_read_support_compression_compress.c
index 3bd4a42..5159099 100644
--- a/lib/libarchive/archive_read_support_compression_compress.c
+++ b/lib/libarchive/archive_read_support_compression_compress.c
@@ -81,6 +81,7 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_private.h"
+#include "archive_read_private.h"
/*
* Because LZW decompression is pretty simple, I've just implemented
@@ -133,16 +134,17 @@ struct private_data {
};
static int bid(const void *, size_t);
-static int finish(struct archive *);
-static int init(struct archive *, const void *, size_t);
-static ssize_t read_ahead(struct archive *, const void **, size_t);
-static ssize_t read_consume(struct archive *, size_t);
-static int getbits(struct archive *, struct private_data *, int n);
-static int next_code(struct archive *a, struct private_data *state);
+static int finish(struct archive_read *);
+static int init(struct archive_read *, const void *, size_t);
+static ssize_t read_ahead(struct archive_read *, const void **, size_t);
+static ssize_t read_consume(struct archive_read *, size_t);
+static int getbits(struct archive_read *, struct private_data *, int n);
+static int next_code(struct archive_read *a, struct private_data *state);
int
-archive_read_support_compression_compress(struct archive *a)
+archive_read_support_compression_compress(struct archive *_a)
{
+ struct archive_read *a = (struct archive_read *)_a;
return (__archive_read_register_compression(a, bid, init));
}
@@ -187,13 +189,13 @@ bid(const void *buff, size_t len)
* Setup the callbacks.
*/
static int
-init(struct archive *a, const void *buff, size_t n)
+init(struct archive_read *a, const void *buff, size_t n)
{
struct private_data *state;
int code;
- a->compression_code = ARCHIVE_COMPRESSION_COMPRESS;
- a->compression_name = "compress (.Z)";
+ a->archive.compression_code = ARCHIVE_COMPRESSION_COMPRESS;
+ a->archive.compression_name = "compress (.Z)";
a->compression_read_ahead = read_ahead;
a->compression_read_consume = read_consume;
@@ -202,9 +204,9 @@ init(struct archive *a, const void *buff, size_t n)
state = (struct private_data *)malloc(sizeof(*state));
if (state == NULL) {
- archive_set_error(a, ENOMEM,
+ archive_set_error(&a->archive, ENOMEM,
"Can't allocate data for %s decompression",
- a->compression_name);
+ a->archive.compression_name);
return (ARCHIVE_FATAL);
}
memset(state, 0, sizeof(*state));
@@ -214,9 +216,9 @@ init(struct archive *a, const void *buff, size_t n)
state->uncompressed_buffer = malloc(state->uncompressed_buffer_size);
if (state->uncompressed_buffer == NULL) {
- archive_set_error(a, ENOMEM,
+ archive_set_error(&a->archive, ENOMEM,
"Can't allocate %s decompression buffers",
- a->compression_name);
+ a->archive.compression_name);
goto fatal;
}
@@ -235,7 +237,7 @@ init(struct archive *a, const void *buff, size_t n)
* blocks and gzip and compress are both enabled.
* You can't distinguish gzip and compress only from
* the first byte. */
- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Compress signature did not match.");
goto fatal;
}
@@ -270,7 +272,7 @@ fatal:
* as necessary.
*/
static ssize_t
-read_ahead(struct archive *a, const void **p, size_t min)
+read_ahead(struct archive_read *a, const void **p, size_t min)
{
struct private_data *state;
int read_avail, was_avail, ret;
@@ -278,7 +280,7 @@ read_ahead(struct archive *a, const void **p, size_t min)
state = (struct private_data *)a->compression_data;
was_avail = -1;
if (!a->client_reader) {
- archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"No read callback is registered? "
"This is probably an internal programming error.");
return (ARCHIVE_FATAL);
@@ -325,12 +327,12 @@ read_ahead(struct archive *a, const void **p, size_t min)
* Mark a previously-returned block of data as read.
*/
static ssize_t
-read_consume(struct archive *a, size_t n)
+read_consume(struct archive_read *a, size_t n)
{
struct private_data *state;
state = (struct private_data *)a->compression_data;
- a->file_position += n;
+ a->archive.file_position += n;
state->read_next += n;
if (state->read_next > state->next_out)
__archive_errx(1, "Request to consume too many "
@@ -342,7 +344,7 @@ read_consume(struct archive *a, size_t n)
* Clean up the decompressor.
*/
static int
-finish(struct archive *a)
+finish(struct archive_read *a)
{
struct private_data *state;
int ret = ARCHIVE_OK;
@@ -357,7 +359,7 @@ finish(struct archive *a)
a->compression_data = NULL;
if (a->client_closer != NULL)
- ret = (a->client_closer)(a, a->client_data);
+ ret = (a->client_closer)(&a->archive, a->client_data);
return (ret);
}
@@ -368,7 +370,7 @@ finish(struct archive *a)
* format error, ARCHIVE_EOF if we hit end of data, ARCHIVE_OK otherwise.
*/
static int
-next_code(struct archive *a, struct private_data *state)
+next_code(struct archive_read *a, struct private_data *state)
{
int code, newcode;
@@ -412,7 +414,7 @@ next_code(struct archive *a, struct private_data *state)
if (code > state->free_ent) {
/* An invalid code is a fatal error. */
- archive_set_error(a, -1, "Invalid compressed data");
+ archive_set_error(&a->archive, -1, "Invalid compressed data");
return (ARCHIVE_FATAL);
}
@@ -456,7 +458,7 @@ next_code(struct archive *a, struct private_data *state)
* -1 indicates end of available data.
*/
static int
-getbits(struct archive *a, struct private_data *state, int n)
+getbits(struct archive_read *a, struct private_data *state, int n)
{
int code, ret;
static const int mask[] = {
@@ -467,13 +469,13 @@ getbits(struct archive *a, struct private_data *state, int n)
while (state->bits_avail < n) {
if (state->avail_in <= 0) {
- ret = (a->client_reader)(a, a->client_data,
+ ret = (a->client_reader)(&a->archive, a->client_data,
(const void **)&state->next_in);
if (ret < 0)
return (ARCHIVE_FATAL);
if (ret == 0)
return (ARCHIVE_EOF);
- a->raw_position += ret;
+ a->archive.raw_position += ret;
state->avail_in = ret;
}
state->bit_buffer |= *state->next_in++ << state->bits_avail;
diff --git a/lib/libarchive/archive_read_support_compression_gzip.c b/lib/libarchive/archive_read_support_compression_gzip.c
index b64e1d2..49e209d 100644
--- a/lib/libarchive/archive_read_support_compression_gzip.c
+++ b/lib/libarchive/archive_read_support_compression_gzip.c
@@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_private.h"
+#include "archive_read_private.h"
#ifdef HAVE_ZLIB_H
struct private_data {
@@ -58,19 +59,20 @@ struct private_data {
char header_done;
};
-static int finish(struct archive *);
-static ssize_t read_ahead(struct archive *, const void **, size_t);
-static ssize_t read_consume(struct archive *, size_t);
-static int drive_decompressor(struct archive *a, struct private_data *);
+static int finish(struct archive_read *);
+static ssize_t read_ahead(struct archive_read *, const void **, size_t);
+static ssize_t read_consume(struct archive_read *, size_t);
+static int drive_decompressor(struct archive_read *a, struct private_data *);
#endif
/* These two functions are defined even if we lack zlib. See below. */
static int bid(const void *, size_t);
-static int init(struct archive *, const void *, size_t);
+static int init(struct archive_read *, const void *, size_t);
int
-archive_read_support_compression_gzip(struct archive *a)
+archive_read_support_compression_gzip(struct archive *_a)
{
+ struct archive_read *a = (struct archive_read *)_a;
return (__archive_read_register_compression(a, bid, init));
}
@@ -135,7 +137,7 @@ bid(const void *buff, size_t len)
* archives and emit a useful message.
*/
static int
-init(struct archive *a, const void *buff, size_t n)
+init(struct archive_read *a, const void *buff, size_t n)
{
(void)a; /* UNUSED */
(void)buff; /* UNUSED */
@@ -153,19 +155,19 @@ init(struct archive *a, const void *buff, size_t n)
* Setup the callbacks.
*/
static int
-init(struct archive *a, const void *buff, size_t n)
+init(struct archive_read *a, const void *buff, size_t n)
{
struct private_data *state;
int ret;
- a->compression_code = ARCHIVE_COMPRESSION_GZIP;
- a->compression_name = "gzip";
+ a->archive.compression_code = ARCHIVE_COMPRESSION_GZIP;
+ a->archive.compression_name = "gzip";
state = (struct private_data *)malloc(sizeof(*state));
if (state == NULL) {
- archive_set_error(a, ENOMEM,
+ archive_set_error(&a->archive, ENOMEM,
"Can't allocate data for %s decompression",
- a->compression_name);
+ a->archive.compression_name);
return (ARCHIVE_FATAL);
}
memset(state, 0, sizeof(*state));
@@ -180,9 +182,9 @@ init(struct archive *a, const void *buff, size_t n)
state->stream.avail_out = state->uncompressed_buffer_size;
if (state->uncompressed_buffer == NULL) {
- archive_set_error(a, ENOMEM,
+ archive_set_error(&a->archive, ENOMEM,
"Can't allocate %s decompression buffers",
- a->compression_name);
+ a->archive.compression_name);
free(state);
return (ARCHIVE_FATAL);
}
@@ -220,25 +222,26 @@ init(struct archive *a, const void *buff, size_t n)
}
/* Library setup failed: Clean up. */
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "Internal error initializing %s library", a->compression_name);
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Internal error initializing %s library",
+ a->archive.compression_name);
free(state->uncompressed_buffer);
free(state);
/* Override the error message if we know what really went wrong. */
switch (ret) {
case Z_STREAM_ERROR:
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Internal error initializing compression library: "
"invalid setup parameter");
break;
case Z_MEM_ERROR:
- archive_set_error(a, ENOMEM,
+ archive_set_error(&a->archive, ENOMEM,
"Internal error initializing compression library: "
"out of memory");
break;
case Z_VERSION_ERROR:
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Internal error initializing compression library: "
"invalid library version");
break;
@@ -252,7 +255,7 @@ init(struct archive *a, const void *buff, size_t n)
* as necessary.
*/
static ssize_t
-read_ahead(struct archive *a, const void **p, size_t min)
+read_ahead(struct archive_read *a, const void **p, size_t min)
{
struct private_data *state;
int read_avail, was_avail, ret;
@@ -260,7 +263,7 @@ read_ahead(struct archive *a, const void **p, size_t min)
state = (struct private_data *)a->compression_data;
was_avail = -1;
if (!a->client_reader) {
- archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"No read callback is registered? "
"This is probably an internal programming error.");
return (ARCHIVE_FATAL);
@@ -294,12 +297,12 @@ read_ahead(struct archive *a, const void **p, size_t min)
* Mark a previously-returned block of data as read.
*/
static ssize_t
-read_consume(struct archive *a, size_t n)
+read_consume(struct archive_read *a, size_t n)
{
struct private_data *state;
state = (struct private_data *)a->compression_data;
- a->file_position += n;
+ a->archive.file_position += n;
state->read_next += n;
if (state->read_next > state->stream.next_out)
__archive_errx(1, "Request to consume too many "
@@ -311,7 +314,7 @@ read_consume(struct archive *a, size_t n)
* Clean up the decompressor.
*/
static int
-finish(struct archive *a)
+finish(struct archive_read *a)
{
struct private_data *state;
int ret;
@@ -322,8 +325,9 @@ finish(struct archive *a)
case Z_OK:
break;
default:
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
- "Failed to clean up %s compressor", a->compression_name);
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Failed to clean up %s compressor",
+ a->archive.compression_name);
ret = ARCHIVE_FATAL;
}
@@ -332,7 +336,7 @@ finish(struct archive *a)
a->compression_data = NULL;
if (a->client_closer != NULL)
- (a->client_closer)(a, a->client_data);
+ (a->client_closer)(&a->archive, a->client_data);
return (ret);
}
@@ -342,7 +346,7 @@ finish(struct archive *a)
* blocks as necessary.
*/
static int
-drive_decompressor(struct archive *a, struct private_data *state)
+drive_decompressor(struct archive_read *a, struct private_data *state)
{
ssize_t ret;
int decompressed, total_decompressed;
@@ -356,7 +360,7 @@ drive_decompressor(struct archive *a, struct private_data *state)
total_decompressed = 0;
for (;;) {
if (state->stream.avail_in == 0) {
- ret = (a->client_reader)(a, a->client_data,
+ ret = (a->client_reader)(&a->archive, a->client_data,
(const void **)&state->stream.next_in);
if (ret < 0) {
/*
@@ -366,12 +370,12 @@ drive_decompressor(struct archive *a, struct private_data *state)
goto fatal;
}
if (ret == 0 && total_decompressed == 0) {
- archive_set_error(a, EIO,
+ archive_set_error(&a->archive, EIO,
"Premature end of %s compressed data",
- a->compression_name);
+ a->archive.compression_name);
return (ARCHIVE_FATAL);
}
- a->raw_position += ret;
+ a->archive.raw_position += ret;
state->stream.avail_in = ret;
}
@@ -520,7 +524,7 @@ drive_decompressor(struct archive *a, struct private_data *state)
return (ARCHIVE_OK);
default:
/* Any other return value is an error. */
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"gzip decompression failed (%s)",
state->stream.msg);
goto fatal;
@@ -531,8 +535,8 @@ drive_decompressor(struct archive *a, struct private_data *state)
/* Return a fatal error. */
fatal:
- archive_set_error(a, ARCHIVE_ERRNO_MISC, "%s decompression failed",
- a->compression_name);
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "%s decompression failed", a->archive.compression_name);
return (ARCHIVE_FATAL);
}
diff --git a/lib/libarchive/archive_read_support_compression_none.c b/lib/libarchive/archive_read_support_compression_none.c
index 1109488..72328a3 100644
--- a/lib/libarchive/archive_read_support_compression_none.c
+++ b/lib/libarchive/archive_read_support_compression_none.c
@@ -26,7 +26,6 @@
#include "archive_platform.h"
__FBSDID("$FreeBSD$");
-#include <assert.h>
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
@@ -45,6 +44,7 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_private.h"
+#include "archive_read_private.h"
struct archive_decompress_none {
char *buffer;
@@ -75,18 +75,19 @@ struct archive_decompress_none {
#define minimum(a, b) (a < b ? a : b)
static int archive_decompressor_none_bid(const void *, size_t);
-static int archive_decompressor_none_finish(struct archive *);
-static int archive_decompressor_none_init(struct archive *,
+static int archive_decompressor_none_finish(struct archive_read *);
+static int archive_decompressor_none_init(struct archive_read *,
const void *, size_t);
-static ssize_t archive_decompressor_none_read_ahead(struct archive *,
+static ssize_t archive_decompressor_none_read_ahead(struct archive_read *,
const void **, size_t);
-static ssize_t archive_decompressor_none_read_consume(struct archive *,
+static ssize_t archive_decompressor_none_read_consume(struct archive_read *,
size_t);
-static off_t archive_decompressor_none_skip(struct archive *, off_t);
+static off_t archive_decompressor_none_skip(struct archive_read *, off_t);
int
-archive_read_support_compression_none(struct archive *a)
+archive_read_support_compression_none(struct archive *_a)
{
+ struct archive_read *a = (struct archive_read *)_a;
return (__archive_read_register_compression(a,
archive_decompressor_none_bid,
archive_decompressor_none_init));
@@ -105,16 +106,16 @@ archive_decompressor_none_bid(const void *buff, size_t len)
}
static int
-archive_decompressor_none_init(struct archive *a, const void *buff, size_t n)
+archive_decompressor_none_init(struct archive_read *a, const void *buff, size_t n)
{
struct archive_decompress_none *state;
- a->compression_code = ARCHIVE_COMPRESSION_NONE;
- a->compression_name = "none";
+ a->archive.compression_code = ARCHIVE_COMPRESSION_NONE;
+ a->archive.compression_name = "none";
state = (struct archive_decompress_none *)malloc(sizeof(*state));
if (!state) {
- archive_set_error(a, ENOMEM, "Can't allocate input data");
+ archive_set_error(&a->archive, ENOMEM, "Can't allocate input data");
return (ARCHIVE_FATAL);
}
memset(state, 0, sizeof(*state));
@@ -124,7 +125,7 @@ archive_decompressor_none_init(struct archive *a, const void *buff, size_t n)
state->next = state->buffer;
if (state->buffer == NULL) {
free(state);
- archive_set_error(a, ENOMEM, "Can't allocate input buffer");
+ archive_set_error(&a->archive, ENOMEM, "Can't allocate input buffer");
return (ARCHIVE_FATAL);
}
@@ -149,7 +150,7 @@ archive_decompressor_none_init(struct archive *a, const void *buff, size_t n)
* buffer to combine reads.
*/
static ssize_t
-archive_decompressor_none_read_ahead(struct archive *a, const void **buff,
+archive_decompressor_none_read_ahead(struct archive_read *a, const void **buff,
size_t min)
{
struct archive_decompress_none *state;
@@ -217,7 +218,8 @@ archive_decompressor_none_read_ahead(struct archive *a, const void **buff,
* char ** should be compatible, but they
* aren't, hence the cast.
*/
- bytes_read = (a->client_reader)(a, a->client_data,
+ bytes_read = (a->client_reader)(&a->archive,
+ a->client_data,
(const void **)&state->client_buff);
if (bytes_read < 0) { /* Read error. */
state->client_total = state->client_avail = 0;
@@ -231,7 +233,7 @@ archive_decompressor_none_read_ahead(struct archive *a, const void **buff,
state->end_of_file = 1;
break;
}
- a->raw_position += bytes_read;
+ a->archive.raw_position += bytes_read;
state->client_total = bytes_read;
state->client_avail = state->client_total;
state->client_next = state->client_buff;
@@ -248,7 +250,7 @@ archive_decompressor_none_read_ahead(struct archive *a, const void **buff,
* request.
*/
static ssize_t
-archive_decompressor_none_read_consume(struct archive *a, size_t request)
+archive_decompressor_none_read_consume(struct archive_read *a, size_t request)
{
struct archive_decompress_none *state;
@@ -262,7 +264,7 @@ archive_decompressor_none_read_consume(struct archive *a, size_t request)
state->client_next += request;
state->client_avail -= request;
}
- a->file_position += request;
+ a->archive.file_position += request;
return (request);
}
@@ -272,7 +274,7 @@ archive_decompressor_none_read_consume(struct archive *a, size_t request)
* read_ahead, which does not guarantee a minimum count.
*/
static off_t
-archive_decompressor_none_skip(struct archive *a, off_t request)
+archive_decompressor_none_skip(struct archive_read *a, off_t request)
{
struct archive_decompress_none *state;
off_t bytes_skipped, total_bytes_skipped = 0;
@@ -306,8 +308,8 @@ archive_decompressor_none_skip(struct archive *a, off_t request)
#else
if (a->client_skipper != NULL) {
#endif
- bytes_skipped = (a->client_skipper)(a, a->client_data,
- request);
+ bytes_skipped = (a->client_skipper)(&a->archive,
+ a->client_data, request);
if (bytes_skipped < 0) { /* error */
state->client_total = state->client_avail = 0;
state->client_next = state->client_buff = NULL;
@@ -315,10 +317,10 @@ archive_decompressor_none_skip(struct archive *a, off_t request)
return (bytes_skipped);
}
total_bytes_skipped += bytes_skipped;
- a->file_position += bytes_skipped;
+ a->archive.file_position += bytes_skipped;
request -= bytes_skipped;
state->client_next = state->client_buff;
- a->raw_position += bytes_skipped;
+ a->archive.raw_position += bytes_skipped;
state->client_avail = state->client_total = 0;
}
/*
@@ -336,23 +338,21 @@ archive_decompressor_none_skip(struct archive *a, off_t request)
return (bytes_read);
if (bytes_read == 0) {
/* We hit EOF before we satisfied the skip request. */
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Truncated input file (need to skip %jd bytes)",
(intmax_t)request);
return (ARCHIVE_FATAL);
}
- assert(bytes_read >= 0); /* precondition for cast below */
min = (size_t)(minimum(bytes_read, request));
bytes_read = archive_decompressor_none_read_consume(a, min);
total_bytes_skipped += bytes_read;
request -= bytes_read;
}
- assert(request == 0);
return (total_bytes_skipped);
}
static int
-archive_decompressor_none_finish(struct archive *a)
+archive_decompressor_none_finish(struct archive_read *a)
{
struct archive_decompress_none *state;
@@ -361,6 +361,6 @@ archive_decompressor_none_finish(struct archive *a)
free(state);
a->compression_data = NULL;
if (a->client_closer != NULL)
- return ((a->client_closer)(a, a->client_data));
+ return ((a->client_closer)(&a->archive, a->client_data));
return (ARCHIVE_OK);
}
diff --git a/lib/libarchive/archive_read_support_format_cpio.c b/lib/libarchive/archive_read_support_format_cpio.c
index 12e24a1..3a0f334 100644
--- a/lib/libarchive/archive_read_support_format_cpio.c
+++ b/lib/libarchive/archive_read_support_format_cpio.c
@@ -50,6 +50,7 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_entry.h"
#include "archive_private.h"
+#include "archive_read_private.h"
struct cpio_bin_header {
unsigned char c_magic[2];
@@ -108,7 +109,7 @@ struct links_entry {
#define CPIO_MAGIC 0x13141516
struct cpio {
int magic;
- int (*read_header)(struct archive *, struct cpio *,
+ int (*read_header)(struct archive_read *, struct cpio *,
struct stat *, size_t *, size_t *);
struct links_entry *links_head;
struct archive_string entry_name;
@@ -120,34 +121,35 @@ struct cpio {
static int64_t atol16(const char *, unsigned);
static int64_t atol8(const char *, unsigned);
-static int archive_read_format_cpio_bid(struct archive *);
-static int archive_read_format_cpio_cleanup(struct archive *);
-static int archive_read_format_cpio_read_data(struct archive *,
+static int archive_read_format_cpio_bid(struct archive_read *);
+static int archive_read_format_cpio_cleanup(struct archive_read *);
+static int archive_read_format_cpio_read_data(struct archive_read *,
const void **, size_t *, off_t *);
-static int archive_read_format_cpio_read_header(struct archive *,
+static int archive_read_format_cpio_read_header(struct archive_read *,
struct archive_entry *);
static int be4(const unsigned char *);
-static int header_bin_be(struct archive *, struct cpio *, struct stat *,
+static int header_bin_be(struct archive_read *, struct cpio *, struct stat *,
size_t *, size_t *);
-static int header_bin_le(struct archive *, struct cpio *, struct stat *,
+static int header_bin_le(struct archive_read *, struct cpio *, struct stat *,
size_t *, size_t *);
-static int header_newc(struct archive *, struct cpio *, struct stat *,
+static int header_newc(struct archive_read *, struct cpio *, struct stat *,
size_t *, size_t *);
-static int header_odc(struct archive *, struct cpio *, struct stat *,
+static int header_odc(struct archive_read *, struct cpio *, struct stat *,
size_t *, size_t *);
static int le4(const unsigned char *);
static void record_hardlink(struct cpio *cpio, struct archive_entry *entry,
const struct stat *st);
int
-archive_read_support_format_cpio(struct archive *a)
+archive_read_support_format_cpio(struct archive *_a)
{
+ struct archive_read *a = (struct archive_read *)_a;
struct cpio *cpio;
int r;
cpio = (struct cpio *)malloc(sizeof(*cpio));
if (cpio == NULL) {
- archive_set_error(a, ENOMEM, "Can't allocate cpio data");
+ archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data");
return (ARCHIVE_FATAL);
}
memset(cpio, 0, sizeof(*cpio));
@@ -168,7 +170,7 @@ archive_read_support_format_cpio(struct archive *a)
static int
-archive_read_format_cpio_bid(struct archive *a)
+archive_read_format_cpio_bid(struct archive_read *a)
{
int bid, bytes_read;
const void *h;
@@ -227,7 +229,7 @@ archive_read_format_cpio_bid(struct archive *a)
}
static int
-archive_read_format_cpio_read_header(struct archive *a,
+archive_read_format_cpio_read_header(struct archive_read *a,
struct archive_entry *entry)
{
struct stat st;
@@ -274,7 +276,7 @@ archive_read_format_cpio_read_header(struct archive *a,
/* Compare name to "TRAILER!!!" to test for end-of-archive. */
if (namelength == 11 && strcmp((const char *)h, "TRAILER!!!") == 0) {
/* TODO: Store file location of start of block. */
- archive_set_error(a, 0, NULL);
+ archive_set_error(&a->archive, 0, NULL);
return (ARCHIVE_EOF);
}
@@ -285,7 +287,7 @@ archive_read_format_cpio_read_header(struct archive *a,
}
static int
-archive_read_format_cpio_read_data(struct archive *a,
+archive_read_format_cpio_read_data(struct archive_read *a,
const void **buff, size_t *size, off_t *offset)
{
ssize_t bytes_read;
@@ -322,7 +324,7 @@ archive_read_format_cpio_read_data(struct archive *a,
}
static int
-header_newc(struct archive *a, struct cpio *cpio, struct stat *st,
+header_newc(struct archive_read *a, struct cpio *cpio, struct stat *st,
size_t *namelength, size_t *name_pad)
{
const void *h;
@@ -339,11 +341,11 @@ header_newc(struct archive *a, struct cpio *cpio, struct stat *st,
header = (const struct cpio_newc_header *)h;
if (memcmp(header->c_magic, "070701", 6) == 0) {
- a->archive_format = ARCHIVE_FORMAT_CPIO_SVR4_NOCRC;
- a->archive_format_name = "ASCII cpio (SVR4 with no CRC)";
+ a->archive.archive_format = ARCHIVE_FORMAT_CPIO_SVR4_NOCRC;
+ a->archive.archive_format_name = "ASCII cpio (SVR4 with no CRC)";
} else if (memcmp(header->c_magic, "070702", 6) == 0) {
- a->archive_format = ARCHIVE_FORMAT_CPIO_SVR4_CRC;
- a->archive_format_name = "ASCII cpio (SVR4 with CRC)";
+ a->archive.archive_format = ARCHIVE_FORMAT_CPIO_SVR4_CRC;
+ a->archive.archive_format_name = "ASCII cpio (SVR4 with CRC)";
} else {
/* TODO: Abort here? */
}
@@ -379,15 +381,15 @@ header_newc(struct archive *a, struct cpio *cpio, struct stat *st,
}
static int
-header_odc(struct archive *a, struct cpio *cpio, struct stat *st,
+header_odc(struct archive_read *a, struct cpio *cpio, struct stat *st,
size_t *namelength, size_t *name_pad)
{
const void *h;
const struct cpio_odc_header *header;
size_t bytes;
- a->archive_format = ARCHIVE_FORMAT_CPIO_POSIX;
- a->archive_format_name = "POSIX octet-oriented cpio";
+ a->archive.archive_format = ARCHIVE_FORMAT_CPIO_POSIX;
+ a->archive.archive_format_name = "POSIX octet-oriented cpio";
/* Read fixed-size portion of header. */
bytes = (a->compression_read_ahead)(a, &h, sizeof(struct cpio_odc_header));
@@ -423,15 +425,15 @@ header_odc(struct archive *a, struct cpio *cpio, struct stat *st,
}
static int
-header_bin_le(struct archive *a, struct cpio *cpio, struct stat *st,
+header_bin_le(struct archive_read *a, struct cpio *cpio, struct stat *st,
size_t *namelength, size_t *name_pad)
{
const void *h;
const struct cpio_bin_header *header;
size_t bytes;
- a->archive_format = ARCHIVE_FORMAT_CPIO_BIN_LE;
- a->archive_format_name = "cpio (little-endian binary)";
+ a->archive.archive_format = ARCHIVE_FORMAT_CPIO_BIN_LE;
+ a->archive.archive_format_name = "cpio (little-endian binary)";
/* Read fixed-size portion of header. */
bytes = (a->compression_read_ahead)(a, &h, sizeof(struct cpio_bin_header));
@@ -460,15 +462,15 @@ header_bin_le(struct archive *a, struct cpio *cpio, struct stat *st,
}
static int
-header_bin_be(struct archive *a, struct cpio *cpio, struct stat *st,
+header_bin_be(struct archive_read *a, struct cpio *cpio, struct stat *st,
size_t *namelength, size_t *name_pad)
{
const void *h;
const struct cpio_bin_header *header;
size_t bytes;
- a->archive_format = ARCHIVE_FORMAT_CPIO_BIN_BE;
- a->archive_format_name = "cpio (big-endian binary)";
+ a->archive.archive_format = ARCHIVE_FORMAT_CPIO_BIN_BE;
+ a->archive.archive_format_name = "cpio (big-endian binary)";
/* Read fixed-size portion of header. */
bytes = (a->compression_read_ahead)(a, &h,
@@ -497,7 +499,7 @@ header_bin_be(struct archive *a, struct cpio *cpio, struct stat *st,
}
static int
-archive_read_format_cpio_cleanup(struct archive *a)
+archive_read_format_cpio_cleanup(struct archive_read *a)
{
struct cpio *cpio;
diff --git a/lib/libarchive/archive_read_support_format_empty.c b/lib/libarchive/archive_read_support_format_empty.c
index 2df2194..f729ae6 100644
--- a/lib/libarchive/archive_read_support_format_empty.c
+++ b/lib/libarchive/archive_read_support_format_empty.c
@@ -29,15 +29,17 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_entry.h"
#include "archive_private.h"
+#include "archive_read_private.h"
-static int archive_read_format_empty_bid(struct archive *);
-static int archive_read_format_empty_read_data(struct archive *,
+static int archive_read_format_empty_bid(struct archive_read *);
+static int archive_read_format_empty_read_data(struct archive_read *,
const void **, size_t *, off_t *);
-static int archive_read_format_empty_read_header(struct archive *,
+static int archive_read_format_empty_read_header(struct archive_read *,
struct archive_entry *);
int
-archive_read_support_format_empty(struct archive *a)
+archive_read_support_format_empty(struct archive *_a)
{
+ struct archive_read *a = (struct archive_read *)_a;
int r;
r = __archive_read_register_format(a,
@@ -53,7 +55,7 @@ archive_read_support_format_empty(struct archive *a)
static int
-archive_read_format_empty_bid(struct archive *a)
+archive_read_format_empty_bid(struct archive_read *a)
{
int bytes_read;
const void *h;
@@ -65,20 +67,20 @@ archive_read_format_empty_bid(struct archive *a)
}
static int
-archive_read_format_empty_read_header(struct archive *a,
+archive_read_format_empty_read_header(struct archive_read *a,
struct archive_entry *entry)
{
(void)a; /* UNUSED */
(void)entry; /* UNUSED */
- a->archive_format = ARCHIVE_FORMAT_EMPTY;
- a->archive_format_name = "Empty file";
+ a->archive.archive_format = ARCHIVE_FORMAT_EMPTY;
+ a->archive.archive_format_name = "Empty file";
return (ARCHIVE_EOF);
}
static int
-archive_read_format_empty_read_data(struct archive *a,
+archive_read_format_empty_read_data(struct archive_read *a,
const void **buff, size_t *size, off_t *offset)
{
(void)a; /* UNUSED */
diff --git a/lib/libarchive/archive_read_support_format_iso9660.c b/lib/libarchive/archive_read_support_format_iso9660.c
index a2dc6fd..f115b0e 100644
--- a/lib/libarchive/archive_read_support_format_iso9660.c
+++ b/lib/libarchive/archive_read_support_format_iso9660.c
@@ -49,6 +49,7 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_entry.h"
#include "archive_private.h"
+#include "archive_read_private.h"
#include "archive_string.h"
/*
@@ -222,12 +223,12 @@ struct iso9660 {
};
static void add_entry(struct iso9660 *iso9660, struct file_info *file);
-static int archive_read_format_iso9660_bid(struct archive *);
-static int archive_read_format_iso9660_cleanup(struct archive *);
-static int archive_read_format_iso9660_read_data(struct archive *,
+static int archive_read_format_iso9660_bid(struct archive_read *);
+static int archive_read_format_iso9660_cleanup(struct archive_read *);
+static int archive_read_format_iso9660_read_data(struct archive_read *,
const void **, size_t *, off_t *);
-static int archive_read_format_iso9660_read_data_skip(struct archive *);
-static int archive_read_format_iso9660_read_header(struct archive *,
+static int archive_read_format_iso9660_read_data_skip(struct archive_read *);
+static int archive_read_format_iso9660_read_header(struct archive_read *,
struct archive_entry *);
static const char *build_pathname(struct archive_string *, struct file_info *);
static void dump_isodirrec(FILE *, const unsigned char *isodirrec);
@@ -236,7 +237,7 @@ static time_t isodate17(const unsigned char *);
static time_t isodate7(const unsigned char *);
static int isPVD(struct iso9660 *, const unsigned char *);
static struct file_info *next_entry(struct iso9660 *);
-static int next_entry_seek(struct archive *a, struct iso9660 *iso9660,
+static int next_entry_seek(struct archive_read *a, struct iso9660 *iso9660,
struct file_info **pfile);
static struct file_info *
parse_file_info(struct iso9660 *iso9660,
@@ -248,14 +249,15 @@ static void release_file(struct iso9660 *, struct file_info *);
static unsigned toi(const void *p, int n);
int
-archive_read_support_format_iso9660(struct archive *a)
+archive_read_support_format_iso9660(struct archive *_a)
{
+ struct archive_read *a = (struct archive_read *)_a;
struct iso9660 *iso9660;
int r;
iso9660 = (struct iso9660 *)malloc(sizeof(*iso9660));
if (iso9660 == NULL) {
- archive_set_error(a, ENOMEM, "Can't allocate iso9660 data");
+ archive_set_error(&a->archive, ENOMEM, "Can't allocate iso9660 data");
return (ARCHIVE_FATAL);
}
memset(iso9660, 0, sizeof(*iso9660));
@@ -279,7 +281,7 @@ archive_read_support_format_iso9660(struct archive *a)
static int
-archive_read_format_iso9660_bid(struct archive *a)
+archive_read_format_iso9660_bid(struct archive_read *a)
{
struct iso9660 *iso9660;
ssize_t bytes_read;
@@ -338,7 +340,7 @@ isPVD(struct iso9660 *iso9660, const unsigned char *h)
}
static int
-archive_read_format_iso9660_read_header(struct archive *a,
+archive_read_format_iso9660_read_header(struct archive_read *a,
struct archive_entry *entry)
{
struct stat st;
@@ -349,9 +351,9 @@ archive_read_format_iso9660_read_header(struct archive *a,
iso9660 = (struct iso9660 *)*(a->pformat_data);
- if (!a->archive_format) {
- a->archive_format = ARCHIVE_FORMAT_ISO9660;
- a->archive_format_name = "ISO9660";
+ if (!a->archive.archive_format) {
+ a->archive.archive_format = ARCHIVE_FORMAT_ISO9660;
+ a->archive.archive_format_name = "ISO9660";
}
/* Get the next entry that appears after the current offset. */
@@ -397,7 +399,7 @@ archive_read_format_iso9660_read_header(struct archive *a,
/* If the offset is before our current position, we can't
* seek backwards to extract it, so issue a warning. */
if (file->offset < iso9660->current_position) {
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Ignoring out-of-order file");
iso9660->entry_bytes_remaining = 0;
iso9660->entry_sparse_offset = 0;
@@ -419,7 +421,7 @@ archive_read_format_iso9660_read_header(struct archive *a,
step = iso9660->entry_bytes_remaining;
bytes_read = (a->compression_read_ahead)(a, &block, step);
if (bytes_read < step) {
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Failed to read full block when scanning ISO9660 directory list");
release_file(iso9660, file);
return (ARCHIVE_FATAL);
@@ -445,9 +447,9 @@ archive_read_format_iso9660_read_header(struct archive *a,
child = parse_file_info(iso9660, file, p);
add_entry(iso9660, child);
if (iso9660->seenRockridge) {
- a->archive_format =
+ a->archive.archive_format =
ARCHIVE_FORMAT_ISO9660_ROCKRIDGE;
- a->archive_format_name =
+ a->archive.archive_format_name =
"ISO9660 with Rockridge extensions";
}
}
@@ -459,7 +461,7 @@ archive_read_format_iso9660_read_header(struct archive *a,
}
static int
-archive_read_format_iso9660_read_data_skip(struct archive *a)
+archive_read_format_iso9660_read_data_skip(struct archive_read *a)
{
/* Because read_next_header always does an explicit skip
* to the next entry, we don't need to do anything here. */
@@ -468,7 +470,7 @@ archive_read_format_iso9660_read_data_skip(struct archive *a)
}
static int
-archive_read_format_iso9660_read_data(struct archive *a,
+archive_read_format_iso9660_read_data(struct archive_read *a,
const void **buff, size_t *size, off_t *offset)
{
ssize_t bytes_read;
@@ -484,7 +486,7 @@ archive_read_format_iso9660_read_data(struct archive *a,
bytes_read = (a->compression_read_ahead)(a, buff, 1);
if (bytes_read == 0)
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Truncated input file");
if (bytes_read <= 0)
return (ARCHIVE_FATAL);
@@ -500,7 +502,7 @@ archive_read_format_iso9660_read_data(struct archive *a,
}
static int
-archive_read_format_iso9660_cleanup(struct archive *a)
+archive_read_format_iso9660_cleanup(struct archive_read *a)
{
struct iso9660 *iso9660;
struct file_info *file;
@@ -889,7 +891,7 @@ release_file(struct iso9660 *iso9660, struct file_info *file)
}
static int
-next_entry_seek(struct archive *a, struct iso9660 *iso9660,
+next_entry_seek(struct archive_read *a, struct iso9660 *iso9660,
struct file_info **pfile)
{
struct file_info *file;
diff --git a/lib/libarchive/archive_read_support_format_tar.c b/lib/libarchive/archive_read_support_format_tar.c
index 1934d55..8aa5a38 100644
--- a/lib/libarchive/archive_read_support_format_tar.c
+++ b/lib/libarchive/archive_read_support_format_tar.c
@@ -83,6 +83,7 @@ static size_t wcslen(const wchar_t *s)
#include "archive.h"
#include "archive_entry.h"
#include "archive_private.h"
+#include "archive_read_private.h"
/*
* Layout of POSIX 'ustar' tar header.
@@ -174,50 +175,50 @@ struct tar {
static size_t UTF8_mbrtowc(wchar_t *pwc, const char *s, size_t n);
static int archive_block_is_null(const unsigned char *p);
static char *base64_decode(const wchar_t *, size_t, size_t *);
-static int gnu_read_sparse_data(struct archive *, struct tar *,
+static int gnu_read_sparse_data(struct archive_read *, struct tar *,
const struct archive_entry_header_gnutar *header);
-static void gnu_parse_sparse_data(struct archive *, struct tar *,
+static void gnu_parse_sparse_data(struct archive_read *, struct tar *,
const struct gnu_sparse *sparse, int length);
-static int header_Solaris_ACL(struct archive *, struct tar *,
+static int header_Solaris_ACL(struct archive_read *, struct tar *,
struct archive_entry *, struct stat *, const void *);
-static int header_common(struct archive *, struct tar *,
+static int header_common(struct archive_read *, struct tar *,
struct archive_entry *, struct stat *, const void *);
-static int header_old_tar(struct archive *, struct tar *,
+static int header_old_tar(struct archive_read *, struct tar *,
struct archive_entry *, struct stat *, const void *);
-static int header_pax_extensions(struct archive *, struct tar *,
+static int header_pax_extensions(struct archive_read *, struct tar *,
struct archive_entry *, struct stat *, const void *);
-static int header_pax_global(struct archive *, struct tar *,
+static int header_pax_global(struct archive_read *, struct tar *,
struct archive_entry *, struct stat *, const void *h);
-static int header_longlink(struct archive *, struct tar *,
+static int header_longlink(struct archive_read *, struct tar *,
struct archive_entry *, struct stat *, const void *h);
-static int header_longname(struct archive *, struct tar *,
+static int header_longname(struct archive_read *, struct tar *,
struct archive_entry *, struct stat *, const void *h);
-static int header_volume(struct archive *, struct tar *,
+static int header_volume(struct archive_read *, struct tar *,
struct archive_entry *, struct stat *, const void *h);
-static int header_ustar(struct archive *, struct tar *,
+static int header_ustar(struct archive_read *, struct tar *,
struct archive_entry *, struct stat *, const void *h);
-static int header_gnutar(struct archive *, struct tar *,
+static int header_gnutar(struct archive_read *, struct tar *,
struct archive_entry *, struct stat *, const void *h);
-static int archive_read_format_tar_bid(struct archive *);
-static int archive_read_format_tar_cleanup(struct archive *);
-static int archive_read_format_tar_read_data(struct archive *a,
+static int archive_read_format_tar_bid(struct archive_read *);
+static int archive_read_format_tar_cleanup(struct archive_read *);
+static int archive_read_format_tar_read_data(struct archive_read *a,
const void **buff, size_t *size, off_t *offset);
-static int archive_read_format_tar_skip(struct archive *a);
-static int archive_read_format_tar_read_header(struct archive *,
+static int archive_read_format_tar_skip(struct archive_read *a);
+static int archive_read_format_tar_read_header(struct archive_read *,
struct archive_entry *);
-static int checksum(struct archive *, const void *);
+static int checksum(struct archive_read *, const void *);
static int pax_attribute(struct archive_entry *, struct stat *,
wchar_t *key, wchar_t *value);
-static int pax_header(struct archive *, struct tar *,
+static int pax_header(struct archive_read *, struct tar *,
struct archive_entry *, struct stat *, char *attr);
static void pax_time(const wchar_t *, int64_t *sec, long *nanos);
-static int read_body_to_string(struct archive *, struct tar *,
+static int read_body_to_string(struct archive_read *, struct tar *,
struct archive_string *, const void *h);
static int64_t tar_atol(const char *, unsigned);
static int64_t tar_atol10(const wchar_t *, unsigned);
static int64_t tar_atol256(const char *, unsigned);
static int64_t tar_atol8(const char *, unsigned);
-static int tar_read_header(struct archive *, struct tar *,
+static int tar_read_header(struct archive_read *, struct tar *,
struct archive_entry *, struct stat *);
static int tohex(int c);
static char *url_decode(const char *);
@@ -254,14 +255,16 @@ archive_read_support_format_gnutar(struct archive *a)
int
-archive_read_support_format_tar(struct archive *a)
+archive_read_support_format_tar(struct archive *_a)
{
+ struct archive_read *a = (struct archive_read *)_a;
struct tar *tar;
int r;
tar = (struct tar *)malloc(sizeof(*tar));
if (tar == NULL) {
- archive_set_error(a, ENOMEM, "Can't allocate tar data");
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate tar data");
return (ARCHIVE_FATAL);
}
memset(tar, 0, sizeof(*tar));
@@ -279,7 +282,7 @@ archive_read_support_format_tar(struct archive *a)
}
static int
-archive_read_format_tar_cleanup(struct archive *a)
+archive_read_format_tar_cleanup(struct archive_read *a)
{
struct tar *tar;
@@ -300,7 +303,7 @@ archive_read_format_tar_cleanup(struct archive *a)
static int
-archive_read_format_tar_bid(struct archive *a)
+archive_read_format_tar_bid(struct archive_read *a)
{
int bid;
ssize_t bytes_read;
@@ -311,8 +314,8 @@ archive_read_format_tar_bid(struct archive *a)
* If we're already reading a non-tar file, don't
* bother to bid.
*/
- if (a->archive_format != 0 &&
- (a->archive_format & ARCHIVE_FORMAT_BASE_MASK) !=
+ if (a->archive.archive_format != 0 &&
+ (a->archive.archive_format & ARCHIVE_FORMAT_BASE_MASK) !=
ARCHIVE_FORMAT_TAR)
return (0);
bid = 0;
@@ -321,7 +324,7 @@ archive_read_format_tar_bid(struct archive *a)
* If we're already reading a tar format, start the bid at 1 as
* a failsafe.
*/
- if ((a->archive_format & ARCHIVE_FORMAT_BASE_MASK) ==
+ if ((a->archive.archive_format & ARCHIVE_FORMAT_BASE_MASK) ==
ARCHIVE_FORMAT_TAR)
bid++;
@@ -345,7 +348,7 @@ archive_read_format_tar_bid(struct archive *a)
* If we already know this is a tar archive,
* then we have a problem.
*/
- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated tar archive");
return (ARCHIVE_FATAL);
}
@@ -353,7 +356,7 @@ archive_read_format_tar_bid(struct archive *a)
/* If it's an end-of-archive mark, we can handle it. */
if ((*(const char *)h) == 0 && archive_block_is_null((const unsigned char *)h)) {
/* If it's a known tar file, end-of-archive is definite. */
- if ((a->archive_format & ARCHIVE_FORMAT_BASE_MASK) ==
+ if ((a->archive.archive_format & ARCHIVE_FORMAT_BASE_MASK) ==
ARCHIVE_FORMAT_TAR)
return (512);
/* Empty archive? */
@@ -412,7 +415,7 @@ archive_read_format_tar_bid(struct archive *a)
* tar_read_header() function below.
*/
static int
-archive_read_format_tar_read_header(struct archive *a,
+archive_read_format_tar_read_header(struct archive_read *a,
struct archive_entry *entry)
{
/*
@@ -472,7 +475,7 @@ archive_read_format_tar_read_header(struct archive *a,
}
static int
-archive_read_format_tar_read_data(struct archive *a,
+archive_read_format_tar_read_data(struct archive_read *a,
const void **buff, size_t *size, off_t *offset)
{
ssize_t bytes_read;
@@ -497,7 +500,7 @@ archive_read_format_tar_read_data(struct archive *a,
if (tar->entry_bytes_remaining > 0) {
bytes_read = (a->compression_read_ahead)(a, buff, 1);
if (bytes_read == 0) {
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Truncated tar archive");
return (ARCHIVE_FATAL);
}
@@ -538,7 +541,7 @@ archive_read_format_tar_read_data(struct archive *a,
}
static int
-archive_read_format_tar_skip(struct archive *a)
+archive_read_format_tar_skip(struct archive_read *a)
{
off_t bytes_skipped;
struct tar* tar;
@@ -584,7 +587,7 @@ archive_read_format_tar_skip(struct archive *a)
* with a single entry.
*/
static int
-tar_read_header(struct archive *a, struct tar *tar,
+tar_read_header(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, struct stat *st)
{
ssize_t bytes;
@@ -610,7 +613,7 @@ tar_read_header(struct archive *a, struct tar *tar,
bytes = (a->compression_read_ahead)(a, &h, 512);
if (bytes > 0)
(a->compression_read_consume)(a, bytes);
- archive_set_error(a, 0, NULL);
+ archive_set_error(&a->archive, 0, NULL);
return (ARCHIVE_EOF);
}
@@ -622,12 +625,12 @@ tar_read_header(struct archive *a, struct tar *tar,
* TODO: Improve this by implementing a real header scan.
*/
if (!checksum(a, h)) {
- archive_set_error(a, EINVAL, "Damaged tar archive");
+ archive_set_error(&a->archive, EINVAL, "Damaged tar archive");
return (ARCHIVE_RETRY); /* Retryable: Invalid header */
}
if (++tar->header_recursion_depth > 32) {
- archive_set_error(a, EINVAL, "Too many special headers");
+ archive_set_error(&a->archive, EINVAL, "Too many special headers");
return (ARCHIVE_WARN);
}
@@ -635,13 +638,13 @@ tar_read_header(struct archive *a, struct tar *tar,
header = (const struct archive_entry_header_ustar *)h;
switch(header->typeflag[0]) {
case 'A': /* Solaris tar ACL */
- a->archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;
- a->archive_format_name = "Solaris tar";
+ a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;
+ a->archive.archive_format_name = "Solaris tar";
err = header_Solaris_ACL(a, tar, entry, st, h);
break;
case 'g': /* POSIX-standard 'g' header. */
- a->archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;
- a->archive_format_name = "POSIX pax interchange format";
+ a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;
+ a->archive.archive_format_name = "POSIX pax interchange format";
err = header_pax_global(a, tar, entry, st, h);
break;
case 'K': /* Long link name (GNU tar, others) */
@@ -654,30 +657,30 @@ tar_read_header(struct archive *a, struct tar *tar,
err = header_volume(a, tar, entry, st, h);
break;
case 'X': /* Used by SUN tar; same as 'x'. */
- a->archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;
- a->archive_format_name =
+ a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;
+ a->archive.archive_format_name =
"POSIX pax interchange format (Sun variant)";
err = header_pax_extensions(a, tar, entry, st, h);
break;
case 'x': /* POSIX-standard 'x' header. */
- a->archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;
- a->archive_format_name = "POSIX pax interchange format";
+ a->archive.archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;
+ a->archive.archive_format_name = "POSIX pax interchange format";
err = header_pax_extensions(a, tar, entry, st, h);
break;
default:
if (memcmp(header->magic, "ustar \0", 8) == 0) {
- a->archive_format = ARCHIVE_FORMAT_TAR_GNUTAR;
- a->archive_format_name = "GNU tar format";
+ a->archive.archive_format = ARCHIVE_FORMAT_TAR_GNUTAR;
+ a->archive.archive_format_name = "GNU tar format";
err = header_gnutar(a, tar, entry, st, h);
} else if (memcmp(header->magic, "ustar", 5) == 0) {
- if (a->archive_format != ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE) {
- a->archive_format = ARCHIVE_FORMAT_TAR_USTAR;
- a->archive_format_name = "POSIX ustar format";
+ if (a->archive.archive_format != ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE) {
+ a->archive.archive_format = ARCHIVE_FORMAT_TAR_USTAR;
+ a->archive.archive_format_name = "POSIX ustar format";
}
err = header_ustar(a, tar, entry, st, h);
} else {
- a->archive_format = ARCHIVE_FORMAT_TAR;
- a->archive_format_name = "tar (non-POSIX)";
+ a->archive.archive_format = ARCHIVE_FORMAT_TAR;
+ a->archive.archive_format_name = "tar (non-POSIX)";
err = header_old_tar(a, tar, entry, st, h);
}
}
@@ -689,7 +692,7 @@ tar_read_header(struct archive *a, struct tar *tar,
* Return true if block checksum is correct.
*/
static int
-checksum(struct archive *a, const void *h)
+checksum(struct archive_read *a, const void *h)
{
const unsigned char *bytes;
const struct archive_entry_header_ustar *header;
@@ -750,7 +753,7 @@ archive_block_is_null(const unsigned char *p)
* Interpret 'A' Solaris ACL header
*/
static int
-header_Solaris_ACL(struct archive *a, struct tar *tar,
+header_Solaris_ACL(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, struct stat *st, const void *h)
{
int err, err2;
@@ -786,7 +789,7 @@ header_Solaris_ACL(struct archive *a, struct tar *tar,
* Interpret 'K' long linkname header.
*/
static int
-header_longlink(struct archive *a, struct tar *tar,
+header_longlink(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, struct stat *st, const void *h)
{
int err, err2;
@@ -804,7 +807,7 @@ header_longlink(struct archive *a, struct tar *tar,
* Interpret 'L' long filename header.
*/
static int
-header_longname(struct archive *a, struct tar *tar,
+header_longname(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, struct stat *st, const void *h)
{
int err, err2;
@@ -822,7 +825,7 @@ header_longname(struct archive *a, struct tar *tar,
* Interpret 'V' GNU tar volume header.
*/
static int
-header_volume(struct archive *a, struct tar *tar,
+header_volume(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, struct stat *st, const void *h)
{
(void)h;
@@ -835,7 +838,7 @@ header_volume(struct archive *a, struct tar *tar,
* Read body of an archive entry into an archive_string object.
*/
static int
-read_body_to_string(struct archive *a, struct tar *tar,
+read_body_to_string(struct archive_read *a, struct tar *tar,
struct archive_string *as, const void *h)
{
off_t size, padded_size;
@@ -882,7 +885,7 @@ read_body_to_string(struct archive *a, struct tar *tar,
* common parsing into one place.
*/
static int
-header_common(struct archive *a, struct tar *tar, struct archive_entry *entry,
+header_common(struct archive_read *a, struct tar *tar, struct archive_entry *entry,
struct stat *st, const void *h)
{
const struct archive_entry_header_ustar *header;
@@ -946,7 +949,7 @@ header_common(struct archive *a, struct tar *tar, struct archive_entry *entry,
* itself an uncompressed tar archive.
*/
if (st->st_size > 0 &&
- a->archive_format != ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE &&
+ a->archive.archive_format != ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE &&
archive_read_format_tar_bid(a) > 50)
st->st_size = 0;
break;
@@ -1014,7 +1017,7 @@ header_common(struct archive *a, struct tar *tar, struct archive_entry *entry,
* Parse out header elements for "old-style" tar archives.
*/
static int
-header_old_tar(struct archive *a, struct tar *tar, struct archive_entry *entry,
+header_old_tar(struct archive_read *a, struct tar *tar, struct archive_entry *entry,
struct stat *st, const void *h)
{
const struct archive_entry_header_ustar *header;
@@ -1036,7 +1039,7 @@ header_old_tar(struct archive *a, struct tar *tar, struct archive_entry *entry,
* Parse a file header for a pax extended archive entry.
*/
static int
-header_pax_global(struct archive *a, struct tar *tar,
+header_pax_global(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, struct stat *st, const void *h)
{
int err, err2;
@@ -1047,7 +1050,7 @@ header_pax_global(struct archive *a, struct tar *tar,
}
static int
-header_pax_extensions(struct archive *a, struct tar *tar,
+header_pax_extensions(struct archive_read *a, struct tar *tar,
struct archive_entry *entry, struct stat *st, const void *h)
{
int err, err2;
@@ -1080,7 +1083,7 @@ header_pax_extensions(struct archive *a, struct tar *tar,
* handles "pax" or "extended ustar" entries.
*/
static int
-header_ustar(struct archive *a, struct tar *tar, struct archive_entry *entry,
+header_ustar(struct archive_read *a, struct tar *tar, struct archive_entry *entry,
struct stat *st, const void *h)
{
const struct archive_entry_header_ustar *header;
@@ -1132,7 +1135,7 @@ header_ustar(struct archive *a, struct tar *tar, struct archive_entry *entry,
* Returns non-zero if there's an error in the data.
*/
static int
-pax_header(struct archive *a, struct tar *tar, struct archive_entry *entry,
+pax_header(struct archive_read *a, struct tar *tar, struct archive_entry *entry,
struct stat *st, char *attr)
{
size_t attr_length, l, line_length;
@@ -1158,7 +1161,7 @@ pax_header(struct archive *a, struct tar *tar, struct archive_entry *entry,
line_length *= 10;
line_length += *p - '0';
if (line_length > 999999) {
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Rejecting pax extended attribute > 1MB");
return (ARCHIVE_WARN);
}
@@ -1183,7 +1186,7 @@ pax_header(struct archive *a, struct tar *tar, struct archive_entry *entry,
tar->pax_entry_length * sizeof(wchar_t));
if (tar->pax_entry == NULL) {
free(old_entry);
- archive_set_error(a, ENOMEM,
+ archive_set_error(&a->archive, ENOMEM,
"No memory");
return (ARCHIVE_FATAL);
}
@@ -1192,7 +1195,7 @@ pax_header(struct archive *a, struct tar *tar, struct archive_entry *entry,
/* Decode UTF-8 to wchar_t, null-terminate result. */
if (utf8_decode(tar->pax_entry, p,
line_length - (p - attr) - 1)) {
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Invalid UTF8 character in pax extended attribute");
err = err_combine(err, ARCHIVE_WARN);
}
@@ -1204,7 +1207,7 @@ pax_header(struct archive *a, struct tar *tar, struct archive_entry *entry,
while (*wp && *wp != L'=')
++wp;
if (*wp == L'\0' || wp == NULL) {
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Invalid pax extended attributes");
return (ARCHIVE_WARN);
}
@@ -1430,7 +1433,7 @@ pax_time(const wchar_t *p, int64_t *ps, long *pn)
* Parse GNU tar header
*/
static int
-header_gnutar(struct archive *a, struct tar *tar, struct archive_entry *entry,
+header_gnutar(struct archive_read *a, struct tar *tar, struct archive_entry *entry,
struct stat *st, const void *h)
{
const struct archive_entry_header_gnutar *header;
@@ -1495,7 +1498,7 @@ header_gnutar(struct archive *a, struct tar *tar, struct archive_entry *entry,
}
static int
-gnu_read_sparse_data(struct archive *a, struct tar *tar,
+gnu_read_sparse_data(struct archive_read *a, struct tar *tar,
const struct archive_entry_header_gnutar *header)
{
ssize_t bytes_read;
@@ -1516,7 +1519,7 @@ gnu_read_sparse_data(struct archive *a, struct tar *tar,
if (bytes_read < 0)
return (ARCHIVE_FATAL);
if (bytes_read < 512) {
- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated tar archive "
"detected while reading sparse file data");
return (ARCHIVE_FATAL);
@@ -1531,7 +1534,7 @@ gnu_read_sparse_data(struct archive *a, struct tar *tar,
}
static void
-gnu_parse_sparse_data(struct archive *a, struct tar *tar,
+gnu_parse_sparse_data(struct archive_read *a, struct tar *tar,
const struct gnu_sparse *sparse, int length)
{
struct sparse_block *last;
diff --git a/lib/libarchive/archive_read_support_format_zip.c b/lib/libarchive/archive_read_support_format_zip.c
index 5807e56..f15eba0 100644
--- a/lib/libarchive/archive_read_support_format_zip.c
+++ b/lib/libarchive/archive_read_support_format_zip.c
@@ -44,15 +44,16 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_entry.h"
#include "archive_private.h"
+#include "archive_read_private.h"
struct zip {
/* entry_bytes_remaining is the number of bytes we expect. */
- off_t entry_bytes_remaining;
- off_t entry_offset;
+ int64_t entry_bytes_remaining;
+ int64_t entry_offset;
/* These count the number of bytes actually read for the entry. */
- off_t entry_compressed_bytes_read;
- off_t entry_uncompressed_bytes_read;
+ int64_t entry_compressed_bytes_read;
+ int64_t entry_uncompressed_bytes_read;
unsigned version;
unsigned system;
@@ -74,8 +75,8 @@ struct zip {
long crc32;
ssize_t filename_length;
ssize_t extra_length;
- off_t uncompressed_size;
- off_t compressed_size;
+ int64_t uncompressed_size;
+ int64_t compressed_size;
unsigned char *uncompressed_buffer;
size_t uncompressed_buffer_size;
@@ -115,36 +116,40 @@ static const char *compression_names[] = {
"deflation"
};
-static int archive_read_format_zip_bid(struct archive *);
-static int archive_read_format_zip_cleanup(struct archive *);
-static int archive_read_format_zip_read_data(struct archive *,
+static int archive_read_format_zip_bid(struct archive_read *);
+static int archive_read_format_zip_cleanup(struct archive_read *);
+static int archive_read_format_zip_read_data(struct archive_read *,
const void **, size_t *, off_t *);
-static int archive_read_format_zip_read_data_skip(struct archive *a);
-static int archive_read_format_zip_read_header(struct archive *,
+static int archive_read_format_zip_read_data_skip(struct archive_read *a);
+static int archive_read_format_zip_read_header(struct archive_read *,
struct archive_entry *);
static int i2(const char *);
static int i4(const char *);
static unsigned int u2(const char *);
static unsigned int u4(const char *);
static uint64_t u8(const char *);
-static int zip_read_data_deflate(struct archive *a, const void **buff,
+static int zip_read_data_deflate(struct archive_read *a, const void **buff,
size_t *size, off_t *offset);
-static int zip_read_data_none(struct archive *a, const void **buff,
+static int zip_read_data_none(struct archive_read *a, const void **buff,
size_t *size, off_t *offset);
-static int zip_read_file_header(struct archive *a,
+static int zip_read_file_header(struct archive_read *a,
struct archive_entry *entry, struct zip *zip);
static time_t zip_time(const char *);
static void process_extra(const void* extra, struct zip* zip);
+/* Largest 32-bit unsigned value, stored in a 64-bit constant. */
+static const uint64_t max_uint32 = (((uint64_t)1) << 32) - 1;
+
int
-archive_read_support_format_zip(struct archive *a)
+archive_read_support_format_zip(struct archive *_a)
{
+ struct archive_read *a = (struct archive_read *)_a;
struct zip *zip;
int r;
zip = (struct zip *)malloc(sizeof(*zip));
if (zip == NULL) {
- archive_set_error(a, ENOMEM, "Can't allocate zip data");
+ archive_set_error(&a->archive, ENOMEM, "Can't allocate zip data");
return (ARCHIVE_FATAL);
}
memset(zip, 0, sizeof(*zip));
@@ -164,14 +169,14 @@ archive_read_support_format_zip(struct archive *a)
static int
-archive_read_format_zip_bid(struct archive *a)
+archive_read_format_zip_bid(struct archive_read *a)
{
int bytes_read;
int bid = 0;
const void *h;
const char *p;
- if (a->archive_format == ARCHIVE_FORMAT_ZIP)
+ if (a->archive.archive_format == ARCHIVE_FORMAT_ZIP)
bid += 1;
bytes_read = (a->compression_read_ahead)(a, &h, 4);
@@ -194,7 +199,7 @@ archive_read_format_zip_bid(struct archive *a)
}
static int
-archive_read_format_zip_read_header(struct archive *a,
+archive_read_format_zip_read_header(struct archive_read *a,
struct archive_entry *entry)
{
int bytes_read;
@@ -202,9 +207,9 @@ archive_read_format_zip_read_header(struct archive *a,
const char *signature;
struct zip *zip;
- a->archive_format = ARCHIVE_FORMAT_ZIP;
- if (a->archive_format_name == NULL)
- a->archive_format_name = "ZIP";
+ a->archive.archive_format = ARCHIVE_FORMAT_ZIP;
+ if (a->archive.archive_format_name == NULL)
+ a->archive.archive_format_name = "ZIP";
zip = (struct zip *)*(a->pformat_data);
zip->decompress_init = 0;
@@ -218,7 +223,7 @@ archive_read_format_zip_read_header(struct archive *a,
signature = (const char *)h;
if (signature[0] != 'P' || signature[1] != 'K') {
- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Bad ZIP file");
return (ARCHIVE_FATAL);
}
@@ -243,19 +248,19 @@ archive_read_format_zip_read_header(struct archive *a,
* We should never encounter this record here;
* see ZIP_LENGTH_AT_END handling below for details.
*/
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Bad ZIP file: Unexpected end-of-entry record");
return (ARCHIVE_FATAL);
}
- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Damaged ZIP file or unsupported format variant (%d,%d)",
signature[2], signature[3]);
return (ARCHIVE_FATAL);
}
int
-zip_read_file_header(struct archive *a, struct archive_entry *entry,
+zip_read_file_header(struct archive_read *a, struct archive_entry *entry,
struct zip *zip)
{
const struct zip_file_header *p;
@@ -266,7 +271,7 @@ zip_read_file_header(struct archive *a, struct archive_entry *entry,
bytes_read =
(a->compression_read_ahead)(a, &h, sizeof(struct zip_file_header));
if (bytes_read < (int)sizeof(struct zip_file_header)) {
- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP file header");
return (ARCHIVE_FATAL);
}
@@ -299,7 +304,7 @@ zip_read_file_header(struct archive *a, struct archive_entry *entry,
/* Read the filename. */
bytes_read = (a->compression_read_ahead)(a, &h, zip->filename_length);
if (bytes_read < zip->filename_length) {
- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP file header");
return (ARCHIVE_FATAL);
}
@@ -316,7 +321,7 @@ zip_read_file_header(struct archive *a, struct archive_entry *entry,
/* Read the extra data. */
bytes_read = (a->compression_read_ahead)(a, &h, zip->extra_length);
if (bytes_read < zip->extra_length) {
- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP file header");
return (ARCHIVE_FATAL);
}
@@ -341,7 +346,7 @@ zip_read_file_header(struct archive *a, struct archive_entry *entry,
sprintf(zip->format_name, "ZIP %d.%d (%s)",
zip->version / 10, zip->version % 10,
zip->compression_name);
- a->archive_format_name = zip->format_name;
+ a->archive.archive_format_name = zip->format_name;
return (ARCHIVE_OK);
}
@@ -368,7 +373,7 @@ zip_time(const char *p)
}
static int
-archive_read_format_zip_read_data(struct archive *a,
+archive_read_format_zip_read_data(struct archive_read *a,
const void **buff, size_t *size, off_t *offset)
{
int r;
@@ -388,7 +393,7 @@ archive_read_format_zip_read_data(struct archive *a,
int bytes_read =
(a->compression_read_ahead)(a, &h, 16);
if (bytes_read < 16) {
- archive_set_error(a,
+ archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP end-of-file record");
return (ARCHIVE_FATAL);
@@ -402,19 +407,21 @@ archive_read_format_zip_read_data(struct archive *a,
/* Check file size, CRC against these values. */
if (zip->compressed_size != zip->entry_compressed_bytes_read) {
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"ZIP compressed data is wrong size");
return (ARCHIVE_WARN);
}
- if (zip->uncompressed_size != zip->entry_uncompressed_bytes_read) {
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ /* Size field only stores the lower 32 bits of the actual size. */
+ if ((zip->uncompressed_size & max_uint32)
+ != (zip->entry_uncompressed_bytes_read & max_uint32)) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"ZIP uncompressed data is wrong size");
return (ARCHIVE_WARN);
}
/* TODO: Compute CRC. */
/*
if (zip->crc32 != zip->entry_crc32_calculated) {
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"ZIP data CRC error");
return (ARCHIVE_WARN);
}
@@ -437,7 +444,7 @@ archive_read_format_zip_read_data(struct archive *a,
*size = 0;
*offset = 0;
/* Return a warning. */
- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Unsupported ZIP compression method (%s)",
zip->compression_name);
if (zip->flags & ZIP_LENGTH_AT_END) {
@@ -472,7 +479,7 @@ archive_read_format_zip_read_data(struct archive *a,
* zip->end_of_entry if it consumes all of the data.
*/
static int
-zip_read_data_none(struct archive *a, const void **buff,
+zip_read_data_none(struct archive_read *a, const void **buff,
size_t *size, off_t *offset)
{
struct zip *zip;
@@ -495,7 +502,7 @@ zip_read_data_none(struct archive *a, const void **buff,
*/
bytes_avail = (a->compression_read_ahead)(a, buff, 1);
if (bytes_avail <= 0) {
- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP file data");
return (ARCHIVE_FATAL);
}
@@ -513,7 +520,7 @@ zip_read_data_none(struct archive *a, const void **buff,
#ifdef HAVE_ZLIB_H
static int
-zip_read_data_deflate(struct archive *a, const void **buff,
+zip_read_data_deflate(struct archive_read *a, const void **buff,
size_t *size, off_t *offset)
{
struct zip *zip;
@@ -529,7 +536,7 @@ zip_read_data_deflate(struct archive *a, const void **buff,
zip->uncompressed_buffer
= (unsigned char *)malloc(zip->uncompressed_buffer_size);
if (zip->uncompressed_buffer == NULL) {
- archive_set_error(a, ENOMEM,
+ archive_set_error(&a->archive, ENOMEM,
"No memory for ZIP decompression");
return (ARCHIVE_FATAL);
}
@@ -540,7 +547,7 @@ zip_read_data_deflate(struct archive *a, const void **buff,
r = inflateInit2(&zip->stream,
-15 /* Don't check for zlib header */);
if (r != Z_OK) {
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Can't initialize ZIP decompression.");
return (ARCHIVE_FATAL);
}
@@ -555,7 +562,7 @@ zip_read_data_deflate(struct archive *a, const void **buff,
*/
bytes_avail = (a->compression_read_ahead)(a, &compressed_buff, 1);
if (bytes_avail <= 0) {
- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP file body");
return (ARCHIVE_FATAL);
}
@@ -581,11 +588,11 @@ zip_read_data_deflate(struct archive *a, const void **buff,
zip->end_of_entry = 1;
break;
case Z_MEM_ERROR:
- archive_set_error(a, ENOMEM,
+ archive_set_error(&a->archive, ENOMEM,
"Out of memory for ZIP decompression");
return (ARCHIVE_FATAL);
default:
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"ZIP decompression failed (%d)", r);
return (ARCHIVE_FATAL);
}
@@ -605,20 +612,20 @@ zip_read_data_deflate(struct archive *a, const void **buff,
}
#else
static int
-zip_read_data_deflate(struct archive *a, const void **buff,
+zip_read_data_deflate(struct archive_read *a, const void **buff,
size_t *size, off_t *offset)
{
*buff = NULL;
*size = 0;
*offset = 0;
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"libarchive compiled without deflate support (no libz)");
return (ARCHIVE_FATAL);
}
#endif
static int
-archive_read_format_zip_read_data_skip(struct archive *a)
+archive_read_format_zip_read_data_skip(struct archive_read *a)
{
struct zip *zip;
const void *buff = NULL;
@@ -648,7 +655,8 @@ archive_read_format_zip_read_data_skip(struct archive *a)
while (zip->entry_bytes_remaining > 0) {
bytes_avail = (a->compression_read_ahead)(a, &buff, 1);
if (bytes_avail <= 0) {
- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP file body");
return (ARCHIVE_FATAL);
}
@@ -663,7 +671,7 @@ archive_read_format_zip_read_data_skip(struct archive *a)
}
static int
-archive_read_format_zip_cleanup(struct archive *a)
+archive_read_format_zip_cleanup(struct archive_read *a)
{
struct zip *zip;
diff --git a/lib/libarchive/archive_util.3 b/lib/libarchive/archive_util.3
index 676abef..a67e529 100644
--- a/lib/libarchive/archive_util.3
+++ b/lib/libarchive/archive_util.3
@@ -28,6 +28,7 @@
.Dt archive_util 3
.Os
.Sh NAME
+.Nm archive_clear_error ,
.Nm archive_compression ,
.Nm archive_compression_name ,
.Nm archive_errno ,
@@ -38,6 +39,8 @@
.Nd libarchive utility functions
.Sh SYNOPSIS
.In archive.h
+.Ft void
+.Fn archive_clear_error "struct archive *"
.Ft int
.Fn archive_compression "struct archive *"
.Ft const char *
@@ -59,6 +62,9 @@ object used in the
.Xr libarchive 3
library.
.Bl -tag -compact -width indent
+.It Fn archive_clear_error
+Clears any error information left over from a previous call.
+Not generally used in client code.
.It Fn archive_compression
Returns a numeric code indicating the current compression.
This value is set by
diff --git a/lib/libarchive/archive_util.c b/lib/libarchive/archive_util.c
index a31f6c8..82e5e02 100644
--- a/lib/libarchive/archive_util.c
+++ b/lib/libarchive/archive_util.c
@@ -118,6 +118,12 @@ archive_position_uncompressed(struct archive *a)
return (a->file_position);
}
+void
+archive_clear_error(struct archive *a)
+{
+ archive_string_empty(&a->error_string);
+ a->error = NULL;
+}
void
archive_set_error(struct archive *a, int error_number, const char *fmt, ...)
diff --git a/lib/libarchive/archive_virtual.c b/lib/libarchive/archive_virtual.c
new file mode 100644
index 0000000..6b7b12e
--- /dev/null
+++ b/lib/libarchive/archive_virtual.c
@@ -0,0 +1,81 @@
+/*-
+ * 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"
+
+int
+archive_write_close(struct archive *a)
+{
+ return ((a->vtable->archive_write_close)(a));
+}
+
+#if ARCHIVE_API_VERSION > 1
+int
+archive_write_finish(struct archive *a)
+{
+ return ((a->vtable->archive_write_finish)(a));
+}
+#else
+/* Temporarily allow library to compile with either 1.x or 2.0 API. */
+void
+archive_write_finish(struct archive *a)
+{
+ (void)(a->vtable->archive_write_finish)(a);
+}
+#endif
+
+int
+archive_write_header(struct archive *a, struct archive_entry *entry)
+{
+ return ((a->vtable->archive_write_header)(a, entry));
+}
+
+int
+archive_write_finish_entry(struct archive *a)
+{
+ return ((a->vtable->archive_write_finish_entry)(a));
+}
+
+#if ARCHIVE_API_VERSION > 1
+ssize_t
+#else
+/* Temporarily allow library to compile with either 1.x or 2.0 API. */
+int
+#endif
+archive_write_data(struct archive *a, const void *buff, size_t s)
+{
+ return ((a->vtable->archive_write_data)(a, buff, s));
+}
+
+ssize_t
+archive_write_data_block(struct archive *a, const void *buff, size_t s, off_t o)
+{
+ return ((a->vtable->archive_write_data_block)(a, buff, s, o));
+}
diff --git a/lib/libarchive/archive_write.3 b/lib/libarchive/archive_write.3
index d90af7d..6725a71 100644
--- a/lib/libarchive/archive_write.3
+++ b/lib/libarchive/archive_write.3
@@ -89,13 +89,13 @@
.Fn archive_write_open_memory "struct archive *" "void *buffer" "size_t bufferSize" "size_t *outUsed"
.Ft int
.Fn archive_write_header "struct archive *" "struct archive_entry *"
-.Ft int
+.Ft ssize_t
.Fn archive_write_data "struct archive *" "const void *" "size_t"
.Ft int
.Fn archive_write_finish_entry "struct archive *"
.Ft int
.Fn archive_write_close "struct archive *"
-.Ft void
+.Ft int
.Fn archive_write_finish "struct archive *"
.Sh DESCRIPTION
These functions provide a complete API for creating streaming
@@ -260,6 +260,12 @@ Complete the archive and invoke the close callback.
Invokes
.Fn archive_write_close
if it was not invoked manually, then releases all resources.
+Note that this function was declared to return
+.Ft void
+in libarchive 1.x, which made it impossible to detect errors when
+.Fn archive_write_close
+was invoked implicitly from this function.
+This is corrected beginning with libarchive 2.0.
.El
More information about the
.Va struct archive
@@ -457,8 +463,9 @@ through whatever API function resulted in that call, which
may include
.Fn archive_write_header ,
.Fn archive_write_data ,
+.Fn archive_write_close ,
or
-.Fn archive_write_close .
+.Fn archive_write_finish .
The client callback can call
.Fn archive_set_error
to provide values that can then be retrieved by
diff --git a/lib/libarchive/archive_write.c b/lib/libarchive/archive_write.c
index 0aff2f1..e68b0b8 100644
--- a/lib/libarchive/archive_write.c
+++ b/lib/libarchive/archive_write.c
@@ -55,6 +55,31 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_entry.h"
#include "archive_private.h"
+#include "archive_write_private.h"
+
+static struct archive_vtable *archive_write_vtable(void);
+
+static int _archive_write_close(struct archive *);
+static int _archive_write_finish(struct archive *);
+static int _archive_write_header(struct archive *, struct archive_entry *);
+static int _archive_write_finish_entry(struct archive *);
+static ssize_t _archive_write_data(struct archive *, const void *, size_t);
+
+static struct archive_vtable *
+archive_write_vtable(void)
+{
+ static struct archive_vtable av;
+ static int inited = 0;
+
+ if (!inited) {
+ av.archive_write_close = _archive_write_close;
+ av.archive_write_finish = _archive_write_finish;
+ av.archive_write_header = _archive_write_header;
+ av.archive_write_finish_entry = _archive_write_finish_entry;
+ av.archive_write_data = _archive_write_data;
+ }
+ return (&av);
+}
/*
* Allocate, initialize and return an archive object.
@@ -62,18 +87,18 @@ __FBSDID("$FreeBSD$");
struct archive *
archive_write_new(void)
{
- struct archive *a;
+ struct archive_write *a;
unsigned char *nulls;
- a = (struct archive *)malloc(sizeof(*a));
+ a = (struct archive_write *)malloc(sizeof(*a));
if (a == NULL)
return (NULL);
memset(a, 0, sizeof(*a));
- a->magic = ARCHIVE_WRITE_MAGIC;
- a->user_uid = geteuid();
+ a->archive.magic = ARCHIVE_WRITE_MAGIC;
+ a->archive.state = ARCHIVE_STATE_NEW;
+ a->archive.vtable = archive_write_vtable();
a->bytes_per_block = ARCHIVE_DEFAULT_BYTES_PER_BLOCK;
a->bytes_in_last_block = -1; /* Default */
- a->state = ARCHIVE_STATE_NEW;
a->pformat_data = &(a->format_data);
/* Initialize a block of nulls for padding purposes. */
@@ -91,17 +116,19 @@ archive_write_new(void)
* client to link in support for that format, even if they didn't
* ever use it.
*/
- archive_write_set_compression_none(a);
- return (a);
+ archive_write_set_compression_none(&a->archive);
+ return (&a->archive);
}
/*
* Set the block size. Returns 0 if successful.
*/
int
-archive_write_set_bytes_per_block(struct archive *a, int bytes_per_block)
+archive_write_set_bytes_per_block(struct archive *_a, int bytes_per_block)
{
- __archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_set_bytes_per_block");
+ struct archive_write *a = (struct archive_write *)_a;
+ __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_write_set_bytes_per_block");
a->bytes_per_block = bytes_per_block;
return (ARCHIVE_OK);
}
@@ -110,9 +137,11 @@ archive_write_set_bytes_per_block(struct archive *a, int bytes_per_block)
* Get the current block size. -1 if it has never been set.
*/
int
-archive_write_get_bytes_per_block(struct archive *a)
+archive_write_get_bytes_per_block(struct archive *_a)
{
- __archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_ANY, "archive_write_get_bytes_per_block");
+ struct archive_write *a = (struct archive_write *)_a;
+ __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+ ARCHIVE_STATE_ANY, "archive_write_get_bytes_per_block");
return (a->bytes_per_block);
}
@@ -121,9 +150,11 @@ archive_write_get_bytes_per_block(struct archive *a)
* Returns 0 if successful.
*/
int
-archive_write_set_bytes_in_last_block(struct archive *a, int bytes)
+archive_write_set_bytes_in_last_block(struct archive *_a, int bytes)
{
- __archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_ANY, "archive_write_set_bytes_in_last_block");
+ struct archive_write *a = (struct archive_write *)_a;
+ __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+ ARCHIVE_STATE_ANY, "archive_write_set_bytes_in_last_block");
a->bytes_in_last_block = bytes;
return (ARCHIVE_OK);
}
@@ -132,9 +163,11 @@ archive_write_set_bytes_in_last_block(struct archive *a, int bytes)
* Return the value set above. -1 indicates it has not been set.
*/
int
-archive_write_get_bytes_in_last_block(struct archive *a)
+archive_write_get_bytes_in_last_block(struct archive *_a)
{
- __archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_ANY, "archive_write_get_bytes_in_last_block");
+ struct archive_write *a = (struct archive_write *)_a;
+ __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+ ARCHIVE_STATE_ANY, "archive_write_get_bytes_in_last_block");
return (a->bytes_in_last_block);
}
@@ -144,9 +177,11 @@ archive_write_get_bytes_in_last_block(struct archive *a)
* an archive to itself recursively.
*/
int
-archive_write_set_skip_file(struct archive *a, dev_t d, ino_t i)
+archive_write_set_skip_file(struct archive *_a, dev_t d, ino_t i)
{
- __archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_ANY, "archive_write_set_skip_file");
+ struct archive_write *a = (struct archive_write *)_a;
+ __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+ ARCHIVE_STATE_ANY, "archive_write_set_skip_file");
a->skip_file_dev = d;
a->skip_file_ino = i;
return (ARCHIVE_OK);
@@ -157,16 +192,18 @@ archive_write_set_skip_file(struct archive *a, dev_t d, ino_t i)
* Open the archive using the current settings.
*/
int
-archive_write_open(struct archive *a, void *client_data,
+archive_write_open(struct archive *_a, void *client_data,
archive_open_callback *opener, archive_write_callback *writer,
archive_close_callback *closer)
{
+ struct archive_write *a = (struct archive_write *)_a;
int ret;
ret = ARCHIVE_OK;
- __archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_open");
- archive_string_empty(&a->error_string);
- a->state = ARCHIVE_STATE_HEADER;
+ __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_write_open");
+ archive_clear_error(&a->archive);
+ a->archive.state = ARCHIVE_STATE_HEADER;
a->client_data = client_data;
a->client_writer = writer;
a->client_opener = opener;
@@ -185,15 +222,17 @@ archive_write_open(struct archive *a, void *client_data,
* Don't assume we actually wrote anything or performed any non-trivial
* initialization.
*/
-int
-archive_write_close(struct archive *a)
+static int
+_archive_write_close(struct archive *_a)
{
+ struct archive_write *a = (struct archive_write *)_a;
int r = ARCHIVE_OK, r1 = ARCHIVE_OK;
- __archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_ANY, "archive_write_close");
+ __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+ ARCHIVE_STATE_ANY, "archive_write_close");
/* Finish the last entry. */
- if (a->state & ARCHIVE_STATE_DATA)
+ if (a->archive.state & ARCHIVE_STATE_DATA)
r = ((a->format_finish_entry)(a));
/* Finish off the archive. */
@@ -203,6 +242,13 @@ archive_write_close(struct archive *a)
r = r1;
}
+ /* Release resources. */
+ if (a->format_destroy != NULL) {
+ r1 = (a->format_destroy)(a);
+ if (r1 < r)
+ r = r1;
+ }
+
/* Finish the compression and close the stream. */
if (a->compression_finish != NULL) {
r1 = (a->compression_finish)(a);
@@ -210,41 +256,47 @@ archive_write_close(struct archive *a)
r = r1;
}
- a->state = ARCHIVE_STATE_CLOSED;
+ a->archive.state = ARCHIVE_STATE_CLOSED;
return (r);
}
/*
* Destroy the archive structure.
*/
-void
-archive_write_finish(struct archive *a)
+static int
+_archive_write_finish(struct archive *_a)
{
- __archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_ANY, "archive_write_finish");
- if (a->state != ARCHIVE_STATE_CLOSED)
- archive_write_close(a);
+ struct archive_write *a = (struct archive_write *)_a;
+ int r = ARCHIVE_OK;
+
+ __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+ ARCHIVE_STATE_ANY, "archive_write_finish");
+ if (a->archive.state != ARCHIVE_STATE_CLOSED)
+ r = archive_write_close(&a->archive);
/* Release various dynamic buffers. */
free((void *)(uintptr_t)(const void *)a->nulls);
- archive_string_free(&a->error_string);
- a->magic = 0;
+ archive_string_free(&a->archive.error_string);
+ a->archive.magic = 0;
free(a);
+ return (r);
}
/*
* Write the appropriate header.
*/
-int
-archive_write_header(struct archive *a, struct archive_entry *entry)
+static int
+_archive_write_header(struct archive *_a, struct archive_entry *entry)
{
+ struct archive_write *a = (struct archive_write *)_a;
int ret, r2;
- __archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
+ __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_DATA | ARCHIVE_STATE_HEADER, "archive_write_header");
- archive_string_empty(&a->error_string);
+ archive_clear_error(&a->archive);
/* In particular, "retry" and "fatal" get returned immediately. */
- ret = archive_write_finish_entry(a);
+ ret = archive_write_finish_entry(&a->archive);
if (ret < ARCHIVE_OK && ret != ARCHIVE_WARN)
return (ret);
@@ -252,7 +304,8 @@ archive_write_header(struct archive *a, struct archive_entry *entry)
archive_entry_dev(entry) == a->skip_file_dev &&
a->skip_file_ino != 0 &&
archive_entry_ino(entry) == a->skip_file_ino) {
- archive_set_error(a, 0, "Can't add archive to itself");
+ archive_set_error(&a->archive, 0,
+ "Can't add archive to itself");
return (ARCHIVE_WARN);
}
@@ -261,33 +314,34 @@ archive_write_header(struct archive *a, struct archive_entry *entry)
if (r2 < ret)
ret = r2;
- a->state = ARCHIVE_STATE_DATA;
+ a->archive.state = ARCHIVE_STATE_DATA;
return (ret);
}
-int
-archive_write_finish_entry(struct archive * a)
+static int
+_archive_write_finish_entry(struct archive *_a)
{
+ struct archive_write *a = (struct archive_write *)_a;
int ret = ARCHIVE_OK;
- __archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
+ __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
"archive_write_finish_entry");
- if (a->state & ARCHIVE_STATE_DATA)
+ if (a->archive.state & ARCHIVE_STATE_DATA)
ret = (a->format_finish_entry)(a);
- a->state = ARCHIVE_STATE_HEADER;
+ a->archive.state = ARCHIVE_STATE_HEADER;
return (ret);
}
/*
* Note that the compressor is responsible for blocking.
*/
-/* Should be "ssize_t", but that breaks the ABI. <sigh> */
-int
-archive_write_data(struct archive *a, const void *buff, size_t s)
+static ssize_t
+_archive_write_data(struct archive *_a, const void *buff, size_t s)
{
- __archive_check_magic(a, ARCHIVE_WRITE_MAGIC,
+ struct archive_write *a = (struct archive_write *)_a;
+ __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_DATA, "archive_write_data");
- archive_string_empty(&a->error_string);
+ archive_clear_error(&a->archive);
return ((a->format_write_data)(a, buff, s));
}
diff --git a/lib/libarchive/archive_write_disk.3 b/lib/libarchive/archive_write_disk.3
new file mode 100644
index 0000000..6b58d9c
--- /dev/null
+++ b/lib/libarchive/archive_write_disk.3
@@ -0,0 +1,358 @@
+.\" 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 March 2, 2007
+.Dt archive_write_disk 3
+.Os
+.Sh NAME
+.Nm archive_write_disk_new ,
+.Nm archive_write_disk_set_options ,
+.Nm archive_write_disk_set_skip_file ,
+.Nm archive_write_disk_set_group_lookup ,
+.Nm archive_write_disk_set_standard_lookup ,
+.Nm archive_write_disk_set_user_lookup ,
+.Nm archive_write_header ,
+.Nm archive_write_data ,
+.Nm archive_write_finish_entry ,
+.Nm archive_write_close ,
+.Nm archive_write_finish
+.Nd functions for creating objects on disk
+.Sh SYNOPSIS
+.In archive.h
+.Ft struct archive *
+.Fn archive_write_disk_new "void"
+.Ft int
+.Fn archive_write_disk_set_options "struct archive *" "int flags"
+.Ft int
+.Fn archive_write_disk_set_skip_file "struct archive *" "dev_t" "ino_t"
+.Ft int
+.Fn archive_write_disk_set_group_lookup "struct archive *" "void *" "gid_t (*)(void *, const char *gname, gid_t gid)" "void (*cleanup)(void *)"
+.Ft int
+.Fn archive_write_disk_set_standard_lookup "struct archive *"
+.Ft int
+.Fn archive_write_disk_set_user_lookup "struct archive *" "void *" "uid_t (*)(void *, const char *uname, uid_t uid)" "void (*cleanup)(void *)"
+.Ft int
+.Fn archive_write_header "struct archive *" "struct archive_entry *"
+.Ft ssize_t
+.Fn archive_write_data "struct archive *" "const void *" "size_t"
+.Ft int
+.Fn archive_write_finish_entry "struct archive *"
+.Ft int
+.Fn archive_write_close "struct archive *"
+.Ft int
+.Fn archive_write_finish "struct archive *"
+.Sh DESCRIPTION
+These functions provide a complete API for creating objects on
+disk from
+.Tn struct archive_entry
+descriptions.
+They are most naturally used when extracting objects from an archive
+using the
+.Fn archive_read
+interface.
+The general process is to read
+.Tn struct archive_entry
+objects from an archive, then write those objects to a
+.Tn struct archive
+object created using the
+.Fn archive_write_disk
+family functions.
+This interface is deliberately very similar to the
+.Fn archive_write
+interface used to write objects to a streaming archive.
+.Bl -tag -width indent
+.It Fn archive_write_disk_new
+Allocates and initializes a
+.Tn struct archive
+object suitable for writing objects to disk.
+.It Fn archive_write_disk_set_skip_file
+Records the device and inode numbers of a file that should not be
+overwritten.
+This is typically used to ensure that an extraction process does not
+overwrite the archive from which objects are being read.
+This capability is technically unnecessary but can be a significant
+performance optimization in practice.
+.It Fn archive_write_disk_set_options
+The options field 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
+Full permissions (including SGID, SUID, and sticky bits) should
+be restored exactly as specified, without obeying the
+current umask.
+Note that SUID and SGID bits can only be restored if the
+user and group ID of the object on disk are correct.
+If
+.Cm ARCHIVE_EXTRACT_OWNER
+is not specified, then SUID and SGID bits will only be restored
+if the default user and group IDs of newly-created objects on disk
+happen to match those specified in the archive entry.
+By default, only basic permissions are restored, and umask is obeyed.
+.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 before any attempt to
+create them.
+In some cases, this can prove to be a significant performance improvement.
+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.
+.It Cm ARCHIVE_EXTRACT_XATTR
+Attempt to restore POSIX.1e extended attributes.
+By default, they are ignored.
+.It Cm ARCHIVE_EXTRACT_SECURE_SYMLINKS
+Refuse to extract any object whose final location would be altered
+by a symlink on disk.
+This is intended to help guard against a variety of mischief
+caused by archives that (deliberately or otherwise) extract
+files outside of the current directory.
+The default is not to perform this check.
+If
+.Cm ARCHIVE_EXTRACT_UNLINK
+is specified together with this option, the library will
+remove any intermediate symlinks it finds and return an
+error only if such symlink could not be removed.
+.It Cm ARCHIVE_EXTRACT_SECURE_NODOTDOT
+Refuse to extract a path that contains a
+.Pa ..
+element anywhere within it.
+The default is to not refuse such paths.
+Note that paths ending in
+.Pa ..
+always cause an error, regardless of this flag.
+.El
+.It Fn archive_write_disk_set_group_lookup , Fn archive_write_disk_set_user_lookup
+The
+.Tn struct archive_entry
+objects contain both names and ids that can be used to identify users
+and groups.
+These names and ids describe the ownership of the file itself and
+also appear in ACL lists.
+By default, the library uses the ids and ignores the names, but
+this can be overridden by registering user and group lookup functions.
+To register, you must provide a lookup function which
+accepts both a name and id and returns a suitable id.
+You may also provide a
+.Tn void *
+pointer to a private data structure and a cleanup function for
+that data.
+The cleanup function will be invoked when the
+.Tn struct archive
+object is destroyed.
+.It Fn archive_write_disk_set_standard_lookup
+This convenience function installs a standard set of user
+and group lookup functions.
+These functions use
+.Xr getpwnam 3
+and
+.Xr getgrnam 3
+to convert names to ids, defaulting to the ids if the names cannot
+be looked up.
+These functions also implement a simple memory cache to reduce
+the number of calls to
+.Xr getpwnam 3
+and
+.Xr getgrnam 3 .
+.It Fn archive_write_header
+Build and write a header using the data in the provided
+.Tn struct archive_entry
+structure.
+See
+.Xr archive_entry 3
+for information on creating and populating
+.Tn struct archive_entry
+objects.
+.It Fn archive_write_data
+Write data corresponding to the header just written.
+Returns number of bytes written or -1 on error.
+.It Fn archive_write_finish_entry
+Close out the entry just written.
+Ordinarily, clients never need to call this, as it
+is called automatically by
+.Fn archive_write_next_header
+and
+.Fn archive_write_close
+as needed.
+.It Fn archive_write_close
+Set any attributes that could not be set during the initial restore.
+For example, directory timestamps are not restored initially because
+restoring a subsequent file would alter that timestamp.
+Similarly, non-writable directories are initially created with
+write permissions (so that their contents can be restored).
+The
+.Nm
+library maintains a list of all such deferred attributes and
+sets them when this function is invoked.
+.It Fn archive_write_finish
+Invokes
+.Fn archive_write_close
+if it was not invoked manually, then releases all resources.
+.El
+More information about the
+.Va struct archive
+object and the overall design of the library can be found in the
+.Xr libarchive 3
+overview.
+Many of these functions are also documented under
+.Xr archive_write 3 .
+.Sh RETURN VALUES
+Most functions return
+.Cm ARCHIVE_OK
+(zero) on success, or one of several non-zero
+error codes for errors.
+Specific error codes include:
+.Cm ARCHIVE_RETRY
+for operations that might succeed if retried,
+.Cm ARCHIVE_WARN
+for unusual conditions that do not prevent further operations, and
+.Cm ARCHIVE_FATAL
+for serious errors that make remaining operations impossible.
+The
+.Fn archive_errno
+and
+.Fn archive_error_string
+functions can be used to retrieve an appropriate error code and a
+textual error message.
+.Pp
+.Fn archive_write_disk_new
+returns a pointer to a newly-allocated
+.Tn struct archive
+object.
+.Pp
+.Fn archive_write_data
+returns a count of the number of bytes actually written.
+On error, -1 is returned and the
+.Fn archive_errno
+and
+.Fn archive_error_string
+functions will return appropriate values.
+.Sh SEE ALSO
+.Xr archive_read 3 ,
+.Xr archive_write 3 ,
+.Xr tar 1 ,
+.Xr libarchive 3
+.Sh HISTORY
+The
+.Nm libarchive
+library first appeared in
+.Fx 5.3 .
+The
+.Nm archive_write_disk
+interface was added to
+.Nm libarchive 2.0
+and first appeared in
+.Fx 6.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_write_header ,
+but final permissions are not set until
+.Fn archive_write_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
+The library attempts to create objects with filenames longer than
+.Cm PATH_MAX
+by creating prefixes of the full path and changing the current directory.
+Currently, this logic is limited in scope; the fixup pass does
+not work correctly for such objects and the symlink security check
+option disables the support for very long pathnames.
+.Pp
+Restoring the path
+.Pa aa/../bb
+does create each intermediate directory.
+In particular, the directory
+.Pa aa
+is created as well as the final object
+.Pa bb .
+In theory, this can be exploited to create an entire directory heirarchy
+with a single request.
+Of course, this does not work if the
+.Cm ARCHIVE_EXTRACT_NODOTDOT
+option is specified.
+.Pp
+Implicit directories are always created obeying the current umask.
+Explicit objects are created obeying the current umask unless
+.Cm ARCHIVE_EXTRACT_PERM
+is specified, in which case they current umask is ignored.
+.Pp
+SGID and SUID bits are restored only if the correct user and
+group could be set.
+If
+.Cm ARCHIVE_EXTRACT_OWNER
+is not specified, then no attempt is made to set the ownership.
+In this case, SGID and SUID bits are restored only if the
+user and group of the final object happen to match those specified
+in the entry.
+.Pp
+The
+.Dq standard
+user-id and group-id lookup functions are not the defaults because
+.Xr getgrnam 3
+and
+.Xr getpwnam 3
+are sometimes too large for particular applications.
+The current design allows the application author to use a more
+compact implementation when appropriate.
+.Pp
+There should be a corresponding
+.Nm archive_read_disk
+interface that walks a directory heirarchy and returns archive
+entry objects. \ No newline at end of file
diff --git a/lib/libarchive/archive_write_disk.c b/lib/libarchive/archive_write_disk.c
new file mode 100644
index 0000000..f6187b8
--- /dev/null
+++ b/lib/libarchive/archive_write_disk.c
@@ -0,0 +1,1929 @@
+/*-
+ * 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
+ * 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_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_ACL_H
+#include <sys/acl.h>
+#endif
+#ifdef HAVE_ATTR_XATTR_H
+#include <attr/xattr.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_EXT2FS_EXT2_FS_H
+#include <ext2fs/ext2_fs.h> /* for Linux file flags */
+#endif
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_GRP_H
+#include <grp.h>
+#endif
+#ifdef HAVE_LINUX_EXT2_FS_H
+#include <linux/ext2_fs.h> /* for Linux file flags */
+#endif
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "archive.h"
+#include "archive_string.h"
+#include "archive_entry.h"
+#include "archive_private.h"
+
+struct fixup_entry {
+ struct fixup_entry *next;
+ mode_t mode;
+ int64_t mtime;
+ int64_t atime;
+ unsigned long mtime_nanos;
+ unsigned long atime_nanos;
+ unsigned long fflags_set;
+ int fixup; /* bitmask of what needs fixing */
+ char *name;
+};
+
+/*
+ * We use a bitmask to track which operations remain to be done for
+ * this file. In particular, this helps us avoid unnecessary
+ * operations when it's possible to take care of one step as a
+ * side-effect of another. For example, mkdir() can specify the mode
+ * for the newly-created object but symlink() cannot. This means we
+ * can skip chmod() if mkdir() succeeded, but we must explicitly
+ * chmod() if we're trying to create a directory that already exists
+ * (mkdir() failed) or if we're restoring a symlink. Similarly, we
+ * need to verify UID/GID before trying to restore SUID/SGID bits;
+ * that verification can occur explicitly through a stat() call or
+ * implicitly because of a successful chown() call.
+ */
+#define TODO_MODE_BASE 0x20000000
+#define TODO_SUID 0x10000000
+#define TODO_SUID_CHECK 0x08000000
+#define TODO_SGID 0x04000000
+#define TODO_SGID_CHECK 0x02000000
+#define TODO_MODE (TODO_MODE_BASE|TODO_SUID|TODO_SGID)
+#define TODO_TIMES ARCHIVE_EXTRACT_TIME
+#define TODO_OWNER ARCHIVE_EXTRACT_OWNER
+#define TODO_FFLAGS ARCHIVE_EXTRACT_FFLAGS
+#define TODO_ACLS ARCHIVE_EXTRACT_ACL
+#define TODO_XATTR ARCHIVE_EXTRACT_XATTR
+
+struct archive_write_disk {
+ struct archive archive;
+
+ mode_t user_umask;
+ struct fixup_entry *fixup_list;
+ struct fixup_entry *current_fixup;
+ uid_t user_uid;
+ dev_t skip_file_dev;
+ ino_t skip_file_ino;
+
+ gid_t (*lookup_gid)(void *private, const char *gname, gid_t gid);
+ void (*cleanup_gid)(void *private);
+ void *lookup_gid_data;
+ uid_t (*lookup_uid)(void *private, const char *gname, gid_t gid);
+ void (*cleanup_uid)(void *private);
+ void *lookup_uid_data;
+
+ /*
+ * Full path of last file to satisfy symlink checks.
+ */
+ struct archive_string path_safe;
+
+ /*
+ * Cached stat data from disk for the current entry.
+ * If this is valid, pst points to st. Otherwise,
+ * pst is null.
+ */
+ struct stat st;
+ struct stat *pst;
+
+ /* Information about the object being restored right now. */
+ struct archive_entry *entry; /* Entry being extracted. */
+ char *name; /* Name of entry, possibly edited. */
+ struct archive_string _name_data; /* backing store for 'name' */
+ /* Tasks remaining for this object. */
+ int todo;
+ /* Tasks deferred until end-of-archive. */
+ int deferred;
+ /* Options requested by the client. */
+ int flags;
+ /* Handle for the file we're restoring. */
+ int fd;
+ /* Current offset for writing data to the file. */
+ off_t offset;
+ /* Dir we were in before this restore; only for deep paths. */
+ int restore_pwd;
+ /* Mode we should use for this entry; affected by _PERM and umask. */
+ mode_t mode;
+ /* UID/GID to use in restoring this entry. */
+ uid_t uid;
+ gid_t gid;
+};
+
+/*
+ * Default mode for dirs created automatically (will be modified by umask).
+ * Note that POSIX specifies 0777 for implicity-created dirs, "modified
+ * by the process' file creation mask."
+ */
+#define DEFAULT_DIR_MODE 0777
+/*
+ * Dir modes are restored in two steps: During the extraction, the permissions
+ * in the archive are modified to match the following limits. During
+ * the post-extract fixup pass, the permissions from the archive are
+ * applied.
+ */
+#define MINIMUM_DIR_MODE 0700
+#define MAXIMUM_DIR_MODE 0775
+
+static int check_symlinks(struct archive_write_disk *);
+static int create_filesystem_object(struct archive_write_disk *);
+static struct fixup_entry *current_fixup(struct archive_write_disk *, const char *pathname);
+#ifdef HAVE_FCHDIR
+static void edit_deep_directories(struct archive_write_disk *ad);
+#endif
+static int cleanup_pathname(struct archive_write_disk *);
+static int create_dir(struct archive_write_disk *, char *);
+static int create_parent_dir(struct archive_write_disk *, char *);
+static int restore_entry(struct archive_write_disk *);
+#ifdef HAVE_POSIX_ACL
+static int set_acl(struct archive_write_disk *, int fd, struct archive_entry *,
+ acl_type_t, int archive_entry_acl_type, const char *tn);
+#endif
+static int set_acls(struct archive_write_disk *);
+static int set_xattrs(struct archive_write_disk *);
+static int set_fflags(struct archive_write_disk *);
+static int set_fflags_platform(struct archive_write_disk *, int fd,
+ const char *name, mode_t mode,
+ unsigned long fflags_set, unsigned long fflags_clear);
+static int set_ownership(struct archive_write_disk *);
+static int set_mode(struct archive_write_disk *, int mode);
+static int set_time(struct archive_write_disk *);
+static struct fixup_entry *sort_dir_list(struct fixup_entry *p);
+static gid_t trivial_lookup_gid(void *, const char *, gid_t);
+static uid_t trivial_lookup_uid(void *, const char *, uid_t);
+
+
+static struct archive_vtable *archive_write_disk_vtable(void);
+
+static int _archive_write_close(struct archive *);
+static int _archive_write_finish(struct archive *);
+static int _archive_write_header(struct archive *, struct archive_entry *);
+static int _archive_write_finish_entry(struct archive *);
+static ssize_t _archive_write_data(struct archive *, const void *, size_t);
+static ssize_t _archive_write_data_block(struct archive *, const void *, size_t, off_t);
+
+static struct archive_vtable *
+archive_write_disk_vtable(void)
+{
+ static struct archive_vtable av;
+ static int inited = 0;
+
+ if (!inited) {
+ av.archive_write_close = _archive_write_close;
+ av.archive_write_finish = _archive_write_finish;
+ av.archive_write_header = _archive_write_header;
+ av.archive_write_finish_entry = _archive_write_finish_entry;
+ av.archive_write_data = _archive_write_data;
+ av.archive_write_data_block = _archive_write_data_block;
+ }
+ return (&av);
+}
+
+
+int
+archive_write_disk_set_options(struct archive *_a, int flags)
+{
+ struct archive_write_disk *a = (struct archive_write_disk *)_a;
+
+ a->flags = flags;
+ return (ARCHIVE_OK);
+}
+
+
+/*
+ * Extract this entry to disk.
+ *
+ * TODO: Validate hardlinks. According to the standards, we're
+ * supposed to check each extracted hardlink and squawk if it refers
+ * to a file that we didn't restore. I'm not entirely convinced this
+ * is a good idea, but more importantly: Is there any way to validate
+ * hardlinks without keeping a complete list of filenames from the
+ * entire archive?? Ugh.
+ *
+ */
+static int
+_archive_write_header(struct archive *_a, struct archive_entry *entry)
+{
+ struct archive_write_disk *a = (struct archive_write_disk *)_a;
+ struct fixup_entry *fe;
+ int ret, r;
+
+ __archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
+ ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
+ "archive_write_disk_header");
+ archive_clear_error(&a->archive);
+ if (a->archive.state & ARCHIVE_STATE_DATA) {
+ r = _archive_write_finish_entry(&a->archive);
+ if (r != ARCHIVE_OK)
+ return (r);
+ }
+
+ /* Set up for this particular entry. */
+ a->pst = NULL;
+ a->current_fixup = NULL;
+ a->deferred = 0;
+ a->entry = entry;
+ a->fd = -1;
+ a->offset = 0;
+ a->uid = a->user_uid;
+ a->mode = archive_entry_mode(a->entry);
+ archive_strcpy(&(a->_name_data), archive_entry_pathname(a->entry));
+ a->name = a->_name_data.s;
+ archive_clear_error(&a->archive);
+
+ /*
+ * Clean up the requested path. This is necessary for correct
+ * dir restores; the dir restore logic otherwise gets messed
+ * up by nonsense like "dir/.".
+ */
+ ret = cleanup_pathname(a);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+
+ /*
+ * Set the umask to zero so we get predictable mode settings.
+ * This gets done on every call to _write_header in case the
+ * user edits their umask during the extraction for some
+ * reason. This will be reset before we return. Note that we
+ * don't need to do this in _finish_entry, as the chmod(), etc,
+ * system calls don't obey umask.
+ */
+ a->user_umask = umask(0);
+ /* From here on, early exit requires "goto done" to clean up. */
+
+ /* Figure out what we need to do for this entry. */
+ a->todo = TODO_MODE_BASE;
+ if (a->flags & ARCHIVE_EXTRACT_PERM) {
+ /*
+ * SGID requires an extra "check" step because we
+ * cannot easily predict the GID that the system will
+ * assign. (Different systems assign GIDs to files
+ * based on a variety of criteria, including process
+ * credentials and the gid of the enclosing
+ * directory.) We can only restore the SGID bit if
+ * the file has the right GID, and we only know the
+ * GID if we either set it (see set_ownership) or if
+ * we've actually called stat() on the file after it
+ * was restored. Since there are several places at
+ * which we might verify the GID, we need a TODO bit
+ * to keep track.
+ */
+ if (a->mode & S_ISGID)
+ a->todo |= TODO_SGID | TODO_SGID_CHECK;
+ /*
+ * Verifying the SUID is simpler, but can still be
+ * done in multiple ways, hence the separate "check" bit.
+ */
+ if (a->mode & S_ISUID)
+ a->todo |= TODO_SUID | TODO_SUID_CHECK;
+ } else {
+ /*
+ * User didn't request full permissions, so don't
+ * restore SUID, SGID bits and obey umask.
+ */
+ a->mode &= ~S_ISUID;
+ a->mode &= ~S_ISGID;
+ a->mode &= ~S_ISVTX;
+ a->mode &= ~a->user_umask;
+ }
+ if (a->flags & ARCHIVE_EXTRACT_OWNER)
+ a->todo |= TODO_OWNER;
+ if (a->flags & ARCHIVE_EXTRACT_TIME)
+ a->todo |= TODO_TIMES;
+ if (a->flags & ARCHIVE_EXTRACT_ACL)
+ a->todo |= TODO_ACLS;
+ if (a->flags & ARCHIVE_EXTRACT_FFLAGS)
+ a->todo |= TODO_FFLAGS;
+ if (a->flags & ARCHIVE_EXTRACT_SECURE_SYMLINKS) {
+ ret = check_symlinks(a);
+ if (ret != ARCHIVE_OK)
+ goto done;
+ }
+#ifdef HAVE_FCHDIR
+ /* If path exceeds PATH_MAX, shorten the path. */
+ edit_deep_directories(a);
+#endif
+
+ ret = restore_entry(a);
+
+#ifdef HAVE_FCHDIR
+ /* If we changed directory above, restore it here. */
+ if (a->restore_pwd >= 0) {
+ fchdir(a->restore_pwd);
+ close(a->restore_pwd);
+ a->restore_pwd = -1;
+ }
+#endif
+
+ /*
+ * Fixup uses the unedited pathname from archive_entry_pathname(),
+ * because it is relative to the base dir and the edited path
+ * might be relative to some intermediate dir as a result of the
+ * deep restore logic.
+ */
+ if (a->deferred & TODO_MODE) {
+ fe = current_fixup(a, archive_entry_pathname(entry));
+ fe->fixup |= TODO_MODE_BASE;
+ fe->mode = a->mode;
+ }
+
+ if (a->deferred & TODO_TIMES) {
+ fe = current_fixup(a, archive_entry_pathname(entry));
+ fe->fixup |= TODO_TIMES;
+ fe->mtime = archive_entry_mtime(entry);
+ fe->mtime_nanos = archive_entry_mtime_nsec(entry);
+ fe->atime = archive_entry_atime(entry);
+ fe->atime_nanos = archive_entry_atime_nsec(entry);
+ }
+
+ if (a->deferred & TODO_FFLAGS) {
+ fe = current_fixup(a, archive_entry_pathname(entry));
+ fe->fixup |= TODO_FFLAGS;
+ /* TODO: Complete this.. defer fflags from below. */
+ }
+
+ /* We've created the object and are ready to pour data into it. */
+ if (ret == ARCHIVE_OK)
+ a->archive.state = ARCHIVE_STATE_DATA;
+done:
+ /* Restore the user's umask before returning. */
+ umask(a->user_umask);
+
+ return (ret);
+}
+
+int
+archive_write_disk_set_skip_file(struct archive *_a, dev_t d, ino_t i)
+{
+ struct archive_write_disk *a = (struct archive_write_disk *)_a;
+ __archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
+ ARCHIVE_STATE_ANY, "archive_write_disk_set_skip_file");
+ a->skip_file_dev = d;
+ a->skip_file_ino = i;
+ return (ARCHIVE_OK);
+}
+
+static ssize_t
+_archive_write_data_block(struct archive *_a,
+ const void *buff, size_t size, off_t offset)
+{
+ struct archive_write_disk *a = (struct archive_write_disk *)_a;
+ ssize_t bytes_written = 0;
+
+ __archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
+ ARCHIVE_STATE_DATA, "archive_write_disk_block");
+ if (a->fd < 0)
+ return (ARCHIVE_OK);
+ archive_clear_error(&a->archive);
+
+ /* Seek if necessary to the specified offset. */
+ if (offset != a->offset) {
+ if (lseek(a->fd, offset, SEEK_SET) < 0) {
+ archive_set_error(&a->archive, errno, "Seek failed");
+ return (ARCHIVE_WARN);
+ }
+ a->offset = offset;
+ }
+
+ /* Write the data. */
+ while (size > 0) {
+ bytes_written = write(a->fd, buff, size);
+ if (bytes_written < 0) {
+ archive_set_error(&a->archive, errno, "Write failed");
+ return (ARCHIVE_WARN);
+ }
+ size -= bytes_written;
+ a->offset += bytes_written;
+ }
+ return (ARCHIVE_OK);
+}
+
+static ssize_t
+_archive_write_data(struct archive *_a, const void *buff, size_t size)
+{
+ struct archive_write_disk *a = (struct archive_write_disk *)_a;
+ __archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
+ ARCHIVE_STATE_DATA, "archive_write_data");
+ if (a->fd < 0)
+ return (ARCHIVE_OK);
+
+ return (_archive_write_data_block(_a, buff, size, a->offset));
+}
+
+static int
+_archive_write_finish_entry(struct archive *_a)
+{
+ struct archive_write_disk *a = (struct archive_write_disk *)_a;
+ int ret = ARCHIVE_OK;
+
+ __archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
+ ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
+ "archive_write_finish_entry");
+ if (a->archive.state & ARCHIVE_STATE_HEADER)
+ return (ARCHIVE_OK);
+ archive_clear_error(&a->archive);
+
+ /* Restore metadata. */
+
+ /*
+ * Look up the "real" UID only if we're going to need it. We
+ * need this for TODO_SGID because chown() requires both.
+ */
+ if (a->todo & (TODO_OWNER | TODO_SUID | TODO_SGID)) {
+ a->uid = a->lookup_uid(a->lookup_uid_data,
+ archive_entry_uname(a->entry),
+ archive_entry_uid(a->entry));
+ }
+ /* Look up the "real" GID only if we're going to need it. */
+ if (a->todo & (TODO_OWNER | TODO_SGID | TODO_SUID)) {
+ a->gid = a->lookup_gid(a->lookup_gid_data,
+ archive_entry_gname(a->entry),
+ archive_entry_gid(a->entry));
+ }
+ /*
+ * If restoring ownership, do it before trying to restore suid/sgid
+ * bits. If we set the owner, we know what it is and can skip
+ * a stat() call to examine the ownership of the file on disk.
+ */
+ if (a->todo & TODO_OWNER)
+ ret = set_ownership(a);
+ if (a->todo & TODO_MODE) {
+ int r2 = set_mode(a, a->mode);
+ if (r2 < ret) ret = r2;
+ }
+ if (a->todo & TODO_TIMES) {
+ int r2 = set_time(a);
+ if (r2 < ret) ret = r2;
+ }
+ if (a->todo & TODO_ACLS) {
+ int r2 = set_acls(a);
+ if (r2 < ret) ret = r2;
+ }
+ if (a->todo & TODO_XATTR) {
+ int r2 = set_xattrs(a);
+ if (r2 < ret) ret = r2;
+ }
+ if (a->todo & TODO_FFLAGS) {
+ int r2 = set_fflags(a);
+ if (r2 < ret) ret = r2;
+ }
+
+ /* If there's an fd, we can close it now. */
+ if (a->fd >= 0) {
+ close(a->fd);
+ a->fd = -1;
+ }
+ a->archive.state = ARCHIVE_STATE_HEADER;
+ return (ret);
+}
+
+int
+archive_write_disk_set_group_lookup(struct archive *_a,
+ void *private_data,
+ gid_t (*lookup_gid)(void *private, const char *gname, gid_t gid),
+ void (*cleanup_gid)(void *private))
+{
+ struct archive_write_disk *a = (struct archive_write_disk *)_a;
+ __archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
+ ARCHIVE_STATE_ANY, "archive_write_disk_set_group_lookup");
+
+ a->lookup_gid = lookup_gid;
+ a->cleanup_gid = cleanup_gid;
+ a->lookup_gid_data = private_data;
+ return (ARCHIVE_OK);
+}
+
+int
+archive_write_disk_set_user_lookup(struct archive *_a,
+ void *private_data,
+ uid_t (*lookup_uid)(void *private, const char *uname, uid_t uid),
+ void (*cleanup_uid)(void *private))
+{
+ struct archive_write_disk *a = (struct archive_write_disk *)_a;
+ __archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
+ ARCHIVE_STATE_ANY, "archive_write_disk_set_user_lookup");
+
+ a->lookup_uid = lookup_uid;
+ a->cleanup_uid = cleanup_uid;
+ a->lookup_uid_data = private_data;
+ return (ARCHIVE_OK);
+}
+
+
+/*
+ * Create a new archive_write_disk object and initialize it with global state.
+ */
+struct archive *
+archive_write_disk_new(void)
+{
+ struct archive_write_disk *a;
+
+ a = (struct archive_write_disk *)malloc(sizeof(*a));
+ if (a == NULL)
+ return (NULL);
+ memset(a, 0, sizeof(*a));
+ a->archive.magic = ARCHIVE_WRITE_DISK_MAGIC;
+ /* We're ready to write a header immediately. */
+ a->archive.state = ARCHIVE_STATE_HEADER;
+ a->archive.vtable = archive_write_disk_vtable();
+ a->lookup_uid = trivial_lookup_uid;
+ a->lookup_gid = trivial_lookup_gid;
+ a->user_uid = geteuid();
+ archive_string_ensure(&a->path_safe, 64);
+ return (&a->archive);
+}
+
+
+/*
+ * If pathname is longer than PATH_MAX, chdir to a suitable
+ * intermediate dir and edit the path down to a shorter suffix. Note
+ * that this routine never returns an error; if the chdir() attempt
+ * fails for any reason, we just go ahead with the long pathname. The
+ * object creation is likely to fail, but any error will get handled
+ * at that time.
+ */
+#ifdef HAVE_FCHDIR
+static void
+edit_deep_directories(struct archive_write_disk *a)
+{
+ int ret;
+ char *tail = a->name;
+
+ a->restore_pwd = -1;
+
+ /* If path is short, avoid the open() below. */
+ if (strlen(tail) <= PATH_MAX)
+ return;
+
+ /* Try to record our starting dir. */
+ a->restore_pwd = open(".", O_RDONLY);
+ if (a->restore_pwd < 0)
+ return;
+
+ /* As long as the path is too long... */
+ while (strlen(tail) > PATH_MAX) {
+ /* Locate a dir prefix shorter than PATH_MAX. */
+ tail += PATH_MAX - 8;
+ while (tail > a->name && *tail != '/')
+ tail--;
+ /* Exit if we find a too-long path component. */
+ if (tail <= a->name)
+ return;
+ /* Create the intermediate dir and chdir to it. */
+ *tail = '\0'; /* Terminate dir portion */
+ ret = create_dir(a, a->name);
+ if (ret == ARCHIVE_OK && chdir(a->name) != 0)
+ ret = ARCHIVE_WARN;
+ *tail = '/'; /* Restore the / we removed. */
+ if (ret != ARCHIVE_OK)
+ return;
+ tail++;
+ /* The chdir() succeeded; we've now shortened the path. */
+ a->name = tail;
+ }
+ return;
+}
+#endif
+
+/*
+ * The main restore function.
+ */
+static int
+restore_entry(struct archive_write_disk *a)
+{
+ int ret = ARCHIVE_OK, en;
+
+ if (a->flags & ARCHIVE_EXTRACT_UNLINK)
+ if (unlink(a->name) != 0 && errno != ENOENT) {
+ /* If the file doesn't exist, that's okay. */
+ /* Anything else is a problem. */
+ archive_set_error(&a->archive, errno,
+ "Could not unlink");
+ return(ARCHIVE_WARN);
+ }
+
+ /* Try creating it first; if this fails, we'll try to recover. */
+ en = create_filesystem_object(a);
+
+ if (en == ENOTDIR || en == ENOENT) {
+ /* If the parent dir doesn't exist, try creating it. */
+ create_parent_dir(a, a->name);
+ /* Now try to create the object again. */
+ en = create_filesystem_object(a);
+ }
+
+ if (en == EEXIST) {
+ /* If we're not overwriting, we're done. */
+ if (a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE) {
+ archive_set_error(&a->archive, en, "Already exists");
+ return (ARCHIVE_WARN);
+ }
+
+ /* Find out what's in the way before we go any further. */
+ if (lstat(a->name, &a->st) != 0) {
+ archive_set_error(&a->archive, errno,
+ "Can't stat existing object");
+ return (ARCHIVE_WARN);
+ }
+
+ /* TODO: if it's a symlink... */
+
+ /* If it's our archive, we're done. */
+ if (a->skip_file_dev > 0 &&
+ a->skip_file_ino > 0 &&
+ a->st.st_dev == a->skip_file_dev &&
+ a->st.st_ino == a->skip_file_ino) {
+ archive_set_error(&a->archive, 0, "Refusing to overwrite archive");
+ return (ARCHIVE_WARN);
+ }
+
+ if (!S_ISDIR(a->st.st_mode)) {
+ /* A non-dir is in the way, unlink it. */
+ if (unlink(a->name) != 0) {
+ archive_set_error(&a->archive, errno,
+ "Can't unlink already-existing object");
+ return (ARCHIVE_WARN);
+ }
+ /* Try again. */
+ en = create_filesystem_object(a);
+ } else if (!S_ISDIR(a->mode)) {
+ /* A dir is in the way of a non-dir, rmdir it. */
+ if (rmdir(a->name) != 0) {
+ archive_set_error(&a->archive, errno,
+ "Can't remove already-existing dir");
+ return (ARCHIVE_WARN);
+ }
+ /* Try again. */
+ en = create_filesystem_object(a);
+ } else {
+ /*
+ * There's a dir in the way of a dir. Don't
+ * waste time with rmdir()/mkdir(), just fix
+ * up the permissions on the existing dir.
+ */
+ if (a->mode != a->st.st_mode)
+ a->deferred |= TODO_MODE;
+ /* Ownership doesn't need deferred fixup. */
+ en = 0; /* Forget the EEXIST. */
+ }
+ }
+
+ if (en) {
+ /* Everything failed; give up here. */
+ archive_set_error(&a->archive, en, "Can't create '%s'", a->name);
+ return (ARCHIVE_WARN);
+ }
+
+ a->pst = NULL; /* Cached stat data no longer valid. */
+ return (ret);
+}
+
+/*
+ * Returns 0 if creation succeeds, or else returns errno value from
+ * the failed system call. Note: This function should only ever perform
+ * a single system call.
+ */
+int
+create_filesystem_object(struct archive_write_disk *a)
+{
+ /* Create the entry. */
+ const char *linkname;
+ mode_t final_mode, mode;
+ int r;
+
+ /* We identify hard/symlinks according to the link names. */
+ /* Since link(2) and symlink(2) don't handle modes, we're done here. */
+ linkname = archive_entry_hardlink(a->entry);
+ if (linkname != NULL)
+ return link(linkname, a->name) ? errno : 0;
+ linkname = archive_entry_symlink(a->entry);
+ if (linkname != NULL)
+ return symlink(linkname, a->name) ? errno : 0;
+
+ /*
+ * The remaining system calls all set permissions, so let's
+ * try to take advantage of that to avoid an extra chmod()
+ * call. (Recall that umask is set to zero right now!)
+ */
+
+ /* Mode we want for the final restored object (w/o file type bits). */
+ final_mode = a->mode & 07777;
+ /*
+ * The mode that will actually be restored in this step. Note
+ * that SUID, SGID, etc, require additional work to ensure
+ * security, so we never restore them at this point.
+ */
+ mode = final_mode & 0777;
+
+ switch (a->mode & S_IFMT) {
+ default:
+ /* Fall through, as required by POSIX. */
+ case S_IFREG:
+ a->fd = open(a->name,
+ O_WRONLY | O_CREAT | O_EXCL, mode);
+ r = (a->fd < 0);
+ break;
+ case S_IFCHR:
+ r = mknod(a->name, mode | S_IFCHR,
+ archive_entry_rdev(a->entry));
+ break;
+ case S_IFBLK:
+ r = mknod(a->name, mode | S_IFBLK,
+ archive_entry_rdev(a->entry));
+ break;
+ case S_IFDIR:
+ mode = (mode | MINIMUM_DIR_MODE) & MAXIMUM_DIR_MODE;
+ r = mkdir(a->name, mode);
+ /* Defer setting dir times. */
+ a->deferred |= (a->todo & TODO_TIMES);
+ a->todo &= ~TODO_TIMES;
+ /* Never use an immediate chmod(). */
+ if (mode != final_mode)
+ a->deferred |= (a->todo & TODO_MODE);
+ a->todo &= ~TODO_MODE;
+ break;
+ case S_IFIFO:
+ r = mkfifo(a->name, mode);
+ break;
+ }
+
+ /* All the system calls above set errno on failure. */
+ if (r)
+ return (errno);
+
+ /* If we managed to set the final mode, we've avoided a chmod(). */
+ if (mode == final_mode)
+ a->todo &= ~TODO_MODE;
+ return (0);
+}
+
+/*
+ * Cleanup function for archive_extract. Mostly, this involves processing
+ * the fixup list, which is used to address a number of problems:
+ * * Dir permissions might prevent us from restoring a file in that
+ * dir, so we restore the dir with minimum 0700 permissions first,
+ * then correct the mode at the end.
+ * * Similarly, the act of restoring a file touches the directory
+ * and changes the timestamp on the dir, so we have to touch-up dir
+ * timestamps at the end as well.
+ * * Some file flags can interfere with the restore by, for example,
+ * preventing the creation of hardlinks to those files.
+ *
+ * Note that tar/cpio do not require that archives be in a particular
+ * order; there is no way to know when the last file has been restored
+ * within a directory, so there's no way to optimize the memory usage
+ * here by fixing up the directory any earlier than the
+ * end-of-archive.
+ *
+ * XXX TODO: Directory ACLs should be restored here, for the same
+ * reason we set directory perms here. XXX
+ */
+static int
+_archive_write_close(struct archive *_a)
+{
+ struct archive_write_disk *a = (struct archive_write_disk *)_a;
+ struct fixup_entry *next, *p;
+ int ret;
+
+ __archive_check_magic(&a->archive, ARCHIVE_WRITE_DISK_MAGIC,
+ ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
+ "archive_write_disk_close");
+ ret = _archive_write_finish_entry(&a->archive);
+
+ /* Sort dir list so directories are fixed up in depth-first order. */
+ p = sort_dir_list(a->fixup_list);
+
+ while (p != NULL) {
+ a->pst = NULL; /* Mark stat cache as out-of-date. */
+ if (p->fixup & TODO_TIMES) {
+ struct timeval times[2];
+ times[1].tv_sec = p->mtime;
+ times[1].tv_usec = p->mtime_nanos / 1000;
+ times[0].tv_sec = p->atime;
+ times[0].tv_usec = p->atime_nanos / 1000;
+#ifdef HAVE_LUTIMES
+ lutimes(p->name, times);
+#else
+ utimes(p->name, times);
+#endif
+ }
+ if (p->fixup & TODO_MODE_BASE)
+ chmod(p->name, p->mode);
+
+ if (p->fixup & TODO_FFLAGS)
+ set_fflags_platform(a, -1, p->name,
+ p->mode, p->fflags_set, 0);
+
+ next = p->next;
+ free(p->name);
+ free(p);
+ p = next;
+ }
+ a->fixup_list = NULL;
+ return (ret);
+}
+
+static int
+_archive_write_finish(struct archive *_a)
+{
+ struct archive_write_disk *a = (struct archive_write_disk *)_a;
+ int ret;
+ ret = _archive_write_close(&a->archive);
+ archive_string_free(&a->_name_data);
+ archive_string_free(&a->archive.error_string);
+ archive_string_free(&a->path_safe);
+ free(a);
+ return (ret);
+}
+
+/*
+ * Simple O(n log n) merge sort to order the fixup list. In
+ * particular, we want to restore dir timestamps depth-first.
+ */
+static struct fixup_entry *
+sort_dir_list(struct fixup_entry *p)
+{
+ struct fixup_entry *a, *b, *t;
+
+ if (p == NULL)
+ return (NULL);
+ /* A one-item list is already sorted. */
+ if (p->next == NULL)
+ return (p);
+
+ /* Step 1: split the list. */
+ t = p;
+ a = p->next->next;
+ while (a != NULL) {
+ /* Step a twice, t once. */
+ a = a->next;
+ if (a != NULL)
+ a = a->next;
+ t = t->next;
+ }
+ /* Now, t is at the mid-point, so break the list here. */
+ b = t->next;
+ t->next = NULL;
+ a = p;
+
+ /* Step 2: Recursively sort the two sub-lists. */
+ a = sort_dir_list(a);
+ b = sort_dir_list(b);
+
+ /* Step 3: Merge the returned lists. */
+ /* Pick the first element for the merged list. */
+ if (strcmp(a->name, b->name) > 0) {
+ t = p = a;
+ a = a->next;
+ } else {
+ t = p = b;
+ b = b->next;
+ }
+
+ /* Always put the later element on the list first. */
+ while (a != NULL && b != NULL) {
+ if (strcmp(a->name, b->name) > 0) {
+ t->next = a;
+ a = a->next;
+ } else {
+ t->next = b;
+ b = b->next;
+ }
+ t = t->next;
+ }
+
+ /* Only one list is non-empty, so just splice it on. */
+ if (a != NULL)
+ t->next = a;
+ if (b != NULL)
+ t->next = b;
+
+ return (p);
+}
+
+/*
+ * Returns a new, initialized fixup entry.
+ *
+ * TODO: Reduce the memory requirements for this list by using a tree
+ * structure rather than a simple list of names.
+ */
+static struct fixup_entry *
+new_fixup(struct archive_write_disk *a, const char *pathname)
+{
+ struct fixup_entry *fe;
+
+ fe = (struct fixup_entry *)malloc(sizeof(struct fixup_entry));
+ if (fe == NULL)
+ return (NULL);
+ fe->next = a->fixup_list;
+ a->fixup_list = fe;
+ fe->fixup = 0;
+ fe->name = strdup(pathname);
+ return (fe);
+}
+
+/*
+ * Returns a fixup structure for the current entry.
+ */
+static struct fixup_entry *
+current_fixup(struct archive_write_disk *a, const char *pathname)
+{
+ if (a->current_fixup == NULL)
+ a->current_fixup = new_fixup(a, pathname);
+ return (a->current_fixup);
+}
+
+/* TODO: Make this work. */
+/*
+ * TODO: The deep-directory support bypasses this; disable deep directory
+ * support if we're doing symlink checks.
+ */
+/*
+ * TODO: Someday, integrate this with the deep dir support; they both
+ * scan the path and both can be optimized by comparing against other
+ * recent paths.
+ */
+static int
+check_symlinks(struct archive_write_disk *a)
+{
+ char *pn, *p;
+ char c;
+ int r;
+ struct stat st;
+
+ /*
+ * Gaurd against symlink tricks. Reject any archive entry whose
+ * destination would be altered by a symlink.
+ */
+ /* Whatever we checked last time doesn't need to be re-checked. */
+ pn = a->name;
+ p = a->path_safe.s;
+ while ((*pn != '\0') && (*p == *pn))
+ ++p, ++pn;
+ c = pn[0];
+ /* Keep going until we've checked the entire name. */
+ while (pn[0] != '\0' && (pn[0] != '/' || pn[1] != '\0')) {
+ /* Skip the next path element. */
+ while (*pn != '\0' && *pn != '/')
+ ++pn;
+ c = pn[0];
+ pn[0] = '\0';
+ /* Check that we haven't hit a symlink. */
+ r = lstat(a->name, &st);
+ if (r != 0) {
+ /* We've hit a dir that doesn't exist; stop now. */
+ if (errno == ENOENT)
+ break;
+ } else if (S_ISLNK(st.st_mode)) {
+ if (c == '\0') {
+ /*
+ * Last element is symlink; remove it
+ * so we can overwrite it with the
+ * item being extracted.
+ */
+ if (unlink(a->name)) {
+ archive_set_error(&a->archive, errno,
+ "Could not remove symlink %s",
+ a->name);
+ pn[0] = c;
+ return (ARCHIVE_WARN);
+ }
+ /*
+ * Even if we did remove it, a warning
+ * is in order. The warning is silly,
+ * though, if we're just replacing one
+ * symlink with another symlink.
+ */
+ if (!S_ISLNK(a->mode)) {
+ archive_set_error(&a->archive, 0,
+ "Removing symlink %s",
+ a->name);
+ }
+ /* Symlink gone. No more problem! */
+ pn[0] = c;
+ return (0);
+ } else if (a->flags & ARCHIVE_EXTRACT_UNLINK) {
+ /* User asked us to remove problems. */
+ if (unlink(a->name) != 0) {
+ archive_set_error(&a->archive, 0,
+ "Cannot remove intervening symlink %s",
+ a->name);
+ pn[0] = c;
+ return (ARCHIVE_WARN);
+ }
+ } else {
+ archive_set_error(&a->archive, 0,
+ "Cannot extract through symlink %s",
+ a->name);
+ pn[0] = c;
+ return (ARCHIVE_WARN);
+ }
+ }
+ }
+ pn[0] = c;
+ /* We've checked and/or cleaned the whole path, so remember it. */
+ archive_strcpy(&a->path_safe, a->name);
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Canonicalize the pathname. In particular, this strips duplicate
+ * '/' characters, '.' elements, and trailing '/'. It also raises an
+ * error for an empty path, a trailing '..' or (if _SECURE_NODOTDOT is
+ * set) any '..' in the path.
+ */
+static int
+cleanup_pathname(struct archive_write_disk *a)
+{
+ char *dest, *src;
+ char separator = '\0';
+ int lastdotdot = 0; /* True if last elt copied was '..' */
+
+ dest = src = a->name;
+ if (*src == '\0') {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Invalid empty pathname");
+ return (ARCHIVE_WARN);
+ }
+
+ /* Skip leading '/'. */
+ if (*src == '/')
+ separator = *src++;
+
+ /* Scan the pathname one element at a time. */
+ for (;;) {
+ /* src points to first char after '/' */
+ if (src[0] == '\0') {
+ break;
+ } else if (src[0] == '/') {
+ /* Found '//', ignore second one. */
+ src++;
+ continue;
+ } else if (src[0] == '.') {
+ if (src[1] == '\0') {
+ /* Ignore trailing '.' */
+ break;
+ } else if (src[1] == '/') {
+ /* Skip './'. */
+ src += 2;
+ continue;
+ } else if (src[1] == '.') {
+ if (src[2] == '/' || src[2] == '\0') {
+ /* Conditionally warn about '..' */
+ if (a->flags & ARCHIVE_EXTRACT_SECURE_NODOTDOT) {
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Path contains '..'");
+ return (ARCHIVE_WARN);
+ }
+ lastdotdot = 1;
+ } else
+ lastdotdot = 0;
+ /*
+ * Note: Under no circumstances do we
+ * remove '..' elements. In
+ * particular, restoring
+ * '/foo/../bar/' should create the
+ * 'foo' dir as a side-effect.
+ */
+ } else
+ lastdotdot = 0;
+ } else
+ lastdotdot = 0;
+
+ /* Copy current element, including leading '/'. */
+ if (separator)
+ *dest++ = '/';
+ while (*src != '\0' && *src != '/') {
+ *dest++ = *src++;
+ }
+
+ if (*src == '\0')
+ break;
+
+ /* Skip '/' separator. */
+ separator = *src++;
+ }
+ /*
+ * We've just copied zero or more path elements, not including the
+ * final '/'.
+ */
+ if (lastdotdot) {
+ /* Trailing '..' is always wrong. */
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_MISC,
+ "Path contains trailing '..'");
+ return (ARCHIVE_WARN);
+ }
+ if (dest == a->name) {
+ /*
+ * Nothing got copied. The path must have been something
+ * like '.' or '/' or './' or '/././././/./'.
+ */
+ if (separator)
+ *dest++ = '/';
+ else
+ *dest++ = '.';
+ }
+ /* Terminate the result. */
+ *dest = '\0';
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Create the parent directory of the specified path, assuming path
+ * is already in mutable storage.
+ */
+static int
+create_parent_dir(struct archive_write_disk *a, char *path)
+{
+ char *slash;
+ int r;
+
+ /* Remove tail element to obtain parent name. */
+ slash = strrchr(path, '/');
+ if (slash == NULL)
+ return (ARCHIVE_OK);
+ *slash = '\0';
+ r = create_dir(a, path);
+ *slash = '/';
+ return (r);
+}
+
+/*
+ * Create the specified dir, recursing to create parents as necessary.
+ *
+ * Returns ARCHIVE_OK if the path exists when we're done here.
+ * Otherwise, returns ARCHIVE_WARN.
+ * Assumes path is in mutable storage; path is unchanged on exit.
+ */
+static int
+create_dir(struct archive_write_disk *a, char *path)
+{
+ struct stat st;
+ struct fixup_entry *le;
+ char *slash, *base;
+ mode_t mode_final, mode;
+ int r;
+
+ r = ARCHIVE_OK;
+
+ /* Check for special names and just skip them. */
+ slash = strrchr(path, '/');
+ base = strrchr(path, '/');
+ if (slash == NULL)
+ base = path;
+ else
+ base = slash + 1;
+
+ if (base[0] == '\0' ||
+ (base[0] == '.' && base[1] == '\0') ||
+ (base[0] == '.' && base[1] == '.' && base[2] == '\0')) {
+ /* Don't bother trying to create null path, '.', or '..'. */
+ if (slash != NULL) {
+ *slash = '\0';
+ r = create_dir(a, path);
+ *slash = '/';
+ return (r);
+ }
+ return (ARCHIVE_OK);
+ }
+
+ /*
+ * Yes, this should be stat() and not lstat(). Using lstat()
+ * here loses the ability to extract through symlinks. Also note
+ * that this should not use the a->st cache.
+ */
+ if (stat(path, &st) == 0) {
+ if (S_ISDIR(st.st_mode))
+ return (ARCHIVE_OK);
+ if ((a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) {
+ archive_set_error(&a->archive, EEXIST,
+ "Can't create directory '%s'", path);
+ return (ARCHIVE_WARN);
+ }
+ if (unlink(path) != 0) {
+ archive_set_error(&a->archive, errno,
+ "Can't create directory '%s': "
+ "Conflicting file cannot be removed");
+ return (ARCHIVE_WARN);
+ }
+ } else if (errno != ENOENT && errno != ENOTDIR) {
+ /* Stat failed? */
+ archive_set_error(&a->archive, errno, "Can't test directory '%s'", path);
+ return (ARCHIVE_WARN);
+ } else if (slash != NULL) {
+ *slash = '\0';
+ r = create_dir(a, path);
+ *slash = '/';
+ if (r != ARCHIVE_OK)
+ return (r);
+ }
+
+ /*
+ * Mode we want for the final restored directory. Per POSIX,
+ * implicitly-created dirs must be created obeying the umask.
+ * There's no mention whether this is different for privileged
+ * restores (which the rest of this code handles by pretending
+ * umask=0). I've chosen here to always obey the user's umask for
+ * implicit dirs, even if _EXTRACT_PERM was specified.
+ */
+ mode_final = DEFAULT_DIR_MODE & ~a->user_umask;
+ /* Mode we want on disk during the restore process. */
+ mode = mode_final;
+ mode |= MINIMUM_DIR_MODE;
+ mode &= MAXIMUM_DIR_MODE;
+ if (mkdir(path, mode) == 0) {
+ if (mode != mode_final) {
+ le = new_fixup(a, path);
+ le->fixup |=TODO_MODE_BASE;
+ le->mode = mode_final;
+ }
+ return (ARCHIVE_OK);
+ }
+
+ /*
+ * Without the following check, a/b/../b/c/d fails at the
+ * second visit to 'b', so 'd' can't be created. Note that we
+ * don't add it to the fixup list here, as it's already been
+ * added.
+ */
+ if (stat(path, &st) == 0 && S_ISDIR(st.st_mode))
+ return (ARCHIVE_OK);
+
+ archive_set_error(&a->archive, errno, "Failed to create dir '%s'", path);
+ return (ARCHIVE_WARN);
+}
+
+/*
+ * Note: Although we can skip setting the user id if the desired user
+ * id matches the current user, we cannot skip setting the group, as
+ * many systems set the gid bit based on the containing directory. So
+ * we have to perform a chown syscall if we want to restore the SGID
+ * bit. (The alternative is to stat() and then possibly chown(); it's
+ * more efficient to skip the stat() and just always chown().) Note
+ * that a successful chown() here clears the TODO_SGID_CHECK bit, which
+ * allows set_mode to skip the stat() check for the GID.
+ */
+static int
+set_ownership(struct archive_write_disk *a)
+{
+ /* If we know we can't change it, don't bother trying. */
+ if (a->user_uid != 0 && a->user_uid != a->uid) {
+ archive_set_error(&a->archive, errno,
+ "Can't set UID=%d", a->uid);
+ return (ARCHIVE_WARN);
+ }
+
+#ifdef HAVE_FCHOWN
+ if (a->fd >= 0 && fchown(a->fd, a->uid, a->gid) == 0)
+ goto success;
+#endif
+
+#ifdef HAVE_LCHOWN
+ if (lchown(a->name, a->uid, a->gid) == 0)
+ goto success;
+#else
+ if (!S_ISLNK(a->mode) && chown(a->name, a->uid, a->gid) == 0)
+ goto success;
+#endif
+
+ archive_set_error(&a->archive, errno,
+ "Can't set user=%d/group=%d for %s", a->uid, a->gid,
+ a->name);
+ return (ARCHIVE_WARN);
+success:
+ a->todo &= ~TODO_OWNER;
+ /* We know the user/group are correct now. */
+ a->todo &= ~TODO_SGID_CHECK;
+ a->todo &= ~TODO_SUID_CHECK;
+ return (ARCHIVE_OK);
+}
+
+static int
+set_time(struct archive_write_disk *a)
+{
+ const struct stat *st;
+ struct timeval times[2];
+
+ st = archive_entry_stat(a->entry);
+
+ times[1].tv_sec = st->st_mtime;
+ times[1].tv_usec = ARCHIVE_STAT_MTIME_NANOS(st) / 1000;
+
+ times[0].tv_sec = st->st_atime;
+ times[0].tv_usec = ARCHIVE_STAT_ATIME_NANOS(st) / 1000;
+
+#ifdef HAVE_FUTIMES
+ if (a->fd >= 0 && futimes(a->fd, times) == 0) {
+ return (ARCHIVE_OK);
+ }
+#endif
+
+#ifdef HAVE_LUTIMES
+ if (lutimes(a->name, times) != 0)
+#else
+ if (!S_ISLNK(a->mode) && utimes(a->name, times) != 0)
+#endif
+ {
+ archive_set_error(&a->archive, errno, "Can't update time for %s",
+ a->name);
+ return (ARCHIVE_WARN);
+ }
+
+ /*
+ * Note: POSIX does not provide a portable way to restore ctime.
+ * (Apart from resetting the system clock, which is distasteful.)
+ * So, any restoration of ctime will necessarily be OS-specific.
+ */
+
+ /* XXX TODO: Can FreeBSD restore ctime? XXX */
+ return (ARCHIVE_OK);
+}
+
+static int
+set_mode(struct archive_write_disk *a, int mode)
+{
+ int r = ARCHIVE_OK;
+
+ if (a->todo & TODO_SGID_CHECK) {
+ /*
+ * If we don't know the GID is right, we must stat()
+ * to verify it. We can't just check the GID of this
+ * process, since systems sometimes set GID from
+ * the enclosing dir or based on ACLs.
+ */
+ if (a->pst != NULL) {
+ /* Already have stat() data available. */
+#ifdef HAVE_FSTAT
+ } else if (fd >= 0 && fstat(fd, &a->st) == 0) {
+ a->pst = &a->st;
+#endif
+ } else if (stat(a->name, &a->st) == 0) {
+ a->pst = &a->st;
+ } else {
+ archive_set_error(&a->archive, errno,
+ "Couldn't stat file");
+ return (ARCHIVE_WARN);
+ }
+ if (a->pst->st_gid != a->gid) {
+ mode &= ~ S_ISGID;
+ archive_set_error(&a->archive, -1, "Can't restore SGID bit");
+ r = ARCHIVE_WARN;
+ }
+ /* While we're here, double-check the UID. */
+ if (a->pst->st_uid != a->uid
+ && (a->todo & TODO_SUID)) {
+ mode &= ~ S_ISUID;
+ archive_set_error(&a->archive, -1, "Can't restore SUID bit");
+ r = ARCHIVE_WARN;
+ }
+ a->todo &= ~TODO_SGID_CHECK;
+ a->todo &= ~TODO_SUID_CHECK;
+ } else if (a->todo & TODO_SUID_CHECK) {
+ /*
+ * If we don't know the UID is right, we can just check
+ * the user, since all systems set the file UID from
+ * the process UID.
+ */
+ if (a->user_uid != a->uid) {
+ mode &= ~ S_ISUID;
+ archive_set_error(&a->archive, -1, "Can't make file SUID");
+ r = ARCHIVE_WARN;
+ }
+ a->todo &= ~TODO_SUID_CHECK;
+ }
+
+ if (S_ISLNK(a->mode)) {
+#ifdef HAVE_LCHMOD
+ /*
+ * If this is a symlink, use lchmod(). If the
+ * platform doesn't support lchmod(), just skip it. A
+ * platform that doesn't provide a way to set
+ * permissions on symlinks probably ignores
+ * permissions on symlinks, so a failure here has no
+ * impact.
+ */
+ if (lchmod(a->name, mode) != 0) {
+ archive_set_error(&a->archive, errno, "Can't set permissions");
+ r = ARCHIVE_WARN;
+ }
+#endif
+ } else if (!S_ISDIR(a->mode)) {
+ /*
+ * If it's not a symlink and not a dir, then use
+ * fchmod() or chmod(), depending on whether we have
+ * an fd. Dirs get their perms set during the
+ * post-extract fixup, which is handled elsewhere.
+ */
+#ifdef HAVE_FCHMOD
+ if (a->fd >= 0) {
+ if (fchmod(a->fd, mode) != 0) {
+ archive_set_error(&a->archive, errno,
+ "Can't set permissions");
+ r = ARCHIVE_WARN;
+ }
+ } else
+#endif
+ /* If this platform lacks fchmod(), then
+ * we'll just use chmod(). */
+ if (chmod(a->name, mode) != 0) {
+ archive_set_error(&a->archive, errno,
+ "Can't set permissions");
+ r = ARCHIVE_WARN;
+ }
+ }
+ return (r);
+}
+
+static int
+set_fflags(struct archive_write_disk *a)
+{
+ struct fixup_entry *le;
+ long set, clear;
+ int r;
+ int critical_flags;
+ mode_t mode = archive_entry_mode(a->entry);
+
+ /*
+ * Make 'critical_flags' hold all file flags that can't be
+ * immediately restored. For example, on BSD systems,
+ * SF_IMMUTABLE prevents hardlinks from being created, so
+ * should not be set until after any hardlinks are created. To
+ * preserve some semblance of portability, this uses #ifdef
+ * extensively. Ugly, but it works.
+ *
+ * Yes, Virginia, this does create a security race. It's mitigated
+ * somewhat by the practice of creating dirs 0700 until the extract
+ * is done, but it would be nice if we could do more than that.
+ * People restoring critical file systems should be wary of
+ * other programs that might try to muck with files as they're
+ * being restored.
+ */
+ /* Hopefully, the compiler will optimize this mess into a constant. */
+ critical_flags = 0;
+#ifdef SF_IMMUTABLE
+ critical_flags |= SF_IMMUTABLE;
+#endif
+#ifdef UF_IMMUTABLE
+ critical_flags |= UF_IMMUTABLE;
+#endif
+#ifdef SF_APPEND
+ critical_flags |= SF_APPEND;
+#endif
+#ifdef UF_APPEND
+ critical_flags |= UF_APPEND;
+#endif
+#ifdef EXT2_APPEND_FL
+ critical_flags |= EXT2_APPEND_FL;
+#endif
+#ifdef EXT2_IMMUTABLE_FL
+ critical_flags |= EXT2_IMMUTABLE_FL;
+#endif
+
+ if (a->todo & TODO_FFLAGS) {
+ archive_entry_fflags(a->entry, &set, &clear);
+
+ /*
+ * The first test encourages the compiler to eliminate
+ * all of this if it's not necessary.
+ */
+ if ((critical_flags != 0) && (set & critical_flags)) {
+ le = current_fixup(a, a->name);
+ le->fixup |= TODO_FFLAGS;
+ le->fflags_set = set;
+ /* Store the mode if it's not already there. */
+ if ((le->fixup & TODO_MODE) == 0)
+ le->mode = mode;
+ } else {
+ r = set_fflags_platform(a, a->fd,
+ a->name, mode, set, clear);
+ if (r != ARCHIVE_OK)
+ return (r);
+ }
+ }
+ return (ARCHIVE_OK);
+}
+
+
+#if ( defined(HAVE_LCHFLAGS) || defined(HAVE_CHFLAGS) || defined(HAVE_FCHFLAGS) ) && !defined(__linux)
+static int
+set_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
+ mode_t mode, unsigned long set, unsigned long clear)
+{
+ (void)mode; /* UNUSED */
+ if (set == 0 && clear == 0)
+ return (ARCHIVE_OK);
+
+ /*
+ * XXX Is the stat here really necessary? Or can I just use
+ * the 'set' flags directly? In particular, I'm not sure
+ * about the correct approach if we're overwriting an existing
+ * file that already has flags on it. XXX
+ */
+ if (fd >= 0 && fstat(fd, &a->st) == 0)
+ a->pst = &a->st;
+ else if (lstat(name, &a->st) == 0)
+ a->pst = &a->st;
+ else {
+ archive_set_error(&a->archive, errno,
+ "Couldn't stat file");
+ return (ARCHIVE_WARN);
+ }
+
+ a->st.st_flags &= ~clear;
+ a->st.st_flags |= set;
+#ifdef HAVE_FCHFLAGS
+ /* If platform has fchflags() and we were given an fd, use it. */
+ if (fd >= 0 && fchflags(fd, a->st.st_flags) == 0)
+ return (ARCHIVE_OK);
+#endif
+ /*
+ * If we can't use the fd to set the flags, we'll use the
+ * pathname to set flags. We prefer lchflags() but will use
+ * chflags() if we must.
+ */
+#ifdef HAVE_LCHFLAGS
+ if (lchflags(name, a->st.st_flags) == 0)
+ return (ARCHIVE_OK);
+#elif defined(HAVE_CHFLAGS)
+ if (S_ISLNK(a->st.st_mode)) {
+ archive_set_error(&a->archive, errno,
+ "Can't set file flags on symlink.");
+ return (ARCHIVE_WARN);
+ }
+ if (chflags(name, a->st.st_flags) == 0)
+ return (ARCHIVE_OK);
+#endif
+ archive_set_error(&a->archive, errno,
+ "Failed to set file flags");
+ return (ARCHIVE_WARN);
+}
+
+#elif defined(__linux) && defined(EXT2_IOC_GETFLAGS) && defined(EXT2_IOC_SETFLAGS)
+
+/*
+ * Linux has flags too, but uses ioctl() to access them instead of
+ * having a separate chflags() system call.
+ */
+static int
+set_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
+ mode_t mode, unsigned long set, unsigned long clear)
+{
+ int ret;
+ int myfd = fd;
+ unsigned long newflags, oldflags;
+ unsigned long sf_mask = 0;
+
+ if (set == 0 && clear == 0)
+ return (ARCHIVE_OK);
+ /* Only regular files and dirs can have flags. */
+ if (!S_ISREG(mode) && !S_ISDIR(mode))
+ return (ARCHIVE_OK);
+
+ /* If we weren't given an fd, open it ourselves. */
+ if (myfd < 0)
+ myfd = open(name, O_RDONLY|O_NONBLOCK);
+ if (myfd < 0)
+ return (ARCHIVE_OK);
+
+ /*
+ * Linux has no define for the flags that are only settable by
+ * the root user. This code may seem a little complex, but
+ * there seem to be some Linux systems that lack these
+ * defines. (?) The code below degrades reasonably gracefully
+ * if sf_mask is incomplete.
+ */
+#ifdef EXT2_IMMUTABLE_FL
+ sf_mask |= EXT2_IMMUTABLE_FL;
+#endif
+#ifdef EXT2_APPEND_FL
+ sf_mask |= EXT2_APPEND_FL;
+#endif
+ /*
+ * XXX As above, this would be way simpler if we didn't have
+ * to read the current flags from disk. XXX
+ */
+ ret = ARCHIVE_OK;
+ /* Try setting the flags as given. */
+ if (ioctl(myfd, EXT2_IOC_GETFLAGS, &oldflags) >= 0) {
+ newflags = (oldflags & ~clear) | set;
+ if (ioctl(myfd, EXT2_IOC_SETFLAGS, &newflags) >= 0)
+ goto cleanup;
+ if (errno != EPERM)
+ goto fail;
+ }
+ /* If we couldn't set all the flags, try again with a subset. */
+ if (ioctl(myfd, EXT2_IOC_GETFLAGS, &oldflags) >= 0) {
+ newflags &= ~sf_mask;
+ oldflags &= sf_mask;
+ newflags |= oldflags;
+ if (ioctl(myfd, EXT2_IOC_SETFLAGS, &newflags) >= 0)
+ goto cleanup;
+ }
+ /* We couldn't set the flags, so report the failure. */
+fail:
+ archive_set_error(&a->archive, errno,
+ "Failed to set file flags");
+ ret = ARCHIVE_WARN;
+cleanup:
+ if (fd < 0)
+ close(myfd);
+ return (ret);
+}
+
+#else /* Not HAVE_CHFLAGS && Not __linux */
+
+/*
+ * Of course, some systems have neither BSD chflags() nor Linux' flags
+ * support through ioctl().
+ */
+static int
+set_fflags_platform(struct archive_write_disk *a, int fd, const char *name,
+ mode_t mode, unsigned long set, unsigned long clear)
+{
+ (void)ad; /* UNUSED */
+ (void)fd; /* UNUSED */
+ (void)name; /* UNUSED */
+ (void)mode; /* UNUSED */
+ (void)set; /* UNUSED */
+ (void)clear; /* UNUSED */
+ return (ARCHIVE_OK);
+}
+
+#endif /* __linux */
+
+#ifndef HAVE_POSIX_ACL
+/* Default empty function body to satisfy mainline code. */
+static int
+set_acls(struct archive_write_disk *a)
+{
+ (void)a; /* UNUSED */
+ return (ARCHIVE_OK);
+}
+
+#else
+
+/*
+ * XXX TODO: What about ACL types other than ACCESS and DEFAULT?
+ */
+static int
+set_acls(struct archive_write_disk *a)
+{
+ int ret;
+
+ ret = set_acl(a, a->fd, a->entry, ACL_TYPE_ACCESS,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS, "access");
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ ret = set_acl(a, a->fd, a->entry, ACL_TYPE_DEFAULT,
+ ARCHIVE_ENTRY_ACL_TYPE_DEFAULT, "default");
+ return (ret);
+}
+
+
+static int
+set_acl(struct archive_write_disk *a, int fd, struct archive_entry *entry,
+ acl_type_t acl_type, int ae_requested_type, const char *tname)
+{
+ acl_t acl;
+ acl_entry_t acl_entry;
+ acl_permset_t acl_permset;
+ int ret;
+ int ae_type, ae_permset, ae_tag, ae_id;
+ uid_t ae_uid;
+ gid_t ae_gid;
+ const char *ae_name;
+ int entries;
+ const char *name;
+
+ ret = ARCHIVE_OK;
+ entries = archive_entry_acl_reset(entry, ae_requested_type);
+ if (entries == 0)
+ return (ARCHIVE_OK);
+ acl = acl_init(entries);
+ while (archive_entry_acl_next(entry, ae_requested_type, &ae_type,
+ &ae_permset, &ae_tag, &ae_id, &ae_name) == ARCHIVE_OK) {
+ acl_create_entry(&acl, &acl_entry);
+
+ switch (ae_tag) {
+ case ARCHIVE_ENTRY_ACL_USER:
+ acl_set_tag_type(acl_entry, ACL_USER);
+ ae_uid = a->lookup_uid(a->lookup_uid_data,
+ ae_name, ae_id);
+ acl_set_qualifier(acl_entry, &ae_uid);
+ break;
+ case ARCHIVE_ENTRY_ACL_GROUP:
+ acl_set_tag_type(acl_entry, ACL_GROUP);
+ ae_gid = a->lookup_gid(a->lookup_gid_data,
+ ae_name, ae_id);
+ acl_set_qualifier(acl_entry, &ae_gid);
+ break;
+ case ARCHIVE_ENTRY_ACL_USER_OBJ:
+ acl_set_tag_type(acl_entry, ACL_USER_OBJ);
+ break;
+ case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
+ acl_set_tag_type(acl_entry, ACL_GROUP_OBJ);
+ break;
+ case ARCHIVE_ENTRY_ACL_MASK:
+ acl_set_tag_type(acl_entry, ACL_MASK);
+ break;
+ case ARCHIVE_ENTRY_ACL_OTHER:
+ acl_set_tag_type(acl_entry, ACL_OTHER);
+ break;
+ default:
+ /* XXX */
+ break;
+ }
+
+ acl_get_permset(acl_entry, &acl_permset);
+ acl_clear_perms(acl_permset);
+ if (ae_permset & ARCHIVE_ENTRY_ACL_EXECUTE)
+ acl_add_perm(acl_permset, ACL_EXECUTE);
+ if (ae_permset & ARCHIVE_ENTRY_ACL_WRITE)
+ acl_add_perm(acl_permset, ACL_WRITE);
+ if (ae_permset & ARCHIVE_ENTRY_ACL_READ)
+ acl_add_perm(acl_permset, ACL_READ);
+ }
+
+ name = archive_entry_pathname(entry);
+
+ /* Try restoring the ACL through 'fd' if we can. */
+#if HAVE_ACL_SET_FD
+ if (fd >= 0 && acl_type == ACL_TYPE_ACCESS && acl_set_fd(fd, acl) == 0)
+ ret = ARCHIVE_OK;
+ else
+#else
+#if HAVE_ACL_SET_FD_NP
+ if (fd >= 0 && acl_set_fd_np(fd, acl, acl_type) == 0)
+ ret = ARCHIVE_OK;
+ else
+#endif
+#endif
+ if (acl_set_file(name, acl_type, acl) != 0) {
+ archive_set_error(&a->archive, errno, "Failed to set %s acl", tname);
+ ret = ARCHIVE_WARN;
+ }
+ acl_free(acl);
+ return (ret);
+}
+#endif
+
+#if HAVE_LSETXATTR
+/*
+ * Restore extended attributes - Linux implementation
+ */
+static int
+set_xattrs(struct archive_write_disk *a)
+{
+ struct archive_entry *entry = a->entry;
+ static int warning_done = 0;
+ int ret = ARCHIVE_OK;
+ int i = archive_entry_xattr_reset(entry);
+
+ while (i--) {
+ const char *name;
+ const void *value;
+ size_t size;
+ archive_entry_xattr_next(entry, &name, &value, &size);
+ if (name != NULL &&
+ strncmp(name, "xfsroot.", 8) != 0 &&
+ strncmp(name, "system.", 7) != 0) {
+ int e;
+#if HAVE_FSETXATTR
+ if (a->fd >= 0)
+ e = fsetxattr(a->fd, name, value, size, 0);
+ else
+#endif
+ {
+ e = lsetxattr(archive_entry_pathname(entry),
+ name, value, size, 0);
+ }
+ if (e == -1) {
+ if (errno == ENOTSUP) {
+ if (!warning_done) {
+ warning_done = 1;
+ archive_set_error(&a->archive, errno,
+ "Cannot restore extended "
+ "attributes on this file "
+ "system");
+ }
+ } else
+ archive_set_error(&a->archive, errno,
+ "Failed to set extended attribute");
+ ret = ARCHIVE_WARN;
+ }
+ } else {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Invalid extended attribute encountered");
+ ret = ARCHIVE_WARN;
+ }
+ }
+ return (ret);
+}
+#else
+/*
+ * Restore extended attributes - stub implementation for unsupported systems
+ */
+static int
+set_xattrs(struct archive_write_disk *a)
+{
+ static int warning_done = 0;
+
+ /* If there aren't any extended attributes, then it's okay not
+ * to extract them, otherwise, issue a single warning. */
+ if (archive_entry_xattr_count(a->entry) != 0 && !warning_done) {
+ warning_done = 1;
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
+ "Cannot restore extended attributes on this system");
+ return (ARCHIVE_WARN);
+ }
+ /* Warning was already emitted; suppress further warnings. */
+ return (ARCHIVE_OK);
+}
+#endif
+
+
+/*
+ * Trivial implementations of gid/uid lookup functions.
+ * These are normally overridden by the client, but these stub
+ * versions ensure that we always have something that works.
+ */
+static gid_t
+trivial_lookup_gid(void *private_data, const char *gname, gid_t gid)
+{
+ (void)private_data; /* UNUSED */
+ (void)gname; /* UNUSED */
+ return (gid);
+}
+
+static uid_t
+trivial_lookup_uid(void *private_data, const char *uname, uid_t uid)
+{
+ (void)private_data; /* UNUSED */
+ (void)uname; /* UNUSED */
+ return (uid);
+}
diff --git a/lib/libarchive/archive_write_disk_private.h b/lib/libarchive/archive_write_disk_private.h
new file mode 100644
index 0000000..562229b
--- /dev/null
+++ b/lib/libarchive/archive_write_disk_private.h
@@ -0,0 +1,34 @@
+/*-
+ * 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
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef ARCHIVE_WRITE_DISK_PRIVATE_H_INCLUDED
+#define ARCHIVE_WRITE_DISK_PRIVATE_H_INCLUDED
+
+struct archive_write_disk;
+
+#endif
diff --git a/lib/libarchive/archive_write_disk_set_standard_lookup.c b/lib/libarchive/archive_write_disk_set_standard_lookup.c
new file mode 100644
index 0000000..273b9af
--- /dev/null
+++ b/lib/libarchive/archive_write_disk_set_standard_lookup.c
@@ -0,0 +1,212 @@
+/*-
+ * 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 <sys/types.h>
+#endif
+#ifdef HAVE_SYS_ACL_H
+#include <sys/acl.h>
+#endif
+#ifdef HAVE_ATTR_XATTR_H
+#include <attr/xattr.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+#ifdef HAVE_GRP_H
+#include <grp.h>
+#endif
+#ifdef HAVE_PWD_H
+#include <pwd.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include "archive.h"
+#include "archive_private.h"
+#include "archive_read_private.h"
+#include "archive_write_disk_private.h"
+
+struct bucket {
+ char *name;
+ int hash;
+ id_t id;
+};
+
+static unsigned int hash(const char *);
+static gid_t lookup_gid(void *, const char *uname, gid_t);
+static uid_t lookup_uid(void *, const char *uname, uid_t);
+static void cleanup(void *);
+
+/*
+ * Installs functions that use getpwnam()/getgrnam()---along with
+ * a simple cache to accelerate such lookups---into the archive_write_disk
+ * object. This is in a separate file because getpwnam()/getgrnam()
+ * can pull in a LOT of library code (including NIS/LDAP functions, which
+ * pull in DNS resolveers, etc). This can easily top 500kB, which makes
+ * it inappropriate for some space-constrained applications.
+ *
+ * Applications that are size-sensitive may want to just use the
+ * real default functions (defined in archive_write_disk.c) that just
+ * use the uid/gid without the lookup. Or define your own custom functions
+ * if you prefer.
+ *
+ * TODO: Replace these hash tables with simpler move-to-front LRU
+ * lists with a bounded size (128 items?). The hash is a bit faster,
+ * but has a bad pathology in which it thrashes a single bucket. Even
+ * walking a list of 128 items is a lot faster than calling
+ * getpwnam()!
+ */
+int
+archive_write_disk_set_standard_lookup(struct archive *a)
+{
+ struct bucket *ucache = malloc(sizeof(struct bucket[127]));
+ struct bucket *gcache = malloc(sizeof(struct bucket[127]));
+ memset(ucache, 0, sizeof(struct bucket[127]));
+ memset(gcache, 0, sizeof(struct bucket[127]));
+ archive_write_disk_set_group_lookup(a, gcache, lookup_gid, cleanup);
+ archive_write_disk_set_user_lookup(a, ucache, lookup_uid, cleanup);
+ return (ARCHIVE_OK);
+}
+
+static gid_t
+lookup_gid(void *private_data, const char *gname, gid_t gid)
+{
+ int h;
+ struct bucket *b;
+ int cache_size;
+ struct bucket *gcache = (struct bucket *)private_data;
+
+ cache_size = 127;
+
+ /* If no gname, just use the gid provided. */
+ if (gname == NULL || *gname == '\0')
+ return (gid);
+
+ /* Try to find gname in the cache. */
+ h = hash(gname);
+ b = &gcache[h % cache_size ];
+ if (b->name != NULL && b->hash == h && strcmp(gname, b->name) == 0)
+ return ((gid_t)b->id);
+
+ /* Free the cache slot for a new entry. */
+ if (b->name != NULL)
+ free(b->name);
+ b->name = strdup(gname);
+ /* Note: If strdup fails, that's okay; we just won't cache. */
+ b->hash = h;
+#if HAVE_GRP_H
+ {
+ struct group *grent = getgrnam(gname);
+ if (grent != NULL)
+ gid = grent->gr_gid;
+ }
+#elif _WIN32
+ /* TODO: do a gname->gid lookup for Windows. */
+#endif
+ b->id = gid;
+
+ return (gid);
+}
+
+static uid_t
+lookup_uid(void *private_data, const char *uname, uid_t uid)
+{
+ int h;
+ struct bucket *b;
+ int cache_size;
+ struct bucket *ucache = (struct bucket *)private_data;
+
+ cache_size = 127;
+
+ /* If no uname, just use the uid provided. */
+ if (uname == NULL || *uname == '\0')
+ return (uid);
+
+ /* Try to find uname in the cache. */
+ h = hash(uname);
+ b = &ucache[h % cache_size ];
+ if (b->name != NULL && b->hash == h && strcmp(uname, b->name) == 0)
+ return ((uid_t)b->id);
+
+ /* Free the cache slot for a new entry. */
+ if (b->name != NULL)
+ free(b->name);
+ b->name = strdup(uname);
+ /* Note: If strdup fails, that's okay; we just won't cache. */
+ b->hash = h;
+#if HAVE_PWD_H
+ {
+ struct passwd *pwent = getpwnam(uname);
+ if (pwent != NULL)
+ uid = pwent->pw_uid;
+ }
+#elif _WIN32
+ /* TODO: do a uname->uid lookup for Windows. */
+#endif
+ b->id = uid;
+
+ return (uid);
+}
+
+static void
+cleanup(void *private)
+{
+ free(private);
+}
+
+
+static unsigned int
+hash(const char *p)
+{
+ /* A 32-bit version of Peter Weinberger's (PJW) hash algorithm,
+ as used by ELF for hashing function names. */
+ unsigned g, h = 0;
+ while (*p != '\0') {
+ h = ( h << 4 ) + *p++;
+ if (( g = h & 0xF0000000 )) {
+ h ^= g >> 24;
+ h &= 0x0FFFFFFF;
+ }
+ }
+ return h;
+}
diff --git a/lib/libarchive/archive_write_private.h b/lib/libarchive/archive_write_private.h
new file mode 100644
index 0000000..c551b46
--- /dev/null
+++ b/lib/libarchive/archive_write_private.h
@@ -0,0 +1,177 @@
+/*-
+ * 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_WRITE_PRIVATE_H_INCLUDED
+#define ARCHIVE_WRITE_PRIVATE_H_INCLUDED
+
+#include "archive.h"
+#include "archive_string.h"
+#include "archive_private.h"
+
+struct archive_write {
+ struct archive archive;
+
+ struct archive_entry *entry;
+
+ /* Dev/ino of the archive being read/written. */
+ dev_t skip_file_dev;
+ ino_t skip_file_ino;
+
+ /* Utility: Pointer to a block of nulls. */
+ const unsigned char *nulls;
+ size_t null_length;
+
+ /*
+ * Used by archive_read_data() to track blocks and copy
+ * data to client buffers, filling gaps with zero bytes.
+ */
+ const char *read_data_block;
+ off_t read_data_offset;
+ off_t read_data_output_offset;
+ size_t read_data_remaining;
+
+ /* Callbacks to open/read/write/close archive stream. */
+ archive_open_callback *client_opener;
+ archive_read_callback *client_reader;
+ archive_skip_callback *client_skipper;
+ archive_write_callback *client_writer;
+ archive_close_callback *client_closer;
+ void *client_data;
+
+ /*
+ * Blocking information. Note that bytes_in_last_block is
+ * misleadingly named; I should find a better name. These
+ * control the final output from all compressors, including
+ * compression_none.
+ */
+ int bytes_per_block;
+ int bytes_in_last_block;
+
+ /*
+ * These control whether data within a gzip/bzip2 compressed
+ * stream gets padded or not. If pad_uncompressed is set,
+ * the data will be padded to a full block before being
+ * compressed. The pad_uncompressed_byte determines the value
+ * that will be used for padding. Note that these have no
+ * effect on compression "none."
+ */
+ int pad_uncompressed;
+ int pad_uncompressed_byte; /* TODO: Support this. */
+
+ /*
+ * On write, the client just invokes an archive_write_set function
+ * which sets up the data here directly.
+ */
+ void *compression_data; /* Data for (de)compressor. */
+ int (*compression_init)(struct archive_write *); /* Initialize. */
+ int (*compression_finish)(struct archive_write *);
+ int (*compression_write)(struct archive_write *, const void *, size_t);
+ /*
+ * Read uses a peek/consume I/O model: the decompression code
+ * returns a pointer to the requested block and advances the
+ * file position only when requested by a consume call. This
+ * reduces copying and also simplifies look-ahead for format
+ * detection.
+ */
+ ssize_t (*compression_read_ahead)(struct archive *,
+ const void **, size_t request);
+ ssize_t (*compression_read_consume)(struct archive *, size_t);
+ off_t (*compression_skip)(struct archive *, off_t);
+
+ /*
+ * Format detection is mostly the same as compression
+ * detection, with two significant differences: The bidders
+ * use the read_ahead calls above to examine the stream rather
+ * than having the supervisor hand them a block of data to
+ * examine, and the auction is repeated for every header.
+ * Winning bidders should set the archive_format and
+ * archive_format_name appropriately. Bid routines should
+ * check archive_format and decline to bid if the format of
+ * the last header was incompatible.
+ *
+ * Again, write support is considerably simpler because there's
+ * no need for an auction.
+ */
+ int archive_format;
+ const char *archive_format_name;
+
+ struct archive_format_descriptor {
+ 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 *);
+ void *format_data; /* Format-specific data for readers. */
+ } formats[8];
+ struct archive_format_descriptor *format; /* Active format. */
+
+ /*
+ * Storage for format-specific data. Note that there can be
+ * multiple format readers active at one time, so we need to
+ * allow for multiple format readers to have their data
+ * available. The pformat_data slot here is the solution: on
+ * read, it is guaranteed to always point to a void* variable
+ * that the format can use.
+ */
+ void **pformat_data; /* Pointer to current format_data. */
+ void *format_data; /* Used by writers. */
+
+ /*
+ * Pointers to format-specific functions for writing. They're
+ * initialized by archive_write_set_format_XXX() calls.
+ */
+ int (*format_init)(struct archive_write *);
+ int (*format_finish)(struct archive_write *);
+ int (*format_destroy)(struct archive_write *);
+ int (*format_finish_entry)(struct archive_write *);
+ int (*format_write_header)(struct archive_write *,
+ struct archive_entry *);
+ ssize_t (*format_write_data)(struct archive_write *,
+ const void *buff, size_t);
+
+ /*
+ * Various information needed by archive_extract.
+ */
+ struct extract *extract;
+ int (*cleanup_archive_extract)(struct archive *);
+};
+
+/*
+ * Utility function to format a USTAR header into a buffer. If
+ * "strict" is set, this tries to create the absolutely most portable
+ * version of a ustar header. If "strict" is set to 0, then it will
+ * relax certain requirements.
+ *
+ * Generally, format-specific declarations don't belong in this
+ * header; this is a rare example of a function that is shared by
+ * two very similar formats (ustar and pax).
+ */
+int
+__archive_write_format_header_ustar(struct archive_write *, char buff[512],
+ struct archive_entry *, int tartype, int strict);
+
+#endif
diff --git a/lib/libarchive/archive_write_set_compression_bzip2.c b/lib/libarchive/archive_write_set_compression_bzip2.c
index 85974f8..eab8c70 100644
--- a/lib/libarchive/archive_write_set_compression_bzip2.c
+++ b/lib/libarchive/archive_write_set_compression_bzip2.c
@@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_private.h"
+#include "archive_write_private.h"
struct private_data {
bz_stream stream;
@@ -62,23 +63,23 @@ struct private_data {
#define SET_NEXT_IN(st,src) \
(st)->stream.next_in = (char *)(uintptr_t)(const void *)(src)
-static int archive_compressor_bzip2_finish(struct archive *);
-static int archive_compressor_bzip2_init(struct archive *);
-static int archive_compressor_bzip2_write(struct archive *, const void *,
- size_t);
-static int drive_compressor(struct archive *, struct private_data *,
+static int archive_compressor_bzip2_finish(struct archive_write *);
+static int archive_compressor_bzip2_init(struct archive_write *);
+static int archive_compressor_bzip2_write(struct archive_write *,
+ const void *, size_t);
+static int drive_compressor(struct archive_write *, struct private_data *,
int finishing);
/*
* Allocate, initialize and return an archive object.
*/
int
-archive_write_set_compression_bzip2(struct archive *a)
+archive_write_set_compression_bzip2(struct archive *_a)
{
- __archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_set_compression_bzip2");
+ struct archive_write *a = (struct archive_write *)_a;
+ __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_write_set_compression_bzip2");
a->compression_init = &archive_compressor_bzip2_init;
- a->compression_code = ARCHIVE_COMPRESSION_BZIP2;
- a->compression_name = "bzip2";
return (ARCHIVE_OK);
}
@@ -86,23 +87,23 @@ archive_write_set_compression_bzip2(struct archive *a)
* Setup callback.
*/
static int
-archive_compressor_bzip2_init(struct archive *a)
+archive_compressor_bzip2_init(struct archive_write *a)
{
int ret;
struct private_data *state;
- a->compression_code = ARCHIVE_COMPRESSION_BZIP2;
- a->compression_name = "bzip2";
+ a->archive.compression_code = ARCHIVE_COMPRESSION_BZIP2;
+ a->archive.compression_name = "bzip2";
if (a->client_opener != NULL) {
- ret = (a->client_opener)(a, a->client_data);
+ ret = (a->client_opener)(&a->archive, a->client_data);
if (ret != 0)
return (ret);
}
state = (struct private_data *)malloc(sizeof(*state));
if (state == NULL) {
- archive_set_error(a, ENOMEM,
+ archive_set_error(&a->archive, ENOMEM,
"Can't allocate data for compression");
return (ARCHIVE_FATAL);
}
@@ -112,7 +113,7 @@ archive_compressor_bzip2_init(struct archive *a)
state->compressed = (char *)malloc(state->compressed_buffer_size);
if (state->compressed == NULL) {
- archive_set_error(a, ENOMEM,
+ archive_set_error(&a->archive, ENOMEM,
"Can't allocate data for compression buffer");
free(state);
return (ARCHIVE_FATAL);
@@ -131,7 +132,7 @@ archive_compressor_bzip2_init(struct archive *a)
}
/* Library setup failed: clean up. */
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Internal error initializing compression library");
free(state->compressed);
free(state);
@@ -139,17 +140,17 @@ archive_compressor_bzip2_init(struct archive *a)
/* Override the error message if we know what really went wrong. */
switch (ret) {
case BZ_PARAM_ERROR:
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Internal error initializing compression library: "
"invalid setup parameter");
break;
case BZ_MEM_ERROR:
- archive_set_error(a, ENOMEM,
+ archive_set_error(&a->archive, ENOMEM,
"Internal error initializing compression library: "
"out of memory");
break;
case BZ_CONFIG_ERROR:
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Internal error initializing compression library: "
"mis-compiled library");
break;
@@ -165,14 +166,14 @@ archive_compressor_bzip2_init(struct archive *a)
* Returns ARCHIVE_OK if all data written, error otherwise.
*/
static int
-archive_compressor_bzip2_write(struct archive *a, const void *buff,
+archive_compressor_bzip2_write(struct archive_write *a, const void *buff,
size_t length)
{
struct private_data *state;
state = (struct private_data *)a->compression_data;
if (a->client_writer == NULL) {
- archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"No write callback is registered? "
"This is probably an internal programming error.");
return (ARCHIVE_FATAL);
@@ -186,7 +187,7 @@ archive_compressor_bzip2_write(struct archive *a, const void *buff,
state->stream.avail_in = length;
if (drive_compressor(a, state, 0))
return (ARCHIVE_FATAL);
- a->file_position += length;
+ a->archive.file_position += length;
return (ARCHIVE_OK);
}
@@ -195,7 +196,7 @@ archive_compressor_bzip2_write(struct archive *a, const void *buff,
* Finish the compression.
*/
static int
-archive_compressor_bzip2_finish(struct archive *a)
+archive_compressor_bzip2_finish(struct archive_write *a)
{
ssize_t block_length;
int ret;
@@ -207,7 +208,7 @@ archive_compressor_bzip2_finish(struct archive *a)
state = (struct private_data *)a->compression_data;
ret = ARCHIVE_OK;
if (a->client_writer == NULL) {
- archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"No write callback is registered?\n"
"This is probably an internal programming error.");
ret = ARCHIVE_FATAL;
@@ -257,14 +258,14 @@ archive_compressor_bzip2_finish(struct archive *a)
}
/* Write the last block */
- bytes_written = (a->client_writer)(a, a->client_data,
+ bytes_written = (a->client_writer)(&a->archive, a->client_data,
state->compressed, block_length);
/* TODO: Handle short write of final block. */
if (bytes_written <= 0)
ret = ARCHIVE_FATAL;
else {
- a->raw_position += ret;
+ a->archive.raw_position += ret;
ret = ARCHIVE_OK;
}
@@ -274,7 +275,7 @@ cleanup:
case BZ_OK:
break;
default:
- archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"Failed to clean up compressor");
ret = ARCHIVE_FATAL;
}
@@ -284,7 +285,7 @@ cleanup:
/* Close the output */
if (a->client_closer != NULL)
- (a->client_closer)(a, a->client_data);
+ (a->client_closer)(&a->archive, a->client_data);
return (ret);
}
@@ -297,15 +298,16 @@ cleanup:
* false) and the end-of-archive case (finishing == true).
*/
static int
-drive_compressor(struct archive *a, struct private_data *state, int finishing)
+drive_compressor(struct archive_write *a, struct private_data *state, int finishing)
{
ssize_t bytes_written;
int ret;
for (;;) {
if (state->stream.avail_out == 0) {
- bytes_written = (a->client_writer)(a, a->client_data,
- state->compressed, state->compressed_buffer_size);
+ bytes_written = (a->client_writer)(&a->archive,
+ a->client_data, state->compressed,
+ state->compressed_buffer_size);
if (bytes_written <= 0) {
/* TODO: Handle this write failure */
return (ARCHIVE_FATAL);
@@ -317,7 +319,7 @@ drive_compressor(struct archive *a, struct private_data *state, int finishing)
state->compressed_buffer_size - bytes_written);
}
- a->raw_position += bytes_written;
+ a->archive.raw_position += bytes_written;
state->stream.next_out = state->compressed +
state->compressed_buffer_size - bytes_written;
state->stream.avail_out = bytes_written;
@@ -340,7 +342,8 @@ drive_compressor(struct archive *a, struct private_data *state, int finishing)
return (ARCHIVE_OK);
default:
/* Any other return value indicates an error */
- archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
+ archive_set_error(&a->archive,
+ ARCHIVE_ERRNO_PROGRAMMER,
"Bzip2 compression failed");
return (ARCHIVE_FATAL);
}
diff --git a/lib/libarchive/archive_write_set_compression_gzip.c b/lib/libarchive/archive_write_set_compression_gzip.c
index 09f43f6..38742f3 100644
--- a/lib/libarchive/archive_write_set_compression_gzip.c
+++ b/lib/libarchive/archive_write_set_compression_gzip.c
@@ -46,6 +46,7 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_private.h"
+#include "archive_write_private.h"
struct private_data {
z_stream stream;
@@ -63,11 +64,11 @@ struct private_data {
#define SET_NEXT_IN(st,src) \
(st)->stream.next_in = (Bytef *)(uintptr_t)(const void *)(src)
-static int archive_compressor_gzip_finish(struct archive *);
-static int archive_compressor_gzip_init(struct archive *);
-static int archive_compressor_gzip_write(struct archive *, const void *,
- size_t);
-static int drive_compressor(struct archive *, struct private_data *,
+static int archive_compressor_gzip_finish(struct archive_write *);
+static int archive_compressor_gzip_init(struct archive_write *);
+static int archive_compressor_gzip_write(struct archive_write *,
+ const void *, size_t);
+static int drive_compressor(struct archive_write *, struct private_data *,
int finishing);
@@ -75,12 +76,14 @@ static int drive_compressor(struct archive *, struct private_data *,
* Allocate, initialize and return a archive object.
*/
int
-archive_write_set_compression_gzip(struct archive *a)
+archive_write_set_compression_gzip(struct archive *_a)
{
- __archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_set_compression_gzip");
+ struct archive_write *a = (struct archive_write *)_a;
+ __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_write_set_compression_gzip");
a->compression_init = &archive_compressor_gzip_init;
- a->compression_code = ARCHIVE_COMPRESSION_GZIP;
- a->compression_name = "gzip";
+ a->archive.compression_code = ARCHIVE_COMPRESSION_GZIP;
+ a->archive.compression_name = "gzip";
return (ARCHIVE_OK);
}
@@ -88,24 +91,24 @@ archive_write_set_compression_gzip(struct archive *a)
* Setup callback.
*/
static int
-archive_compressor_gzip_init(struct archive *a)
+archive_compressor_gzip_init(struct archive_write *a)
{
int ret;
struct private_data *state;
time_t t;
- a->compression_code = ARCHIVE_COMPRESSION_GZIP;
- a->compression_name = "gzip";
+ a->archive.compression_code = ARCHIVE_COMPRESSION_GZIP;
+ a->archive.compression_name = "gzip";
if (a->client_opener != NULL) {
- ret = (a->client_opener)(a, a->client_data);
+ ret = (a->client_opener)(&a->archive, a->client_data);
if (ret != ARCHIVE_OK)
return (ret);
}
state = (struct private_data *)malloc(sizeof(*state));
if (state == NULL) {
- archive_set_error(a, ENOMEM,
+ archive_set_error(&a->archive, ENOMEM,
"Can't allocate data for compression");
return (ARCHIVE_FATAL);
}
@@ -116,7 +119,7 @@ archive_compressor_gzip_init(struct archive *a)
state->crc = crc32(0L, NULL, 0);
if (state->compressed == NULL) {
- archive_set_error(a, ENOMEM,
+ archive_set_error(&a->archive, ENOMEM,
"Can't allocate data for compression buffer");
free(state);
return (ARCHIVE_FATAL);
@@ -157,7 +160,7 @@ archive_compressor_gzip_init(struct archive *a)
}
/* Library setup failed: clean up. */
- archive_set_error(a, ARCHIVE_ERRNO_MISC, "Internal error "
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Internal error "
"initializing compression library");
free(state->compressed);
free(state);
@@ -165,16 +168,16 @@ archive_compressor_gzip_init(struct archive *a)
/* Override the error message if we know what really went wrong. */
switch (ret) {
case Z_STREAM_ERROR:
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Internal error initializing "
"compression library: invalid setup parameter");
break;
case Z_MEM_ERROR:
- archive_set_error(a, ENOMEM, "Internal error initializing "
+ archive_set_error(&a->archive, ENOMEM, "Internal error initializing "
"compression library");
break;
case Z_VERSION_ERROR:
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Internal error initializing "
"compression library: invalid library version");
break;
@@ -187,7 +190,7 @@ archive_compressor_gzip_init(struct archive *a)
* Write data to the compressed stream.
*/
static int
-archive_compressor_gzip_write(struct archive *a, const void *buff,
+archive_compressor_gzip_write(struct archive_write *a, const void *buff,
size_t length)
{
struct private_data *state;
@@ -195,7 +198,7 @@ archive_compressor_gzip_write(struct archive *a, const void *buff,
state = (struct private_data *)a->compression_data;
if (a->client_writer == NULL) {
- archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"No write callback is registered? "
"This is probably an internal programming error.");
return (ARCHIVE_FATAL);
@@ -211,7 +214,7 @@ archive_compressor_gzip_write(struct archive *a, const void *buff,
if ((ret = drive_compressor(a, state, 0)) != ARCHIVE_OK)
return (ret);
- a->file_position += length;
+ a->archive.file_position += length;
return (ARCHIVE_OK);
}
@@ -220,7 +223,7 @@ archive_compressor_gzip_write(struct archive *a, const void *buff,
* Finish the compression...
*/
static int
-archive_compressor_gzip_finish(struct archive *a)
+archive_compressor_gzip_finish(struct archive_write *a)
{
ssize_t block_length, target_block_length, bytes_written;
int ret;
@@ -231,7 +234,7 @@ archive_compressor_gzip_finish(struct archive *a)
state = (struct private_data *)a->compression_data;
ret = 0;
if (a->client_writer == NULL) {
- archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"No write callback is registered? "
"This is probably an internal programming error.");
ret = ARCHIVE_FATAL;
@@ -280,13 +283,13 @@ archive_compressor_gzip_finish(struct archive *a)
/* If it overflowed, flush and start a new block. */
if (tocopy < 8) {
- bytes_written = (a->client_writer)(a, a->client_data,
+ bytes_written = (a->client_writer)(&a->archive, a->client_data,
state->compressed, state->compressed_buffer_size);
if (bytes_written <= 0) {
ret = ARCHIVE_FATAL;
goto cleanup;
}
- a->raw_position += bytes_written;
+ a->archive.raw_position += bytes_written;
state->stream.next_out = state->compressed;
state->stream.avail_out = state->compressed_buffer_size;
memcpy(state->stream.next_out, trailer + tocopy, 8-tocopy);
@@ -317,13 +320,13 @@ archive_compressor_gzip_finish(struct archive *a)
}
/* Write the last block */
- bytes_written = (a->client_writer)(a, a->client_data,
+ bytes_written = (a->client_writer)(&a->archive, a->client_data,
state->compressed, block_length);
if (bytes_written <= 0) {
ret = ARCHIVE_FATAL;
goto cleanup;
}
- a->raw_position += bytes_written;
+ a->archive.raw_position += bytes_written;
/* Cleanup: shut down compressor, release memory, etc. */
cleanup:
@@ -331,7 +334,7 @@ cleanup:
case Z_OK:
break;
default:
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Failed to clean up compressor");
ret = ARCHIVE_FATAL;
}
@@ -340,7 +343,7 @@ cleanup:
/* Close the output */
if (a->client_closer != NULL)
- (a->client_closer)(a, a->client_data);
+ (a->client_closer)(&a->archive, a->client_data);
return (ret);
}
@@ -353,15 +356,16 @@ cleanup:
* false) and the end-of-archive case (finishing == true).
*/
static int
-drive_compressor(struct archive *a, struct private_data *state, int finishing)
+drive_compressor(struct archive_write *a, struct private_data *state, int finishing)
{
ssize_t bytes_written;
int ret;
for (;;) {
if (state->stream.avail_out == 0) {
- bytes_written = (a->client_writer)(a, a->client_data,
- state->compressed, state->compressed_buffer_size);
+ bytes_written = (a->client_writer)(&a->archive,
+ a->client_data, state->compressed,
+ state->compressed_buffer_size);
if (bytes_written <= 0) {
/* TODO: Handle this write failure */
return (ARCHIVE_FATAL);
@@ -372,7 +376,7 @@ drive_compressor(struct archive *a, struct private_data *state, int finishing)
state->compressed + bytes_written,
state->compressed_buffer_size - bytes_written);
}
- a->raw_position += bytes_written;
+ a->archive.raw_position += bytes_written;
state->stream.next_out
= state->compressed +
state->compressed_buffer_size - bytes_written;
@@ -396,7 +400,7 @@ drive_compressor(struct archive *a, struct private_data *state, int finishing)
return (ARCHIVE_OK);
default:
/* Any other return value indicates an error. */
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"GZip compression failed");
return (ARCHIVE_FATAL);
}
diff --git a/lib/libarchive/archive_write_set_compression_none.c b/lib/libarchive/archive_write_set_compression_none.c
index 329bd76..44ac83e 100644
--- a/lib/libarchive/archive_write_set_compression_none.c
+++ b/lib/libarchive/archive_write_set_compression_none.c
@@ -38,11 +38,12 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_private.h"
+#include "archive_write_private.h"
-static int archive_compressor_none_finish(struct archive *a);
-static int archive_compressor_none_init(struct archive *);
-static int archive_compressor_none_write(struct archive *, const void *,
- size_t);
+static int archive_compressor_none_finish(struct archive_write *a);
+static int archive_compressor_none_init(struct archive_write *);
+static int archive_compressor_none_write(struct archive_write *,
+ const void *, size_t);
struct archive_none {
char *buffer;
@@ -52,12 +53,12 @@ struct archive_none {
};
int
-archive_write_set_compression_none(struct archive *a)
+archive_write_set_compression_none(struct archive *_a)
{
- __archive_check_magic(a, ARCHIVE_WRITE_MAGIC, ARCHIVE_STATE_NEW, "archive_write_set_compression_none");
+ struct archive_write *a = (struct archive_write *)_a;
+ __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_write_set_compression_none");
a->compression_init = &archive_compressor_none_init;
- a->compression_code = ARCHIVE_COMPRESSION_NONE;
- a->compression_name = "none";
return (0);
}
@@ -65,23 +66,23 @@ archive_write_set_compression_none(struct archive *a)
* Setup callback.
*/
static int
-archive_compressor_none_init(struct archive *a)
+archive_compressor_none_init(struct archive_write *a)
{
int ret;
struct archive_none *state;
- a->compression_code = ARCHIVE_COMPRESSION_NONE;
- a->compression_name = "none";
+ a->archive.compression_code = ARCHIVE_COMPRESSION_NONE;
+ a->archive.compression_name = "none";
if (a->client_opener != NULL) {
- ret = (a->client_opener)(a, a->client_data);
+ ret = (a->client_opener)(&a->archive, a->client_data);
if (ret != 0)
return (ret);
}
state = (struct archive_none *)malloc(sizeof(*state));
if (state == NULL) {
- archive_set_error(a, ENOMEM,
+ archive_set_error(&a->archive, ENOMEM,
"Can't allocate data for output buffering");
return (ARCHIVE_FATAL);
}
@@ -91,7 +92,7 @@ archive_compressor_none_init(struct archive *a)
if (state->buffer_size != 0) {
state->buffer = (char *)malloc(state->buffer_size);
if (state->buffer == NULL) {
- archive_set_error(a, ENOMEM,
+ archive_set_error(&a->archive, ENOMEM,
"Can't allocate output buffer");
free(state);
return (ARCHIVE_FATAL);
@@ -111,7 +112,7 @@ archive_compressor_none_init(struct archive *a)
* Write data to the stream.
*/
static int
-archive_compressor_none_write(struct archive *a, const void *vbuff,
+archive_compressor_none_write(struct archive_write *a, const void *vbuff,
size_t length)
{
const char *buff;
@@ -122,7 +123,7 @@ archive_compressor_none_write(struct archive *a, const void *vbuff,
state = (struct archive_none *)a->compression_data;
buff = (const char *)vbuff;
if (a->client_writer == NULL) {
- archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"No write callback is registered? "
"This is probably an internal programming error.");
return (ARCHIVE_FATAL);
@@ -138,14 +139,14 @@ archive_compressor_none_write(struct archive *a, const void *vbuff,
*/
if (state->buffer_size == 0) {
while (remaining > 0) {
- bytes_written = (a->client_writer)(a, a->client_data,
- buff, remaining);
+ bytes_written = (a->client_writer)(&a->archive,
+ a->client_data, buff, remaining);
if (bytes_written <= 0)
return (ARCHIVE_FATAL);
remaining -= bytes_written;
buff += bytes_written;
}
- a->file_position += length;
+ a->archive.file_position += length;
return (ARCHIVE_OK);
}
@@ -155,12 +156,12 @@ archive_compressor_none_write(struct archive *a, const void *vbuff,
* output buffer.
*/
if (state->avail == 0) {
- bytes_written = (a->client_writer)(a, a->client_data,
- state->buffer, state->buffer_size);
+ bytes_written = (a->client_writer)(&a->archive,
+ a->client_data, state->buffer, state->buffer_size);
if (bytes_written <= 0)
return (ARCHIVE_FATAL);
/* XXX TODO: if bytes_written < state->buffer_size */
- a->raw_position += bytes_written;
+ a->archive.raw_position += bytes_written;
state->next = state->buffer;
state->avail = state->buffer_size;
}
@@ -174,7 +175,7 @@ archive_compressor_none_write(struct archive *a, const void *vbuff,
buff += to_copy;
remaining -= to_copy;
}
- a->file_position += length;
+ a->archive.file_position += length;
return (ARCHIVE_OK);
}
@@ -183,7 +184,7 @@ archive_compressor_none_write(struct archive *a, const void *vbuff,
* Finish the compression.
*/
static int
-archive_compressor_none_finish(struct archive *a)
+archive_compressor_none_finish(struct archive_write *a)
{
ssize_t block_length;
ssize_t target_block_length;
@@ -195,7 +196,7 @@ archive_compressor_none_finish(struct archive *a)
state = (struct archive_none *)a->compression_data;
ret = ret2 = ARCHIVE_OK;
if (a->client_writer == NULL) {
- archive_set_error(a, ARCHIVE_ERRNO_PROGRAMMER,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"No write callback is registered? "
"This is probably an internal programming error.");
return (ARCHIVE_FATAL);
@@ -222,19 +223,19 @@ archive_compressor_none_finish(struct archive *a)
target_block_length - block_length);
block_length = target_block_length;
}
- bytes_written = (a->client_writer)(a, a->client_data,
- state->buffer, block_length);
+ bytes_written = (a->client_writer)(&a->archive,
+ a->client_data, state->buffer, block_length);
if (bytes_written <= 0)
ret = ARCHIVE_FATAL;
else {
- a->raw_position += bytes_written;
+ a->archive.raw_position += bytes_written;
ret = ARCHIVE_OK;
}
}
/* Close the output */
if (a->client_closer != NULL)
- ret2 = (a->client_closer)(a, a->client_data);
+ ret2 = (a->client_closer)(&a->archive, a->client_data);
free(state->buffer);
free(state);
diff --git a/lib/libarchive/archive_write_set_format_cpio.c b/lib/libarchive/archive_write_set_format_cpio.c
index 8aeb02b..e16fe31 100644
--- a/lib/libarchive/archive_write_set_format_cpio.c
+++ b/lib/libarchive/archive_write_set_format_cpio.c
@@ -43,12 +43,14 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_entry.h"
#include "archive_private.h"
-
-static ssize_t archive_write_cpio_data(struct archive *, const void *buff,
- size_t s);
-static int archive_write_cpio_finish(struct archive *);
-static int archive_write_cpio_finish_entry(struct archive *);
-static int archive_write_cpio_header(struct archive *,
+#include "archive_write_private.h"
+
+static ssize_t archive_write_cpio_data(struct archive_write *,
+ const void *buff, size_t s);
+static int archive_write_cpio_finish(struct archive_write *);
+static int archive_write_cpio_destroy(struct archive_write *);
+static int archive_write_cpio_finish_entry(struct archive_write *);
+static int archive_write_cpio_header(struct archive_write *,
struct archive_entry *);
static int format_octal(int64_t, void *, int);
static int64_t format_octal_recursive(int64_t, char *, int);
@@ -75,17 +77,18 @@ struct cpio_header {
* Set output format to 'cpio' format.
*/
int
-archive_write_set_format_cpio(struct archive *a)
+archive_write_set_format_cpio(struct archive *_a)
{
+ struct archive_write *a = (struct archive_write *)_a;
struct cpio *cpio;
/* If someone else was already registered, unregister them. */
- if (a->format_finish != NULL)
- (a->format_finish)(a);
+ if (a->format_destroy != NULL)
+ (a->format_destroy)(a);
cpio = (struct cpio *)malloc(sizeof(*cpio));
if (cpio == NULL) {
- archive_set_error(a, ENOMEM, "Can't allocate cpio data");
+ archive_set_error(&a->archive, ENOMEM, "Can't allocate cpio data");
return (ARCHIVE_FATAL);
}
memset(cpio, 0, sizeof(*cpio));
@@ -96,13 +99,14 @@ archive_write_set_format_cpio(struct archive *a)
a->format_write_data = archive_write_cpio_data;
a->format_finish_entry = archive_write_cpio_finish_entry;
a->format_finish = archive_write_cpio_finish;
+ a->format_destroy = archive_write_cpio_destroy;
a->archive_format = ARCHIVE_FORMAT_CPIO_POSIX;
a->archive_format_name = "POSIX cpio";
return (ARCHIVE_OK);
}
static int
-archive_write_cpio_header(struct archive *a, struct archive_entry *entry)
+archive_write_cpio_header(struct archive_write *a, struct archive_entry *entry)
{
struct cpio *cpio;
const char *p, *path;
@@ -126,7 +130,7 @@ archive_write_cpio_header(struct archive *a, struct archive_entry *entry)
* field only limits the number of files in the archive.
*/
if (st->st_ino > 0777777) {
- archive_set_error(a, ERANGE, "large inode number truncated");
+ archive_set_error(&a->archive, ERANGE, "large inode number truncated");
ret = ARCHIVE_WARN;
}
@@ -167,7 +171,7 @@ archive_write_cpio_header(struct archive *a, struct archive_entry *entry)
}
static ssize_t
-archive_write_cpio_data(struct archive *a, const void *buff, size_t s)
+archive_write_cpio_data(struct archive_write *a, const void *buff, size_t s)
{
struct cpio *cpio;
int ret;
@@ -215,7 +219,7 @@ format_octal_recursive(int64_t v, char *p, int s)
}
static int
-archive_write_cpio_finish(struct archive *a)
+archive_write_cpio_finish(struct archive_write *a)
{
struct cpio *cpio;
struct stat st;
@@ -230,14 +234,22 @@ archive_write_cpio_finish(struct archive *a)
archive_entry_set_pathname(trailer, "TRAILER!!!");
er = archive_write_cpio_header(a, trailer);
archive_entry_free(trailer);
+ return (er);
+}
+
+static int
+archive_write_cpio_destroy(struct archive_write *a)
+{
+ struct cpio *cpio;
+ cpio = (struct cpio *)a->format_data;
free(cpio);
a->format_data = NULL;
- return (er);
+ return (ARCHIVE_OK);
}
static int
-archive_write_cpio_finish_entry(struct archive *a)
+archive_write_cpio_finish_entry(struct archive_write *a)
{
struct cpio *cpio;
int to_write, ret;
diff --git a/lib/libarchive/archive_write_set_format_pax.c b/lib/libarchive/archive_write_set_format_pax.c
index 8bc4f9e..35a43ff 100644
--- a/lib/libarchive/archive_write_set_format_pax.c
+++ b/lib/libarchive/archive_write_set_format_pax.c
@@ -52,12 +52,12 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_entry.h"
#include "archive_private.h"
+#include "archive_write_private.h"
struct pax {
uint64_t entry_bytes_remaining;
uint64_t entry_padding;
struct archive_string pax_header;
- char written;
};
static void add_pax_attr(struct archive_string *, const char *key,
@@ -69,11 +69,12 @@ static void add_pax_attr_time(struct archive_string *,
unsigned long nanos);
static void add_pax_attr_w(struct archive_string *,
const char *key, const wchar_t *wvalue);
-static ssize_t archive_write_pax_data(struct archive *,
+static ssize_t archive_write_pax_data(struct archive_write *,
const void *, size_t);
-static int archive_write_pax_finish(struct archive *);
-static int archive_write_pax_finish_entry(struct archive *);
-static int archive_write_pax_header(struct archive *,
+static int archive_write_pax_finish(struct archive_write *);
+static int archive_write_pax_destroy(struct archive_write *);
+static int archive_write_pax_finish_entry(struct archive_write *);
+static int archive_write_pax_header(struct archive_write *,
struct archive_entry *);
static char *base64_encode(const char *src, size_t len);
static char *build_pax_attribute_name(char *dest, const char *src);
@@ -82,7 +83,7 @@ static char *build_ustar_entry_name(char *dest, const char *src,
static char *format_int(char *dest, int64_t);
static int has_non_ASCII(const wchar_t *);
static char *url_encode(const char *in);
-static int write_nulls(struct archive *, size_t);
+static int write_nulls(struct archive_write *, size_t);
/*
* Set output format to 'restricted pax' format.
@@ -92,10 +93,11 @@ static int write_nulls(struct archive *, size_t);
* bsdtar, for instance.
*/
int
-archive_write_set_format_pax_restricted(struct archive *a)
+archive_write_set_format_pax_restricted(struct archive *_a)
{
+ struct archive_write *a = (struct archive_write *)_a;
int r;
- r = archive_write_set_format_pax(a);
+ r = archive_write_set_format_pax(&a->archive);
a->archive_format = ARCHIVE_FORMAT_TAR_PAX_RESTRICTED;
a->archive_format_name = "restricted POSIX pax interchange";
return (r);
@@ -105,16 +107,17 @@ archive_write_set_format_pax_restricted(struct archive *a)
* Set output format to 'pax' format.
*/
int
-archive_write_set_format_pax(struct archive *a)
+archive_write_set_format_pax(struct archive *_a)
{
+ struct archive_write *a = (struct archive_write *)_a;
struct pax *pax;
- if (a->format_finish != NULL)
- (a->format_finish)(a);
+ if (a->format_destroy != NULL)
+ (a->format_destroy)(a);
pax = (struct pax *)malloc(sizeof(*pax));
if (pax == NULL) {
- archive_set_error(a, ENOMEM, "Can't allocate pax data");
+ archive_set_error(&a->archive, ENOMEM, "Can't allocate pax data");
return (ARCHIVE_FATAL);
}
memset(pax, 0, sizeof(*pax));
@@ -124,6 +127,7 @@ archive_write_set_format_pax(struct archive *a)
a->format_write_header = archive_write_pax_header;
a->format_write_data = archive_write_pax_data;
a->format_finish = archive_write_pax_finish;
+ a->format_destroy = archive_write_pax_destroy;
a->format_finish_entry = archive_write_pax_finish_entry;
a->archive_format = ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE;
a->archive_format_name = "POSIX pax interchange";
@@ -388,7 +392,7 @@ archive_write_pax_header_xattrs(struct pax *pax, struct archive_entry *entry)
* key/value data.
*/
static int
-archive_write_pax_header(struct archive *a,
+archive_write_pax_header(struct archive_write *a,
struct archive_entry *entry_original)
{
struct archive_entry *entry_main;
@@ -407,7 +411,6 @@ archive_write_pax_header(struct archive *a,
need_extension = 0;
pax = (struct pax *)a->format_data;
- pax->written = 1;
st_original = archive_entry_stat(entry_original);
@@ -424,11 +427,11 @@ archive_write_pax_header(struct archive *a,
case S_IFIFO:
break;
case S_IFSOCK:
- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"tar format cannot archive socket");
return (ARCHIVE_WARN);
default:
- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"tar format cannot archive this (mode=0%lo)",
(unsigned long)st_original->st_mode);
return (ARCHIVE_WARN);
@@ -1038,23 +1041,33 @@ build_pax_attribute_name(char *dest, const char *src)
/* Write two null blocks for the end of archive */
static int
-archive_write_pax_finish(struct archive *a)
+archive_write_pax_finish(struct archive_write *a)
{
struct pax *pax;
int r;
- r = ARCHIVE_OK;
+ if (a->compression_write == NULL)
+ return (ARCHIVE_OK);
+
+ pax = (struct pax *)a->format_data;
+ r = write_nulls(a, 512 * 2);
+ return (r);
+}
+
+static int
+archive_write_pax_destroy(struct archive_write *a)
+{
+ struct pax *pax;
+
pax = (struct pax *)a->format_data;
- if (pax->written && a->compression_write != NULL)
- r = write_nulls(a, 512 * 2);
archive_string_free(&pax->pax_header);
free(pax);
a->format_data = NULL;
- return (r);
+ return (ARCHIVE_OK);
}
static int
-archive_write_pax_finish_entry(struct archive *a)
+archive_write_pax_finish_entry(struct archive_write *a)
{
struct pax *pax;
int ret;
@@ -1066,7 +1079,7 @@ archive_write_pax_finish_entry(struct archive *a)
}
static int
-write_nulls(struct archive *a, size_t padding)
+write_nulls(struct archive_write *a, size_t padding)
{
int ret, to_write;
@@ -1081,13 +1094,12 @@ write_nulls(struct archive *a, size_t padding)
}
static ssize_t
-archive_write_pax_data(struct archive *a, const void *buff, size_t s)
+archive_write_pax_data(struct archive_write *a, const void *buff, size_t s)
{
struct pax *pax;
int ret;
pax = (struct pax *)a->format_data;
- pax->written = 1;
if (s > pax->entry_bytes_remaining)
s = pax->entry_bytes_remaining;
diff --git a/lib/libarchive/archive_write_set_format_shar.c b/lib/libarchive/archive_write_set_format_shar.c
index cf4c38e..5751b3e 100644
--- a/lib/libarchive/archive_write_set_format_shar.c
+++ b/lib/libarchive/archive_write_set_format_shar.c
@@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_entry.h"
#include "archive_private.h"
+#include "archive_write_private.h"
struct shar {
int dump;
@@ -60,19 +61,20 @@ struct shar {
struct archive_string work;
};
-static int archive_write_shar_finish(struct archive *);
-static int archive_write_shar_header(struct archive *,
+static int archive_write_shar_finish(struct archive_write *);
+static int archive_write_shar_destroy(struct archive_write *);
+static int archive_write_shar_header(struct archive_write *,
struct archive_entry *);
-static ssize_t archive_write_shar_data_sed(struct archive *,
+static ssize_t archive_write_shar_data_sed(struct archive_write *,
const void * buff, size_t);
-static ssize_t archive_write_shar_data_uuencode(struct archive *,
+static ssize_t archive_write_shar_data_uuencode(struct archive_write *,
const void * buff, size_t);
-static int archive_write_shar_finish_entry(struct archive *);
-static int shar_printf(struct archive *, const char *fmt, ...);
+static int archive_write_shar_finish_entry(struct archive_write *);
+static int shar_printf(struct archive_write *, const char *fmt, ...);
static void uuencode_group(struct shar *);
static int
-shar_printf(struct archive *a, const char *fmt, ...)
+shar_printf(struct archive_write *a, const char *fmt, ...)
{
struct shar *shar;
va_list ap;
@@ -91,17 +93,18 @@ shar_printf(struct archive *a, const char *fmt, ...)
* Set output format to 'shar' format.
*/
int
-archive_write_set_format_shar(struct archive *a)
+archive_write_set_format_shar(struct archive *_a)
{
+ struct archive_write *a = (struct archive_write *)_a;
struct shar *shar;
/* If someone else was already registered, unregister them. */
- if (a->format_finish != NULL)
- (a->format_finish)(a);
+ if (a->format_destroy != NULL)
+ (a->format_destroy)(a);
shar = (struct shar *)malloc(sizeof(*shar));
if (shar == NULL) {
- archive_set_error(a, ENOMEM, "Can't allocate shar data");
+ archive_set_error(&a->archive, ENOMEM, "Can't allocate shar data");
return (ARCHIVE_FATAL);
}
memset(shar, 0, sizeof(*shar));
@@ -110,6 +113,7 @@ archive_write_set_format_shar(struct archive *a)
a->pad_uncompressed = 0;
a->format_write_header = archive_write_shar_header;
a->format_finish = archive_write_shar_finish;
+ a->format_destroy = archive_write_shar_destroy;
a->format_write_data = archive_write_shar_data_sed;
a->format_finish_entry = archive_write_shar_finish_entry;
a->archive_format = ARCHIVE_FORMAT_SHAR_BASE;
@@ -124,11 +128,12 @@ archive_write_set_format_shar(struct archive *a)
* and other extended file information.
*/
int
-archive_write_set_format_shar_dump(struct archive *a)
+archive_write_set_format_shar_dump(struct archive *_a)
{
+ struct archive_write *a = (struct archive_write *)_a;
struct shar *shar;
- archive_write_set_format_shar(a);
+ archive_write_set_format_shar(&a->archive);
shar = (struct shar *)a->format_data;
shar->dump = 1;
a->format_write_data = archive_write_shar_data_uuencode;
@@ -138,7 +143,7 @@ archive_write_set_format_shar_dump(struct archive *a)
}
static int
-archive_write_shar_header(struct archive *a, struct archive_entry *entry)
+archive_write_shar_header(struct archive_write *a, struct archive_entry *entry)
{
const char *linkname;
const char *name;
@@ -186,7 +191,7 @@ archive_write_shar_header(struct archive *a, struct archive_entry *entry)
archive_entry_set_size(entry, 0);
if (archive_entry_hardlink(entry) == NULL &&
archive_entry_symlink(entry) == NULL) {
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"shar format cannot archive this");
return (ARCHIVE_WARN);
}
@@ -323,7 +328,7 @@ archive_write_shar_header(struct archive *a, struct archive_entry *entry)
/* XXX TODO: This could be more efficient XXX */
static ssize_t
-archive_write_shar_data_sed(struct archive *a, const void *buff, size_t n)
+archive_write_shar_data_sed(struct archive_write *a, const void *buff, size_t n)
{
struct shar *shar;
const char *src;
@@ -387,7 +392,7 @@ uuencode_group(struct shar *shar)
}
static ssize_t
-archive_write_shar_data_uuencode(struct archive *a, const void *buff,
+archive_write_shar_data_uuencode(struct archive_write *a, const void *buff,
size_t length)
{
struct shar *shar;
@@ -419,7 +424,7 @@ archive_write_shar_data_uuencode(struct archive *a, const void *buff,
}
static int
-archive_write_shar_finish_entry(struct archive *a)
+archive_write_shar_finish_entry(struct archive_write *a)
{
const char *g, *p, *u;
struct shar *shar;
@@ -504,7 +509,7 @@ archive_write_shar_finish_entry(struct archive *a)
}
static int
-archive_write_shar_finish(struct archive *a)
+archive_write_shar_finish(struct archive_write *a)
{
struct shar *shar;
int ret;
@@ -527,12 +532,21 @@ archive_write_shar_finish(struct archive *a)
if (ret != ARCHIVE_OK)
return (ret);
/* Shar output is never padded. */
- archive_write_set_bytes_in_last_block(a, 1);
+ archive_write_set_bytes_in_last_block(&a->archive, 1);
/*
* TODO: shar should also suppress padding of
* uncompressed data within gzip/bzip2 streams.
*/
}
+ return (ARCHIVE_OK);
+}
+
+static int
+archive_write_shar_destroy(struct archive_write *a)
+{
+ struct shar *shar;
+
+ shar = (struct shar *)a->format_data;
if (shar->entry != NULL)
archive_entry_free(shar->entry);
if (shar->last_dir != NULL)
diff --git a/lib/libarchive/archive_write_set_format_ustar.c b/lib/libarchive/archive_write_set_format_ustar.c
index 2829ea6..87fc16a 100644
--- a/lib/libarchive/archive_write_set_format_ustar.c
+++ b/lib/libarchive/archive_write_set_format_ustar.c
@@ -50,11 +50,11 @@ __FBSDID("$FreeBSD$");
#include "archive.h"
#include "archive_entry.h"
#include "archive_private.h"
+#include "archive_write_private.h"
struct ustar {
uint64_t entry_bytes_remaining;
uint64_t entry_padding;
- char written;
};
/*
@@ -150,38 +150,40 @@ static const char template_header[] = {
0,0,0,0,0,0,0,0, 0,0,0,0
};
-static ssize_t archive_write_ustar_data(struct archive *a, const void *buff,
+static ssize_t archive_write_ustar_data(struct archive_write *a, const void *buff,
size_t s);
-static int archive_write_ustar_finish(struct archive *);
-static int archive_write_ustar_finish_entry(struct archive *);
-static int archive_write_ustar_header(struct archive *,
+static int archive_write_ustar_destroy(struct archive_write *);
+static int archive_write_ustar_finish(struct archive_write *);
+static int archive_write_ustar_finish_entry(struct archive_write *);
+static int archive_write_ustar_header(struct archive_write *,
struct archive_entry *entry);
static int format_256(int64_t, char *, int);
static int format_number(int64_t, char *, int size, int max, int strict);
static int format_octal(int64_t, char *, int);
-static int write_nulls(struct archive *a, size_t);
+static int write_nulls(struct archive_write *a, size_t);
/*
* Set output format to 'ustar' format.
*/
int
-archive_write_set_format_ustar(struct archive *a)
+archive_write_set_format_ustar(struct archive *_a)
{
+ struct archive_write *a = (struct archive_write *)_a;
struct ustar *ustar;
/* If someone else was already registered, unregister them. */
- if (a->format_finish != NULL)
- (a->format_finish)(a);
+ if (a->format_destroy != NULL)
+ (a->format_destroy)(a);
/* Basic internal sanity test. */
if (sizeof(template_header) != 512) {
- archive_set_error(a, ARCHIVE_ERRNO_MISC, "Internal: template_header wrong size: %d should be 512", sizeof(template_header));
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC, "Internal: template_header wrong size: %d should be 512", sizeof(template_header));
return (ARCHIVE_FATAL);
}
ustar = (struct ustar *)malloc(sizeof(*ustar));
if (ustar == NULL) {
- archive_set_error(a, ENOMEM, "Can't allocate ustar data");
+ archive_set_error(&a->archive, ENOMEM, "Can't allocate ustar data");
return (ARCHIVE_FATAL);
}
memset(ustar, 0, sizeof(*ustar));
@@ -191,6 +193,7 @@ archive_write_set_format_ustar(struct archive *a)
a->format_write_header = archive_write_ustar_header;
a->format_write_data = archive_write_ustar_data;
a->format_finish = archive_write_ustar_finish;
+ a->format_destroy = archive_write_ustar_destroy;
a->format_finish_entry = archive_write_ustar_finish_entry;
a->archive_format = ARCHIVE_FORMAT_TAR_USTAR;
a->archive_format_name = "POSIX ustar";
@@ -198,14 +201,13 @@ archive_write_set_format_ustar(struct archive *a)
}
static int
-archive_write_ustar_header(struct archive *a, struct archive_entry *entry)
+archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry)
{
char buff[512];
int ret;
struct ustar *ustar;
ustar = (struct ustar *)a->format_data;
- ustar->written = 1;
/* Only regular files (not hardlinks) have data. */
if (archive_entry_hardlink(entry) != NULL ||
@@ -236,7 +238,7 @@ archive_write_ustar_header(struct archive *a, struct archive_entry *entry)
* This is exported so that other 'tar' formats can use it.
*/
int
-__archive_write_format_header_ustar(struct archive *a, char h[512],
+__archive_write_format_header_ustar(struct archive_write *a, char h[512],
struct archive_entry *entry, int tartype, int strict)
{
unsigned int checksum;
@@ -272,11 +274,11 @@ __archive_write_format_header_ustar(struct archive *a, char h[512],
* remaining name are too large, return an error.
*/
if (!p) {
- archive_set_error(a, ENAMETOOLONG,
+ archive_set_error(&a->archive, ENAMETOOLONG,
"Pathname too long");
ret = ARCHIVE_WARN;
} else if (p > pp + USTAR_prefix_size) {
- archive_set_error(a, ENAMETOOLONG,
+ archive_set_error(&a->archive, ENAMETOOLONG,
"Pathname too long");
ret = ARCHIVE_WARN;
} else {
@@ -294,7 +296,7 @@ __archive_write_format_header_ustar(struct archive *a, char h[512],
if (p != NULL && p[0] != '\0') {
copy_length = strlen(p);
if (copy_length > USTAR_linkname_size) {
- archive_set_error(a, ENAMETOOLONG,
+ archive_set_error(&a->archive, ENAMETOOLONG,
"Link contents too long");
ret = ARCHIVE_WARN;
copy_length = USTAR_linkname_size;
@@ -306,7 +308,7 @@ __archive_write_format_header_ustar(struct archive *a, char h[512],
if (p != NULL && p[0] != '\0') {
copy_length = strlen(p);
if (copy_length > USTAR_uname_size) {
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Username too long");
ret = ARCHIVE_WARN;
copy_length = USTAR_uname_size;
@@ -318,7 +320,7 @@ __archive_write_format_header_ustar(struct archive *a, char h[512],
if (p != NULL && p[0] != '\0') {
copy_length = strlen(p);
if (strlen(p) > USTAR_gname_size) {
- archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Group name too long");
ret = ARCHIVE_WARN;
copy_length = USTAR_gname_size;
@@ -329,27 +331,27 @@ __archive_write_format_header_ustar(struct archive *a, char h[512],
st = archive_entry_stat(entry);
if (format_number(st->st_mode & 07777, h + USTAR_mode_offset, USTAR_mode_size, USTAR_mode_max_size, strict)) {
- archive_set_error(a, ERANGE, "Numeric mode too large");
+ archive_set_error(&a->archive, ERANGE, "Numeric mode too large");
ret = ARCHIVE_WARN;
}
if (format_number(st->st_uid, h + USTAR_uid_offset, USTAR_uid_size, USTAR_uid_max_size, strict)) {
- archive_set_error(a, ERANGE, "Numeric user ID too large");
+ archive_set_error(&a->archive, ERANGE, "Numeric user ID too large");
ret = ARCHIVE_WARN;
}
if (format_number(st->st_gid, h + USTAR_gid_offset, USTAR_gid_size, USTAR_gid_max_size, strict)) {
- archive_set_error(a, ERANGE, "Numeric group ID too large");
+ archive_set_error(&a->archive, ERANGE, "Numeric group ID too large");
ret = ARCHIVE_WARN;
}
if (format_number(st->st_size, h + USTAR_size_offset, USTAR_size_size, USTAR_size_max_size, strict)) {
- archive_set_error(a, ERANGE, "File size out of range");
+ archive_set_error(&a->archive, ERANGE, "File size out of range");
ret = ARCHIVE_WARN;
}
if (format_number(st->st_mtime, h + USTAR_mtime_offset, USTAR_mtime_size, USTAR_mtime_max_size, strict)) {
- archive_set_error(a, ERANGE,
+ archive_set_error(&a->archive, ERANGE,
"File modification time too large");
ret = ARCHIVE_WARN;
}
@@ -357,14 +359,14 @@ __archive_write_format_header_ustar(struct archive *a, char h[512],
if (S_ISBLK(st->st_mode) || S_ISCHR(st->st_mode)) {
if (format_number(major(st->st_rdev), h + USTAR_rdevmajor_offset,
USTAR_rdevmajor_size, USTAR_rdevmajor_max_size, strict)) {
- archive_set_error(a, ERANGE,
+ archive_set_error(&a->archive, ERANGE,
"Major device number too large");
ret = ARCHIVE_WARN;
}
if (format_number(minor(st->st_rdev), h + USTAR_rdevminor_offset,
USTAR_rdevminor_size, USTAR_rdevminor_max_size, strict)) {
- archive_set_error(a, ERANGE,
+ archive_set_error(&a->archive, ERANGE,
"Minor device number too large");
ret = ARCHIVE_WARN;
}
@@ -383,12 +385,12 @@ __archive_write_format_header_ustar(struct archive *a, char h[512],
case S_IFDIR: h[USTAR_typeflag_offset] = '5' ; break;
case S_IFIFO: h[USTAR_typeflag_offset] = '6' ; break;
case S_IFSOCK:
- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"tar format cannot archive socket");
ret = ARCHIVE_WARN;
break;
default:
- archive_set_error(a, ARCHIVE_ERRNO_FILE_FORMAT,
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"tar format cannot archive this (mode=0%lo)",
(unsigned long)st->st_mode);
ret = ARCHIVE_WARN;
@@ -486,27 +488,32 @@ format_octal(int64_t v, char *p, int s)
}
static int
-archive_write_ustar_finish(struct archive *a)
+archive_write_ustar_finish(struct archive_write *a)
{
struct ustar *ustar;
int r;
- r = ARCHIVE_OK;
+ if (a->compression_write == NULL)
+ return (ARCHIVE_OK);
+
+ ustar = (struct ustar *)a->format_data;
+ r = write_nulls(a, 512*2);
+ return (r);
+}
+
+static int
+archive_write_ustar_destroy(struct archive_write *a)
+{
+ struct ustar *ustar;
+
ustar = (struct ustar *)a->format_data;
- /*
- * Suppress end-of-archive if nothing else was ever written.
- * This fixes a problem where setting one format, then another
- * ends up writing a gratuitous end-of-archive marker.
- */
- if (ustar->written && a->compression_write != NULL)
- r = write_nulls(a, 512*2);
free(ustar);
a->format_data = NULL;
- return (r);
+ return (ARCHIVE_OK);
}
static int
-archive_write_ustar_finish_entry(struct archive *a)
+archive_write_ustar_finish_entry(struct archive_write *a)
{
struct ustar *ustar;
int ret;
@@ -519,7 +526,7 @@ archive_write_ustar_finish_entry(struct archive *a)
}
static int
-write_nulls(struct archive *a, size_t padding)
+write_nulls(struct archive_write *a, size_t padding)
{
int ret, to_write;
@@ -534,7 +541,7 @@ write_nulls(struct archive *a, size_t padding)
}
static ssize_t
-archive_write_ustar_data(struct archive *a, const void *buff, size_t s)
+archive_write_ustar_data(struct archive_write *a, const void *buff, size_t s)
{
struct ustar *ustar;
int ret;
diff --git a/lib/libarchive/test/Makefile b/lib/libarchive/test/Makefile
new file mode 100644
index 0000000..4bd434e
--- /dev/null
+++ b/lib/libarchive/test/Makefile
@@ -0,0 +1,67 @@
+# $FreeBSD$
+
+TESTS= \
+ test_archive_api_feature.c \
+ test_bad_fd.c \
+ test_read_data_large.c \
+ test_read_extract.c \
+ test_read_format_cpio_bin.c \
+ test_read_format_cpio_bin_Z.c \
+ test_read_format_cpio_bin_bz2.c \
+ test_read_format_cpio_bin_gz.c \
+ test_read_format_cpio_odc.c \
+ test_read_format_cpio_svr4_gzip.c \
+ test_read_format_cpio_svr4c_Z.c \
+ test_read_format_empty.c \
+ test_read_format_gtar_gz.c \
+ test_read_format_iso_gz.c \
+ test_read_format_isorr_bz2.c \
+ test_read_format_pax_bz2.c \
+ test_read_format_tar.c \
+ test_read_format_tbz.c \
+ test_read_format_tgz.c \
+ test_read_format_tz.c \
+ test_read_format_zip.c \
+ test_read_large.c \
+ test_read_position.c \
+ test_read_truncated.c \
+ test_write_disk.c \
+ test_write_disk_perms.c \
+ test_write_disk_secure.c \
+ test_write_format_cpio_empty.c \
+ test_write_format_shar_empty.c \
+ test_write_format_tar.c \
+ test_write_format_tar_empty.c \
+ test_write_open_memory.c
+
+SRCS= ${TESTS} \
+ list.h \
+ main.c
+
+CLEANFILES+= list.h
+
+MK_MAN=no
+NO_MAN=yes
+
+PROG=libarchive_test
+DPADD=${LIBARCHIVE} ${LIBBZ2} ${LIBZ}
+LDADD= -larchive -lz -lbz2
+CFLAGS+= -static -g
+CFLAGS+= -I${.OBJDIR}
+
+test: libarchive_test
+ ./libarchive_test
+
+list.h: ${TESTS} Makefile
+ (cd ${.CURDIR}; cat ${TESTS}) | grep DEFINE_TEST > list.h
+
+clean:
+ rm -f *.out
+ rm -f *.o
+ rm -f *.core
+ rm -f *~
+ rm -f list.h
+ -chmod -R +w /tmp/libarchive_test.*
+ rm -rf /tmp/libarchive_test.*
+
+.include <bsd.prog.mk> \ No newline at end of file
diff --git a/lib/libarchive/test/README b/lib/libarchive/test/README
new file mode 100644
index 0000000..c6c242e
--- /dev/null
+++ b/lib/libarchive/test/README
@@ -0,0 +1,46 @@
+$FreeBSD$
+
+This is the test harness for libarchive.
+
+It compiles into a single program "libarchive_test" that is intended
+to exercise as much of the library as possible. It is, of course,
+very much a work in progress.
+
+Each test is a function named test_foo in a file named test_foo.c.
+Note that the file name is the same as the function name.
+Each file must start with this line:
+
+ #include "test.h"
+
+The test function must be declared with a line of this form
+
+ DEFINE_TEST(test_foo)
+
+Nothing else should appear on that line.
+
+When you add a test, please update the Makefile to add your
+file to the list of tests. The Makefile and main.c use various
+macro trickery to automatically collect a list of test functions
+to be invoked.
+
+Each test function can rely on the following:
+
+ * The current directory will be a freshly-created empty directory
+ suitable for that test. (The top-level main() creates a
+ directory for each separate test and chdir()s to that directory
+ before running the test.)
+
+ * The test function should use assert(), assertA() and similar macros
+ defined in test.h. If you need to add new macros of this form, feel
+ free to do so.
+
+ * You are encouraged to document each assertion with a failure() call
+ just before the assert. The failure() function is a printf-like
+ function whose text is displayed only if the assertion fails. It
+ can be used to display additional information relevant to the failure:
+
+ failure("The data read from file %s did not match the data written to that file.", filename);
+ assert(strcmp(buff1, buff2) == 0);
+
+ * Tests are encouraged to be economical with their memory and disk usage,
+ though this is not essential.
diff --git a/lib/libarchive/test/main.c b/lib/libarchive/test/main.c
new file mode 100644
index 0000000..f9abce0
--- /dev/null
+++ b/lib/libarchive/test/main.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2003-2006 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 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.
+ */
+
+/*
+ * Various utility routines useful for test programs.
+ * Each test program is linked against this file.
+ */
+#include <stdarg.h>
+#include <time.h>
+
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+/*
+ * My own implementation of the standard assert() macro emits the
+ * message in the same format as GCC (file:line: message).
+ * It also includes some additional useful information.
+ * This makes it a lot easier to skim through test failures in
+ * Emacs. ;-)
+ *
+ * It also supports a few special features specifically to simplify
+ * libarchive test harnesses:
+ * failure(fmt, args) -- Stores a text string that gets
+ * printed if the following assertion fails, good for
+ * explaining subtle tests.
+ * assertA(a, cond) -- If the test fails, also prints out any error
+ * message stored in archive object 'a'.
+ */
+static char msg[4096];
+
+void
+failure(const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vsprintf(msg, fmt, ap);
+ va_end(ap);
+}
+
+void
+test_assert(const char *file, int line, int value, const char *condition, struct archive *a)
+{
+ if (value) {
+ msg[0] = '\0';
+ return;
+ }
+ fprintf(stderr, "%s:%d: Assertion failed\n", file, line);
+ fprintf(stderr, " Condition: %s\n", condition);
+ if (msg[0] != '\0') {
+ fprintf(stderr, " Description: %s\n", msg);
+ msg[0] = '\0';
+ }
+ if (a != NULL) {
+ fprintf(stderr, " archive error: %s\n", archive_error_string(a));
+ }
+ *(char *)(NULL) = 0;
+ exit(1);
+}
+
+void
+test_assert_equal_int(const char *file, int line,
+ int v1, const char *e1, int v2, const char *e2, struct archive *a)
+{
+ if (v1 == v2) {
+ msg[0] = '\0';
+ return;
+ }
+ fprintf(stderr, "%s:%d: Assertion failed\n", file, line);
+ fprintf(stderr, " Condition: %s==%s\n", e1, e2);
+ fprintf(stderr, " %s=%d\n", e1, v1);
+ fprintf(stderr, " %s=%d\n", e2, v2);
+ if (msg[0] != '\0') {
+ fprintf(stderr, " Description: %s\n", msg);
+ msg[0] = '\0';
+ }
+ if (a != NULL) {
+ fprintf(stderr, " archive error: %s\n", archive_error_string(a));
+ }
+ *(char *)(NULL) = 0;
+ exit(1);
+}
+
+/*
+ * "list.h" is automatically generated; it just has a lot of lines like:
+ * DEFINE_TEST(function_name)
+ * The common "test.h" includes it to declare all of the test functions.
+ * We reuse it here to define a list of all tests to run.
+ */
+#undef DEFINE_TEST
+#define DEFINE_TEST(n) n, #n,
+struct { void (*func)(void); char *name; } tests[] = {
+ #include "list.h"
+};
+
+int main(int argc, char **argv)
+{
+ void (*f)(void);
+ int limit = sizeof(tests) / sizeof(tests[0]);
+ int i;
+ time_t now;
+ char tmpdir[256];
+ int tmpdirHandle;
+
+ /*
+ * Create a temp directory for the following tests.
+ * Include the time the tests started as part of the name,
+ * to make it easier to track the results of multiple tests.
+ */
+ now = time(NULL);
+ strftime(tmpdir, sizeof(tmpdir),
+ "/tmp/libarchive_test.%Y-%m-%dT%H.%M.%S.XXXXXX",
+ localtime(&now));
+ if (mkdtemp(tmpdir) == NULL) {
+ fprintf(stderr, "ERROR: Unable to create temp directory %s\n",
+ tmpdir);
+ exit(1);
+ }
+
+ printf("Running libarchive tests in: %s\n", tmpdir);
+
+ for (i = 0; i < limit; i++) {
+ printf("%d: %s\n", i, tests[i].name);
+ if (chdir(tmpdir)) {
+ fprintf(stderr,
+ "ERROR: Couldn't chdir to temp dir %s\n",
+ tmpdir);
+ exit(1);
+ }
+ /* Create a temp directory for this specific test. */
+ if (mkdir(tests[i].name, 0755)) {
+ fprintf(stderr,
+ "ERROR: Couldn't create temp dir ``%s''\n",
+ tests[i].name);
+ exit(1);
+ }
+ if (chdir(tests[i].name)) {
+ fprintf(stderr,
+ "ERROR: Couldn't chdir to temp dir ``%s''\n",
+ tests[i].name);
+ exit(1);
+ }
+ (*tests[i].func)();
+ }
+ printf("%d tests succeeded.\n", limit);
+ return (0);
+}
diff --git a/lib/libarchive/test/test.h b/lib/libarchive/test/test.h
new file mode 100644
index 0000000..7849215
--- /dev/null
+++ b/lib/libarchive/test/test.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2003-2006 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 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$
+ */
+
+/* Every test program should #include "test.h" as the first thing. */
+
+/*
+ * The goal of this file (and the matching test.c) is to
+ * simplify the very repetitive test-*.c test programs.
+ */
+
+#include <archive.h>
+#include <archive_entry.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#if defined(HAVE_CONFIG_H)
+/* Most POSIX platforms use the 'configure' script to build config.h */
+#include "../../config.h"
+#elif defined(__FreeBSD__)
+/* Building as part of FreeBSD system requires a pre-built config.h. */
+#include "../config_freebsd.h"
+#elif defined(_WIN32)
+/* Win32 can't run the 'configure' script. */
+#include "../config_windows.h"
+#else
+/* Warn if the library hasn't been (automatically or manually) configured. */
+#error Oops: No config.h and no pre-built configuration in test.h.
+#endif
+
+
+/*
+ * "list.h" is simply created by "grep DEFINE_TEST"; it has
+ * a line like
+ * DEFINE_TEST(test_function)
+ * for each test.
+ * Include it here with a suitable DEFINE_TEST to declare all of the
+ * test functions.
+ */
+#define DEFINE_TEST(name) void name(void);
+#include "list.h"
+/*
+ * Redefine DEFINE_TEST for use in defining the test functions.
+ */
+#undef DEFINE_TEST
+#define DEFINE_TEST(name) void name(void)
+
+/* An implementation of the standard assert() macro */
+#define assert(e) test_assert(__FILE__, __LINE__, (e), #e, NULL)
+/* As above, but reports any archive_error found in variable 'a' */
+#define assertA(e) test_assert(__FILE__, __LINE__, (e), #e, (a))
+/* Asserts that two values are the same. Reports value of each one if not. */
+#define assertEqualIntA(a,v1,v2) \
+ test_assert_equal_int(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (a))
+/* Asserts that two values are the same. Reports value of each one if not. */
+#define assertEqualInt(v1,v2) \
+ test_assert_equal_int(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL)
+
+/* Function declarations. These are defined in test_utility.c. */
+void failure(const char *fmt, ...);
+void test_assert(const char *, int, int, const char *, struct archive *);
+void test_assert_equal_int(const char *, int, int, const char *, int, const char *, struct archive *);
+
diff --git a/lib/libarchive/test/test_archive_api_feature.c b/lib/libarchive/test/test_archive_api_feature.c
new file mode 100644
index 0000000..876cd9e
--- /dev/null
+++ b/lib/libarchive/test/test_archive_api_feature.c
@@ -0,0 +1,33 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+DEFINE_TEST(test_archive_api_feature)
+{
+ assert(ARCHIVE_API_FEATURE == archive_api_feature());
+ assert(ARCHIVE_API_VERSION == archive_api_version());
+ assert(0 == (strcmp(ARCHIVE_LIBRARY_VERSION, archive_version())));
+}
diff --git a/lib/libarchive/test/test_bad_fd.c b/lib/libarchive/test/test_bad_fd.c
new file mode 100644
index 0000000..dc83d18
--- /dev/null
+++ b/lib/libarchive/test/test_bad_fd.c
@@ -0,0 +1,41 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+/* Verify that attempting to open an invalid fd returns correct error. */
+DEFINE_TEST(test_bad_fd)
+{
+ struct archive *a;
+ assert((a = archive_read_new()) != NULL);
+ assertA(0 == archive_read_support_compression_all(a));
+ assertA(ARCHIVE_FATAL == archive_read_open_fd(a, -1, 1024));
+ assertA(0 == archive_read_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assert(0 == archive_read_finish(a));
+#else
+ archive_read_finish(a);
+#endif
+}
diff --git a/lib/libarchive/test/test_read_data_large.c b/lib/libarchive/test/test_read_data_large.c
new file mode 100644
index 0000000..7a97bb9
--- /dev/null
+++ b/lib/libarchive/test/test_read_data_large.c
@@ -0,0 +1,116 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+/*
+ * Test read/write of a 10M block of data in a single operation.
+ * Uses an in-memory archive with a single 10M entry. Exercises
+ * archive_read_data() to ensure it can handle large blocks like
+ * this and also exercises archive_read_data_into_fd() (which
+ * had a bug relating to this, fixed in Nov 2006).
+ */
+
+char buff1[11000000];
+char buff2[10000000];
+char buff3[10000000];
+
+DEFINE_TEST(test_read_data_large)
+{
+ struct archive_entry *ae;
+ struct archive *a;
+ char tmpfilename[] = "largefile";
+ int tmpfile;
+ int i;
+ size_t used;
+
+ /* Create a new archive in memory. */
+ assert((a = archive_write_new()) != NULL);
+ assertA(0 == archive_write_set_format_ustar(a));
+ assertA(0 == archive_write_set_compression_none(a));
+ assertA(0 == archive_write_open_memory(a, buff1, sizeof(buff1), &used));
+
+ /*
+ * Write a file (with random contents) to it.
+ */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "file");
+ archive_entry_set_mode(ae, S_IFREG | 0755);
+ for (i = 0; i < sizeof(buff2); i++)
+ buff2[i] = (unsigned char)rand();
+ archive_entry_set_size(ae, sizeof(buff2));
+ assertA(0 == archive_write_header(a, ae));
+ assertA(sizeof(buff2) == archive_write_data(a, buff2, sizeof(buff2)));
+
+ /* Close out the archive. */
+ assertA(0 == archive_write_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assertA(0 == archive_write_finish(a));
+#else
+ archive_write_finish(a);
+#endif
+
+ /* Check that archive_read_data can handle 10*10^6 at a pop. */
+ 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, buff1, sizeof(buff1)));
+ assertA(0 == archive_read_next_header(a, &ae));
+ failure("Wrote 10MB, but didn't read the same amount");
+ assertEqualIntA(a, sizeof(buff2),archive_read_data(a, buff3, sizeof(buff3)));
+ failure("Read expected 10MB, but data read didn't match what was written");
+ assert(0 == memcmp(buff2, buff3, sizeof(buff3)));
+ assert(0 == archive_read_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assert(0 == archive_read_finish(a));
+#else
+ archive_read_finish(a);
+#endif
+
+ /* Check archive_read_data_into_fd */
+ 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, buff1, sizeof(buff1)));
+ assertA(0 == archive_read_next_header(a, &ae));
+ tmpfile = open(tmpfilename, O_WRONLY | O_CREAT, 0777);
+ assert(tmpfile != 0);
+ assertEqualIntA(a, 0, archive_read_data_into_fd(a, tmpfile));
+ assert(0 == archive_read_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assert(0 == archive_read_finish(a));
+#else
+ archive_read_finish(a);
+#endif
+ close(tmpfile);
+
+ tmpfile = open(tmpfilename, O_RDONLY);
+ assert(tmpfile != 0);
+ assertEqualIntA(NULL, sizeof(buff3), read(tmpfile, buff3, sizeof(buff3)));
+ close(tmpfile);
+ assert(0 == memcmp(buff2, buff3, sizeof(buff3)));
+
+ unlink(tmpfilename);
+}
diff --git a/lib/libarchive/test/test_read_extract.c b/lib/libarchive/test/test_read_extract.c
new file mode 100644
index 0000000..37cabbc
--- /dev/null
+++ b/lib/libarchive/test/test_read_extract.c
@@ -0,0 +1,177 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+#define BUFF_SIZE 1000000
+#define FILE_BUFF_SIZE 100000
+
+DEFINE_TEST(test_read_extract)
+{
+ struct archive_entry *ae;
+ struct archive *a;
+ struct stat st;
+ ssize_t used;
+ int i;
+ char *buff, *file_buff;
+ int fd;
+ ssize_t bytes_read;
+
+ buff = malloc(BUFF_SIZE);
+ file_buff = malloc(FILE_BUFF_SIZE);
+
+ /* Force the umask to something predictable. */
+ umask(022);
+
+ /* Create a new archive in memory containing various types of entries. */
+ assert((a = archive_write_new()) != NULL);
+ assertA(0 == archive_write_set_format_ustar(a));
+ assertA(0 == archive_write_set_compression_none(a));
+ assertA(0 == archive_write_open_memory(a, buff, BUFF_SIZE, &used));
+ /* A directory to be restored with EXTRACT_PERM. */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "dir_0775");
+ archive_entry_set_mode(ae, S_IFDIR | 0775);
+ assertA(0 == archive_write_header(a, ae));
+ /* A regular file. */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "file");
+ archive_entry_set_mode(ae, S_IFREG | 0755);
+ for (i = 0; i < FILE_BUFF_SIZE; i++)
+ file_buff[i] = (unsigned char)rand();
+ archive_entry_set_size(ae, FILE_BUFF_SIZE);
+ assertA(0 == archive_write_header(a, ae));
+ assertA(FILE_BUFF_SIZE == archive_write_data(a, file_buff, FILE_BUFF_SIZE));
+ archive_entry_free(ae);
+ /* A directory that should obey umask when restored. */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "dir");
+ archive_entry_set_mode(ae, S_IFDIR | 0777);
+ assertA(0 == archive_write_header(a, ae));
+ /* A file in the directory. */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "dir/file");
+ archive_entry_set_mode(ae, S_IFREG | 0700);
+ assertA(0 == archive_write_header(a, ae));
+ /* A file in a dir that is not already in the archive. */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "dir2/file");
+ archive_entry_set_mode(ae, S_IFREG | 0000);
+ assertA(0 == archive_write_header(a, ae));
+ /* A dir with a trailing /. */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "dir3/.");
+ archive_entry_set_mode(ae, S_IFDIR | 0710);
+ assertA(0 == archive_write_header(a, ae));
+ /* Multiple dirs with a single entry. */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "dir4/a/../b/../c/");
+ archive_entry_set_mode(ae, S_IFDIR | 0711);
+ assertA(0 == archive_write_header(a, ae));
+ /* A symlink. */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "symlink");
+ archive_entry_set_mode(ae, S_IFLNK | 0755);
+ archive_entry_set_symlink(ae, "file");
+ assertA(0 == archive_write_header(a, ae));
+ /* Close out the archive. */
+ assertA(0 == archive_write_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assertA(0 == archive_write_finish(a));
+#else
+ archive_write_finish(a);
+#endif
+
+ /* Extract the entries to disk. */
+ 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, BUFF_SIZE));
+ /* Restore first entry with _EXTRACT_PERM. */
+ failure("Error reading first entry", i);
+ assertA(0 == archive_read_next_header(a, &ae));
+ assertA(0 == archive_read_extract(a, ae, ARCHIVE_EXTRACT_PERM));
+ /* Rest of entries get restored with no flags. */
+ for (i = 0; i < 7; i++) {
+ failure("Error reading entry %d", i+1);
+ assertA(0 == archive_read_next_header(a, &ae));
+ assertA(0 == archive_read_extract(a, ae, 0));
+ }
+ assertA(ARCHIVE_EOF == 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
+
+ /* Test the entries on disk. */
+ assert(0 == stat("dir_0775", &st));
+ failure("This was 0775 in archive, and should be 0775 on disk");
+ assert(st.st_mode == (S_IFDIR | 0775));
+ assert(0 == stat("file", &st));
+ failure("st.st_mode=%o should be %o", st.st_mode, S_IFREG | 0755);
+ assert(st.st_mode == (S_IFREG | 0755));
+ failure("The file extracted to disk is the wrong size.");
+ assert(st.st_size == FILE_BUFF_SIZE);
+ fd = open("file", O_RDONLY);
+ failure("The file on disk could not be opened.");
+ assert(fd != 0);
+ bytes_read = read(fd, buff, FILE_BUFF_SIZE);
+ failure("The file contents read from disk are the wrong size");
+ assert(bytes_read == FILE_BUFF_SIZE);
+ failure("The file contents on disk do not match the file contents that were put into the archive.");
+ assert(memcmp(buff, file_buff, FILE_BUFF_SIZE) == 0);
+ assert(0 == stat("dir", &st));
+ failure("This was 0777 in archive, but umask should make it 0755");
+ assert(st.st_mode == (S_IFDIR | 0755));
+ assert(0 == stat("dir/file", &st));
+ assert(st.st_mode == (S_IFREG | 0700));
+ assert(0 == stat("dir2", &st));
+ assert(st.st_mode == (S_IFDIR | 0755));
+ assert(0 == stat("dir2/file", &st));
+ assert(st.st_mode == (S_IFREG | 0000));
+ assert(0 == stat("dir3", &st));
+ assert(st.st_mode == (S_IFDIR | 0710));
+ assert(0 == stat("dir4", &st));
+ assert(st.st_mode == (S_IFDIR | 0755));
+ assert(0 == stat("dir4/a", &st));
+ assert(st.st_mode == (S_IFDIR | 0755));
+ assert(0 == stat("dir4/b", &st));
+ assert(st.st_mode == (S_IFDIR | 0755));
+ assert(0 == stat("dir4/c", &st));
+ assert(st.st_mode == (S_IFDIR | 0711));
+ assert(0 == lstat("symlink", &st));
+ assert(S_ISLNK(st.st_mode));
+#if HAVE_LCHMOD
+ /* Systems that lack lchmod() can't set symlink perms, so skip this. */
+ assert((st.st_mode & 07777) == 0755);
+#endif
+ assert(0 == stat("symlink", &st));
+ assert(st.st_mode == (S_IFREG | 0755));
+
+ free(buff);
+ free(file_buff);
+}
diff --git a/lib/libarchive/test/test_read_format_cpio_bin.c b/lib/libarchive/test/test_read_format_cpio_bin.c
new file mode 100644
index 0000000..dc840c4
--- /dev/null
+++ b/lib/libarchive/test/test_read_format_cpio_bin.c
@@ -0,0 +1,64 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+static unsigned char archive[] = {
+199,'q',21,4,177,'y',237,'A',232,3,232,3,2,0,0,0,'p','C',244,'M',2,0,0,0,
+0,0,'.',0,199,'q',0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,11,0,0,0,0,0,'T','R',
+'A','I','L','E','R','!','!','!',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+
+DEFINE_TEST(test_read_format_cpio_bin)
+{
+ 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)));
+ assertA(0 == archive_read_next_header(a, &ae));
+ assertA(archive_compression(a) == ARCHIVE_COMPRESSION_NONE);
+ assertA(archive_format(a) == ARCHIVE_FORMAT_CPIO_BIN_LE);
+ assert(0 == archive_read_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assert(0 == archive_read_finish(a));
+#else
+ archive_read_finish(a);
+#endif
+}
+
+
diff --git a/lib/libarchive/test/test_read_format_cpio_bin_Z.c b/lib/libarchive/test/test_read_format_cpio_bin_Z.c
new file mode 100644
index 0000000..a22c259
--- /dev/null
+++ b/lib/libarchive/test/test_read_format_cpio_bin_Z.c
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+static unsigned char archive[] = {
+31,157,144,199,226,'T',' ',16,'+','O',187,' ',232,6,'$',20,0,160,'!',156,
+'!',244,154,'0','l',216,208,5,128,128,20,'3','R',12,160,177,225,2,141,'T',
+164,4,'I',194,164,136,148,16,'(',';',170,'\\',201,178,165,203,151,'0','c',
+202,156,'I',179,166,205,155,'8','s',234,220,201,179,167,207,159,'@',127,2};
+
+DEFINE_TEST(test_read_format_cpio_bin_Z)
+{
+ 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)));
+ assertA(0 == archive_read_next_header(a, &ae));
+ assertA(archive_compression(a) == ARCHIVE_COMPRESSION_COMPRESS);
+ assertA(archive_format(a) == ARCHIVE_FORMAT_CPIO_BIN_LE);
+ assert(0 == archive_read_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assert(0 == archive_read_finish(a));
+#else
+ archive_read_finish(a);
+#endif
+}
+
+
diff --git a/lib/libarchive/test/test_read_format_cpio_bin_bz2.c b/lib/libarchive/test/test_read_format_cpio_bin_bz2.c
new file mode 100644
index 0000000..4aeb70a
--- /dev/null
+++ b/lib/libarchive/test/test_read_format_cpio_bin_bz2.c
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+static unsigned char archive[] = {
+'B','Z','h','9','1','A','Y','&','S','Y',134,'J',208,'4',0,0,30,246,141,253,
+8,2,0,' ',1,'*','&',20,0,'`',' ',' ',2,0,128,0,'B',4,8,' ',0,'T','P',0,'4',
+0,13,6,137,168,245,27,'Q',160,'a',25,169,5,'I',187,'(',10,'d','E',177,177,
+142,218,232,'r',130,'4','D',247,'<','Z',190,'U',237,236,'d',227,31,' ','z',
+192,'E','_',23,'r','E','8','P',144,134,'J',208,'4'};
+
+DEFINE_TEST(test_read_format_cpio_bin_bz2)
+{
+ struct archive_entry *ae;
+ struct archive *a;
+ assert((a = archive_read_new()) != NULL);
+ assert(0 == archive_read_support_compression_all(a));
+ assert(0 == archive_read_support_format_all(a));
+ assert(0 == archive_read_open_memory(a, archive, sizeof(archive)));
+ assert(0 == archive_read_next_header(a, &ae));
+ assert(archive_compression(a) == ARCHIVE_COMPRESSION_BZIP2);
+ assert(archive_format(a) == ARCHIVE_FORMAT_CPIO_BIN_LE);
+ assert(0 == archive_read_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assert(0 == archive_read_finish(a));
+#else
+ archive_read_finish(a);
+#endif
+}
+
+
diff --git a/lib/libarchive/test/test_read_format_cpio_bin_gz.c b/lib/libarchive/test/test_read_format_cpio_bin_gz.c
new file mode 100644
index 0000000..cefa0b3
--- /dev/null
+++ b/lib/libarchive/test/test_read_format_cpio_bin_gz.c
@@ -0,0 +1,53 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+static unsigned char archive[] = {
+31,139,8,0,244,'M','p','C',0,3,';','^','(',202,178,177,242,173,227,11,230,
+23,204,'L',12,12,12,5,206,'_','|','A','4',3,131,30,195,241,'B',6,'8','`',
+132,210,220,'`','2','$',200,209,211,199,'5','H','Q','Q',145,'a',20,12,'i',
+0,0,170,199,228,195,0,2,0,0};
+
+DEFINE_TEST(test_read_format_cpio_bin_gz)
+{
+ struct archive_entry *ae;
+ struct archive *a;
+ assert((a = archive_read_new()) != NULL);
+ assert(0 == archive_read_support_compression_all(a));
+ assert(0 == archive_read_support_format_all(a));
+ assert(0 == archive_read_open_memory(a, archive, sizeof(archive)));
+ assert(0 == archive_read_next_header(a, &ae));
+ assert(archive_compression(a) == ARCHIVE_COMPRESSION_GZIP);
+ assert(archive_format(a) == ARCHIVE_FORMAT_CPIO_BIN_LE);
+ assert(0 == archive_read_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assert(0 == archive_read_finish(a));
+#else
+ archive_read_finish(a);
+#endif
+}
+
+
diff --git a/lib/libarchive/test/test_read_format_cpio_odc.c b/lib/libarchive/test/test_read_format_cpio_odc.c
new file mode 100644
index 0000000..de4d8d5
--- /dev/null
+++ b/lib/libarchive/test/test_read_format_cpio_odc.c
@@ -0,0 +1,68 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+static unsigned char archive[] = {
+'0','7','0','7','0','7','0','0','2','0','2','5','0','7','4','6','6','1','0',
+'4','0','7','5','5','0','0','1','7','5','0','0','0','1','7','5','0','0','0',
+'0','0','0','2','0','0','0','0','0','0','1','0','3','3','4','0','5','0','0',
+'5','3','0','0','0','0','0','2','0','0','0','0','0','0','0','0','0','0','0',
+'.',0,'0','7','0','7','0','7','0','0','0','0','0','0','0','0','0','0','0',
+'0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0',
+'0','0','0','0','0','1','0','0','0','0','0','0','0','0','0','0','0','0','0',
+'0','0','0','0','0','0','0','0','1','3','0','0','0','0','0','0','0','0','0',
+'0','0','T','R','A','I','L','E','R','!','!','!',0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0};
+
+DEFINE_TEST(test_read_format_cpio_odc)
+{
+ 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)));
+ assertA(0 == archive_read_next_header(a, &ae));
+ assertA(archive_compression(a) == ARCHIVE_COMPRESSION_NONE);
+ assertA(archive_format(a) == ARCHIVE_FORMAT_CPIO_POSIX);
+ assert(0 == archive_read_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assert(0 == archive_read_finish(a));
+#else
+ archive_read_finish(a);
+#endif
+}
+
+
diff --git a/lib/libarchive/test/test_read_format_cpio_svr4_gzip.c b/lib/libarchive/test/test_read_format_cpio_svr4_gzip.c
new file mode 100644
index 0000000..e46f0f8
--- /dev/null
+++ b/lib/libarchive/test/test_read_format_cpio_svr4_gzip.c
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+static unsigned char archive[] = {
+31,139,8,0,236,'c',217,'D',0,3,'3','0','7','0','7','0','4','0','0',181,'0',
+183,'L',2,210,6,6,'&',134,169,')',' ',218,192,'8',213,2,133,'6','0','0','2',
+'1','6','7','0','5','0','N','6','@',5,'&',16,202,208,212,0,';','0',130,'1',
+244,24,12,160,246,17,5,136,'U',135,14,146,'`',140,144,' ','G','O',31,215,
+' ','E','E','E',134,'Q',128,21,0,0,'%',215,202,221,0,2,0,0};
+
+DEFINE_TEST(test_read_format_cpio_svr4_gzip)
+{
+ struct archive_entry *ae;
+ struct archive *a;
+ assert((a = archive_read_new()) != NULL);
+ assert(0 == archive_read_support_compression_all(a));
+ assert(0 == archive_read_support_format_all(a));
+ assert(0 == archive_read_open_memory(a, archive, sizeof(archive)));
+ assert(0 == archive_read_next_header(a, &ae));
+ assert(archive_compression(a) == ARCHIVE_COMPRESSION_GZIP);
+ assert(archive_format(a) == ARCHIVE_FORMAT_CPIO_SVR4_NOCRC);
+ assert(0 == archive_read_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assert(0 == archive_read_finish(a));
+#else
+ archive_read_finish(a);
+#endif
+}
+
+
diff --git a/lib/libarchive/test/test_read_format_cpio_svr4c_Z.c b/lib/libarchive/test/test_read_format_cpio_svr4c_Z.c
new file mode 100644
index 0000000..bc89c8f
--- /dev/null
+++ b/lib/libarchive/test/test_read_format_cpio_svr4c_Z.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+static unsigned char archive[] = {
+31,157,144,'0','n',4,132,'!',3,6,140,26,'8','n',228,16,19,195,160,'A',26,
+'1',202,144,'q','h','p','F',25,28,20,'a','X',196,152,145,' ',141,25,2,'k',
+192,160,'A',163,163,201,135,29,'c',136,'<',201,'2','c','A',147,'.',0,12,20,
+248,178,165,205,155,20,27,226,220,201,243,166,152,147,'T',164,4,'I',194,164,
+136,148,16,'H',1,'(',']',202,180,169,211,167,'P',163,'J',157,'J',181,170,
+213,171,'X',179,'j',221,202,181,171,215,175,'L',1};
+
+DEFINE_TEST(test_read_format_cpio_svr4c_Z)
+{
+ struct archive_entry *ae;
+ struct archive *a;
+/* printf("Archive address: start=%X, end=%X\n", archive, archive+sizeof(archive)); */
+ 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)));
+ assertA(0 == archive_read_next_header(a, &ae));
+ assertA(archive_compression(a) == ARCHIVE_COMPRESSION_COMPRESS);
+ assertA(archive_format(a) == ARCHIVE_FORMAT_CPIO_SVR4_CRC);
+ assert(0 == archive_read_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assert(0 == archive_read_finish(a));
+#else
+ archive_read_finish(a);
+#endif
+}
+
+
diff --git a/lib/libarchive/test/test_read_format_empty.c b/lib/libarchive/test/test_read_format_empty.c
new file mode 100644
index 0000000..761b2a9
--- /dev/null
+++ b/lib/libarchive/test/test_read_format_empty.c
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+static unsigned char archive[] = { };
+
+DEFINE_TEST(test_read_format_empty)
+{
+ 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)));
+ assertA(ARCHIVE_EOF == archive_read_next_header(a, &ae));
+ assertA(archive_compression(a) == ARCHIVE_COMPRESSION_NONE);
+ assertA(archive_format(a) == ARCHIVE_FORMAT_EMPTY);
+ assert(0 == archive_read_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assert(0 == archive_read_finish(a));
+#else
+ archive_read_finish(a);
+#endif
+}
+
+
diff --git a/lib/libarchive/test/test_read_format_gtar_gz.c b/lib/libarchive/test/test_read_format_gtar_gz.c
new file mode 100644
index 0000000..5ea549a
--- /dev/null
+++ b/lib/libarchive/test/test_read_format_gtar_gz.c
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+static unsigned char archive[] = {
+31,139,8,0,'+','e',217,'D',0,3,211,211,'g',160,'9','0',0,2,'s','S','S',16,
+'m','h','n','j',128,'L',195,0,131,161,129,177,177,137,129,137,185,185,161,
+'!',131,129,161,129,153,161,'9',131,130,')',237,157,198,192,'P','Z','\\',
+146,'X',164,160,192,'P',146,153,139,'W',29,'!','y',152,'G','`',244,'(',24,
+5,163,'`',20,12,'r',0,0,226,234,'6',162,0,6,0,0};
+
+DEFINE_TEST(test_read_format_gtar_gz)
+{
+ struct archive_entry *ae;
+ struct archive *a;
+ assert((a = archive_read_new()) != NULL);
+ assert(0 == archive_read_support_compression_all(a));
+ assert(0 == archive_read_support_format_all(a));
+ assert(0 == archive_read_open_memory(a, archive, sizeof(archive)));
+ assert(0 == archive_read_next_header(a, &ae));
+ assert(archive_compression(a) == ARCHIVE_COMPRESSION_GZIP);
+ assert(archive_format(a) == ARCHIVE_FORMAT_TAR_GNUTAR);
+ assert(0 == archive_read_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assert(0 == archive_read_finish(a));
+#else
+ archive_read_finish(a);
+#endif
+}
+
+
diff --git a/lib/libarchive/test/test_read_format_iso_gz.c b/lib/libarchive/test/test_read_format_iso_gz.c
new file mode 100644
index 0000000..fd8f60e
--- /dev/null
+++ b/lib/libarchive/test/test_read_format_iso_gz.c
@@ -0,0 +1,73 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+static unsigned char archive[] = {
+31,139,8,8,201,'R','p','C',0,3,'t','e','s','t','-','r','e','a','d','_','f',
+'o','r','m','a','t','.','i','s','o',0,237,219,223,'k',211,'@',28,0,240,212,
+23,'K','}',20,169,143,135,15,162,224,218,180,']','W',186,183,173,'I',183,
+206,254,144,'d',19,246,'$',5,';',24,'2',11,235,240,239,221,127,162,233,'f',
+17,29,219,24,12,'\'',243,243,'!',185,187,220,']',146,';',8,9,223,131,'D',
+17,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'P',234,
+'%','q',220,'(','E',253,211,217,'l',';','O',194,'u','z','I','6',25,']',219,
+26,194,234,'z',241,'o',217,13,247,'-',182,229,30,149,203,'Q',229,178,170,
+242,252,'W',243,139,'e',242,'*',170,'^',30,'U',163,242,'2','+','G',199,207,
+158,'V','_',190,';',127,178,':',255,134,1,241,23,140,222,15,242,'I','?',15,
+'E',26,186,27,27,'q','}',183,'8',232,15,134,'i','~',152,239,167,163,176,'}',
+'0',24,'&','i',22,'^','/',159,159,180,'7',201,146,162,176,150,213,147,143,
+'E','!','K',183,246,'\'','Y','x',211,'{',27,26,221,'n','+',164,181,195,201,
+193,'x','\'',217,26,166,171,202,'N',216,171,'}','H',183,178,'|','2',174,239,
+213,242,222,238,'`','8',28,140,'w',30,'j',186,205,'8','n','7',26,'q',167,
+217,'j',174,183,';','q','|','~',165,'"',254,'C','t',165,'G',')','z',168,209,
+243,'o',184,143,215,'6',220,139,239,'?',191,255,0,192,255,163,136,224,194,
+'h',254,'5',140,231,223,'B',232,132,'f','k',179,185,190,217,238,'\\',132,
+':',149,147,'/',199,139,249,209,'"','4','k','q',173,21,214,230,225,'l',182,
+'8','[',';',157,'M','?',127,':',154,159,158,'L',207,'j','E','{',152,'>',244,
+28,0,128,187,')',']',172,177,139,255,1,0,0,224,'1',187,136,252,171,22,0,0,
+0,0,224,'1',187,253,31,187,'[','{','X',';',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,224,206,
+'~',0,137,'#',195,182,0,128,1,0};
+
+DEFINE_TEST(test_read_format_iso_gz)
+{
+ struct archive_entry *ae;
+ struct archive *a;
+ assert((a = archive_read_new()) != NULL);
+ assert(0 == archive_read_support_compression_all(a));
+ assert(0 == archive_read_support_format_all(a));
+ assert(0 == archive_read_open_memory(a, archive, sizeof(archive)));
+ assert(0 == archive_read_next_header(a, &ae));
+ assert(archive_compression(a) == ARCHIVE_COMPRESSION_GZIP);
+ assert(archive_format(a) == ARCHIVE_FORMAT_ISO9660);
+ assert(0 == archive_read_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assert(0 == archive_read_finish(a));
+#else
+ archive_read_finish(a);
+#endif
+}
+
+
diff --git a/lib/libarchive/test/test_read_format_isorr_bz2.c b/lib/libarchive/test/test_read_format_isorr_bz2.c
new file mode 100644
index 0000000..3a7c56d
--- /dev/null
+++ b/lib/libarchive/test/test_read_format_isorr_bz2.c
@@ -0,0 +1,180 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+/*
+Execute the following to rebuild the data for this program:
+ tail -n +5 test-read_format-isorr_bz2.c | /bin/sh
+
+rm -rf /tmp/iso
+mkdir /tmp/iso
+mkdir /tmp/iso/dir
+echo "hello" >/tmp/iso/file
+ln /tmp/iso/file /tmp/iso/hardlink
+(cd /tmp/iso; ln -s file symlink)
+TZ=utc touch -afhm -t 197001010000.01 /tmp/iso /tmp/iso/file /tmp/iso/dir
+TZ=utc touch -afhm -t 196912312359.58 /tmp/iso/symlink
+mkhybrid -R -uid 1 -gid 2 /tmp/iso | bzip2 > data.iso.bz2
+cat data.iso.bz2 | ./maketest.pl > data.c
+exit 1
+ */
+
+static unsigned char archive[] = {
+'B','Z','h','9','1','A','Y','&','S','Y','G',11,4,'c',0,0,199,255,221,255,
+255,203,252,221,'c',251,248,'?',255,223,224,167,255,222,'&','!',234,'$',0,
+'0',1,' ',0,'D',2,129,8,192,3,14,'2','3','$',19,184,'J',' ','F',168,244,201,
+149,'6','Q',226,155,'S',212,209,160,'h','4','i',160,26,13,0,244,134,212,0,
+218,'O',212,153,1,144,244,128,148,' ',147,13,' ',213,'=','1','\'',169,166,
+128,'=','!',233,0,208,0,26,0,0,30,160,'h',0,'4','z',130,180,163,'@',0,0,4,
+211,0,0,0,2,'b','`',0,0,0,0,0,8,146,133,'F',154,'y','A',163,'A',161,163,'@',
+'z',134,'C','C','F',131,'F','@',0,0,0,0,6,154,26,'Q',24,234,180,'P',172,251,
+'=',2,'P','H','&','Y','o',130,28,'"',229,210,247,227,248,200,'?','6',161,
+'?',170,'H',172,'"','H','I',16,'2','"','&',148,'G',133,'T','z',224,1,215,
+' ',0,191,184,10,160,24,248,180,183,244,156,'K',202,133,208,'U',5,'6','C',
+26,144,'H',168,'H','H','(','"',151,'@','m',223,'(','P',169,'e',145,148,'6',
+237,235,7,227,204,']','k','{',241,187,227,244,251,':','a','L',138,'#','R',
+'"',221,'_',239,')',140,'*','*',172,'Q',16,1,16,207,166,251,233,'Z',169,'4',
+'_',195,'a',14,18,231,'}',14,139,137,'e',213,185,'T',194,'D','`',25,'$',187,
+208,'%','c',162,'~',181,'@',204,'2',238,'P',161,213,127,'I',169,3,' ','o',
+6,161,16,128,'F',214,'S','m',6,244,11,229,'Z','y','.',176,'q',' ',248,167,
+204,26,193,'q',211,241,214,133,221,212,'I','`',28,244,'N','N','f','H','9',
+'w',245,209,'*',20,26,208,'h','(',194,156,192,'l',';',192,'X','T',151,177,
+209,'0',156,16,'=',20,'k',184,144,'z',26,'j',133,194,'9',227,'<','[','^',
+17,'w','p',225,220,248,'>',205,'>','[',19,'5',155,17,175,28,28,168,175,'n',
+'\'','c','w',27,222,204,'k','n','x','I',23,237,'c',145,11,184,'A','(',1,169,
+'0',180,189,134,'\\','Y','x',187,'C',151,'d','k','y','-','L',218,138,'s',
+'*','(',12,'h',242,'*',17,'E','L',202,146,138,'l','0',217,160,'9','.','S',
+214,198,143,'3','&',237,'=','t','P',168,214,210,'`','p','J',181,'H',138,149,
+'1','B',206,22,164,'[','O','A',172,134,224,179,219,166,184,'X',185,'W',154,
+219,19,161,'Y',184,220,237,147,'9',191,237,'&','i','_',226,146,205,160,'@',
+'b',182,';',3,'!',183,'J','t',161,160,178,173,'S',235,':','2',159,':',245,
+'{','U',174,'P',142,'G','(',')',9,168,185,'A','U',231,193,'g',213,'e',12,
+'X',223,22,249,')',152,237,'G',150,156,3,201,245,212,'2',218,209,177,196,
+235,'_','~',137,24,31,196,232,'B',172,'w',159,24,'n',156,150,225,'1','y',
+22,'#',138,193,227,232,169,170,166,179,1,11,182,'i',')',160,180,198,175,128,
+249,167,5,194,142,183,'f',134,206,180,'&','E','!','[',31,195,':',192,'s',
+232,187,'N',131,'Y',137,243,15,'y',12,'J',163,'-',242,'5',197,151,130,163,
+240,220,'T',161,'L',159,141,159,152,'4',18,128,'.','^',250,168,200,163,'P',
+231,'Y','w','F','U',186,'x',190,16,'0',228,22,'9','F','t',168,157,'i',190,
+'+',246,141,142,18,' ','M',174,197,'O',165,'m',224,27,'b',150,'|','W','H',
+196,'.','*','Q','$',225,'I','-',148,169,'F',7,197,'m','-',130,153,0,158,21,
+'(',221,221,226,206,'g',13,159,163,'y',176,'~',158,'k','4','q','d','s',177,
+'7',14,217,'1',173,206,228,'t',250,200,170,162,'d','2','Z','$','e',168,224,
+223,129,174,229,165,187,252,203,'-',28,'`',207,183,'-','/',127,196,230,131,
+'B',30,237,' ',8,26,194,'O',132,'L','K','\\',144,'L','c',1,10,176,192,'c',
+0,244,2,168,3,0,'+',233,186,16,17,'P',17,129,252,'2',0,2,154,247,255,166,
+'.',228,138,'p',161,' ',142,22,8,198};
+
+DEFINE_TEST(test_read_format_isorr_bz2)
+{
+ struct archive_entry *ae;
+ struct archive *a;
+ const void *p;
+ size_t size;
+ off_t offset;
+ assert((a = archive_read_new()) != NULL);
+ assert(0 == archive_read_support_compression_all(a));
+ assert(0 == archive_read_support_format_all(a));
+ assert(0 == archive_read_open_memory(a, archive, sizeof(archive)));
+
+ /* First entry is '.' root directory. */
+ assert(0 == archive_read_next_header(a, &ae));
+ assert(0 == strcmp(".", archive_entry_pathname(ae)));
+ assert(S_ISDIR(archive_entry_stat(ae)->st_mode));
+ assert(2048 == archive_entry_size(ae));
+ assert(1 == archive_entry_mtime(ae));
+ assert(0 == archive_entry_mtime_nsec(ae));
+ assert(1 == archive_entry_ctime(ae));
+ assert(0 == archive_entry_stat(ae)->st_nlink);
+ assert(0 == archive_entry_uid(ae));
+
+ /* A directory. */
+ assert(0 == archive_read_next_header(a, &ae));
+ assert(0 == strcmp("dir", archive_entry_pathname(ae)));
+ assert(S_ISDIR(archive_entry_stat(ae)->st_mode));
+ assert(2048 == archive_entry_size(ae));
+ assert(1 == archive_entry_mtime(ae));
+ assert(1 == archive_entry_atime(ae));
+ assert(2 == archive_entry_stat(ae)->st_nlink);
+ assert(1 == archive_entry_uid(ae));
+ assert(2 == archive_entry_gid(ae));
+
+ /* A regular file. */
+ assert(0 == archive_read_next_header(a, &ae));
+ assert(0 == strcmp("file", archive_entry_pathname(ae)));
+ assert(S_ISREG(archive_entry_stat(ae)->st_mode));
+ assert(6 == archive_entry_size(ae));
+ assert(0 == archive_read_data_block(a, &p, &size, &offset));
+ assert(6 == size);
+ assert(0 == offset);
+ assert(0 == memcmp(p, "hello\n", 6));
+ assert(1 == archive_entry_mtime(ae));
+ assert(1 == archive_entry_atime(ae));
+ assert(2 == archive_entry_stat(ae)->st_nlink);
+ assert(1 == archive_entry_uid(ae));
+ assert(2 == archive_entry_gid(ae));
+
+ /* A hardlink to the regular file. */
+ assert(0 == archive_read_next_header(a, &ae));
+ assert(0 == strcmp("hardlink", archive_entry_pathname(ae)));
+ assert(S_ISREG(archive_entry_stat(ae)->st_mode));
+ assert(0 == strcmp("file", archive_entry_hardlink(ae)));
+ assert(6 == archive_entry_size(ae));
+ assert(1 == archive_entry_mtime(ae));
+ assert(1 == archive_entry_atime(ae));
+ assert(2 == archive_entry_stat(ae)->st_nlink);
+ assert(1 == archive_entry_uid(ae));
+ assert(2 == archive_entry_gid(ae));
+
+ /* A symlink to the regular file. */
+ assert(0 == archive_read_next_header(a, &ae));
+ assert(0 == strcmp("symlink", archive_entry_pathname(ae)));
+ assert(S_ISLNK(archive_entry_stat(ae)->st_mode));
+ assert(0 == strcmp("file", archive_entry_symlink(ae)));
+ assert(0 == archive_entry_size(ae));
+ assert(-2 == archive_entry_mtime(ae));
+ assert(-2 == archive_entry_atime(ae));
+ assert(1 == archive_entry_stat(ae)->st_nlink);
+ assert(1 == archive_entry_uid(ae));
+ assert(2 == archive_entry_gid(ae));
+
+ /* End of archive. */
+ assert(ARCHIVE_EOF == archive_read_next_header(a, &ae));
+
+ /* Verify archive format. */
+ assert(archive_compression(a) == ARCHIVE_COMPRESSION_BZIP2);
+ assert(archive_format(a) == ARCHIVE_FORMAT_ISO9660_ROCKRIDGE);
+
+ /* Close the archive. */
+ assert(0 == archive_read_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assert(0 == archive_read_finish(a));
+#else
+ archive_read_finish(a);
+#endif
+}
+
+
diff --git a/lib/libarchive/test/test_read_format_pax_bz2.c b/lib/libarchive/test/test_read_format_pax_bz2.c
new file mode 100644
index 0000000..039bd53
--- /dev/null
+++ b/lib/libarchive/test/test_read_format_pax_bz2.c
@@ -0,0 +1,62 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+static unsigned char archive[] = {
+'B','Z','h','9','1','A','Y','&','S','Y',152,180,30,185,0,0,140,127,176,212,
+144,0,' ','@',1,255,226,8,'d','H',' ',238,'/',159,'@',0,16,4,'@',0,8,'0',
+0,216,'A',164,167,147,'Q',147,'!',180,'#',0,'L',153,162,'i',181,'?','P',192,
+26,'h','h',209,136,200,6,128,13,12,18,132,202,'5','O',209,'5','=',26,'2',
+154,7,168,12,2,'d',252,13,254,29,'4',247,181,'l','T','i',130,5,195,1,'2',
+'@',146,18,251,245,'c','J',130,224,172,'$','l','4',235,170,186,'c','1',255,
+179,'K',188,136,18,208,152,192,149,153,10,'{','|','0','8',166,3,6,9,128,172,
+'(',164,220,244,149,6,' ',243,212,'B',25,17,'6',237,13,'I',152,'L',129,209,
+'G','J','<',137,'Y',16,'b',21,18,'a','Y','l','t','r',160,128,147,'l','f',
+'~',219,206,'=','?','S',233,'3',251,'L','~',17,176,169,'%',23,'_',225,'M',
+'C','u','k',218,8,'q',216,'(',22,235,'K',131,136,146,136,147,202,0,158,134,
+'F',23,160,184,'s','0','a',246,'*','P',7,2,238,'H',167,10,18,19,22,131,215,
+' '};
+
+DEFINE_TEST(test_read_format_pax_bz2)
+{
+ struct archive_entry *ae;
+ struct archive *a;
+ assert((a = archive_read_new()) != NULL);
+ assert(0 == archive_read_support_compression_all(a));
+ assert(0 == archive_read_support_format_all(a));
+ assert(0 == archive_read_open_memory(a, archive, sizeof(archive)));
+ assert(0 == archive_read_next_header(a, &ae));
+ assert(archive_compression(a) == ARCHIVE_COMPRESSION_BZIP2);
+ assert(archive_format(a) == ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE);
+ assert(0 == archive_read_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assert(0 == archive_read_finish(a));
+#else
+ archive_read_finish(a);
+#endif
+}
+
+
diff --git a/lib/libarchive/test/test_read_format_tar.c b/lib/libarchive/test/test_read_format_tar.c
new file mode 100644
index 0000000..1515527
--- /dev/null
+++ b/lib/libarchive/test/test_read_format_tar.c
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+static unsigned char archive[] = {
+'.',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'0','0','0','7','5',
+'5',' ',0,'0','0','1','7','5','0',' ',0,'0','0','1','7','5','0',' ',0,'0',
+'0','0','0','0','0','0','0','0','0','0',' ','1','0','3','3','4','0','4','1',
+'7','3','6',' ','0','1','0','5','6','1',0,' ','5',0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,'u','s','t','a','r',0,'0','0','t','i','m',0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'t','i','m',0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,'0','0','0','0','0','0',
+' ',0,'0','0','0','0','0','0',' ',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
+
+DEFINE_TEST(test_read_format_tar)
+{
+ 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)));
+ assertA(0 == archive_read_next_header(a, &ae));
+ assertA(archive_compression(a) == ARCHIVE_COMPRESSION_NONE);
+ assertA(archive_format(a) == ARCHIVE_FORMAT_TAR_USTAR);
+ assert(0 == archive_read_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assert(0 == archive_read_finish(a));
+#else
+ archive_read_finish(a);
+#endif
+}
+
+
diff --git a/lib/libarchive/test/test_read_format_tbz.c b/lib/libarchive/test/test_read_format_tbz.c
new file mode 100644
index 0000000..17f24ea
--- /dev/null
+++ b/lib/libarchive/test/test_read_format_tbz.c
@@ -0,0 +1,55 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+static unsigned char archive[] = {
+'B','Z','h','9','1','A','Y','&','S','Y',237,7,140,'W',0,0,27,251,144,208,
+128,0,' ','@',1,'o',128,0,0,224,'"',30,0,0,'@',0,8,' ',0,'T','2',26,163,'&',
+129,160,211,212,18,'I',169,234,13,168,26,6,150,'1',155,134,'p',8,173,3,183,
+'J','S',26,20,'2',222,'b',240,160,'a','>',205,'f',29,170,227,'[',179,139,
+'\'','L','o',211,':',178,'0',162,134,'*','>','8',24,153,230,147,'R','?',23,
+'r','E','8','P',144,237,7,140,'W'};
+
+DEFINE_TEST(test_read_format_tbz)
+{
+ struct archive_entry *ae;
+ struct archive *a;
+ assert((a = archive_read_new()) != NULL);
+ assert(0 == archive_read_support_compression_all(a));
+ assert(0 == archive_read_support_format_all(a));
+ assert(0 == archive_read_open_memory(a, archive, sizeof(archive)));
+ assert(0 == archive_read_next_header(a, &ae));
+ assert(archive_compression(a) == ARCHIVE_COMPRESSION_BZIP2);
+ assert(archive_format(a) == ARCHIVE_FORMAT_TAR_USTAR);
+ assert(0 == archive_read_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assert(0 == archive_read_finish(a));
+#else
+ archive_read_finish(a);
+#endif
+}
+
+
diff --git a/lib/libarchive/test/test_read_format_tgz.c b/lib/libarchive/test/test_read_format_tgz.c
new file mode 100644
index 0000000..4235358
--- /dev/null
+++ b/lib/libarchive/test/test_read_format_tgz.c
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+static unsigned char archive[] = {
+31,139,8,0,222,'C','p','C',0,3,211,'c',160,'=','0','0','0','0','7','5','U',
+0,210,134,230,166,6,200,'4',28,'(',24,26,24,27,155,24,152,24,154,27,155,')',
+24,24,26,152,154,25,'2','(',152,210,193,'m',12,165,197,'%',137,'E','@',167,
+148,'d',230,226,'U','G','H',30,234,15,'8','=',10,'F',193,'(',24,5,131,28,
+0,0,29,172,5,240,0,6,0,0};
+
+DEFINE_TEST(test_read_format_tgz)
+{
+ struct archive_entry *ae;
+ struct archive *a;
+ assert((a = archive_read_new()) != NULL);
+ assert(0 == archive_read_support_compression_all(a));
+ assert(0 == archive_read_support_format_all(a));
+ assert(0 == archive_read_open_memory(a, archive, sizeof(archive)));
+ assert(0 == archive_read_next_header(a, &ae));
+ assert(archive_compression(a) == ARCHIVE_COMPRESSION_GZIP);
+ assert(archive_format(a) == ARCHIVE_FORMAT_TAR_USTAR);
+ assert(0 == archive_read_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assert(0 == archive_read_finish(a));
+#else
+ archive_read_finish(a);
+#endif
+}
+
+
diff --git a/lib/libarchive/test/test_read_format_tz.c b/lib/libarchive/test/test_read_format_tz.c
new file mode 100644
index 0000000..d7a91e2
--- /dev/null
+++ b/lib/libarchive/test/test_read_format_tz.c
@@ -0,0 +1,56 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+static unsigned char archive[] = {
+31,157,144,'.',0,8,28,'H',176,160,193,131,8,19,'*','\\',200,176,'!','B',24,
+16,'o',212,168,1,2,0,196,24,18,'a','T',188,152,'q','#',196,143,' ','5',198,
+128,'1','c',6,13,24,'4','0',206,176,1,2,198,200,26,'6','b',0,0,'Q',195,161,
+205,155,'8','s',234,4,'P','g',14,157,'0','r',',',194,160,147,166,205,206,
+132,'D',141,30,'=',24,'R',163,'P',144,21,151,'J',157,'J',181,170,213,171,
+'X',179,'j',221,202,181,171,215,175,'`',195,138,29,'K',182,172,217,179,'h',
+211,170,']',203,182,173,219,183,'g',1};
+
+DEFINE_TEST(test_read_format_tz)
+{
+ 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)));
+ assertA(0 == archive_read_next_header(a, &ae));
+ assertA(archive_compression(a) == ARCHIVE_COMPRESSION_COMPRESS);
+ assertA(archive_format(a) == ARCHIVE_FORMAT_TAR_USTAR);
+ assert(0 == archive_read_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assert(0 == archive_read_finish(a));
+#else
+ archive_read_finish(a);
+#endif
+}
+
+
diff --git a/lib/libarchive/test/test_read_format_zip.c b/lib/libarchive/test/test_read_format_zip.c
new file mode 100644
index 0000000..98b4ff1
--- /dev/null
+++ b/lib/libarchive/test/test_read_format_zip.c
@@ -0,0 +1,54 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+static unsigned char archive[] = {
+'P','K',3,4,10,0,0,0,0,0,162,186,'g','3',0,0,0,0,0,0,0,0,0,0,0,0,1,0,21,0,
+'a','U','T',9,0,3,224,'Q','p','C',224,'Q','p','C','U','x',4,0,232,3,232,3,
+'P','K',1,2,23,3,10,0,0,0,0,0,162,186,'g','3',0,0,0,0,0,0,0,0,0,0,0,0,1,0,
+13,0,0,0,0,0,0,0,0,0,164,129,0,0,0,0,'a','U','T',5,0,3,224,'Q','p','C','U',
+'x',0,0,'P','K',5,6,0,0,0,0,1,0,1,0,'<',0,0,0,'4',0,0,0,0,0};
+
+DEFINE_TEST(test_read_format_zip)
+{
+ 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)));
+ assertA(0 == archive_read_next_header(a, &ae));
+ assertA(archive_compression(a) == ARCHIVE_COMPRESSION_NONE);
+ assertA(archive_format(a) == ARCHIVE_FORMAT_ZIP);
+ assert(0 == archive_read_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assert(0 == archive_read_finish(a));
+#else
+ archive_read_finish(a);
+#endif
+}
+
+
diff --git a/lib/libarchive/test/test_read_large.c b/lib/libarchive/test/test_read_large.c
new file mode 100644
index 0000000..8c32c3d
--- /dev/null
+++ b/lib/libarchive/test/test_read_large.c
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+static unsigned char testdata[10 * 1024 * 1024];
+static unsigned char testdatacopy[10 * 1024 * 1024];
+static unsigned char buff[11 * 1024 * 1024];
+
+/* Check correct behavior on large reads. */
+DEFINE_TEST(test_read_large)
+{
+ int i;
+ int tmpfile;
+ char tmpfilename[] = "/tmp/test-read_large.XXXXXX";
+ size_t used;
+ struct archive *a;
+ struct archive_entry *entry;
+
+ for (i = 0; i < sizeof(testdata); i++)
+ testdata[i] = (unsigned char)(rand());
+
+ assert(NULL != (a = archive_write_new()));
+ assertA(0 == archive_write_set_format_ustar(a));
+ assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &used));
+ assert(NULL != (entry = archive_entry_new()));
+ archive_entry_set_size(entry, sizeof(testdata));
+ archive_entry_set_mode(entry, S_IFREG | 0777);
+ archive_entry_set_pathname(entry, "test");
+ assertA(0 == archive_write_header(a, entry));
+ assertA(sizeof(testdata) == archive_write_data(a, testdata, sizeof(testdata)));
+#if ARCHIVE_API_VERSION > 1
+ assertA(0 == archive_write_finish(a));
+#else
+ archive_write_finish(a);
+#endif
+
+ assert(NULL != (a = archive_read_new()));
+ assertA(0 == archive_read_support_format_all(a));
+ assertA(0 == archive_read_support_compression_all(a));
+ assertA(0 == archive_read_open_memory(a, buff, sizeof(buff)));
+ assertA(0 == archive_read_next_header(a, &entry));
+ assertA(0 == archive_read_data_into_buffer(a, testdatacopy, sizeof(testdatacopy)));
+#if ARCHIVE_API_VERSION > 1
+ assertA(0 == archive_read_finish(a));
+#else
+ archive_read_finish(a);
+#endif
+ assert(0 == memcmp(testdata, testdatacopy, sizeof(testdata)));
+
+
+ assert(NULL != (a = archive_read_new()));
+ assertA(0 == archive_read_support_format_all(a));
+ assertA(0 == archive_read_support_compression_all(a));
+ assertA(0 == archive_read_open_memory(a, buff, sizeof(buff)));
+ assertA(0 == archive_read_next_header(a, &entry));
+ assert(0 < (tmpfile = mkstemp(tmpfilename)));
+ assertA(0 == archive_read_data_into_fd(a, tmpfile));
+ close(tmpfile);
+#if ARCHIVE_API_VERSION > 1
+ assertA(0 == archive_read_finish(a));
+#else
+ archive_read_finish(a);
+#endif
+ tmpfile = open(tmpfilename, O_RDONLY);
+ read(tmpfile, testdatacopy, sizeof(testdatacopy));
+ close(tmpfile);
+ assert(0 == memcmp(testdata, testdatacopy, sizeof(testdata)));
+
+ unlink(tmpfilename);
+}
diff --git a/lib/libarchive/test/test_read_position.c b/lib/libarchive/test/test_read_position.c
new file mode 100644
index 0000000..3b1f110
--- /dev/null
+++ b/lib/libarchive/test/test_read_position.c
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+static unsigned char nulls[10000000];
+static unsigned char buff[10000000];
+
+/* Check that header_position tracks correctly on read. */
+DEFINE_TEST(test_read_position)
+{
+ struct archive *a;
+ struct archive_entry *ae;
+ size_t write_pos;
+ const size_t data_size = 1000000;
+
+ /* Create a simple archive_entry. */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_set_pathname(ae, "testfile");
+ archive_entry_set_mode(ae, S_IFREG);
+ archive_entry_set_size(ae, data_size);
+
+ assert(NULL != (a = archive_write_new()));
+ assertA(0 == archive_write_set_format_pax_restricted(a));
+ assertA(0 == archive_write_set_bytes_per_block(a, 512));
+ assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &write_pos));
+ assertA(0 == archive_write_header(a, ae));
+ assertA(data_size == archive_write_data(a, nulls, sizeof(nulls)));
+#if ARCHIVE_API_VERSION > 1
+ assertA(0 == archive_write_finish(a));
+#else
+ assertA(0 == archive_write_close(a));
+ archive_write_finish(a);
+#endif
+ /* 512-byte header + data_size (rounded up) + 1024 end-of-archive */
+ assert(write_pos == ((512 + data_size + 1024 + 511)/512)*512);
+
+ /* Read the archive back. */
+ assert(NULL != (a = archive_read_new()));
+ assertA(0 == archive_read_support_format_tar(a));
+ assertA(0 == archive_read_open_memory2(a, buff, sizeof(buff), 512));
+ assert((intmax_t)0 == (intmax_t)archive_read_header_position(a));
+ assertA(0 == archive_read_next_header(a, &ae));
+ assert((intmax_t)0 == (intmax_t)archive_read_header_position(a));
+ assertA(0 == archive_read_data_skip(a));
+ assert((intmax_t)0 == (intmax_t)archive_read_header_position(a));
+ assertA(1 == archive_read_next_header(a, &ae));
+ assert((intmax_t)((data_size + 511 + 512)/512)*512 == (intmax_t)archive_read_header_position(a));
+ assertA(0 == archive_read_close(a));
+ assert((intmax_t)((data_size + 511 + 512)/512)*512 == (intmax_t)archive_read_header_position(a));
+ archive_read_finish(a);
+}
diff --git a/lib/libarchive/test/test_read_truncated.c b/lib/libarchive/test/test_read_truncated.c
new file mode 100644
index 0000000..eba2e81
--- /dev/null
+++ b/lib/libarchive/test/test_read_truncated.c
@@ -0,0 +1,148 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+char buff[1000000];
+char buff2[100000];
+
+DEFINE_TEST(test_read_truncated)
+{
+ struct archive_entry *ae;
+ struct archive *a;
+ int i;
+ size_t used;
+
+ /* Create a new archive in memory. */
+ assert((a = archive_write_new()) != NULL);
+ assertA(0 == archive_write_set_format_ustar(a));
+ assertA(0 == archive_write_set_compression_none(a));
+ assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &used));
+
+ /*
+ * Write a file to it.
+ */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "file");
+ archive_entry_set_mode(ae, S_IFREG | 0755);
+ for (i = 0; i < sizeof(buff2); i++)
+ buff2[i] = (unsigned char)rand();
+ archive_entry_set_size(ae, sizeof(buff2));
+ assertA(0 == archive_write_header(a, ae));
+ assertA(sizeof(buff2) == archive_write_data(a, buff2, sizeof(buff2)));
+
+ /* Close out the archive. */
+ assertA(0 == archive_write_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assertA(0 == archive_write_finish(a));
+#else
+ archive_write_finish(a);
+#endif
+
+ /* Now, read back a truncated version of the archive and
+ * verify that we get an appropriate error. */
+ for (i = 1; i < used + 100; i += 100) {
+ 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, i));
+
+ if (i < 512) {
+ assertA(ARCHIVE_FATAL == archive_read_next_header(a, &ae));
+ goto wrap_up;
+ } else {
+ assertA(0 == archive_read_next_header(a, &ae));
+ }
+
+ if (i < 512 + sizeof(buff2)) {
+ assertA(ARCHIVE_FATAL == archive_read_data(a, buff2, sizeof(buff2)));
+ goto wrap_up;
+ } else {
+ assertA(sizeof(buff2) == archive_read_data(a, buff2, sizeof(buff2)));
+ }
+
+ /* Verify the end of the archive. */
+ /* Archive must be long enough to capture a 512-byte
+ * block of zeroes after the entry. (POSIX requires a
+ * second block of zeros to be written but libarchive
+ * does not return an error if it can't consume
+ * it.) */
+ if (i < 512 + 512*((sizeof(buff2) + 511)/512) + 512) {
+ assertA(ARCHIVE_FATAL == archive_read_next_header(a, &ae));
+ } else {
+ assertA(ARCHIVE_EOF == archive_read_next_header(a, &ae));
+ }
+ wrap_up:
+ assert(0 == archive_read_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assert(0 == archive_read_finish(a));
+#else
+ archive_read_finish(a);
+#endif
+ }
+
+
+
+ /* Same as above, except skip the body instead of reading it. */
+ for (i = 1; i < used + 100; i += 100) {
+ 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, i));
+
+ if (i < 512) {
+ assertA(ARCHIVE_FATAL == archive_read_next_header(a, &ae));
+ goto wrap_up2;
+ } else {
+ assertA(0 == archive_read_next_header(a, &ae));
+ }
+
+ if (i < 512 + 512*((sizeof(buff2)+511)/512)) {
+ assertA(ARCHIVE_FATAL == archive_read_data_skip(a));
+ goto wrap_up2;
+ } else {
+ assertA(ARCHIVE_OK == archive_read_data_skip(a));
+ }
+
+ /* Verify the end of the archive. */
+ /* Archive must be long enough to capture a 512-byte
+ * block of zeroes after the entry. (POSIX requires a
+ * second block of zeros to be written but libarchive
+ * does not return an error if it can't consume
+ * it.) */
+ if (i < 512 + 512*((sizeof(buff2) + 511)/512) + 512) {
+ assertA(ARCHIVE_FATAL == archive_read_next_header(a, &ae));
+ } else {
+ assertA(ARCHIVE_EOF == archive_read_next_header(a, &ae));
+ }
+ wrap_up2:
+ assert(0 == archive_read_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assert(0 == archive_read_finish(a));
+#else
+ archive_read_finish(a);
+#endif
+ }
+}
diff --git a/lib/libarchive/test/test_write_disk.c b/lib/libarchive/test/test_write_disk.c
new file mode 100644
index 0000000..4ff70c3
--- /dev/null
+++ b/lib/libarchive/test/test_write_disk.c
@@ -0,0 +1,92 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+#define UMASK 022
+
+static void create(struct archive_entry *ae)
+{
+ struct archive *ad;
+ struct stat st;
+
+ /* Write the entry to disk. */
+ assert((ad = archive_write_disk_new()) != NULL);
+ assert(0 == archive_write_header(ad, ae));
+ assert(0 == archive_write_finish_entry(ad));
+#if ARCHIVE_API_VERSION > 1
+ assert(0 == archive_write_finish(ad));
+#else
+ archive_write_finish(ad);
+#endif
+ /* Test the entries on disk. */
+ assert(0 == stat(archive_entry_pathname(ae), &st));
+ failure("st.st_mode=%o archive_entry_mode(ae)=%o",
+ st.st_mode, archive_entry_mode(ae));
+ assert(st.st_mode == (archive_entry_mode(ae) & ~UMASK));
+}
+
+DEFINE_TEST(test_write_disk)
+{
+ struct archive_entry *ae;
+
+ /* Force the umask to something predictable. */
+ umask(UMASK);
+
+ /* A regular file. */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "file");
+ archive_entry_set_mode(ae, S_IFREG | 0755);
+ create(ae);
+ archive_entry_free(ae);
+
+ /* A regular file over an existing file */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "file");
+ archive_entry_set_mode(ae, S_IFREG | 0724);
+ create(ae);
+ archive_entry_free(ae);
+
+ /* A directory. */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "dir");
+ archive_entry_set_mode(ae, S_IFDIR | 0555);
+ create(ae);
+ archive_entry_free(ae);
+
+ /* A directory over an existing file. */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "file");
+ archive_entry_set_mode(ae, S_IFDIR | 0742);
+ create(ae);
+ archive_entry_free(ae);
+
+ /* A file over an existing dir. */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "file");
+ archive_entry_set_mode(ae, S_IFREG | 0744);
+ create(ae);
+ archive_entry_free(ae);
+}
diff --git a/lib/libarchive/test/test_write_disk_perms.c b/lib/libarchive/test/test_write_disk_perms.c
new file mode 100644
index 0000000..285b516
--- /dev/null
+++ b/lib/libarchive/test/test_write_disk_perms.c
@@ -0,0 +1,324 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+#define UMASK 022
+
+static gid_t _default_gid = 0;
+static gid_t _invalid_gid = 0;
+static gid_t _alt_gid = 0;
+
+/*
+ * To fully test SGID restores, we need three distinct GIDs to work
+ * with:
+ * * the GID that files are created with by default (for the
+ * current user in the current directory)
+ * * An "alt gid" that this user can create files with
+ * * An "invalid gid" that this user is not permitted to create
+ * files with.
+ * The second fails if this user doesn't belong to at least two groups;
+ * the third fails if the current user is root.
+ */
+static int
+searchgid(void)
+{
+ static int _searched = 0;
+ uid_t uid = getuid();
+ gid_t gid = 0;
+ int n;
+ struct stat st;
+ int fd;
+
+ /* If we've already looked this up, we're done. */
+ if (_searched)
+ return;
+ _searched = 1;
+
+ /* Create a file on disk. */
+ fd = open("test_gid", O_CREAT, 0664);
+ failure("Couldn't create a file for gid testing.");
+ assert(fd > 0);
+
+ /* See what GID it ended up with. This is our "valid" GID. */
+ assert(fstat(fd, &st) == 0);
+ _default_gid = st.st_gid;
+
+ /* Find a GID for which fchown() fails. This is our "invalid" GID. */
+ _invalid_gid = 0;
+ /* This loop stops when we wrap the gid or examine 10,000 gids. */
+ for (gid = 1, n = 1; gid == n && n < 10000 ; n++, gid++) {
+ if (fchown(fd, uid, gid) != 0) {
+ _invalid_gid = gid;
+ break;
+ }
+ }
+
+ /*
+ * Find a GID for which fchown() succeeds, but which isn't the
+ * default. This is the "alternate" gid.
+ */
+ _alt_gid = 0;
+ for (gid = 1, n = 1; gid == n && n < 10000 ; n++, gid++) {
+ /* _alt_gid must be different than _default_gid */
+ if (gid == _default_gid)
+ continue;
+ if (fchown(fd, uid, gid) == 0) {
+ _alt_gid = gid;
+ break;
+ }
+ }
+ close(fd);
+}
+
+static int
+altgid(void)
+{
+ searchgid();
+ return (_alt_gid);
+}
+
+static int
+invalidgid(void)
+{
+ searchgid();
+ return (_invalid_gid);
+}
+
+static int
+defaultgid(void)
+{
+ searchgid();
+ return (_default_gid);
+}
+
+/*
+ * Exercise permission and ownership restores.
+ * In particular, try to exercise a bunch of border cases related
+ * to files/dirs that already exist, SUID/SGID bits, etc.
+ */
+
+DEFINE_TEST(test_write_disk_perms)
+{
+ struct archive *a;
+ struct archive_entry *ae;
+ struct stat st;
+
+ /* Create an archive_write_disk object. */
+ assert((a = archive_write_disk_new()) != NULL);
+
+ /* Write a regular file to it. */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "file_0755");
+ archive_entry_set_mode(ae, S_IFREG | 0777);
+ assert(0 == archive_write_header(a, ae));
+ assert(0 == archive_write_finish_entry(a));
+
+ /* Write a regular file with SUID bit, but don't use _EXTRACT_PERM. */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "file_no_suid");
+ archive_entry_set_mode(ae, S_IFREG | S_ISUID | 0777);
+ archive_write_disk_set_options(a, 0);
+ assert(0 == archive_write_header(a, ae));
+ assert(0 == archive_write_finish_entry(a));
+
+ /* Write a regular file with ARCHIVE_EXTRACT_PERM. */
+ assert(archive_entry_clear(ae) != NULL);
+ archive_entry_copy_pathname(ae, "file_0777");
+ archive_entry_set_mode(ae, S_IFREG | 0777);
+ archive_write_disk_set_options(a, ARCHIVE_EXTRACT_PERM);
+ assert(0 == archive_write_header(a, ae));
+ assert(0 == archive_write_finish_entry(a));
+
+ /* Write a regular file with ARCHIVE_EXTRACT_PERM & SUID bit */
+ assert(archive_entry_clear(ae) != NULL);
+ archive_entry_copy_pathname(ae, "file_4742");
+ archive_entry_set_mode(ae, S_IFREG | S_ISUID | 0742);
+ archive_entry_set_uid(ae, getuid());
+ archive_write_disk_set_options(a, ARCHIVE_EXTRACT_PERM);
+ assert(0 == archive_write_header(a, ae));
+ assert(0 == archive_write_finish_entry(a));
+
+ /*
+ * Write a regular file with ARCHIVE_EXTRACT_PERM & SUID bit,
+ * but wrong uid. POSIX says you shouldn't restore SUID bit
+ * unless the UID could be restored.
+ */
+ assert(archive_entry_clear(ae) != NULL);
+ archive_entry_copy_pathname(ae, "file_bad_suid");
+ archive_entry_set_mode(ae, S_IFREG | S_ISUID | 0742);
+ archive_entry_set_uid(ae, getuid() + 1);
+ archive_write_disk_set_options(a, ARCHIVE_EXTRACT_PERM);
+ assertA(0 == archive_write_header(a, ae));
+ assertA(ARCHIVE_WARN == archive_write_finish_entry(a));
+
+ /* Write a regular file with ARCHIVE_EXTRACT_PERM & SGID bit */
+ assert(archive_entry_clear(ae) != NULL);
+ archive_entry_copy_pathname(ae, "file_perm_sgid");
+ archive_entry_set_mode(ae, S_IFREG | S_ISGID | 0742);
+ archive_entry_set_gid(ae, defaultgid());
+ archive_write_disk_set_options(a, ARCHIVE_EXTRACT_PERM);
+ assert(0 == archive_write_header(a, ae));
+ failure("Setting SGID bit should succeed here.");
+ assertEqualIntA(a, 0, archive_write_finish_entry(a));
+
+ if (altgid() == 0) {
+ /*
+ * Current user must belong to at least two groups or
+ * else we can't test setting the GID to another group.
+ */
+ printf("Current user can't test gid restore: must belong to more than one group.\n");
+ } else {
+ /* Write a regular file with ARCHIVE_EXTRACT_PERM & SGID bit */
+ /*
+ * This is a weird case: The user has asked for permissions to
+ * be restored but not asked for ownership to be restored. As
+ * a result, the default file creation will create a file with
+ * the wrong group. There are two reasonable behaviors: warn
+ * and drop the SGID bit (the current libarchive behavior) or
+ * try to set the group. It is completely wrong to set the
+ * SGID bit with the wrong group (which is, incidentally,
+ * exactly what gtar 1.15 does).
+ */
+ assert(archive_entry_clear(ae) != NULL);
+ archive_entry_copy_pathname(ae, "file_alt_sgid");
+ archive_entry_set_mode(ae, S_IFREG | S_ISGID | 0742);
+ archive_entry_set_uid(ae, getuid());
+ archive_entry_set_gid(ae, altgid());
+ archive_write_disk_set_options(a, ARCHIVE_EXTRACT_PERM);
+ assert(0 == archive_write_header(a, ae));
+ failure("Setting SGID bit should not succeed here.");
+ assertEqualIntA(a, ARCHIVE_WARN, archive_write_finish_entry(a));
+
+ /* As above, but add _EXTRACT_OWNER. */
+ assert(archive_entry_clear(ae) != NULL);
+ archive_entry_copy_pathname(ae, "file_alt_sgid_owner");
+ archive_entry_set_mode(ae, S_IFREG | S_ISGID | 0742);
+ archive_entry_set_uid(ae, getuid());
+ archive_entry_set_gid(ae, altgid());
+ archive_write_disk_set_options(a,
+ ARCHIVE_EXTRACT_PERM | ARCHIVE_EXTRACT_OWNER);
+ assert(0 == archive_write_header(a, ae));
+ failure("Setting SGID bit should succeed here.");
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_finish_entry(a));
+ }
+
+ /*
+ * Write a regular file with ARCHIVE_EXTRACT_PERM & SGID bit,
+ * but wrong GID. POSIX says you shouldn't restore SGID bit
+ * unless the GID could be restored.
+ */
+ if (invalidgid() == 0) {
+ /* This test always fails for root. */
+ printf("Running as root: Can't test SGID failures.\n");
+ } else {
+ assert(archive_entry_clear(ae) != NULL);
+ archive_entry_copy_pathname(ae, "file_bad_sgid");
+ archive_entry_set_mode(ae, S_IFREG | S_ISGID | 0742);
+ archive_entry_set_gid(ae, invalidgid());
+ archive_write_disk_set_options(a, ARCHIVE_EXTRACT_PERM);
+ assertA(0 == archive_write_header(a, ae));
+ failure("This SGID restore should fail.");
+ assertEqualIntA(a, ARCHIVE_WARN, archive_write_finish_entry(a));
+ }
+
+ /* Set ownership should fail if we're not root. */
+ if (getuid() == 0) {
+ printf("Running as root: Can't test setuid failures.\n");
+ } else {
+ assert(archive_entry_clear(ae) != NULL);
+ archive_entry_copy_pathname(ae, "file_bad_owner");
+ archive_entry_set_mode(ae, S_IFREG | 0744);
+ archive_entry_set_uid(ae, getuid() + 1);
+ archive_write_disk_set_options(a, ARCHIVE_EXTRACT_OWNER);
+ assertA(0 == archive_write_header(a, ae));
+ assertEqualIntA(a,ARCHIVE_WARN,archive_write_finish_entry(a));
+ }
+
+#if ARCHIVE_API_VERSION > 1
+ assert(0 == archive_write_finish(a));
+#else
+ archive_write_finish(a);
+#endif
+
+ /* Test the entries on disk. */
+ assert(0 == stat("file_0755", &st));
+ failure("file_0755: st.st_mode=%o", st.st_mode);
+ assert((st.st_mode & 07777) == 0755);
+
+ assert(0 == stat("file_no_suid", &st));
+ failure("file_0755: st.st_mode=%o", st.st_mode);
+ assert((st.st_mode & 07777) == 0755);
+
+ assert(0 == stat("file_0777", &st));
+ failure("file_0777: st.st_mode=%o", st.st_mode);
+ assert((st.st_mode & 07777) == 0777);
+
+ /* SUID bit should get set here. */
+ assert(0 == stat("file_4742", &st));
+ failure("file_4742: st.st_mode=%o", st.st_mode);
+ assert((st.st_mode & 07777) == (S_ISUID | 0742));
+
+ /* SUID bit should NOT have been set here. */
+ assert(0 == stat("file_bad_suid", &st));
+ failure("file_bad_suid: st.st_mode=%o", st.st_mode);
+ assert((st.st_mode & 07777) == (0742));
+
+ /* SGID should be set here. */
+ assert(0 == stat("file_perm_sgid", &st));
+ failure("file_perm_sgid: st.st_mode=%o", st.st_mode);
+ assert((st.st_mode & 07777) == (S_ISGID | 0742));
+
+ if (altgid() != 0) {
+ /* SGID should not be set here. */
+ assert(0 == stat("file_alt_sgid", &st));
+ failure("file_alt_sgid: st.st_mode=%o", st.st_mode);
+ assert((st.st_mode & 07777) == (0742));
+
+ /* SGID should be set here. */
+ assert(0 == stat("file_alt_sgid_owner", &st));
+ failure("file_alt_sgid: st.st_mode=%o", st.st_mode);
+ assert((st.st_mode & 07777) == (S_ISGID | 0742));
+ }
+
+ if (invalidgid() != 0) {
+ /* SGID should NOT be set here. */
+ assert(0 == stat("file_bad_sgid", &st));
+ failure("file_bad_sgid: st.st_mode=%o", st.st_mode);
+ assert((st.st_mode & 07777) == (0742));
+ }
+
+ if (getuid() != 0) {
+ assert(0 == stat("file_bad_owner", &st));
+ failure("file_bad_owner: st.st_mode=%o", st.st_mode);
+ assert((st.st_mode & 07777) == (0744));
+ failure("file_bad_owner: st.st_uid=%d getuid()=%d",
+ st.st_uid, getuid());
+ /* The entry had getuid()+1, but because we're
+ * not root, we should not have been able to set that. */
+ assert(st.st_uid == getuid());
+ }
+
+}
diff --git a/lib/libarchive/test/test_write_disk_secure.c b/lib/libarchive/test/test_write_disk_secure.c
new file mode 100644
index 0000000..09560e0
--- /dev/null
+++ b/lib/libarchive/test/test_write_disk_secure.c
@@ -0,0 +1,140 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+#define UMASK 022
+
+/*
+ * Exercise security checks that should prevent certain
+ * writes.
+ */
+
+DEFINE_TEST(test_write_disk_secure)
+{
+ struct archive *a;
+ struct archive_entry *ae;
+ struct stat st;
+
+ /* Start with a known umask. */
+ umask(UMASK);
+
+ /* Create an archive_write_disk object. */
+ assert((a = archive_write_disk_new()) != NULL);
+
+ /* Write a regular dir to it. */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "dir");
+ archive_entry_set_mode(ae, S_IFDIR | 0777);
+ assert(0 == archive_write_header(a, ae));
+ assert(0 == archive_write_finish_entry(a));
+
+ /* Write a symlink to the dir above. */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "link_to_dir");
+ archive_entry_set_mode(ae, S_IFLNK | 0777);
+ archive_entry_set_symlink(ae, "dir");
+ archive_write_disk_set_options(a, 0);
+ assert(0 == archive_write_header(a, ae));
+ assert(0 == archive_write_finish_entry(a));
+
+ /*
+ * Without security checks, we should be able to
+ * extract a file through the link.
+ */
+ assert(archive_entry_clear(ae) != NULL);
+ archive_entry_copy_pathname(ae, "link_to_dir/filea");
+ archive_entry_set_mode(ae, S_IFREG | 0777);
+ assert(0 == archive_write_header(a, ae));
+ assert(0 == archive_write_finish_entry(a));
+
+ /* But with security checks enabled, this should fail. */
+ assert(archive_entry_clear(ae) != NULL);
+ archive_entry_copy_pathname(ae, "link_to_dir/fileb");
+ archive_entry_set_mode(ae, S_IFREG | 0777);
+ archive_write_disk_set_options(a, ARCHIVE_EXTRACT_SECURE_SYMLINKS);
+ failure("Extracting a file through a symlink should fail here.");
+ assertEqualInt(ARCHIVE_WARN, archive_write_header(a, ae));
+ assert(0 == archive_write_finish_entry(a));
+
+ /* Create another link. */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "link_to_dir2");
+ archive_entry_set_mode(ae, S_IFLNK | 0777);
+ archive_entry_set_symlink(ae, "dir");
+ archive_write_disk_set_options(a, 0);
+ assert(0 == archive_write_header(a, ae));
+ assert(0 == archive_write_finish_entry(a));
+
+ /*
+ * With symlink check and unlink option, it should remove
+ * the link and create the dir.
+ */
+ assert(archive_entry_clear(ae) != NULL);
+ archive_entry_copy_pathname(ae, "link_to_dir2/filec");
+ archive_entry_set_mode(ae, S_IFREG | 0777);
+ archive_write_disk_set_options(a, ARCHIVE_EXTRACT_SECURE_SYMLINKS | ARCHIVE_EXTRACT_UNLINK);
+ assertEqualIntA(a, ARCHIVE_OK, archive_write_header(a, ae));
+ assert(0 == archive_write_finish_entry(a));
+
+
+#if ARCHIVE_API_VERSION > 1
+ assert(0 == archive_write_finish(a));
+#else
+ archive_write_finish(a);
+#endif
+
+ /* Test the entries on disk. */
+ assert(0 == lstat("dir", &st));
+ failure("dir: st.st_mode=%o", st.st_mode);
+ assert((st.st_mode & 07777) == 0755);
+
+ assert(0 == lstat("link_to_dir", &st));
+ failure("link_to_dir: st.st_mode=%o", st.st_mode);
+ assert(S_ISLNK(st.st_mode));
+#if HAVE_LCHMOD
+ /* Systems that lack lchmod() can't set symlink perms, so skip this. */
+ failure("link_to_dir: st.st_mode=%o", st.st_mode);
+ assert((st.st_mode & 07777) == 0755);
+#endif
+
+ assert(0 == lstat("dir/filea", &st));
+ failure("dir/filea: st.st_mode=%o", st.st_mode);
+ assert((st.st_mode & 07777) == 0755);
+
+ failure("dir/fileb: This file should not have been created");
+ assert(0 != lstat("dir/fileb", &st));
+
+ assert(0 == lstat("link_to_dir2", &st));
+ failure("link_to_dir2 should have been re-created as a true dir");
+ assert(S_ISDIR(st.st_mode));
+ failure("link_to_dir2: Implicit dir creation should obey umask, but st.st_mode=%o", st.st_mode);
+ assert((st.st_mode & 07777) == 0755);
+
+ assert(0 == lstat("link_to_dir2/filec", &st));
+ assert(S_ISREG(st.st_mode));
+ failure("link_to_dir2/filec: st.st_mode=%o", st.st_mode);
+ assert((st.st_mode & 07777) == 0755);
+}
diff --git a/lib/libarchive/test/test_write_format_cpio_empty.c b/lib/libarchive/test/test_write_format_cpio_empty.c
new file mode 100644
index 0000000..c2e46d1
--- /dev/null
+++ b/lib/libarchive/test/test_write_format_cpio_empty.c
@@ -0,0 +1,76 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+/*
+ * Check that an "empty" cpio archive is correctly created.
+ */
+
+/* Here's what an empty cpio archive should look like. */
+static char ref[] =
+"070707" /* Magic number */
+"000000" /* Dev = 0 */
+"000000" /* ino = 0 */
+"000000" /* mode = 0 */
+"000000" /* uid = 0 */
+"000000" /* gid = 0 */
+"000001" /* nlink = 1 */
+"000000" /* rdev = 0 */
+"00000000000" /* mtime = 0 */
+"000013" /* Namesize = 11 */
+"00000000000" /* filesize = 0 */
+"TRAILER!!!\0"; /* Name */
+
+DEFINE_TEST(test_write_format_cpio_empty)
+{
+ struct archive *a;
+ char buff[2048];
+ size_t used;
+ int i;
+
+ /* Create a new archive in memory. */
+ assert((a = archive_write_new()) != NULL);
+ assertA(0 == archive_write_set_format_cpio(a));
+ assertA(0 == archive_write_set_compression_none(a));
+ /* 1-byte block size ensures we see only the required bytes. */
+ /* We're not testing the padding here. */
+ assertA(0 == archive_write_set_bytes_per_block(a, 1));
+ assertA(0 == archive_write_set_bytes_in_last_block(a, 1));
+ assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &used));
+
+ /* Close out the archive. */
+ assertA(0 == archive_write_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assertA(0 == archive_write_finish(a));
+#else
+ archive_write_finish(a);
+#endif
+
+ failure("Empty cpio archive should be exactly 87 bytes, was %d.", used);
+ assert(used == 87);
+ failure("Empty cpio archive is incorrectly formatted.");
+ assert(memcmp(buff, ref, 87) == 0);
+}
diff --git a/lib/libarchive/test/test_write_format_shar_empty.c b/lib/libarchive/test/test_write_format_shar_empty.c
new file mode 100644
index 0000000..81a024f
--- /dev/null
+++ b/lib/libarchive/test/test_write_format_shar_empty.c
@@ -0,0 +1,59 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+/*
+ * Check that an "empty" shar archive is correctly created as an empty file.
+ */
+
+DEFINE_TEST(test_write_format_shar_empty)
+{
+ struct archive *a;
+ char buff[2048];
+ size_t used;
+ int i;
+
+ /* Create a new archive in memory. */
+ assert((a = archive_write_new()) != NULL);
+ assertA(0 == archive_write_set_format_shar(a));
+ assertA(0 == archive_write_set_compression_none(a));
+ /* 1-byte block size ensures we see only the required bytes. */
+ /* We're not testing the padding here. */
+ assertA(0 == archive_write_set_bytes_per_block(a, 1));
+ assertA(0 == archive_write_set_bytes_in_last_block(a, 1));
+ assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &used));
+
+ /* Close out the archive. */
+ assertA(0 == archive_write_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assertA(0 == archive_write_finish(a));
+#else
+ archive_write_finish(a);
+#endif
+
+ failure("Empty shar archive should be exactly 0 bytes, was %d.", used);
+ assert(used == 0);
+}
diff --git a/lib/libarchive/test/test_write_format_tar.c b/lib/libarchive/test/test_write_format_tar.c
new file mode 100644
index 0000000..4b63bb2
--- /dev/null
+++ b/lib/libarchive/test/test_write_format_tar.c
@@ -0,0 +1,111 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+char buff[1000000];
+char buff2[64];
+
+DEFINE_TEST(test_write_format_tar)
+{
+ struct archive_entry *ae;
+ struct archive *a;
+ char *p;
+ size_t used;
+ int blocksize;
+
+ /* Repeat the following for a variety of odd blocksizes. */
+ for (blocksize = 1; blocksize < 100000; blocksize += blocksize + 3) {
+ /* Create a new archive in memory. */
+ assert((a = archive_write_new()) != NULL);
+ assertA(0 == archive_write_set_format_ustar(a));
+ assertA(0 == archive_write_set_compression_none(a));
+ assertA(0 == archive_write_set_bytes_per_block(a, blocksize));
+ assertA(0 == archive_write_set_bytes_in_last_block(a, blocksize));
+ assertA(blocksize == archive_write_get_bytes_in_last_block(a));
+ assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &used));
+ assertA(blocksize == archive_write_get_bytes_in_last_block(a));
+
+ /*
+ * Write a file to it.
+ */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_set_mtime(ae, 1, 10);
+ assert(1 == archive_entry_mtime(ae));
+ assert(10 == archive_entry_mtime_nsec(ae));
+ p = strdup("file");
+ archive_entry_copy_pathname(ae, p);
+ strcpy(p, "XXXX");
+ free(p);
+ assert(0 == strcmp("file", archive_entry_pathname(ae)));
+ archive_entry_set_mode(ae, S_IFREG | 0755);
+ assert((S_IFREG | 0755) == archive_entry_mode(ae));
+ archive_entry_set_size(ae, 8);
+
+ assertA(0 == archive_write_header(a, ae));
+ assertA(8 == archive_write_data(a, "12345678", 9));
+
+ /* Close out the archive. */
+ assertA(0 == archive_write_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assertA(0 == archive_write_finish(a));
+#else
+ archive_write_finish(a);
+#endif
+ /* This calculation gives "the smallest multiple of
+ * the block size that is at least 2048 bytes". */
+ assert(((2048 - 1)/blocksize+1)*blocksize == used);
+
+ /*
+ * 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));
+
+ assert(1 == archive_entry_mtime(ae));
+ /* Not the same as above: ustar doesn't store hi-res timestamps. */
+ assert(0 == archive_entry_mtime_nsec(ae));
+ assert(0 == archive_entry_atime(ae));
+ assert(0 == archive_entry_ctime(ae));
+ assert(0 == strcmp("file", archive_entry_pathname(ae)));
+ assert((S_IFREG | 0755) == archive_entry_mode(ae));
+ assert(8 == archive_entry_size(ae));
+ assertA(8 == archive_read_data(a, buff2, 10));
+ assert(0 == memcmp(buff2, "12345678", 8));
+
+ /* Verify the end of the archive. */
+ assert(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
+ }
+}
diff --git a/lib/libarchive/test/test_write_format_tar_empty.c b/lib/libarchive/test/test_write_format_tar_empty.c
new file mode 100644
index 0000000..3273c0d
--- /dev/null
+++ b/lib/libarchive/test/test_write_format_tar_empty.c
@@ -0,0 +1,84 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+/*
+ * Check that an "empty" tar archive is correctly created.
+ */
+
+DEFINE_TEST(test_write_format_tar_empty)
+{
+ struct archive *a;
+ char buff[2048];
+ size_t used;
+ int i;
+
+ /* USTAR format: Create a new archive in memory. */
+ assert((a = archive_write_new()) != NULL);
+ assertA(0 == archive_write_set_format_ustar(a));
+ assertA(0 == archive_write_set_compression_none(a));
+ assertA(0 == archive_write_set_bytes_per_block(a, 512));
+ assertA(0 == archive_write_set_bytes_in_last_block(a, 512));
+ assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &used));
+
+ /* Close out the archive. */
+ assertA(0 == archive_write_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assertA(0 == archive_write_finish(a));
+#else
+ archive_write_finish(a);
+#endif
+
+ failure("Empty tar archive should be exactly 1024 bytes, was %d.", used);
+ assert(used == 1024);
+ for (i = 0; i < used; i++) {
+ failure("Empty tar archive should be all nulls.");
+ assert(buff[i] == 0);
+ }
+
+ /* PAX format: Create a new archive in memory. */
+ assert((a = archive_write_new()) != NULL);
+ assertA(0 == archive_write_set_format_pax(a));
+ assertA(0 == archive_write_set_compression_none(a));
+ assertA(0 == archive_write_set_bytes_per_block(a, 512));
+ assertA(0 == archive_write_set_bytes_in_last_block(a, 512));
+ assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &used));
+
+ /* Close out the archive. */
+ assertA(0 == archive_write_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assertA(0 == archive_write_finish(a));
+#else
+ archive_write_finish(a);
+#endif
+
+ failure("Empty tar archive should be exactly 1024 bytes, was %d.", used);
+ assert(used == 1024);
+ for (i = 0; i < used; i++) {
+ failure("Empty tar archive should be all nulls.");
+ assert(buff[i] == 0);
+ }
+}
diff --git a/lib/libarchive/test/test_write_open_memory.c b/lib/libarchive/test/test_write_open_memory.c
new file mode 100644
index 0000000..dd4171e
--- /dev/null
+++ b/lib/libarchive/test/test_write_open_memory.c
@@ -0,0 +1,75 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "test.h"
+__FBSDID("$FreeBSD$");
+
+/* Try to force archive_write_open_memory.c to write past the end of an array. */
+static unsigned char buff[16384];
+
+DEFINE_TEST(test_write_open_memory)
+{
+ int i;
+ struct archive *a;
+ struct archive_entry *ae;
+ const char *name="/tmp/test";
+
+ /* Create a simple archive_entry. */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_set_pathname(ae, name);
+ archive_entry_set_mode(ae, S_IFREG);
+ assert(0 == strcmp(archive_entry_pathname(ae), name));
+
+ /* Try writing with different buffer sizes. */
+ /* Make sure that we get failure on too-small buffers, success on
+ * large enough ones. */
+ for (i = 100; i < 1600; i++) {
+ size_t s;
+ size_t blocksize = 94;
+ assert((a = archive_write_new()) != NULL);
+ assertA(0 == archive_write_set_format_ustar(a));
+ assertA(0 == archive_write_set_bytes_in_last_block(a, 1));
+ assertA(0 == archive_write_set_bytes_per_block(a, blocksize));
+ buff[i] = 0xAE;
+ assertA(0 == archive_write_open_memory(a, buff, i, &s));
+ /* If buffer is smaller than a tar header, this should fail. */
+ if (i < (511/blocksize)*blocksize)
+ assertA(ARCHIVE_FATAL == archive_write_header(a,ae));
+ else
+ assertA(0 == archive_write_header(a, ae));
+ /* If buffer is smaller than a tar header plus 1024 byte
+ * end-of-archive marker, then this should fail. */
+ if (i < 1536)
+ assertA(ARCHIVE_FATAL == archive_write_close(a));
+ else
+ assertA(0 == archive_write_close(a));
+#if ARCHIVE_API_VERSION > 1
+ assert(0 == archive_write_finish(a));
+#else
+ archive_write_finish(a);
+#endif
+ assert(buff[i] == 0xAE);
+ assert(s <= i);
+ }
+}
OpenPOWER on IntegriCloud