diff options
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, ×) != 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 |