summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorkientzle <kientzle@FreeBSD.org>2007-05-29 01:00:21 +0000
committerkientzle <kientzle@FreeBSD.org>2007-05-29 01:00:21 +0000
commit013be331bc10706807599a452a143f4744398e9f (patch)
tree793787ab8615d768ba51341dfd934a5fb3039728 /lib
parentc611006e893ac2bf962cabe02743954e3b3c3314 (diff)
downloadFreeBSD-src-013be331bc10706807599a452a143f4744398e9f.zip
FreeBSD-src-013be331bc10706807599a452a143f4744398e9f.tar.gz
libarchive 2.2.3
* "compression_program" support uses an external program * Portability: no longer uses "struct stat" as a primary data interchange structure internally * Part of the above: refactor archive_entry to separate out copy_stat() and stat() functions * More complete tests for archive_entry * Finish archive_entry_clone() * Isolate major()/minor()/makedev() in archive_entry; remove these from everywhere else. * Bug fix: properly handle decompression look-ahead at end-of-data * Bug fixes to 'ar' support * Fix memory leak in ZIP reader * Portability: better timegm() emulation in iso9660 reader * New write_disk flags to suppress auto dir creation and not overwrite newer files (for future cpio front-end) * Simplify trailing-'/' fixup when writing tar and pax * Test enhancements: fix various compiler warnings, improve portability, add lots of new tests. * Documentation: document new functions, first draft of libarchive_internals.3 MFC after: 14 days Thanks to: Joerg Sonnenberger (compression_program) Thanks to: Kai Wang (ar) Thanks to: Colin Percival (many small fixes) Thanks to: Many others who sent me various patches and problem reports.
Diffstat (limited to 'lib')
-rw-r--r--lib/libarchive/Makefile25
-rw-r--r--lib/libarchive/archive.h.in10
-rw-r--r--lib/libarchive/archive_entry.332
-rw-r--r--lib/libarchive/archive_entry.c364
-rw-r--r--lib/libarchive/archive_entry.h38
-rw-r--r--lib/libarchive/archive_entry_copy_stat.c59
-rw-r--r--lib/libarchive/archive_entry_private.h155
-rw-r--r--lib/libarchive/archive_entry_stat.c100
-rw-r--r--lib/libarchive/archive_platform.h29
-rw-r--r--lib/libarchive/archive_read.38
-rw-r--r--lib/libarchive/archive_read.c79
-rw-r--r--lib/libarchive/archive_read_extract.c8
-rw-r--r--lib/libarchive/archive_read_private.h64
-rw-r--r--lib/libarchive/archive_read_support_compression_bzip2.c43
-rw-r--r--lib/libarchive/archive_read_support_compression_compress.c25
-rw-r--r--lib/libarchive/archive_read_support_compression_gzip.c44
-rw-r--r--lib/libarchive/archive_read_support_compression_none.c30
-rw-r--r--lib/libarchive/archive_read_support_compression_program.c312
-rw-r--r--lib/libarchive/archive_read_support_format_ar.c41
-rw-r--r--lib/libarchive/archive_read_support_format_cpio.c215
-rw-r--r--lib/libarchive/archive_read_support_format_empty.c2
-rw-r--r--lib/libarchive/archive_read_support_format_iso9660.c113
-rw-r--r--lib/libarchive/archive_read_support_format_tar.c279
-rw-r--r--lib/libarchive/archive_read_support_format_zip.c88
-rw-r--r--lib/libarchive/archive_string.c9
-rw-r--r--lib/libarchive/archive_string.h6
-rw-r--r--lib/libarchive/archive_util.35
-rw-r--r--lib/libarchive/archive_util.c9
-rw-r--r--lib/libarchive/archive_write.320
-rw-r--r--lib/libarchive/archive_write.c16
-rw-r--r--lib/libarchive/archive_write_disk.c112
-rw-r--r--lib/libarchive/archive_write_disk_set_standard_lookup.c16
-rw-r--r--lib/libarchive/archive_write_private.h75
-rw-r--r--lib/libarchive/archive_write_set_compression_bzip2.c17
-rw-r--r--lib/libarchive/archive_write_set_compression_gzip.c17
-rw-r--r--lib/libarchive/archive_write_set_compression_none.c21
-rw-r--r--lib/libarchive/archive_write_set_compression_program.c322
-rw-r--r--lib/libarchive/archive_write_set_format_ar.c168
-rw-r--r--lib/libarchive/archive_write_set_format_cpio.c45
-rw-r--r--lib/libarchive/archive_write_set_format_pax.c311
-rw-r--r--lib/libarchive/archive_write_set_format_shar.c37
-rw-r--r--lib/libarchive/archive_write_set_format_ustar.c101
-rw-r--r--lib/libarchive/config_freebsd.h5
-rw-r--r--lib/libarchive/filter_fork.c137
-rw-r--r--lib/libarchive/filter_fork.h37
-rw-r--r--lib/libarchive/libarchive_internals.3376
-rw-r--r--lib/libarchive/test/Makefile8
-rw-r--r--lib/libarchive/test/README9
-rw-r--r--lib/libarchive/test/main.c190
-rw-r--r--lib/libarchive/test/test.h20
-rw-r--r--lib/libarchive/test/test_acl_basic.c14
-rw-r--r--lib/libarchive/test/test_acl_pax.c7
-rw-r--r--lib/libarchive/test/test_archive_api_feature.c6
-rw-r--r--lib/libarchive/test/test_entry.c576
-rw-r--r--lib/libarchive/test/test_read_compress_program.c55
-rw-r--r--lib/libarchive/test/test_read_data_large.c20
-rw-r--r--lib/libarchive/test/test_read_extract.c2
-rw-r--r--lib/libarchive/test/test_read_format_ar.c8
-rw-r--r--lib/libarchive/test/test_read_format_isorr_bz2.c26
-rw-r--r--lib/libarchive/test/test_read_format_zip.c38
-rw-r--r--lib/libarchive/test/test_read_large.c16
-rw-r--r--lib/libarchive/test/test_read_position.c2
-rw-r--r--lib/libarchive/test/test_read_truncated.c2
-rw-r--r--lib/libarchive/test/test_tar_filenames.c8
-rw-r--r--lib/libarchive/test/test_write_compress_program.c97
-rw-r--r--lib/libarchive/test/test_write_disk.c19
-rw-r--r--lib/libarchive/test/test_write_disk_perms.c35
-rw-r--r--lib/libarchive/test/test_write_format_ar.c56
-rw-r--r--lib/libarchive/test/test_write_format_cpio_empty.c1
-rw-r--r--lib/libarchive/test/test_write_format_shar_empty.c1
-rw-r--r--lib/libarchive/test/test_write_format_tar.c14
-rw-r--r--lib/libarchive/test/test_write_format_tar_empty.c2
-rw-r--r--lib/libarchive/test/test_write_open_memory.c4
73 files changed, 3889 insertions, 1372 deletions
diff --git a/lib/libarchive/Makefile b/lib/libarchive/Makefile
index 4581557..5380b4c 100644
--- a/lib/libarchive/Makefile
+++ b/lib/libarchive/Makefile
@@ -9,7 +9,7 @@ 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= 2.0.31
+VERSION= 2.2.3
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/\..*//'
@@ -46,6 +46,8 @@ CLEANFILES+= archive.h
SRCS= archive.h \
archive_check_magic.c \
archive_entry.c \
+ archive_entry_copy_stat.c \
+ archive_entry_stat.c \
archive_read.c \
archive_read_data_into_fd.c \
archive_read_extract.c \
@@ -58,6 +60,7 @@ SRCS= archive.h \
archive_read_support_compression_compress.c \
archive_read_support_compression_gzip.c \
archive_read_support_compression_none.c \
+ archive_read_support_compression_program.c \
archive_read_support_format_all.c \
archive_read_support_format_ar.c \
archive_read_support_format_cpio.c \
@@ -79,13 +82,15 @@ SRCS= archive.h \
archive_write_set_compression_bzip2.c \
archive_write_set_compression_gzip.c \
archive_write_set_compression_none.c \
+ archive_write_set_compression_program.c \
archive_write_set_format.c \
archive_write_set_format_ar.c \
archive_write_set_format_by_name.c \
archive_write_set_format_cpio.c \
archive_write_set_format_pax.c \
archive_write_set_format_shar.c \
- archive_write_set_format_ustar.c
+ archive_write_set_format_ustar.c \
+ filter_fork.c
# Man pages to be installed.
MAN= archive_entry.3 \
@@ -115,6 +120,10 @@ MLINKS+= archive_entry.3 archive_entry_copy_pathname_w.3
MLINKS+= archive_entry.3 archive_entry_copy_stat.3
MLINKS+= archive_entry.3 archive_entry_copy_symlink_w.3
MLINKS+= archive_entry.3 archive_entry_copy_uname_w.3
+MLINKS+= archive_entry.3 archive_entry_dev.3
+MLINKS+= archive_entry.3 archive_entry_devmajor.3
+MLINKS+= archive_entry.3 archive_entry_devminor.3
+MLINKS+= archive_entry.3 archive_entry_filetype.3
MLINKS+= archive_entry.3 archive_entry_fflags.3
MLINKS+= archive_entry.3 archive_entry_fflags_text.3
MLINKS+= archive_entry.3 archive_entry_free.3
@@ -126,19 +135,28 @@ MLINKS+= archive_entry.3 archive_entry_ino.3
MLINKS+= archive_entry.3 archive_entry_mode.3
MLINKS+= archive_entry.3 archive_entry_mtime.3
MLINKS+= archive_entry.3 archive_entry_mtime_nsec.3
+MLINKS+= archive_entry.3 archive_entry_nlink.3
MLINKS+= archive_entry.3 archive_entry_new.3
MLINKS+= archive_entry.3 archive_entry_pathname.3
MLINKS+= archive_entry.3 archive_entry_pathname_w.3
MLINKS+= archive_entry.3 archive_entry_rdev.3
MLINKS+= archive_entry.3 archive_entry_rdevmajor.3
MLINKS+= archive_entry.3 archive_entry_rdevminor.3
+MLINKS+= archive_entry.3 archive_entry_set_atime.3
+MLINKS+= archive_entry.3 archive_entry_set_ctime.3
+MLINKS+= archive_entry.3 archive_entry_set_dev.3
+MLINKS+= archive_entry.3 archive_entry_set_devmajor.3
+MLINKS+= archive_entry.3 archive_entry_set_devminor.3
MLINKS+= archive_entry.3 archive_entry_set_fflags.3
MLINKS+= archive_entry.3 archive_entry_set_gid.3
MLINKS+= archive_entry.3 archive_entry_set_gname.3
MLINKS+= archive_entry.3 archive_entry_set_hardlink.3
MLINKS+= archive_entry.3 archive_entry_set_link.3
MLINKS+= archive_entry.3 archive_entry_set_mode.3
+MLINKS+= archive_entry.3 archive_entry_set_mtime.3
+MLINKS+= archive_entry.3 archive_entry_set_nlink.3
MLINKS+= archive_entry.3 archive_entry_set_pathname.3
+MLINKS+= archive_entry.3 archive_entry_set_rdev.3
MLINKS+= archive_entry.3 archive_entry_set_rdevmajor.3
MLINKS+= archive_entry.3 archive_entry_set_rdevminor.3
MLINKS+= archive_entry.3 archive_entry_set_size.3
@@ -174,6 +192,7 @@ MLINKS+= archive_read.3 archive_read_support_compression_bzip2.3
MLINKS+= archive_read.3 archive_read_support_compression_compress.3
MLINKS+= archive_read.3 archive_read_support_compression_gzip.3
MLINKS+= archive_read.3 archive_read_support_compression_none.3
+MLINKS+= archive_read.3 archive_read_support_compression_program.3
MLINKS+= archive_read.3 archive_read_support_format_all.3
MLINKS+= archive_read.3 archive_read_support_format_cpio.3
MLINKS+= archive_read.3 archive_read_support_format_iso9660.3
@@ -205,6 +224,8 @@ MLINKS+= archive_write.3 archive_write_set_bytes_per_block.3
MLINKS+= archive_write.3 archive_write_set_callbacks.3
MLINKS+= archive_write.3 archive_write_set_compression_bzip2.3
MLINKS+= archive_write.3 archive_write_set_compression_gzip.3
+MLINKS+= archive_write.3 archive_write_set_compression_none.3
+MLINKS+= archive_write.3 archive_write_set_compression_program.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
diff --git a/lib/libarchive/archive.h.in b/lib/libarchive/archive.h.in
index 0f83800..0797977 100644
--- a/lib/libarchive/archive.h.in
+++ b/lib/libarchive/archive.h.in
@@ -141,6 +141,7 @@ typedef int archive_close_callback(struct archive *, void *_client_data);
#define ARCHIVE_COMPRESSION_GZIP 1
#define ARCHIVE_COMPRESSION_BZIP2 2
#define ARCHIVE_COMPRESSION_COMPRESS 3
+#define ARCHIVE_COMPRESSION_PROGRAM 4
/*
* Codes returned by archive_format.
@@ -207,6 +208,8 @@ int archive_read_support_compression_bzip2(struct archive *);
int archive_read_support_compression_compress(struct archive *);
int archive_read_support_compression_gzip(struct archive *);
int archive_read_support_compression_none(struct archive *);
+int archive_read_support_compression_program(struct archive *,
+ const char *command);
int archive_read_support_format_all(struct archive *);
int archive_read_support_format_ar(struct archive *);
@@ -319,6 +322,10 @@ int archive_read_data_into_fd(struct archive *, int fd);
#define ARCHIVE_EXTRACT_SECURE_SYMLINKS (256)
/* Default: Do not reject entries with '..' as path elements. */
#define ARCHIVE_EXTRACT_SECURE_NODOTDOT (512)
+/* Default: Create parent directories as needed. */
+#define ARCHIVE_EXTRACT_NO_AUTODIR (1024)
+/* Default: Overwrite files, even if one on disk is newer. */
+#define ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER (2048)
int archive_read_extract(struct archive *, struct archive_entry *,
int flags);
@@ -373,6 +380,8 @@ int archive_write_set_skip_file(struct archive *, dev_t, ino_t);
int archive_write_set_compression_bzip2(struct archive *);
int archive_write_set_compression_gzip(struct archive *);
int archive_write_set_compression_none(struct archive *);
+int archive_write_set_compression_program(struct archive *,
+ const char *cmd);
/* A convenience function to set the format based on the code or name. */
int archive_write_set_format(struct archive *, int format_code);
int archive_write_set_format_by_name(struct archive *,
@@ -494,6 +503,7 @@ 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, ...);
+void archive_copy_error(struct archive *dest, struct archive *src);
#ifdef __cplusplus
}
diff --git a/lib/libarchive/archive_entry.3 b/lib/libarchive/archive_entry.3
index 8205c11..47c0009 100644
--- a/lib/libarchive/archive_entry.3
+++ b/lib/libarchive/archive_entry.3
@@ -50,6 +50,9 @@
.Nm archive_entry_copy_symlink_w ,
.Nm archive_entry_copy_uname_w ,
.Nm archive_entry_dev ,
+.Nm archive_entry_devmajor ,
+.Nm archive_entry_devminor ,
+.Nm archive_entry_filetype ,
.Nm archive_entry_fflags ,
.Nm archive_entry_fflags_text ,
.Nm archive_entry_free ,
@@ -60,12 +63,19 @@
.Nm archive_entry_mode ,
.Nm archive_entry_mtime ,
.Nm archive_entry_mtime_nsec ,
+.Nm archive_entry_nlink ,
.Nm archive_entry_new ,
.Nm archive_entry_pathname ,
.Nm archive_entry_pathname_w ,
.Nm archive_entry_rdev ,
.Nm archive_entry_rdevmajor ,
.Nm archive_entry_rdevminor ,
+.Nm archive_entry_set_atime ,
+.Nm archive_entry_set_ctime ,
+.Nm archive_entry_set_dev ,
+.Nm archive_entry_set_devmajor ,
+.Nm archive_entry_set_devminor ,
+.Nm archive_entry_set_filetype ,
.Nm archive_entry_set_fflags ,
.Nm archive_entry_set_gid ,
.Nm archive_entry_set_gname ,
@@ -132,6 +142,12 @@
.Fn archive_entry_copy_uname_w "struct archive_entry *" "const wchar_t *"
.Ft dev_t
.Fn archive_entry_dev "struct archive_entry *"
+.Ft dev_t
+.Fn archive_entry_devmajor "struct archive_entry *"
+.Ft dev_t
+.Fn archive_entry_devminor "struct archive_entry *"
+.Ft mode_t
+.Fn archive_entry_filetype "struct archive_entry *"
.Ft void
.Fn archive_entry_fflags "struct archive_entry *" "unsigned long *set" "unsigned long *clear"
.Ft const char *
@@ -150,6 +166,8 @@
.Fn archive_entry_mtime "struct archive_entry *"
.Ft long
.Fn archive_entry_mtime_nsec "struct archive_entry *"
+.Ft unsigned int
+.Fn archive_entry_nlink "struct archive_entry *"
.Ft struct archive_entry *
.Fn archive_entry_new "void"
.Ft const char *
@@ -163,6 +181,14 @@
.Ft dev_t
.Fn archive_entry_rdevminor "struct archive_entry *"
.Ft void
+.Fn archive_entry_set_dev "struct archive_entry *" "dev_t"
+.Ft void
+.Fn archive_entry_set_devmajor "struct archive_entry *" "dev_t"
+.Ft void
+.Fn archive_entry_set_devminor "struct archive_entry *" "dev_t"
+.Ft void
+.Fn archive_entry_set_filetype "struct archive_entry *" "unsigned int"
+.Ft void
.Fn archive_entry_set_fflags "struct archive_entry *" "unsigned long set" "unsigned long clear"
.Ft void
.Fn archive_entry_set_gid "struct archive_entry *" "gid_t"
@@ -171,14 +197,20 @@
.Ft void
.Fn archive_entry_set_hardlink "struct archive_entry *" "const char *"
.Ft void
+.Fn archive_entry_set_ino "struct archive_entry *" "unsigned long"
+.Ft void
.Fn archive_entry_set_link "struct archive_entry *" "const char *"
.Ft void
.Fn archive_entry_set_mode "struct archive_entry *" "mode_t"
.Ft void
.Fn archive_entry_set_mtime "struct archive_entry *" "time_t" "long nanos"
.Ft void
+.Fn archive_entry_set_nlink "struct archive_entry *" "unsigned int"
+.Ft void
.Fn archive_entry_set_pathname "struct archive_entry *" "const char *"
.Ft void
+.Fn archive_entry_set_rdev "struct archive_entry *" "dev_t"
+.Ft void
.Fn archive_entry_set_rdevmajor "struct archive_entry *" "dev_t"
.Ft void
.Fn archive_entry_set_rdevminor "struct archive_entry *" "dev_t"
diff --git a/lib/libarchive/archive_entry.c b/lib/libarchive/archive_entry.c
index 8309d4f..6123a6a 100644
--- a/lib/libarchive/archive_entry.c
+++ b/lib/libarchive/archive_entry.c
@@ -34,6 +34,9 @@ __FBSDID("$FreeBSD$");
#endif
#ifdef MAJOR_IN_MKDEV
#include <sys/mkdev.h>
+# if !defined makedev && (defined mkdev || defined _WIN32 || defined __WIN32__)
+# define makedev mkdev
+# endif
#else
#ifdef MAJOR_IN_SYSMACROS
#include <sys/sysmacros.h>
@@ -63,69 +66,14 @@ __FBSDID("$FreeBSD$");
#include <wchar.h>
#endif
-#ifndef HAVE_WCSCPY
-static wchar_t * wcscpy(wchar_t *s1, const wchar_t *s2)
-{
- wchar_t *dest = s1;
- while ((*s1 = *s2) != L'\0')
- ++s1, ++s2;
- return dest;
-}
-#endif
-#ifndef HAVE_WCSLEN
-static size_t wcslen(const wchar_t *s)
-{
- const wchar_t *p = s;
- while (*p != L'\0')
- ++p;
- return p - s;
-}
-#endif
-#ifndef HAVE_WMEMCMP
-/* Good enough for simple equality testing, but not for sorting. */
-#define wmemcmp(a,b,i) memcmp((a), (b), (i) * sizeof(wchar_t))
-#endif
-#ifndef HAVE_WMEMCPY
-#define wmemcpy(a,b,i) (wchar_t *)memcpy((a), (b), (i) * sizeof(wchar_t))
-#endif
-
#include "archive.h"
#include "archive_entry.h"
#include "archive_private.h"
+#include "archive_entry_private.h"
#undef max
#define max(a, b) ((a)>(b)?(a):(b))
-/*
- * Handle wide character (i.e., Unicode) and non-wide character
- * strings transparently.
- *
- */
-
-struct aes {
- const char *aes_mbs;
- char *aes_mbs_alloc;
- const wchar_t *aes_wcs;
- wchar_t *aes_wcs_alloc;
-};
-
-struct ae_acl {
- struct ae_acl *next;
- int type; /* E.g., access or default */
- int tag; /* E.g., user/group/other/mask */
- int permset; /* r/w/x bits */
- int id; /* uid/gid for user/group */
- struct aes name; /* uname/gname */
-};
-
-struct ae_xattr {
- struct ae_xattr *next;
-
- char *name;
- void *value;
- size_t size;
-};
-
static void aes_clean(struct aes *);
static void aes_copy(struct aes *dest, struct aes *src);
static const char * aes_get_mbs(struct aes *);
@@ -157,57 +105,32 @@ archive_entry_acl_add_entry_w_len(struct archive_entry *entry, int type,
int permset, int tag, int id, const wchar_t *name, size_t);
-/*
- * Description of an archive entry.
- *
- * Basically, this is a "struct stat" with a few text fields added in.
- *
- * TODO: Add "comment", "charset", and possibly other entries
- * that are supported by "pax interchange" format. However, GNU, ustar,
- * cpio, and other variants don't support these features, so they're not an
- * excruciatingly high priority right now.
- *
- * TODO: "pax interchange" format allows essentially arbitrary
- * key/value attributes to be attached to any entry. Supporting
- * such extensions may make this library useful for special
- * applications (e.g., a package manager could attach special
- * package-management attributes to each entry). There are tricky
- * API issues involved, so this is not going to happen until
- * there's a real demand for it.
- *
- * TODO: Design a good API for handling sparse files.
- */
-struct archive_entry {
- /*
- * Note that ae_stat.st_mode & S_IFMT can be 0!
- *
- * This occurs when the actual file type of the object is not
- * in the archive. For example, 'tar' archives store
- * hardlinks without marking the type of the underlying
- * object.
- */
- struct stat ae_stat;
+#ifndef HAVE_WCSCPY
+static wchar_t * wcscpy(wchar_t *s1, const wchar_t *s2)
+{
+ wchar_t *dest = s1;
+ while ((*s1 = *s2) != L'\0')
+ ++s1, ++s2;
+ return dest;
+}
+#endif
+#ifndef HAVE_WCSLEN
+static size_t wcslen(const wchar_t *s)
+{
+ const wchar_t *p = s;
+ while (*p != L'\0')
+ ++p;
+ return p - s;
+}
+#endif
+#ifndef HAVE_WMEMCMP
+/* Good enough for simple equality testing, but not for sorting. */
+#define wmemcmp(a,b,i) memcmp((a), (b), (i) * sizeof(wchar_t))
+#endif
+#ifndef HAVE_WMEMCPY
+#define wmemcpy(a,b,i) (wchar_t *)memcpy((a), (b), (i) * sizeof(wchar_t))
+#endif
- /*
- * Use aes here so that we get transparent mbs<->wcs conversions.
- */
- struct aes ae_fflags_text; /* Text fflags per fflagstostr(3) */
- unsigned long ae_fflags_set; /* Bitmap fflags */
- unsigned long ae_fflags_clear;
- struct aes ae_gname; /* Name of owning group */
- struct aes ae_hardlink; /* Name of target for hardlink */
- struct aes ae_pathname; /* Name of entry */
- struct aes ae_symlink; /* symlink contents */
- struct aes ae_uname; /* Name of owner */
-
- struct ae_acl *acl_head;
- struct ae_acl *acl_p;
- int acl_state; /* See acl_next for details. */
- wchar_t *acl_text_w;
-
- struct ae_xattr *xattr_head;
- struct ae_xattr *xattr_p;
-};
static void
aes_clean(struct aes *aes)
@@ -379,6 +302,7 @@ archive_entry_clear(struct archive_entry *entry)
aes_clean(&entry->ae_uname);
archive_entry_acl_clear(entry);
archive_entry_xattr_clear(entry);
+ free(entry->stat);
memset(entry, 0, sizeof(*entry));
return entry;
}
@@ -387,6 +311,8 @@ struct archive_entry *
archive_entry_clone(struct archive_entry *entry)
{
struct archive_entry *entry2;
+ struct ae_acl *ap, *ap2;
+ struct ae_xattr *xp;
/* Allocate new structure and copy over all of the fields. */
entry2 = (struct archive_entry *)malloc(sizeof(*entry2));
@@ -404,8 +330,24 @@ archive_entry_clone(struct archive_entry *entry)
aes_copy(&entry2->ae_symlink, &entry->ae_symlink);
aes_copy(&entry2->ae_uname, &entry->ae_uname);
- /* XXX TODO: Copy ACL data over as well. XXX */
- /* XXX TODO: Copy xattr data over as well. XXX */
+ /* Copy ACL data over. */
+ ap = entry->acl_head;
+ while (ap != NULL) {
+ ap2 = acl_new_entry(entry2,
+ ap->type, ap->permset, ap->tag, ap->id);
+ if (ap2 != NULL)
+ aes_copy(&ap2->name, &ap->name);
+ ap = ap->next;
+ }
+
+ /* Copy xattr data over. */
+ xp = entry->xattr_head;
+ while (xp != NULL) {
+ archive_entry_xattr_add_entry(entry2,
+ xp->name, xp->value, xp->size);
+ xp = xp->next;
+ }
+
return (entry2);
}
@@ -435,33 +377,59 @@ archive_entry_new(void)
time_t
archive_entry_atime(struct archive_entry *entry)
{
- return (entry->ae_stat.st_atime);
+ return (entry->ae_stat.aest_atime);
}
long
archive_entry_atime_nsec(struct archive_entry *entry)
{
- (void)entry; /* entry can be unused here. */
- return (ARCHIVE_STAT_ATIME_NANOS(&entry->ae_stat));
+ return (entry->ae_stat.aest_atime_nsec);
}
time_t
archive_entry_ctime(struct archive_entry *entry)
{
- return (entry->ae_stat.st_ctime);
+ return (entry->ae_stat.aest_ctime);
}
long
archive_entry_ctime_nsec(struct archive_entry *entry)
{
- (void)entry; /* entry can be unused here. */
- return (ARCHIVE_STAT_CTIME_NANOS(&entry->ae_stat));
+ return (entry->ae_stat.aest_ctime_nsec);
}
dev_t
archive_entry_dev(struct archive_entry *entry)
{
- return (entry->ae_stat.st_dev);
+ if (entry->ae_stat.aest_dev_is_broken_down)
+ return makedev(entry->ae_stat.aest_devmajor,
+ entry->ae_stat.aest_devminor);
+ else
+ return (entry->ae_stat.aest_dev);
+}
+
+dev_t
+archive_entry_devmajor(struct archive_entry *entry)
+{
+ if (entry->ae_stat.aest_dev_is_broken_down)
+ return (entry->ae_stat.aest_devmajor);
+ else
+ return major(entry->ae_stat.aest_dev);
+}
+
+dev_t
+archive_entry_devminor(struct archive_entry *entry)
+{
+ if (entry->ae_stat.aest_dev_is_broken_down)
+ return (entry->ae_stat.aest_devminor);
+ else
+ return minor(entry->ae_stat.aest_dev);
+}
+
+mode_t
+archive_entry_filetype(struct archive_entry *entry)
+{
+ return (AE_IFMT & entry->ae_stat.aest_mode);
}
void
@@ -507,7 +475,7 @@ archive_entry_fflags_text(struct archive_entry *entry)
gid_t
archive_entry_gid(struct archive_entry *entry)
{
- return (entry->ae_stat.st_gid);
+ return (entry->ae_stat.aest_gid);
}
const char *
@@ -537,26 +505,31 @@ archive_entry_hardlink_w(struct archive_entry *entry)
ino_t
archive_entry_ino(struct archive_entry *entry)
{
- return (entry->ae_stat.st_ino);
+ return (entry->ae_stat.aest_ino);
}
mode_t
archive_entry_mode(struct archive_entry *entry)
{
- return (entry->ae_stat.st_mode);
+ return (entry->ae_stat.aest_mode);
}
time_t
archive_entry_mtime(struct archive_entry *entry)
{
- return (entry->ae_stat.st_mtime);
+ return (entry->ae_stat.aest_mtime);
}
long
archive_entry_mtime_nsec(struct archive_entry *entry)
{
- (void)entry; /* entry can be unused here. */
- return (ARCHIVE_STAT_MTIME_NANOS(&entry->ae_stat));
+ return (entry->ae_stat.aest_mtime_nsec);
+}
+
+unsigned int
+archive_entry_nlink(struct archive_entry *entry)
+{
+ return (entry->ae_stat.aest_nlink);
}
const char *
@@ -574,31 +547,35 @@ archive_entry_pathname_w(struct archive_entry *entry)
dev_t
archive_entry_rdev(struct archive_entry *entry)
{
- return (entry->ae_stat.st_rdev);
+ if (entry->ae_stat.aest_rdev_is_broken_down)
+ return makedev(entry->ae_stat.aest_rdevmajor,
+ entry->ae_stat.aest_rdevminor);
+ else
+ return (entry->ae_stat.aest_rdev);
}
dev_t
archive_entry_rdevmajor(struct archive_entry *entry)
{
- return (major(entry->ae_stat.st_rdev));
+ if (entry->ae_stat.aest_rdev_is_broken_down)
+ return (entry->ae_stat.aest_rdevmajor);
+ else
+ return major(entry->ae_stat.aest_rdev);
}
dev_t
archive_entry_rdevminor(struct archive_entry *entry)
{
- return (minor(entry->ae_stat.st_rdev));
+ if (entry->ae_stat.aest_rdev_is_broken_down)
+ return (entry->ae_stat.aest_rdevminor);
+ else
+ return minor(entry->ae_stat.aest_rdev);
}
int64_t
archive_entry_size(struct archive_entry *entry)
{
- return (entry->ae_stat.st_size);
-}
-
-const struct stat *
-archive_entry_stat(struct archive_entry *entry)
-{
- return (&entry->ae_stat);
+ return (entry->ae_stat.aest_size);
}
const char *
@@ -616,7 +593,7 @@ archive_entry_symlink_w(struct archive_entry *entry)
uid_t
archive_entry_uid(struct archive_entry *entry)
{
- return (entry->ae_stat.st_uid);
+ return (entry->ae_stat.aest_uid);
}
const char *
@@ -635,14 +612,12 @@ archive_entry_uname_w(struct archive_entry *entry)
* Functions to set archive_entry properties.
*/
-/*
- * Note "copy" not "set" here. The "set" functions that accept a pointer
- * only store the pointer; they don't copy the underlying object.
- */
void
-archive_entry_copy_stat(struct archive_entry *entry, const struct stat *st)
+archive_entry_set_filetype(struct archive_entry *entry, unsigned int type)
{
- entry->ae_stat = *st;
+ entry->stat_valid = 0;
+ entry->ae_stat.aest_mode &= ~AE_IFMT;
+ entry->ae_stat.aest_mode |= AE_IFMT & type;
}
void
@@ -666,7 +641,8 @@ archive_entry_copy_fflags_text_w(struct archive_entry *entry,
void
archive_entry_set_gid(struct archive_entry *entry, gid_t g)
{
- entry->ae_stat.st_gid = g;
+ entry->stat_valid = 0;
+ entry->ae_stat.aest_gid = g;
}
void
@@ -682,6 +658,13 @@ archive_entry_copy_gname_w(struct archive_entry *entry, const wchar_t *name)
}
void
+archive_entry_set_ino(struct archive_entry *entry, unsigned long ino)
+{
+ entry->stat_valid = 0;
+ entry->ae_stat.aest_ino = ino;
+}
+
+void
archive_entry_set_hardlink(struct archive_entry *entry, const char *target)
{
aes_set_mbs(&entry->ae_hardlink, target);
@@ -702,15 +685,41 @@ archive_entry_copy_hardlink_w(struct archive_entry *entry, const wchar_t *target
void
archive_entry_set_atime(struct archive_entry *entry, time_t t, long ns)
{
- entry->ae_stat.st_atime = t;
- ARCHIVE_STAT_SET_ATIME_NANOS(&entry->ae_stat, ns);
+ entry->stat_valid = 0;
+ entry->ae_stat.aest_atime = t;
+ entry->ae_stat.aest_atime_nsec = ns;
}
void
archive_entry_set_ctime(struct archive_entry *entry, time_t t, long ns)
{
- entry->ae_stat.st_ctime = t;
- ARCHIVE_STAT_SET_CTIME_NANOS(&entry->ae_stat, ns);
+ entry->stat_valid = 0;
+ entry->ae_stat.aest_ctime = t;
+ entry->ae_stat.aest_ctime_nsec = ns;
+}
+
+void
+archive_entry_set_dev(struct archive_entry *entry, dev_t d)
+{
+ entry->stat_valid = 0;
+ entry->ae_stat.aest_dev_is_broken_down = 0;
+ entry->ae_stat.aest_dev = d;
+}
+
+void
+archive_entry_set_devmajor(struct archive_entry *entry, dev_t m)
+{
+ entry->stat_valid = 0;
+ entry->ae_stat.aest_dev_is_broken_down = 1;
+ entry->ae_stat.aest_devmajor = m;
+}
+
+void
+archive_entry_set_devminor(struct archive_entry *entry, dev_t m)
+{
+ entry->stat_valid = 0;
+ entry->ae_stat.aest_dev_is_broken_down = 1;
+ entry->ae_stat.aest_devminor = m;
}
/* Set symlink if symlink is already set, else set hardlink. */
@@ -727,14 +736,23 @@ archive_entry_set_link(struct archive_entry *entry, const char *target)
void
archive_entry_set_mode(struct archive_entry *entry, mode_t m)
{
- entry->ae_stat.st_mode = m;
+ entry->stat_valid = 0;
+ entry->ae_stat.aest_mode = m;
}
void
archive_entry_set_mtime(struct archive_entry *entry, time_t m, long ns)
{
- entry->ae_stat.st_mtime = m;
- ARCHIVE_STAT_SET_MTIME_NANOS(&entry->ae_stat, ns);
+ entry->stat_valid = 0;
+ entry->ae_stat.aest_mtime = m;
+ entry->ae_stat.aest_mtime_nsec = ns;
+}
+
+void
+archive_entry_set_nlink(struct archive_entry *entry, unsigned int nlink)
+{
+ entry->stat_valid = 0;
+ entry->ae_stat.aest_nlink = nlink;
}
void
@@ -756,27 +774,34 @@ archive_entry_copy_pathname_w(struct archive_entry *entry, const wchar_t *name)
}
void
-archive_entry_set_rdevmajor(struct archive_entry *entry, dev_t m)
+archive_entry_set_rdev(struct archive_entry *entry, dev_t m)
{
- dev_t d;
+ entry->stat_valid = 0;
+ entry->ae_stat.aest_rdev = m;
+ entry->ae_stat.aest_rdev_is_broken_down = 0;
+}
- d = entry->ae_stat.st_rdev;
- entry->ae_stat.st_rdev = makedev(major(m), minor(d));
+void
+archive_entry_set_rdevmajor(struct archive_entry *entry, dev_t m)
+{
+ entry->stat_valid = 0;
+ entry->ae_stat.aest_rdev_is_broken_down = 1;
+ entry->ae_stat.aest_rdevmajor = m;
}
void
archive_entry_set_rdevminor(struct archive_entry *entry, dev_t m)
{
- dev_t d;
-
- d = entry->ae_stat.st_rdev;
- entry->ae_stat.st_rdev = makedev(major(d), minor(m));
+ entry->stat_valid = 0;
+ entry->ae_stat.aest_rdev_is_broken_down = 1;
+ entry->ae_stat.aest_rdevminor = m;
}
void
archive_entry_set_size(struct archive_entry *entry, int64_t s)
{
- entry->ae_stat.st_size = s;
+ entry->stat_valid = 0;
+ entry->ae_stat.aest_size = s;
}
void
@@ -800,7 +825,8 @@ archive_entry_copy_symlink_w(struct archive_entry *entry, const wchar_t *linknam
void
archive_entry_set_uid(struct archive_entry *entry, uid_t u)
{
- entry->ae_stat.st_uid = u;
+ entry->stat_valid = 0;
+ entry->ae_stat.aest_uid = u;
}
void
@@ -904,16 +930,16 @@ acl_special(struct archive_entry *entry, int type, int permset, int tag)
if (type == ARCHIVE_ENTRY_ACL_TYPE_ACCESS) {
switch (tag) {
case ARCHIVE_ENTRY_ACL_USER_OBJ:
- entry->ae_stat.st_mode &= ~0700;
- entry->ae_stat.st_mode |= (permset & 7) << 6;
+ entry->ae_stat.aest_mode &= ~0700;
+ entry->ae_stat.aest_mode |= (permset & 7) << 6;
return (0);
case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
- entry->ae_stat.st_mode &= ~0070;
- entry->ae_stat.st_mode |= (permset & 7) << 3;
+ entry->ae_stat.aest_mode &= ~0070;
+ entry->ae_stat.aest_mode |= (permset & 7) << 3;
return (0);
case ARCHIVE_ENTRY_ACL_OTHER:
- entry->ae_stat.st_mode &= ~0007;
- entry->ae_stat.st_mode |= permset & 7;
+ entry->ae_stat.aest_mode &= ~0007;
+ entry->ae_stat.aest_mode |= permset & 7;
return (0);
}
}
@@ -1029,7 +1055,7 @@ archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type,
/*
* The acl_state is either zero (no entries available), -1
* (reading from list), or an entry type (retrieve that type
- * from ae_stat.st_mode).
+ * from ae_stat.aest_mode).
*/
if (entry->acl_state == 0)
return (ARCHIVE_WARN);
@@ -1038,19 +1064,19 @@ archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type,
if ((want_type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
switch (entry->acl_state) {
case ARCHIVE_ENTRY_ACL_USER_OBJ:
- *permset = (entry->ae_stat.st_mode >> 6) & 7;
+ *permset = (entry->ae_stat.aest_mode >> 6) & 7;
*type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
*tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
entry->acl_state = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
return (ARCHIVE_OK);
case ARCHIVE_ENTRY_ACL_GROUP_OBJ:
- *permset = (entry->ae_stat.st_mode >> 3) & 7;
+ *permset = (entry->ae_stat.aest_mode >> 3) & 7;
*type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
*tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
entry->acl_state = ARCHIVE_ENTRY_ACL_OTHER;
return (ARCHIVE_OK);
case ARCHIVE_ENTRY_ACL_OTHER:
- *permset = entry->ae_stat.st_mode & 7;
+ *permset = entry->ae_stat.aest_mode & 7;
*type = ARCHIVE_ENTRY_ACL_TYPE_ACCESS;
*tag = ARCHIVE_ENTRY_ACL_OTHER;
entry->acl_state = -1;
@@ -1139,13 +1165,13 @@ archive_entry_acl_text_w(struct archive_entry *entry, int flags)
count = 0;
if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL,
- entry->ae_stat.st_mode & 0700, -1);
+ entry->ae_stat.aest_mode & 0700, -1);
*wp++ = ',';
append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_GROUP_OBJ, NULL,
- entry->ae_stat.st_mode & 0070, -1);
+ entry->ae_stat.aest_mode & 0070, -1);
*wp++ = ',';
append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_OTHER, NULL,
- entry->ae_stat.st_mode & 0007, -1);
+ entry->ae_stat.aest_mode & 0007, -1);
count += 3;
ap = entry->acl_head;
diff --git a/lib/libarchive/archive_entry.h b/lib/libarchive/archive_entry.h
index 2604f86..043ddcf 100644
--- a/lib/libarchive/archive_entry.h
+++ b/lib/libarchive/archive_entry.h
@@ -28,7 +28,9 @@
#ifndef ARCHIVE_ENTRY_H_INCLUDED
#define ARCHIVE_ENTRY_H_INCLUDED
+#include <sys/types.h>
#include <stddef.h> /* for wchar_t */
+#include <time.h>
#include <unistd.h>
#ifdef __cplusplus
@@ -55,6 +57,17 @@ extern "C" {
struct archive_entry;
/*
+ * File-type constants. These are returned from archive_entry_filetype().
+ */
+#define AE_IFMT 0170000
+#define AE_IFREG 0100000
+#define AE_IFLNK 0120000
+#define AE_IFCHR 0020000
+#define AE_IFBLK 0060000
+#define AE_IFDIR 0040000
+#define AE_IFIFO 0010000
+
+/*
* Basic object manipulation
*/
@@ -73,6 +86,9 @@ long archive_entry_atime_nsec(struct archive_entry *);
time_t archive_entry_ctime(struct archive_entry *);
long archive_entry_ctime_nsec(struct archive_entry *);
dev_t archive_entry_dev(struct archive_entry *);
+dev_t archive_entry_devmajor(struct archive_entry *);
+dev_t archive_entry_devminor(struct archive_entry *);
+mode_t archive_entry_filetype(struct archive_entry *);
void archive_entry_fflags(struct archive_entry *,
unsigned long *set, unsigned long *clear);
const char *archive_entry_fflags_text(struct archive_entry *);
@@ -85,13 +101,13 @@ ino_t archive_entry_ino(struct archive_entry *);
mode_t archive_entry_mode(struct archive_entry *);
time_t archive_entry_mtime(struct archive_entry *);
long archive_entry_mtime_nsec(struct archive_entry *);
+unsigned int archive_entry_nlink(struct archive_entry *);
const char *archive_entry_pathname(struct archive_entry *);
const wchar_t *archive_entry_pathname_w(struct archive_entry *);
dev_t archive_entry_rdev(struct archive_entry *);
dev_t archive_entry_rdevmajor(struct archive_entry *);
dev_t archive_entry_rdevminor(struct archive_entry *);
int64_t archive_entry_size(struct archive_entry *);
-const struct stat *archive_entry_stat(struct archive_entry *);
const char *archive_entry_symlink(struct archive_entry *);
const wchar_t *archive_entry_symlink_w(struct archive_entry *);
uid_t archive_entry_uid(struct archive_entry *);
@@ -105,9 +121,12 @@ const wchar_t *archive_entry_uname_w(struct archive_entry *);
* In contrast, 'copy' functions do copy the object pointed to.
*/
-void archive_entry_copy_stat(struct archive_entry *, const struct stat *);
void archive_entry_set_atime(struct archive_entry *, time_t, long);
void archive_entry_set_ctime(struct archive_entry *, time_t, long);
+void archive_entry_set_dev(struct archive_entry *, dev_t);
+void archive_entry_set_devmajor(struct archive_entry *, dev_t);
+void archive_entry_set_devminor(struct archive_entry *, dev_t);
+void archive_entry_set_filetype(struct archive_entry *, unsigned int);
void archive_entry_set_fflags(struct archive_entry *,
unsigned long set, unsigned long clear);
/* Returns pointer to start of first invalid token, or NULL if none. */
@@ -120,12 +139,15 @@ void archive_entry_copy_gname_w(struct archive_entry *, const wchar_t *);
void archive_entry_set_hardlink(struct archive_entry *, const char *);
void archive_entry_copy_hardlink(struct archive_entry *, const char *);
void archive_entry_copy_hardlink_w(struct archive_entry *, const wchar_t *);
+void archive_entry_set_ino(struct archive_entry *, unsigned long);
void archive_entry_set_link(struct archive_entry *, const char *);
void archive_entry_set_mode(struct archive_entry *, mode_t);
void archive_entry_set_mtime(struct archive_entry *, time_t, long);
+void archive_entry_set_nlink(struct archive_entry *, unsigned int);
void archive_entry_set_pathname(struct archive_entry *, const char *);
void archive_entry_copy_pathname(struct archive_entry *, const char *);
void archive_entry_copy_pathname_w(struct archive_entry *, const wchar_t *);
+void archive_entry_set_rdev(struct archive_entry *, dev_t);
void archive_entry_set_rdevmajor(struct archive_entry *, dev_t);
void archive_entry_set_rdevminor(struct archive_entry *, dev_t);
void archive_entry_set_size(struct archive_entry *, int64_t);
@@ -137,6 +159,18 @@ void archive_entry_set_uname(struct archive_entry *, const char *);
void archive_entry_copy_uname_w(struct archive_entry *, const wchar_t *);
/*
+ * Routines to bulk copy fields to/from a platform-native "struct
+ * stat." Libarchive used to just store a struct stat inside of each
+ * archive_entry object, but this created issues when trying to
+ * manipulate archives on systems different than the ones they were
+ * created on.
+ *
+ * TODO: On Linux, provide both stat32 and stat64 versions of these functions.
+ */
+const struct stat *archive_entry_stat(struct archive_entry *);
+void archive_entry_copy_stat(struct archive_entry *, const struct stat *);
+
+/*
* ACL routines. This used to simply store and return text-format ACL
* strings, but that proved insufficient for a number of reasons:
* = clients need control over uname/uid and gname/gid mappings
diff --git a/lib/libarchive/archive_entry_copy_stat.c b/lib/libarchive/archive_entry_copy_stat.c
new file mode 100644
index 0000000..5b3d35e
--- /dev/null
+++ b/lib/libarchive/archive_entry_copy_stat.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 "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#include "archive_entry.h"
+
+void
+archive_entry_copy_stat(struct archive_entry *entry, const struct stat *st)
+{
+#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
+ archive_entry_set_atime(entry, st->st_atime, st->st_atimespec.tv_nsec);
+ archive_entry_set_ctime(entry, st->st_ctime, st->st_ctimespec.tv_nsec);
+ archive_entry_set_mtime(entry, st->st_mtime, st->st_mtimespec.tv_nsec);
+#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
+ archive_entry_set_atime(entry, st->st_atime, st->st_atim.tv_nsec);
+ archive_entry_set_ctime(entry, st->st_ctime, st->st_ctim.tv_nsec);
+ archive_entry_set_mtime(entry, st->st_mtime, st->st_mtim.tv_nsec);
+#else
+ archive_entry_set_atime(entry, st->st_atime, 0);
+ archive_entry_set_ctime(entry, st->st_ctime, 0);
+ archive_entry_set_mtime(entry, st->st_mtime, 0);
+#endif
+ archive_entry_set_dev(entry, st->st_dev);
+ archive_entry_set_gid(entry, st->st_gid);
+ archive_entry_set_uid(entry, st->st_uid);
+ archive_entry_set_ino(entry, st->st_ino);
+ archive_entry_set_nlink(entry, st->st_nlink);
+ archive_entry_set_rdev(entry, st->st_rdev);
+ archive_entry_set_size(entry, st->st_size);
+ archive_entry_set_mode(entry, st->st_mode);
+}
diff --git a/lib/libarchive/archive_entry_private.h b/lib/libarchive/archive_entry_private.h
new file mode 100644
index 0000000..34b8e26
--- /dev/null
+++ b/lib/libarchive/archive_entry_private.h
@@ -0,0 +1,155 @@
+/*-
+ * 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_ENTRY_PRIVATE_H_INCLUDED
+#define ARCHIVE_ENTRY_PRIVATE_H_INCLUDED
+
+/*
+ * Handle wide character (i.e., Unicode) and non-wide character
+ * strings transparently.
+ *
+ */
+
+struct aes {
+ const char *aes_mbs;
+ char *aes_mbs_alloc;
+ const wchar_t *aes_wcs;
+ wchar_t *aes_wcs_alloc;
+};
+
+struct ae_acl {
+ struct ae_acl *next;
+ int type; /* E.g., access or default */
+ int tag; /* E.g., user/group/other/mask */
+ int permset; /* r/w/x bits */
+ int id; /* uid/gid for user/group */
+ struct aes name; /* uname/gname */
+};
+
+struct ae_xattr {
+ struct ae_xattr *next;
+
+ char *name;
+ void *value;
+ size_t size;
+};
+
+/*
+ * Description of an archive entry.
+ *
+ * Basically, this is a "struct stat" with a few text fields added in.
+ *
+ * TODO: Add "comment", "charset", and possibly other entries
+ * that are supported by "pax interchange" format. However, GNU, ustar,
+ * cpio, and other variants don't support these features, so they're not an
+ * excruciatingly high priority right now.
+ *
+ * TODO: "pax interchange" format allows essentially arbitrary
+ * key/value attributes to be attached to any entry. Supporting
+ * such extensions may make this library useful for special
+ * applications (e.g., a package manager could attach special
+ * package-management attributes to each entry). There are tricky
+ * API issues involved, so this is not going to happen until
+ * there's a real demand for it.
+ *
+ * TODO: Design a good API for handling sparse files.
+ */
+struct archive_entry {
+ /*
+ * Note that ae_stat.st_mode & AE_IFMT can be 0!
+ *
+ * This occurs when the actual file type of the object is not
+ * in the archive. For example, 'tar' archives store
+ * hardlinks without marking the type of the underlying
+ * object.
+ */
+
+ /*
+ * Read archive_entry_copy_stat.c for an explanation of why I
+ * don't just use "struct stat" instead of "struct aest" here
+ * and why I have this odd pointer to a separately-allocated
+ * struct stat.
+ */
+ void *stat;
+ int stat_valid; /* Set to 0 whenever a field in aest changes. */
+
+ struct aest {
+ int64_t aest_atime;
+ uint32_t aest_atime_nsec;
+ int64_t aest_ctime;
+ uint32_t aest_ctime_nsec;
+ int64_t aest_mtime;
+ uint32_t aest_mtime_nsec;
+ gid_t aest_gid;
+ ino_t aest_ino;
+ mode_t aest_mode;
+ uint32_t aest_nlink;
+ uint64_t aest_size;
+ uid_t aest_uid;
+ /*
+ * Because converting between device codes and
+ * major/minor values is platform-specific and
+ * inherently a bit risky, we only do that conversion
+ * lazily. That way, we will do a better job of
+ * preserving information in those cases where no
+ * conversion is actually required.
+ */
+ int aest_dev_is_broken_down;
+ dev_t aest_dev;
+ dev_t aest_devmajor;
+ dev_t aest_devminor;
+ int aest_rdev_is_broken_down;
+ dev_t aest_rdev;
+ dev_t aest_rdevmajor;
+ dev_t aest_rdevminor;
+ } ae_stat;
+
+
+
+ /*
+ * Use aes here so that we get transparent mbs<->wcs conversions.
+ */
+ struct aes ae_fflags_text; /* Text fflags per fflagstostr(3) */
+ unsigned long ae_fflags_set; /* Bitmap fflags */
+ unsigned long ae_fflags_clear;
+ struct aes ae_gname; /* Name of owning group */
+ struct aes ae_hardlink; /* Name of target for hardlink */
+ struct aes ae_pathname; /* Name of entry */
+ struct aes ae_symlink; /* symlink contents */
+ struct aes ae_uname; /* Name of owner */
+
+ struct ae_acl *acl_head;
+ struct ae_acl *acl_p;
+ int acl_state; /* See acl_next for details. */
+ wchar_t *acl_text_w;
+
+ struct ae_xattr *xattr_head;
+ struct ae_xattr *xattr_p;
+};
+
+
+#endif /* ARCHIVE_ENTRY_PRIVATE_H_INCLUDED */
diff --git a/lib/libarchive/archive_entry_stat.c b/lib/libarchive/archive_entry_stat.c
new file mode 100644
index 0000000..d06ee2c
--- /dev/null
+++ b/lib/libarchive/archive_entry_stat.c
@@ -0,0 +1,100 @@
+/*-
+ * 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_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#include "archive_entry.h"
+#include "archive_entry_private.h"
+
+const struct stat *
+archive_entry_stat(struct archive_entry *entry)
+{
+ struct stat *st;
+ if (entry->stat == NULL) {
+ entry->stat = malloc(sizeof(*st));
+ if (entry->stat == NULL)
+ return (NULL);
+ entry->stat_valid = 0;
+ }
+
+ /*
+ * If none of the underlying fields have been changed, we
+ * don't need to regenerate. In theory, we could use a bitmap
+ * here to flag only those items that have changed, but the
+ * extra complexity probably isn't worth it. It will be very
+ * rare for anyone to change just one field then request a new
+ * stat structure.
+ */
+ if (entry->stat_valid)
+ return (entry->stat);
+
+ st = entry->stat;
+ /*
+ * Use the public interfaces to extract items, so that
+ * the appropriate conversions get invoked.
+ */
+ st->st_atime = archive_entry_atime(entry);
+ st->st_ctime = archive_entry_ctime(entry);
+ st->st_mtime = archive_entry_mtime(entry);
+ st->st_dev = archive_entry_dev(entry);
+ st->st_gid = archive_entry_gid(entry);
+ st->st_uid = archive_entry_uid(entry);
+ st->st_ino = archive_entry_ino(entry);
+ st->st_nlink = archive_entry_nlink(entry);
+ st->st_rdev = archive_entry_rdev(entry);
+ st->st_size = archive_entry_size(entry);
+ st->st_mode = archive_entry_mode(entry);
+
+ /*
+ * On systems that support high-res timestamps, copy that
+ * information into struct stat.
+ */
+#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
+ st->st_atimespec.tv_nsec = archive_entry_atime_nsec(entry);
+ st->st_ctimespec.tv_nsec = archive_entry_ctime_nsec(entry);
+ st->st_mtimespec.tv_nsec = archive_entry_mtime_nsec(entry);
+#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
+ st->st_atim.tv_nsec = archive_entry_atime_nsec(entry);
+ st->st_ctim.tv_nsec = archive_entry_ctime_nsec(entry);
+ st->st_mtim.tv_nsec = archive_entry_mtime_nsec(entry);
+#endif
+
+ /*
+ * TODO: On Linux, store 32 or 64 here depending on whether
+ * the cached stat structure is a stat32 or a stat64. This
+ * will allow us to support both variants interchangably.
+ */
+ entry->stat_valid = 1;
+
+ return (st);
+}
diff --git a/lib/libarchive/archive_platform.h b/lib/libarchive/archive_platform.h
index c9317cc..cd48a83 100644
--- a/lib/libarchive/archive_platform.h
+++ b/lib/libarchive/archive_platform.h
@@ -122,33 +122,4 @@
#define ARCHIVE_ERRNO_MISC (-1)
#endif
-/* Select the best way to set/get hi-res timestamps. */
-#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
-/* FreeBSD uses "timespec" members. */
-#define ARCHIVE_STAT_ATIME_NANOS(st) (st)->st_atimespec.tv_nsec
-#define ARCHIVE_STAT_CTIME_NANOS(st) (st)->st_ctimespec.tv_nsec
-#define ARCHIVE_STAT_MTIME_NANOS(st) (st)->st_mtimespec.tv_nsec
-#define ARCHIVE_STAT_SET_ATIME_NANOS(st, n) (st)->st_atimespec.tv_nsec = (n)
-#define ARCHIVE_STAT_SET_CTIME_NANOS(st, n) (st)->st_ctimespec.tv_nsec = (n)
-#define ARCHIVE_STAT_SET_MTIME_NANOS(st, n) (st)->st_mtimespec.tv_nsec = (n)
-#else
-#if HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
-/* Linux uses "tim" members. */
-#define ARCHIVE_STAT_ATIME_NANOS(pstat) (pstat)->st_atim.tv_nsec
-#define ARCHIVE_STAT_CTIME_NANOS(pstat) (pstat)->st_ctim.tv_nsec
-#define ARCHIVE_STAT_MTIME_NANOS(pstat) (pstat)->st_mtim.tv_nsec
-#define ARCHIVE_STAT_SET_ATIME_NANOS(st, n) (st)->st_atim.tv_nsec = (n)
-#define ARCHIVE_STAT_SET_CTIME_NANOS(st, n) (st)->st_ctim.tv_nsec = (n)
-#define ARCHIVE_STAT_SET_MTIME_NANOS(st, n) (st)->st_mtim.tv_nsec = (n)
-#else
-/* If we can't find a better way, just use stubs. */
-#define ARCHIVE_STAT_ATIME_NANOS(pstat) 0
-#define ARCHIVE_STAT_CTIME_NANOS(pstat) 0
-#define ARCHIVE_STAT_MTIME_NANOS(pstat) 0
-#define ARCHIVE_STAT_SET_ATIME_NANOS(st, n) ((void)(n))
-#define ARCHIVE_STAT_SET_CTIME_NANOS(st, n) ((void)(n))
-#define ARCHIVE_STAT_SET_MTIME_NANOS(st, n) ((void)(n))
-#endif
-#endif
-
#endif /* !ARCHIVE_H_INCLUDED */
diff --git a/lib/libarchive/archive_read.3 b/lib/libarchive/archive_read.3
index 579c6f2..c4fdaa1 100644
--- a/lib/libarchive/archive_read.3
+++ b/lib/libarchive/archive_read.3
@@ -34,6 +34,7 @@
.Nm archive_read_support_compression_compress ,
.Nm archive_read_support_compression_gzip ,
.Nm archive_read_support_compression_none ,
+.Nm archive_read_support_compression_program ,
.Nm archive_read_support_format_all ,
.Nm archive_read_support_format_cpio ,
.Nm archive_read_support_format_empty ,
@@ -74,6 +75,8 @@
.Ft int
.Fn archive_read_support_compression_none "struct archive *"
.Ft int
+.Fn archive_read_support_compression_program "struct archive *" "const char *cmd"
+.Ft int
.Fn archive_read_support_format_all "struct archive *"
.Ft int
.Fn archive_read_support_format_cpio "struct archive *"
@@ -142,6 +145,11 @@ is always enabled by default.
For convenience,
.Fn archive_read_support_compression_all
enables all available decompression code.
+.It Fn archive_read_support_compression_program
+Data is fed through the specified external program before being dearchived.
+Note that this disables automatic detection of the compression format,
+so it makes no sense to specify this in conjunction with any other
+decompression option.
.It Fn archive_read_support_format_all , Fn archive_read_support_format_cpio , Fn archive_read_support_format_empty , Fn archive_read_support_format_iso9660 , Fn archive_read_support_format_tar, Fn archive_read_support_format_zip
Enables support---including auto-detection code---for the
specified archive format.
diff --git a/lib/libarchive/archive_read.c b/lib/libarchive/archive_read.c
index 4a62a99..e0763f2 100644
--- a/lib/libarchive/archive_read.c
+++ b/lib/libarchive/archive_read.c
@@ -53,7 +53,7 @@ __FBSDID("$FreeBSD$");
#include "archive_private.h"
#include "archive_read_private.h"
-static int choose_decompressor(struct archive_read *, const void*, size_t);
+static void choose_decompressor(struct archive_read *, const void*, size_t);
static int choose_format(struct archive_read *);
static off_t dummy_skip(struct archive_read *, off_t);
@@ -131,7 +131,6 @@ archive_read_open2(struct archive *_a, void *client_data,
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");
@@ -163,7 +162,7 @@ archive_read_open2(struct archive *_a, void *client_data,
}
}
- /* Read first block now for format detection. */
+ /* Read first block now for compress format detection. */
bytes_read = (client_reader)(&a->archive, client_data, &buffer);
if (bytes_read < 0) {
@@ -182,12 +181,12 @@ archive_read_open2(struct archive *_a, void *client_data,
a->client_data = client_data;
/* Select a decompression routine. */
- high_bidder = choose_decompressor(a, buffer, (size_t)bytes_read);
- if (high_bidder < 0)
+ choose_decompressor(a, buffer, (size_t)bytes_read);
+ if (a->decompressor == NULL)
return (ARCHIVE_FATAL);
/* Initialize decompression routine with the first block of data. */
- e = (a->decompressors[high_bidder].init)(a, buffer, (size_t)bytes_read);
+ e = (a->decompressor->init)(a, buffer, (size_t)bytes_read);
if (e == ARCHIVE_OK)
a->archive.state = ARCHIVE_STATE_HEADER;
@@ -196,8 +195,8 @@ archive_read_open2(struct archive *_a, void *client_data,
* If the decompressor didn't register a skip function, provide a
* dummy compression-layer skip function.
*/
- if (a->compression_skip == NULL)
- a->compression_skip = dummy_skip;
+ if (a->decompressor->skip == NULL)
+ a->decompressor->skip = dummy_skip;
return (e);
}
@@ -206,33 +205,37 @@ archive_read_open2(struct archive *_a, void *client_data,
* Allow each registered decompression routine to bid on whether it
* wants to handle this stream. Return index of winning bidder.
*/
-static int
+static void
choose_decompressor(struct archive_read *a,
const void *buffer, size_t bytes_read)
{
- int decompression_slots, i, bid, best_bid, best_bid_slot;
+ int decompression_slots, i, bid, best_bid;
+ struct decompressor_t *decompressor, *best_decompressor;
decompression_slots = sizeof(a->decompressors) /
sizeof(a->decompressors[0]);
- best_bid = -1;
- best_bid_slot = -1;
+ best_bid = 0;
+ a->decompressor = NULL;
+ best_decompressor = NULL;
+ decompressor = a->decompressors;
for (i = 0; i < decompression_slots; i++) {
- if (a->decompressors[i].bid) {
- bid = (a->decompressors[i].bid)(buffer, bytes_read);
- if ((bid > best_bid) || (best_bid_slot < 0)) {
+ if (decompressor->bid) {
+ bid = (decompressor->bid)(buffer, bytes_read);
+ if (bid > best_bid || best_decompressor == NULL) {
best_bid = bid;
- best_bid_slot = i;
+ best_decompressor = decompressor;
}
}
+ decompressor ++;
}
/*
* There were no bidders; this is a serious programmer error
* and demands a quick and definitive abort.
*/
- if (best_bid_slot < 0)
+ if (best_decompressor == NULL)
__archive_errx(1, "No decompressors were registered; you "
"must call at least one "
"archive_read_support_compression_XXX function in order "
@@ -245,10 +248,11 @@ choose_decompressor(struct archive_read *a,
if (best_bid < 1) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Unrecognized archive format");
- return (ARCHIVE_FATAL);
+ return;
}
- return (best_bid_slot);
+ /* Record the best decompressor for this stream. */
+ a->decompressor = best_decompressor;
}
/*
@@ -263,7 +267,7 @@ dummy_skip(struct archive_read * a, off_t request)
off_t bytes_skipped;
for (bytes_skipped = 0; request > 0;) {
- bytes_read = (a->compression_read_ahead)(a, &dummy_buffer, 1);
+ bytes_read = (a->decompressor->read_ahead)(a, &dummy_buffer, 1);
if (bytes_read < 0)
return (bytes_read);
if (bytes_read == 0) {
@@ -275,7 +279,7 @@ dummy_skip(struct archive_read * a, off_t request)
}
if (bytes_read > request)
bytes_read = (ssize_t)request;
- (a->compression_read_consume)(a, (size_t)bytes_read);
+ (a->decompressor->consume)(a, (size_t)bytes_read);
request -= bytes_read;
bytes_skipped += bytes_read;
}
@@ -326,7 +330,6 @@ archive_read_next_header(struct archive *_a, struct archive_entry **entryp)
return (ARCHIVE_FATAL);
}
a->format = &(a->formats[slot]);
- a->pformat_data = &(a->format->format_data);
ret = (a->format->read_header)(a, entry);
/*
@@ -377,7 +380,6 @@ choose_format(struct archive_read *a)
a->format = &(a->formats[0]);
for (i = 0; i < slots; i++, a->format++) {
if (a->format->bid) {
- a->pformat_data = &(a->format->format_data);
bid = (a->format->bid)(a);
if (bid == ARCHIVE_FATAL)
return (ARCHIVE_FATAL);
@@ -591,6 +593,7 @@ archive_read_close(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
int r = ARCHIVE_OK, r1 = ARCHIVE_OK;
+ size_t i, n;
__archive_check_magic(&a->archive, ARCHIVE_READ_MAGIC,
ARCHIVE_STATE_ANY, "archive_read_close");
@@ -600,11 +603,21 @@ archive_read_close(struct archive *_a)
if (a->cleanup_archive_extract != NULL)
r = (a->cleanup_archive_extract)(a);
- /* TODO: Finish the format processing. */
+ /* TODO: Clean up the formatters. */
+
+ /* Clean up the decompressors. */
+ n = sizeof(a->decompressors)/sizeof(a->decompressors[0]);
+ for (i = 0; i < n; i++) {
+ if (a->decompressors[i].finish != NULL) {
+ r1 = (a->decompressors[i].finish)(a);
+ if (r1 < r)
+ r = r1;
+ }
+ }
- /* Close the input machinery. */
- if (a->compression_finish != NULL) {
- r1 = (a->compression_finish)(a);
+ /* Close the client stream. */
+ if (a->client_closer != NULL) {
+ r1 = ((a->client_closer)(&a->archive, a->client_data));
if (r1 < r)
r = r1;
}
@@ -636,7 +649,7 @@ archive_read_finish(struct archive *_a)
/* Cleanup format-specific data. */
slots = sizeof(a->formats) / sizeof(a->formats[0]);
for (i = 0; i < slots; i++) {
- a->pformat_data = &(a->formats[i].format_data);
+ a->format = &(a->formats[i]);
if (a->formats[i].cleanup)
(a->formats[i].cleanup)(a);
}
@@ -683,7 +696,7 @@ __archive_read_register_format(struct archive_read *a,
a->formats[i].read_data = read_data;
a->formats[i].read_data_skip = read_data_skip;
a->formats[i].cleanup = cleanup;
- a->formats[i].format_data = format_data;
+ a->formats[i].data = format_data;
return (ARCHIVE_OK);
}
}
@@ -696,7 +709,7 @@ __archive_read_register_format(struct archive_read *a,
* Used internally by decompression routines to register their bid and
* initialization functions.
*/
-int
+struct decompressor_t *
__archive_read_register_compression(struct archive_read *a,
int (*bid)(const void *, size_t),
int (*init)(struct archive_read *, const void *, size_t))
@@ -711,14 +724,14 @@ __archive_read_register_compression(struct archive_read *a,
for (i = 0; i < number_slots; i++) {
if (a->decompressors[i].bid == bid)
- return (ARCHIVE_OK); /* We've already installed */
+ return (a->decompressors + i);
if (a->decompressors[i].bid == NULL) {
a->decompressors[i].bid = bid;
a->decompressors[i].init = init;
- return (ARCHIVE_OK);
+ return (a->decompressors + i);
}
}
__archive_errx(1, "Not enough slots for compression registration");
- return (ARCHIVE_FATAL); /* Never actually executed. */
+ return (NULL); /* Never actually executed. */
}
diff --git a/lib/libarchive/archive_read_extract.c b/lib/libarchive/archive_read_extract.c
index 464ebe9..c69c34f 100644
--- a/lib/libarchive/archive_read_extract.c
+++ b/lib/libarchive/archive_read_extract.c
@@ -99,9 +99,7 @@ archive_read_extract(struct archive *_a, struct archive_entry *entry, int flags)
r = ARCHIVE_WARN;
if (r != ARCHIVE_OK)
/* If _write_header failed, copy the error. */
- archive_set_error(&a->archive,
- archive_errno(extract->ad),
- "%s", archive_error_string(extract->ad));
+ archive_copy_error(&a->archive, extract->ad);
else
/* Otherwise, pour data into the entry. */
r = copy_data(_a, a->extract->ad);
@@ -110,9 +108,7 @@ archive_read_extract(struct archive *_a, struct archive_entry *entry, int flags)
r2 = ARCHIVE_WARN;
/* 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));
+ archive_copy_error(&a->archive, extract->ad);
/* Use the worst error return. */
if (r2 < r)
r = r2;
diff --git a/lib/libarchive/archive_read_private.h b/lib/libarchive/archive_read_private.h
index 64844d7..f9b1749 100644
--- a/lib/libarchive/archive_read_private.h
+++ b/lib/libarchive/archive_read_private.h
@@ -86,33 +86,35 @@ struct archive_read {
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.
+ * Decompressors have a very specific lifecycle:
+ * public setup function initializes a slot in this table
+ * 'config' holds minimal configuration data
+ * bid() examines a block of data and returns a bid [1]
+ * init() is called for successful bidder
+ * 'data' is initialized by init()
+ * read() returns a pointer to the next block of data
+ * consume() indicates how much data is used
+ * skip() ignores bytes of data
+ * finish() cleans up and frees 'data' and 'config'
+ *
+ * [1] General guideline: bid the number of bits that you actually
+ * test, e.g., 16 if you test a 2-byte magic value.
*/
- struct {
+ struct decompressor_t {
+ void *config;
+ void *data;
int (*bid)(const void *buff, size_t);
- int (*init)(struct archive_read *, const void *buff, size_t);
+ int (*init)(struct archive_read *,
+ const void *buff, size_t);
+ int (*finish)(struct archive_read *);
+ ssize_t (*read_ahead)(struct archive_read *,
+ const void **, size_t);
+ ssize_t (*consume)(struct archive_read *, size_t);
+ off_t (*skip)(struct archive_read *, off_t);
} decompressors[4];
- /* Read/write data stream (with compression). */
- void *compression_data; /* Data for (de)compressor. */
- int (*compression_finish)(struct archive_read *);
- /*
- * 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);
+ /* Pointer to current decompressor. */
+ struct decompressor_t *decompressor;
/*
* Format detection is mostly the same as compression
@@ -130,27 +132,16 @@ struct archive_read {
*/
struct archive_format_descriptor {
+ void *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 *);
- 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.
*/
@@ -177,7 +168,8 @@ int __archive_read_register_format(struct archive_read *a,
int (*read_data_skip)(struct archive_read *),
int (*cleanup)(struct archive_read *));
-int __archive_read_register_compression(struct archive_read *a,
+struct decompressor_t
+ *__archive_read_register_compression(struct archive_read *a,
int (*bid)(const void *, size_t),
int (*init)(struct archive_read *, const void *, size_t));
diff --git a/lib/libarchive/archive_read_support_compression_bzip2.c b/lib/libarchive/archive_read_support_compression_bzip2.c
index 71fd4bb..ec39981 100644
--- a/lib/libarchive/archive_read_support_compression_bzip2.c
+++ b/lib/libarchive/archive_read_support_compression_bzip2.c
@@ -55,6 +55,7 @@ struct private_data {
size_t uncompressed_buffer_size;
char *read_next;
int64_t total_out;
+ char eof; /* True = found end of compressed data. */
};
static int finish(struct archive_read *);
@@ -63,7 +64,7 @@ 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. */
+/* These two functions are defined even if we lack the library. See below. */
static int bid(const void *, size_t);
static int init(struct archive_read *, const void *, size_t);
@@ -71,7 +72,9 @@ int
archive_read_support_compression_bzip2(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
- return (__archive_read_register_compression(a, bid, init));
+ if (__archive_read_register_compression(a, bid, init) != NULL)
+ return (ARCHIVE_OK);
+ return (ARCHIVE_FATAL);
}
/*
@@ -131,9 +134,9 @@ bid(const void *buff, size_t len)
#ifndef HAVE_BZLIB_H
/*
- * If we don't have bzlib on this system, we can't actually do the
- * decompression. We can, however, still detect bzip2-compressed
- * archives and emit a useful message.
+ * If we don't have the library on this system, we can't actually do the
+ * decompression. We can, however, still detect compressed archives
+ * and emit a useful message.
*/
static int
init(struct archive_read *a, const void *buff, size_t n)
@@ -194,10 +197,10 @@ init(struct archive_read *a, const void *buff, size_t n)
state->stream.next_in = (char *)(uintptr_t)(const void *)buff;
state->stream.avail_in = n;
- a->compression_read_ahead = read_ahead;
- a->compression_read_consume = read_consume;
- a->compression_skip = NULL; /* not supported */
- a->compression_finish = finish;
+ a->decompressor->read_ahead = read_ahead;
+ a->decompressor->consume = read_consume;
+ a->decompressor->skip = NULL; /* not supported */
+ a->decompressor->finish = finish;
/* Initialize compression library. */
ret = BZ2_bzDecompressInit(&(state->stream),
@@ -212,7 +215,7 @@ init(struct archive_read *a, const void *buff, size_t n)
}
if (ret == BZ_OK) {
- a->compression_data = state;
+ a->decompressor->data = state;
return (ARCHIVE_OK);
}
@@ -231,7 +234,7 @@ init(struct archive_read *a, const void *buff, size_t n)
"invalid setup parameter");
break;
case BZ_MEM_ERROR:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ archive_set_error(&a->archive, ENOMEM,
"Internal error initializing compression library: "
"out of memory");
break;
@@ -256,7 +259,7 @@ read_ahead(struct archive_read *a, const void **p, size_t min)
size_t read_avail, was_avail;
int ret;
- state = (struct private_data *)a->compression_data;
+ state = (struct private_data *)a->decompressor->data;
if (!a->client_reader) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"No read callback is registered? "
@@ -278,8 +281,10 @@ read_ahead(struct archive_read *a, const void **p, size_t min)
while (read_avail < min && /* Haven't satisfied min. */
read_avail < state->uncompressed_buffer_size) { /* !full */
was_avail = read_avail;
- if ((ret = drive_decompressor(a, state)) != ARCHIVE_OK)
+ if ((ret = drive_decompressor(a, state)) < ARCHIVE_OK)
return (ret);
+ if (ret == ARCHIVE_EOF)
+ break; /* Break on EOF even if we haven't met min. */
read_avail = state->stream.next_out - state->read_next;
if (was_avail == read_avail) /* No progress? */
break;
@@ -297,7 +302,7 @@ read_consume(struct archive_read *a, size_t n)
{
struct private_data *state;
- state = (struct private_data *)a->compression_data;
+ state = (struct private_data *)a->decompressor->data;
a->archive.file_position += n;
state->read_next += n;
if (state->read_next > state->stream.next_out)
@@ -315,7 +320,7 @@ finish(struct archive_read *a)
struct private_data *state;
int ret;
- state = (struct private_data *)a->compression_data;
+ state = (struct private_data *)a->decompressor->data;
ret = ARCHIVE_OK;
switch (BZ2_bzDecompressEnd(&(state->stream))) {
case BZ_OK:
@@ -330,10 +335,7 @@ finish(struct archive_read *a)
free(state->uncompressed_buffer);
free(state);
- a->compression_data = NULL;
- if (a->client_closer != NULL)
- (a->client_closer)(&a->archive, a->client_data);
-
+ a->decompressor->data = NULL;
return (ret);
}
@@ -349,6 +351,8 @@ drive_decompressor(struct archive_read *a, struct private_data *state)
char *output;
const void *read_buf;
+ if (state->eof)
+ return (ARCHIVE_EOF);
total_decompressed = 0;
for (;;) {
if (state->stream.avail_in == 0) {
@@ -390,6 +394,7 @@ drive_decompressor(struct archive_read *a, struct private_data *state)
return (ARCHIVE_OK);
break;
case BZ_STREAM_END: /* Found end of stream. */
+ state->eof = 1;
return (ARCHIVE_OK);
default:
/* Any other return value is an error. */
diff --git a/lib/libarchive/archive_read_support_compression_compress.c b/lib/libarchive/archive_read_support_compression_compress.c
index 9bd1765..f45b7cd 100644
--- a/lib/libarchive/archive_read_support_compression_compress.c
+++ b/lib/libarchive/archive_read_support_compression_compress.c
@@ -145,7 +145,9 @@ int
archive_read_support_compression_compress(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
- return (__archive_read_register_compression(a, bid, init));
+ if (__archive_read_register_compression(a, bid, init) != NULL)
+ return (ARCHIVE_OK);
+ return (ARCHIVE_FATAL);
}
/*
@@ -197,10 +199,10 @@ init(struct archive_read *a, const void *buff, size_t n)
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;
- a->compression_skip = NULL; /* not supported */
- a->compression_finish = finish;
+ a->decompressor->read_ahead = read_ahead;
+ a->decompressor->consume = read_consume;
+ a->decompressor->skip = NULL; /* not supported */
+ a->decompressor->finish = finish;
state = (struct private_data *)malloc(sizeof(*state));
if (state == NULL) {
@@ -210,7 +212,7 @@ init(struct archive_read *a, const void *buff, size_t n)
return (ARCHIVE_FATAL);
}
memset(state, 0, sizeof(*state));
- a->compression_data = state;
+ a->decompressor->data = state;
state->uncompressed_buffer_size = 64 * 1024;
state->uncompressed_buffer = malloc(state->uncompressed_buffer_size);
@@ -278,7 +280,7 @@ read_ahead(struct archive_read *a, const void **p, size_t min)
size_t read_avail;
int ret;
- state = (struct private_data *)a->compression_data;
+ state = (struct private_data *)a->decompressor->data;
if (!a->client_reader) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"No read callback is registered? "
@@ -331,7 +333,7 @@ read_consume(struct archive_read *a, size_t n)
{
struct private_data *state;
- state = (struct private_data *)a->compression_data;
+ state = (struct private_data *)a->decompressor->data;
a->archive.file_position += n;
state->read_next += n;
if (state->read_next > state->next_out)
@@ -349,7 +351,7 @@ finish(struct archive_read *a)
struct private_data *state;
int ret = ARCHIVE_OK;
- state = (struct private_data *)a->compression_data;
+ state = (struct private_data *)a->decompressor->data;
if (state != NULL) {
if (state->uncompressed_buffer != NULL)
@@ -357,10 +359,7 @@ finish(struct archive_read *a)
free(state);
}
- a->compression_data = NULL;
- if (a->client_closer != NULL)
- ret = (a->client_closer)(&a->archive, a->client_data);
-
+ a->decompressor->data = NULL;
return (ret);
}
diff --git a/lib/libarchive/archive_read_support_compression_gzip.c b/lib/libarchive/archive_read_support_compression_gzip.c
index 751fffc..72afbd1 100644
--- a/lib/libarchive/archive_read_support_compression_gzip.c
+++ b/lib/libarchive/archive_read_support_compression_gzip.c
@@ -57,6 +57,7 @@ struct private_data {
int64_t total_out;
unsigned long crc;
char header_done;
+ char eof; /* True = found end of compressed data. */
};
static int finish(struct archive_read *);
@@ -65,7 +66,7 @@ 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. */
+/* These two functions are defined even if we lack the library. See below. */
static int bid(const void *, size_t);
static int init(struct archive_read *, const void *, size_t);
@@ -73,7 +74,9 @@ int
archive_read_support_compression_gzip(struct archive *_a)
{
struct archive_read *a = (struct archive_read *)_a;
- return (__archive_read_register_compression(a, bid, init));
+ if (__archive_read_register_compression(a, bid, init) != NULL)
+ return (ARCHIVE_OK);
+ return (ARCHIVE_FATAL);
}
/*
@@ -132,9 +135,9 @@ bid(const void *buff, size_t len)
#ifndef HAVE_ZLIB_H
/*
- * If we don't have zlib on this system, we can't actually do the
- * decompression. We can, however, still detect gzip-compressed
- * archives and emit a useful message.
+ * If we don't have the library on this system, we can't actually do the
+ * decompression. We can, however, still detect compressed archives
+ * and emit a useful message.
*/
static int
init(struct archive_read *a, const void *buff, size_t n)
@@ -198,10 +201,10 @@ init(struct archive_read *a, const void *buff, size_t n)
state->stream.next_in = (Bytef *)(uintptr_t)(const void *)buff;
state->stream.avail_in = n;
- a->compression_read_ahead = read_ahead;
- a->compression_read_consume = read_consume;
- a->compression_skip = NULL; /* not supported */
- a->compression_finish = finish;
+ a->decompressor->read_ahead = read_ahead;
+ a->decompressor->consume = read_consume;
+ a->decompressor->skip = NULL; /* not supported */
+ a->decompressor->finish = finish;
/*
* TODO: Do I need to parse the gzip header before calling
@@ -217,7 +220,7 @@ init(struct archive_read *a, const void *buff, size_t n)
ret = inflateInit2(&(state->stream),
-15 /* Don't check for zlib header */);
if (ret == Z_OK) {
- a->compression_data = state;
+ a->decompressor->data = state;
return (ARCHIVE_OK);
}
@@ -261,7 +264,7 @@ read_ahead(struct archive_read *a, const void **p, size_t min)
size_t read_avail, was_avail;
int ret;
- state = (struct private_data *)a->compression_data;
+ state = (struct private_data *)a->decompressor->data;
if (!a->client_reader) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"No read callback is registered? "
@@ -283,8 +286,10 @@ read_ahead(struct archive_read *a, const void **p, size_t min)
while (read_avail < min && /* Haven't satisfied min. */
read_avail < state->uncompressed_buffer_size) { /* !full */
was_avail = read_avail;
- if ((ret = drive_decompressor(a, state)) != ARCHIVE_OK)
+ if ((ret = drive_decompressor(a, state)) < ARCHIVE_OK)
return (ret);
+ if (ret == ARCHIVE_EOF)
+ break; /* Break on EOF even if we haven't met min. */
read_avail = state->stream.next_out - state->read_next;
if (was_avail == read_avail) /* No progress? */
break;
@@ -302,7 +307,7 @@ read_consume(struct archive_read *a, size_t n)
{
struct private_data *state;
- state = (struct private_data *)a->compression_data;
+ state = (struct private_data *)a->decompressor->data;
a->archive.file_position += n;
state->read_next += n;
if (state->read_next > state->stream.next_out)
@@ -320,7 +325,7 @@ finish(struct archive_read *a)
struct private_data *state;
int ret;
- state = (struct private_data *)a->compression_data;
+ state = (struct private_data *)a->decompressor->data;
ret = ARCHIVE_OK;
switch (inflateEnd(&(state->stream))) {
case Z_OK:
@@ -335,10 +340,7 @@ finish(struct archive_read *a)
free(state->uncompressed_buffer);
free(state);
- a->compression_data = NULL;
- if (a->client_closer != NULL)
- (a->client_closer)(&a->archive, a->client_data);
-
+ a->decompressor->data = NULL;
return (ret);
}
@@ -356,6 +358,8 @@ drive_decompressor(struct archive_read *a, struct private_data *state)
unsigned char b;
const void *read_buf;
+ if (state->eof)
+ return (ARCHIVE_EOF);
flags = 0;
count = 0;
header_state = 0;
@@ -525,12 +529,10 @@ drive_decompressor(struct archive_read *a, struct private_data *state)
* TODO: Verify gzip trailer
* (uncompressed length and CRC).
*/
+ state->eof = 1;
return (ARCHIVE_OK);
default:
/* Any other return value is an error. */
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "gzip decompression failed (%s)",
- state->stream.msg);
goto fatal;
}
}
diff --git a/lib/libarchive/archive_read_support_compression_none.c b/lib/libarchive/archive_read_support_compression_none.c
index 1c8c6e3..07368b2 100644
--- a/lib/libarchive/archive_read_support_compression_none.c
+++ b/lib/libarchive/archive_read_support_compression_none.c
@@ -88,9 +88,11 @@ int
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));
+ if (__archive_read_register_compression(a,
+ archive_decompressor_none_bid,
+ archive_decompressor_none_init) != NULL)
+ return (ARCHIVE_OK);
+ return (ARCHIVE_FATAL);
}
/*
@@ -135,11 +137,11 @@ archive_decompressor_none_init(struct archive_read *a, const void *buff, size_t
state->client_next = state->client_buff;
state->client_avail = state->client_total;
- a->compression_data = state;
- a->compression_read_ahead = archive_decompressor_none_read_ahead;
- a->compression_read_consume = archive_decompressor_none_read_consume;
- a->compression_skip = archive_decompressor_none_skip;
- a->compression_finish = archive_decompressor_none_finish;
+ a->decompressor->data = state;
+ a->decompressor->read_ahead = archive_decompressor_none_read_ahead;
+ a->decompressor->consume = archive_decompressor_none_read_consume;
+ a->decompressor->skip = archive_decompressor_none_skip;
+ a->decompressor->finish = archive_decompressor_none_finish;
return (ARCHIVE_OK);
}
@@ -156,7 +158,7 @@ archive_decompressor_none_read_ahead(struct archive_read *a, const void **buff,
struct archive_decompress_none *state;
ssize_t bytes_read;
- state = (struct archive_decompress_none *)a->compression_data;
+ state = (struct archive_decompress_none *)a->decompressor->data;
if (state->fatal)
return (-1);
@@ -253,7 +255,7 @@ archive_decompressor_none_read_consume(struct archive_read *a, size_t request)
{
struct archive_decompress_none *state;
- state = (struct archive_decompress_none *)a->compression_data;
+ state = (struct archive_decompress_none *)a->decompressor->data;
if (state->avail > 0) {
/* Read came from copy buffer. */
state->next += request;
@@ -279,7 +281,7 @@ archive_decompressor_none_skip(struct archive_read *a, off_t request)
off_t bytes_skipped, total_bytes_skipped = 0;
size_t min;
- state = (struct archive_decompress_none *)a->compression_data;
+ state = (struct archive_decompress_none *)a->decompressor->data;
if (state->fatal)
return (-1);
/*
@@ -355,11 +357,9 @@ archive_decompressor_none_finish(struct archive_read *a)
{
struct archive_decompress_none *state;
- state = (struct archive_decompress_none *)a->compression_data;
+ state = (struct archive_decompress_none *)a->decompressor->data;
free(state->buffer);
free(state);
- a->compression_data = NULL;
- if (a->client_closer != NULL)
- return ((a->client_closer)(&a->archive, a->client_data));
+ a->decompressor->data = NULL;
return (ARCHIVE_OK);
}
diff --git a/lib/libarchive/archive_read_support_compression_program.c b/lib/libarchive/archive_read_support_compression_program.c
new file mode 100644
index 0000000..d406797
--- /dev/null
+++ b/lib/libarchive/archive_read_support_compression_program.c
@@ -0,0 +1,312 @@
+/*-
+ * Copyright (c) 2007 Joerg Sonnenberger
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+#ifdef HAVE_ERRNO_H
+# include <errno.h>
+#endif
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#ifdef HAVE_LIMITS_H
+# include <limits.h>
+#endif
+#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_private.h"
+#include "archive_read_private.h"
+
+#include "filter_fork.h"
+
+struct archive_decompress_program {
+ char *description;
+ pid_t child;
+ int child_stdin, child_stdout;
+
+ char *child_out_buf;
+ char *child_out_buf_next;
+ size_t child_out_buf_len, child_out_buf_avail;
+
+ const char *child_in_buf;
+ size_t child_in_buf_avail;
+};
+
+static int archive_decompressor_program_bid(const void *, size_t);
+static int archive_decompressor_program_finish(struct archive_read *);
+static int archive_decompressor_program_init(struct archive_read *,
+ const void *, size_t);
+static ssize_t archive_decompressor_program_read_ahead(struct archive_read *,
+ const void **, size_t);
+static ssize_t archive_decompressor_program_read_consume(struct archive_read *,
+ size_t);
+
+int
+archive_read_support_compression_program(struct archive *_a, const char *cmd)
+{
+ struct archive_read *a = (struct archive_read *)_a;
+ struct decompressor_t *decompressor;
+
+ if (cmd == NULL || *cmd == '\0')
+ return (ARCHIVE_WARN);
+
+ decompressor = __archive_read_register_compression(a,
+ archive_decompressor_program_bid,
+ archive_decompressor_program_init);
+ if (decompressor == NULL)
+ return (ARCHIVE_WARN);
+
+ decompressor->config = strdup(cmd);
+ return (ARCHIVE_OK);
+}
+
+/*
+ * If the user used us to register, they must really want us to
+ * handle it, so this module always bids INT_MAX.
+ */
+static int
+archive_decompressor_program_bid(const void *buff, size_t len)
+{
+ (void)buff; /* UNUSED */
+ (void)len; /* UNUSED */
+
+ return (INT_MAX); /* Default: We'll take it. */
+}
+
+static ssize_t
+child_read(struct archive_read *a, char *buf, size_t buf_len)
+{
+ struct archive_decompress_program *state = a->decompressor->data;
+ ssize_t ret, requested;
+
+ if (state->child_stdout == -1)
+ return (-1);
+
+ if (buf_len == 0)
+ return (-1);
+
+restart_read:
+ requested = buf_len > SSIZE_MAX ? SSIZE_MAX : buf_len;
+
+ do {
+ ret = read(state->child_stdout, buf, requested);
+ } while (ret == -1 && errno == EINTR);
+
+ if (ret > 0)
+ return (ret);
+ if (ret == 0 || (ret == -1 && errno == EPIPE)) {
+ close(state->child_stdout);
+ state->child_stdout = -1;
+ return (0);
+ }
+ if (ret == -1 && errno != EAGAIN)
+ return (-1);
+
+ if (state->child_in_buf_avail == 0) {
+ ret = (a->client_reader)(&a->archive,
+ a->client_data, (const void **)&state->child_in_buf);
+
+ if (ret < 0) {
+ close(state->child_stdin);
+ state->child_stdin = -1;
+ fcntl(state->child_stdout, F_SETFL, 0);
+ return (-1);
+ }
+ if (ret == 0) {
+ close(state->child_stdin);
+ state->child_stdin = -1;
+ fcntl(state->child_stdout, F_SETFL, 0);
+ goto restart_read;
+ }
+ state->child_in_buf_avail = ret;
+ }
+
+ do {
+ ret = write(state->child_stdin, state->child_in_buf,
+ state->child_in_buf_avail);
+ } while (ret == -1 && errno == EINTR);
+
+ if (ret > 0) {
+ state->child_in_buf += ret;
+ state->child_in_buf_avail -= ret;
+ goto restart_read;
+ } else if (ret == -1 && errno == EAGAIN) {
+ __archive_check_child(state->child_stdin, state->child_stdout);
+ goto restart_read;
+ } else if (ret == 0 || (ret == -1 && errno == EPIPE)) {
+ close(state->child_stdin);
+ state->child_stdout = -1;
+ fcntl(state->child_stdout, F_SETFL, 0);
+ goto restart_read;
+ } else {
+ close(state->child_stdin);
+ state->child_stdin = -1;
+ fcntl(state->child_stdout, F_SETFL, 0);
+ return (-1);
+ }
+}
+
+static int
+archive_decompressor_program_init(struct archive_read *a, const void *buff, size_t n)
+{
+ struct archive_decompress_program *state;
+ const char *cmd = a->decompressor->config;
+ const char *prefix = "Program: ";
+
+
+ state = (struct archive_decompress_program *)malloc(sizeof(*state));
+ if (!state) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate input data");
+ return (ARCHIVE_FATAL);
+ }
+
+ a->archive.compression_code = ARCHIVE_COMPRESSION_PROGRAM;
+ state->description = (char *)malloc(strlen(prefix) + strlen(cmd) + 1);
+ strcpy(state->description, prefix);
+ strcat(state->description, cmd);
+ a->archive.compression_name = state->description;
+
+ state->child_out_buf_next = state->child_out_buf = malloc(65536);
+ if (!state->child_out_buf) {
+ free(state);
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate filter buffer");
+ return (ARCHIVE_FATAL);
+ }
+ state->child_out_buf_len = 65536;
+ state->child_out_buf_avail = 0;
+
+ state->child_in_buf = buff;
+ state->child_in_buf_avail = n;
+
+ if ((state->child = __archive_create_child(cmd,
+ &state->child_stdin, &state->child_stdout)) == -1) {
+ free(state->child_out_buf);
+ free(state);
+ archive_set_error(&a->archive, EINVAL,
+ "Can't initialise filter");
+ return (ARCHIVE_FATAL);
+ }
+
+ a->decompressor->data = state;
+ a->decompressor->read_ahead = archive_decompressor_program_read_ahead;
+ a->decompressor->consume = archive_decompressor_program_read_consume;
+ a->decompressor->skip = NULL;
+ a->decompressor->finish = archive_decompressor_program_finish;
+
+ /* XXX Check that we can read at least one byte? */
+ return (ARCHIVE_OK);
+}
+
+static ssize_t
+archive_decompressor_program_read_ahead(struct archive_read *a, const void **buff,
+ size_t min)
+{
+ struct archive_decompress_program *state;
+ ssize_t bytes_read;
+
+ state = (struct archive_decompress_program *)a->decompressor->data;
+
+ if (min > state->child_out_buf_len)
+ min = state->child_out_buf_len;
+
+ while (state->child_stdout != -1 && min > state->child_out_buf_avail) {
+ if (state->child_out_buf != state->child_out_buf_next) {
+ memmove(state->child_out_buf, state->child_out_buf_next,
+ state->child_out_buf_avail);
+ state->child_out_buf_next = state->child_out_buf;
+ }
+
+ bytes_read = child_read(a,
+ state->child_out_buf + state->child_out_buf_avail,
+ state->child_out_buf_len - state->child_out_buf_avail);
+ if (bytes_read == -1)
+ return (-1);
+ if (bytes_read == 0)
+ break;
+ state->child_out_buf_avail += bytes_read;
+ a->archive.raw_position += bytes_read;
+ }
+
+ *buff = state->child_out_buf_next;
+ return (state->child_out_buf_avail);
+}
+
+static ssize_t
+archive_decompressor_program_read_consume(struct archive_read *a, size_t request)
+{
+ struct archive_decompress_program *state;
+
+ state = (struct archive_decompress_program *)a->decompressor->data;
+
+ state->child_out_buf_next += request;
+ state->child_out_buf_avail -= request;
+
+ a->archive.file_position += request;
+ return (request);
+}
+
+static int
+archive_decompressor_program_finish(struct archive_read *a)
+{
+ struct archive_decompress_program *state;
+ int status;
+
+ state = (struct archive_decompress_program *)a->decompressor->data;
+
+ /* Release our configuration data. */
+ free(a->decompressor->config);
+ a->decompressor->config = NULL;
+
+ /* Shut down the child. */
+ if (state->child_stdin != -1)
+ close(state->child_stdin);
+ if (state->child_stdout != -1)
+ close(state->child_stdout);
+ while (waitpid(state->child, &status, 0) == -1 && errno == EINTR)
+ continue;
+
+ /* Release our private data. */
+ free(state->child_out_buf);
+ free(state->description);
+ free(state);
+ a->decompressor->data = NULL;
+
+ return (ARCHIVE_OK);
+}
diff --git a/lib/libarchive/archive_read_support_format_ar.c b/lib/libarchive/archive_read_support_format_ar.c
index 44f9ca6..c7f4cae 100644
--- a/lib/libarchive/archive_read_support_format_ar.c
+++ b/lib/libarchive/archive_read_support_format_ar.c
@@ -126,10 +126,11 @@ archive_read_format_ar_cleanup(struct archive_read *a)
{
struct ar *ar;
- ar = (struct ar *)*(a->pformat_data);
- free(ar->strtab);
+ ar = (struct ar *)(a->format->data);
+ if (ar->strtab)
+ free(ar->strtab);
free(ar);
- *(a->pformat_data) = NULL;
+ (a->format->data) = NULL;
return (ARCHIVE_OK);
}
@@ -145,7 +146,7 @@ archive_read_format_ar_bid(struct archive_read *a)
ARCHIVE_FORMAT_AR)
return(0);
- ar = (struct ar *)*(a->pformat_data);
+ ar = (struct ar *)(a->format->data);
if (ar->bid > 0)
return (ar->bid);
@@ -154,7 +155,7 @@ archive_read_format_ar_bid(struct archive_read *a)
* Verify the 8-byte file signature.
* TODO: Do we need to check more than this?
*/
- bytes_read = (a->compression_read_ahead)(a, &h, 8);
+ bytes_read = (a->decompressor->read_ahead)(a, &h, 8);
if (bytes_read < 8)
return (-1);
if (strncmp((const char*)h, "!<arch>\n", 8) == 0) {
@@ -178,25 +179,25 @@ archive_read_format_ar_read_header(struct archive_read *a,
const char *h;
int r;
- ar = (struct ar*)*(a->pformat_data);
+ ar = (struct ar*)(a->format->data);
if (a->archive.file_position == 0) {
/*
* We are now at the beginning of the archive,
* so we need first consume the ar global header.
*/
- (a->compression_read_consume)(a, 8);
+ (a->decompressor->consume)(a, 8);
/* Set a default format code for now. */
a->archive.archive_format = ARCHIVE_FORMAT_AR;
}
/* Read the header for the next file entry. */
- bytes_read = (a->compression_read_ahead)(a, &b, 60);
+ bytes_read = (a->decompressor->read_ahead)(a, &b, 60);
if (bytes_read < 60) {
/* Broken header. */
return (ARCHIVE_EOF);
}
- (a->compression_read_consume)(a, 60);
+ (a->decompressor->consume)(a, 60);
h = (const char *)b;
/* Verify the magic signature on the file header. */
@@ -284,7 +285,7 @@ archive_read_format_ar_read_header(struct archive_read *a,
}
entry_size = (size_t)number;
/* Read the filename table into memory. */
- bytes_read = (a->compression_read_ahead)(a, &b, entry_size);
+ bytes_read = (a->decompressor->read_ahead)(a, &b, entry_size);
if (bytes_read <= 0)
return (ARCHIVE_FATAL);
if ((size_t)bytes_read < entry_size) {
@@ -348,7 +349,7 @@ archive_read_format_ar_read_header(struct archive_read *a,
archive_entry_set_size(entry, ar->entry_bytes_remaining);
/* Read the long name into memory. */
- bytes_read = (a->compression_read_ahead)(a, &b, bsd_name_length);
+ bytes_read = (a->decompressor->read_ahead)(a, &b, bsd_name_length);
if (bytes_read <= 0)
return (ARCHIVE_FATAL);
if ((size_t)bytes_read < bsd_name_length) {
@@ -356,7 +357,7 @@ archive_read_format_ar_read_header(struct archive_read *a,
"Truncated input file");
return (ARCHIVE_FATAL);
}
- (a->compression_read_consume)(a, bsd_name_length);
+ (a->decompressor->consume)(a, bsd_name_length);
/* Store it in the entry. */
p = (char *)malloc(bsd_name_length + 1);
@@ -434,10 +435,10 @@ archive_read_format_ar_read_data(struct archive_read *a,
ssize_t bytes_read;
struct ar *ar;
- ar = (struct ar *)*(a->pformat_data);
+ ar = (struct ar *)(a->format->data);
if (ar->entry_bytes_remaining > 0) {
- bytes_read = (a->compression_read_ahead)(a, buff, 1);
+ bytes_read = (a->decompressor->read_ahead)(a, buff, 1);
if (bytes_read == 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Truncated ar archive");
@@ -451,16 +452,16 @@ archive_read_format_ar_read_data(struct archive_read *a,
*offset = ar->entry_offset;
ar->entry_offset += bytes_read;
ar->entry_bytes_remaining -= bytes_read;
- (a->compression_read_consume)(a, (size_t)bytes_read);
+ (a->decompressor->consume)(a, (size_t)bytes_read);
return (ARCHIVE_OK);
} else {
while (ar->entry_padding > 0) {
- bytes_read = (a->compression_read_ahead)(a, buff, 1);
+ bytes_read = (a->decompressor->read_ahead)(a, buff, 1);
if (bytes_read <= 0)
return (ARCHIVE_FATAL);
if (bytes_read > ar->entry_padding)
bytes_read = (ssize_t)ar->entry_padding;
- (a->compression_read_consume)(a, (size_t)bytes_read);
+ (a->decompressor->consume)(a, (size_t)bytes_read);
ar->entry_padding -= bytes_read;
}
*buff = NULL;
@@ -480,14 +481,14 @@ archive_read_format_ar_skip(struct archive_read *a)
size_t s;
off_t o;
- ar = (struct ar *)*(a->pformat_data);
- if (a->compression_skip == NULL) {
+ ar = (struct ar *)(a->format->data);
+ if (a->decompressor->skip == NULL) {
while (r == ARCHIVE_OK)
r = archive_read_format_ar_read_data(a, &b, &s, &o);
return (r);
}
- bytes_skipped = (a->compression_skip)(a, ar->entry_bytes_remaining +
+ bytes_skipped = (a->decompressor->skip)(a, ar->entry_bytes_remaining +
ar->entry_padding);
if (bytes_skipped < 0)
return (ARCHIVE_FATAL);
diff --git a/lib/libarchive/archive_read_support_format_cpio.c b/lib/libarchive/archive_read_support_format_cpio.c
index 0fe4051..7eccc87 100644
--- a/lib/libarchive/archive_read_support_format_cpio.c
+++ b/lib/libarchive/archive_read_support_format_cpio.c
@@ -26,15 +26,6 @@
#include "archive_platform.h"
__FBSDID("$FreeBSD$");
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#ifdef MAJOR_IN_MKDEV
-#include <sys/mkdev.h>
-#elif defined(MAJOR_IN_SYSMACROS)
-#include <sys/sysmacros.h>
-#endif
-
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
@@ -45,9 +36,6 @@ __FBSDID("$FreeBSD$");
#ifdef HAVE_STRING_H
#include <string.h>
#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
#include "archive.h"
#include "archive_entry.h"
@@ -112,7 +100,7 @@ struct links_entry {
struct cpio {
int magic;
int (*read_header)(struct archive_read *, struct cpio *,
- struct stat *, size_t *, size_t *);
+ struct archive_entry *, size_t *, size_t *);
struct links_entry *links_head;
struct archive_string entry_name;
struct archive_string entry_linkname;
@@ -130,17 +118,16 @@ static int archive_read_format_cpio_read_data(struct archive_read *,
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_read *, struct cpio *, struct stat *,
- size_t *, size_t *);
-static int header_bin_le(struct archive_read *, struct cpio *, struct stat *,
- size_t *, size_t *);
-static int header_newc(struct archive_read *, struct cpio *, struct stat *,
- size_t *, size_t *);
-static int header_odc(struct archive_read *, struct cpio *, struct stat *,
- size_t *, size_t *);
+static int header_bin_be(struct archive_read *, struct cpio *,
+ struct archive_entry *, size_t *, size_t *);
+static int header_bin_le(struct archive_read *, struct cpio *,
+ struct archive_entry *, size_t *, size_t *);
+static int header_newc(struct archive_read *, struct cpio *,
+ struct archive_entry *, size_t *, size_t *);
+static int header_odc(struct archive_read *, struct cpio *,
+ struct archive_entry *, 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);
+static void record_hardlink(struct cpio *cpio, struct archive_entry *entry);
int
archive_read_support_format_cpio(struct archive *_a)
@@ -179,9 +166,9 @@ archive_read_format_cpio_bid(struct archive_read *a)
const unsigned char *p;
struct cpio *cpio;
- cpio = (struct cpio *)*(a->pformat_data);
+ cpio = (struct cpio *)(a->format->data);
bid = 0;
- bytes_read = (a->compression_read_ahead)(a, &h, 6);
+ bytes_read = (a->decompressor->read_ahead)(a, &h, 6);
/* Convert error code into error return. */
if (bytes_read < 0)
return ((int)bytes_read);
@@ -234,7 +221,6 @@ static int
archive_read_format_cpio_read_header(struct archive_read *a,
struct archive_entry *entry)
{
- struct stat st;
struct cpio *cpio;
size_t bytes;
const void *h;
@@ -242,33 +228,28 @@ archive_read_format_cpio_read_header(struct archive_read *a,
size_t name_pad;
int r;
- memset(&st, 0, sizeof(st));
-
- cpio = (struct cpio *)*(a->pformat_data);
- r = (cpio->read_header(a, cpio, &st, &namelength, &name_pad));
+ cpio = (struct cpio *)(a->format->data);
+ r = (cpio->read_header(a, cpio, entry, &namelength, &name_pad));
if (r != ARCHIVE_OK)
return (r);
- /* Assign all of the 'stat' fields at once. */
- archive_entry_copy_stat(entry, &st);
-
/* Read name from buffer. */
- bytes = (a->compression_read_ahead)(a, &h, namelength + name_pad);
+ bytes = (a->decompressor->read_ahead)(a, &h, namelength + name_pad);
if (bytes < namelength + name_pad)
return (ARCHIVE_FATAL);
- (a->compression_read_consume)(a, namelength + name_pad);
+ (a->decompressor->consume)(a, namelength + name_pad);
archive_strncpy(&cpio->entry_name, (const char *)h, namelength);
archive_entry_set_pathname(entry, cpio->entry_name.s);
cpio->entry_offset = 0;
/* If this is a symlink, read the link contents. */
- if (S_ISLNK(st.st_mode)) {
- bytes = (a->compression_read_ahead)(a, &h,
+ if (archive_entry_filetype(entry) == AE_IFLNK) {
+ bytes = (a->decompressor->read_ahead)(a, &h,
cpio->entry_bytes_remaining);
if ((off_t)bytes < cpio->entry_bytes_remaining)
return (ARCHIVE_FATAL);
- (a->compression_read_consume)(a, cpio->entry_bytes_remaining);
+ (a->decompressor->consume)(a, cpio->entry_bytes_remaining);
archive_strncpy(&cpio->entry_linkname, (const char *)h,
cpio->entry_bytes_remaining);
archive_entry_set_symlink(entry, cpio->entry_linkname.s);
@@ -283,7 +264,7 @@ archive_read_format_cpio_read_header(struct archive_read *a,
}
/* Detect and record hardlinks to previously-extracted entries. */
- record_hardlink(cpio, entry, &st);
+ record_hardlink(cpio, entry);
return (ARCHIVE_OK);
}
@@ -295,9 +276,9 @@ archive_read_format_cpio_read_data(struct archive_read *a,
ssize_t bytes_read;
struct cpio *cpio;
- cpio = (struct cpio *)*(a->pformat_data);
+ cpio = (struct cpio *)(a->format->data);
if (cpio->entry_bytes_remaining > 0) {
- bytes_read = (a->compression_read_ahead)(a, buff, 1);
+ bytes_read = (a->decompressor->read_ahead)(a, buff, 1);
if (bytes_read <= 0)
return (ARCHIVE_FATAL);
if (bytes_read > cpio->entry_bytes_remaining)
@@ -306,16 +287,16 @@ archive_read_format_cpio_read_data(struct archive_read *a,
*offset = cpio->entry_offset;
cpio->entry_offset += bytes_read;
cpio->entry_bytes_remaining -= bytes_read;
- (a->compression_read_consume)(a, bytes_read);
+ (a->decompressor->consume)(a, bytes_read);
return (ARCHIVE_OK);
} else {
while (cpio->entry_padding > 0) {
- bytes_read = (a->compression_read_ahead)(a, buff, 1);
+ bytes_read = (a->decompressor->read_ahead)(a, buff, 1);
if (bytes_read <= 0)
return (ARCHIVE_FATAL);
if (bytes_read > cpio->entry_padding)
bytes_read = cpio->entry_padding;
- (a->compression_read_consume)(a, bytes_read);
+ (a->decompressor->consume)(a, bytes_read);
cpio->entry_padding -= bytes_read;
}
*buff = NULL;
@@ -326,20 +307,20 @@ archive_read_format_cpio_read_data(struct archive_read *a,
}
static int
-header_newc(struct archive_read *a, struct cpio *cpio, struct stat *st,
- size_t *namelength, size_t *name_pad)
+header_newc(struct archive_read *a, struct cpio *cpio,
+ struct archive_entry *entry, size_t *namelength, size_t *name_pad)
{
const void *h;
const struct cpio_newc_header *header;
size_t bytes;
/* Read fixed-size portion of header. */
- bytes = (a->compression_read_ahead)(a, &h, sizeof(struct cpio_newc_header));
+ bytes = (a->decompressor->read_ahead)(a, &h, sizeof(struct cpio_newc_header));
if (bytes < sizeof(struct cpio_newc_header))
return (ARCHIVE_FATAL);
- (a->compression_read_consume)(a, sizeof(struct cpio_newc_header));
+ (a->decompressor->consume)(a, sizeof(struct cpio_newc_header));
- /* Parse out hex fields into struct stat. */
+ /* Parse out hex fields. */
header = (const struct cpio_newc_header *)h;
if (memcmp(header->c_magic, "070701", 6) == 0) {
@@ -352,18 +333,16 @@ header_newc(struct archive_read *a, struct cpio *cpio, struct stat *st,
/* TODO: Abort here? */
}
- st->st_dev = makedev(
- atol16(header->c_devmajor, sizeof(header->c_devmajor)),
- atol16(header->c_devminor, sizeof(header->c_devminor)));
- st->st_ino = atol16(header->c_ino, sizeof(header->c_ino));
- st->st_mode = atol16(header->c_mode, sizeof(header->c_mode));
- st->st_uid = atol16(header->c_uid, sizeof(header->c_uid));
- st->st_gid = atol16(header->c_gid, sizeof(header->c_gid));
- st->st_nlink = atol16(header->c_nlink, sizeof(header->c_nlink));
- st->st_rdev = makedev(
- atol16(header->c_rdevmajor, sizeof(header->c_rdevmajor)),
- atol16(header->c_rdevminor, sizeof(header->c_rdevminor)));
- st->st_mtime = atol16(header->c_mtime, sizeof(header->c_mtime));
+ archive_entry_set_devmajor(entry, atol16(header->c_devmajor, sizeof(header->c_devmajor)));
+ archive_entry_set_devminor(entry, atol16(header->c_devminor, sizeof(header->c_devminor)));
+ archive_entry_set_ino(entry, atol16(header->c_ino, sizeof(header->c_ino)));
+ archive_entry_set_mode(entry, atol16(header->c_mode, sizeof(header->c_mode)));
+ archive_entry_set_uid(entry, atol16(header->c_uid, sizeof(header->c_uid)));
+ archive_entry_set_gid(entry, atol16(header->c_gid, sizeof(header->c_gid)));
+ archive_entry_set_nlink(entry, atol16(header->c_nlink, sizeof(header->c_nlink)));
+ archive_entry_set_rdevmajor(entry, atol16(header->c_rdevmajor, sizeof(header->c_rdevmajor)));
+ archive_entry_set_rdevminor(entry, atol16(header->c_rdevminor, sizeof(header->c_rdevminor)));
+ archive_entry_set_mtime(entry, atol16(header->c_mtime, sizeof(header->c_mtime)), 0);
*namelength = atol16(header->c_namesize, sizeof(header->c_namesize));
/* Pad name to 2 more than a multiple of 4. */
*name_pad = (2 - *namelength) & 3;
@@ -371,20 +350,19 @@ header_newc(struct archive_read *a, struct cpio *cpio, struct stat *st,
/*
* Note: entry_bytes_remaining is at least 64 bits and
* therefore guaranteed to be big enough for a 33-bit file
- * size. struct stat.st_size may only be 32 bits, so
- * assigning there first could lose information.
+ * size.
*/
cpio->entry_bytes_remaining =
atol16(header->c_filesize, sizeof(header->c_filesize));
- st->st_size = cpio->entry_bytes_remaining;
+ archive_entry_set_size(entry, cpio->entry_bytes_remaining);
/* Pad file contents to a multiple of 4. */
cpio->entry_padding = 3 & -cpio->entry_bytes_remaining;
return (ARCHIVE_OK);
}
static int
-header_odc(struct archive_read *a, struct cpio *cpio, struct stat *st,
- size_t *namelength, size_t *name_pad)
+header_odc(struct archive_read *a, struct cpio *cpio,
+ struct archive_entry *entry, size_t *namelength, size_t *name_pad)
{
const void *h;
const struct cpio_odc_header *header;
@@ -394,41 +372,40 @@ header_odc(struct archive_read *a, struct cpio *cpio, struct stat *st,
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));
+ bytes = (a->decompressor->read_ahead)(a, &h, sizeof(struct cpio_odc_header));
if (bytes < sizeof(struct cpio_odc_header))
return (ARCHIVE_FATAL);
- (a->compression_read_consume)(a, sizeof(struct cpio_odc_header));
+ (a->decompressor->consume)(a, sizeof(struct cpio_odc_header));
- /* Parse out octal fields into struct stat. */
+ /* Parse out octal fields. */
header = (const struct cpio_odc_header *)h;
- st->st_dev = atol8(header->c_dev, sizeof(header->c_dev));
- st->st_ino = atol8(header->c_ino, sizeof(header->c_ino));
- st->st_mode = atol8(header->c_mode, sizeof(header->c_mode));
- st->st_uid = atol8(header->c_uid, sizeof(header->c_uid));
- st->st_gid = atol8(header->c_gid, sizeof(header->c_gid));
- st->st_nlink = atol8(header->c_nlink, sizeof(header->c_nlink));
- st->st_rdev = atol8(header->c_rdev, sizeof(header->c_rdev));
- st->st_mtime = atol8(header->c_mtime, sizeof(header->c_mtime));
+ archive_entry_set_dev(entry, atol8(header->c_dev, sizeof(header->c_dev)));
+ archive_entry_set_ino(entry, atol8(header->c_ino, sizeof(header->c_ino)));
+ archive_entry_set_mode(entry, atol8(header->c_mode, sizeof(header->c_mode)));
+ archive_entry_set_uid(entry, atol8(header->c_uid, sizeof(header->c_uid)));
+ archive_entry_set_gid(entry, atol8(header->c_gid, sizeof(header->c_gid)));
+ archive_entry_set_nlink(entry, atol8(header->c_nlink, sizeof(header->c_nlink)));
+ archive_entry_set_rdev(entry, atol8(header->c_rdev, sizeof(header->c_rdev)));
+ archive_entry_set_mtime(entry, atol8(header->c_mtime, sizeof(header->c_mtime)), 0);
*namelength = atol8(header->c_namesize, sizeof(header->c_namesize));
*name_pad = 0; /* No padding of filename. */
/*
* Note: entry_bytes_remaining is at least 64 bits and
* therefore guaranteed to be big enough for a 33-bit file
- * size. struct stat.st_size may only be 32 bits, so
- * assigning there first could lose information.
+ * size.
*/
cpio->entry_bytes_remaining =
atol8(header->c_filesize, sizeof(header->c_filesize));
- st->st_size = cpio->entry_bytes_remaining;
+ archive_entry_set_size(entry, cpio->entry_bytes_remaining);
cpio->entry_padding = 0;
return (ARCHIVE_OK);
}
static int
-header_bin_le(struct archive_read *a, struct cpio *cpio, struct stat *st,
- size_t *namelength, size_t *name_pad)
+header_bin_le(struct archive_read *a, struct cpio *cpio,
+ struct archive_entry *entry, size_t *namelength, size_t *name_pad)
{
const void *h;
const struct cpio_bin_header *header;
@@ -438,34 +415,34 @@ header_bin_le(struct archive_read *a, struct cpio *cpio, struct stat *st,
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));
+ bytes = (a->decompressor->read_ahead)(a, &h, sizeof(struct cpio_bin_header));
if (bytes < sizeof(struct cpio_bin_header))
return (ARCHIVE_FATAL);
- (a->compression_read_consume)(a, sizeof(struct cpio_bin_header));
+ (a->decompressor->consume)(a, sizeof(struct cpio_bin_header));
- /* Parse out binary fields into struct stat. */
+ /* Parse out binary fields. */
header = (const struct cpio_bin_header *)h;
- st->st_dev = header->c_dev[0] + header->c_dev[1] * 256;
- st->st_ino = header->c_ino[0] + header->c_ino[1] * 256;
- st->st_mode = header->c_mode[0] + header->c_mode[1] * 256;
- st->st_uid = header->c_uid[0] + header->c_uid[1] * 256;
- st->st_gid = header->c_gid[0] + header->c_gid[1] * 256;
- st->st_nlink = header->c_nlink[0] + header->c_nlink[1] * 256;
- st->st_rdev = header->c_rdev[0] + header->c_rdev[1] * 256;
- st->st_mtime = le4(header->c_mtime);
+ archive_entry_set_dev(entry, header->c_dev[0] + header->c_dev[1] * 256);
+ archive_entry_set_ino(entry, header->c_ino[0] + header->c_ino[1] * 256);
+ archive_entry_set_mode(entry, header->c_mode[0] + header->c_mode[1] * 256);
+ archive_entry_set_uid(entry, header->c_uid[0] + header->c_uid[1] * 256);
+ archive_entry_set_gid(entry, header->c_gid[0] + header->c_gid[1] * 256);
+ archive_entry_set_nlink(entry, header->c_nlink[0] + header->c_nlink[1] * 256);
+ archive_entry_set_rdev(entry, header->c_rdev[0] + header->c_rdev[1] * 256);
+ archive_entry_set_mtime(entry, le4(header->c_mtime), 0);
*namelength = header->c_namesize[0] + header->c_namesize[1] * 256;
*name_pad = *namelength & 1; /* Pad to even. */
cpio->entry_bytes_remaining = le4(header->c_filesize);
- st->st_size = cpio->entry_bytes_remaining;
+ archive_entry_set_size(entry, cpio->entry_bytes_remaining);
cpio->entry_padding = cpio->entry_bytes_remaining & 1; /* Pad to even. */
return (ARCHIVE_OK);
}
static int
-header_bin_be(struct archive_read *a, struct cpio *cpio, struct stat *st,
- size_t *namelength, size_t *name_pad)
+header_bin_be(struct archive_read *a, struct cpio *cpio,
+ struct archive_entry *entry, size_t *namelength, size_t *name_pad)
{
const void *h;
const struct cpio_bin_header *header;
@@ -475,27 +452,27 @@ header_bin_be(struct archive_read *a, struct cpio *cpio, struct stat *st,
a->archive.archive_format_name = "cpio (big-endian binary)";
/* Read fixed-size portion of header. */
- bytes = (a->compression_read_ahead)(a, &h,
+ bytes = (a->decompressor->read_ahead)(a, &h,
sizeof(struct cpio_bin_header));
if (bytes < sizeof(struct cpio_bin_header))
return (ARCHIVE_FATAL);
- (a->compression_read_consume)(a, sizeof(struct cpio_bin_header));
+ (a->decompressor->consume)(a, sizeof(struct cpio_bin_header));
- /* Parse out binary fields into struct stat. */
+ /* Parse out binary fields. */
header = (const struct cpio_bin_header *)h;
- st->st_dev = header->c_dev[0] * 256 + header->c_dev[1];
- st->st_ino = header->c_ino[0] * 256 + header->c_ino[1];
- st->st_mode = header->c_mode[0] * 256 + header->c_mode[1];
- st->st_uid = header->c_uid[0] * 256 + header->c_uid[1];
- st->st_gid = header->c_gid[0] * 256 + header->c_gid[1];
- st->st_nlink = header->c_nlink[0] * 256 + header->c_nlink[1];
- st->st_rdev = header->c_rdev[0] * 256 + header->c_rdev[1];
- st->st_mtime = be4(header->c_mtime);
+ archive_entry_set_dev(entry, header->c_dev[0] * 256 + header->c_dev[1]);
+ archive_entry_set_ino(entry, header->c_ino[0] * 256 + header->c_ino[1]);
+ archive_entry_set_mode(entry, header->c_mode[0] * 256 + header->c_mode[1]);
+ archive_entry_set_uid(entry, header->c_uid[0] * 256 + header->c_uid[1]);
+ archive_entry_set_gid(entry, header->c_gid[0] * 256 + header->c_gid[1]);
+ archive_entry_set_nlink(entry, header->c_nlink[0] * 256 + header->c_nlink[1]);
+ archive_entry_set_rdev(entry, header->c_rdev[0] * 256 + header->c_rdev[1]);
+ archive_entry_set_mtime(entry, be4(header->c_mtime), 0);
*namelength = header->c_namesize[0] * 256 + header->c_namesize[1];
*name_pad = *namelength & 1; /* Pad to even. */
cpio->entry_bytes_remaining = be4(header->c_filesize);
- st->st_size = cpio->entry_bytes_remaining;
+ archive_entry_set_size(entry, cpio->entry_bytes_remaining);
cpio->entry_padding = cpio->entry_bytes_remaining & 1; /* Pad to even. */
return (ARCHIVE_OK);
}
@@ -505,7 +482,7 @@ archive_read_format_cpio_cleanup(struct archive_read *a)
{
struct cpio *cpio;
- cpio = (struct cpio *)*(a->pformat_data);
+ cpio = (struct cpio *)(a->format->data);
/* Free inode->name map */
while (cpio->links_head != NULL) {
struct links_entry *lp = cpio->links_head->next;
@@ -515,9 +492,9 @@ archive_read_format_cpio_cleanup(struct archive_read *a)
free(cpio->links_head);
cpio->links_head = lp;
}
-
+ archive_string_free(&cpio->entry_name);
free(cpio);
- *(a->pformat_data) = NULL;
+ (a->format->data) = NULL;
return (ARCHIVE_OK);
}
@@ -582,17 +559,21 @@ atol16(const char *p, unsigned char_cnt)
}
static void
-record_hardlink(struct cpio *cpio, struct archive_entry *entry,
- const struct stat *st)
+record_hardlink(struct cpio *cpio, struct archive_entry *entry)
{
struct links_entry *le;
+ dev_t dev;
+ ino_t ino;
+
+ dev = archive_entry_dev(entry);
+ ino = archive_entry_ino(entry);
/*
* First look in the list of multiply-linked files. If we've
* already dumped it, convert this entry to a hard link entry.
*/
for (le = cpio->links_head; le; le = le->next) {
- if (le->dev == st->st_dev && le->ino == st->st_ino) {
+ if (le->dev == dev && le->ino == ino) {
archive_entry_set_hardlink(entry, le->name);
if (--le->links <= 0) {
@@ -617,9 +598,9 @@ record_hardlink(struct cpio *cpio, struct archive_entry *entry,
le->next = cpio->links_head;
le->previous = NULL;
cpio->links_head = le;
- le->dev = st->st_dev;
- le->ino = st->st_ino;
- le->links = st->st_nlink - 1;
+ le->dev = dev;
+ le->ino = ino;
+ le->links = archive_entry_nlink(entry) - 1;
le->name = strdup(archive_entry_pathname(entry));
if (le->name == NULL)
__archive_errx(1, "Out of memory adding file to list");
diff --git a/lib/libarchive/archive_read_support_format_empty.c b/lib/libarchive/archive_read_support_format_empty.c
index f729ae6..976306c 100644
--- a/lib/libarchive/archive_read_support_format_empty.c
+++ b/lib/libarchive/archive_read_support_format_empty.c
@@ -60,7 +60,7 @@ archive_read_format_empty_bid(struct archive_read *a)
int bytes_read;
const void *h;
- bytes_read = (a->compression_read_ahead)(a, &h, 1);
+ bytes_read = (a->decompressor->read_ahead)(a, &h, 1);
if (bytes_read > 0)
return (-1);
return (1);
diff --git a/lib/libarchive/archive_read_support_format_iso9660.c b/lib/libarchive/archive_read_support_format_iso9660.c
index 2b3e0fa..9e3785c 100644
--- a/lib/libarchive/archive_read_support_format_iso9660.c
+++ b/lib/libarchive/archive_read_support_format_iso9660.c
@@ -26,10 +26,6 @@
#include "archive_platform.h"
__FBSDID("$FreeBSD$");
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
@@ -42,9 +38,6 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#endif
#include <time.h>
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
#include "archive.h"
#include "archive_entry.h"
@@ -288,7 +281,7 @@ archive_read_format_iso9660_bid(struct archive_read *a)
const void *h;
const unsigned char *p;
- iso9660 = (struct iso9660 *)*(a->pformat_data);
+ iso9660 = (struct iso9660 *)(a->format->data);
if (iso9660->bid >= 0)
return (iso9660->bid);
@@ -298,7 +291,7 @@ archive_read_format_iso9660_bid(struct archive_read *a)
* 8 sectors of the volume descriptor table. Of course,
* if the I/O layer gives us more, we'll take it.
*/
- bytes_read = (a->compression_read_ahead)(a, &h, 32768 + 8*2048);
+ bytes_read = (a->decompressor->read_ahead)(a, &h, 32768 + 8*2048);
if (bytes_read < 32768 + 8*2048)
return (iso9660->bid = -1);
p = (const unsigned char *)h;
@@ -343,13 +336,12 @@ static int
archive_read_format_iso9660_read_header(struct archive_read *a,
struct archive_entry *entry)
{
- struct stat st;
struct iso9660 *iso9660;
struct file_info *file;
ssize_t bytes_read;
int r;
- iso9660 = (struct iso9660 *)*(a->pformat_data);
+ iso9660 = (struct iso9660 *)(a->format->data);
if (!a->archive.archive_format) {
a->archive.archive_format = ARCHIVE_FORMAT_ISO9660;
@@ -365,17 +357,15 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
iso9660->entry_sparse_offset = 0; /* Offset for sparse-file-aware clients. */
/* Set up the entry structure with information about this entry. */
- memset(&st, 0, sizeof(st));
- st.st_mode = file->mode;
- st.st_uid = file->uid;
- st.st_gid = file->gid;
- st.st_nlink = file->nlinks;
- st.st_ino = file->inode;
- st.st_mtime = file->mtime;
- st.st_ctime = file->ctime;
- st.st_atime = file->atime;
- st.st_size = iso9660->entry_bytes_remaining;
- archive_entry_copy_stat(entry, &st);
+ archive_entry_set_mode(entry, file->mode);
+ archive_entry_set_uid(entry, file->uid);
+ archive_entry_set_gid(entry, file->gid);
+ archive_entry_set_nlink(entry, file->nlinks);
+ archive_entry_set_ino(entry, file->inode);
+ archive_entry_set_mtime(entry, file->mtime, 0);
+ archive_entry_set_ctime(entry, file->ctime, 0);
+ archive_entry_set_atime(entry, file->atime, 0);
+ archive_entry_set_size(entry, iso9660->entry_bytes_remaining);
archive_string_empty(&iso9660->pathname);
archive_entry_set_pathname(entry,
build_pathname(&iso9660->pathname, file));
@@ -412,14 +402,14 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
archive_strcpy(&iso9660->previous_pathname, iso9660->pathname.s);
/* If this is a directory, read in all of the entries right now. */
- if (S_ISDIR(st.st_mode)) {
+ if (archive_entry_filetype(entry) == AE_IFDIR) {
while (iso9660->entry_bytes_remaining > 0) {
const void *block;
const unsigned char *p;
ssize_t step = iso9660->logical_block_size;
if (step > iso9660->entry_bytes_remaining)
step = iso9660->entry_bytes_remaining;
- bytes_read = (a->compression_read_ahead)(a, &block, step);
+ bytes_read = (a->decompressor->read_ahead)(a, &block, step);
if (bytes_read < step) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Failed to read full block when scanning ISO9660 directory list");
@@ -428,7 +418,7 @@ archive_read_format_iso9660_read_header(struct archive_read *a,
}
if (bytes_read > step)
bytes_read = step;
- (a->compression_read_consume)(a, bytes_read);
+ (a->decompressor->consume)(a, bytes_read);
iso9660->current_position += bytes_read;
iso9660->entry_bytes_remaining -= bytes_read;
for (p = (const unsigned char *)block;
@@ -476,7 +466,7 @@ archive_read_format_iso9660_read_data(struct archive_read *a,
ssize_t bytes_read;
struct iso9660 *iso9660;
- iso9660 = (struct iso9660 *)*(a->pformat_data);
+ iso9660 = (struct iso9660 *)(a->format->data);
if (iso9660->entry_bytes_remaining <= 0) {
*buff = NULL;
*size = 0;
@@ -484,7 +474,7 @@ archive_read_format_iso9660_read_data(struct archive_read *a,
return (ARCHIVE_EOF);
}
- bytes_read = (a->compression_read_ahead)(a, buff, 1);
+ bytes_read = (a->decompressor->read_ahead)(a, buff, 1);
if (bytes_read == 0)
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Truncated input file");
@@ -497,7 +487,7 @@ archive_read_format_iso9660_read_data(struct archive_read *a,
iso9660->entry_sparse_offset += bytes_read;
iso9660->entry_bytes_remaining -= bytes_read;
iso9660->current_position += bytes_read;
- (a->compression_read_consume)(a, bytes_read);
+ (a->decompressor->consume)(a, bytes_read);
return (ARCHIVE_OK);
}
@@ -507,13 +497,15 @@ archive_read_format_iso9660_cleanup(struct archive_read *a)
struct iso9660 *iso9660;
struct file_info *file;
- iso9660 = (struct iso9660 *)*(a->pformat_data);
+ iso9660 = (struct iso9660 *)(a->format->data);
while ((file = next_entry(iso9660)) != NULL)
release_file(iso9660, file);
archive_string_free(&iso9660->pathname);
archive_string_free(&iso9660->previous_pathname);
+ if (iso9660->pending_files)
+ free(iso9660->pending_files);
free(iso9660);
- *(a->pformat_data) = NULL;
+ (a->format->data) = NULL;
return (ARCHIVE_OK);
}
@@ -554,9 +546,9 @@ parse_file_info(struct iso9660 *iso9660, struct file_info *parent,
file->name[name_len] = '\0';
flags = *(isodirrec + DR_flags_offset);
if (flags & 0x02)
- file->mode = S_IFDIR | 0700;
+ file->mode = AE_IFDIR | 0700;
else
- file->mode = S_IFREG | 0400;
+ file->mode = AE_IFREG | 0400;
/* Rockridge extensions overwrite information from above. */
{
@@ -920,7 +912,7 @@ fprintf(stderr, " *** Discarding CE data.\n");
if (iso9660->current_position < offset) {
off_t step = offset - iso9660->current_position;
off_t bytes_read;
- bytes_read = (a->compression_skip)(a, step);
+ bytes_read = (a->decompressor->skip)(a, step);
if (bytes_read < 0)
return (bytes_read);
iso9660->current_position = offset;
@@ -939,13 +931,13 @@ fprintf(stderr, " *** Discarding CE data.\n");
file->ce_offset = 0;
file->ce_size = 0;
- bytes_read = (a->compression_read_ahead)(a, &p, size);
+ bytes_read = (a->decompressor->read_ahead)(a, &p, size);
if (bytes_read > size)
bytes_read = size;
rr_start = (const unsigned char *)p;
parse_rockridge(iso9660, file, rr_start,
rr_start + bytes_read);
- (a->compression_read_consume)(a, bytes_read);
+ (a->decompressor->consume)(a, bytes_read);
iso9660->current_position += bytes_read;
add_entry(iso9660, file);
}
@@ -1053,34 +1045,37 @@ time_from_tm(struct tm *t)
{
#if HAVE_TIMEGM
return (timegm(t));
-#else
+#elif HAVE_STRUCT_TM_TM_GMTOFF
/*
* Unfortunately, timegm() isn't standard. The standard
* mktime() function is a close match, except that it uses
- * local timezone instead of GMT. Close enough for now.
- * Note that it is not possible to emulate timegm() using
- * completely standard interfaces:
- * * ANSI C90 does not even guarantee that time_t is
- * an arithmetic type, so time adjustments can only be
- * done by manipulating struct tm elements. You cannot
- * portably calculate time_t values.
- * * POSIX does promise that time_t is an arithmetic type
- * measured in seconds, so you can do time_t calculations
- * while remaining POSIX-compliant.
- * * Neither ANSI nor POSIX provides an easy way to measure
- * the timezone offset, so you can't adjust mktime() to
- * work like timegm().
- * * POSIX does not promise that the epoch begins in 1970,
- * so you can't write a portable timegm() function from
- * scratch.
- * In practice, of course, mktime() is a reasonable approximation
- * and most POSIX systems do use seconds since 1970, so you
- * can roll your own and have it work on all but a few pretty
- * whacky systems.
+ * local timezone instead of GMT. You can compensate for
+ * this by adding the timezone and DST offsets back in, at
+ * the cost of two calls to mktime().
*/
- time_t result = mktime(t);
- /* TODO: Find a way to improve this approximation to timegm(). */
- return result;
+ mktime(t); /* Normalize the time and get the TZ offset. */
+ t->tm_sec += t->tm_gmtoff; /* Try to adjust for the timezone and DST.*/
+ if (t->tm_isdst)
+ t->tm_hour -= 1;
+ return (mktime(t)); /* Re-convert. */
+#else
+ /*
+ * If you don't have tm_gmtoff, let's try resetting the timezone
+ * (yecch!).
+ */
+ time_t ret;
+ char *tz;
+
+ tz = getenv("TZ");
+ setenv("TZ", "UTC 0", 1);
+ tzset();
+ ret = mktime(t);
+ if (tz)
+ setenv("TZ", tz, 1);
+ else
+ unsetenv("TZ");
+ tzset();
+ return ret;
#endif
}
diff --git a/lib/libarchive/archive_read_support_format_tar.c b/lib/libarchive/archive_read_support_format_tar.c
index d778b9d..c05a415 100644
--- a/lib/libarchive/archive_read_support_format_tar.c
+++ b/lib/libarchive/archive_read_support_format_tar.c
@@ -26,16 +26,6 @@
#include "archive_platform.h"
__FBSDID("$FreeBSD$");
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#ifdef MAJOR_IN_MKDEV
-#include <sys/mkdev.h>
-#else
-#ifdef MAJOR_IN_SYSMACROS
-#include <sys/sysmacros.h>
-#endif
-#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
@@ -47,9 +37,6 @@ __FBSDID("$FreeBSD$");
#ifdef HAVE_STRING_H
#include <string.h>
#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
/* Obtain suitable wide-character manipulation functions. */
#ifdef HAVE_WCHAR_H
@@ -180,25 +167,25 @@ static int gnu_read_sparse_data(struct archive_read *, 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_read *, struct tar *,
- struct archive_entry *, struct stat *, const void *);
+ struct archive_entry *, const void *);
static int header_common(struct archive_read *, struct tar *,
- struct archive_entry *, struct stat *, const void *);
+ struct archive_entry *, const void *);
static int header_old_tar(struct archive_read *, struct tar *,
- struct archive_entry *, struct stat *, const void *);
+ struct archive_entry *, const void *);
static int header_pax_extensions(struct archive_read *, struct tar *,
- struct archive_entry *, struct stat *, const void *);
+ struct archive_entry *, const void *);
static int header_pax_global(struct archive_read *, struct tar *,
- struct archive_entry *, struct stat *, const void *h);
+ struct archive_entry *, const void *h);
static int header_longlink(struct archive_read *, struct tar *,
- struct archive_entry *, struct stat *, const void *h);
+ struct archive_entry *, const void *h);
static int header_longname(struct archive_read *, struct tar *,
- struct archive_entry *, struct stat *, const void *h);
+ struct archive_entry *, const void *h);
static int header_volume(struct archive_read *, struct tar *,
- struct archive_entry *, struct stat *, const void *h);
+ struct archive_entry *, const void *h);
static int header_ustar(struct archive_read *, struct tar *,
- struct archive_entry *, struct stat *, const void *h);
+ struct archive_entry *, const void *h);
static int header_gnutar(struct archive_read *, struct tar *,
- struct archive_entry *, struct stat *, const void *h);
+ struct archive_entry *, const void *h);
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,
@@ -207,10 +194,10 @@ 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_read *, const void *);
-static int pax_attribute(struct archive_entry *, struct stat *,
+static int pax_attribute(struct archive_entry *,
wchar_t *key, wchar_t *value);
static int pax_header(struct archive_read *, struct tar *,
- struct archive_entry *, struct stat *, char *attr);
+ struct archive_entry *, char *attr);
static void pax_time(const wchar_t *, int64_t *sec, long *nanos);
static int read_body_to_string(struct archive_read *, struct tar *,
struct archive_string *, const void *h);
@@ -219,7 +206,7 @@ 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_read *, struct tar *,
- struct archive_entry *, struct stat *);
+ struct archive_entry *);
static int tohex(int c);
static char *url_decode(const char *);
static int utf8_decode(wchar_t *, const char *, size_t length);
@@ -264,7 +251,7 @@ archive_read_format_tar_cleanup(struct archive_read *a)
{
struct tar *tar;
- tar = (struct tar *)*(a->pformat_data);
+ tar = (struct tar *)(a->format->data);
archive_string_free(&tar->acl_text);
archive_string_free(&tar->entry_name);
archive_string_free(&tar->entry_linkname);
@@ -275,7 +262,7 @@ archive_read_format_tar_cleanup(struct archive_read *a)
if (tar->pax_entry != NULL)
free(tar->pax_entry);
free(tar);
- *(a->pformat_data) = NULL;
+ (a->format->data) = NULL;
return (ARCHIVE_OK);
}
@@ -307,8 +294,8 @@ archive_read_format_tar_bid(struct archive_read *a)
bid++;
/* Now let's look at the actual header and see if it matches. */
- if (a->compression_read_ahead != NULL)
- bytes_read = (a->compression_read_ahead)(a, &h, 512);
+ if (a->decompressor->read_ahead != NULL)
+ bytes_read = (a->decompressor->read_ahead)(a, &h, 512);
else
bytes_read = 0; /* Empty file. */
if (bytes_read < 0)
@@ -412,26 +399,24 @@ archive_read_format_tar_read_header(struct archive_read *a,
*/
static int default_inode;
static int default_dev;
- struct stat st;
struct tar *tar;
const char *p;
int r;
size_t l;
- memset(&st, 0, sizeof(st));
/* Assign default device/inode values. */
- st.st_dev = 1 + default_dev; /* Don't use zero. */
- st.st_ino = ++default_inode; /* Don't use zero. */
+ archive_entry_set_dev(entry, 1 + default_dev); /* Don't use zero. */
+ archive_entry_set_ino(entry, ++default_inode); /* Don't use zero. */
/* Limit generated st_ino number to 16 bits. */
if (default_inode >= 0xffff) {
++default_dev;
default_inode = 0;
}
- tar = (struct tar *)*(a->pformat_data);
+ tar = (struct tar *)(a->format->data);
tar->entry_offset = 0;
- r = tar_read_header(a, tar, entry, &st);
+ r = tar_read_header(a, tar, entry);
if (r == ARCHIVE_OK) {
/*
@@ -441,13 +426,9 @@ archive_read_format_tar_read_header(struct archive_read *a,
*/
p = archive_entry_pathname(entry);
l = strlen(p);
- if (S_ISREG(st.st_mode) && p[l-1] == '/') {
- st.st_mode &= ~S_IFMT;
- st.st_mode |= S_IFDIR;
- }
-
- /* Copy the final stat data into the entry. */
- archive_entry_copy_stat(entry, &st);
+ if (archive_entry_filetype(entry) == AE_IFREG
+ && p[l-1] == '/')
+ archive_entry_set_filetype(entry, AE_IFDIR);
}
return (r);
}
@@ -460,7 +441,7 @@ archive_read_format_tar_read_data(struct archive_read *a,
struct tar *tar;
struct sparse_block *p;
- tar = (struct tar *)*(a->pformat_data);
+ tar = (struct tar *)(a->format->data);
if (tar->sparse_list != NULL) {
/* Remove exhausted entries from sparse list. */
while (tar->sparse_list != NULL &&
@@ -476,7 +457,7 @@ archive_read_format_tar_read_data(struct archive_read *a,
}
if (tar->entry_bytes_remaining > 0) {
- bytes_read = (a->compression_read_ahead)(a, buff, 1);
+ bytes_read = (a->decompressor->read_ahead)(a, buff, 1);
if (bytes_read == 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Truncated tar archive");
@@ -499,10 +480,10 @@ archive_read_format_tar_read_data(struct archive_read *a,
*offset = tar->entry_offset;
tar->entry_offset += bytes_read;
tar->entry_bytes_remaining -= bytes_read;
- (a->compression_read_consume)(a, bytes_read);
+ (a->decompressor->consume)(a, bytes_read);
return (ARCHIVE_OK);
} else {
- if ((a->compression_skip)(a, tar->entry_padding) < 0)
+ if ((a->decompressor->skip)(a, tar->entry_padding) < 0)
return (ARCHIVE_FATAL);
tar->entry_padding = 0;
*buff = NULL;
@@ -519,14 +500,14 @@ archive_read_format_tar_skip(struct archive_read *a)
struct tar* tar;
struct sparse_block *p;
- tar = (struct tar *)*(a->pformat_data);
+ tar = (struct tar *)(a->format->data);
/*
* Compression layer skip functions are required to either skip the
* length requested or fail, so we can rely upon the entire entry
* plus padding being skipped.
*/
- bytes_skipped = (a->compression_skip)(a, tar->entry_bytes_remaining +
+ bytes_skipped = (a->decompressor->skip)(a, tar->entry_bytes_remaining +
tar->entry_padding);
if (bytes_skipped < 0)
return (ARCHIVE_FATAL);
@@ -550,7 +531,7 @@ archive_read_format_tar_skip(struct archive_read *a)
*/
static int
tar_read_header(struct archive_read *a, struct tar *tar,
- struct archive_entry *entry, struct stat *st)
+ struct archive_entry *entry)
{
ssize_t bytes;
int err;
@@ -558,7 +539,7 @@ tar_read_header(struct archive_read *a, struct tar *tar,
const struct archive_entry_header_ustar *header;
/* Read 512-byte header record */
- bytes = (a->compression_read_ahead)(a, &h, 512);
+ bytes = (a->decompressor->read_ahead)(a, &h, 512);
if (bytes < 512) {
/*
* If we're here, it's becase the _bid function accepted
@@ -567,14 +548,14 @@ tar_read_header(struct archive_read *a, struct tar *tar,
*/
return (ARCHIVE_EOF);
}
- (a->compression_read_consume)(a, 512);
+ (a->decompressor->consume)(a, 512);
/* Check for end-of-archive mark. */
if (((*(const char *)h)==0) && archive_block_is_null((const unsigned char *)h)) {
/* Try to consume a second all-null record, as well. */
- bytes = (a->compression_read_ahead)(a, &h, 512);
+ bytes = (a->decompressor->read_ahead)(a, &h, 512);
if (bytes > 0)
- (a->compression_read_consume)(a, bytes);
+ (a->decompressor->consume)(a, bytes);
archive_set_error(&a->archive, 0, NULL);
return (ARCHIVE_EOF);
}
@@ -602,48 +583,48 @@ tar_read_header(struct archive_read *a, struct tar *tar,
case 'A': /* Solaris tar ACL */
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);
+ err = header_Solaris_ACL(a, tar, entry, h);
break;
case 'g': /* POSIX-standard 'g' header. */
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);
+ err = header_pax_global(a, tar, entry, h);
break;
case 'K': /* Long link name (GNU tar, others) */
- err = header_longlink(a, tar, entry, st, h);
+ err = header_longlink(a, tar, entry, h);
break;
case 'L': /* Long filename (GNU tar, others) */
- err = header_longname(a, tar, entry, st, h);
+ err = header_longname(a, tar, entry, h);
break;
case 'V': /* GNU volume header */
- err = header_volume(a, tar, entry, st, h);
+ err = header_volume(a, tar, entry, h);
break;
case 'X': /* Used by SUN tar; same as 'x'. */
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);
+ err = header_pax_extensions(a, tar, entry, h);
break;
case 'x': /* POSIX-standard 'x' header. */
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);
+ err = header_pax_extensions(a, tar, entry, h);
break;
default:
if (memcmp(header->magic, "ustar \0", 8) == 0) {
a->archive.archive_format = ARCHIVE_FORMAT_TAR_GNUTAR;
a->archive.archive_format_name = "GNU tar format";
- err = header_gnutar(a, tar, entry, st, h);
+ err = header_gnutar(a, tar, entry, h);
} else if (memcmp(header->magic, "ustar", 5) == 0) {
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);
+ err = header_ustar(a, tar, entry, h);
} else {
a->archive.archive_format = ARCHIVE_FORMAT_TAR;
a->archive.archive_format_name = "tar (non-POSIX)";
- err = header_old_tar(a, tar, entry, st, h);
+ err = header_old_tar(a, tar, entry, h);
}
}
--tar->header_recursion_depth;
@@ -716,14 +697,14 @@ archive_block_is_null(const unsigned char *p)
*/
static int
header_Solaris_ACL(struct archive_read *a, struct tar *tar,
- struct archive_entry *entry, struct stat *st, const void *h)
+ struct archive_entry *entry, const void *h)
{
int err, err2;
char *p;
wchar_t *wp;
err = read_body_to_string(a, tar, &(tar->acl_text), h);
- err2 = tar_read_header(a, tar, entry, st);
+ err2 = tar_read_header(a, tar, entry);
err = err_combine(err, err2);
/* XXX Ensure p doesn't overrun acl_text */
@@ -752,12 +733,12 @@ header_Solaris_ACL(struct archive_read *a, struct tar *tar,
*/
static int
header_longlink(struct archive_read *a, struct tar *tar,
- struct archive_entry *entry, struct stat *st, const void *h)
+ struct archive_entry *entry, const void *h)
{
int err, err2;
err = read_body_to_string(a, tar, &(tar->longlink), h);
- err2 = tar_read_header(a, tar, entry, st);
+ err2 = tar_read_header(a, tar, entry);
if (err == ARCHIVE_OK && err2 == ARCHIVE_OK) {
/* Set symlink if symlink already set, else hardlink. */
archive_entry_set_link(entry, tar->longlink.s);
@@ -770,13 +751,13 @@ header_longlink(struct archive_read *a, struct tar *tar,
*/
static int
header_longname(struct archive_read *a, struct tar *tar,
- struct archive_entry *entry, struct stat *st, const void *h)
+ struct archive_entry *entry, const void *h)
{
int err, err2;
err = read_body_to_string(a, tar, &(tar->longname), h);
/* Read and parse "real" header, then override name. */
- err2 = tar_read_header(a, tar, entry, st);
+ err2 = tar_read_header(a, tar, entry);
if (err == ARCHIVE_OK && err2 == ARCHIVE_OK)
archive_entry_set_pathname(entry, tar->longname.s);
return (err_combine(err, err2));
@@ -788,12 +769,12 @@ header_longname(struct archive_read *a, struct tar *tar,
*/
static int
header_volume(struct archive_read *a, struct tar *tar,
- struct archive_entry *entry, struct stat *st, const void *h)
+ struct archive_entry *entry, const void *h)
{
(void)h;
/* Just skip this and read the next header. */
- return (tar_read_header(a, tar, entry, st));
+ return (tar_read_header(a, tar, entry));
}
/*
@@ -818,12 +799,12 @@ read_body_to_string(struct archive_read *a, struct tar *tar,
padded_size = (size + 511) & ~ 511;
dest = as->s;
while (padded_size > 0) {
- bytes_read = (a->compression_read_ahead)(a, &src, padded_size);
+ bytes_read = (a->decompressor->read_ahead)(a, &src, padded_size);
if (bytes_read < 0)
return (ARCHIVE_FATAL);
if (bytes_read > padded_size)
bytes_read = padded_size;
- (a->compression_read_consume)(a, bytes_read);
+ (a->decompressor->consume)(a, bytes_read);
bytes_to_copy = bytes_read;
if ((off_t)bytes_to_copy > size)
bytes_to_copy = (ssize_t)size;
@@ -847,8 +828,8 @@ read_body_to_string(struct archive_read *a, struct tar *tar,
* common parsing into one place.
*/
static int
-header_common(struct archive_read *a, struct tar *tar, struct archive_entry *entry,
- struct stat *st, const void *h)
+header_common(struct archive_read *a, struct tar *tar,
+ struct archive_entry *entry, const void *h)
{
const struct archive_entry_header_ustar *header;
char tartype;
@@ -863,15 +844,14 @@ header_common(struct archive_read *a, struct tar *tar, struct archive_entry *ent
archive_string_empty(&(tar->entry_linkname));
/* Parse out the numeric fields (all are octal) */
- st->st_mode = tar_atol(header->mode, sizeof(header->mode));
- st->st_uid = tar_atol(header->uid, sizeof(header->uid));
- st->st_gid = tar_atol(header->gid, sizeof(header->gid));
- st->st_size = tar_atol(header->size, sizeof(header->size));
- st->st_mtime = tar_atol(header->mtime, sizeof(header->mtime));
+ archive_entry_set_mode(entry, tar_atol(header->mode, sizeof(header->mode)));
+ archive_entry_set_uid(entry, tar_atol(header->uid, sizeof(header->uid)));
+ archive_entry_set_gid(entry, tar_atol(header->gid, sizeof(header->gid)));
+ archive_entry_set_size(entry, tar_atol(header->size, sizeof(header->size)));
+ archive_entry_set_mtime(entry, tar_atol(header->mtime, sizeof(header->mtime)), 0);
/* Handle the tar type flag appropriately. */
tartype = header->typeflag[0];
- st->st_mode &= ~S_IFMT;
switch (tartype) {
case '1': /* Hard link */
@@ -885,8 +865,8 @@ header_common(struct archive_read *a, struct tar *tar, struct archive_entry *ent
* implies that the underlying entry is a regular
* file.
*/
- if (st->st_size > 0)
- st->st_mode |= S_IFREG;
+ if (archive_entry_size(entry) > 0)
+ archive_entry_set_filetype(entry, AE_IFREG);
/*
* A tricky point: Traditionally, tar readers have
@@ -910,31 +890,31 @@ header_common(struct archive_read *a, struct tar *tar, struct archive_entry *ent
* we encounter a hardlink entry for a file that is
* itself an uncompressed tar archive.
*/
- if (st->st_size > 0 &&
+ if (archive_entry_size(entry) > 0 &&
a->archive.archive_format != ARCHIVE_FORMAT_TAR_PAX_INTERCHANGE &&
archive_read_format_tar_bid(a) > 50)
- st->st_size = 0;
+ archive_entry_set_size(entry, 0);
break;
case '2': /* Symlink */
- st->st_mode |= S_IFLNK;
- st->st_size = 0;
+ archive_entry_set_filetype(entry, AE_IFLNK);
+ archive_entry_set_size(entry, 0);
archive_entry_set_symlink(entry, tar->entry_linkname.s);
break;
case '3': /* Character device */
- st->st_mode |= S_IFCHR;
- st->st_size = 0;
+ archive_entry_set_filetype(entry, AE_IFCHR);
+ archive_entry_set_size(entry, 0);
break;
case '4': /* Block device */
- st->st_mode |= S_IFBLK;
- st->st_size = 0;
+ archive_entry_set_filetype(entry, AE_IFBLK);
+ archive_entry_set_size(entry, 0);
break;
case '5': /* Dir */
- st->st_mode |= S_IFDIR;
- st->st_size = 0;
+ archive_entry_set_filetype(entry, AE_IFDIR);
+ archive_entry_set_size(entry, 0);
break;
case '6': /* FIFO device */
- st->st_mode |= S_IFIFO;
- st->st_size = 0;
+ archive_entry_set_filetype(entry, AE_IFIFO);
+ archive_entry_set_size(entry, 0);
break;
case 'D': /* GNU incremental directory type */
/*
@@ -942,7 +922,7 @@ header_common(struct archive_read *a, struct tar *tar, struct archive_entry *ent
* It might be nice someday to preprocess the file list and
* provide it to the client, though.
*/
- st->st_mode |= S_IFDIR;
+ archive_entry_set_filetype(entry, AE_IFDIR);
break;
case 'M': /* GNU "Multi-volume" (remainder of file from last archive)*/
/*
@@ -956,7 +936,7 @@ header_common(struct archive_read *a, struct tar *tar, struct archive_entry *ent
/* The body of this entry is a script for renaming
* previously-extracted entries. Ugh. It will never
* be supported by libarchive. */
- st->st_mode |= S_IFREG;
+ archive_entry_set_filetype(entry, AE_IFREG);
break;
case 'S': /* GNU sparse files */
/*
@@ -969,7 +949,7 @@ header_common(struct archive_read *a, struct tar *tar, struct archive_entry *ent
* Per POSIX: non-recognized types should always be
* treated as regular files.
*/
- st->st_mode |= S_IFREG;
+ archive_entry_set_filetype(entry, AE_IFREG);
break;
}
return (0);
@@ -979,8 +959,8 @@ header_common(struct archive_read *a, struct tar *tar, struct archive_entry *ent
* Parse out header elements for "old-style" tar archives.
*/
static int
-header_old_tar(struct archive_read *a, struct tar *tar, struct archive_entry *entry,
- struct stat *st, const void *h)
+header_old_tar(struct archive_read *a, struct tar *tar,
+ struct archive_entry *entry, const void *h)
{
const struct archive_entry_header_ustar *header;
@@ -990,9 +970,9 @@ header_old_tar(struct archive_read *a, struct tar *tar, struct archive_entry *en
archive_entry_set_pathname(entry, tar->entry_name.s);
/* Grab rest of common fields */
- header_common(a, tar, entry, st, h);
+ header_common(a, tar, entry, h);
- tar->entry_bytes_remaining = st->st_size;
+ tar->entry_bytes_remaining = archive_entry_size(entry);
tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining);
return (0);
}
@@ -1002,25 +982,25 @@ header_old_tar(struct archive_read *a, struct tar *tar, struct archive_entry *en
*/
static int
header_pax_global(struct archive_read *a, struct tar *tar,
- struct archive_entry *entry, struct stat *st, const void *h)
+ struct archive_entry *entry, const void *h)
{
int err, err2;
err = read_body_to_string(a, tar, &(tar->pax_global), h);
- err2 = tar_read_header(a, tar, entry, st);
+ err2 = tar_read_header(a, tar, entry);
return (err_combine(err, err2));
}
static int
header_pax_extensions(struct archive_read *a, struct tar *tar,
- struct archive_entry *entry, struct stat *st, const void *h)
+ struct archive_entry *entry, const void *h)
{
int err, err2;
read_body_to_string(a, tar, &(tar->pax_header), h);
/* Parse the next header. */
- err = tar_read_header(a, tar, entry, st);
+ err = tar_read_header(a, tar, entry);
/*
* TODO: Parse global/default options into 'entry' struct here
@@ -1032,9 +1012,9 @@ header_pax_extensions(struct archive_read *a, struct tar *tar,
* and then skip any fields in the standard header that were
* defined in the pax header.
*/
- err2 = pax_header(a, tar, entry, st, tar->pax_header.s);
+ err2 = pax_header(a, tar, entry, tar->pax_header.s);
err = err_combine(err, err2);
- tar->entry_bytes_remaining = st->st_size;
+ tar->entry_bytes_remaining = archive_entry_size(entry);
tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining);
return (err);
}
@@ -1045,8 +1025,8 @@ header_pax_extensions(struct archive_read *a, struct tar *tar,
* handles "pax" or "extended ustar" entries.
*/
static int
-header_ustar(struct archive_read *a, struct tar *tar, struct archive_entry *entry,
- struct stat *st, const void *h)
+header_ustar(struct archive_read *a, struct tar *tar,
+ struct archive_entry *entry, const void *h)
{
const struct archive_entry_header_ustar *header;
struct archive_string *as;
@@ -1066,7 +1046,7 @@ header_ustar(struct archive_read *a, struct tar *tar, struct archive_entry *entr
archive_entry_set_pathname(entry, as->s);
/* Handle rest of common fields. */
- header_common(a, tar, entry, st, h);
+ header_common(a, tar, entry, h);
/* Handle POSIX ustar fields. */
archive_strncpy(&(tar->entry_uname), header->uname,
@@ -1079,12 +1059,13 @@ header_ustar(struct archive_read *a, struct tar *tar, struct archive_entry *entr
/* Parse out device numbers only for char and block specials. */
if (header->typeflag[0] == '3' || header->typeflag[0] == '4') {
- st->st_rdev = makedev(
- tar_atol(header->rdevmajor, sizeof(header->rdevmajor)),
+ archive_entry_set_rdevmajor(entry,
+ tar_atol(header->rdevmajor, sizeof(header->rdevmajor)));
+ archive_entry_set_rdevminor(entry,
tar_atol(header->rdevminor, sizeof(header->rdevminor)));
}
- tar->entry_bytes_remaining = st->st_size;
+ tar->entry_bytes_remaining = archive_entry_size(entry);
tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining);
return (0);
@@ -1097,8 +1078,8 @@ header_ustar(struct archive_read *a, struct tar *tar, struct archive_entry *entr
* Returns non-zero if there's an error in the data.
*/
static int
-pax_header(struct archive_read *a, struct tar *tar, struct archive_entry *entry,
- struct stat *st, char *attr)
+pax_header(struct archive_read *a, struct tar *tar,
+ struct archive_entry *entry, char *attr)
{
size_t attr_length, l, line_length;
char *line, *p;
@@ -1179,7 +1160,7 @@ pax_header(struct archive_read *a, struct tar *tar, struct archive_entry *entry,
value = wp + 1;
/* Identify this attribute and set it in the entry. */
- err2 = pax_attribute(entry, st, key, value);
+ err2 = pax_attribute(entry, key, value);
err = err_combine(err, err2);
/* Skip to next line */
@@ -1240,7 +1221,7 @@ pax_attribute_xattr(struct archive_entry *entry,
* any of them look useful.
*/
static int
-pax_attribute(struct archive_entry *entry, struct stat *st,
+pax_attribute(struct archive_entry *entry,
wchar_t *key, wchar_t *value)
{
int64_t s;
@@ -1266,32 +1247,28 @@ pax_attribute(struct archive_entry *entry, struct stat *st,
__archive_entry_acl_parse_w(entry, value,
ARCHIVE_ENTRY_ACL_TYPE_DEFAULT);
else if (wcscmp(key, L"SCHILY.devmajor")==0)
- st->st_rdev = makedev(tar_atol10(value, wcslen(value)),
- minor(st->st_rdev));
+ archive_entry_set_rdevmajor(entry, tar_atol10(value, wcslen(value)));
else if (wcscmp(key, L"SCHILY.devminor")==0)
- st->st_rdev = makedev(major(st->st_rdev),
- tar_atol10(value, wcslen(value)));
+ archive_entry_set_rdevminor(entry, tar_atol10(value, wcslen(value)));
else if (wcscmp(key, L"SCHILY.fflags")==0)
archive_entry_copy_fflags_text_w(entry, value);
else if (wcscmp(key, L"SCHILY.dev")==0)
- st->st_dev = tar_atol10(value, wcslen(value));
+ archive_entry_set_dev(entry, tar_atol10(value, wcslen(value)));
else if (wcscmp(key, L"SCHILY.ino")==0)
- st->st_ino = tar_atol10(value, wcslen(value));
+ archive_entry_set_ino(entry, tar_atol10(value, wcslen(value)));
else if (wcscmp(key, L"SCHILY.nlink")==0)
- st->st_nlink = tar_atol10(value, wcslen(value));
+ archive_entry_set_nlink(entry, tar_atol10(value, wcslen(value)));
break;
case 'a':
if (wcscmp(key, L"atime")==0) {
pax_time(value, &s, &n);
- st->st_atime = s;
- ARCHIVE_STAT_SET_ATIME_NANOS(st, n);
+ archive_entry_set_atime(entry, s, n);
}
break;
case 'c':
if (wcscmp(key, L"ctime")==0) {
pax_time(value, &s, &n);
- st->st_ctime = s;
- ARCHIVE_STAT_SET_CTIME_NANOS(st, n);
+ archive_entry_set_ctime(entry, s, n);
} else if (wcscmp(key, L"charset")==0) {
/* TODO: Publish charset information in entry. */
} else if (wcscmp(key, L"comment")==0) {
@@ -1300,7 +1277,7 @@ pax_attribute(struct archive_entry *entry, struct stat *st,
break;
case 'g':
if (wcscmp(key, L"gid")==0)
- st->st_gid = tar_atol10(value, wcslen(value));
+ archive_entry_set_gid(entry, tar_atol10(value, wcslen(value)));
else if (wcscmp(key, L"gname")==0)
archive_entry_copy_gname_w(entry, value);
break;
@@ -1316,8 +1293,7 @@ pax_attribute(struct archive_entry *entry, struct stat *st,
case 'm':
if (wcscmp(key, L"mtime")==0) {
pax_time(value, &s, &n);
- st->st_mtime = s;
- ARCHIVE_STAT_SET_MTIME_NANOS(st, n);
+ archive_entry_set_mtime(entry, s, n);
}
break;
case 'p':
@@ -1331,11 +1307,11 @@ pax_attribute(struct archive_entry *entry, struct stat *st,
/* POSIX has reserved 'security.*' */
/* Someday: if (wcscmp(key, L"security.acl")==0) { ... } */
if (wcscmp(key, L"size")==0)
- st->st_size = tar_atol10(value, wcslen(value));
+ archive_entry_set_size(entry, tar_atol10(value, wcslen(value)));
break;
case 'u':
if (wcscmp(key, L"uid")==0)
- st->st_uid = tar_atol10(value, wcslen(value));
+ archive_entry_set_uid(entry, tar_atol10(value, wcslen(value)));
else if (wcscmp(key, L"uname")==0)
archive_entry_copy_uname_w(entry, value);
break;
@@ -1399,8 +1375,8 @@ pax_time(const wchar_t *p, int64_t *ps, long *pn)
* Parse GNU tar header
*/
static int
-header_gnutar(struct archive_read *a, struct tar *tar, struct archive_entry *entry,
- struct stat *st, const void *h)
+header_gnutar(struct archive_read *a, struct tar *tar,
+ struct archive_entry *entry, const void *h)
{
const struct archive_entry_header_gnutar *header;
@@ -1413,7 +1389,7 @@ header_gnutar(struct archive_read *a, struct tar *tar, struct archive_entry *ent
*/
/* Grab fields common to all tar variants. */
- header_common(a, tar, entry, st, h);
+ header_common(a, tar, entry, h);
/* Copy filename over (to ensure null termination). */
header = (const struct archive_entry_header_gnutar *)h;
@@ -1434,22 +1410,25 @@ header_gnutar(struct archive_read *a, struct tar *tar, struct archive_entry *ent
archive_entry_set_gname(entry, tar->entry_gname.s);
/* Parse out device numbers only for char and block specials */
- if (header->typeflag[0] == '3' || header->typeflag[0] == '4')
- st->st_rdev = makedev (
- tar_atol(header->rdevmajor, sizeof(header->rdevmajor)),
+ if (header->typeflag[0] == '3' || header->typeflag[0] == '4') {
+ archive_entry_set_rdevmajor(entry,
+ tar_atol(header->rdevmajor, sizeof(header->rdevmajor)));
+ archive_entry_set_rdevminor(entry,
tar_atol(header->rdevminor, sizeof(header->rdevminor)));
- else
- st->st_rdev = 0;
+ } else
+ archive_entry_set_rdev(entry, 0);
- tar->entry_bytes_remaining = st->st_size;
+ tar->entry_bytes_remaining = archive_entry_size(entry);
tar->entry_padding = 0x1ff & (-tar->entry_bytes_remaining);
/* Grab GNU-specific fields. */
- st->st_atime = tar_atol(header->atime, sizeof(header->atime));
- st->st_ctime = tar_atol(header->ctime, sizeof(header->ctime));
+ archive_entry_set_atime(entry,
+ tar_atol(header->atime, sizeof(header->atime)), 0);
+ archive_entry_set_ctime(entry,
+ tar_atol(header->ctime, sizeof(header->ctime)), 0);
if (header->realsize[0] != 0) {
- st->st_size = tar_atol(header->realsize,
- sizeof(header->realsize));
+ archive_entry_set_size(entry,
+ tar_atol(header->realsize, sizeof(header->realsize)));
}
if (header->sparse[0].offset[0] != 0) {
@@ -1481,7 +1460,7 @@ gnu_read_sparse_data(struct archive_read *a, struct tar *tar,
return (ARCHIVE_OK);
do {
- bytes_read = (a->compression_read_ahead)(a, &data, 512);
+ bytes_read = (a->decompressor->read_ahead)(a, &data, 512);
if (bytes_read < 0)
return (ARCHIVE_FATAL);
if (bytes_read < 512) {
@@ -1490,7 +1469,7 @@ gnu_read_sparse_data(struct archive_read *a, struct tar *tar,
"detected while reading sparse file data");
return (ARCHIVE_FATAL);
}
- (a->compression_read_consume)(a, 512);
+ (a->decompressor->consume)(a, 512);
ext = (const struct extended *)data;
gnu_parse_sparse_data(a, tar, ext->sparse, 21);
} while (ext->isextended[0] != 0);
diff --git a/lib/libarchive/archive_read_support_format_zip.c b/lib/libarchive/archive_read_support_format_zip.c
index 857d3f7..a3e8573 100644
--- a/lib/libarchive/archive_read_support_format_zip.c
+++ b/lib/libarchive/archive_read_support_format_zip.c
@@ -26,9 +26,6 @@
#include "archive_platform.h"
__FBSDID("$FreeBSD$");
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
@@ -82,6 +79,7 @@ struct zip {
size_t uncompressed_buffer_size;
#ifdef HAVE_ZLIB_H
z_stream stream;
+ char stream_valid;
#endif
struct archive_string pathname;
@@ -176,7 +174,7 @@ archive_read_format_zip_bid(struct archive_read *a)
if (a->archive.archive_format == ARCHIVE_FORMAT_ZIP)
bid += 1;
- bytes_read = (a->compression_read_ahead)(a, &h, 4);
+ bytes_read = (a->decompressor->read_ahead)(a, &h, 4);
if (bytes_read < 4)
return (-1);
p = (const char *)h;
@@ -208,13 +206,13 @@ archive_read_format_zip_read_header(struct archive_read *a,
if (a->archive.archive_format_name == NULL)
a->archive.archive_format_name = "ZIP";
- zip = (struct zip *)*(a->pformat_data);
+ zip = (struct zip *)(a->format->data);
zip->decompress_init = 0;
zip->end_of_entry = 0;
zip->end_of_entry_cleanup = 0;
zip->entry_uncompressed_bytes_read = 0;
zip->entry_compressed_bytes_read = 0;
- bytes_read = (a->compression_read_ahead)(a, &h, 4);
+ bytes_read = (a->decompressor->read_ahead)(a, &h, 4);
if (bytes_read < 4)
return (ARCHIVE_FATAL);
@@ -263,10 +261,9 @@ zip_read_file_header(struct archive_read *a, struct archive_entry *entry,
const struct zip_file_header *p;
const void *h;
int bytes_read;
- struct stat st;
bytes_read =
- (a->compression_read_ahead)(a, &h, sizeof(struct zip_file_header));
+ (a->decompressor->read_ahead)(a, &h, sizeof(struct zip_file_header));
if (bytes_read < (int)sizeof(struct zip_file_header)) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP file header");
@@ -295,11 +292,11 @@ zip_read_file_header(struct archive_read *a, struct archive_entry *entry,
zip->uncompressed_size = u4(p->uncompressed_size);
zip->compressed_size = u4(p->compressed_size);
- (a->compression_read_consume)(a, sizeof(struct zip_file_header));
+ (a->decompressor->consume)(a, sizeof(struct zip_file_header));
/* Read the filename. */
- bytes_read = (a->compression_read_ahead)(a, &h, zip->filename_length);
+ bytes_read = (a->decompressor->read_ahead)(a, &h, zip->filename_length);
if (bytes_read < zip->filename_length) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP file header");
@@ -307,34 +304,32 @@ zip_read_file_header(struct archive_read *a, struct archive_entry *entry,
}
archive_string_ensure(&zip->pathname, zip->filename_length);
archive_strncpy(&zip->pathname, (const char *)h, zip->filename_length);
- (a->compression_read_consume)(a, zip->filename_length);
+ (a->decompressor->consume)(a, zip->filename_length);
archive_entry_set_pathname(entry, zip->pathname.s);
if (zip->pathname.s[archive_strlen(&zip->pathname) - 1] == '/')
- zip->mode = S_IFDIR | 0777;
+ zip->mode = AE_IFDIR | 0777;
else
- zip->mode = S_IFREG | 0777;
+ zip->mode = AE_IFREG | 0777;
/* Read the extra data. */
- bytes_read = (a->compression_read_ahead)(a, &h, zip->extra_length);
+ bytes_read = (a->decompressor->read_ahead)(a, &h, zip->extra_length);
if (bytes_read < zip->extra_length) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP file header");
return (ARCHIVE_FATAL);
}
process_extra(h, zip);
- (a->compression_read_consume)(a, zip->extra_length);
+ (a->decompressor->consume)(a, zip->extra_length);
/* Populate some additional entry fields: */
- memset(&st, 0, sizeof(st));
- st.st_mode = zip->mode;
- st.st_uid = zip->uid;
- st.st_gid = zip->gid;
- st.st_mtime = zip->mtime;
- st.st_ctime = zip->ctime;
- st.st_atime = zip->atime;
- st.st_size = zip->uncompressed_size;
- archive_entry_copy_stat(entry, &st);
+ archive_entry_set_mode(entry, zip->mode);
+ archive_entry_set_uid(entry, zip->uid);
+ archive_entry_set_gid(entry, zip->gid);
+ archive_entry_set_mtime(entry, zip->mtime, 0);
+ archive_entry_set_ctime(entry, zip->ctime, 0);
+ archive_entry_set_atime(entry, zip->atime, 0);
+ archive_entry_set_size(entry, zip->uncompressed_size);
zip->entry_bytes_remaining = zip->compressed_size;
zip->entry_offset = 0;
@@ -376,7 +371,7 @@ archive_read_format_zip_read_data(struct archive_read *a,
int r;
struct zip *zip;
- zip = (struct zip *)*(a->pformat_data);
+ zip = (struct zip *)(a->format->data);
/*
* If we hit end-of-entry last time, clean up and return
@@ -388,7 +383,7 @@ archive_read_format_zip_read_data(struct archive_read *a,
const void *h;
const char *p;
int bytes_read =
- (a->compression_read_ahead)(a, &h, 16);
+ (a->decompressor->read_ahead)(a, &h, 16);
if (bytes_read < 16) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
@@ -399,7 +394,7 @@ archive_read_format_zip_read_data(struct archive_read *a,
zip->crc32 = i4(p + 4);
zip->compressed_size = u4(p + 8);
zip->uncompressed_size = u4(p + 12);
- bytes_read = (a->compression_read_consume)(a, 16);
+ bytes_read = (a->decompressor->consume)(a, 16);
}
/* Check file size, CRC against these values. */
@@ -482,7 +477,7 @@ zip_read_data_none(struct archive_read *a, const void **buff,
struct zip *zip;
ssize_t bytes_avail;
- zip = (struct zip *)*(a->pformat_data);
+ zip = (struct zip *)(a->format->data);
if (zip->entry_bytes_remaining == 0) {
*buff = NULL;
@@ -497,7 +492,7 @@ zip_read_data_none(struct archive_read *a, const void **buff,
* available bytes; asking for more than that forces the
* decompressor to combine reads by copying data.
*/
- bytes_avail = (a->compression_read_ahead)(a, buff, 1);
+ bytes_avail = (a->decompressor->read_ahead)(a, buff, 1);
if (bytes_avail <= 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP file data");
@@ -505,7 +500,7 @@ zip_read_data_none(struct archive_read *a, const void **buff,
}
if (bytes_avail > zip->entry_bytes_remaining)
bytes_avail = zip->entry_bytes_remaining;
- (a->compression_read_consume)(a, bytes_avail);
+ (a->decompressor->consume)(a, bytes_avail);
*size = bytes_avail;
*offset = zip->entry_offset;
zip->entry_offset += *size;
@@ -525,7 +520,7 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,
const void *compressed_buff;
int r;
- zip = (struct zip *)*(a->pformat_data);
+ zip = (struct zip *)(a->format->data);
/* If the buffer hasn't been allocated, allocate it now. */
if (zip->uncompressed_buffer == NULL) {
@@ -541,13 +536,19 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,
/* If we haven't yet read any data, initialize the decompressor. */
if (!zip->decompress_init) {
- r = inflateInit2(&zip->stream,
- -15 /* Don't check for zlib header */);
+ if (zip->stream_valid)
+ r = inflateReset(&zip->stream);
+ else
+ r = inflateInit2(&zip->stream,
+ -15 /* Don't check for zlib header */);
if (r != Z_OK) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
"Can't initialize ZIP decompression.");
return (ARCHIVE_FATAL);
}
+ /* Stream structure has been set up. */
+ zip->stream_valid = 1;
+ /* We've initialized decompression for this stream. */
zip->decompress_init = 1;
}
@@ -557,7 +558,7 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,
* available bytes; asking for more than that forces the
* decompressor to combine reads by copying data.
*/
- bytes_avail = (a->compression_read_ahead)(a, &compressed_buff, 1);
+ bytes_avail = (a->decompressor->read_ahead)(a, &compressed_buff, 1);
if (bytes_avail <= 0) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"Truncated ZIP file body");
@@ -596,7 +597,7 @@ zip_read_data_deflate(struct archive_read *a, const void **buff,
/* Consume as much as the compressor actually used. */
bytes_avail = zip->stream.total_in;
- (a->compression_read_consume)(a, bytes_avail);
+ (a->decompressor->consume)(a, bytes_avail);
zip->entry_bytes_remaining -= bytes_avail;
zip->entry_compressed_bytes_read += bytes_avail;
@@ -628,7 +629,7 @@ archive_read_format_zip_read_data_skip(struct archive_read *a)
const void *buff = NULL;
ssize_t bytes_avail;
- zip = (struct zip *)*(a->pformat_data);
+ zip = (struct zip *)(a->format->data);
/*
* If the length is at the end, we have no choice but
@@ -650,7 +651,7 @@ archive_read_format_zip_read_data_skip(struct archive_read *a)
* compressed data much more quickly.
*/
while (zip->entry_bytes_remaining > 0) {
- bytes_avail = (a->compression_read_ahead)(a, &buff, 1);
+ bytes_avail = (a->decompressor->read_ahead)(a, &buff, 1);
if (bytes_avail <= 0) {
archive_set_error(&a->archive,
ARCHIVE_ERRNO_FILE_FORMAT,
@@ -659,7 +660,7 @@ archive_read_format_zip_read_data_skip(struct archive_read *a)
}
if (bytes_avail > zip->entry_bytes_remaining)
bytes_avail = zip->entry_bytes_remaining;
- (a->compression_read_consume)(a, bytes_avail);
+ (a->decompressor->consume)(a, bytes_avail);
zip->entry_bytes_remaining -= bytes_avail;
}
/* This entry is finished and done. */
@@ -672,13 +673,16 @@ archive_read_format_zip_cleanup(struct archive_read *a)
{
struct zip *zip;
- zip = (struct zip *)*(a->pformat_data);
- if (zip->uncompressed_buffer != NULL)
- free(zip->uncompressed_buffer);
+ zip = (struct zip *)(a->format->data);
+#ifdef HAVE_ZLIB_H
+ if (zip->stream_valid)
+ inflateEnd(&zip->stream);
+#endif
+ free(zip->uncompressed_buffer);
archive_string_free(&(zip->pathname));
archive_string_free(&(zip->extra));
free(zip);
- *(a->pformat_data) = NULL;
+ (a->format->data) = NULL;
return (ARCHIVE_OK);
}
diff --git a/lib/libarchive/archive_string.c b/lib/libarchive/archive_string.c
index b42bb22..b79c663 100644
--- a/lib/libarchive/archive_string.c
+++ b/lib/libarchive/archive_string.c
@@ -52,6 +52,15 @@ __archive_string_append(struct archive_string *as, const char *p, size_t s)
}
void
+__archive_string_copy(struct archive_string *dest, struct archive_string *src)
+{
+ __archive_string_ensure(dest, src->length + 1);
+ memcpy(dest->s, src->s, src->length);
+ dest->length = src->length;
+ dest->s[dest->length] = 0;
+}
+
+void
__archive_string_free(struct archive_string *as)
{
as->length = 0;
diff --git a/lib/libarchive/archive_string.h b/lib/libarchive/archive_string.h
index 3e9d8d8..b9b5352 100644
--- a/lib/libarchive/archive_string.h
+++ b/lib/libarchive/archive_string.h
@@ -74,6 +74,12 @@ __archive_strappend_int(struct archive_string *as, int d, int base);
struct archive_string *
__archive_string_append(struct archive_string *as, const char *p, size_t s);
+/* Copy one archive_string to another */
+void
+__archive_string_copy(struct archive_string *dest, struct archive_string *src);
+#define archive_string_copy(dest, src) \
+ __archive_string_copy(dest, src)
+
/* Ensure that the underlying buffer is at least as large as the request. */
struct archive_string *
__archive_string_ensure(struct archive_string *, size_t);
diff --git a/lib/libarchive/archive_util.3 b/lib/libarchive/archive_util.3
index a67e529..e9af8b4 100644
--- a/lib/libarchive/archive_util.3
+++ b/lib/libarchive/archive_util.3
@@ -31,6 +31,7 @@
.Nm archive_clear_error ,
.Nm archive_compression ,
.Nm archive_compression_name ,
+.Nm archive_copy_error ,
.Nm archive_errno ,
.Nm archive_error_string ,
.Nm archive_format ,
@@ -45,6 +46,8 @@
.Fn archive_compression "struct archive *"
.Ft const char *
.Fn archive_compression_name "struct archive *"
+.Ft void
+.Fn archive_copy_error "struct archive *" "struct archive *"
.Ft int
.Fn archive_errno "struct archive *"
.Ft const char *
@@ -71,6 +74,8 @@ This value is set by
.Fn archive_read_open .
.It Fn archive_compression_name
Returns a text description of the current compression suitable for display.
+.It Fn archive_copy_error
+Copies error information from one archive to another.
.It Fn archive_errno
Returns a numeric error code (see
.Xr errno 2 )
diff --git a/lib/libarchive/archive_util.c b/lib/libarchive/archive_util.c
index 82e5e02..46e322a 100644
--- a/lib/libarchive/archive_util.c
+++ b/lib/libarchive/archive_util.c
@@ -162,6 +162,15 @@ archive_set_error(struct archive *a, int error_number, const char *fmt, ...)
}
void
+archive_copy_error(struct archive *dest, struct archive *src)
+{
+ dest->archive_error_number = src->archive_error_number;
+
+ archive_string_copy(&dest->error_string, &src->error_string);
+ dest->error = dest->error_string.s;
+}
+
+void
__archive_errx(int retvalue, const char *msg)
{
static const char *msg1 = "Fatal Internal Error in libarchive: ";
diff --git a/lib/libarchive/archive_write.3 b/lib/libarchive/archive_write.3
index 6725a71..3481acb 100644
--- a/lib/libarchive/archive_write.3
+++ b/lib/libarchive/archive_write.3
@@ -38,8 +38,10 @@
.Nm archive_write_get_bytes_per_block ,
.Nm archive_write_set_bytes_per_block ,
.Nm archive_write_set_bytes_in_last_block ,
-.Nm archive_write_set_compressor_gzip ,
-.Nm archive_write_set_compressor_bzip2 ,
+.Nm archive_write_set_compression_bzip2 ,
+.Nm archive_write_set_compression_gzip ,
+.Nm archive_write_set_compression_none ,
+.Nm archive_write_set_compression_program ,
.Nm archive_write_open ,
.Nm archive_write_open_fd ,
.Nm archive_write_open_FILE ,
@@ -62,9 +64,13 @@
.Ft int
.Fn archive_write_set_bytes_in_last_block "struct archive *" "int"
.Ft int
-.Fn archive_write_set_compressor_gzip "struct archive *"
+.Fn archive_write_set_compression_bzip2 "struct archive *"
.Ft int
-.Fn archive_write_set_compressor_bzip2 "struct archive *"
+.Fn archive_write_set_compression_gzip "struct archive *"
+.Ft int
+.Fn archive_write_set_compression_none "struct archive *"
+.Ft int
+.Fn archive_write_set_compression_program "struct archive *" "const char * cmd"
.Ft int
.Fn archive_write_set_format_cpio "struct archive *"
.Ft int
@@ -168,9 +174,13 @@ filenames, linknames, uids, sizes, etc.
is the library default; this is the same as pax format, but suppresses
the pax extended header for most normal files.
In most cases, this will result in ordinary ustar archives.
-.It Fn archive_write_set_compression_gzip , Fn archive_write_set_compression_bzip2
+.It Fn archive_write_set_compression_bzip2 , Fn archive_write_set_compression_gzip , Fn archive_write_set_compression_none
The resulting archive will be compressed as specified.
Note that the compressed output is always properly blocked.
+.It Fn archive_write_set_compression_program
+The archive will be fed into the specified compression program.
+The output of that program is blocked and written to the client
+write callbacks.
.It Fn archive_write_open
Freeze the settings, open the archive, and prepare for writing entries.
This is the most generic form of this function, which accepts
diff --git a/lib/libarchive/archive_write.c b/lib/libarchive/archive_write.c
index ee1a9db..c9d40b0 100644
--- a/lib/libarchive/archive_write.c
+++ b/lib/libarchive/archive_write.c
@@ -99,7 +99,6 @@ archive_write_new(void)
a->archive.vtable = archive_write_vtable();
a->bytes_per_block = ARCHIVE_DEFAULT_BYTES_PER_BLOCK;
a->bytes_in_last_block = -1; /* Default */
- a->pformat_data = &(a->format_data);
/* Initialize a block of nulls for padding purposes. */
a->null_length = 1024;
@@ -208,7 +207,7 @@ archive_write_open(struct archive *_a, void *client_data,
a->client_writer = writer;
a->client_opener = opener;
a->client_closer = closer;
- ret = (a->compression_init)(a);
+ ret = (a->compressor.init)(a);
if (a->format_init && ret == ARCHIVE_OK)
ret = (a->format_init)(a);
return (ret);
@@ -242,7 +241,7 @@ _archive_write_close(struct archive *_a)
r = r1;
}
- /* Release resources. */
+ /* Release format resources. */
if (a->format_destroy != NULL) {
r1 = (a->format_destroy)(a);
if (r1 < r)
@@ -250,8 +249,15 @@ _archive_write_close(struct archive *_a)
}
/* Finish the compression and close the stream. */
- if (a->compression_finish != NULL) {
- r1 = (a->compression_finish)(a);
+ if (a->compressor.finish != NULL) {
+ r1 = (a->compressor.finish)(a);
+ if (r1 < r)
+ r = r1;
+ }
+
+ /* Close out the client stream. */
+ if (a->client_closer != NULL) {
+ r1 = (a->client_closer)(&a->archive, a->client_data);
if (r1 < r)
r = r1;
}
diff --git a/lib/libarchive/archive_write_disk.c b/lib/libarchive/archive_write_disk.c
index 86426f1..9bf7d33 100644
--- a/lib/libarchive/archive_write_disk.c
+++ b/lib/libarchive/archive_write_disk.c
@@ -204,6 +204,7 @@ static void edit_deep_directories(struct archive_write_disk *ad);
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 older(struct stat *, struct archive_entry *);
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 *,
@@ -292,7 +293,11 @@ _archive_write_header(struct archive *_a, struct archive_entry *entry)
a->pst = NULL;
a->current_fixup = NULL;
a->deferred = 0;
- a->entry = entry;
+ if (a->entry) {
+ archive_entry_free(a->entry);
+ a->entry = NULL;
+ }
+ a->entry = archive_entry_clone(entry);
a->fd = -1;
a->offset = 0;
a->uid = a->user_uid;
@@ -544,6 +549,11 @@ _archive_write_finish_entry(struct archive *_a)
close(a->fd);
a->fd = -1;
}
+ /* If there's an entry, we can release it now. */
+ if (a->entry) {
+ archive_entry_free(a->entry);
+ a->entry = NULL;
+ }
a->archive.state = ARCHIVE_STATE_HEADER;
return (ret);
}
@@ -682,21 +692,42 @@ restore_entry(struct archive_write_disk *a)
/* Try creating it first; if this fails, we'll try to recover. */
en = create_filesystem_object(a);
- if (en == ENOTDIR || en == ENOENT) {
+ if ((en == ENOTDIR || en == ENOENT)
+ && !(a->flags & ARCHIVE_EXTRACT_NO_AUTODIR)) {
/* 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 ((en == EISDIR || en == EEXIST)
+ && (a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE)) {
/* If we're not overwriting, we're done. */
- if (a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE) {
- archive_set_error(&a->archive, en, "Already exists");
+ archive_set_error(&a->archive, en, "Already exists");
+ return (ARCHIVE_WARN);
+ }
+
+ /*
+ * Some platforms return EISDIR if you call
+ * open(O_WRONLY | O_EXCL | O_CREAT) on a directory, some
+ * return EEXIST. POSIX is ambiguous, requiring EISDIR
+ * for open(O_WRONLY) on a dir and EEXIST for open(O_EXCL | O_CREAT)
+ * on an existing item.
+ */
+ if (en == EISDIR) {
+ /* 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);
}
-
- /* Find out what's in the way before we go any further. */
+ /* Try again. */
+ en = create_filesystem_object(a);
+ } else if (en == EEXIST) {
+ /*
+ * We know something is in the way, but we don't know what;
+ * we need to find out before we go any further.
+ */
if (lstat(a->name, &a->st) != 0) {
archive_set_error(&a->archive, errno,
"Can't stat existing object");
@@ -705,6 +736,14 @@ restore_entry(struct archive_write_disk *a)
/* TODO: if it's a symlink... */
+ if (a->flags & ARCHIVE_EXTRACT_NO_OVERWRITE_NEWER) {
+ if (!older(&(a->st), a->entry)) {
+ archive_set_error(&a->archive, 0,
+ "File on disk is not older; skipping.");
+ return (ARCHIVE_FAILED);
+ }
+ }
+
/* If it's our archive, we're done. */
if (a->skip_file_dev > 0 &&
a->skip_file_ino > 0 &&
@@ -1405,16 +1444,13 @@ success:
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 = archive_entry_mtime(a->entry);
+ times[1].tv_usec = archive_entry_mtime_nsec(a->entry) / 1000;
- 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;
+ times[0].tv_sec = archive_entry_atime(a->entry);
+ times[0].tv_usec = archive_entry_atime_nsec(a->entry) / 1000;
#ifdef HAVE_FUTIMES
if (a->fd >= 0 && futimes(a->fd, times) == 0) {
@@ -1450,11 +1486,10 @@ set_time(struct archive_write_disk *a)
static int
set_time(struct archive_write_disk *a)
{
- const struct stat *st = archive_entry_stat(a->entry);
struct utimbuf times;
- times.modtime = st->st_mtime;
- times.actime = st->st_atime;
+ times.modtime = archive_entry_mtime(a->entry);
+ times.actime = archive_entry_atime(a->entry);
if (!S_ISLNK(a->mode) && utime(a->name, &times) != 0) {
archive_set_error(&a->archive, errno,
"Can't update time for %s", a->name);
@@ -1479,6 +1514,7 @@ static int
set_mode(struct archive_write_disk *a, int mode)
{
int r = ARCHIVE_OK;
+ mode &= 07777; /* Strip off file type bits. */
if (a->todo & TODO_SGID_CHECK) {
/*
@@ -1539,7 +1575,8 @@ set_mode(struct archive_write_disk *a, int mode)
* impact.
*/
if (lchmod(a->name, mode) != 0) {
- archive_set_error(&a->archive, errno, "Can't set permissions");
+ archive_set_error(&a->archive, errno,
+ "Can't set permissions to 0%o", (int)mode);
r = ARCHIVE_WARN;
}
#endif
@@ -1554,7 +1591,7 @@ set_mode(struct archive_write_disk *a, int mode)
if (a->fd >= 0) {
if (fchmod(a->fd, mode) != 0) {
archive_set_error(&a->archive, errno,
- "Can't set permissions");
+ "Can't set permissions to 0%o", (int)mode);
r = ARCHIVE_WARN;
}
} else
@@ -1563,7 +1600,7 @@ set_mode(struct archive_write_disk *a, int mode)
* we'll just use chmod(). */
if (chmod(a->name, mode) != 0) {
archive_set_error(&a->archive, errno,
- "Can't set permissions");
+ "Can't set permissions to 0%o", (int)mode);
r = ARCHIVE_WARN;
}
}
@@ -1998,3 +2035,38 @@ trivial_lookup_uid(void *private_data, const char *uname, uid_t uid)
(void)uname; /* UNUSED */
return (uid);
}
+
+/*
+ * Test if file on disk is older than entry.
+ */
+static int
+older(struct stat *st, struct archive_entry *entry)
+{
+ /* First, test the seconds and return if we have a definite answer. */
+ /* Definitely older. */
+ if (st->st_mtime < archive_entry_mtime(entry))
+ return (1);
+ /* Definitely younger. */
+ if (st->st_mtime > archive_entry_mtime(entry))
+ return (0);
+ /* If this platform supports fractional seconds, try those. */
+#if HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC
+ /* Definitely older. */
+ if (st->st_mtimespec.tv_nsec < archive_entry_mtime_nsec(entry))
+ return (1);
+ /* Definitely younger. */
+ if (st->st_mtimespec.tv_nsec > archive_entry_mtime_nsec(entry))
+ return (0);
+#elif HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
+ /* Definitely older. */
+ if (st->st_mtim.tv_nsec < archive_entry_mtime_nsec(entry))
+ return (1);
+ /* Definitely older. */
+ if (st->st_mtim.tv_nsec > archive_entry_mtime_nsec(entry))
+ return (0);
+#else
+ /* This system doesn't have high-res timestamps. */
+#endif
+ /* Same age, so not older. */
+ return (0);
+}
diff --git a/lib/libarchive/archive_write_disk_set_standard_lookup.c b/lib/libarchive/archive_write_disk_set_standard_lookup.c
index 25c8b86..39f5891 100644
--- a/lib/libarchive/archive_write_disk_set_standard_lookup.c
+++ b/lib/libarchive/archive_write_disk_set_standard_lookup.c
@@ -29,22 +29,6 @@ __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
diff --git a/lib/libarchive/archive_write_private.h b/lib/libarchive/archive_write_private.h
index c551b46..7764fdd 100644
--- a/lib/libarchive/archive_write_private.h
+++ b/lib/libarchive/archive_write_private.h
@@ -35,9 +35,7 @@
struct archive_write {
struct archive archive;
- struct archive_entry *entry;
-
- /* Dev/ino of the archive being read/written. */
+ /* Dev/ino of the archive being written. */
dev_t skip_file_dev;
ino_t skip_file_ino;
@@ -45,19 +43,8 @@ struct archive_write {
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;
@@ -86,64 +73,26 @@ struct archive_write {
* 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);
+ struct {
+ void *data;
+ void *config;
+ int (*init)(struct archive_write *);
+ int (*finish)(struct archive_write *);
+ int (*write)(struct archive_write *, const void *, size_t);
+ } compressor;
/*
- * 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.
*/
+ void *format_data;
int (*format_init)(struct archive_write *);
int (*format_finish)(struct archive_write *);
int (*format_destroy)(struct archive_write *);
@@ -152,12 +101,6 @@ 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 *);
};
/*
diff --git a/lib/libarchive/archive_write_set_compression_bzip2.c b/lib/libarchive/archive_write_set_compression_bzip2.c
index eab8c70..58cd8a6 100644
--- a/lib/libarchive/archive_write_set_compression_bzip2.c
+++ b/lib/libarchive/archive_write_set_compression_bzip2.c
@@ -79,7 +79,7 @@ archive_write_set_compression_bzip2(struct archive *_a)
struct archive_write *a = (struct archive_write *)_a;
__archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_set_compression_bzip2");
- a->compression_init = &archive_compressor_bzip2_init;
+ a->compressor.init = &archive_compressor_bzip2_init;
return (ARCHIVE_OK);
}
@@ -121,13 +121,13 @@ archive_compressor_bzip2_init(struct archive_write *a)
state->stream.next_out = state->compressed;
state->stream.avail_out = state->compressed_buffer_size;
- a->compression_write = archive_compressor_bzip2_write;
- a->compression_finish = archive_compressor_bzip2_finish;
+ a->compressor.write = archive_compressor_bzip2_write;
+ a->compressor.finish = archive_compressor_bzip2_finish;
/* Initialize compression library */
ret = BZ2_bzCompressInit(&(state->stream), 9, 0, 30);
if (ret == BZ_OK) {
- a->compression_data = state;
+ a->compressor.data = state;
return (ARCHIVE_OK);
}
@@ -171,7 +171,7 @@ archive_compressor_bzip2_write(struct archive_write *a, const void *buff,
{
struct private_data *state;
- state = (struct private_data *)a->compression_data;
+ state = (struct private_data *)a->compressor.data;
if (a->client_writer == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"No write callback is registered? "
@@ -205,7 +205,7 @@ archive_compressor_bzip2_finish(struct archive_write *a)
ssize_t bytes_written;
unsigned tocopy;
- state = (struct private_data *)a->compression_data;
+ state = (struct private_data *)a->compressor.data;
ret = ARCHIVE_OK;
if (a->client_writer == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
@@ -282,11 +282,6 @@ cleanup:
free(state->compressed);
free(state);
-
- /* Close the output */
- if (a->client_closer != NULL)
- (a->client_closer)(&a->archive, a->client_data);
-
return (ret);
}
diff --git a/lib/libarchive/archive_write_set_compression_gzip.c b/lib/libarchive/archive_write_set_compression_gzip.c
index 38742f3..8c6d427 100644
--- a/lib/libarchive/archive_write_set_compression_gzip.c
+++ b/lib/libarchive/archive_write_set_compression_gzip.c
@@ -81,7 +81,7 @@ archive_write_set_compression_gzip(struct archive *_a)
struct archive_write *a = (struct archive_write *)_a;
__archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_set_compression_gzip");
- a->compression_init = &archive_compressor_gzip_init;
+ a->compressor.init = &archive_compressor_gzip_init;
a->archive.compression_code = ARCHIVE_COMPRESSION_GZIP;
a->archive.compression_name = "gzip";
return (ARCHIVE_OK);
@@ -143,8 +143,8 @@ archive_compressor_gzip_init(struct archive_write *a)
state->stream.next_out += 10;
state->stream.avail_out -= 10;
- a->compression_write = archive_compressor_gzip_write;
- a->compression_finish = archive_compressor_gzip_finish;
+ a->compressor.write = archive_compressor_gzip_write;
+ a->compressor.finish = archive_compressor_gzip_finish;
/* Initialize compression library. */
ret = deflateInit2(&(state->stream),
@@ -155,7 +155,7 @@ archive_compressor_gzip_init(struct archive_write *a)
Z_DEFAULT_STRATEGY);
if (ret == Z_OK) {
- a->compression_data = state;
+ a->compressor.data = state;
return (0);
}
@@ -196,7 +196,7 @@ archive_compressor_gzip_write(struct archive_write *a, const void *buff,
struct private_data *state;
int ret;
- state = (struct private_data *)a->compression_data;
+ state = (struct private_data *)a->compressor.data;
if (a->client_writer == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
"No write callback is registered? "
@@ -231,7 +231,7 @@ archive_compressor_gzip_finish(struct archive_write *a)
unsigned tocopy;
unsigned char trailer[8];
- state = (struct private_data *)a->compression_data;
+ state = (struct private_data *)a->compressor.data;
ret = 0;
if (a->client_writer == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
@@ -340,11 +340,6 @@ cleanup:
}
free(state->compressed);
free(state);
-
- /* Close the output */
- if (a->client_closer != NULL)
- (a->client_closer)(&a->archive, a->client_data);
-
return (ret);
}
diff --git a/lib/libarchive/archive_write_set_compression_none.c b/lib/libarchive/archive_write_set_compression_none.c
index b5093ce..1fc8f11 100644
--- a/lib/libarchive/archive_write_set_compression_none.c
+++ b/lib/libarchive/archive_write_set_compression_none.c
@@ -58,7 +58,7 @@ archive_write_set_compression_none(struct archive *_a)
struct archive_write *a = (struct archive_write *)_a;
__archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
ARCHIVE_STATE_NEW, "archive_write_set_compression_none");
- a->compression_init = &archive_compressor_none_init;
+ a->compressor.init = &archive_compressor_none_init;
return (0);
}
@@ -102,9 +102,9 @@ archive_compressor_none_init(struct archive_write *a)
state->next = state->buffer;
state->avail = state->buffer_size;
- a->compression_data = state;
- a->compression_write = archive_compressor_none_write;
- a->compression_finish = archive_compressor_none_finish;
+ a->compressor.data = state;
+ a->compressor.write = archive_compressor_none_write;
+ a->compressor.finish = archive_compressor_none_finish;
return (ARCHIVE_OK);
}
@@ -120,7 +120,7 @@ archive_compressor_none_write(struct archive_write *a, const void *vbuff,
ssize_t bytes_written;
struct archive_none *state;
- state = (struct archive_none *)a->compression_data;
+ state = (struct archive_none *)a->compressor.data;
buff = (const char *)vbuff;
if (a->client_writer == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
@@ -194,7 +194,7 @@ archive_compressor_none_finish(struct archive_write *a)
int ret2;
struct archive_none *state;
- state = (struct archive_none *)a->compression_data;
+ state = (struct archive_none *)a->compressor.data;
ret = ret2 = ARCHIVE_OK;
if (a->client_writer == NULL) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
@@ -233,15 +233,10 @@ archive_compressor_none_finish(struct archive_write *a)
ret = ARCHIVE_OK;
}
}
-
- /* Close the output */
- if (a->client_closer != NULL)
- ret2 = (a->client_closer)(&a->archive, a->client_data);
-
if (state->buffer)
free(state->buffer);
free(state);
- a->compression_data = NULL;
+ a->compressor.data = NULL;
- return (ret != ARCHIVE_OK ? ret : ret2);
+ return (ret);
}
diff --git a/lib/libarchive/archive_write_set_compression_program.c b/lib/libarchive/archive_write_set_compression_program.c
new file mode 100644
index 0000000..4f28a0f
--- /dev/null
+++ b/lib/libarchive/archive_write_set_compression_program.c
@@ -0,0 +1,322 @@
+/*-
+ * Copyright (c) 2007 Joerg Sonnenberger
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_SYS_WAIT_H
+# include <sys/wait.h>
+#endif
+#ifdef HAVE_ERRNO_H
+# include <errno.h>
+#endif
+#ifdef HAVE_FCNTL_H
+# include <fcntl.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_write_private.h"
+
+#include "filter_fork.h"
+
+struct private_data {
+ char *description;
+ pid_t child;
+ int child_stdin, child_stdout;
+
+ char *child_buf;
+ size_t child_buf_len, child_buf_avail;
+};
+
+static int archive_compressor_program_finish(struct archive_write *);
+static int archive_compressor_program_init(struct archive_write *);
+static int archive_compressor_program_write(struct archive_write *,
+ const void *, size_t);
+
+/*
+ * Allocate, initialize and return a archive object.
+ */
+int
+archive_write_set_compression_program(struct archive *_a, const char *cmd)
+{
+ struct archive_write *a = (struct archive_write *)_a;
+ __archive_check_magic(&a->archive, ARCHIVE_WRITE_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_write_set_compression_program");
+ a->compressor.init = &archive_compressor_program_init;
+ a->compressor.config = strdup(cmd);
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Setup callback.
+ */
+static int
+archive_compressor_program_init(struct archive_write *a)
+{
+ int ret;
+ struct private_data *state;
+ static const char *prefix = "Program: ";
+ char *cmd = a->compressor.config;
+
+ if (a->client_opener != NULL) {
+ ret = (a->client_opener)(&a->archive, a->client_data);
+ if (ret != ARCHIVE_OK)
+ return (ret);
+ }
+
+ state = (struct private_data *)malloc(sizeof(*state));
+ if (state == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate data for compression");
+ return (ARCHIVE_FATAL);
+ }
+ memset(state, 0, sizeof(*state));
+
+ a->archive.compression_code = ARCHIVE_COMPRESSION_PROGRAM;
+ state->description = (char *)malloc(strlen(prefix) + strlen(cmd) + 1);
+ strcpy(state->description, prefix);
+ strcat(state->description, cmd);
+ a->archive.compression_name = state->description;
+
+ state->child_buf_len = a->bytes_per_block;
+ state->child_buf_avail = 0;
+ state->child_buf = malloc(state->child_buf_len);
+
+ if (state->child_buf == NULL) {
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate data for compression buffer");
+ free(state);
+ return (ARCHIVE_FATAL);
+ }
+
+ if ((state->child = __archive_create_child(cmd,
+ &state->child_stdin, &state->child_stdout)) == -1) {
+ archive_set_error(&a->archive, EINVAL,
+ "Can't initialise filter");
+ free(state->child_buf);
+ free(state);
+ return (ARCHIVE_FATAL);
+ }
+
+ a->compressor.write = archive_compressor_program_write;
+ a->compressor.finish = archive_compressor_program_finish;
+
+ a->compressor.data = state;
+ return (0);
+}
+
+static ssize_t
+child_write(struct archive_write *a, const char *buf, size_t buf_len)
+{
+ struct private_data *state = a->compressor.data;
+ ssize_t ret;
+
+ if (state->child_stdin == -1)
+ return (-1);
+
+ if (buf_len == 0)
+ return (-1);
+
+restart_write:
+ do {
+ ret = write(state->child_stdin, buf, buf_len);
+ } while (ret == -1 && errno == EINTR);
+
+ if (ret > 0)
+ return (ret);
+ if (ret == 0) {
+ close(state->child_stdin);
+ state->child_stdin = -1;
+ fcntl(state->child_stdout, F_SETFL, 0);
+ return (0);
+ }
+ if (ret == -1 && errno != EAGAIN)
+ return (-1);
+
+ do {
+ ret = read(state->child_stdout,
+ state->child_buf + state->child_buf_avail,
+ state->child_buf_len - state->child_buf_avail);
+ } while (ret == -1 && errno == EINTR);
+
+ if (ret == 0 || (ret == -1 && errno == EPIPE)) {
+ close(state->child_stdout);
+ state->child_stdout = -1;
+ fcntl(state->child_stdin, F_SETFL, 0);
+ goto restart_write;
+ }
+ if (ret == -1 && errno == EAGAIN) {
+ __archive_check_child(state->child_stdin, state->child_stdout);
+ goto restart_write;
+ }
+ if (ret == -1)
+ return (-1);
+
+ state->child_buf_avail += ret;
+
+ ret = (a->client_writer)(&a->archive, a->client_data,
+ state->child_buf, state->child_buf_avail);
+ if (ret <= 0)
+ return (-1);
+
+ if ((size_t)ret < state->child_buf_avail) {
+ memmove(state->child_buf, state->child_buf + ret,
+ state->child_buf_avail - ret);
+ }
+ state->child_buf_avail -= ret;
+ a->archive.raw_position += ret;
+ goto restart_write;
+}
+
+/*
+ * Write data to the compressed stream.
+ */
+static int
+archive_compressor_program_write(struct archive_write *a, const void *buff,
+ size_t length)
+{
+ struct private_data *state;
+ ssize_t ret;
+ const char *buf;
+
+ state = (struct private_data *)a->compressor.data;
+ if (a->client_writer == NULL) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
+ "No write callback is registered? "
+ "This is probably an internal programming error.");
+ return (ARCHIVE_FATAL);
+ }
+
+ buf = buff;
+ while (length > 0) {
+ ret = child_write(a, buf, length);
+ if (ret == -1 || ret == 0) {
+ archive_set_error(&a->archive, EIO,
+ "Can't write to filter");
+ return (ARCHIVE_FATAL);
+ }
+ length -= ret;
+ buf += ret;
+ }
+
+ a->archive.file_position += length;
+ return (ARCHIVE_OK);
+}
+
+
+/*
+ * Finish the compression...
+ */
+static int
+archive_compressor_program_finish(struct archive_write *a)
+{
+ int ret, status;
+ ssize_t bytes_read, bytes_written;
+ struct private_data *state;
+
+ state = (struct private_data *)a->compressor.data;
+ ret = 0;
+ if (a->client_writer == NULL) {
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_PROGRAMMER,
+ "No write callback is registered? "
+ "This is probably an internal programming error.");
+ ret = ARCHIVE_FATAL;
+ goto cleanup;
+ }
+
+ /* XXX pad compressed data. */
+
+ close(state->child_stdin);
+ state->child_stdin = -1;
+ fcntl(state->child_stdout, F_SETFL, 0);
+
+ for (;;) {
+ do {
+ bytes_read = read(state->child_stdout,
+ state->child_buf + state->child_buf_avail,
+ state->child_buf_len - state->child_buf_avail);
+ } while (bytes_read == -1 && errno == EINTR);
+
+ if (bytes_read == 0 || (bytes_read == -1 && errno == EPIPE))
+ break;
+
+ if (bytes_read == -1) {
+ archive_set_error(&a->archive, errno,
+ "Read from filter failed unexpectedly.");
+ ret = ARCHIVE_FATAL;
+ goto cleanup;
+ }
+ state->child_buf_avail += bytes_read;
+
+ bytes_written = (a->client_writer)(&a->archive, a->client_data,
+ state->child_buf, state->child_buf_avail);
+ if (bytes_written <= 0) {
+ ret = ARCHIVE_FATAL;
+ goto cleanup;
+ }
+ if ((size_t)bytes_written < state->child_buf_avail) {
+ memmove(state->child_buf,
+ state->child_buf + bytes_written,
+ state->child_buf_avail - bytes_written);
+ }
+ state->child_buf_avail -= bytes_written;
+ a->archive.raw_position += bytes_written;
+ }
+
+ /* XXX pad final compressed block. */
+
+cleanup:
+ /* Shut down the child. */
+ if (state->child_stdin != -1)
+ close(state->child_stdin);
+ if (state->child_stdout != -1)
+ close(state->child_stdout);
+ while (waitpid(state->child, &status, 0) == -1 && errno == EINTR)
+ continue;
+
+ if (status != 0) {
+ archive_set_error(&a->archive, EIO,
+ "Filter exited with failure.");
+ ret = ARCHIVE_FATAL;
+ }
+
+ /* Release our configuration data. */
+ free(a->compressor.config);
+ a->compressor.config = NULL;
+
+ /* Release our private state data. */
+ free(state->child_buf);
+ free(state->description);
+ free(state);
+ return (ret);
+}
diff --git a/lib/libarchive/archive_write_set_format_ar.c b/lib/libarchive/archive_write_set_format_ar.c
index 7658a8f..1b17282 100644
--- a/lib/libarchive/archive_write_set_format_ar.c
+++ b/lib/libarchive/archive_write_set_format_ar.c
@@ -28,9 +28,6 @@
#include "archive_platform.h"
__FBSDID("$FreeBSD$");
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
@@ -72,31 +69,22 @@ struct ar_w {
#define AR_fmag_offset 58
#define AR_fmag_size 2
-/*
- * "ar" magic numbers.
- */
-#define ARMAG "!<arch>\n"
-#define SARMAG 8 /* strlen(ARMAG); */
-#define AR_EFMT1 "#1/"
-#define SAR_EFMT1 3 /* strlen(AR_EFMT1); */
-#define ARFMAG "`\n"
-#define SARFMAG 2 /* strlen(ARFMAG); */
-
-static int __archive_write_set_format_ar(struct archive_write *);
-static int archive_write_ar_header(struct archive_write *,
- struct archive_entry *);
-static ssize_t archive_write_ar_data(struct archive_write *, const void *buff,
- size_t s);
-static int archive_write_ar_destroy(struct archive_write *);
-static int archive_write_ar_finish_entry(struct archive_write *);
-static int format_octal(int64_t v, char *p, int s);
-static int format_decimal(int64_t v, char *p, int s);
+static int archive_write_set_format_ar(struct archive_write *);
+static int archive_write_ar_header(struct archive_write *,
+ struct archive_entry *);
+static ssize_t archive_write_ar_data(struct archive_write *,
+ const void *buff, size_t s);
+static int archive_write_ar_destroy(struct archive_write *);
+static int archive_write_ar_finish_entry(struct archive_write *);
+static const char *basename(const char *path);
+static int format_octal(int64_t v, char *p, int s);
+static int format_decimal(int64_t v, char *p, int s);
int
archive_write_set_format_ar_bsd(struct archive *_a)
{
struct archive_write *a = (struct archive_write *)_a;
- int r = __archive_write_set_format_ar(a);
+ int r = archive_write_set_format_ar(a);
if (r == ARCHIVE_OK) {
a->archive_format = ARCHIVE_FORMAT_AR_BSD;
a->archive_format_name = "ar (BSD)";
@@ -108,7 +96,7 @@ int
archive_write_set_format_ar_svr4(struct archive *_a)
{
struct archive_write *a = (struct archive_write *)_a;
- int r = __archive_write_set_format_ar(a);
+ int r = archive_write_set_format_ar(a);
if (r == ARCHIVE_OK) {
a->archive_format = ARCHIVE_FORMAT_AR_GNU;
a->archive_format_name = "ar (GNU/SVR4)";
@@ -120,7 +108,7 @@ archive_write_set_format_ar_svr4(struct archive *_a)
* Generic initialization.
*/
static int
-__archive_write_set_format_ar(struct archive_write *a)
+archive_write_set_format_ar(struct archive_write *a)
{
struct ar_w *ar;
@@ -151,40 +139,48 @@ archive_write_ar_header(struct archive_write *a, struct archive_entry *entry)
char buff[60];
char *ss, *se;
struct ar_w *ar;
- const char *pp;
- const struct stat *st;
+ const char *pathname;
+ const char *filename;
ret = 0;
append_fn = 0;
ar = (struct ar_w *)a->format_data;
ar->is_strtab = 0;
-
- if (a->archive.file_position == 0) {
- /*
- * We are now at the beginning of the archive,
- * so we need first write the ar global header.
- */
- (a->compression_write)(a, ARMAG, SARMAG);
+ filename = NULL;
+
+ /*
+ * Reject files with empty name.
+ */
+ pathname = archive_entry_pathname(entry);
+ if (*pathname == '\0') {
+ archive_set_error(&a->archive, EINVAL,
+ "Invalid filename");
+ return (ARCHIVE_WARN);
}
- memset(buff, ' ', 60);
- strncpy(&buff[AR_fmag_offset], ARFMAG, SARFMAG);
+ /*
+ * If we are now at the beginning of the archive,
+ * we need first write the ar global header.
+ */
+ if (a->archive.file_position == 0)
+ (a->compressor.write)(a, "!<arch>\n", 8);
- pp = archive_entry_pathname(entry);
+ memset(buff, ' ', 60);
+ strncpy(&buff[AR_fmag_offset], "`\n", 2);
- if (strcmp(pp, "/") == 0 ) {
+ if (strcmp(pathname, "/") == 0 ) {
/* Entry is archive symbol table in GNU format */
buff[AR_name_offset] = '/';
goto stat;
}
- if (strcmp(pp, "__.SYMDEF") == 0) {
+ if (strcmp(pathname, "__.SYMDEF") == 0) {
/* Entry is archive symbol table in BSD format */
strncpy(buff + AR_name_offset, "__.SYMDEF", 9);
goto stat;
}
- if (strcmp(pp, "//") == 0) {
+ if (strcmp(pathname, "//") == 0) {
/*
- * Entry is archive string table, inform that we should
+ * Entry is archive filename table, inform that we should
* collect strtab in next _data call.
*/
ar->is_strtab = 1;
@@ -196,7 +192,17 @@ archive_write_ar_header(struct archive_write *a, struct archive_entry *entry)
goto size;
}
- /* Otherwise, entry is a normal archive member. */
+ /*
+ * Otherwise, entry is a normal archive member.
+ * Strip leading paths from filenames, if any.
+ */
+ if ((filename = basename(pathname)) == NULL) {
+ /* Reject filenames with trailing "/" */
+ archive_set_error(&a->archive, EINVAL,
+ "Invalid filename");
+ return (ARCHIVE_WARN);
+ }
+
if (a->archive_format == ARCHIVE_FORMAT_AR_GNU) {
/*
* SVR4/GNU variant use a "/" to mark then end of the filename,
@@ -204,9 +210,10 @@ archive_write_ar_header(struct archive_write *a, struct archive_entry *entry)
* So, the longest filename here (without extension) is
* actually 15 bytes.
*/
- if (strlen(pp) <= 15) {
- strncpy(&buff[AR_name_offset], pp, strlen(pp));
- buff[AR_name_offset + strlen(pp)] = '/';
+ if (strlen(filename) <= 15) {
+ strncpy(&buff[AR_name_offset],
+ filename, strlen(filename));
+ buff[AR_name_offset + strlen(filename)] = '/';
} else {
/*
* For filename longer than 15 bytes, GNU variant
@@ -220,15 +227,15 @@ archive_write_ar_header(struct archive_write *a, struct archive_entry *entry)
return (ARCHIVE_WARN);
}
- se = (char *)malloc(strlen(pp) + 3);
+ se = (char *)malloc(strlen(filename) + 3);
if (se == NULL) {
archive_set_error(&a->archive, ENOMEM,
"Can't allocate filename buffer");
return (ARCHIVE_FATAL);
}
- strncpy(se, pp, strlen(pp));
- strcpy(se + strlen(pp), "/\n");
+ strncpy(se, filename, strlen(filename));
+ strcpy(se + strlen(filename), "/\n");
ss = strstr(ar->strtab, se);
free(se);
@@ -263,47 +270,55 @@ archive_write_ar_header(struct archive_write *a, struct archive_entry *entry)
* The name is then written immediately following the
* archive header.
*/
- if (strlen(pp) <= 16 && strchr(pp, ' ') == NULL) {
- strncpy(&buff[AR_name_offset], pp, strlen(pp));
- buff[AR_name_offset + strlen(pp)] = ' ';
+ if (strlen(filename) <= 16 && strchr(filename, ' ') == NULL) {
+ strncpy(&buff[AR_name_offset], filename, strlen(filename));
+ buff[AR_name_offset + strlen(filename)] = ' ';
}
else {
- strncpy(buff + AR_name_offset, AR_EFMT1, SAR_EFMT1);
- if (format_decimal(strlen(pp),
- buff + AR_name_offset + SAR_EFMT1,
- AR_name_size - SAR_EFMT1)) {
+ strncpy(buff + AR_name_offset, "#1/", 3);
+ if (format_decimal(strlen(filename),
+ buff + AR_name_offset + 3,
+ AR_name_size - 3)) {
archive_set_error(&a->archive, ERANGE,
"File name too long");
return (ARCHIVE_WARN);
}
append_fn = 1;
archive_entry_set_size(entry,
- archive_entry_size(entry) + strlen(pp));
+ archive_entry_size(entry) + strlen(filename));
}
}
stat:
- st = archive_entry_stat(entry);
- if (format_decimal(st->st_mtime, buff + AR_date_offset, AR_date_size)) {
+ if (format_decimal(archive_entry_mtime(entry), buff + AR_date_offset, AR_date_size)) {
archive_set_error(&a->archive, ERANGE,
"File modification time too large");
return (ARCHIVE_WARN);
}
- if (format_decimal(st->st_uid, buff + AR_uid_offset, AR_uid_size)) {
+ if (format_decimal(archive_entry_uid(entry), buff + AR_uid_offset, AR_uid_size)) {
archive_set_error(&a->archive, ERANGE,
"Numeric user ID too large");
return (ARCHIVE_WARN);
}
- if (format_decimal(st->st_gid, buff + AR_gid_offset, AR_gid_size)) {
+ if (format_decimal(archive_entry_gid(entry), buff + AR_gid_offset, AR_gid_size)) {
archive_set_error(&a->archive, ERANGE,
"Numeric group ID too large");
return (ARCHIVE_WARN);
}
- if (format_octal(st->st_mode, buff + AR_mode_offset, AR_mode_size)) {
+ if (format_octal(archive_entry_mode(entry), buff + AR_mode_offset, AR_mode_size)) {
archive_set_error(&a->archive, ERANGE,
"Numeric mode too large");
return (ARCHIVE_WARN);
}
+ /*
+ * Sanity Check: A non-pseudo archive member should always be
+ * a regular file.
+ */
+ if (filename != NULL && archive_entry_filetype(entry) != AE_IFREG) {
+ archive_set_error(&a->archive, EINVAL,
+ "Regular file required for non-pseudo member");
+ return (ARCHIVE_WARN);
+ }
size:
if (format_decimal(archive_entry_size(entry), buff + AR_size_offset,
@@ -313,7 +328,7 @@ size:
return (ARCHIVE_WARN);
}
- ret = (a->compression_write)(a, buff, 60);
+ ret = (a->compressor.write)(a, buff, 60);
if (ret != ARCHIVE_OK)
return (ret);
@@ -321,10 +336,10 @@ size:
ar->entry_padding = ar->entry_bytes_remaining % 2;
if (append_fn > 0) {
- ret = (a->compression_write)(a, pp, strlen(pp));
+ ret = (a->compressor.write)(a, filename, strlen(filename));
if (ret != ARCHIVE_OK)
return (ret);
- ar->entry_bytes_remaining -= strlen(pp);
+ ar->entry_bytes_remaining -= strlen(filename);
}
return (ARCHIVE_OK);
@@ -357,7 +372,7 @@ archive_write_ar_data(struct archive_write *a, const void *buff, size_t s)
ar->has_strtab = 1;
}
- ret = (a->compression_write)(a, buff, s);
+ ret = (a->compressor.write)(a, buff, s);
if (ret != ARCHIVE_OK)
return (ret);
@@ -407,7 +422,7 @@ archive_write_ar_finish_entry(struct archive_write *a)
return (ARCHIVE_WARN);
}
- ret = (a->compression_write)(a, "\n", 1);
+ ret = (a->compressor.write)(a, "\n", 1);
return (ret);
}
@@ -490,3 +505,24 @@ format_decimal(int64_t v, char *p, int s)
return (-1);
}
+
+static const char *
+basename(const char *path)
+{
+ const char *endp, *startp;
+
+ endp = path + strlen(path) - 1;
+ /*
+ * For filename with trailing slash(es), we return
+ * NULL indicating an error.
+ */
+ if (*endp == '/')
+ return (NULL);
+
+ /* Find the start of the base */
+ startp = endp;
+ while (startp > path && *(startp - 1) != '/')
+ startp--;
+
+ return (startp);
+}
diff --git a/lib/libarchive/archive_write_set_format_cpio.c b/lib/libarchive/archive_write_set_format_cpio.c
index e16fe31..80dbf38 100644
--- a/lib/libarchive/archive_write_set_format_cpio.c
+++ b/lib/libarchive/archive_write_set_format_cpio.c
@@ -26,9 +26,6 @@
#include "archive_platform.h"
__FBSDID("$FreeBSD$");
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
@@ -111,7 +108,6 @@ archive_write_cpio_header(struct archive_write *a, struct archive_entry *entry)
struct cpio *cpio;
const char *p, *path;
int pathlength, ret;
- const struct stat *st;
struct cpio_header h;
cpio = (struct cpio *)a->format_data;
@@ -119,31 +115,31 @@ archive_write_cpio_header(struct archive_write *a, struct archive_entry *entry)
path = archive_entry_pathname(entry);
pathlength = strlen(path) + 1; /* Include trailing null. */
- st = archive_entry_stat(entry);
memset(&h, 0, sizeof(h));
format_octal(070707, &h.c_magic, sizeof(h.c_magic));
- format_octal(st->st_dev, &h.c_dev, sizeof(h.c_dev));
+ format_octal(archive_entry_dev(entry), &h.c_dev, sizeof(h.c_dev));
/*
* TODO: Generate artificial inode numbers rather than just
* re-using the ones off the disk. That way, the 18-bit c_ino
* field only limits the number of files in the archive.
*/
- if (st->st_ino > 0777777) {
+ if (archive_entry_ino(entry) > 0777777) {
archive_set_error(&a->archive, ERANGE, "large inode number truncated");
ret = ARCHIVE_WARN;
}
- format_octal(st->st_ino & 0777777, &h.c_ino, sizeof(h.c_ino));
- format_octal(st->st_mode, &h.c_mode, sizeof(h.c_mode));
- format_octal(st->st_uid, &h.c_uid, sizeof(h.c_uid));
- format_octal(st->st_gid, &h.c_gid, sizeof(h.c_gid));
- format_octal(st->st_nlink, &h.c_nlink, sizeof(h.c_nlink));
- if (S_ISBLK(st->st_mode) || S_ISCHR(st->st_mode))
- format_octal(st->st_rdev, &h.c_rdev, sizeof(h.c_rdev));
+ format_octal(archive_entry_ino(entry) & 0777777, &h.c_ino, sizeof(h.c_ino));
+ format_octal(archive_entry_mode(entry), &h.c_mode, sizeof(h.c_mode));
+ format_octal(archive_entry_uid(entry), &h.c_uid, sizeof(h.c_uid));
+ format_octal(archive_entry_gid(entry), &h.c_gid, sizeof(h.c_gid));
+ format_octal(archive_entry_nlink(entry), &h.c_nlink, sizeof(h.c_nlink));
+ if (archive_entry_filetype(entry) == AE_IFBLK
+ || archive_entry_filetype(entry) == AE_IFCHR)
+ format_octal(archive_entry_dev(entry), &h.c_rdev, sizeof(h.c_rdev));
else
format_octal(0, &h.c_rdev, sizeof(h.c_rdev));
- format_octal(st->st_mtime, &h.c_mtime, sizeof(h.c_mtime));
+ format_octal(archive_entry_mtime(entry), &h.c_mtime, sizeof(h.c_mtime));
format_octal(pathlength, &h.c_namesize, sizeof(h.c_namesize));
/* Symlinks get the link written as the body of the entry. */
@@ -151,21 +147,21 @@ archive_write_cpio_header(struct archive_write *a, struct archive_entry *entry)
if (p != NULL && *p != '\0')
format_octal(strlen(p), &h.c_filesize, sizeof(h.c_filesize));
else
- format_octal(st->st_size, &h.c_filesize, sizeof(h.c_filesize));
+ format_octal(archive_entry_size(entry), &h.c_filesize, sizeof(h.c_filesize));
- ret = (a->compression_write)(a, &h, sizeof(h));
+ ret = (a->compressor.write)(a, &h, sizeof(h));
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
- ret = (a->compression_write)(a, path, pathlength);
+ ret = (a->compressor.write)(a, path, pathlength);
if (ret != ARCHIVE_OK)
return (ARCHIVE_FATAL);
- cpio->entry_bytes_remaining = st->st_size;
+ cpio->entry_bytes_remaining = archive_entry_size(entry);
/* Write the symlink now. */
if (p != NULL && *p != '\0')
- ret = (a->compression_write)(a, p, strlen(p));
+ ret = (a->compressor.write)(a, p, strlen(p));
return (ret);
}
@@ -180,7 +176,7 @@ archive_write_cpio_data(struct archive_write *a, const void *buff, size_t s)
if (s > cpio->entry_bytes_remaining)
s = cpio->entry_bytes_remaining;
- ret = (a->compression_write)(a, buff, s);
+ ret = (a->compressor.write)(a, buff, s);
cpio->entry_bytes_remaining -= s;
if (ret >= 0)
return (s);
@@ -222,15 +218,12 @@ static int
archive_write_cpio_finish(struct archive_write *a)
{
struct cpio *cpio;
- struct stat st;
int er;
struct archive_entry *trailer;
cpio = (struct cpio *)a->format_data;
trailer = archive_entry_new();
- memset(&st, 0, sizeof(st));
- st.st_nlink = 1;
- archive_entry_copy_stat(trailer, &st);
+ archive_entry_set_nlink(trailer, 1);
archive_entry_set_pathname(trailer, "TRAILER!!!");
er = archive_write_cpio_header(a, trailer);
archive_entry_free(trailer);
@@ -259,7 +252,7 @@ archive_write_cpio_finish_entry(struct archive_write *a)
while (cpio->entry_bytes_remaining > 0) {
to_write = cpio->entry_bytes_remaining < a->null_length ?
cpio->entry_bytes_remaining : a->null_length;
- ret = (a->compression_write)(a, a->nulls, to_write);
+ ret = (a->compressor.write)(a, a->nulls, to_write);
if (ret != ARCHIVE_OK)
return (ret);
cpio->entry_bytes_remaining -= to_write;
diff --git a/lib/libarchive/archive_write_set_format_pax.c b/lib/libarchive/archive_write_set_format_pax.c
index 28cbdca..0007e3a 100644
--- a/lib/libarchive/archive_write_set_format_pax.c
+++ b/lib/libarchive/archive_write_set_format_pax.c
@@ -26,16 +26,6 @@
#include "archive_platform.h"
__FBSDID("$FreeBSD$");
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#ifdef MAJOR_IN_MKDEV
-#include <sys/mkdev.h>
-#else
-#ifdef MAJOR_IN_SYSMACROS
-#include <sys/sysmacros.h>
-#endif
-#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
@@ -45,9 +35,6 @@ __FBSDID("$FreeBSD$");
#ifdef HAVE_STRING_H
#include <string.h>
#endif
-#ifdef HAVE_UNISTD_H
-#include <unistd.h>
-#endif
#include "archive.h"
#include "archive_entry.h"
@@ -67,8 +54,8 @@ static void add_pax_attr_int(struct archive_string *,
static void add_pax_attr_time(struct archive_string *,
const char *key, int64_t sec,
unsigned long nanos);
-static void add_pax_attr_w(struct archive_string *, const char *,
- const wchar_t *, const wchar_t *);
+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_write *,
const void *, size_t);
static int archive_write_pax_finish(struct archive_write *);
@@ -205,42 +192,30 @@ add_pax_attr_int(struct archive_string *as, const char *key, int64_t value)
add_pax_attr(as, key, format_int(tmp + sizeof(tmp) - 1, value));
}
-/*
- * UTF-8 encode the concatenation of two strings.
- *
- * This interface eliminates the need to do some string
- * manipulations at higher layers.
- */
static char *
-utf8_encode(const wchar_t *wval1, const wchar_t *wval2)
+utf8_encode(const wchar_t *wval)
{
int utf8len;
- const wchar_t *wp, **wpp;
+ const wchar_t *wp;
unsigned long wc;
char *utf8_value, *p;
- const wchar_t *vals[2];
-
- vals[0] = wval1;
- vals[1] = wval2;
utf8len = 0;
- for (wpp = vals; wpp < vals + 2 && *wpp; wpp++) {
- for (wp = *wpp; *wp != L'\0'; ) {
- wc = *wp++;
- if (wc <= 0x7f)
- utf8len++;
- else if (wc <= 0x7ff)
- utf8len += 2;
- else if (wc <= 0xffff)
- utf8len += 3;
- else if (wc <= 0x1fffff)
- utf8len += 4;
- else if (wc <= 0x3ffffff)
- utf8len += 5;
- else if (wc <= 0x7fffffff)
- utf8len += 6;
- /* Ignore larger values; UTF-8 can't encode them. */
- }
+ for (wp = wval; *wp != L'\0'; ) {
+ wc = *wp++;
+ if (wc <= 0x7f)
+ utf8len++;
+ else if (wc <= 0x7ff)
+ utf8len += 2;
+ else if (wc <= 0xffff)
+ utf8len += 3;
+ else if (wc <= 0x1fffff)
+ utf8len += 4;
+ else if (wc <= 0x3ffffff)
+ utf8len += 5;
+ else if (wc <= 0x7fffffff)
+ utf8len += 6;
+ /* Ignore larger values; UTF-8 can't encode them. */
}
utf8_value = (char *)malloc(utf8len + 1);
@@ -249,45 +224,42 @@ utf8_encode(const wchar_t *wval1, const wchar_t *wval2)
return (NULL);
}
- p = utf8_value;
- for (wpp = vals; wpp < vals + 2 && *wpp; wpp++) {
- for (wp = *wpp; *wp != L'\0'; ) {
- wc = *wp++;
- if (wc <= 0x7f) {
- *p++ = (char)wc;
- } else if (wc <= 0x7ff) {
- p[0] = 0xc0 | ((wc >> 6) & 0x1f);
- p[1] = 0x80 | (wc & 0x3f);
- p += 2;
- } else if (wc <= 0xffff) {
- p[0] = 0xe0 | ((wc >> 12) & 0x0f);
- p[1] = 0x80 | ((wc >> 6) & 0x3f);
- p[2] = 0x80 | (wc & 0x3f);
- p += 3;
- } else if (wc <= 0x1fffff) {
- p[0] = 0xf0 | ((wc >> 18) & 0x07);
- p[1] = 0x80 | ((wc >> 12) & 0x3f);
- p[2] = 0x80 | ((wc >> 6) & 0x3f);
- p[3] = 0x80 | (wc & 0x3f);
- p += 4;
- } else if (wc <= 0x3ffffff) {
- p[0] = 0xf8 | ((wc >> 24) & 0x03);
- p[1] = 0x80 | ((wc >> 18) & 0x3f);
- p[2] = 0x80 | ((wc >> 12) & 0x3f);
- p[3] = 0x80 | ((wc >> 6) & 0x3f);
- p[4] = 0x80 | (wc & 0x3f);
- p += 5;
- } else if (wc <= 0x7fffffff) {
- p[0] = 0xfc | ((wc >> 30) & 0x01);
- p[1] = 0x80 | ((wc >> 24) & 0x3f);
- p[1] = 0x80 | ((wc >> 18) & 0x3f);
- p[2] = 0x80 | ((wc >> 12) & 0x3f);
- p[3] = 0x80 | ((wc >> 6) & 0x3f);
- p[4] = 0x80 | (wc & 0x3f);
- p += 6;
- }
- /* Ignore larger values; UTF-8 can't encode them. */
+ for (wp = wval, p = utf8_value; *wp != L'\0'; ) {
+ wc = *wp++;
+ if (wc <= 0x7f) {
+ *p++ = (char)wc;
+ } else if (wc <= 0x7ff) {
+ p[0] = 0xc0 | ((wc >> 6) & 0x1f);
+ p[1] = 0x80 | (wc & 0x3f);
+ p += 2;
+ } else if (wc <= 0xffff) {
+ p[0] = 0xe0 | ((wc >> 12) & 0x0f);
+ p[1] = 0x80 | ((wc >> 6) & 0x3f);
+ p[2] = 0x80 | (wc & 0x3f);
+ p += 3;
+ } else if (wc <= 0x1fffff) {
+ p[0] = 0xf0 | ((wc >> 18) & 0x07);
+ p[1] = 0x80 | ((wc >> 12) & 0x3f);
+ p[2] = 0x80 | ((wc >> 6) & 0x3f);
+ p[3] = 0x80 | (wc & 0x3f);
+ p += 4;
+ } else if (wc <= 0x3ffffff) {
+ p[0] = 0xf8 | ((wc >> 24) & 0x03);
+ p[1] = 0x80 | ((wc >> 18) & 0x3f);
+ p[2] = 0x80 | ((wc >> 12) & 0x3f);
+ p[3] = 0x80 | ((wc >> 6) & 0x3f);
+ p[4] = 0x80 | (wc & 0x3f);
+ p += 5;
+ } else if (wc <= 0x7fffffff) {
+ p[0] = 0xfc | ((wc >> 30) & 0x01);
+ p[1] = 0x80 | ((wc >> 24) & 0x3f);
+ p[1] = 0x80 | ((wc >> 18) & 0x3f);
+ p[2] = 0x80 | ((wc >> 12) & 0x3f);
+ p[3] = 0x80 | ((wc >> 6) & 0x3f);
+ p[4] = 0x80 | (wc & 0x3f);
+ p += 6;
}
+ /* Ignore larger values; UTF-8 can't encode them. */
}
*p = '\0';
@@ -295,10 +267,9 @@ utf8_encode(const wchar_t *wval1, const wchar_t *wval2)
}
static void
-add_pax_attr_w(struct archive_string *as, const char *key,
- const wchar_t *wval1, const wchar_t *wval2)
+add_pax_attr_w(struct archive_string *as, const char *key, const wchar_t *wval)
{
- char *utf8_value = utf8_encode(wval1, wval2);
+ char *utf8_value = utf8_encode(wval);
if (utf8_value == NULL)
return;
add_pax_attr(as, key, utf8_value);
@@ -383,7 +354,7 @@ archive_write_pax_header_xattrs(struct pax *pax, struct archive_entry *entry)
free(url_encoded_name); /* Done with this. */
}
if (wcs_name != NULL) {
- encoded_name = utf8_encode(wcs_name, NULL);
+ encoded_name = utf8_encode(wcs_name);
free(wcs_name); /* Done with wchar_t name. */
}
@@ -413,13 +384,12 @@ archive_write_pax_header(struct archive_write *a,
{
struct archive_entry *entry_main;
const char *linkname, *p;
+ char *t;
const char *hardlink;
const wchar_t *wp;
const char *suffix_start;
int need_extension, r, ret;
- int need_slash = 0;
struct pax *pax;
- const struct stat *st_main, *st_original;
char paxbuff[512];
char ustarbuff[512];
@@ -429,28 +399,37 @@ archive_write_pax_header(struct archive_write *a,
need_extension = 0;
pax = (struct pax *)a->format_data;
- st_original = archive_entry_stat(entry_original);
-
hardlink = archive_entry_hardlink(entry_original);
/* Make sure this is a type of entry that we can handle here */
if (hardlink == NULL) {
- switch (st_original->st_mode & S_IFMT) {
- case S_IFREG:
- case S_IFLNK:
- case S_IFCHR:
- case S_IFBLK:
- case S_IFDIR:
- case S_IFIFO:
+ switch (archive_entry_filetype(entry_original)) {
+ case AE_IFBLK:
+ case AE_IFCHR:
+ case AE_IFIFO:
+ case AE_IFLNK:
+ case AE_IFREG:
+ break;
+ case AE_IFDIR:
+ /*
+ * Ensure a trailing '/'. Modify the original
+ * entry so the client sees the change.
+ */
+ p = archive_entry_pathname(entry_original);
+ if (p[strlen(p) - 1] != '/') {
+ t = (char *)malloc(strlen(p) + 2);
+ if (t != NULL) {
+ strcpy(t, p);
+ strcat(t, "/");
+ archive_entry_copy_pathname(entry_original, t);
+ free(t);
+ }
+ }
break;
- case S_IFSOCK:
- archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "tar format cannot archive socket");
- return (ARCHIVE_WARN);
default:
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
- "tar format cannot archive this (mode=0%lo)",
- (unsigned long)st_original->st_mode);
+ "tar format cannot archive this (type=0%lo)",
+ (unsigned long)archive_entry_filetype(entry_original));
return (ARCHIVE_WARN);
}
}
@@ -458,7 +437,6 @@ archive_write_pax_header(struct archive_write *a,
/* Copy entry so we can modify it as needed. */
entry_main = archive_entry_clone(entry_original);
archive_string_empty(&(pax->pax_header)); /* Blank our work area. */
- st_main = archive_entry_stat(entry_main);
/*
* Determining whether or not the name is too big is ugly
@@ -468,23 +446,18 @@ archive_write_pax_header(struct archive_write *a,
*/
wp = archive_entry_pathname_w(entry_main);
p = archive_entry_pathname(entry_main);
- if (S_ISDIR(st_original->st_mode))
- if (p[strlen(p) - 1] != '/')
- need_slash = 1;
- /* Short enough for just 'name' field */
- if (strlen(p) + need_slash <= 100)
+ if (strlen(p) <= 100) /* Short enough for just 'name' field */
suffix_start = p; /* Record a zero-length prefix */
else
/* Find the largest suffix that fits in 'name' field. */
- suffix_start = strchr(p + strlen(p) + need_slash - 100 - 1, '/');
+ suffix_start = strchr(p + strlen(p) - 100 - 1, '/');
/*
* If name is too long, or has non-ASCII characters, add
* 'path' to pax extended attrs.
*/
if (suffix_start == NULL || suffix_start - p > 155 || has_non_ASCII(wp)) {
- add_pax_attr_w(&(pax->pax_header), "path", wp,
- need_slash ? L"/" : NULL);
+ add_pax_attr_w(&(pax->pax_header), "path", wp);
archive_entry_set_pathname(entry_main,
build_ustar_entry_name(ustar_entry_name, p, strlen(p), NULL));
need_extension = 1;
@@ -506,7 +479,7 @@ archive_write_pax_header(struct archive_write *a,
/* If the link is long or has a non-ASCII character,
* store it as a pax extended attribute. */
if (strlen(linkname) > 100 || has_non_ASCII(wp)) {
- add_pax_attr_w(&(pax->pax_header), "linkpath", wp, NULL);
+ add_pax_attr_w(&(pax->pax_header), "linkpath", wp);
if (hardlink != NULL)
archive_entry_set_hardlink(entry_main,
"././@LongHardLink");
@@ -518,14 +491,16 @@ archive_write_pax_header(struct archive_write *a,
}
/* If file size is too large, add 'size' to pax extended attrs. */
- if (st_main->st_size >= (((int64_t)1) << 33)) {
- add_pax_attr_int(&(pax->pax_header), "size", st_main->st_size);
+ if (archive_entry_size(entry_main) >= (((int64_t)1) << 33)) {
+ add_pax_attr_int(&(pax->pax_header), "size",
+ archive_entry_size(entry_main));
need_extension = 1;
}
/* If numeric GID is too large, add 'gid' to pax extended attrs. */
- if (st_main->st_gid >= (1 << 18)) {
- add_pax_attr_int(&(pax->pax_header), "gid", st_main->st_gid);
+ if (archive_entry_gid(entry_main) >= (1 << 18)) {
+ add_pax_attr_int(&(pax->pax_header), "gid",
+ archive_entry_gid(entry_main));
need_extension = 1;
}
@@ -534,14 +509,15 @@ archive_write_pax_header(struct archive_write *a,
p = archive_entry_gname(entry_main);
wp = archive_entry_gname_w(entry_main);
if (p != NULL && (strlen(p) > 31 || has_non_ASCII(wp))) {
- add_pax_attr_w(&(pax->pax_header), "gname", wp, NULL);
+ add_pax_attr_w(&(pax->pax_header), "gname", wp);
archive_entry_set_gname(entry_main, NULL);
need_extension = 1;
}
/* If numeric UID is too large, add 'uid' to pax extended attrs. */
- if (st_main->st_uid >= (1 << 18)) {
- add_pax_attr_int(&(pax->pax_header), "uid", st_main->st_uid);
+ if (archive_entry_uid(entry_main) >= (1 << 18)) {
+ add_pax_attr_int(&(pax->pax_header), "uid",
+ archive_entry_uid(entry_main));
need_extension = 1;
}
@@ -550,7 +526,7 @@ archive_write_pax_header(struct archive_write *a,
p = archive_entry_uname(entry_main);
wp = archive_entry_uname_w(entry_main);
if (p != NULL && (strlen(p) > 31 || has_non_ASCII(wp))) {
- add_pax_attr_w(&(pax->pax_header), "uname", wp, NULL);
+ add_pax_attr_w(&(pax->pax_header), "uname", wp);
archive_entry_set_uname(entry_main, NULL);
need_extension = 1;
}
@@ -566,15 +542,15 @@ archive_write_pax_header(struct archive_write *a,
*
* Of course, this is only needed for block or char device entries.
*/
- if (S_ISBLK(st_main->st_mode) ||
- S_ISCHR(st_main->st_mode)) {
+ if (archive_entry_filetype(entry_main) == AE_IFBLK
+ || archive_entry_filetype(entry_main) == AE_IFCHR) {
/*
* If rdevmajor is too large, add 'SCHILY.devmajor' to
* extended attributes.
*/
dev_t rdevmajor, rdevminor;
- rdevmajor = major(st_main->st_rdev);
- rdevminor = minor(st_main->st_rdev);
+ rdevmajor = archive_entry_rdevmajor(entry_main);
+ rdevminor = archive_entry_rdevminor(entry_main);
if (rdevmajor >= (1 << 18)) {
add_pax_attr_int(&(pax->pax_header), "SCHILY.devmajor",
rdevmajor);
@@ -615,7 +591,8 @@ archive_write_pax_header(struct archive_write *a,
* high-resolution timestamp in "restricted pax" mode.
*/
if (!need_extension &&
- ((st_main->st_mtime < 0) || (st_main->st_mtime >= 0x7fffffff)))
+ ((archive_entry_mtime(entry_main) < 0)
+ || (archive_entry_mtime(entry_main) >= 0x7fffffff)))
need_extension = 1;
/* I use a star-compatible file flag attribute. */
@@ -647,24 +624,24 @@ archive_write_pax_header(struct archive_write *a,
if (a->archive_format != ARCHIVE_FORMAT_TAR_PAX_RESTRICTED ||
need_extension) {
- if (st_main->st_mtime < 0 ||
- st_main->st_mtime >= 0x7fffffff ||
- ARCHIVE_STAT_MTIME_NANOS(st_main) != 0)
+ if (archive_entry_mtime(entry_main) < 0 ||
+ archive_entry_mtime(entry_main) >= 0x7fffffff ||
+ archive_entry_mtime_nsec(entry_main) != 0)
add_pax_attr_time(&(pax->pax_header), "mtime",
- st_main->st_mtime,
- ARCHIVE_STAT_MTIME_NANOS(st_main));
+ archive_entry_mtime(entry_main),
+ archive_entry_mtime_nsec(entry_main));
- if (st_main->st_ctime != 0 ||
- ARCHIVE_STAT_CTIME_NANOS(st_main) != 0)
+ if (archive_entry_ctime(entry_main) != 0 ||
+ archive_entry_ctime_nsec(entry_main) != 0)
add_pax_attr_time(&(pax->pax_header), "ctime",
- st_main->st_ctime,
- ARCHIVE_STAT_CTIME_NANOS(st_main));
+ archive_entry_ctime(entry_main),
+ archive_entry_ctime_nsec(entry_main));
- if (st_main->st_atime != 0 ||
- ARCHIVE_STAT_ATIME_NANOS(st_main) != 0)
+ if (archive_entry_atime(entry_main) != 0 ||
+ archive_entry_atime_nsec(entry_main) != 0)
add_pax_attr_time(&(pax->pax_header), "atime",
- st_main->st_atime,
- ARCHIVE_STAT_ATIME_NANOS(st_main));
+ archive_entry_atime(entry_main),
+ archive_entry_atime_nsec(entry_main));
/* I use a star-compatible file flag attribute. */
p = archive_entry_fflags_text(entry_main);
@@ -677,30 +654,30 @@ archive_write_pax_header(struct archive_write *a,
ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID);
if (wp != NULL && *wp != L'\0')
add_pax_attr_w(&(pax->pax_header),
- "SCHILY.acl.access", wp, NULL);
+ "SCHILY.acl.access", wp);
wp = archive_entry_acl_text_w(entry_original,
ARCHIVE_ENTRY_ACL_TYPE_DEFAULT |
ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID);
if (wp != NULL && *wp != L'\0')
add_pax_attr_w(&(pax->pax_header),
- "SCHILY.acl.default", wp, NULL);
+ "SCHILY.acl.default", wp);
/* Include star-compatible metadata info. */
/* Note: "SCHILY.dev{major,minor}" are NOT the
* major/minor portions of "SCHILY.dev". */
add_pax_attr_int(&(pax->pax_header), "SCHILY.dev",
- st_main->st_dev);
+ archive_entry_dev(entry_main));
add_pax_attr_int(&(pax->pax_header), "SCHILY.ino",
- st_main->st_ino);
+ archive_entry_ino(entry_main));
add_pax_attr_int(&(pax->pax_header), "SCHILY.nlink",
- st_main->st_nlink);
+ archive_entry_nlink(entry_main));
/* Store extended attributes */
archive_write_pax_header_xattrs(pax, entry_original);
}
/* Only regular files have data. */
- if (!S_ISREG(archive_entry_mode(entry_main)))
+ if (archive_entry_filetype(entry_main) != AE_IFREG)
archive_entry_set_size(entry_main, 0);
/*
@@ -755,36 +732,40 @@ archive_write_pax_header(struct archive_write *a,
/* If we built any extended attributes, write that entry first. */
ret = ARCHIVE_OK;
if (archive_strlen(&(pax->pax_header)) > 0) {
- struct stat st;
struct archive_entry *pax_attr_entry;
time_t s;
+ uid_t uid;
+ gid_t gid;
+ mode_t mode;
long ns;
- memset(&st, 0, sizeof(st));
pax_attr_entry = archive_entry_new();
p = archive_entry_pathname(entry_main);
archive_entry_set_pathname(pax_attr_entry,
build_pax_attribute_name(pax_entry_name, p));
- st.st_size = archive_strlen(&(pax->pax_header));
+ archive_entry_set_size(pax_attr_entry,
+ archive_strlen(&(pax->pax_header)));
/* Copy uid/gid (but clip to ustar limits). */
- st.st_uid = st_main->st_uid;
- if (st.st_uid >= 1 << 18)
- st.st_uid = (1 << 18) - 1;
- st.st_gid = st_main->st_gid;
- if (st.st_gid >= 1 << 18)
- st.st_gid = (1 << 18) - 1;
+ uid = archive_entry_uid(entry_main);
+ if (uid >= 1 << 18)
+ uid = (1 << 18) - 1;
+ archive_entry_set_uid(pax_attr_entry, uid);
+ gid = archive_entry_gid(entry_main);
+ if (gid >= 1 << 18)
+ gid = (1 << 18) - 1;
+ archive_entry_set_gid(pax_attr_entry, gid);
/* Copy mode over (but not setuid/setgid bits) */
- st.st_mode = st_main->st_mode;
+ mode = archive_entry_mode(entry_main);
#ifdef S_ISUID
- st.st_mode &= ~S_ISUID;
+ mode &= ~S_ISUID;
#endif
#ifdef S_ISGID
- st.st_mode &= ~S_ISGID;
+ mode &= ~S_ISGID;
#endif
#ifdef S_ISVTX
- st.st_mode &= ~S_ISVTX;
+ mode &= ~S_ISVTX;
#endif
- archive_entry_copy_stat(pax_attr_entry, &st);
+ archive_entry_set_mode(pax_attr_entry, mode);
/* Copy uname/gname. */
archive_entry_set_uname(pax_attr_entry,
@@ -821,7 +802,7 @@ archive_write_pax_header(struct archive_write *a,
write(2, msg, strlen(msg));
exit(1);
}
- r = (a->compression_write)(a, paxbuff, 512);
+ r = (a->compressor.write)(a, paxbuff, 512);
if (r != ARCHIVE_OK) {
pax->entry_bytes_remaining = 0;
pax->entry_padding = 0;
@@ -831,7 +812,7 @@ archive_write_pax_header(struct archive_write *a,
pax->entry_bytes_remaining = archive_strlen(&(pax->pax_header));
pax->entry_padding = 0x1ff & (-(int64_t)pax->entry_bytes_remaining);
- r = (a->compression_write)(a, pax->pax_header.s,
+ r = (a->compressor.write)(a, pax->pax_header.s,
archive_strlen(&(pax->pax_header)));
if (r != ARCHIVE_OK) {
/* If a write fails, we're pretty much toast. */
@@ -847,7 +828,7 @@ archive_write_pax_header(struct archive_write *a,
}
/* Write the header for main entry. */
- r = (a->compression_write)(a, ustarbuff, 512);
+ r = (a->compressor.write)(a, ustarbuff, 512);
if (r != ARCHIVE_OK)
return (r);
@@ -1068,7 +1049,7 @@ archive_write_pax_finish(struct archive_write *a)
struct pax *pax;
int r;
- if (a->compression_write == NULL)
+ if (a->compressor.write == NULL)
return (ARCHIVE_OK);
pax = (struct pax *)a->format_data;
@@ -1107,7 +1088,7 @@ write_nulls(struct archive_write *a, size_t padding)
while (padding > 0) {
to_write = padding < a->null_length ? padding : a->null_length;
- ret = (a->compression_write)(a, a->nulls, to_write);
+ ret = (a->compressor.write)(a, a->nulls, to_write);
if (ret != ARCHIVE_OK)
return (ret);
padding -= to_write;
@@ -1125,7 +1106,7 @@ archive_write_pax_data(struct archive_write *a, const void *buff, size_t s)
if (s > pax->entry_bytes_remaining)
s = pax->entry_bytes_remaining;
- ret = (a->compression_write)(a, buff, s);
+ ret = (a->compressor.write)(a, buff, s);
pax->entry_bytes_remaining -= s;
if (ret == ARCHIVE_OK)
return (s);
diff --git a/lib/libarchive/archive_write_set_format_shar.c b/lib/libarchive/archive_write_set_format_shar.c
index 3d6729c..f832ec2 100644
--- a/lib/libarchive/archive_write_set_format_shar.c
+++ b/lib/libarchive/archive_write_set_format_shar.c
@@ -26,9 +26,6 @@
#include "archive_platform.h"
__FBSDID("$FreeBSD$");
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
@@ -84,7 +81,7 @@ shar_printf(struct archive_write *a, const char *fmt, ...)
va_start(ap, fmt);
archive_string_empty(&(shar->work));
archive_string_vsprintf(&(shar->work), fmt, ap);
- ret = ((a->compression_write)(a, shar->work.s, strlen(shar->work.s)));
+ ret = ((a->compressor.write)(a, shar->work.s, strlen(shar->work.s)));
va_end(ap);
return (ret);
}
@@ -149,7 +146,6 @@ archive_write_shar_header(struct archive_write *a, struct archive_entry *entry)
const char *name;
char *p, *pp;
struct shar *shar;
- const struct stat *st;
int ret;
shar = (struct shar *)a->format_data;
@@ -168,22 +164,21 @@ archive_write_shar_header(struct archive_write *a, struct archive_entry *entry)
archive_entry_free(shar->entry);
shar->entry = archive_entry_clone(entry);
name = archive_entry_pathname(entry);
- st = archive_entry_stat(entry);
/* Handle some preparatory issues. */
- switch(st->st_mode & S_IFMT) {
- case S_IFREG:
+ switch(archive_entry_filetype(entry)) {
+ case AE_IFREG:
/* Only regular files have non-zero size. */
break;
- case S_IFDIR:
+ case AE_IFDIR:
archive_entry_set_size(entry, 0);
/* Don't bother trying to recreate '.' */
if (strcmp(name, ".") == 0 || strcmp(name, "./") == 0)
return (ARCHIVE_OK);
break;
- case S_IFIFO:
- case S_IFCHR:
- case S_IFBLK:
+ case AE_IFIFO:
+ case AE_IFCHR:
+ case AE_IFBLK:
/* All other file types have zero size in the archive. */
archive_entry_set_size(entry, 0);
break;
@@ -202,7 +197,7 @@ archive_write_shar_header(struct archive_write *a, struct archive_entry *entry)
if (ret != ARCHIVE_OK)
return (ret);
- if (!S_ISDIR(st->st_mode)) {
+ if (archive_entry_filetype(entry) != AE_IFDIR) {
/* Try to create the dir. */
p = strdup(name);
pp = strrchr(p, '/');
@@ -255,8 +250,8 @@ archive_write_shar_header(struct archive_write *a, struct archive_entry *entry)
if (ret != ARCHIVE_OK)
return (ret);
} else {
- switch(st->st_mode & S_IFMT) {
- case S_IFREG:
+ switch(archive_entry_filetype(entry)) {
+ case AE_IFREG:
if (archive_entry_size(entry) == 0) {
/* More portable than "touch." */
ret = shar_printf(a, "test -e \"%s\" || :> \"%s\"\n", name, name);
@@ -287,7 +282,7 @@ archive_write_shar_header(struct archive_write *a, struct archive_entry *entry)
shar->outbytes = 0;
}
break;
- case S_IFDIR:
+ case AE_IFDIR:
ret = shar_printf(a, "mkdir -p %s > /dev/null 2>&1\n",
name);
if (ret != ARCHIVE_OK)
@@ -306,19 +301,19 @@ archive_write_shar_header(struct archive_write *a, struct archive_entry *entry)
* up at end of archive.
*/
break;
- case S_IFIFO:
+ case AE_IFIFO:
ret = shar_printf(a, "mkfifo %s\n", name);
if (ret != ARCHIVE_OK)
return (ret);
break;
- case S_IFCHR:
+ case AE_IFCHR:
ret = shar_printf(a, "mknod %s c %d %d\n", name,
archive_entry_rdevmajor(entry),
archive_entry_rdevminor(entry));
if (ret != ARCHIVE_OK)
return (ret);
break;
- case S_IFBLK:
+ case AE_IFBLK:
ret = shar_printf(a, "mknod %s b %d %d\n", name,
archive_entry_rdevmajor(entry),
archive_entry_rdevminor(entry));
@@ -359,7 +354,7 @@ archive_write_shar_data_sed(struct archive_write *a, const void *buff, size_t n)
shar->outbuff[shar->outpos++] = *src++;
if (shar->outpos > sizeof(shar->outbuff) - 2) {
- ret = (a->compression_write)(a, shar->outbuff,
+ ret = (a->compressor.write)(a, shar->outbuff,
shar->outpos);
if (ret != ARCHIVE_OK)
return (ret);
@@ -368,7 +363,7 @@ archive_write_shar_data_sed(struct archive_write *a, const void *buff, size_t n)
}
if (shar->outpos > 0)
- ret = (a->compression_write)(a, shar->outbuff, shar->outpos);
+ ret = (a->compressor.write)(a, shar->outbuff, shar->outpos);
if (ret != ARCHIVE_OK)
return (ret);
return (written);
diff --git a/lib/libarchive/archive_write_set_format_ustar.c b/lib/libarchive/archive_write_set_format_ustar.c
index b977317..f43c23a 100644
--- a/lib/libarchive/archive_write_set_format_ustar.c
+++ b/lib/libarchive/archive_write_set_format_ustar.c
@@ -26,16 +26,7 @@
#include "archive_platform.h"
__FBSDID("$FreeBSD$");
-#ifdef HAVE_SYS_STAT_H
-#include <sys/stat.h>
-#endif
-#ifdef MAJOR_IN_MKDEV
-#include <sys/mkdev.h>
-#else
-#ifdef MAJOR_IN_SYSMACROS
-#include <sys/sysmacros.h>
-#endif
-#endif
+
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
@@ -212,13 +203,32 @@ archive_write_ustar_header(struct archive_write *a, struct archive_entry *entry)
/* Only regular files (not hardlinks) have data. */
if (archive_entry_hardlink(entry) != NULL ||
archive_entry_symlink(entry) != NULL ||
- !S_ISREG(archive_entry_mode(entry)))
+ !(archive_entry_filetype(entry) == AE_IFREG))
archive_entry_set_size(entry, 0);
+ if (AE_IFDIR == archive_entry_mode(entry)) {
+ const char *p;
+ char *t;
+ /*
+ * Ensure a trailing '/'. Modify the entry so
+ * the client sees the change.
+ */
+ p = archive_entry_pathname(entry);
+ if (p[strlen(p) - 1] != '/') {
+ t = (char *)malloc(strlen(p) + 2);
+ if (t != NULL) {
+ strcpy(t, p);
+ strcat(t, "/");
+ archive_entry_copy_pathname(entry, t);
+ free(t);
+ }
+ }
+ }
+
ret = __archive_write_format_header_ustar(a, buff, entry, -1, 1);
if (ret != ARCHIVE_OK)
return (ret);
- ret = (a->compression_write)(a, buff, 512);
+ ret = (a->compressor.write)(a, buff, 512);
if (ret != ARCHIVE_OK)
return (ret);
@@ -243,9 +253,8 @@ __archive_write_format_header_ustar(struct archive_write *a, char h[512],
{
unsigned int checksum;
int i, ret;
- size_t copy_length, ps, extra_slash;
+ size_t copy_length;
const char *p, *pp;
- const struct stat *st;
int mytartype;
ret = 0;
@@ -256,7 +265,6 @@ __archive_write_format_header_ustar(struct archive_write *a, char h[512],
* elements.
*/
memcpy(h, &template_header, 512);
- st = archive_entry_stat(entry);
/*
* Because the block is already null-filled, and strings
@@ -265,18 +273,11 @@ __archive_write_format_header_ustar(struct archive_write *a, char h[512],
*/
pp = archive_entry_pathname(entry);
- ps = strlen(pp);
- if (S_ISDIR(st->st_mode) && pp[ps - 1] != '/')
- extra_slash = 1;
- else
- extra_slash = 0;
- if (ps + extra_slash <= USTAR_name_size) {
- memcpy(h + USTAR_name_offset, pp, ps);
- if (extra_slash)
- h[USTAR_name_offset + ps] = '/';
- } else {
+ if (strlen(pp) <= USTAR_name_size)
+ memcpy(h + USTAR_name_offset, pp, strlen(pp));
+ else {
/* Store in two pieces, splitting at a '/'. */
- p = strchr(pp + ps + extra_slash - USTAR_name_size - 1, '/');
+ p = strchr(pp + strlen(pp) - USTAR_name_size - 1, '/');
/*
* If there is no path separator, or the prefix or
* remaining name are too large, return an error.
@@ -292,9 +293,7 @@ __archive_write_format_header_ustar(struct archive_write *a, char h[512],
} else {
/* Copy prefix and remainder to appropriate places */
memcpy(h + USTAR_prefix_offset, pp, p - pp);
- memcpy(h + USTAR_name_offset, p + 1, pp + ps - p - 1);
- if (extra_slash)
- h[USTAR_name_offset + pp + ps - p - 1] = '/';
+ memcpy(h + USTAR_name_offset, p + 1, pp + strlen(pp) - p - 1);
}
}
@@ -338,41 +337,42 @@ __archive_write_format_header_ustar(struct archive_write *a, char h[512],
memcpy(h + USTAR_gname_offset, p, copy_length);
}
- if (format_number(st->st_mode & 07777, h + USTAR_mode_offset, USTAR_mode_size, USTAR_mode_max_size, strict)) {
+ if (format_number(archive_entry_mode(entry) & 07777, h + USTAR_mode_offset, USTAR_mode_size, USTAR_mode_max_size, strict)) {
archive_set_error(&a->archive, ERANGE, "Numeric mode too large");
ret = ARCHIVE_WARN;
}
- if (format_number(st->st_uid, h + USTAR_uid_offset, USTAR_uid_size, USTAR_uid_max_size, strict)) {
+ if (format_number(archive_entry_uid(entry), h + USTAR_uid_offset, USTAR_uid_size, USTAR_uid_max_size, strict)) {
archive_set_error(&a->archive, ERANGE, "Numeric user ID too large");
ret = ARCHIVE_WARN;
}
- if (format_number(st->st_gid, h + USTAR_gid_offset, USTAR_gid_size, USTAR_gid_max_size, strict)) {
+ if (format_number(archive_entry_gid(entry), h + USTAR_gid_offset, USTAR_gid_size, USTAR_gid_max_size, strict)) {
archive_set_error(&a->archive, ERANGE, "Numeric group ID too large");
ret = ARCHIVE_WARN;
}
- if (format_number(st->st_size, h + USTAR_size_offset, USTAR_size_size, USTAR_size_max_size, strict)) {
+ if (format_number(archive_entry_size(entry), h + USTAR_size_offset, USTAR_size_size, USTAR_size_max_size, strict)) {
archive_set_error(&a->archive, ERANGE, "File size out of range");
ret = ARCHIVE_WARN;
}
- if (format_number(st->st_mtime, h + USTAR_mtime_offset, USTAR_mtime_size, USTAR_mtime_max_size, strict)) {
+ if (format_number(archive_entry_mtime(entry), h + USTAR_mtime_offset, USTAR_mtime_size, USTAR_mtime_max_size, strict)) {
archive_set_error(&a->archive, ERANGE,
"File modification time too large");
ret = ARCHIVE_WARN;
}
- if (S_ISBLK(st->st_mode) || S_ISCHR(st->st_mode)) {
- if (format_number(major(st->st_rdev), h + USTAR_rdevmajor_offset,
+ if (archive_entry_filetype(entry) == AE_IFBLK
+ || archive_entry_filetype(entry) == AE_IFCHR) {
+ if (format_number(archive_entry_rdevmajor(entry), h + USTAR_rdevmajor_offset,
USTAR_rdevmajor_size, USTAR_rdevmajor_max_size, strict)) {
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,
+ if (format_number(archive_entry_rdevminor(entry), h + USTAR_rdevminor_offset,
USTAR_rdevminor_size, USTAR_rdevminor_max_size, strict)) {
archive_set_error(&a->archive, ERANGE,
"Minor device number too large");
@@ -385,22 +385,17 @@ __archive_write_format_header_ustar(struct archive_write *a, char h[512],
} else if (mytartype >= 0) {
h[USTAR_typeflag_offset] = mytartype;
} else {
- switch (st->st_mode & S_IFMT) {
- case S_IFREG: h[USTAR_typeflag_offset] = '0' ; break;
- case S_IFLNK: h[USTAR_typeflag_offset] = '2' ; break;
- case S_IFCHR: h[USTAR_typeflag_offset] = '3' ; break;
- case S_IFBLK: h[USTAR_typeflag_offset] = '4' ; break;
- 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, ARCHIVE_ERRNO_FILE_FORMAT,
- "tar format cannot archive socket");
- ret = ARCHIVE_WARN;
- break;
+ switch (archive_entry_filetype(entry)) {
+ case AE_IFREG: h[USTAR_typeflag_offset] = '0' ; break;
+ case AE_IFLNK: h[USTAR_typeflag_offset] = '2' ; break;
+ case AE_IFCHR: h[USTAR_typeflag_offset] = '3' ; break;
+ case AE_IFBLK: h[USTAR_typeflag_offset] = '4' ; break;
+ case AE_IFDIR: h[USTAR_typeflag_offset] = '5' ; break;
+ case AE_IFIFO: h[USTAR_typeflag_offset] = '6' ; break;
default:
archive_set_error(&a->archive, ARCHIVE_ERRNO_FILE_FORMAT,
"tar format cannot archive this (mode=0%lo)",
- (unsigned long)st->st_mode);
+ (unsigned long)archive_entry_mode(entry));
ret = ARCHIVE_WARN;
}
}
@@ -500,7 +495,7 @@ archive_write_ustar_finish(struct archive_write *a)
{
int r;
- if (a->compression_write == NULL)
+ if (a->compressor.write == NULL)
return (ARCHIVE_OK);
r = write_nulls(a, 512*2);
@@ -539,7 +534,7 @@ write_nulls(struct archive_write *a, size_t padding)
while (padding > 0) {
to_write = padding < a->null_length ? padding : a->null_length;
- ret = (a->compression_write)(a, a->nulls, to_write);
+ ret = (a->compressor.write)(a, a->nulls, to_write);
if (ret != ARCHIVE_OK)
return (ret);
padding -= to_write;
@@ -556,7 +551,7 @@ archive_write_ustar_data(struct archive_write *a, const void *buff, size_t s)
ustar = (struct ustar *)a->format_data;
if (s > ustar->entry_bytes_remaining)
s = ustar->entry_bytes_remaining;
- ret = (a->compression_write)(a, buff, s);
+ ret = (a->compressor.write)(a, buff, s);
ustar->entry_bytes_remaining -= s;
if (ret != ARCHIVE_OK)
return (ret);
diff --git a/lib/libarchive/config_freebsd.h b/lib/libarchive/config_freebsd.h
index 4cb69e6..90c54f8 100644
--- a/lib/libarchive/config_freebsd.h
+++ b/lib/libarchive/config_freebsd.h
@@ -65,7 +65,10 @@
#define HAVE_MEMSET 1
#define HAVE_MKDIR 1
#define HAVE_MKFIFO 1
+#define HAVE_POLL 1
+#define HAVE_POLL_H 1
#define HAVE_PWD_H 1
+#define HAVE_SELECT 1
#define HAVE_STDINT_H 1
#define HAVE_STDLIB_H 1
#define HAVE_STRCHR 1
@@ -77,8 +80,10 @@
#define HAVE_STRRCHR 1
#define HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC 1
#define HAVE_STRUCT_STAT_ST_RDEV 1
+#define HAVE_STRUCT_TM_TM_GMTOFF 1
#define HAVE_SYS_ACL_H 1
#define HAVE_SYS_IOCTL_H 1
+#define HAVE_SYS_SELECT_H 1
#define HAVE_SYS_STAT_H 1
#define HAVE_SYS_TIME_H 1
#define HAVE_SYS_TYPES_H 1
diff --git a/lib/libarchive/filter_fork.c b/lib/libarchive/filter_fork.c
new file mode 100644
index 0000000..a7ee48b
--- /dev/null
+++ b/lib/libarchive/filter_fork.c
@@ -0,0 +1,137 @@
+/*-
+ * Copyright (c) 2007 Joerg Sonnenberger
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+
+__FBSDID("$FreeBSD$");
+
+#if defined(HAVE_POLL)
+# if defined(HAVE_POLL_H)
+# include <poll.h>
+# endif
+#elif defined(HAVE_SELECT)
+# if defined(HAVE_SYS_SELECT_H)
+# include <sys/select.h>
+# elif defined(HAVE_UNISTD_H)
+# include <unistd.h>
+# endif
+#endif
+#ifdef HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include "filter_fork.h"
+
+pid_t
+__archive_create_child(const char *path, int *child_stdin, int *child_stdout)
+{
+ pid_t child;
+ int stdin_pipe[2], stdout_pipe[2], tmp;
+
+ if (pipe(stdin_pipe) == -1)
+ goto state_allocated;
+ if (stdin_pipe[0] == STDOUT_FILENO) {
+ if ((tmp = dup(stdin_pipe[0])) == -1)
+ goto stdin_opened;
+ close(stdin_pipe[0]);
+ stdin_pipe[0] = tmp;
+ }
+ if (pipe(stdout_pipe) == -1)
+ goto stdin_opened;
+ if (stdout_pipe[1] == STDIN_FILENO) {
+ if ((tmp = dup(stdout_pipe[1])) == -1)
+ goto stdout_opened;
+ close(stdout_pipe[1]);
+ stdout_pipe[1] = tmp;
+ }
+
+ switch ((child = vfork())) {
+ case -1:
+ goto stdout_opened;
+ case 0:
+ close(stdin_pipe[1]);
+ close(stdout_pipe[0]);
+ if (dup2(stdin_pipe[0], STDIN_FILENO) == -1)
+ _exit(254);
+ if (stdin_pipe[0] != STDIN_FILENO)
+ close(stdin_pipe[0]);
+ if (dup2(stdout_pipe[1], STDOUT_FILENO) == -1)
+ _exit(254);
+ if (stdout_pipe[1] != STDOUT_FILENO)
+ close(stdout_pipe[1]);
+ execlp(path, path, (char *)NULL);
+ _exit(254);
+ default:
+ close(stdin_pipe[0]);
+ close(stdout_pipe[1]);
+
+ *child_stdin = stdin_pipe[1];
+ fcntl(*child_stdin, F_SETFL, O_NONBLOCK);
+ *child_stdout = stdout_pipe[0];
+ fcntl(*child_stdout, F_SETFL, O_NONBLOCK);
+ }
+
+ return child;
+
+stdout_opened:
+ close(stdout_pipe[0]);
+ close(stdout_pipe[1]);
+stdin_opened:
+ close(stdin_pipe[0]);
+ close(stdin_pipe[1]);
+state_allocated:
+ return -1;
+}
+
+void
+__archive_check_child(int in, int out)
+{
+#if defined(HAVE_POLL)
+ struct pollfd fds[2];
+
+ fds[0].fd = in;
+ fds[0].events = POLLOUT;
+ fds[1].fd = out;
+ fds[1].events = POLLIN;
+
+ poll(fds, 2, -1); /* -1 == INFTIM, wait forever */
+#elif defined(HAVE_SELECT)
+ fd_set fds_in, fds_out, fds_error;
+
+ FD_ZERO(&fds_in);
+ FD_SET(out, &fds_in);
+ FD_ZERO(&fds_out);
+ FD_SET(in, &fds_out);
+ FD_ZERO(&fds_error);
+ FD_SET(in, &fds_error);
+ FD_SET(out, &fds_error);
+ select(in < out ? out + 1 : in + 1, &fds_in, &fds_out, &fds_error, NULL);
+#else
+ sleep(1);
+#endif
+}
diff --git a/lib/libarchive/filter_fork.h b/lib/libarchive/filter_fork.h
new file mode 100644
index 0000000..d34ae22
--- /dev/null
+++ b/lib/libarchive/filter_fork.h
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (c) 2007 Joerg Sonnenberger
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef FILTER_FORK_H
+#define FILTER_FORK_H
+
+pid_t
+__archive_create_child(const char *path, int *child_stdin, int *child_stdout);
+
+void
+__archive_check_child(int in, int out);
+
+#endif
diff --git a/lib/libarchive/libarchive_internals.3 b/lib/libarchive/libarchive_internals.3
new file mode 100644
index 0000000..c8f79ff
--- /dev/null
+++ b/lib/libarchive/libarchive_internals.3
@@ -0,0 +1,376 @@
+.\" 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 April 16, 2007
+.Dt LIBARCHIVE 3
+.Os
+.Sh NAME
+.Nm libarchive_internals
+.Nd description of libarchive internal interfaces
+.Sh OVERVIEW
+The
+.Nm libarchive
+library provides a flexible interface for reading and writing
+streaming archive files such as tar and cpio.
+Internally, it follows a modular layered design that should
+make it easy to add new archive and compression formats.
+.Sh GENERAL ARCHITECTURE
+Externally, libarchive exposes most operations through an
+opaque, object-style interface.
+The
+.Xr archive_entry 1
+objects store information about a single filesystem object.
+The rest of the library provides facilities to write
+.Xr archive_entry 1
+objects to archive files,
+read them from archive files,
+and write them to disk.
+(There are plans to add a facility to read
+.Xr archive_entry 1
+objects from disk as well.)
+.Pp
+The read and write APIs each have four layers: a public API
+layer, a format layer that understands the archive file format,
+a compression layer, and an I/O layer.
+The I/O layer is completely exposed to clients who can replace
+it entirely with their own functions.
+.Pp
+In order to provide as much consistency as possible for clients,
+some public functions are virtualized.
+Eventually, it should be possible for clients to open
+an archive or disk writer, and then use a single set of
+code to select and write entries, regardless of the target.
+.Sh READ ARCHITECTURE
+From the outside, clients use the
+.Xr archive_read 3
+API to manipulate an
+.Nm archive
+object to read entries and bodies from an archive stream.
+Internally, the
+.Nm archive
+object is cast to an
+.Nm archive_read
+object, which holds all read-specific data.
+The API has four layers:
+The lowest layer is the I/O layer.
+This layer can be overridden by clients, but most clients use
+the packaged I/O callbacks provided, for example, by
+.Xr archive_read_open_memory 3 ,
+and
+.Xr archive_read_open_fd 3 .
+The compression layer calls the I/O layer to
+read bytes and decompresses them for the format layer.
+The format layer unpacks a stream of uncompressed bytes and
+creates
+.Nm archive_entry
+objects from the incoming data.
+The API layer tracks overall state
+(for example, it prevents clients from reading data before reading a header)
+and invokes the format and compression layer operations
+through registered function pointers.
+In particular, the API layer drives the format-detection process:
+When opening the archive, it reads an initial block of data
+and offers it to each registered compression handler.
+The one with the highest bid is initialized with the first block.
+Similarly, the format handlers are polled to see which handler
+is the best for each header request.
+(Note that a single file can have entries handled by different
+format handlers;
+this allows a simple handler for a generic version of a format
+with more complex handlers implemented independently for
+extended sub-formats.)
+.Ss I/O Layer and Client Callbacks
+The read API goes to some lengths to be nice to clients.
+As a result, there are few restrictions on the behavior of
+the client callbacks.
+.Pp
+The client read callback is expected to provide a block
+of data on each call.
+A zero-length return does indicate end of file, but otherwise
+blocks may be as small as one byte or as large as the entire file.
+In particular, blocks may be of different sizes.
+.Pp
+The client skip callback returns the number of bytes actually
+skipped, which may be much smaller than the skip requested.
+The only requirement is that the skip not be larger.
+The skip callback must never be invoked with a negative value.
+.Pp
+Keep in mind that not all clients are reading from disk:
+clients reading from networks may provide different-sized
+blocks on every request and cannot skip at all;
+advanced clients may use
+.Xr mmap 2
+to read the entire file into memory at once and return the
+entire file to libarchive as a single block;
+other clients may begin asynchronous I/O operations for the
+next block on each request.
+.Ss Decompresssion Layer
+The decompression layer not only handles decompression,
+it also buffers data so that the format handlers see a
+much nicer I/O model.
+The decompression API is a two stage peek/consume model.
+A read_ahead request specifies a minimum read amount;
+the decompression layer must provide a pointer to at least
+that much data.
+If more data is immediately available, it should return more:
+the format layer handles bulk data reads by asking for a minimum
+of one byte and then copying as much data as is available.
+.Pp
+A subsequent call to the
+.Fn consume
+function advances the read pointer.
+Note that data returned from a
+.Fn read_ahead
+call is guaranteed to remain in place until
+the next call to
+.Fn read_ahead .
+Intervening calls to
+.Fn consume
+should not cause the data to move.
+.Pp
+Skip requests must always be handled exactly.
+Decompression handlers that cannot seek forward should
+not register a skip handler;
+the API layer fills in a generic skip handler that reads and discards data.
+.Pp
+A decompression handler has a specific lifecycle:
+.Bl -tag -compact -width indent
+.It Registration/Configuration
+When the client invokes the public support function,
+the decompression handler invokes the internal
+.Fn __archive_read_register_compression
+function to provide bid and initialization functions.
+This function returns
+.Cm NULL
+on error or else a pointer to a
+.Cm struct decompressor_t .
+This structure contains a
+.Va void * config
+slot that can be used for storing any customization information.
+.It Bid
+The bid function is invoked with a pointer and size of a block of data.
+The decompressor can access its config data
+through the
+.Va decompressor
+element of the
+.Cm archive_read
+object.
+The bid function is otherwise stateless.
+In particular, it must not perform any I/O operations.
+.Pp
+The value returned by the bid function indicates its suitability
+for handling this data stream.
+A bid of zero will ensure that this decompressor is never invoked.
+Return zero if magic number checks fail.
+Otherwise, your initial implementation should return the number of bits
+actually checked.
+For example, if you verify two full bytes and three bits of another
+byte, bid 19.
+Note that the initial block may be very short;
+be careful to only inspect the data you are given.
+(The current decompressors require two bytes for correct bidding.)
+.It Initialize
+The winning bidder will have its init function called.
+This function should initialize the remaining slots of the
+.Va struct decompressor_t
+object pointed to by the
+.Va decompressor
+element of the
+.Va archive_read
+object.
+In particular, it should allocate any working data it needs
+in the
+.Va data
+slot of that structure.
+The init function is called with the block of data that
+was used for tasting.
+At this point, the decompressor is responsible for all I/O
+requests to the client callbacks.
+The decompressor is free to read more data as and when
+necessary.
+.It Satisfy I/O requests
+The format handler will invoke the
+.Va read_ahead ,
+.Va consume ,
+and
+.Va skip
+functions as needed.
+.It Finish
+The finish method is called only once when the archive is closed.
+It should release anything stored in the
+.Va data
+and
+.Va config
+slots of the
+.Va decompressor
+object.
+It should not invoke the client close callback.
+.El
+.Ss Format Layer
+The read formats have a similar lifecycle to the decompression handlers:
+.Bl -tag -compact -width indent
+.It Registration
+Allocate your private data and initialize your pointers.
+.It Bid
+Formats bid by invoking the
+.Fn read_ahead
+decompression method but not calling the
+.Fn consume
+method.
+This allows each bidder to look ahead in the input stream.
+Bidders should not look further ahead than necessary, as long
+look aheads put pressure on the compression layer to buffer
+lots of data.
+Most formats only require a few hundred bytes of look ahead;
+look aheads of a few kilobytes are reasonable.
+(The ISO9660 reader sometimes looks ahead by 48k, which
+should be considered an upper limit.)
+Note that the bidder is invoked for every entry.
+For many formats, this is inappropriate; if you can only bid at
+the beginning of the file, store your bid value and check that
+each time your bid function is called.
+For example, the ISO9660 reader initializes a
+.Va bid
+value to -1 at registration time;
+each time the bid function is called, the bid value is returned
+immediately if it is zero or larger.
+.It Read header
+The header read is usually the most complex part of any format.
+There are a few strategies worth mentioning:
+For formats such as tar or cpio, reading and parsing the header is
+straightforward since headers alternate with data.
+For formats that store all header data at the beginning of the file,
+the first header read request may have to read all headers into
+memory and store that data, sorted by the location of the file
+data.
+Subsequent header read requests will skip forward to the
+beginning of the file data and return the corresponding header.
+.It Read Data
+The read data interface supports sparse files; this requires that
+each call return a block of data specifying the file offset and
+size.
+This may require you to carefully track the location so that you
+can return accurate file offsets for each read.
+Remember that the decompressor will return as much data as it has.
+Generally, you will want to request one byte,
+examine the return value to see how much data is available, and
+possibly trim that to the amount you can use.
+You should invoke consume for each block just before you return it.
+.It Skip All Data
+The skip data call should skip over all file data and trailing padding.
+This is called automatically by the API layer just before each
+header read.
+It is also called in response to the client calling the public
+.Fn data_skip
+function.
+.It Cleanup
+On cleanup, the format should release all of its allocated memory.
+.El
+.Ss API Layer
+XXX to do XXX
+.Sh WRITE ARCHITECTURE
+The write API has a similar set of four layers:
+an API layer, a format layer, a compression layer, and an I/O layer.
+The registration here is much simpler because only
+one format and one compression can be registered at a time.
+.Ss I/O Layer and Client Callbacks
+XXX To be written XXX
+.Ss Compression Layer
+XXX To be written XXX
+.Ss Format Layer
+XXX To be written XXX
+.Ss API Layer
+XXX To be written XXX
+.Sh WRITE_DISK ARCHITECTURE
+The write_disk API is intended to look just like the write API
+to clients.
+Since it does not handle multiple formats or compression, it
+is not layered internally.
+.Sh GENERAL SERVICES
+The
+.Nm archive_read ,
+.Nm archive_write ,
+and
+.Nm archive_write_disk
+objects all contain an initial
+.Nm archive
+object which provides common support for a set of standard services.
+(Recall that ANSI/ISO C90 guarantees that you can cast freely between
+a pointer to a structure and a pointer to the first element of that
+structure.)
+The
+.Nm archive
+object has a magic value that indicates which API this object
+is associated with,
+slots for storing error information,
+and function pointers for virtualized API functions.
+.Sh MISCELLANEOUS NOTES
+Connecting existing archiving libraries into libarchive is generally
+quite difficult.
+In particular, many existing libraries strongly assume that you
+are reading from a file; they seek forwards and backwards as necessary
+to locate various pieces of information.
+In contrast, libarchive never seeks backwards in its input, which
+sometimes requires very different approaches.
+.Pp
+For example, libarchive's ISO9660 support operates very differently
+from most ISO9660 readers.
+The libarchive support utilizes a work-queue design that
+keeps a list of known entries sorted by their location in the input.
+Whenever libarchive's ISO9660 implementation is asked for the next
+header, checks this list to find the next item on the disk.
+Directories are parsed when they are encountered and new
+items are added to the list.
+This design relies heavily on the ISO9660 image being optimized so that
+directories always occur earlier on the disk than the files they
+describe.
+.Pp
+Depending on the specific format, such approaches may not be possible.
+The ZIP format specification, for example, allows archivers to store
+key information only at the end of the file.
+In theory, it is possible to create ZIP archives that cannot
+be read without seeking.
+Fortunately, such archives are very rare, and libarchive can read
+most ZIP archives, though it cannot always extract as much information
+as a dedicated ZIP program.
+.Sh SEE ALSO
+.Xr archive 3 ,
+.Xr archive_entry 3 ,
+.Xr archive_read 3 ,
+.Xr archive_write 3 ,
+.Xr archive_write_disk 3
+.Sh HISTORY
+The
+.Nm libarchive
+library first appeared in
+.Fx 5.3 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm libarchive
+library was written by
+.An Tim Kientzle Aq kientzle@acm.org .
+.Sh BUGS
diff --git a/lib/libarchive/test/Makefile b/lib/libarchive/test/Makefile
index b436bbd..4163e0f 100644
--- a/lib/libarchive/test/Makefile
+++ b/lib/libarchive/test/Makefile
@@ -5,6 +5,8 @@ TESTS= \
test_acl_pax.c \
test_archive_api_feature.c \
test_bad_fd.c \
+ test_entry.c \
+ test_read_compress_program.c \
test_read_data_large.c \
test_read_extract.c \
test_read_format_ar.c \
@@ -29,6 +31,7 @@ TESTS= \
test_read_position.c \
test_read_truncated.c \
test_tar_filenames.c \
+ test_write_compress_program.c \
test_write_disk.c \
test_write_disk_perms.c \
test_write_disk_secure.c \
@@ -54,6 +57,11 @@ LDADD= -larchive -lz -lbz2
CFLAGS+= -static -g
CFLAGS+= -I${.OBJDIR}
+# Uncomment to link against dmalloc
+#LDADD+= -L/usr/local/lib -ldmalloc
+#CFLAGS+= -I/usr/local/include -DUSE_DMALLOC
+#WARNS=6
+
test: libarchive_test
./libarchive_test
diff --git a/lib/libarchive/test/README b/lib/libarchive/test/README
index c6c242e..011aa8e 100644
--- a/lib/libarchive/test/README
+++ b/lib/libarchive/test/README
@@ -44,3 +44,12 @@ Each test function can rely on the following:
* Tests are encouraged to be economical with their memory and disk usage,
though this is not essential.
+
+ * Disable tests on specific platforms as necessary. Please don't
+ use config.h to adjust feature requirements, as I want the tests
+ to also serve as a check on the configure process. The following
+ form is appropriate:
+
+#if !defined(__PLATFORM) && !defined(__Platform2__)
+ assert(xxxx)
+#endif
diff --git a/lib/libarchive/test/main.c b/lib/libarchive/test/main.c
index da5330d..ade4993 100644
--- a/lib/libarchive/test/main.c
+++ b/lib/libarchive/test/main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2003-2006 Tim Kientzle
+ * Copyright (c) 2003-2007 Tim Kientzle
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,6 +27,7 @@
* Various utility routines useful for test programs.
* Each test program is linked against this file.
*/
+#include <errno.h>
#include <stdarg.h>
#include <time.h>
@@ -50,6 +51,24 @@ __FBSDID("$FreeBSD$");
*/
static char msg[4096];
+/* Common handling of failed tests. */
+static void
+test_failed(struct archive *a)
+{
+ 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));
+ }
+
+ fprintf(stderr, " *** forcing core dump so failure can be debugged ***\n");
+ *(char *)(NULL) = 0;
+ exit(1);
+}
+
+/* Set up a message to display only after a test fails. */
void
failure(const char *fmt, ...)
{
@@ -59,6 +78,7 @@ failure(const char *fmt, ...)
va_end(ap);
}
+/* Generic assert() just displays the failed condition. */
void
test_assert(const char *file, int line, int value, const char *condition, struct archive *a)
{
@@ -68,17 +88,10 @@ test_assert(const char *file, int line, int value, const char *condition, struct
}
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);
+ test_failed(a);
}
+/* assertEqualInt() displays the values of the two integers. */
void
test_assert_equal_int(const char *file, int line,
int v1, const char *e1, int v2, const char *e2, struct archive *a)
@@ -87,19 +100,52 @@ test_assert_equal_int(const char *file, int line,
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);
+ fprintf(stderr, "%s:%d: Assertion failed: Ints not equal\n",
+ file, line);
+ fprintf(stderr, " %s=%d\n", e1, v1);
+ fprintf(stderr, " %s=%d\n", e2, v2);
+ test_failed(a);
+}
+
+/* assertEqualString() displays the values of the two strings. */
+void
+test_assert_equal_string(const char *file, int line,
+ const char *v1, const char *e1,
+ const char *v2, const char *e2,
+ struct archive *a)
+{
+ if (v1 == NULL || v2 == NULL) {
+ if (v1 == v2) {
+ msg[0] = '\0';
+ return;
+ }
+ } else if (strcmp(v1, v2) == 0) {
msg[0] = '\0';
+ return;
}
- if (a != NULL) {
- fprintf(stderr, " archive error: %s\n", archive_error_string(a));
+ fprintf(stderr, "%s:%d: Assertion failed: Strings not equal\n",
+ file, line);
+ fprintf(stderr, " %s = \"%s\"\n", e1, v1);
+ fprintf(stderr, " %s = \"%s\"\n", e2, v2);
+ test_failed(a);
+}
+
+/* assertEqualWString() displays the values of the two strings. */
+void
+test_assert_equal_wstring(const char *file, int line,
+ const wchar_t *v1, const char *e1,
+ const wchar_t *v2, const char *e2,
+ struct archive *a)
+{
+ if (wcscmp(v1, v2) == 0) {
+ msg[0] = '\0';
+ return;
}
- *(char *)(NULL) = 0;
- exit(1);
+ fprintf(stderr, "%s:%d: Assertion failed: Unicode strings not equal\n",
+ file, line);
+ fwprintf(stderr, L" %s = \"%ls\"\n", e1, v1);
+ fwprintf(stderr, L" %s = \"%ls\"\n", e2, v2);
+ test_failed(a);
}
/*
@@ -109,19 +155,60 @@ test_assert_equal_int(const char *file, int line,
* 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[] = {
+#define DEFINE_TEST(n) { n, #n },
+struct { void (*func)(void); const char *name; } tests[] = {
#include "list.h"
};
-int main(int argc, char **argv)
+static void test_run(int i, const char *tmpdir)
{
- void (*f)(void);
- int limit = sizeof(tests) / sizeof(tests[0]);
+ printf("%d: %s\n", i, tests[i].name);
+ /*
+ * Always explicitly chdir() in case the last test moved us to
+ * a strange place.
+ */
+ 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)();
+}
+
+static void usage(void)
+{
+ static const int limit = sizeof(tests) / sizeof(tests[0]);
int i;
+
+ printf("Usage: libarchive_test <test> <test> ...\n");
+ printf("Default is to run all tests.\n");
+ printf("Otherwise, specify the numbers of the tests you wish to run.\n");
+ printf("Available tests:\n");
+ for (i = 0; i < limit; i++)
+ printf(" %d: %s\n", i, tests[i].name);
+ exit(1);
+}
+
+int main(int argc, char **argv)
+{
+ static const int limit = sizeof(tests) / sizeof(tests[0]);
+ int i, tests_run = 0;
time_t now;
char tmpdir[256];
- int tmpdirHandle;
/*
* Create a temp directory for the following tests.
@@ -129,10 +216,15 @@ int main(int argc, char **argv)
* 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",
- localtime(&now));
- if (mkdir(tmpdir,0755) != 0) {
+ for (i = 0; i < 1000; i++) {
+ strftime(tmpdir, sizeof(tmpdir),
+ "/tmp/libarchive_test.%Y-%m-%dT%H.%M.%S",
+ localtime(&now));
+ sprintf(tmpdir + strlen(tmpdir), "-%03d", i);
+ if (mkdir(tmpdir,0755) == 0)
+ break;
+ if (errno == EEXIST)
+ continue;
fprintf(stderr, "ERROR: Unable to create temp directory %s\n",
tmpdir);
exit(1);
@@ -140,29 +232,25 @@ int main(int argc, char **argv)
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 (argc == 1) {
+ /* Default: Run all tests. */
+ for (i = 0; i < limit; i++) {
+ test_run(i, tmpdir);
+ tests_run++;
}
- if (chdir(tests[i].name)) {
- fprintf(stderr,
- "ERROR: Couldn't chdir to temp dir ``%s''\n",
- tests[i].name);
- exit(1);
+ } else {
+ while (*(++argv) != NULL) {
+ i = atoi(*argv);
+ if (**argv < '0' || **argv > '9' || i < 0 || i >= limit) {
+ printf("*** INVALID Test %s\n", *argv);
+ usage();
+ } else {
+ test_run(i, tmpdir);
+ tests_run++;
+ }
}
- (*tests[i].func)();
}
- printf("%d tests succeeded.\n", limit);
+
+ printf("%d tests succeeded.\n", tests_run);
return (0);
}
diff --git a/lib/libarchive/test/test.h b/lib/libarchive/test/test.h
index 685a8eb..b6a1eba 100644
--- a/lib/libarchive/test/test.h
+++ b/lib/libarchive/test/test.h
@@ -41,6 +41,11 @@
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
+#include <wchar.h>
+
+#ifdef USE_DMALLOC
+#include <dmalloc.h>
+#endif
#if defined(HAVE_CONFIG_H)
/* Most POSIX platforms use the 'configure' script to build config.h */
@@ -83,15 +88,26 @@
#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. */
+
+/* Asserts that two integers 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)
+/* Asserts that two strings are the same. Reports value of each one if not. */
+#define assertEqualStringA(a,v1,v2) \
+ test_assert_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, (a))
+#define assertEqualString(v1,v2) \
+ test_assert_equal_string(__FILE__, __LINE__, (v1), #v1, (v2), #v2, NULL)
+/* As above, but v1 and v2 are wchar_t * */
+#define assertEqualWString(v1,v2) \
+ test_assert_equal_wstring(__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 *);
+void test_assert_equal_string(const char *, int, const char *v1, const char *, const char *v2, const char *, struct archive *);
+void test_assert_equal_wstring(const char *, int, const wchar_t *v1, const char *, const wchar_t *v2, const char *, struct archive *);
diff --git a/lib/libarchive/test/test_acl_basic.c b/lib/libarchive/test/test_acl_basic.c
index 192c12b..e7fb8a9 100644
--- a/lib/libarchive/test/test_acl_basic.c
+++ b/lib/libarchive/test/test_acl_basic.c
@@ -34,14 +34,12 @@ __FBSDID("$FreeBSD$");
* filesystems support ACLs or not.
*/
-static unsigned char buff[16384];
-
struct acl_t {
int type; /* Type of ACL: "access" or "default" */
int permset; /* Permissions for this class of users. */
int tag; /* Owner, User, Owning group, group, other, etc. */
int qual; /* GID or UID of user/group, depending on tag. */
- char *name; /* Name of user/group, depending on tag. */
+ const char *name; /* Name of user/group, depending on tag. */
};
struct acl_t acls0[] = {
@@ -79,7 +77,7 @@ struct acl_t acls2[] = {
ARCHIVE_ENTRY_ACL_OTHER, -1, "" },
};
-void
+static void
set_acls(struct archive_entry *ae, struct acl_t *acls, int n)
{
int i;
@@ -92,7 +90,7 @@ set_acls(struct archive_entry *ae, struct acl_t *acls, int n)
}
}
-int
+static int
acl_match(struct acl_t *acl, int type, int permset, int tag, int qual, const char *name)
{
if (type != acl->type)
@@ -120,11 +118,11 @@ acl_match(struct acl_t *acl, int type, int permset, int tag, int qual, const cha
return (0 == strcmp(name, acl->name));
}
-void
+static void
compare_acls(struct archive_entry *ae, struct acl_t *acls, int n, int mode)
{
int *marker = malloc(sizeof(marker[0]) * n);
- int marker_i, i;
+ int i;
int r;
int type, permset, tag, qual;
int matched;
@@ -179,8 +177,6 @@ compare_acls(struct archive_entry *ae, struct acl_t *acls, int n, int mode)
DEFINE_TEST(test_acl_basic)
{
- int i;
- struct archive *a;
struct archive_entry *ae;
/* Create a simple archive_entry. */
diff --git a/lib/libarchive/test/test_acl_pax.c b/lib/libarchive/test/test_acl_pax.c
index 186b185..7aa3e35 100644
--- a/lib/libarchive/test/test_acl_pax.c
+++ b/lib/libarchive/test/test_acl_pax.c
@@ -264,7 +264,7 @@ struct acl_t {
int permset; /* Permissions for this class of users. */
int tag; /* Owner, User, Owning group, group, other, etc. */
int qual; /* GID or UID of user/group, depending on tag. */
- char *name; /* Name of user/group, depending on tag. */
+ const char *name; /* Name of user/group, depending on tag. */
};
static struct acl_t acls0[] = {
@@ -347,7 +347,7 @@ static void
compare_acls(struct archive_entry *ae, struct acl_t *acls, int n, int mode)
{
int *marker = malloc(sizeof(marker[0]) * n);
- int marker_i, i;
+ int i;
int r;
int type, permset, tag, qual;
int matched;
@@ -402,7 +402,6 @@ compare_acls(struct archive_entry *ae, struct acl_t *acls, int n, int mode)
DEFINE_TEST(test_acl_pax)
{
- int i;
struct archive *a;
struct archive_entry *ae;
size_t used;
@@ -454,7 +453,7 @@ DEFINE_TEST(test_acl_pax)
/* Write out the data we generated to a file for manual inspection. */
assert(-1 < (fd = open("testout", O_WRONLY | O_CREAT | O_TRUNC, 0775)));
- assert(used == write(fd, buff, used));
+ assert(used == (size_t)write(fd, buff, used));
close(fd);
/* Write out the reference data to a file for manual inspection. */
diff --git a/lib/libarchive/test/test_archive_api_feature.c b/lib/libarchive/test/test_archive_api_feature.c
index 876cd9e..db6d3a8 100644
--- a/lib/libarchive/test/test_archive_api_feature.c
+++ b/lib/libarchive/test/test_archive_api_feature.c
@@ -27,7 +27,7 @@ __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())));
+ assertEqualInt(ARCHIVE_API_FEATURE, archive_api_feature());
+ assertEqualInt(ARCHIVE_API_VERSION, archive_api_version());
+ assertEqualString(ARCHIVE_LIBRARY_VERSION, archive_version());
}
diff --git a/lib/libarchive/test/test_entry.c b/lib/libarchive/test/test_entry.c
new file mode 100644
index 0000000..6cc96ee
--- /dev/null
+++ b/lib/libarchive/test/test_entry.c
@@ -0,0 +1,576 @@
+/*-
+ * 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$");
+
+/*
+ * Most of these tests are system-independent, though a few depend on
+ * features of the local system. Such tests are conditionalized on
+ * the platform name. On unsupported platforms, only the
+ * system-independent features will be tested.
+ *
+ * No, I don't want to use config.h in the test files because I want
+ * the tests to also serve as a check on the correctness of config.h.
+ * A mis-configured library build should cause tests to fail.
+ */
+
+DEFINE_TEST(test_entry)
+{
+ char buff[128];
+ wchar_t wbuff[128];
+ struct stat st;
+ struct archive_entry *e, *e2;
+ const struct stat *pst;
+ unsigned long set, clear; /* For fflag testing. */
+ int type, permset, tag, qual; /* For ACL testing. */
+ const char *name; /* For ACL testing. */
+ const char *xname; /* For xattr tests. */
+ const void *xval; /* For xattr tests. */
+ size_t xsize; /* For xattr tests. */
+
+ assert((e = archive_entry_new()) != NULL);
+
+ /*
+ * Basic set/read tests for all fields.
+ * We should be able to set any field and read
+ * back the same value.
+ *
+ * For methods that "copy" a string, we should be able
+ * to overwrite the original passed-in string without
+ * changing the value in the entry.
+ *
+ * The following tests are ordered alphabetically by the
+ * name of the field.
+ */
+ /* atime */
+ archive_entry_set_atime(e, 13579, 24680);
+ assertEqualInt(archive_entry_atime(e), 13579);
+ assertEqualInt(archive_entry_atime_nsec(e), 24680);
+ /* ctime */
+ archive_entry_set_ctime(e, 13580, 24681);
+ assertEqualInt(archive_entry_ctime(e), 13580);
+ assertEqualInt(archive_entry_ctime_nsec(e), 24681);
+ /* dev */
+ archive_entry_set_dev(e, 235);
+ assertEqualInt(archive_entry_dev(e), 235);
+ /* devmajor/devminor are tested specially below. */
+ /* filetype */
+ archive_entry_set_filetype(e, AE_IFREG);
+ assertEqualInt(archive_entry_filetype(e), AE_IFREG);
+ /* fflags are tested specially below */
+ /* gid */
+ archive_entry_set_gid(e, 204);
+ assertEqualInt(archive_entry_gid(e), 204);
+ /* gname */
+ archive_entry_set_gname(e, "group");
+ assertEqualString(archive_entry_gname(e), "group");
+ wcscpy(wbuff, L"wgroup");
+ archive_entry_copy_gname_w(e, wbuff);
+ assertEqualWString(archive_entry_gname_w(e), L"wgroup");
+ memset(wbuff, 0, sizeof(wbuff));
+ assertEqualWString(archive_entry_gname_w(e), L"wgroup");
+ /* hardlink */
+ archive_entry_set_hardlink(e, "hardlinkname");
+ assertEqualString(archive_entry_hardlink(e), "hardlinkname");
+ strcpy(buff, "hardlinkname2");
+ archive_entry_copy_hardlink(e, buff);
+ assertEqualString(archive_entry_hardlink(e), "hardlinkname2");
+ memset(buff, 0, sizeof(buff));
+ assertEqualString(archive_entry_hardlink(e), "hardlinkname2");
+ wcscpy(wbuff, L"whardlink");
+ archive_entry_copy_hardlink_w(e, wbuff);
+ assertEqualWString(archive_entry_hardlink_w(e), L"whardlink");
+ memset(wbuff, 0, sizeof(wbuff));
+ assertEqualWString(archive_entry_hardlink_w(e), L"whardlink");
+ /* ino */
+ archive_entry_set_ino(e, 8593);
+ assertEqualInt(archive_entry_ino(e), 8593);
+ /* link */
+ /* TODO: implement these tests. */
+ /* mode */
+ archive_entry_set_mode(e, 0123456);
+ assertEqualInt(archive_entry_mode(e), 0123456);
+ /* mtime */
+ archive_entry_set_mtime(e, 13581, 24682);
+ assertEqualInt(archive_entry_mtime(e), 13581);
+ assertEqualInt(archive_entry_mtime_nsec(e), 24682);
+ /* nlink */
+ archive_entry_set_nlink(e, 736);
+ assertEqualInt(archive_entry_nlink(e), 736);
+ /* pathname */
+ archive_entry_set_pathname(e, "path");
+ assertEqualString(archive_entry_pathname(e), "path");
+ archive_entry_set_pathname(e, "path");
+ assertEqualString(archive_entry_pathname(e), "path");
+ strcpy(buff, "path2");
+ archive_entry_copy_pathname(e, buff);
+ assertEqualString(archive_entry_pathname(e), "path2");
+ memset(buff, 0, sizeof(buff));
+ assertEqualString(archive_entry_pathname(e), "path2");
+ wcscpy(wbuff, L"wpath");
+ archive_entry_copy_pathname_w(e, wbuff);
+ assertEqualWString(archive_entry_pathname_w(e), L"wpath");
+ memset(wbuff, 0, sizeof(wbuff));
+ assertEqualWString(archive_entry_pathname_w(e), L"wpath");
+ /* rdev */
+ archive_entry_set_rdev(e, 532);
+ assertEqualInt(archive_entry_rdev(e), 532);
+ /* rdevmajor/rdevminor are tested specially below. */
+ /* size */
+ archive_entry_set_size(e, 987654321);
+ assertEqualInt(archive_entry_size(e), 987654321);
+ /* symlink */
+ archive_entry_set_symlink(e, "symlinkname");
+ assertEqualString(archive_entry_symlink(e), "symlinkname");
+ strcpy(buff, "symlinkname2");
+ archive_entry_copy_symlink(e, buff);
+ assertEqualString(archive_entry_symlink(e), "symlinkname2");
+ memset(buff, 0, sizeof(buff));
+ assertEqualString(archive_entry_symlink(e), "symlinkname2");
+ archive_entry_copy_symlink_w(e, L"wsymlink");
+ assertEqualWString(archive_entry_symlink_w(e), L"wsymlink");
+ /* uid */
+ archive_entry_set_uid(e, 83);
+ assertEqualInt(archive_entry_uid(e), 83);
+ /* uname */
+ archive_entry_set_uname(e, "user");
+ assertEqualString(archive_entry_uname(e), "user");
+ wcscpy(wbuff, L"wuser");
+ archive_entry_copy_gname_w(e, wbuff);
+ assertEqualWString(archive_entry_gname_w(e), L"wuser");
+ memset(wbuff, 0, sizeof(wbuff));
+ assertEqualWString(archive_entry_gname_w(e), L"wuser");
+
+ /* Test fflags interface. */
+ archive_entry_set_fflags(e, 0x55, 0xAA);
+ archive_entry_fflags(e, &set, &clear);
+ failure("Testing set/get of fflags data.");
+ assertEqualInt(set, 0x55);
+ failure("Testing set/get of fflags data.");
+ assertEqualInt(clear, 0xAA);
+#ifdef __FreeBSD__
+ /* Converting fflags bitmap to string is currently system-dependent. */
+ /* TODO: Make this system-independent. */
+ assertEqualString(archive_entry_fflags_text(e),
+ "uappnd,nouchg,nodump,noopaque,uunlnk");
+ /* TODO: Test archive_entry_copy_fflags_text_w() */
+#endif
+
+ /* See test_acl_basic.c for tests of ACL set/get consistency. */
+
+ /* Test xattrs set/get consistency. */
+ archive_entry_xattr_add_entry(e, "xattr1", "xattrvalue1", 12);
+ assertEqualInt(1, archive_entry_xattr_reset(e));
+ assertEqualInt(0, archive_entry_xattr_next(e, &xname, &xval, &xsize));
+ assertEqualString(xname, "xattr1");
+ assertEqualString(xval, "xattrvalue1");
+ assertEqualInt(xsize, 12);
+ assertEqualInt(1, archive_entry_xattr_count(e));
+ assertEqualInt(ARCHIVE_WARN,
+ archive_entry_xattr_next(e, &xname, &xval, &xsize));
+ archive_entry_xattr_clear(e);
+ assertEqualInt(0, archive_entry_xattr_reset(e));
+ assertEqualInt(ARCHIVE_WARN,
+ archive_entry_xattr_next(e, &xname, &xval, &xsize));
+ archive_entry_xattr_add_entry(e, "xattr1", "xattrvalue1", 12);
+ assertEqualInt(1, archive_entry_xattr_reset(e));
+ archive_entry_xattr_add_entry(e, "xattr2", "xattrvalue2", 12);
+ assertEqualInt(2, archive_entry_xattr_reset(e));
+ assertEqualInt(0, archive_entry_xattr_next(e, &xname, &xval, &xsize));
+ assertEqualInt(0, archive_entry_xattr_next(e, &xname, &xval, &xsize));
+ assertEqualInt(ARCHIVE_WARN,
+ archive_entry_xattr_next(e, &xname, &xval, &xsize));
+
+
+ /*
+ * Test clone() implementation.
+ */
+
+ /* Set values in 'e' */
+ archive_entry_clear(e);
+ archive_entry_set_atime(e, 13579, 24680);
+ archive_entry_set_ctime(e, 13580, 24681);
+ archive_entry_set_dev(e, 235);
+ archive_entry_set_fflags(e, 0x55, 0xAA);
+ archive_entry_set_gid(e, 204);
+ archive_entry_set_gname(e, "group");
+ archive_entry_set_hardlink(e, "hardlinkname");
+ archive_entry_set_ino(e, 8593);
+ archive_entry_set_mode(e, 0123456);
+ archive_entry_set_mtime(e, 13581, 24682);
+ archive_entry_set_nlink(e, 736);
+ archive_entry_set_pathname(e, "path");
+ archive_entry_set_rdev(e, 532);
+ archive_entry_set_size(e, 987654321);
+ archive_entry_set_symlink(e, "symlinkname");
+ archive_entry_set_uid(e, 83);
+ archive_entry_set_uname(e, "user");
+ /* Add an ACL entry. */
+ archive_entry_acl_add_entry(e, ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ ARCHIVE_ENTRY_ACL_READ, ARCHIVE_ENTRY_ACL_USER, 77, "user77");
+ /* Add an extended attribute. */
+ archive_entry_xattr_add_entry(e, "xattr1", "xattrvalue", 11);
+
+ /* Make a clone. */
+ e2 = archive_entry_clone(e);
+
+ /* Clone should have same contents. */
+ assertEqualInt(archive_entry_atime(e2), 13579);
+ assertEqualInt(archive_entry_atime_nsec(e2), 24680);
+ assertEqualInt(archive_entry_ctime(e2), 13580);
+ assertEqualInt(archive_entry_ctime_nsec(e2), 24681);
+ assertEqualInt(archive_entry_dev(e2), 235);
+ archive_entry_fflags(e, &set, &clear);
+ assertEqualInt(clear, 0xAA);
+ assertEqualInt(set, 0x55);
+ assertEqualInt(archive_entry_gid(e2), 204);
+ assertEqualString(archive_entry_gname(e2), "group");
+ assertEqualString(archive_entry_hardlink(e2), "hardlinkname");
+ assertEqualInt(archive_entry_ino(e2), 8593);
+ assertEqualInt(archive_entry_mode(e2), 0123456);
+ assertEqualInt(archive_entry_mtime(e2), 13581);
+ assertEqualInt(archive_entry_mtime_nsec(e2), 24682);
+ assertEqualInt(archive_entry_nlink(e2), 736);
+ assertEqualString(archive_entry_pathname(e2), "path");
+ assertEqualInt(archive_entry_rdev(e2), 532);
+ assertEqualInt(archive_entry_size(e2), 987654321);
+ assertEqualString(archive_entry_symlink(e2), "symlinkname");
+ assertEqualInt(archive_entry_uid(e2), 83);
+ assertEqualString(archive_entry_uname(e2), "user");
+ /* Verify ACL was copied. */
+ assertEqualInt(4, archive_entry_acl_reset(e2,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ /* First three are standard permission bits. */
+ assertEqualInt(0, archive_entry_acl_next(e2,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ &type, &permset, &tag, &qual, &name));
+ assertEqualInt(type, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
+ assertEqualInt(permset, 4);
+ assertEqualInt(tag, ARCHIVE_ENTRY_ACL_USER_OBJ);
+ assertEqualInt(qual, -1);
+ assertEqualString(name, NULL);
+ assertEqualInt(0, archive_entry_acl_next(e2,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ &type, &permset, &tag, &qual, &name));
+ assertEqualInt(type, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
+ assertEqualInt(permset, 5);
+ assertEqualInt(tag, ARCHIVE_ENTRY_ACL_GROUP_OBJ);
+ assertEqualInt(qual, -1);
+ assertEqualString(name, NULL);
+ assertEqualInt(0, archive_entry_acl_next(e2,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ &type, &permset, &tag, &qual, &name));
+ assertEqualInt(type, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
+ assertEqualInt(permset, 6);
+ assertEqualInt(tag, ARCHIVE_ENTRY_ACL_OTHER);
+ assertEqualInt(qual, -1);
+ assertEqualString(name, NULL);
+ /* Fourth is custom one. */
+ assertEqualInt(0, archive_entry_acl_next(e2,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ &type, &permset, &tag, &qual, &name));
+ assertEqualInt(type, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
+ assertEqualInt(permset, ARCHIVE_ENTRY_ACL_READ);
+ assertEqualInt(tag, ARCHIVE_ENTRY_ACL_USER);
+ assertEqualInt(qual, 77);
+ assertEqualString(name, "user77");
+ /* Verify xattr was copied. */
+ assertEqualInt(1, archive_entry_xattr_reset(e2));
+ assertEqualInt(0, archive_entry_xattr_next(e2, &xname, &xval, &xsize));
+ assertEqualString(xname, "xattr1");
+ assertEqualString(xval, "xattrvalue");
+ assertEqualInt(xsize, 11);
+
+ /* Change the original */
+ archive_entry_set_atime(e, 13580, 24690);
+ archive_entry_set_ctime(e, 13590, 24691);
+ archive_entry_set_dev(e, 245);
+ archive_entry_set_fflags(e, 0x85, 0xDA);
+ archive_entry_set_filetype(e, AE_IFLNK);
+ archive_entry_set_gid(e, 214);
+ archive_entry_set_gname(e, "grouper");
+ archive_entry_set_hardlink(e, "hardlinkpath");
+ archive_entry_set_ino(e, 8763);
+ archive_entry_set_mode(e, 0123654);
+ archive_entry_set_mtime(e, 18351, 28642);
+ archive_entry_set_nlink(e, 73);
+ archive_entry_set_pathname(e, "pathest");
+ archive_entry_set_rdev(e, 132);
+ archive_entry_set_size(e, 987456321);
+ archive_entry_set_symlink(e, "symlinkpath");
+ archive_entry_set_uid(e, 93);
+ archive_entry_set_uname(e, "username");
+ archive_entry_acl_clear(e);
+ archive_entry_xattr_clear(e);
+
+ /* Clone should still have same contents. */
+ assertEqualInt(archive_entry_atime(e2), 13579);
+ assertEqualInt(archive_entry_atime_nsec(e2), 24680);
+ assertEqualInt(archive_entry_ctime(e2), 13580);
+ assertEqualInt(archive_entry_ctime_nsec(e2), 24681);
+ assertEqualInt(archive_entry_dev(e2), 235);
+ archive_entry_fflags(e2, &set, &clear);
+ assertEqualInt(clear, 0xAA);
+ assertEqualInt(set, 0x55);
+ assertEqualInt(archive_entry_gid(e2), 204);
+ assertEqualString(archive_entry_gname(e2), "group");
+ assertEqualString(archive_entry_hardlink(e2), "hardlinkname");
+ assertEqualInt(archive_entry_ino(e2), 8593);
+ assertEqualInt(archive_entry_mode(e2), 0123456);
+ assertEqualInt(archive_entry_mtime(e2), 13581);
+ assertEqualInt(archive_entry_mtime_nsec(e2), 24682);
+ assertEqualInt(archive_entry_nlink(e2), 736);
+ assertEqualString(archive_entry_pathname(e2), "path");
+ assertEqualInt(archive_entry_rdev(e2), 532);
+ assertEqualInt(archive_entry_size(e2), 987654321);
+ assertEqualString(archive_entry_symlink(e2), "symlinkname");
+ assertEqualInt(archive_entry_uid(e2), 83);
+ assertEqualString(archive_entry_uname(e2), "user");
+ /* Verify ACL was unchanged. */
+ assertEqualInt(4, archive_entry_acl_reset(e2,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS));
+ /* First three are standard permission bits. */
+ assertEqualInt(0, archive_entry_acl_next(e2,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ &type, &permset, &tag, &qual, &name));
+ assertEqualInt(type, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
+ assertEqualInt(permset, 4);
+ assertEqualInt(tag, ARCHIVE_ENTRY_ACL_USER_OBJ);
+ assertEqualInt(qual, -1);
+ assertEqualString(name, NULL);
+ assertEqualInt(0, archive_entry_acl_next(e2,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ &type, &permset, &tag, &qual, &name));
+ assertEqualInt(type, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
+ assertEqualInt(permset, 5);
+ assertEqualInt(tag, ARCHIVE_ENTRY_ACL_GROUP_OBJ);
+ assertEqualInt(qual, -1);
+ assertEqualString(name, NULL);
+ assertEqualInt(0, archive_entry_acl_next(e2,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ &type, &permset, &tag, &qual, &name));
+ assertEqualInt(type, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
+ assertEqualInt(permset, 6);
+ assertEqualInt(tag, ARCHIVE_ENTRY_ACL_OTHER);
+ assertEqualInt(qual, -1);
+ assertEqualString(name, NULL);
+ /* Fourth is custom one. */
+ assertEqualInt(0, archive_entry_acl_next(e2,
+ ARCHIVE_ENTRY_ACL_TYPE_ACCESS,
+ &type, &permset, &tag, &qual, &name));
+ assertEqualInt(type, ARCHIVE_ENTRY_ACL_TYPE_ACCESS);
+ assertEqualInt(permset, ARCHIVE_ENTRY_ACL_READ);
+ assertEqualInt(tag, ARCHIVE_ENTRY_ACL_USER);
+ assertEqualInt(qual, 77);
+ assertEqualString(name, "user77");
+ /* Verify xattr was unchanged. */
+ assertEqualInt(1, archive_entry_xattr_reset(e2));
+
+ /* Release clone. */
+ archive_entry_free(e2);
+
+ /*
+ * Test clear() implementation.
+ */
+ archive_entry_clear(e);
+ assertEqualInt(archive_entry_atime(e), 0);
+ assertEqualInt(archive_entry_atime_nsec(e), 0);
+ assertEqualInt(archive_entry_ctime(e), 0);
+ assertEqualInt(archive_entry_ctime_nsec(e), 0);
+ assertEqualInt(archive_entry_dev(e), 0);
+ archive_entry_fflags(e, &set, &clear);
+ assertEqualInt(clear, 0);
+ assertEqualInt(set, 0);
+ assertEqualInt(archive_entry_filetype(e), 0);
+ assertEqualInt(archive_entry_gid(e), 0);
+ assertEqualString(archive_entry_gname(e), NULL);
+ assertEqualString(archive_entry_hardlink(e), NULL);
+ assertEqualInt(archive_entry_ino(e), 0);
+ assertEqualInt(archive_entry_mode(e), 0);
+ assertEqualInt(archive_entry_mtime(e), 0);
+ assertEqualInt(archive_entry_mtime_nsec(e), 0);
+ assertEqualInt(archive_entry_nlink(e), 0);
+ assertEqualString(archive_entry_pathname(e), NULL);
+ assertEqualInt(archive_entry_rdev(e), 0);
+ assertEqualInt(archive_entry_size(e), 0);
+ assertEqualString(archive_entry_symlink(e), NULL);
+ assertEqualInt(archive_entry_uid(e), 0);
+ assertEqualString(archive_entry_uname(e), NULL);
+ /* ACLs should be cleared. */
+ assertEqualInt(archive_entry_acl_count(e, ARCHIVE_ENTRY_ACL_TYPE_ACCESS), 0);
+ assertEqualInt(archive_entry_acl_count(e, ARCHIVE_ENTRY_ACL_TYPE_DEFAULT), 0);
+ /* Extended attributes should be cleared. */
+ assertEqualInt(archive_entry_xattr_count(e), 0);
+
+ /*
+ * Test archive_entry_copy_stat().
+ */
+ memset(&st, 0, sizeof(st));
+ /* Set all of the standard 'struct stat' fields. */
+ st.st_atime = 456789;
+ st.st_ctime = 345678;
+ st.st_dev = 123;
+ st.st_gid = 34;
+ st.st_ino = 234;
+ st.st_mode = 077777;
+ st.st_mtime = 234567;
+ st.st_nlink = 345;
+ st.st_size = 123456789;
+ st.st_uid = 23;
+#ifdef __FreeBSD__
+ /* On FreeBSD, high-res timestamp data should come through. */
+ st.st_atimespec.tv_nsec = 6543210;
+ st.st_ctimespec.tv_nsec = 5432109;
+ st.st_mtimespec.tv_nsec = 3210987;
+#endif
+ /* Copy them into the entry. */
+ archive_entry_copy_stat(e, &st);
+ /* Read each one back separately and compare. */
+ assertEqualInt(archive_entry_atime(e), 456789);
+ assertEqualInt(archive_entry_ctime(e), 345678);
+ assertEqualInt(archive_entry_dev(e), 123);
+ assertEqualInt(archive_entry_gid(e), 34);
+ assertEqualInt(archive_entry_ino(e), 234);
+ assertEqualInt(archive_entry_mode(e), 077777);
+ assertEqualInt(archive_entry_mtime(e), 234567);
+ assertEqualInt(archive_entry_nlink(e), 345);
+ assertEqualInt(archive_entry_size(e), 123456789);
+ assertEqualInt(archive_entry_uid(e), 23);
+#if __FreeBSD__
+ /* On FreeBSD, high-res timestamp data should come through. */
+ assertEqualInt(archive_entry_atime_nsec(e), 6543210);
+ assertEqualInt(archive_entry_ctime_nsec(e), 5432109);
+ assertEqualInt(archive_entry_mtime_nsec(e), 3210987);
+#endif
+
+ /*
+ * Test archive_entry_stat().
+ */
+ /* First, clear out any existing stat data. */
+ memset(&st, 0, sizeof(st));
+ archive_entry_copy_stat(e, &st);
+ /* Set a bunch of fields individually. */
+ archive_entry_set_atime(e, 456789, 321);
+ archive_entry_set_ctime(e, 345678, 432);
+ archive_entry_set_dev(e, 123);
+ archive_entry_set_gid(e, 34);
+ archive_entry_set_ino(e, 234);
+ archive_entry_set_mode(e, 012345);
+ archive_entry_set_mode(e, 012345);
+ archive_entry_set_mtime(e, 234567, 543);
+ archive_entry_set_nlink(e, 345);
+ archive_entry_set_size(e, 123456789);
+ archive_entry_set_uid(e, 23);
+ /* Retrieve a stat structure. */
+ assert((pst = archive_entry_stat(e)) != NULL);
+ /* Check that the values match. */
+ assertEqualInt(pst->st_atime, 456789);
+ assertEqualInt(pst->st_ctime, 345678);
+ assertEqualInt(pst->st_dev, 123);
+ assertEqualInt(pst->st_gid, 34);
+ assertEqualInt(pst->st_ino, 234);
+ assertEqualInt(pst->st_mode, 012345);
+ assertEqualInt(pst->st_mtime, 234567);
+ assertEqualInt(pst->st_nlink, 345);
+ assertEqualInt(pst->st_size, 123456789);
+ assertEqualInt(pst->st_uid, 23);
+#ifdef __FreeBSD__
+ /* On FreeBSD, high-res timestamp data should come through. */
+ assertEqualInt(pst->st_atimespec.tv_nsec, 321);
+ assertEqualInt(pst->st_ctimespec.tv_nsec, 432);
+ assertEqualInt(pst->st_mtimespec.tv_nsec, 543);
+#endif
+
+ /* Changing any one value should update struct stat. */
+ archive_entry_set_atime(e, 456788, 0);
+ assert((pst = archive_entry_stat(e)) != NULL);
+ assertEqualInt(pst->st_atime, 456788);
+ archive_entry_set_ctime(e, 345677, 431);
+ assert((pst = archive_entry_stat(e)) != NULL);
+ assertEqualInt(pst->st_ctime, 345677);
+ archive_entry_set_dev(e, 122);
+ assert((pst = archive_entry_stat(e)) != NULL);
+ assertEqualInt(pst->st_dev, 122);
+ archive_entry_set_gid(e, 33);
+ assert((pst = archive_entry_stat(e)) != NULL);
+ assertEqualInt(pst->st_gid, 33);
+ archive_entry_set_ino(e, 233);
+ assert((pst = archive_entry_stat(e)) != NULL);
+ assertEqualInt(pst->st_ino, 233);
+ archive_entry_set_mode(e, 012344);
+ assert((pst = archive_entry_stat(e)) != NULL);
+ assertEqualInt(pst->st_mode, 012344);
+ archive_entry_set_mtime(e, 234566, 542);
+ assert((pst = archive_entry_stat(e)) != NULL);
+ assertEqualInt(pst->st_mtime, 234566);
+ archive_entry_set_nlink(e, 344);
+ assert((pst = archive_entry_stat(e)) != NULL);
+ assertEqualInt(pst->st_nlink, 344);
+ archive_entry_set_size(e, 123456788);
+ assert((pst = archive_entry_stat(e)) != NULL);
+ assertEqualInt(pst->st_size, 123456788);
+ archive_entry_set_uid(e, 22);
+ assert((pst = archive_entry_stat(e)) != NULL);
+ assertEqualInt(pst->st_uid, 22);
+ /* We don't need to check high-res fields here. */
+
+ /*
+ * Test dev/major/minor interfaces. Setting 'dev' or 'rdev'
+ * should change the corresponding major/minor values, and
+ * vice versa.
+ *
+ * The test here is system-specific because it assumes that
+ * makedev(), major(), and minor() are defined in sys/stat.h.
+ * I'm not too worried about it, though, because the code is
+ * simple. If it works on FreeBSD, it's unlikely to be broken
+ * anywhere else. Note: The functionality is present on every
+ * platform even if these tests only run some places;
+ * libarchive's more extensive configuration logic should find
+ * the necessary definitions on every platform.
+ */
+#if __FreeBSD__
+ archive_entry_set_dev(e, 0x12345678);
+ assertEqualInt(archive_entry_devmajor(e), major(0x12345678));
+ assertEqualInt(archive_entry_devminor(e), minor(0x12345678));
+ assertEqualInt(archive_entry_dev(e), 0x12345678);
+ archive_entry_set_devmajor(e, 0xfe);
+ archive_entry_set_devminor(e, 0xdcba98);
+ assertEqualInt(archive_entry_devmajor(e), 0xfe);
+ assertEqualInt(archive_entry_devminor(e), 0xdcba98);
+ assertEqualInt(archive_entry_dev(e), makedev(0xfe, 0xdcba98));
+ archive_entry_set_rdev(e, 0x12345678);
+ assertEqualInt(archive_entry_rdevmajor(e), major(0x12345678));
+ assertEqualInt(archive_entry_rdevminor(e), minor(0x12345678));
+ assertEqualInt(archive_entry_rdev(e), 0x12345678);
+ archive_entry_set_rdevmajor(e, 0xfe);
+ archive_entry_set_rdevminor(e, 0xdcba98);
+ assertEqualInt(archive_entry_rdevmajor(e), 0xfe);
+ assertEqualInt(archive_entry_rdevminor(e), 0xdcba98);
+ assertEqualInt(archive_entry_rdev(e), makedev(0xfe, 0xdcba98));
+#endif
+
+ /* Release the experimental entry. */
+ archive_entry_free(e);
+}
diff --git a/lib/libarchive/test/test_read_compress_program.c b/lib/libarchive/test/test_read_compress_program.c
new file mode 100644
index 0000000..993e872
--- /dev/null
+++ b/lib/libarchive/test/test_read_compress_program.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[] = {
+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_compress_program)
+{
+ struct archive_entry *ae;
+ struct archive *a;
+ assert((a = archive_read_new()) != NULL);
+ assertEqualIntA(a, 0, archive_read_support_compression_none(a));
+ assertEqualIntA(a, 0, archive_read_support_compression_program(a, "gunzip"));
+ assert(0 == archive_read_support_format_all(a));
+ assertEqualIntA(a, 0, archive_read_open_memory(a, archive, sizeof(archive)));
+ assertEqualIntA(a, 0, archive_read_next_header(a, &ae));
+ assert(archive_compression(a) == ARCHIVE_COMPRESSION_PROGRAM);
+ 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_data_large.c b/lib/libarchive/test/test_read_data_large.c
index e7dcc21..0361d5e 100644
--- a/lib/libarchive/test/test_read_data_large.c
+++ b/lib/libarchive/test/test_read_data_large.c
@@ -42,8 +42,8 @@ DEFINE_TEST(test_read_data_large)
struct archive_entry *ae;
struct archive *a;
char tmpfilename[] = "largefile";
- int tmpfile;
- int i;
+ int tmpfilefd;
+ unsigned int i;
size_t used;
/* Create a new archive in memory. */
@@ -96,21 +96,21 @@ DEFINE_TEST(test_read_data_large)
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));
+ tmpfilefd = open(tmpfilename, O_WRONLY | O_CREAT, 0777);
+ assert(tmpfilefd != 0);
+ assertEqualIntA(a, 0, archive_read_data_into_fd(a, tmpfilefd));
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);
+ close(tmpfilefd);
- tmpfile = open(tmpfilename, O_RDONLY);
- assert(tmpfile != 0);
- assertEqualIntA(NULL, sizeof(buff3), read(tmpfile, buff3, sizeof(buff3)));
- close(tmpfile);
+ tmpfilefd = open(tmpfilename, O_RDONLY);
+ assert(tmpfilefd != 0);
+ assertEqualIntA(NULL, sizeof(buff3), read(tmpfilefd, buff3, sizeof(buff3)));
+ close(tmpfilefd);
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
index 34aa59f..5a32eed 100644
--- a/lib/libarchive/test/test_read_extract.c
+++ b/lib/libarchive/test/test_read_extract.c
@@ -33,7 +33,7 @@ DEFINE_TEST(test_read_extract)
struct archive_entry *ae;
struct archive *a;
struct stat st;
- ssize_t used;
+ size_t used;
int i;
char *buff, *file_buff;
int fd;
diff --git a/lib/libarchive/test/test_read_format_ar.c b/lib/libarchive/test/test_read_format_ar.c
index 7a2a1e4..006d20b 100644
--- a/lib/libarchive/test/test_read_format_ar.c
+++ b/lib/libarchive/test/test_read_format_ar.c
@@ -66,7 +66,7 @@ DEFINE_TEST(test_read_format_ar)
/* Filename table. */
assertA(0 == archive_read_next_header(a, &ae));
- assert(0 == strcmp("//", archive_entry_pathname(ae)));
+ assertEqualString("//", archive_entry_pathname(ae));
assertEqualInt(0, archive_entry_mtime(ae));
assertEqualInt(0, archive_entry_uid(ae));
assertEqualInt(0, archive_entry_gid(ae));
@@ -76,7 +76,7 @@ DEFINE_TEST(test_read_format_ar)
/* First Entry */
assertA(0 == archive_read_next_header(a, &ae));
- assert(0 == strcmp("yyytttsssaaafff.o", archive_entry_pathname(ae)));
+ assertEqualString("yyytttsssaaafff.o", archive_entry_pathname(ae));
assertEqualInt(1175465652, archive_entry_mtime(ae));
assertEqualInt(1001, archive_entry_uid(ae));
assertEqualInt(0, archive_entry_gid(ae));
@@ -86,7 +86,7 @@ DEFINE_TEST(test_read_format_ar)
/* Second Entry */
assertA(0 == archive_read_next_header(a, &ae));
- assert(0 == strcmp("gghh.o", archive_entry_pathname(ae)));
+ assertEqualString("gghh.o", archive_entry_pathname(ae));
assertEqualInt(1175465668, archive_entry_mtime(ae));
assertEqualInt(1001, archive_entry_uid(ae));
assertEqualInt(0, archive_entry_gid(ae));
@@ -96,7 +96,7 @@ DEFINE_TEST(test_read_format_ar)
/* Third Entry */
assertA(0 == archive_read_next_header(a, &ae));
- assert(0 == strcmp("hhhhjjjjkkkkllll.o", archive_entry_pathname(ae)));
+ assertEqualString("hhhhjjjjkkkkllll.o", archive_entry_pathname(ae));
assertEqualInt(1175465713, archive_entry_mtime(ae));
assertEqualInt(1001, archive_entry_uid(ae));
assertEqualInt(0, archive_entry_gid(ae));
diff --git a/lib/libarchive/test/test_read_format_isorr_bz2.c b/lib/libarchive/test/test_read_format_isorr_bz2.c
index 3a7c56d..a0859f9 100644
--- a/lib/libarchive/test/test_read_format_isorr_bz2.c
+++ b/lib/libarchive/test/test_read_format_isorr_bz2.c
@@ -102,18 +102,18 @@ DEFINE_TEST(test_read_format_isorr_bz2)
/* First entry is '.' root directory. */
assert(0 == archive_read_next_header(a, &ae));
- assert(0 == strcmp(".", archive_entry_pathname(ae)));
+ assertEqualString(".", 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));
+ assertEqualInt(2048, archive_entry_size(ae));
+ assertEqualInt(1, archive_entry_mtime(ae));
+ assertEqualInt(0, archive_entry_mtime_nsec(ae));
+ assertEqualInt(1, archive_entry_ctime(ae));
+ assertEqualInt(0, archive_entry_stat(ae)->st_nlink);
+ assertEqualInt(0, archive_entry_uid(ae));
/* A directory. */
assert(0 == archive_read_next_header(a, &ae));
- assert(0 == strcmp("dir", archive_entry_pathname(ae)));
+ assertEqualString("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));
@@ -124,7 +124,7 @@ DEFINE_TEST(test_read_format_isorr_bz2)
/* A regular file. */
assert(0 == archive_read_next_header(a, &ae));
- assert(0 == strcmp("file", archive_entry_pathname(ae)));
+ assertEqualString("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));
@@ -139,9 +139,9 @@ DEFINE_TEST(test_read_format_isorr_bz2)
/* A hardlink to the regular file. */
assert(0 == archive_read_next_header(a, &ae));
- assert(0 == strcmp("hardlink", archive_entry_pathname(ae)));
+ assertEqualString("hardlink", archive_entry_pathname(ae));
assert(S_ISREG(archive_entry_stat(ae)->st_mode));
- assert(0 == strcmp("file", archive_entry_hardlink(ae)));
+ assertEqualString("file", archive_entry_hardlink(ae));
assert(6 == archive_entry_size(ae));
assert(1 == archive_entry_mtime(ae));
assert(1 == archive_entry_atime(ae));
@@ -151,9 +151,9 @@ DEFINE_TEST(test_read_format_isorr_bz2)
/* A symlink to the regular file. */
assert(0 == archive_read_next_header(a, &ae));
- assert(0 == strcmp("symlink", archive_entry_pathname(ae)));
+ assertEqualString("symlink", archive_entry_pathname(ae));
assert(S_ISLNK(archive_entry_stat(ae)->st_mode));
- assert(0 == strcmp("file", archive_entry_symlink(ae)));
+ assertEqualString("file", archive_entry_symlink(ae));
assert(0 == archive_entry_size(ae));
assert(-2 == archive_entry_mtime(ae));
assert(-2 == archive_entry_atime(ae));
diff --git a/lib/libarchive/test/test_read_format_zip.c b/lib/libarchive/test/test_read_format_zip.c
index 98b4ff1..96caf85 100644
--- a/lib/libarchive/test/test_read_format_zip.c
+++ b/lib/libarchive/test/test_read_format_zip.c
@@ -26,21 +26,49 @@
__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};
+'P','K',3,4,10,0,0,0,0,0,'Y','f',179,'6',0,0,0,0,0,0,0,0,0,0,0,0,4,0,21,0,
+'d','i','r','/','U','T',9,0,3,25,'U','O','F',25,'U','O','F','U','x',4,0,232,
+3,232,3,'P','K',3,4,20,0,0,0,8,0,'o','f',179,'6',':','7','f','=',10,0,0,0,
+18,0,0,0,5,0,21,0,'f','i','l','e','1','U','T',9,0,3,'A','U','O','F',172,'[',
+'O','F','U','x',4,0,232,3,232,3,203,'H',205,201,201,231,202,'@','"',1,'P',
+'K',3,4,20,0,0,0,8,0,'Z','j',179,'6',':','7','f','=',10,0,0,0,18,0,0,0,5,
+0,21,0,'f','i','l','e','2','U','T',9,0,3,172,'[','O','F',172,'[','O','F',
+'U','x',4,0,232,3,232,3,203,'H',205,201,201,231,202,'@','"',1,'P','K',1,2,
+23,3,10,0,0,0,0,0,'Y','f',179,'6',0,0,0,0,0,0,0,0,0,0,0,0,4,0,13,0,0,0,0,
+0,0,0,16,0,237,'A',0,0,0,0,'d','i','r','/','U','T',5,0,3,25,'U','O','F','U',
+'x',0,0,'P','K',1,2,23,3,20,0,0,0,8,0,'o','f',179,'6',':','7','f','=',10,
+0,0,0,18,0,0,0,5,0,13,0,0,0,0,0,1,0,0,0,164,129,'7',0,0,0,'f','i','l','e',
+'1','U','T',5,0,3,'A','U','O','F','U','x',0,0,'P','K',1,2,23,3,20,0,0,0,8,
+0,'Z','j',179,'6',':','7','f','=',10,0,0,0,18,0,0,0,5,0,13,0,0,0,0,0,1,0,
+0,0,164,129,'y',0,0,0,'f','i','l','e','2','U','T',5,0,3,172,'[','O','F','U',
+'x',0,0,'P','K',5,6,0,0,0,0,3,0,3,0,191,0,0,0,187,0,0,0,0,0};
DEFINE_TEST(test_read_format_zip)
{
struct archive_entry *ae;
struct archive *a;
+ char *buff[128];
+
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));
+ assertEqualString("dir/", archive_entry_pathname(ae));
+ assertEqualInt(1179604249, archive_entry_mtime(ae));
+ assertEqualInt(0, archive_entry_size(ae));
+ assertA(0 == archive_read_next_header(a, &ae));
+ assertEqualString("file1", archive_entry_pathname(ae));
+ assertEqualInt(1179604289, archive_entry_mtime(ae));
+ assertEqualInt(18, archive_entry_size(ae));
+ assertEqualInt(18, archive_read_data(a, buff, 18));
+ assert(0 == memcmp(buff, "hello\nhello\nhello\n", 18));
+ assertA(0 == archive_read_next_header(a, &ae));
+ assertEqualString("file2", archive_entry_pathname(ae));
+ assertEqualInt(1179605932, archive_entry_mtime(ae));
+ assertEqualInt(18, archive_entry_size(ae));
+ assertEqualInt(18, archive_read_data(a, buff, 18));
+ assert(0 == memcmp(buff, "hello\nhello\nhello\n", 18));
assertA(archive_compression(a) == ARCHIVE_COMPRESSION_NONE);
assertA(archive_format(a) == ARCHIVE_FORMAT_ZIP);
assert(0 == archive_read_close(a));
diff --git a/lib/libarchive/test/test_read_large.c b/lib/libarchive/test/test_read_large.c
index 11f7194..44a2b38 100644
--- a/lib/libarchive/test/test_read_large.c
+++ b/lib/libarchive/test/test_read_large.c
@@ -32,8 +32,8 @@ static unsigned char buff[11 * 1024 * 1024];
/* Check correct behavior on large reads. */
DEFINE_TEST(test_read_large)
{
- int i;
- int tmpfile;
+ unsigned int i;
+ int tmpfilefd;
char tmpfilename[] = "/tmp/test-read_large.XXXXXX";
size_t used;
struct archive *a;
@@ -77,17 +77,17 @@ DEFINE_TEST(test_read_large)
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);
+ assert(0 < (tmpfilefd = mkstemp(tmpfilename)));
+ assertA(0 == archive_read_data_into_fd(a, tmpfilefd));
+ close(tmpfilefd);
#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);
+ tmpfilefd = open(tmpfilename, O_RDONLY);
+ read(tmpfilefd, testdatacopy, sizeof(testdatacopy));
+ close(tmpfilefd);
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
index 0557774..d35766c 100644
--- a/lib/libarchive/test/test_read_position.c
+++ b/lib/libarchive/test/test_read_position.c
@@ -48,7 +48,7 @@ DEFINE_TEST(test_read_position)
assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &write_pos));
assertA(0 == archive_write_header(a, ae));
archive_entry_free(ae);
- assertA(data_size == archive_write_data(a, nulls, sizeof(nulls)));
+ assertA(data_size == (size_t)archive_write_data(a, nulls, sizeof(nulls)));
#if ARCHIVE_API_VERSION > 1
assertA(0 == archive_write_finish(a));
#else
diff --git a/lib/libarchive/test/test_read_truncated.c b/lib/libarchive/test/test_read_truncated.c
index ffbb74a..1cc62b2 100644
--- a/lib/libarchive/test/test_read_truncated.c
+++ b/lib/libarchive/test/test_read_truncated.c
@@ -32,7 +32,7 @@ DEFINE_TEST(test_read_truncated)
{
struct archive_entry *ae;
struct archive *a;
- int i;
+ unsigned int i;
size_t used;
/* Create a new archive in memory. */
diff --git a/lib/libarchive/test/test_tar_filenames.c b/lib/libarchive/test/test_tar_filenames.c
index 0f3c082..fb15a96 100644
--- a/lib/libarchive/test/test_tar_filenames.c
+++ b/lib/libarchive/test/test_tar_filenames.c
@@ -31,7 +31,7 @@ __FBSDID("$FreeBSD$");
* filenames into prefix/suffix.
*/
-static
+static void
test_filename(int dlen, int flen)
{
char buff[8192];
@@ -110,7 +110,7 @@ test_filename(int dlen, int flen)
/* Read the file and check the filename. */
assertA(0 == archive_read_next_header(a, &ae));
failure("Pathname %d/%d: %s", dlen, flen, archive_entry_pathname(ae));
- assert(0 == strcmp(filename, archive_entry_pathname(ae)));
+ assertEqualString(filename, archive_entry_pathname(ae));
assert((S_IFREG | 0755) == archive_entry_mode(ae));
/*
@@ -122,12 +122,12 @@ test_filename(int dlen, int flen)
*/
assertA(0 == archive_read_next_header(a, &ae));
failure("Pathname %d/%d: %s", dlen, flen, archive_entry_pathname(ae));
- assert(0 == strcmp(dirname, archive_entry_pathname(ae)));
+ assertEqualString(dirname, archive_entry_pathname(ae));
assert((S_IFDIR | 0755) == archive_entry_mode(ae));
assertA(0 == archive_read_next_header(a, &ae));
failure("Pathname %d/%d: %s", dlen, flen, archive_entry_pathname(ae));
- assert(0 == strcmp(dirname, archive_entry_pathname(ae)));
+ assertEqualString(dirname, archive_entry_pathname(ae));
assert((S_IFDIR | 0755) == archive_entry_mode(ae));
/* Verify the end of the archive. */
diff --git a/lib/libarchive/test/test_write_compress_program.c b/lib/libarchive/test/test_write_compress_program.c
new file mode 100644
index 0000000..c6b2a05
--- /dev/null
+++ b/lib/libarchive/test/test_write_compress_program.c
@@ -0,0 +1,97 @@
+/*-
+ * 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_compress_program)
+{
+ struct archive_entry *ae;
+ struct archive *a;
+ size_t used;
+ int blocksize = 1024;
+
+ /* Create a new archive in memory. */
+ /* Write it through an external "gzip" program. */
+ assert((a = archive_write_new()) != NULL);
+ assertA(0 == archive_write_set_format_ustar(a));
+ assertA(0 == archive_write_set_compression_program(a, "gzip"));
+ 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);
+ archive_entry_copy_pathname(ae, "file");
+ archive_entry_set_mode(ae, S_IFREG | 0755);
+ archive_entry_set_size(ae, 8);
+
+ assertA(0 == archive_write_header(a, ae));
+ archive_entry_free(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
+
+ /*
+ * Now, read the data back through the built-in gzip support.
+ */
+ 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));
+ assert(0 == archive_entry_atime(ae));
+ assert(0 == archive_entry_ctime(ae));
+ assertEqualString("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_disk.c b/lib/libarchive/test/test_write_disk.c
index 4ff70c3..a2d95bb 100644
--- a/lib/libarchive/test/test_write_disk.c
+++ b/lib/libarchive/test/test_write_disk.c
@@ -27,17 +27,18 @@ __FBSDID("$FreeBSD$");
#define UMASK 022
-static void create(struct archive_entry *ae)
+static void create(struct archive_entry *ae, const char *msg)
{
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));
+ failure("%s", msg);
+ assertEqualIntA(ad, 0, archive_write_header(ad, ae));
+ assertEqualIntA(ad, 0, archive_write_finish_entry(ad));
#if ARCHIVE_API_VERSION > 1
- assert(0 == archive_write_finish(ad));
+ assertEqualInt(0, archive_write_finish(ad));
#else
archive_write_finish(ad);
#endif
@@ -59,34 +60,34 @@ DEFINE_TEST(test_write_disk)
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "file");
archive_entry_set_mode(ae, S_IFREG | 0755);
- create(ae);
+ create(ae, "Test creating a regular file");
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);
+ create(ae, "Test creating a file over an existing file.");
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);
+ create(ae, "Test creating a regular dir.");
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);
+ create(ae, "Test creating a dir over an existing file.");
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);
+ create(ae, "Test creating a file over an existing dir.");
archive_entry_free(ae);
}
diff --git a/lib/libarchive/test/test_write_disk_perms.c b/lib/libarchive/test/test_write_disk_perms.c
index f514d40..c5d6559 100644
--- a/lib/libarchive/test/test_write_disk_perms.c
+++ b/lib/libarchive/test/test_write_disk_perms.c
@@ -27,9 +27,9 @@ __FBSDID("$FreeBSD$");
#define UMASK 022
-static gid_t _default_gid = 0;
-static gid_t _invalid_gid = 0;
-static gid_t _alt_gid = 0;
+static long _default_gid = -1;
+static long _invalid_gid = -1;
+static long _alt_gid = -1;
/*
* To fully test SGID restores, we need three distinct GIDs to work
@@ -42,13 +42,13 @@ static gid_t _alt_gid = 0;
* 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
+static void
searchgid(void)
{
static int _searched = 0;
uid_t uid = getuid();
gid_t gid = 0;
- int n;
+ unsigned int n;
struct stat st;
int fd;
@@ -67,7 +67,7 @@ searchgid(void)
_default_gid = st.st_gid;
/* Find a GID for which fchown() fails. This is our "invalid" GID. */
- _invalid_gid = 0;
+ _invalid_gid = -1;
/* 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) {
@@ -80,10 +80,10 @@ searchgid(void)
* 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 = -1;
+ for (gid = 0, n = 0; gid == n && n < 10000 ; n++, gid++) {
/* _alt_gid must be different than _default_gid */
- if (gid == _default_gid)
+ if (gid == (gid_t)_default_gid)
continue;
if (fchown(fd, uid, gid) == 0) {
_alt_gid = gid;
@@ -126,6 +126,15 @@ DEFINE_TEST(test_write_disk_perms)
struct archive_entry *ae;
struct stat st;
+ /*
+ * Set ownership of the current directory to the group of this
+ * process. Otherwise, the SGID tests below fail if the
+ * /tmp directory is owned by a group to which we don't belong
+ * and we're on a system where group ownership is inherited.
+ * (Because we're not allowed to SGID files with defaultgid().)
+ */
+ assertEqualInt(0, chown(".", getuid(), getgid()));
+
/* Create an archive_write_disk object. */
assert((a = archive_write_disk_new()) != NULL);
@@ -232,7 +241,7 @@ DEFINE_TEST(test_write_disk_perms)
failure("Setting SGID bit should succeed here.");
assertEqualIntA(a, 0, archive_write_finish_entry(a));
- if (altgid() == 0) {
+ if (altgid() == -1) {
/*
* Current user must belong to at least two groups or
* else we can't test setting the GID to another group.
@@ -278,7 +287,7 @@ DEFINE_TEST(test_write_disk_perms)
* but wrong GID. POSIX says you shouldn't restore SGID bit
* unless the GID could be restored.
*/
- if (invalidgid() == 0) {
+ if (invalidgid() == -1) {
/* This test always fails for root. */
printf("Running as root: Can't test SGID failures.\n");
} else {
@@ -352,7 +361,7 @@ DEFINE_TEST(test_write_disk_perms)
failure("file_perm_sgid: st.st_mode=%o", st.st_mode);
assert((st.st_mode & 07777) == (S_ISGID | 0742));
- if (altgid() != 0) {
+ if (altgid() != -1) {
/* SGID should not be set here. */
assert(0 == stat("file_alt_sgid", &st));
failure("file_alt_sgid: st.st_mode=%o", st.st_mode);
@@ -364,7 +373,7 @@ DEFINE_TEST(test_write_disk_perms)
assert((st.st_mode & 07777) == (S_ISGID | 0742));
}
- if (invalidgid() != 0) {
+ if (invalidgid() != -1) {
/* SGID should NOT be set here. */
assert(0 == stat("file_bad_sgid", &st));
failure("file_bad_sgid: st.st_mode=%o", st.st_mode);
diff --git a/lib/libarchive/test/test_write_format_ar.c b/lib/libarchive/test/test_write_format_ar.c
index a352641..1ee4a66 100644
--- a/lib/libarchive/test/test_write_format_ar.c
+++ b/lib/libarchive/test/test_write_format_ar.c
@@ -30,7 +30,7 @@ __FBSDID("$FreeBSD$");
char buff[4096];
char buff2[64];
-static unsigned char strtab[] = "abcdefghijklmn.o/\nggghhhjjjrrrttt.o/\n\n";
+static unsigned char strtab[] = "abcdefghijklmn.o/\nggghhhjjjrrrttt.o/\niiijjjdddsssppp.o/\n";
DEFINE_TEST(test_write_format_ar)
{
@@ -43,7 +43,7 @@ DEFINE_TEST(test_write_format_ar)
*/
assert((a = archive_write_new()) != NULL);
assertA(0 == archive_write_set_format_ar_svr4(a));
- assertA(0 == archive_write_set_compression_none(a));
+ assertA(0 == archive_write_set_compression_gzip(a));
assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &used));
/* write the filename table */
@@ -51,7 +51,7 @@ DEFINE_TEST(test_write_format_ar)
archive_entry_copy_pathname(ae, "//");
archive_entry_set_size(ae, strlen(strtab));
assertA(0 == archive_write_header(a, ae));
- assertA(strlen(strtab) == archive_write_data(a, strtab, strlen(strtab)));
+ assertA(strlen(strtab) == (size_t)archive_write_data(a, strtab, strlen(strtab)));
archive_entry_free(ae);
/* write entries */
@@ -68,11 +68,36 @@ DEFINE_TEST(test_write_format_ar)
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "ggghhhjjjrrrttt.o");
+ archive_entry_set_mode(ae, S_IFREG | 0755);
archive_entry_set_size(ae, 7);
assertA(0 == archive_write_header(a, ae));
assertA(7 == archive_write_data(a, "7777777", 7));
+ archive_entry_free(ae);
+ /* test full pathname */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "/usr/home/xx/iiijjjdddsssppp.o");
+ archive_entry_set_mode(ae, S_IFREG | 0755);
+ archive_entry_set_size(ae, 8);
+ assertA(0 == archive_write_header(a, ae));
+ assertA(8 == archive_write_data(a, "88877766", 8));
archive_entry_free(ae);
+
+ /* trailing "/" should be rejected */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "/usr/home/xx/iiijjj/");
+ archive_entry_set_size(ae, 8);
+ assertA(0 != archive_write_header(a, ae));
+ archive_entry_free(ae);
+
+ /* Non regular file should be rejected */
+ assert((ae = archive_entry_new()) != NULL);
+ archive_entry_copy_pathname(ae, "gfgh.o");
+ archive_entry_set_mode(ae, S_IFDIR | 0755);
+ archive_entry_set_size(ae, 6);
+ assertA(0 != archive_write_header(a, ae));
+ archive_entry_free(ae);
+
archive_write_close(a);
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_write_finish(a));
@@ -90,24 +115,30 @@ DEFINE_TEST(test_write_format_ar)
assertA(0 == archive_read_next_header(a, &ae));
assertEqualInt(0, archive_entry_mtime(ae));
- assert(0 == strcmp("//", archive_entry_pathname(ae)));
+ assertEqualString("//", archive_entry_pathname(ae));
assertEqualInt(strlen(strtab), archive_entry_size(ae));
assertEqualIntA(a, strlen(strtab), archive_read_data(a, buff2, 100));
assert(0 == memcmp(buff2, strtab, strlen(strtab)));
assertA(0 == archive_read_next_header(a, &ae));
assert(1 == archive_entry_mtime(ae));
- assert(0 == strcmp("abcdefghijklmn.o", archive_entry_pathname(ae)));
+ assertEqualString("abcdefghijklmn.o", archive_entry_pathname(ae));
assert(8 == archive_entry_size(ae));
assertA(8 == archive_read_data(a, buff2, 10));
assert(0 == memcmp(buff2, "87654321", 8));
assert(0 == archive_read_next_header(a, &ae));
- assert(0 == strcmp("ggghhhjjjrrrttt.o", archive_entry_pathname(ae)));
+ assertEqualString("ggghhhjjjrrrttt.o", archive_entry_pathname(ae));
assert(7 == archive_entry_size(ae));
assertA(7 == archive_read_data(a, buff2, 11));
assert(0 == memcmp(buff2, "7777777", 7));
+ assert(0 == archive_read_next_header(a, &ae));
+ assertEqualString("iiijjjdddsssppp.o", archive_entry_pathname(ae));
+ assert(8 == archive_entry_size(ae));
+ assertA(8 == archive_read_data(a, buff2, 17));
+ assert(0 == memcmp(buff2, "88877766", 8));
+
assert(0 == archive_read_close(a));
#if ARCHIVE_API_VERSION > 1
assert(0 == archive_read_finish(a));
@@ -118,14 +149,16 @@ DEFINE_TEST(test_write_format_ar)
/*
* Then, we try to create a BSD format archive.
*/
+ memset(buff, 0, sizeof(buff));
assert((a = archive_write_new()) != NULL);
assertA(0 == archive_write_set_format_ar_bsd(a));
- assertA(0 == archive_write_set_compression_none(a));
+ assertA(0 == archive_write_set_compression_bzip2(a));
assertA(0 == archive_write_open_memory(a, buff, sizeof(buff), &used));
/* write a entry need long name extension */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "ttttyyyyuuuuiiii.o");
+ archive_entry_set_mode(ae, S_IFREG | 0755);
archive_entry_set_size(ae, 5);
assertA(0 == archive_write_header(a, ae));
assertA(5 == archive_write_data(a, "12345", 7));
@@ -134,6 +167,7 @@ DEFINE_TEST(test_write_format_ar)
/* write a entry with a short name */
assert((ae = archive_entry_new()) != NULL);
archive_entry_copy_pathname(ae, "ttyy.o");
+ archive_entry_set_mode(ae, S_IFREG | 0755);
archive_entry_set_size(ae, 6);
assertA(0 == archive_write_header(a, ae));
assertA(6 == archive_write_data(a, "555555", 7));
@@ -151,20 +185,20 @@ DEFINE_TEST(test_write_format_ar)
assertA(0 == archive_read_support_compression_all(a));
assertA(0 == archive_read_open_memory(a, buff, used));
- assert(0 == archive_read_next_header(a, &ae));
- assert(0 == strcmp("ttttyyyyuuuuiiii.o", archive_entry_pathname(ae)));
+ assertEqualIntA(a, 0, archive_read_next_header(a, &ae));
+ assertEqualString("ttttyyyyuuuuiiii.o", archive_entry_pathname(ae));
assertEqualInt(5, archive_entry_size(ae));
assertA(5 == archive_read_data(a, buff2, 10));
assert(0 == memcmp(buff2, "12345", 5));
assert(0 == archive_read_next_header(a, &ae));
- assert(0 == strcmp("ttyy.o", archive_entry_pathname(ae)));
+ assertEqualString("ttyy.o", archive_entry_pathname(ae));
assert(6 == archive_entry_size(ae));
assertA(6 == archive_read_data(a, buff2, 10));
assert(0 == memcmp(buff2, "555555", 6));
/* Test EOF */
- assertA(1 == archive_read_next_header(a, &ae));
+ assertEqualIntA(a, 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));
diff --git a/lib/libarchive/test/test_write_format_cpio_empty.c b/lib/libarchive/test/test_write_format_cpio_empty.c
index c2e46d1..9f50e77 100644
--- a/lib/libarchive/test/test_write_format_cpio_empty.c
+++ b/lib/libarchive/test/test_write_format_cpio_empty.c
@@ -49,7 +49,6 @@ 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);
diff --git a/lib/libarchive/test/test_write_format_shar_empty.c b/lib/libarchive/test/test_write_format_shar_empty.c
index 81a024f..0af57dd 100644
--- a/lib/libarchive/test/test_write_format_shar_empty.c
+++ b/lib/libarchive/test/test_write_format_shar_empty.c
@@ -34,7 +34,6 @@ 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);
diff --git a/lib/libarchive/test/test_write_format_tar.c b/lib/libarchive/test/test_write_format_tar.c
index 2c2f41d..8b49895 100644
--- a/lib/libarchive/test/test_write_format_tar.c
+++ b/lib/libarchive/test/test_write_format_tar.c
@@ -34,7 +34,7 @@ DEFINE_TEST(test_write_format_tar)
struct archive *a;
char *p;
size_t used;
- int blocksize;
+ size_t blocksize;
/* Repeat the following for a variety of odd blocksizes. */
for (blocksize = 1; blocksize < 100000; blocksize += blocksize + 3) {
@@ -44,9 +44,9 @@ DEFINE_TEST(test_write_format_tar)
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(blocksize == (size_t)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));
+ assertA(blocksize == (size_t)archive_write_get_bytes_in_last_block(a));
/*
* Write a file to it.
@@ -54,12 +54,14 @@ DEFINE_TEST(test_write_format_tar)
assert((ae = archive_entry_new()) != NULL);
archive_entry_set_mtime(ae, 1, 10);
assert(1 == archive_entry_mtime(ae));
+#if !defined(__INTERIX)
assert(10 == archive_entry_mtime_nsec(ae));
+#endif
p = strdup("file");
archive_entry_copy_pathname(ae, p);
strcpy(p, "XXXX");
free(p);
- assert(0 == strcmp("file", archive_entry_pathname(ae)));
+ assertEqualString("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);
@@ -90,11 +92,11 @@ DEFINE_TEST(test_write_format_tar)
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. */
+ /* Not the same as above: ustar doesn't store hi-res times. */
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)));
+ assertEqualString("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));
diff --git a/lib/libarchive/test/test_write_format_tar_empty.c b/lib/libarchive/test/test_write_format_tar_empty.c
index 3273c0d..5fb8c8c 100644
--- a/lib/libarchive/test/test_write_format_tar_empty.c
+++ b/lib/libarchive/test/test_write_format_tar_empty.c
@@ -34,7 +34,7 @@ DEFINE_TEST(test_write_format_tar_empty)
struct archive *a;
char buff[2048];
size_t used;
- int i;
+ unsigned int i;
/* USTAR format: Create a new archive in memory. */
assert((a = archive_write_new()) != NULL);
diff --git a/lib/libarchive/test/test_write_open_memory.c b/lib/libarchive/test/test_write_open_memory.c
index fd8c7c8..9042876 100644
--- a/lib/libarchive/test/test_write_open_memory.c
+++ b/lib/libarchive/test/test_write_open_memory.c
@@ -30,7 +30,7 @@ static unsigned char buff[16384];
DEFINE_TEST(test_write_open_memory)
{
- int i;
+ unsigned int i;
struct archive *a;
struct archive_entry *ae;
const char *name="/tmp/test";
@@ -39,7 +39,7 @@ DEFINE_TEST(test_write_open_memory)
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));
+ assertEqualString(archive_entry_pathname(ae), name);
/* Try writing with different buffer sizes. */
/* Make sure that we get failure on too-small buffers, success on
OpenPOWER on IntegriCloud