-Jan 10, 2012: Issue 223: Skip atime tests if atime not supported
-Jan 09, 2012: Issue 222: Errors saving sparse files to pax archives
-Jan 09, 2012: Issue 221: allow archive_*_free(NULL)
-Dec 31, 2011: Issue 212: configure script on Solaris
-Dec 30, 2011: Issue 218: empty contents extracting Zip files with bsdcpio
-Dec 30, 2011: Issue 217: fix compile warning
-Dec 30, 2011: Issue 216: truncated filenames in listings
-Dec 28, 2011: Issue 210: memory leak on Windows
-Dec 28, 2011: Issue 206: fix hardlink tests on Windows 2000
-Dec 27, 2011: Issue 208: Don't hang when using external compression
- program on Windows
+Mar 27, 2012: libarchive 3.0.4 released
+
+Feb 05, 2012: libarchive development now hosted at GitHub.
+ http://libarchive.github.com/
+Feb 05, 2012: libarchive's issue tracker remains at Google Code.
+ http://code.google.com/p/libarchive/issues/list
+Feb 05, 2012: libarchive's mailing lists remain at Google Groups.
Dec 24, 2011: libarchive 3.0.2 released
Dec 23, 2011: Various fixes merged from FreeBSD
README for libarchive bundle.
Questions? Issues?
- * http://libarchive.googlecode.com/ is the home for ongoing
- libarchive development, including issue tracker, additional
- documentation, and links to the libarchive mailing lists.
+ * http://libarchive.github.com/ is the home for ongoing
+ libarchive development, including documentation, and
+ links to the libarchive mailing lists.
+ * To report an issue, use the issue tracker at
+ http://code.google.com/p/libarchive/issues/list
+ * To submit an enhancement to libarchive, please submit
+ a pull request via GitHub.
+ https://github.com/libarchive/libarchive/pulls
This distribution bundle includes the following components:
* libarchive: a library for reading and writing streaming archives
* ZIP archives (with uncompressed or "deflate" compressed entries)
* GNU and BSD 'ar' archives
* 'mtree' format
+ * 7-Zip archives
* Microsoft CAB format
* LHA and LZH archives
* RAR archives
* GNU and BSD 'ar' archives
* 'mtree' format
* ISO9660 format
+ * 7-Zip archives
* XAR archives
When creating archives, the result can be filtered with any of the following:
.\"
.\" $FreeBSD$
.\"
-.Dd December 21, 2007
+.Dd December 24, 2011
.Dt CPIO 1
.Os
.Sh NAME
snprintf(errbuff, sizeof(errbuff),
"Couldn't lookup user ``%s''", user);
errbuff[sizeof(errbuff) - 1] = '\0';
+ free(user);
return (errbuff);
}
}
#include "cpio.h"
#include "err.h"
#include "line_reader.h"
-#include "matching.h"
/* Fixed size of uname/gname caches. */
#define name_cache_size 101
static void mode_list(struct cpio *);
static void mode_out(struct cpio *);
static void mode_pass(struct cpio *, const char *);
+static const char *remove_leading_slash(const char *);
static int restore_time(struct cpio *, struct archive_entry *,
const char *, int fd);
static void usage(void);
else {
#if defined(_WIN32) && !defined(__CYGWIN__)
lafe_progname = strrchr(*argv, '\\');
-#else
- lafe_progname = strrchr(*argv, '/');
+ if (strrchr(*argv, '/') > lafe_progname)
#endif
+ lafe_progname = strrchr(*argv, '/');
if (lafe_progname != NULL)
lafe_progname++;
else
cpio->bytes_per_block = 512;
cpio->filename = NULL;
+ cpio->matching = archive_match_new();
+ if (cpio->matching == NULL)
+ lafe_errc(1, 0, "Out of memory");
+
while ((opt = cpio_getopt(cpio)) != -1) {
switch (opt) {
case '0': /* GNU convention: --null, -0 */
cpio->extract_flags &= ~ARCHIVE_EXTRACT_NO_AUTODIR;
break;
case 'E': /* NetBSD/OpenBSD */
- lafe_include_from_file(&cpio->matching,
- cpio->argument, cpio->option_null);
+ if (archive_match_include_pattern_from_file(
+ cpio->matching, cpio->argument,
+ cpio->option_null) != ARCHIVE_OK)
+ lafe_errc(1, 0, "Error : %s",
+ archive_error_string(cpio->matching));
break;
case 'F': /* NetBSD/OpenBSD/GNU cpio */
cpio->filename = cpio->argument;
break;
case 'f': /* POSIX 1997 */
- lafe_exclude(&cpio->matching, cpio->argument);
+ if (archive_match_exclude_pattern(cpio->matching,
+ cpio->argument) != ARCHIVE_OK)
+ lafe_errc(1, 0, "Error : %s",
+ archive_error_string(cpio->matching));
break;
case 'H': /* GNU cpio (also --format) */
cpio->format = cpio->argument;
/* -v overrides -V */
if (cpio->dot && cpio->verbose)
cpio->dot = 0;
- /* -v overrides -V */
- if (cpio->dot && cpio->verbose)
- cpio->dot = 0;
/* TODO: Flag other nonsensical combinations. */
switch (cpio->mode) {
break;
case 'i':
while (*cpio->argv != NULL) {
- lafe_include(&cpio->matching, *cpio->argv);
+ if (archive_match_include_pattern(cpio->matching,
+ *cpio->argv) != ARCHIVE_OK)
+ lafe_errc(1, 0, "Error : %s",
+ archive_error_string(cpio->matching));
--cpio->argc;
++cpio->argv;
}
"Must specify at least one of -i, -o, or -p");
}
+ archive_match_free(cpio->matching);
free_cache(cpio->gname_cache);
free_cache(cpio->uname_cache);
return (cpio->return_value);
archive_write_free(cpio->archive);
}
+static const char *
+remove_leading_slash(const char *p)
+{
+ const char *rp;
+
+ /* Remove leading "//./" or "//?/" or "//?/UNC/"
+ * (absolute path prefixes used by Windows API) */
+ if ((p[0] == '/' || p[0] == '\\') &&
+ (p[1] == '/' || p[1] == '\\') &&
+ (p[2] == '.' || p[2] == '?') &&
+ (p[3] == '/' || p[3] == '\\'))
+ {
+ if (p[2] == '?' &&
+ (p[4] == 'U' || p[4] == 'u') &&
+ (p[5] == 'N' || p[5] == 'n') &&
+ (p[6] == 'C' || p[6] == 'c') &&
+ (p[7] == '/' || p[7] == '\\'))
+ p += 8;
+ else
+ p += 4;
+ }
+ do {
+ rp = p;
+ /* Remove leading drive letter from archives created
+ * on Windows. */
+ if (((p[0] >= 'a' && p[0] <= 'z') ||
+ (p[0] >= 'A' && p[0] <= 'Z')) &&
+ p[1] == ':') {
+ p += 2;
+ }
+ /* Remove leading "/../", "//", etc. */
+ while (p[0] == '/' || p[0] == '\\') {
+ if (p[1] == '.' && p[2] == '.' &&
+ (p[3] == '/' || p[3] == '\\')) {
+ p += 3; /* Remove "/..", leave "/"
+ * for next pass. */
+ } else
+ p += 1; /* Remove "/". */
+ }
+ } while (rp != p);
+ return (p);
+}
+
/*
* This is used by both out mode (to copy objects from disk into
* an archive) and pass mode (to copy objects from disk to
const char *destpath;
struct archive_entry *entry, *spare;
size_t len;
- const char *p;
int r;
/*
"Can't allocate path buffer");
}
strcpy(cpio->pass_destpath, cpio->destdir);
- p = srcpath;
- while (p[0] == '/')
- ++p;
- strcat(cpio->pass_destpath, p);
+ strcat(cpio->pass_destpath, remove_leading_slash(srcpath));
destpath = cpio->pass_destpath;
}
if (cpio->option_rename)
lafe_errc(1, archive_errno(a),
"%s", archive_error_string(a));
}
- if (lafe_excluded(cpio->matching, archive_entry_pathname(entry)))
+ if (archive_match_path_excluded(cpio->matching, entry))
continue;
if (cpio->option_rename) {
destpath = cpio_rename(archive_entry_pathname(entry));
lafe_errc(1, archive_errno(a),
"%s", archive_error_string(a));
}
- if (lafe_excluded(cpio->matching, archive_entry_pathname(entry)))
+ if (archive_match_path_excluded(cpio->matching, entry))
continue;
if (cpio->verbose)
list_item_verbose(cpio, entry);
static char buff[1024];
FILE *t;
char *p, *ret;
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ FILE *to;
+ t = fopen("CONIN$", "r");
+ if (t == NULL)
+ return (name);
+ to = fopen("CONOUT$", "w");
+ if (to == NULL)
+ return (name);
+ fprintf(to, "%s (Enter/./(new name))? ", name);
+ fclose(to);
+#else
t = fopen("/dev/tty", "r+");
if (t == NULL)
return (name);
fprintf(t, "%s (Enter/./(new name))? ", name);
fflush(t);
+#endif
p = fgets(buff, sizeof(buff), t);
fclose(t);
if (pwent == NULL) {
*name = NULL;
if (errno != 0 && errno != ENOENT)
- lafe_warnc(errno, "getpwuid(%d) failed", id);
+ lafe_warnc(errno, "getpwuid(%s) failed",
+ cpio_i64toa((int64_t)id));
return (errno);
}
if (grent == NULL) {
*name = NULL;
if (errno != 0)
- lafe_warnc(errno, "getgrgid(%d) failed", id);
+ lafe_warnc(errno, "getgrgid(%s) failed",
+ cpio_i64toa((int64_t)id));
return (errno);
}
#include "cpio_platform.h"
#include <stdio.h>
-#include "matching.h"
-
/*
* The internal state for the "cpio" program.
*
struct name_cache *gname_cache;
/* Work data. */
- struct lafe_matching *matching;
+ struct archive *matching;
char *buff;
size_t buff_size;
};
# else
# define __LA_SSIZE_T long
# endif
-# if defined(__BORLANDC__)
-# define __LA_UID_T uid_t
-# define __LA_GID_T gid_t
-# else
-# define __LA_UID_T short
-# define __LA_GID_T short
-# endif
#else
-# include <unistd.h> /* ssize_t, uid_t, and gid_t */
+# include <unistd.h> /* ssize_t */
# if defined(_SCO_DS)
# define __LA_INT64_T long long
# else
# define __LA_INT64_T int64_t
# endif
# define __LA_SSIZE_T ssize_t
-# define __LA_UID_T uid_t
-# define __LA_GID_T gid_t
#endif
/*
* assert that ARCHIVE_VERSION_NUMBER >= 2012108.
*/
/* Note: Compiler will complain if this does not match archive_entry.h! */
-#define ARCHIVE_VERSION_NUMBER 3000003
+#define ARCHIVE_VERSION_NUMBER 3000004
__LA_DECL int archive_version_number(void);
/*
* Textual name/version of the library, useful for version displays.
*/
-#define ARCHIVE_VERSION_STRING "libarchive 3.0.3"
+#define ARCHIVE_VERSION_STRING "libarchive 3.0.4"
__LA_DECL const char * archive_version_string(void);
/* Declare our basic types. */
__LA_DECL int archive_write_set_compression_xz(struct archive *);
#endif
+/* A convenience function to set the filter based on the code. */
+__LA_DECL int archive_write_add_filter(struct archive *, int filter_code);
__LA_DECL int archive_write_add_filter_bzip2(struct archive *);
__LA_DECL int archive_write_add_filter_compress(struct archive *);
__LA_DECL int archive_write_add_filter_gzip(struct archive *);
* traversal.
*/
__LA_DECL int archive_read_disk_descend(struct archive *);
+__LA_DECL int archive_read_disk_can_descend(struct archive *);
__LA_DECL int archive_read_disk_current_filesystem(struct archive *);
__LA_DECL int archive_read_disk_current_filesystem_is_synthetic(struct archive *);
__LA_DECL int archive_read_disk_current_filesystem_is_remote(struct archive *);
/* Request that the access time of the entry visited by travesal be restored. */
__LA_DECL int archive_read_disk_set_atime_restored(struct archive *);
+/*
+ * Set behavior. The "flags" argument selects optional behavior.
+ */
+/* Request that the access time of the entry visited by travesal be restored.
+ * This is the same as archive_read_disk_set_atime_restored. */
+#define ARCHIVE_READDISK_RESTORE_ATIME (0x0001)
+/* Default: Do not skip an entry which has nodump flags. */
+#define ARCHIVE_READDISK_HONOR_NODUMP (0x0002)
+/* Default: Skip a mac resource fork file whose prefix is "._" because of
+ * using copyfile. */
+#define ARCHIVE_READDISK_MAC_COPYFILE (0x0004)
+/* Default: Do not traverse mount points. */
+#define ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS (0x0008)
+
+__LA_DECL int archive_read_disk_set_behavior(struct archive *,
+ int flags);
+
+/*
+ * Set archive_match object that will be used in archive_read_disk to
+ * know whether an entry should be skipped. The callback function
+ * _excluded_func will be invoked when an entry is skipped by the result
+ * of archive_match.
+ */
+__LA_DECL int archive_read_disk_set_matching(struct archive *,
+ struct archive *_matching, void (*_excluded_func)
+ (struct archive *, void *, struct archive_entry *),
+ void *_client_data);
+__LA_DECL int archive_read_disk_set_metadata_filter_callback(struct archive *,
+ int (*_metadata_filter_func)(struct archive *, void *,
+ struct archive_entry *), void *_client_data);
/*
* Accessor functions to read/set various information in
struct archive *src);
__LA_DECL int archive_file_count(struct archive *);
+/*
+ * ARCHIVE_MATCH API
+ */
+__LA_DECL struct archive *archive_match_new(void);
+__LA_DECL int archive_match_free(struct archive *);
+
+/*
+ * Test if archive_entry is excluded.
+ * This is a convenience function. This is the same as calling all
+ * archive_match_path_excluded, archive_match_time_excluded
+ * and archive_match_owner_excluded.
+ */
+__LA_DECL int archive_match_excluded(struct archive *,
+ struct archive_entry *);
+
+/*
+ * Test if pathname is excluded. The conditions are set by following functions.
+ */
+__LA_DECL int archive_match_path_excluded(struct archive *,
+ struct archive_entry *);
+/* Add exclusion pathname pattern. */
+__LA_DECL int archive_match_exclude_pattern(struct archive *, const char *);
+__LA_DECL int archive_match_exclude_pattern_w(struct archive *,
+ const wchar_t *);
+/* Add exclusion pathname pattern from file. */
+__LA_DECL int archive_match_exclude_pattern_from_file(struct archive *,
+ const char *, int _nullSeparator);
+__LA_DECL int archive_match_exclude_pattern_from_file_w(struct archive *,
+ const wchar_t *, int _nullSeparator);
+/* Add inclusion pathname pattern. */
+__LA_DECL int archive_match_include_pattern(struct archive *, const char *);
+__LA_DECL int archive_match_include_pattern_w(struct archive *,
+ const wchar_t *);
+/* Add inclusion pathname pattern from file. */
+__LA_DECL int archive_match_include_pattern_from_file(struct archive *,
+ const char *, int _nullSeparator);
+__LA_DECL int archive_match_include_pattern_from_file_w(struct archive *,
+ const wchar_t *, int _nullSeparator);
+/*
+ * How to get statistic information for inclusion patterns.
+ */
+/* Return the amount number of unmatched inclusion patterns. */
+__LA_DECL int archive_match_path_unmatched_inclusions(struct archive *);
+/* Return the pattern of unmatched inclusion with ARCHIVE_OK.
+ * Return ARCHIVE_EOF if there is no inclusion pattern. */
+__LA_DECL int archive_match_path_unmatched_inclusions_next(
+ struct archive *, const char **);
+__LA_DECL int archive_match_path_unmatched_inclusions_next_w(
+ struct archive *, const wchar_t **);
+
+/*
+ * Test if a file is excluded by its time stamp.
+ * The conditions are set by following functions.
+ */
+__LA_DECL int archive_match_time_excluded(struct archive *,
+ struct archive_entry *);
+
+/*
+ * Flags to tell a matching type of time stamps. These are used for
+ * following functinos.
+ */
+/* Time flag: mtime to be tested. */
+#define ARCHIVE_MATCH_MTIME (0x0100)
+/* Time flag: ctime to be tested. */
+#define ARCHIVE_MATCH_CTIME (0x0200)
+/* Comparison flag: Match the time if it is newer than. */
+#define ARCHIVE_MATCH_NEWER (0x0001)
+/* Comparison flag: Match the time if it is older than. */
+#define ARCHIVE_MATCH_OLDER (0x0002)
+/* Comparison flag: Match the time if it is equal to. */
+#define ARCHIVE_MATCH_EQUAL (0x0010)
+/* Set inclusion time. */
+__LA_DECL int archive_match_include_time(struct archive *, int _flag,
+ time_t _sec, long _nsec);
+/* Set inclusion time by a date string. */
+__LA_DECL int archive_match_include_date(struct archive *, int _flag,
+ const char *_datestr);
+__LA_DECL int archive_match_include_date_w(struct archive *, int _flag,
+ const wchar_t *_datestr);
+/* Set inclusion time by a particluar file. */
+__LA_DECL int archive_match_include_file_time(struct archive *,
+ int _flag, const char *_pathname);
+__LA_DECL int archive_match_include_file_time_w(struct archive *,
+ int _flag, const wchar_t *_pathname);
+/* Add exclusion entry. */
+__LA_DECL int archive_match_exclude_entry(struct archive *,
+ int _flag, struct archive_entry *);
+
+/*
+ * Test if a file is excluded by its uid ,gid, uname or gname.
+ * The conditions are set by following functions.
+ */
+__LA_DECL int archive_match_owner_excluded(struct archive *,
+ struct archive_entry *);
+/* Add inclusion uid, gid, uname and gname. */
+__LA_DECL int archive_match_include_uid(struct archive *, __LA_INT64_T);
+__LA_DECL int archive_match_include_gid(struct archive *, __LA_INT64_T);
+__LA_DECL int archive_match_include_uname(struct archive *, const char *);
+__LA_DECL int archive_match_include_uname_w(struct archive *,
+ const wchar_t *);
+__LA_DECL int archive_match_include_gname(struct archive *, const char *);
+__LA_DECL int archive_match_include_gname_w(struct archive *,
+ const wchar_t *);
+
#ifdef __cplusplus
}
#endif
/* These are meaningless outside of this header. */
#undef __LA_DECL
-#undef __LA_GID_T
-#undef __LA_UID_T
/* These need to remain defined because they're used in the
* callback type definitions. XXX Fix this. This is ugly. XXX */
int type, int permset, int tag);
static struct archive_acl_entry *acl_new_entry(struct archive_acl *acl,
int type, int permset, int tag, int id);
+static int archive_acl_add_entry_len_l(struct archive_acl *acl,
+ int type, int permset, int tag, int id, const char *name,
+ size_t len, struct archive_string_conv *sc);
static int isint_w(const wchar_t *start, const wchar_t *end, int *result);
static int ismode_w(const wchar_t *start, const wchar_t *end, int *result);
static void next_field_w(const wchar_t **wp, const wchar_t **start,
static int ismode(const char *start, const char *end, int *result);
static void next_field(const char **p, const char **start,
const char **end, char *sep);
-static int prefix(const char *start, const char *end,
+static int prefix_c(const char *start, const char *end,
const char *test);
static void append_entry(char **p, const char *prefix, int tag,
const char *name, int perm, int id);
return ARCHIVE_OK;
}
-int
+static int
archive_acl_add_entry_len_l(struct archive_acl *acl,
int type, int permset, int tag, int id, const char *name, size_t len,
struct archive_string_conv *sc)
*permset = acl->acl_p->permset;
*tag = acl->acl_p->tag;
*id = acl->acl_p->id;
- if (archive_mstring_get_mbs(a, &acl->acl_p->name, name) != 0)
+ if (archive_mstring_get_mbs(a, &acl->acl_p->name, name) != 0) {
+ if (errno == ENOMEM)
+ return (ARCHIVE_FATAL);
*name = NULL;
+ }
acl->acl_p = acl->acl_p->next;
return (ARCHIVE_OK);
}
const wchar_t *prefix;
wchar_t separator;
struct archive_acl_entry *ap;
- int id;
+ int id, r;
wchar_t *wp;
if (acl->acl_text_w != NULL) {
length += 8; /* "default:" */
length += 5; /* tag name */
length += 1; /* colon */
- if (archive_mstring_get_wcs(a, &ap->name, &wname) == 0 &&
- wname != NULL)
+ r = archive_mstring_get_wcs(a, &ap->name, &wname);
+ if (r == 0 && wname != NULL)
length += wcslen(wname);
+ else if (r < 0 && errno == ENOMEM)
+ return (NULL);
else
length += sizeof(uid_t) * 3 + 1;
length ++; /* colon */
/* Now, allocate the string and actually populate it. */
wp = acl->acl_text_w = (wchar_t *)malloc(length * sizeof(wchar_t));
if (wp == NULL)
- __archive_errx(1, "No memory to generate the text version of the ACL");
+ return (NULL);
count = 0;
if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
append_entry_w(&wp, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL,
ap = acl->acl_head;
while (ap != NULL) {
- if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0 &&
- archive_mstring_get_wcs(a, &ap->name, &wname) == 0) {
- *wp++ = separator;
- if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
- id = ap->id;
- else
- id = -1;
- append_entry_w(&wp, NULL, ap->tag, wname,
- ap->permset, id);
- count++;
+ if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
+ r = archive_mstring_get_wcs(a, &ap->name, &wname);
+ if (r == 0) {
+ *wp++ = separator;
+ if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
+ id = ap->id;
+ else
+ id = -1;
+ append_entry_w(&wp, NULL, ap->tag, wname,
+ ap->permset, id);
+ count++;
+ } else if (r < 0 && errno == ENOMEM)
+ return (NULL);
}
ap = ap->next;
}
ap = acl->acl_head;
count = 0;
while (ap != NULL) {
- if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0 &&
- archive_mstring_get_wcs(a, &ap->name, &wname) == 0) {
- if (count > 0)
- *wp++ = separator;
- if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
- id = ap->id;
- else
- id = -1;
- append_entry_w(&wp, prefix, ap->tag,
- wname, ap->permset, id);
- count ++;
+ if ((ap->type & ARCHIVE_ENTRY_ACL_TYPE_DEFAULT) != 0) {
+ r = archive_mstring_get_wcs(a, &ap->name, &wname);
+ if (r == 0) {
+ if (count > 0)
+ *wp++ = separator;
+ if (flags & ARCHIVE_ENTRY_ACL_STYLE_EXTRA_ID)
+ id = ap->id;
+ else
+ id = -1;
+ append_entry_w(&wp, prefix, ap->tag,
+ wname, ap->permset, id);
+ count ++;
+ } else if (r < 0 && errno == ENOMEM)
+ return (NULL);
}
ap = ap->next;
}
/* Now, allocate the string and actually populate it. */
p = acl->acl_text = (char *)malloc(length);
if (p == NULL)
- __archive_errx(1, "No memory to generate the text version of the ACL");
+ return (-1);
count = 0;
if ((flags & ARCHIVE_ENTRY_ACL_TYPE_ACCESS) != 0) {
append_entry(&p, NULL, ARCHIVE_ENTRY_ACL_USER_OBJ, NULL,
type = default_type;
name.start = name.end = NULL;
- if (prefix(field[0].start, field[0].end, "user")) {
+ if (prefix_c(field[0].start, field[0].end, "user")) {
if (!ismode(field[2].start, field[2].end, &permset))
return (ARCHIVE_WARN);
if (id != -1 || field[1].start < field[1].end) {
name = field[1];
} else
tag = ARCHIVE_ENTRY_ACL_USER_OBJ;
- } else if (prefix(field[0].start, field[0].end, "group")) {
+ } else if (prefix_c(field[0].start, field[0].end, "group")) {
if (!ismode(field[2].start, field[2].end, &permset))
return (ARCHIVE_WARN);
if (id != -1 || field[1].start < field[1].end) {
name = field[1];
} else
tag = ARCHIVE_ENTRY_ACL_GROUP_OBJ;
- } else if (prefix(field[0].start, field[0].end, "other")) {
+ } else if (prefix_c(field[0].start, field[0].end, "other")) {
if (fields == 2
&& field[1].start < field[1].end
&& ismode(field[1].start, field[1].end, &permset)) {
} else
return (ARCHIVE_WARN);
tag = ARCHIVE_ENTRY_ACL_OTHER;
- } else if (prefix(field[0].start, field[0].end, "mask")) {
+ } else if (prefix_c(field[0].start, field[0].end, "mask")) {
if (fields == 2
&& field[1].start < field[1].end
&& ismode(field[1].start, field[1].end, &permset)) {
* This makes it easy to handle the obvious abbreviations: 'u' for 'user', etc.
*/
static int
-prefix(const char *start, const char *end, const char *test)
+prefix_c(const char *start, const char *end, const char *test)
{
if (start == end)
return (0);
case ARCHIVE_READ_MAGIC: return ("archive_read");
case ARCHIVE_WRITE_DISK_MAGIC: return ("archive_write_disk");
case ARCHIVE_READ_DISK_MAGIC: return ("archive_read_disk");
+ case ARCHIVE_MATCH_MAGIC: return ("archive_match");
default: return NULL;
}
}
{
unsigned char *p = (unsigned char *)pp;
- archive_be32enc(p, u >> 32);
- archive_be32enc(p + 4, u & 0xffffffff);
+ archive_be32enc(p, (uint32_t)(u >> 32));
+ archive_be32enc(p + 4, (uint32_t)(u & 0xffffffff));
}
static inline void
{
unsigned char *p = (unsigned char *)pp;
- archive_le32enc(p, u & 0xffffffff);
- archive_le32enc(p + 4, u >> 32);
+ archive_le32enc(p, (uint32_t)(u & 0xffffffff));
+ archive_le32enc(p + 4, (uint32_t)(u >> 32));
}
#endif
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" $FreeBSD: src/lib/libarchive/archive_entry.3,v 1.18 2008/05/26 17:00:22 kientzle Exp $
+.\" $FreeBSD$
.\"
-.Dd Feburary 22, 2010
+.Dd Feburary 2, 2012
.Dt ARCHIVE_ENTRY 3
.Os
.Sh NAME
.Nm archive_entry_free ,
.Nm archive_entry_new ,
.Nd functions for managing archive entry descriptions
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
.Sh SYNOPSIS
.In archive_entry.h
.Ft "struct archive_entry *"
char *p;
if (archive_mstring_get_mbs(entry->archive,
- &entry->ae_fflags_text, &f) == 0 && f != NULL)
- return (f);
+ &entry->ae_fflags_text, &f) == 0) {
+ if (f != NULL)
+ return (f);
+ } else if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
if (entry->ae_fflags_set == 0 && entry->ae_fflags_clear == 0)
return (NULL);
if (archive_mstring_get_mbs(entry->archive,
&entry->ae_fflags_text, &f) == 0)
return (f);
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
return (NULL);
}
const char *p;
if (archive_mstring_get_mbs(entry->archive, &entry->ae_gname, &p) == 0)
return (p);
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
return (NULL);
}
const wchar_t *p;
if (archive_mstring_get_wcs(entry->archive, &entry->ae_gname, &p) == 0)
return (p);
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
return (NULL);
}
archive_entry_hardlink(struct archive_entry *entry)
{
const char *p;
- if ((entry->ae_set & AE_SET_HARDLINK) && archive_mstring_get_mbs(
+ if ((entry->ae_set & AE_SET_HARDLINK) == 0)
+ return (NULL);
+ if (archive_mstring_get_mbs(
entry->archive, &entry->ae_hardlink, &p) == 0)
return (p);
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
return (NULL);
}
archive_entry_hardlink_w(struct archive_entry *entry)
{
const wchar_t *p;
- if ((entry->ae_set & AE_SET_HARDLINK) && archive_mstring_get_wcs(
+ if ((entry->ae_set & AE_SET_HARDLINK) == 0)
+ return (NULL);
+ if (archive_mstring_get_wcs(
entry->archive, &entry->ae_hardlink, &p) == 0)
return (p);
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
return (NULL);
}
if (archive_mstring_get_mbs(
entry->archive, &entry->ae_pathname, &p) == 0)
return (p);
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
return (NULL);
}
if (archive_mstring_get_wcs(
entry->archive, &entry->ae_pathname, &p) == 0)
return (p);
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
return (NULL);
}
if (archive_mstring_get_mbs(
entry->archive, &entry->ae_sourcepath, &p) == 0)
return (p);
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
return (NULL);
}
archive_entry_symlink(struct archive_entry *entry)
{
const char *p;
- if ((entry->ae_set & AE_SET_SYMLINK) && archive_mstring_get_mbs(
+ if ((entry->ae_set & AE_SET_SYMLINK) == 0)
+ return (NULL);
+ if (archive_mstring_get_mbs(
entry->archive, &entry->ae_symlink, &p) == 0)
return (p);
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
return (NULL);
}
archive_entry_symlink_w(struct archive_entry *entry)
{
const wchar_t *p;
- if ((entry->ae_set & AE_SET_SYMLINK) && archive_mstring_get_wcs(
+ if ((entry->ae_set & AE_SET_SYMLINK) == 0)
+ return (NULL);
+ if (archive_mstring_get_wcs(
entry->archive, &entry->ae_symlink, &p) == 0)
return (p);
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
return (NULL);
}
const char *p;
if (archive_mstring_get_mbs(entry->archive, &entry->ae_uname, &p) == 0)
return (p);
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
return (NULL);
}
const wchar_t *p;
if (archive_mstring_get_wcs(entry->archive, &entry->ae_uname, &p) == 0)
return (p);
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
return (NULL);
}
if (archive_mstring_update_utf8(entry->archive,
&entry->ae_gname, name) == 0)
return (1);
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
return (0);
}
if (archive_mstring_update_utf8(entry->archive,
&entry->ae_hardlink, target) == 0)
return (1);
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
return (0);
}
else
r = archive_mstring_update_utf8(entry->archive,
&entry->ae_hardlink, target);
- return ((r == 0)? 1: 0);
+ if (r == 0)
+ return (1);
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
+ return (0);
}
int
if (archive_mstring_update_utf8(entry->archive,
&entry->ae_pathname, name) == 0)
return (1);
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
return (0);
}
if (archive_mstring_update_utf8(entry->archive,
&entry->ae_symlink, linkname) == 0)
return (1);
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
return (0);
}
if (archive_mstring_update_utf8(entry->archive,
&entry->ae_uname, name) == 0)
return (1);
+ if (errno == ENOMEM)
+ __archive_errx(1, "No memory");
return (0);
}
archive_entry_acl_next(struct archive_entry *entry, int want_type, int *type,
int *permset, int *tag, int *id, const char **name)
{
- return archive_acl_next(entry->archive, &entry->acl, want_type, type, permset, tag, id, name);
+ int r;
+ r = archive_acl_next(entry->archive, &entry->acl, want_type, type,
+ permset, tag, id, name);
+ if (r == ARCHIVE_FATAL && errno == ENOMEM)
+ __archive_errx(1, "No memory");
+ return (r);
}
/*
const wchar_t *
archive_entry_acl_text_w(struct archive_entry *entry, int flags)
{
- return archive_acl_text_w(entry->archive, &entry->acl, flags);
+ const wchar_t *r;
+ r = archive_acl_text_w(entry->archive, &entry->acl, flags);
+ if (r == NULL && errno == ENOMEM)
+ __archive_errx(1, "No memory");
+ return (r);
}
const char *
const char *p;
if (archive_acl_text_l(&entry->acl, flags, &p, NULL, NULL) != 0
&& errno == ENOMEM)
- return (NULL);
+ __archive_errx(1, "No memory");
return (p);
}
#define ARCHIVE_ENTRY_H_INCLUDED
/* Note: Compiler will complain if this does not match archive.h! */
-#define ARCHIVE_VERSION_NUMBER 3000003
+#define ARCHIVE_VERSION_NUMBER 3000004
/*
* Note: archive_entry.h is for use outside of libarchive; the
#include <windows.h>
#endif
-/* Get appropriate definitions of standard POSIX-style types. */
-/* These should match the types used in 'struct stat' */
+/* Get a suitable 64-bit integer type. */
#if defined(_WIN32) && !defined(__CYGWIN__)
-#define __LA_INT64_T __int64
-# if defined(__BORLANDC__)
-# define __LA_UID_T uid_t /* Remove in libarchive 3.2 */
-# define __LA_GID_T gid_t /* Remove in libarchive 3.2 */
-# define __LA_DEV_T dev_t
-# define __LA_MODE_T mode_t
-# else
-# define __LA_UID_T short /* Remove in libarchive 3.2 */
-# define __LA_GID_T short /* Remove in libarchive 3.2 */
-# define __LA_DEV_T unsigned int
-# define __LA_MODE_T unsigned short
-# endif
+# define __LA_INT64_T __int64
#else
#include <unistd.h>
# if defined(_SCO_DS)
# else
# define __LA_INT64_T int64_t
# endif
-# define __LA_UID_T uid_t /* Remove in libarchive 3.2 */
-# define __LA_GID_T gid_t /* Remove in libarchive 3.2 */
-# define __LA_DEV_T dev_t
-# define __LA_MODE_T mode_t
#endif
-/*
- * Remove this for libarchive 3.2, since ino_t is no longer used.
- */
-#define __LA_INO_T ino_t
-
+/* Get a suitable definition for mode_t */
+#if ARCHIVE_VERSION_NUMBER >= 3999000
+/* Switch to plain 'int' for libarchive 4.0. It's less broken than 'mode_t' */
+# define __LA_MODE_T int
+#elif defined(_WIN32) && !defined(__CYGWIN__) && !defined(__BORLANDC__)
+# define __LA_MODE_T unsigned short
+#else
+# define __LA_MODE_T mode_t
+#endif
/*
* On Windows, define LIBARCHIVE_STATIC if you're building or using a
* portable values to platform-native values when entries are read from
* or written to disk.
*/
-#define AE_IFMT 0170000
-#define AE_IFREG 0100000
-#define AE_IFLNK 0120000
-#define AE_IFSOCK 0140000
-#define AE_IFCHR 0020000
-#define AE_IFBLK 0060000
-#define AE_IFDIR 0040000
-#define AE_IFIFO 0010000
+/*
+ * In libarchive 4.0, we can drop the casts here.
+ * They're needed to work around Borland C's broken mode_t.
+ */
+#define AE_IFMT ((__LA_MODE_T)0170000)
+#define AE_IFREG ((__LA_MODE_T)0100000)
+#define AE_IFLNK ((__LA_MODE_T)0120000)
+#define AE_IFSOCK ((__LA_MODE_T)0140000)
+#define AE_IFCHR ((__LA_MODE_T)0020000)
+#define AE_IFBLK ((__LA_MODE_T)0060000)
+#define AE_IFDIR ((__LA_MODE_T)0040000)
+#define AE_IFIFO ((__LA_MODE_T)0010000)
/*
* Basic object manipulation
* manipulate archives on systems different than the ones they were
* created on.
*
- * TODO: On Linux, provide both stat32 and stat64 versions of these functions.
+ * TODO: On Linux and other LFS systems, provide both stat32 and
+ * stat64 versions of these functions and all of the macro glue so
+ * that archive_entry_stat is magically defined to
+ * archive_entry_stat32 or archive_entry_stat64 as appropriate.
*/
__LA_DECL const struct stat *archive_entry_stat(struct archive_entry *);
__LA_DECL void archive_entry_copy_stat(struct archive_entry *, const struct stat *);
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd February 21, 2010
+.Dd February 2, 2012
.Dt ARCHIVE_ENTRY_ACL 3
.Os
.Sh NAME
.Nm archive_entry_acl_reset ,
.Nm archive_entry_acl_text_w
.Nd functions for manipulating Access Control Lists in archive entry descriptions
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
.Sh SYNOPSIS
.In archive_entry.h
.Ft void
if (res->number_entries > res->number_buckets * 2)
grow_hash(res);
- hash = archive_entry_dev(entry) ^ archive_entry_ino64(entry);
+ hash = (size_t)(archive_entry_dev(entry) ^ archive_entry_ino64(entry));
bucket = hash & (res->number_buckets - 1);
/* If we could allocate the entry, record it. */
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd February 20, 2010
+.Dd February 2, 2012
.Dt ARCHIVE_ENTRY_LINKIFY 3
.Os
.Sh NAME
.Nm archive_entry_linkify
.Nd hardlink resolver functions
.Sh LIBRARY
-.Lb libarchive
+Streaming Archive Library (libarchive, -larchive)
.Sh SYNOPSIS
.In archive_entry.h
.Ft struct archive_entry_linkresolver *
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd February 22, 2010
+.Dd February 2, 2012
.Dt ARCHIVE_ENTRY_PATHS 3
.Os
.Sh NAME
.Nm archive_entry_copy_symlink_w ,
.Nm archve_entry_update_symlink_utf8
.Nd functions for manipulating path names in archive entry descriptions
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
.Sh SYNOPSIS
.In archive_entry.h
.Ft const char *
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd February 22, 2010
+.Dd February 2, 2012
.Dt ARCHIVE_ENTRY_PERMS 3
.Os
.Sh NAME
.Nm archive_entry_copy_fflags_text ,
.Nm archive_entry_copy_fflags_text_w
.Nd functions for manipulating ownership and permissions in archive entry descriptions
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
.Sh SYNOPSIS
.In archive_entry.h
.Ft gid_t
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.Dd May 12, 2008
-.Dt ARCHIVE_ENTRY 3
+.Dd February 2, 2012
+.Dt ARCHIVE_ENTRY_STAT 3
.Os
.Sh NAME
.Nm archive_entry_stat ,
.Nm archive_entry_rdevminor ,
.Nm archive_entry_set_rdevminor ,
.Nd accessor functions for manipulating archive entry descriptions
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
.Sh SYNOPSIS
.In archive_entry.h
.Ft const struct stat *
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_ino64(entry);
+ st->st_gid = (gid_t)archive_entry_gid(entry);
+ st->st_uid = (uid_t)archive_entry_uid(entry);
+ st->st_ino = (ino_t)archive_entry_ino64(entry);
st->st_nlink = archive_entry_nlink(entry);
st->st_rdev = archive_entry_rdev(entry);
- st->st_size = archive_entry_size(entry);
+ st->st_size = (off_t)archive_entry_size(entry);
st->st_mode = archive_entry_mode(entry);
/*
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" $FreeBSD: src/lib/libarchive/archive_entry.3,v 1.18 2008/05/26 17:00:22 kientzle Exp $
+.\" $FreeBSD$
.\"
-.Dd February 21, 2010
+.Dd February 2, 2012
.Dt ARCHIVE_ENTRY_TIME 3
.Os
.Sh NAME
.Nm archive_entry_set_mtime ,
.Nm archive_entry_unset_mtime ,
.Nd functions for manipulating times in archive entry descriptions
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
.Sh SYNOPSIS
.In archive_entry.h
.Ft time_t
#include <time.h>
/* This file defines a single public function. */
-time_t get_date(time_t now, char *);
+time_t __archive_get_date(time_t now, char *);
/* Basic time units. */
#define EPOCH 1970
* TODO: tokens[] array should be dynamically sized.
*/
time_t
-get_date(time_t now, char *p)
+__archive_get_date(time_t now, char *p)
{
struct token tokens[256];
struct gdstate _gds;
--- /dev/null
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * Copyright (c) 2012 Michihiro NAKAJIMA
+ * 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_ERRNO_H
+#include <errno.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_entry.h"
+#include "archive_pathmatch.h"
+#include "archive_rb.h"
+#include "archive_string.h"
+
+struct match {
+ struct match *next;
+ int matches;
+ struct archive_mstring pattern;
+};
+
+struct match_list {
+ struct match *first;
+ struct match **last;
+ int count;
+ int unmatched_count;
+ struct match *unmatched_next;
+ int unmatched_eof;
+};
+
+struct match_file {
+ struct archive_rb_node node;
+ struct match_file *next;
+ struct archive_mstring pathname;
+ int flag;
+ time_t mtime_sec;
+ long mtime_nsec;
+ time_t ctime_sec;
+ long ctime_nsec;
+};
+
+struct entry_list {
+ struct match_file *first;
+ struct match_file **last;
+ int count;
+};
+
+struct id_array {
+ size_t size;/* Allocated size */
+ size_t count;
+ int64_t *ids;
+};
+
+#define PATTERN_IS_SET 1
+#define TIME_IS_SET 2
+#define ID_IS_SET 4
+
+struct archive_match {
+ struct archive archive;
+
+ /* exclusion/inclusion set flag. */
+ int setflag;
+
+ /*
+ * Matching filename patterns.
+ */
+ struct match_list exclusions;
+ struct match_list inclusions;
+
+ /*
+ * Matching time stamps.
+ */
+ time_t now;
+ int newer_mtime_filter;
+ time_t newer_mtime_sec;
+ long newer_mtime_nsec;
+ int newer_ctime_filter;
+ time_t newer_ctime_sec;
+ long newer_ctime_nsec;
+ int older_mtime_filter;
+ time_t older_mtime_sec;
+ long older_mtime_nsec;
+ int older_ctime_filter;
+ time_t older_ctime_sec;
+ long older_ctime_nsec;
+ /*
+ * Matching time stamps with its filename.
+ */
+ struct archive_rb_tree exclusion_tree;
+ struct entry_list exclusion_entry_list;
+
+ /*
+ * Matching file owners.
+ */
+ struct id_array inclusion_uids;
+ struct id_array inclusion_gids;
+ struct match_list inclusion_unames;
+ struct match_list inclusion_gnames;
+};
+
+static int add_pattern_from_file(struct archive_match *,
+ struct match_list *, int, const void *, int);
+static int add_entry(struct archive_match *, int,
+ struct archive_entry *);
+static int add_owner_id(struct archive_match *, struct id_array *,
+ int64_t);
+static int add_owner_name(struct archive_match *, struct match_list *,
+ int, const void *);
+static int add_pattern_mbs(struct archive_match *, struct match_list *,
+ const char *);
+static int add_pattern_wcs(struct archive_match *, struct match_list *,
+ const wchar_t *);
+static int cmp_key_mbs(const struct archive_rb_node *, const void *);
+static int cmp_key_wcs(const struct archive_rb_node *, const void *);
+static int cmp_node_mbs(const struct archive_rb_node *,
+ const struct archive_rb_node *);
+static int cmp_node_wcs(const struct archive_rb_node *,
+ const struct archive_rb_node *);
+static void entry_list_add(struct entry_list *, struct match_file *);
+static void entry_list_free(struct entry_list *);
+static void entry_list_init(struct entry_list *);
+static int error_nomem(struct archive_match *);
+static void match_list_add(struct match_list *, struct match *);
+static void match_list_free(struct match_list *);
+static void match_list_init(struct match_list *);
+static int match_list_unmatched_inclusions_next(struct archive_match *,
+ struct match_list *, int, const void **);
+static int match_owner_id(struct id_array *, int64_t);
+#if !defined(_WIN32) || defined(__CYGWIN__)
+static int match_owner_name_mbs(struct archive_match *,
+ struct match_list *, const char *);
+#else
+static int match_owner_name_wcs(struct archive_match *,
+ struct match_list *, const wchar_t *);
+#endif
+static int match_path_exclusion(struct archive_match *,
+ struct match *, int, const void *);
+static int match_path_inclusion(struct archive_match *,
+ struct match *, int, const void *);
+static int owner_excluded(struct archive_match *,
+ struct archive_entry *);
+static int path_excluded(struct archive_match *, int, const void *);
+static int set_timefilter(struct archive_match *, int, time_t, long,
+ time_t, long);
+static int set_timefilter_pathname_mbs(struct archive_match *,
+ int, const char *);
+static int set_timefilter_pathname_wcs(struct archive_match *,
+ int, const wchar_t *);
+static int set_timefilter_date(struct archive_match *, int, const char *);
+static int set_timefilter_date_w(struct archive_match *, int,
+ const wchar_t *);
+static int time_excluded(struct archive_match *,
+ struct archive_entry *);
+static int validate_time_flag(struct archive *, int, const char *);
+
+time_t __archive_get_date(time_t now, const char *);
+#define get_date __archive_get_date
+
+static const struct archive_rb_tree_ops rb_ops_mbs = {
+ cmp_node_mbs, cmp_key_mbs
+};
+
+static const struct archive_rb_tree_ops rb_ops_wcs = {
+ cmp_node_wcs, cmp_key_wcs
+};
+
+/*
+ * The matching logic here needs to be re-thought. I started out to
+ * try to mimic gtar's matching logic, but it's not entirely
+ * consistent. In particular 'tar -t' and 'tar -x' interpret patterns
+ * on the command line as anchored, but --exclude doesn't.
+ */
+
+static int
+error_nomem(struct archive_match *a)
+{
+ archive_set_error(&(a->archive), ENOMEM, "No memory");
+ a->archive.state = ARCHIVE_STATE_FATAL;
+ return (ARCHIVE_FATAL);
+}
+
+/*
+ * Create an ARCHIVE_MATCH object.
+ */
+struct archive *
+archive_match_new(void)
+{
+ struct archive_match *a;
+
+ a = (struct archive_match *)calloc(1, sizeof(*a));
+ if (a == NULL)
+ return (NULL);
+ a->archive.magic = ARCHIVE_MATCH_MAGIC;
+ a->archive.state = ARCHIVE_STATE_NEW;
+ match_list_init(&(a->inclusions));
+ match_list_init(&(a->exclusions));
+ __archive_rb_tree_init(&(a->exclusion_tree), &rb_ops_mbs);
+ entry_list_init(&(a->exclusion_entry_list));
+ match_list_init(&(a->inclusion_unames));
+ match_list_init(&(a->inclusion_gnames));
+ time(&a->now);
+ return (&(a->archive));
+}
+
+/*
+ * Free an ARCHIVE_MATCH object.
+ */
+int
+archive_match_free(struct archive *_a)
+{
+ struct archive_match *a;
+
+ if (_a == NULL)
+ return (ARCHIVE_OK);
+ archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+ ARCHIVE_STATE_ANY | ARCHIVE_STATE_FATAL, "archive_match_free");
+ a = (struct archive_match *)_a;
+ match_list_free(&(a->inclusions));
+ match_list_free(&(a->exclusions));
+ entry_list_free(&(a->exclusion_entry_list));
+ free(a->inclusion_uids.ids);
+ free(a->inclusion_gids.ids);
+ match_list_free(&(a->inclusion_unames));
+ match_list_free(&(a->inclusion_gnames));
+ free(a);
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Convenience function to perform all exclusion tests.
+ *
+ * Returns 1 if archive entry is excluded.
+ * Returns 0 if archive entry is not excluded.
+ * Returns <0 if something error happened.
+ */
+int
+archive_match_excluded(struct archive *_a, struct archive_entry *entry)
+{
+ struct archive_match *a;
+ int r;
+
+ archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_match_excluded_ae");
+
+ a = (struct archive_match *)_a;
+ if (entry == NULL) {
+ archive_set_error(&(a->archive), EINVAL, "entry is NULL");
+ return (ARCHIVE_FAILED);
+ }
+
+ r = 0;
+ if (a->setflag & PATTERN_IS_SET) {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ r = path_excluded(a, 0, archive_entry_pathname_w(entry));
+#else
+ r = path_excluded(a, 1, archive_entry_pathname(entry));
+#endif
+ if (r != 0)
+ return (r);
+ }
+
+ if (a->setflag & TIME_IS_SET) {
+ r = time_excluded(a, entry);
+ if (r != 0)
+ return (r);
+ }
+
+ if (a->setflag & ID_IS_SET)
+ r = owner_excluded(a, entry);
+ return (r);
+}
+
+/*
+ * Utility functions to manage exclusion/inclusion patterns
+ */
+
+int
+archive_match_exclude_pattern(struct archive *_a, const char *pattern)
+{
+ struct archive_match *a;
+ int r;
+
+ archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_match_exclude_pattern");
+ a = (struct archive_match *)_a;
+
+ if (pattern == NULL || *pattern == '\0') {
+ archive_set_error(&(a->archive), EINVAL, "pattern is empty");
+ return (ARCHIVE_FAILED);
+ }
+ if ((r = add_pattern_mbs(a, &(a->exclusions), pattern)) != ARCHIVE_OK)
+ return (r);
+ return (ARCHIVE_OK);
+}
+
+int
+archive_match_exclude_pattern_w(struct archive *_a, const wchar_t *pattern)
+{
+ struct archive_match *a;
+ int r;
+
+ archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_w");
+ a = (struct archive_match *)_a;
+
+ if (pattern == NULL || *pattern == L'\0') {
+ archive_set_error(&(a->archive), EINVAL, "pattern is empty");
+ return (ARCHIVE_FAILED);
+ }
+ if ((r = add_pattern_wcs(a, &(a->exclusions), pattern)) != ARCHIVE_OK)
+ return (r);
+ return (ARCHIVE_OK);
+}
+
+int
+archive_match_exclude_pattern_from_file(struct archive *_a,
+ const char *pathname, int nullSeparator)
+{
+ struct archive_match *a;
+
+ archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_from_file");
+ a = (struct archive_match *)_a;
+
+ return add_pattern_from_file(a, &(a->exclusions), 1, pathname,
+ nullSeparator);
+}
+
+int
+archive_match_exclude_pattern_from_file_w(struct archive *_a,
+ const wchar_t *pathname, int nullSeparator)
+{
+ struct archive_match *a;
+
+ archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_match_exclude_pattern_from_file_w");
+ a = (struct archive_match *)_a;
+
+ return add_pattern_from_file(a, &(a->exclusions), 0, pathname,
+ nullSeparator);
+}
+
+int
+archive_match_include_pattern(struct archive *_a, const char *pattern)
+{
+ struct archive_match *a;
+ int r;
+
+ archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_match_include_pattern");
+ a = (struct archive_match *)_a;
+
+ if (pattern == NULL || *pattern == '\0') {
+ archive_set_error(&(a->archive), EINVAL, "pattern is empty");
+ return (ARCHIVE_FAILED);
+ }
+ if ((r = add_pattern_mbs(a, &(a->inclusions), pattern)) != ARCHIVE_OK)
+ return (r);
+ return (ARCHIVE_OK);
+}
+
+int
+archive_match_include_pattern_w(struct archive *_a, const wchar_t *pattern)
+{
+ struct archive_match *a;
+ int r;
+
+ archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_match_include_pattern_w");
+ a = (struct archive_match *)_a;
+
+ if (pattern == NULL || *pattern == L'\0') {
+ archive_set_error(&(a->archive), EINVAL, "pattern is empty");
+ return (ARCHIVE_FAILED);
+ }
+ if ((r = add_pattern_wcs(a, &(a->inclusions), pattern)) != ARCHIVE_OK)
+ return (r);
+ return (ARCHIVE_OK);
+}
+
+int
+archive_match_include_pattern_from_file(struct archive *_a,
+ const char *pathname, int nullSeparator)
+{
+ struct archive_match *a;
+
+ archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_match_include_pattern_from_file");
+ a = (struct archive_match *)_a;
+
+ return add_pattern_from_file(a, &(a->inclusions), 1, pathname,
+ nullSeparator);
+}
+
+int
+archive_match_include_pattern_from_file_w(struct archive *_a,
+ const wchar_t *pathname, int nullSeparator)
+{
+ struct archive_match *a;
+
+ archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_match_include_pattern_from_file_w");
+ a = (struct archive_match *)_a;
+
+ return add_pattern_from_file(a, &(a->inclusions), 0, pathname,
+ nullSeparator);
+}
+
+/*
+ * Test functions for pathname patterns.
+ *
+ * Returns 1 if archive entry is excluded.
+ * Returns 0 if archive entry is not excluded.
+ * Returns <0 if something error happened.
+ */
+int
+archive_match_path_excluded(struct archive *_a,
+ struct archive_entry *entry)
+{
+ struct archive_match *a;
+
+ archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_match_path_excluded");
+
+ a = (struct archive_match *)_a;
+ if (entry == NULL) {
+ archive_set_error(&(a->archive), EINVAL, "entry is NULL");
+ return (ARCHIVE_FAILED);
+ }
+
+ /* If we don't have exclusion/inclusion pattern set at all,
+ * the entry is always not excluded. */
+ if ((a->setflag & PATTERN_IS_SET) == 0)
+ return (0);
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ return (path_excluded(a, 0, archive_entry_pathname_w(entry)));
+#else
+ return (path_excluded(a, 1, archive_entry_pathname(entry)));
+#endif
+}
+
+/*
+ * Utilty functions to get statistic information for inclusion patterns.
+ */
+int
+archive_match_path_unmatched_inclusions(struct archive *_a)
+{
+ struct archive_match *a;
+
+ archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions");
+ a = (struct archive_match *)_a;
+
+ return (a->inclusions.unmatched_count);
+}
+
+int
+archive_match_path_unmatched_inclusions_next(struct archive *_a,
+ const char **_p)
+{
+ struct archive_match *a;
+ const void *v;
+ int r;
+
+ archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions_next");
+ a = (struct archive_match *)_a;
+
+ r = match_list_unmatched_inclusions_next(a, &(a->inclusions), 1, &v);
+ *_p = (const char *)v;
+ return (r);
+}
+
+int
+archive_match_path_unmatched_inclusions_next_w(struct archive *_a,
+ const wchar_t **_p)
+{
+ struct archive_match *a;
+ const void *v;
+ int r;
+
+ archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_match_unmatched_inclusions_next_w");
+ a = (struct archive_match *)_a;
+
+ r = match_list_unmatched_inclusions_next(a, &(a->inclusions), 0, &v);
+ *_p = (const wchar_t *)v;
+ return (r);
+}
+
+/*
+ * Add inclusion/exclusion patterns.
+ */
+static int
+add_pattern_mbs(struct archive_match *a, struct match_list *list,
+ const char *pattern)
+{
+ struct match *match;
+ size_t len;
+
+ match = calloc(1, sizeof(*match));
+ if (match == NULL)
+ return (error_nomem(a));
+ /* Both "foo/" and "foo" should match "foo/bar". */
+ len = strlen(pattern);
+ if (len && pattern[len - 1] == '/')
+ --len;
+ archive_mstring_copy_mbs_len(&(match->pattern), pattern, len);
+ match_list_add(list, match);
+ a->setflag |= PATTERN_IS_SET;
+ return (ARCHIVE_OK);
+}
+
+static int
+add_pattern_wcs(struct archive_match *a, struct match_list *list,
+ const wchar_t *pattern)
+{
+ struct match *match;
+ size_t len;
+
+ match = calloc(1, sizeof(*match));
+ if (match == NULL)
+ return (error_nomem(a));
+ /* Both "foo/" and "foo" should match "foo/bar". */
+ len = wcslen(pattern);
+ if (len && pattern[len - 1] == L'/')
+ --len;
+ archive_mstring_copy_wcs_len(&(match->pattern), pattern, len);
+ match_list_add(list, match);
+ a->setflag |= PATTERN_IS_SET;
+ return (ARCHIVE_OK);
+}
+
+static int
+add_pattern_from_file(struct archive_match *a, struct match_list *mlist,
+ int mbs, const void *pathname, int nullSeparator)
+{
+ struct archive *ar;
+ struct archive_entry *ae;
+ struct archive_string as;
+ const void *buff;
+ size_t size;
+ int64_t offset;
+ int r;
+
+ ar = archive_read_new();
+ if (ar == NULL) {
+ archive_set_error(&(a->archive), ENOMEM, "No memory");
+ return (ARCHIVE_FATAL);
+ }
+ r = archive_read_support_format_raw(ar);
+ if (r != ARCHIVE_OK) {
+ archive_copy_error(&(a->archive), ar);
+ archive_read_free(ar);
+ return (r);
+ }
+ if (mbs)
+ r = archive_read_open_filename(ar, pathname, 512*20);
+ else
+ r = archive_read_open_filename_w(ar, pathname, 512*20);
+ if (r != ARCHIVE_OK) {
+ archive_copy_error(&(a->archive), ar);
+ archive_read_free(ar);
+ return (r);
+ }
+ r = archive_read_next_header(ar, &ae);
+ if (r != ARCHIVE_OK) {
+ archive_copy_error(&(a->archive), ar);
+ archive_read_free(ar);
+ return (r);
+ }
+
+ archive_string_init(&as);
+
+ while ((r = archive_read_data_block(ar, &buff, &size, &offset))
+ == ARCHIVE_OK) {
+ const char *b = (const char *)buff;
+
+ while (size) {
+ const char *s = (const char *)b;
+ size_t length = 0;
+ int found_separator = 0;
+
+ while (length < size) {
+ if (nullSeparator) {
+ if (*b == '\0') {
+ found_separator = 1;
+ break;
+ }
+ } else {
+ if (*b == 0x0d || *b == 0x0a) {
+ found_separator = 1;
+ break;
+ }
+ }
+ b++;
+ length++;
+ }
+ if (!found_separator) {
+ archive_strncat(&as, s, length);
+ /* Read next data block. */
+ break;
+ }
+ b++;
+ size -= length + 1;
+ archive_strncat(&as, s, length);
+
+ /* If the line is not empty, add the pattern. */
+ if (archive_strlen(&as) > 0) {
+ /* Add pattern. */
+ r = add_pattern_mbs(a, mlist, as.s);
+ if (r != ARCHIVE_OK) {
+ archive_read_free(ar);
+ archive_string_free(&as);
+ return (r);
+ }
+ archive_string_empty(&as);
+ }
+ }
+ }
+
+ /* If something error happend, report it immediately. */
+ if (r < ARCHIVE_OK) {
+ archive_copy_error(&(a->archive), ar);
+ archive_read_free(ar);
+ archive_string_free(&as);
+ return (r);
+ }
+
+ /* If the line is not empty, add the pattern. */
+ if (r == ARCHIVE_EOF && archive_strlen(&as) > 0) {
+ /* Add pattern. */
+ r = add_pattern_mbs(a, mlist, as.s);
+ if (r != ARCHIVE_OK) {
+ archive_read_free(ar);
+ archive_string_free(&as);
+ return (r);
+ }
+ }
+ archive_read_free(ar);
+ archive_string_free(&as);
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Test if pathname is excluded by inclusion/exclusion patterns.
+ */
+static int
+path_excluded(struct archive_match *a, int mbs, const void *pathname)
+{
+ struct match *match;
+ struct match *matched;
+ int r;
+
+ if (a == NULL)
+ return (0);
+
+ /* Mark off any unmatched inclusions. */
+ /* In particular, if a filename does appear in the archive and
+ * is explicitly included and excluded, then we don't report
+ * it as missing even though we don't extract it.
+ */
+ matched = NULL;
+ for (match = a->inclusions.first; match != NULL;
+ match = match->next){
+ if (match->matches == 0 &&
+ (r = match_path_inclusion(a, match, mbs, pathname)) != 0) {
+ if (r < 0)
+ return (r);
+ a->inclusions.unmatched_count--;
+ match->matches++;
+ matched = match;
+ }
+ }
+
+ /* Exclusions take priority */
+ for (match = a->exclusions.first; match != NULL;
+ match = match->next){
+ r = match_path_exclusion(a, match, mbs, pathname);
+ if (r)
+ return (r);
+ }
+
+ /* It's not excluded and we found an inclusion above, so it's
+ * included. */
+ if (matched != NULL)
+ return (0);
+
+
+ /* We didn't find an unmatched inclusion, check the remaining ones. */
+ for (match = a->inclusions.first; match != NULL;
+ match = match->next){
+ /* We looked at previously-unmatched inclusions already. */
+ if (match->matches > 0 &&
+ (r = match_path_inclusion(a, match, mbs, pathname)) != 0) {
+ if (r < 0)
+ return (r);
+ match->matches++;
+ return (0);
+ }
+ }
+
+ /* If there were inclusions, default is to exclude. */
+ if (a->inclusions.first != NULL)
+ return (1);
+
+ /* No explicit inclusions, default is to match. */
+ return (0);
+}
+
+/*
+ * This is a little odd, but it matches the default behavior of
+ * gtar. In particular, 'a*b' will match 'foo/a1111/222b/bar'
+ *
+ */
+static int
+match_path_exclusion(struct archive_match *a, struct match *m,
+ int mbs, const void *pn)
+{
+ int flag = PATHMATCH_NO_ANCHOR_START | PATHMATCH_NO_ANCHOR_END;
+ int r;
+
+ if (mbs) {
+ const char *p;
+ r = archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p);
+ if (r == 0)
+ return (archive_pathmatch(p, (const char *)pn, flag));
+ } else {
+ const wchar_t *p;
+ r = archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p);
+ if (r == 0)
+ return (archive_pathmatch_w(p, (const wchar_t *)pn,
+ flag));
+ }
+ if (errno == ENOMEM)
+ return (error_nomem(a));
+ return (0);
+}
+
+/*
+ * Again, mimic gtar: inclusions are always anchored (have to match
+ * the beginning of the path) even though exclusions are not anchored.
+ */
+static int
+match_path_inclusion(struct archive_match *a, struct match *m,
+ int mbs, const void *pn)
+{
+ int flag = PATHMATCH_NO_ANCHOR_END;
+ int r;
+
+ if (mbs) {
+ const char *p;
+ r = archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p);
+ if (r == 0)
+ return (archive_pathmatch(p, (const char *)pn, flag));
+ } else {
+ const wchar_t *p;
+ r = archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p);
+ if (r == 0)
+ return (archive_pathmatch_w(p, (const wchar_t *)pn,
+ flag));
+ }
+ if (errno == ENOMEM)
+ return (error_nomem(a));
+ return (0);
+}
+
+static void
+match_list_init(struct match_list *list)
+{
+ list->first = NULL;
+ list->last = &(list->first);
+ list->count = 0;
+}
+
+static void
+match_list_free(struct match_list *list)
+{
+ struct match *p, *q;
+
+ for (p = list->first; p != NULL; ) {
+ q = p;
+ p = p->next;
+ archive_mstring_clean(&(q->pattern));
+ free(q);
+ }
+}
+
+static void
+match_list_add(struct match_list *list, struct match *m)
+{
+ *list->last = m;
+ list->last = &(m->next);
+ list->count++;
+ list->unmatched_count++;
+}
+
+static int
+match_list_unmatched_inclusions_next(struct archive_match *a,
+ struct match_list *list, int mbs, const void **vp)
+{
+ struct match *m;
+
+ *vp = NULL;
+ if (list->unmatched_eof) {
+ list->unmatched_eof = 0;
+ return (ARCHIVE_EOF);
+ }
+ if (list->unmatched_next == NULL) {
+ if (list->unmatched_count == 0)
+ return (ARCHIVE_EOF);
+ list->unmatched_next = list->first;
+ }
+
+ for (m = list->unmatched_next; m != NULL; m = m->next) {
+ int r;
+
+ if (m->matches)
+ continue;
+ if (mbs) {
+ const char *p;
+ r = archive_mstring_get_mbs(&(a->archive),
+ &(m->pattern), &p);
+ if (r < 0 && errno == ENOMEM)
+ return (error_nomem(a));
+ if (p == NULL)
+ p = "";
+ *vp = p;
+ } else {
+ const wchar_t *p;
+ r = archive_mstring_get_wcs(&(a->archive),
+ &(m->pattern), &p);
+ if (r < 0 && errno == ENOMEM)
+ return (error_nomem(a));
+ if (p == NULL)
+ p = L"";
+ *vp = p;
+ }
+ list->unmatched_next = m->next;
+ if (list->unmatched_next == NULL)
+ /* To return EOF next time. */
+ list->unmatched_eof = 1;
+ return (ARCHIVE_OK);
+ }
+ list->unmatched_next = NULL;
+ return (ARCHIVE_EOF);
+}
+
+/*
+ * Utility functions to manage inclusion timestamps.
+ */
+int
+archive_match_include_time(struct archive *_a, int flag, time_t sec,
+ long nsec)
+{
+ int r;
+
+ r = validate_time_flag(_a, flag, "archive_match_include_time");
+ if (r != ARCHIVE_OK)
+ return (r);
+ return set_timefilter((struct archive_match *)_a, flag,
+ sec, nsec, sec, nsec);
+}
+
+int
+archive_match_include_date(struct archive *_a, int flag,
+ const char *datestr)
+{
+ int r;
+
+ r = validate_time_flag(_a, flag, "archive_match_include_date");
+ if (r != ARCHIVE_OK)
+ return (r);
+ return set_timefilter_date((struct archive_match *)_a, flag, datestr);
+}
+
+int
+archive_match_include_date_w(struct archive *_a, int flag,
+ const wchar_t *datestr)
+{
+ int r;
+
+ r = validate_time_flag(_a, flag, "archive_match_include_date_w");
+ if (r != ARCHIVE_OK)
+ return (r);
+
+ return set_timefilter_date_w((struct archive_match *)_a, flag, datestr);
+}
+
+int
+archive_match_include_file_time(struct archive *_a, int flag,
+ const char *pathname)
+{
+ int r;
+
+ r = validate_time_flag(_a, flag, "archive_match_include_file_time");
+ if (r != ARCHIVE_OK)
+ return (r);
+ return set_timefilter_pathname_mbs((struct archive_match *)_a,
+ flag, pathname);
+}
+
+int
+archive_match_include_file_time_w(struct archive *_a, int flag,
+ const wchar_t *pathname)
+{
+ int r;
+
+ r = validate_time_flag(_a, flag, "archive_match_include_file_time_w");
+ if (r != ARCHIVE_OK)
+ return (r);
+ return set_timefilter_pathname_wcs((struct archive_match *)_a,
+ flag, pathname);
+}
+
+int
+archive_match_exclude_entry(struct archive *_a, int flag,
+ struct archive_entry *entry)
+{
+ struct archive_match *a;
+ int r;
+
+ archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_match_time_include_entry");
+ a = (struct archive_match *)_a;
+
+ if (entry == NULL) {
+ archive_set_error(&(a->archive), EINVAL, "entry is NULL");
+ return (ARCHIVE_FAILED);
+ }
+ r = validate_time_flag(_a, flag, "archive_match_exclude_entry");
+ if (r != ARCHIVE_OK)
+ return (r);
+ return (add_entry(a, flag, entry));
+}
+
+/*
+ * Test function for time stamps.
+ *
+ * Returns 1 if archive entry is excluded.
+ * Returns 0 if archive entry is not excluded.
+ * Returns <0 if something error happened.
+ */
+int
+archive_match_time_excluded(struct archive *_a,
+ struct archive_entry *entry)
+{
+ struct archive_match *a;
+
+ archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_match_time_excluded_ae");
+
+ a = (struct archive_match *)_a;
+ if (entry == NULL) {
+ archive_set_error(&(a->archive), EINVAL, "entry is NULL");
+ return (ARCHIVE_FAILED);
+ }
+
+ /* If we don't have inclusion time set at all, the entry is always
+ * not excluded. */
+ if ((a->setflag & TIME_IS_SET) == 0)
+ return (0);
+ return (time_excluded(a, entry));
+}
+
+static int
+validate_time_flag(struct archive *_a, int flag, const char *_fn)
+{
+ archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+ ARCHIVE_STATE_NEW, _fn);
+
+ /* Check a type of time. */
+ if (flag &
+ ((~(ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME)) & 0xff00)) {
+ archive_set_error(_a, EINVAL, "Invalid time flag");
+ return (ARCHIVE_FAILED);
+ }
+ if ((flag & (ARCHIVE_MATCH_MTIME | ARCHIVE_MATCH_CTIME)) == 0) {
+ archive_set_error(_a, EINVAL, "No time flag");
+ return (ARCHIVE_FAILED);
+ }
+
+ /* Check a type of comparison. */
+ if (flag &
+ ((~(ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER
+ | ARCHIVE_MATCH_EQUAL)) & 0x00ff)) {
+ archive_set_error(_a, EINVAL, "Invalid comparison flag");
+ return (ARCHIVE_FAILED);
+ }
+ if ((flag & (ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER
+ | ARCHIVE_MATCH_EQUAL)) == 0) {
+ archive_set_error(_a, EINVAL, "No comparison flag");
+ return (ARCHIVE_FAILED);
+ }
+
+ return (ARCHIVE_OK);
+}
+
+#define JUST_EQUAL(t) (((t) & (ARCHIVE_MATCH_EQUAL |\
+ ARCHIVE_MATCH_NEWER | ARCHIVE_MATCH_OLDER)) == ARCHIVE_MATCH_EQUAL)
+static int
+set_timefilter(struct archive_match *a, int timetype,
+ time_t mtime_sec, long mtime_nsec, time_t ctime_sec, long ctime_nsec)
+{
+ if (timetype & ARCHIVE_MATCH_MTIME) {
+ if ((timetype & ARCHIVE_MATCH_NEWER) || JUST_EQUAL(timetype)) {
+ a->newer_mtime_filter = timetype;
+ a->newer_mtime_sec = mtime_sec;
+ a->newer_mtime_nsec = mtime_nsec;
+ a->setflag |= TIME_IS_SET;
+ }
+ if ((timetype & ARCHIVE_MATCH_OLDER) || JUST_EQUAL(timetype)) {
+ a->older_mtime_filter = timetype;
+ a->older_mtime_sec = mtime_sec;
+ a->older_mtime_nsec = mtime_nsec;
+ a->setflag |= TIME_IS_SET;
+ }
+ }
+ if (timetype & ARCHIVE_MATCH_CTIME) {
+ if ((timetype & ARCHIVE_MATCH_NEWER) || JUST_EQUAL(timetype)) {
+ a->newer_ctime_filter = timetype;
+ a->newer_ctime_sec = ctime_sec;
+ a->newer_ctime_nsec = ctime_nsec;
+ a->setflag |= TIME_IS_SET;
+ }
+ if ((timetype & ARCHIVE_MATCH_OLDER) || JUST_EQUAL(timetype)) {
+ a->older_ctime_filter = timetype;
+ a->older_ctime_sec = ctime_sec;
+ a->older_ctime_nsec = ctime_nsec;
+ a->setflag |= TIME_IS_SET;
+ }
+ }
+ return (ARCHIVE_OK);
+}
+
+static int
+set_timefilter_date(struct archive_match *a, int timetype, const char *datestr)
+{
+ time_t t;
+
+ if (datestr == NULL || *datestr == '\0') {
+ archive_set_error(&(a->archive), EINVAL, "date is empty");
+ return (ARCHIVE_FAILED);
+ }
+ t = get_date(a->now, datestr);
+ if (t == (time_t)-1) {
+ archive_set_error(&(a->archive), EINVAL, "invalid date string");
+ return (ARCHIVE_FAILED);
+ }
+ return set_timefilter(a, timetype, t, 0, t, 0);
+}
+
+static int
+set_timefilter_date_w(struct archive_match *a, int timetype,
+ const wchar_t *datestr)
+{
+ struct archive_string as;
+ time_t t;
+
+ if (datestr == NULL || *datestr == L'\0') {
+ archive_set_error(&(a->archive), EINVAL, "date is empty");
+ return (ARCHIVE_FAILED);
+ }
+
+ archive_string_init(&as);
+ if (archive_string_append_from_wcs(&as, datestr, wcslen(datestr)) < 0) {
+ archive_string_free(&as);
+ if (errno == ENOMEM)
+ return (error_nomem(a));
+ archive_set_error(&(a->archive), -1,
+ "Failed to convert WCS to MBS");
+ return (ARCHIVE_FAILED);
+ }
+ t = get_date(a->now, as.s);
+ archive_string_free(&as);
+ if (t == (time_t)-1) {
+ archive_set_error(&(a->archive), EINVAL, "invalid date string");
+ return (ARCHIVE_FAILED);
+ }
+ return set_timefilter(a, timetype, t, 0, t, 0);
+}
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
+static int
+set_timefilter_find_data(struct archive_match *a, int timetype,
+ DWORD ftLastWriteTime_dwHighDateTime, DWORD ftLastWriteTime_dwLowDateTime,
+ DWORD ftCreationTime_dwHighDateTime, DWORD ftCreationTime_dwLowDateTime)
+{
+ ULARGE_INTEGER utc;
+ time_t ctime_sec, mtime_sec;
+ long ctime_ns, mtime_ns;
+
+ utc.HighPart = ftCreationTime_dwHighDateTime;
+ utc.LowPart = ftCreationTime_dwLowDateTime;
+ if (utc.QuadPart >= EPOC_TIME) {
+ utc.QuadPart -= EPOC_TIME;
+ ctime_sec = (time_t)(utc.QuadPart / 10000000);
+ ctime_ns = (long)(utc.QuadPart % 10000000) * 100;
+ } else {
+ ctime_sec = 0;
+ ctime_ns = 0;
+ }
+ utc.HighPart = ftLastWriteTime_dwHighDateTime;
+ utc.LowPart = ftLastWriteTime_dwLowDateTime;
+ if (utc.QuadPart >= EPOC_TIME) {
+ utc.QuadPart -= EPOC_TIME;
+ mtime_sec = (time_t)(utc.QuadPart / 10000000);
+ mtime_ns = (long)(utc.QuadPart % 10000000) * 100;
+ } else {
+ mtime_sec = 0;
+ mtime_ns = 0;
+ }
+ return set_timefilter(a, timetype,
+ mtime_sec, mtime_ns, ctime_sec, ctime_ns);
+}
+
+static int
+set_timefilter_pathname_mbs(struct archive_match *a, int timetype,
+ const char *path)
+{
+ /* NOTE: stat() on Windows cannot handle nano seconds. */
+ HANDLE h;
+ WIN32_FIND_DATA d;
+
+ if (path == NULL || *path == '\0') {
+ archive_set_error(&(a->archive), EINVAL, "pathname is empty");
+ return (ARCHIVE_FAILED);
+ }
+ h = FindFirstFileA(path, &d);
+ if (h == INVALID_HANDLE_VALUE) {
+ la_dosmaperr(GetLastError());
+ archive_set_error(&(a->archive), errno,
+ "Failed to FindFirstFileA");
+ return (ARCHIVE_FAILED);
+ }
+ FindClose(h);
+ return set_timefilter_find_data(a, timetype,
+ d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime,
+ d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime);
+}
+
+static int
+set_timefilter_pathname_wcs(struct archive_match *a, int timetype,
+ const wchar_t *path)
+{
+ HANDLE h;
+ WIN32_FIND_DATAW d;
+
+ if (path == NULL || *path == L'\0') {
+ archive_set_error(&(a->archive), EINVAL, "pathname is empty");
+ return (ARCHIVE_FAILED);
+ }
+ h = FindFirstFileW(path, &d);
+ if (h == INVALID_HANDLE_VALUE) {
+ la_dosmaperr(GetLastError());
+ archive_set_error(&(a->archive), errno,
+ "Failed to FindFirstFile");
+ return (ARCHIVE_FAILED);
+ }
+ FindClose(h);
+ return set_timefilter_find_data(a, timetype,
+ d.ftLastWriteTime.dwHighDateTime, d.ftLastWriteTime.dwLowDateTime,
+ d.ftCreationTime.dwHighDateTime, d.ftCreationTime.dwLowDateTime);
+}
+
+#else /* _WIN32 && !__CYGWIN__ */
+
+static int
+set_timefilter_stat(struct archive_match *a, int timetype, struct stat *st)
+{
+ struct archive_entry *ae;
+ time_t ctime_sec, mtime_sec;
+ long ctime_ns, mtime_ns;
+
+ ae = archive_entry_new();
+ if (ae == NULL)
+ return (error_nomem(a));
+ archive_entry_copy_stat(ae, st);
+ ctime_sec = archive_entry_ctime(ae);
+ ctime_ns = archive_entry_ctime_nsec(ae);
+ mtime_sec = archive_entry_mtime(ae);
+ mtime_ns = archive_entry_mtime_nsec(ae);
+ archive_entry_free(ae);
+ return set_timefilter(a, timetype, mtime_sec, mtime_ns,
+ ctime_sec, ctime_ns);
+}
+
+static int
+set_timefilter_pathname_mbs(struct archive_match *a, int timetype,
+ const char *path)
+{
+ struct stat st;
+
+ if (path == NULL || *path == '\0') {
+ archive_set_error(&(a->archive), EINVAL, "pathname is empty");
+ return (ARCHIVE_FAILED);
+ }
+ if (stat(path, &st) != 0) {
+ archive_set_error(&(a->archive), errno, "Failed to stat()");
+ return (ARCHIVE_FAILED);
+ }
+ return (set_timefilter_stat(a, timetype, &st));
+}
+
+static int
+set_timefilter_pathname_wcs(struct archive_match *a, int timetype,
+ const wchar_t *path)
+{
+ struct archive_string as;
+ int r;
+
+ if (path == NULL || *path == L'\0') {
+ archive_set_error(&(a->archive), EINVAL, "pathname is empty");
+ return (ARCHIVE_FAILED);
+ }
+
+ /* Convert WCS filename to MBS filename. */
+ archive_string_init(&as);
+ if (archive_string_append_from_wcs(&as, path, wcslen(path)) < 0) {
+ archive_string_free(&as);
+ if (errno == ENOMEM)
+ return (error_nomem(a));
+ archive_set_error(&(a->archive), -1,
+ "Failed to convert WCS to MBS");
+ return (ARCHIVE_FAILED);
+ }
+
+ r = set_timefilter_pathname_mbs(a, timetype, as.s);
+ archive_string_free(&as);
+
+ return (r);
+}
+#endif /* _WIN32 && !__CYGWIN__ */
+
+/*
+ * Call back funtions for archive_rb.
+ */
+static int
+cmp_node_mbs(const struct archive_rb_node *n1,
+ const struct archive_rb_node *n2)
+{
+ struct match_file *f1 = (struct match_file *)(uintptr_t)n1;
+ struct match_file *f2 = (struct match_file *)(uintptr_t)n2;
+ const char *p1, *p2;
+
+ archive_mstring_get_mbs(NULL, &(f1->pathname), &p1);
+ archive_mstring_get_mbs(NULL, &(f2->pathname), &p2);
+ if (p1 == NULL)
+ return (1);
+ if (p2 == NULL)
+ return (-1);
+ return (strcmp(p1, p2));
+}
+
+static int
+cmp_key_mbs(const struct archive_rb_node *n, const void *key)
+{
+ struct match_file *f = (struct match_file *)(uintptr_t)n;
+ const char *p;
+
+ archive_mstring_get_mbs(NULL, &(f->pathname), &p);
+ if (p == NULL)
+ return (-1);
+ return (strcmp(p, (const char *)key));
+}
+
+static int
+cmp_node_wcs(const struct archive_rb_node *n1,
+ const struct archive_rb_node *n2)
+{
+ struct match_file *f1 = (struct match_file *)(uintptr_t)n1;
+ struct match_file *f2 = (struct match_file *)(uintptr_t)n2;
+ const wchar_t *p1, *p2;
+
+ archive_mstring_get_wcs(NULL, &(f1->pathname), &p1);
+ archive_mstring_get_wcs(NULL, &(f2->pathname), &p2);
+ if (p1 == NULL)
+ return (1);
+ if (p2 == NULL)
+ return (-1);
+ return (wcscmp(p1, p2));
+}
+
+static int
+cmp_key_wcs(const struct archive_rb_node *n, const void *key)
+{
+ struct match_file *f = (struct match_file *)(uintptr_t)n;
+ const wchar_t *p;
+
+ archive_mstring_get_wcs(NULL, &(f->pathname), &p);
+ if (p == NULL)
+ return (-1);
+ return (wcscmp(p, (const wchar_t *)key));
+}
+
+static void
+entry_list_init(struct entry_list *list)
+{
+ list->first = NULL;
+ list->last = &(list->first);
+ list->count = 0;
+}
+
+static void
+entry_list_free(struct entry_list *list)
+{
+ struct match_file *p, *q;
+
+ for (p = list->first; p != NULL; ) {
+ q = p;
+ p = p->next;
+ archive_mstring_clean(&(q->pathname));
+ free(q);
+ }
+}
+
+static void
+entry_list_add(struct entry_list *list, struct match_file *file)
+{
+ *list->last = file;
+ list->last = &(file->next);
+ list->count++;
+}
+
+static int
+add_entry(struct archive_match *a, int flag,
+ struct archive_entry *entry)
+{
+ struct match_file *f;
+ const void *pathname;
+ int r;
+
+ f = calloc(1, sizeof(*f));
+ if (f == NULL)
+ return (error_nomem(a));
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ pathname = archive_entry_pathname_w(entry);
+ if (pathname == NULL) {
+ free(f);
+ archive_set_error(&(a->archive), EINVAL, "pathname is NULL");
+ return (ARCHIVE_FAILED);
+ }
+ archive_mstring_copy_wcs(&(f->pathname), pathname);
+ a->exclusion_tree.rbt_ops = &rb_ops_wcs;
+#else
+ pathname = archive_entry_pathname(entry);
+ if (pathname == NULL) {
+ free(f);
+ archive_set_error(&(a->archive), EINVAL, "pathname is NULL");
+ return (ARCHIVE_FAILED);
+ }
+ archive_mstring_copy_mbs(&(f->pathname), pathname);
+ a->exclusion_tree.rbt_ops = &rb_ops_mbs;
+#endif
+ f->flag = flag;
+ f->mtime_sec = archive_entry_mtime(entry);
+ f->mtime_nsec = archive_entry_mtime_nsec(entry);
+ f->ctime_sec = archive_entry_ctime(entry);
+ f->ctime_nsec = archive_entry_ctime_nsec(entry);
+ r = __archive_rb_tree_insert_node(&(a->exclusion_tree), &(f->node));
+ if (!r) {
+ struct match_file *f2;
+
+ /* Get the duplicated file. */
+ f2 = (struct match_file *)__archive_rb_tree_find_node(
+ &(a->exclusion_tree), pathname);
+
+ /*
+ * We always overwrite comparison condision.
+ * If you do not want to overwrite it, you should not
+ * call archive_match_exclude_entry(). We cannot know
+ * what behavior you really expect since overwriting
+ * condition might be different with the flag.
+ */
+ if (f2 != NULL) {
+ f2->flag = f->flag;
+ f2->mtime_sec = f->mtime_sec;
+ f2->mtime_nsec = f->mtime_nsec;
+ f2->ctime_sec = f->ctime_sec;
+ f2->ctime_nsec = f->ctime_nsec;
+ }
+ /* Release the duplicated file. */
+ archive_mstring_clean(&(f->pathname));
+ free(f);
+ return (ARCHIVE_OK);
+ }
+ entry_list_add(&(a->exclusion_entry_list), f);
+ a->setflag |= TIME_IS_SET;
+ return (ARCHIVE_OK);
+}
+
+/*
+ * Test if entry is excluded by its timestamp.
+ */
+static int
+time_excluded(struct archive_match *a, struct archive_entry *entry)
+{
+ struct match_file *f;
+ const void *pathname;
+ time_t sec;
+ long nsec;
+
+ /*
+ * If this file/dir is excluded by a time comparison, skip it.
+ */
+ if (a->newer_ctime_filter) {
+ /* If ctime is not set, use mtime instead. */
+ if (archive_entry_ctime_is_set(entry))
+ sec = archive_entry_ctime(entry);
+ else
+ sec = archive_entry_mtime(entry);
+ if (sec < a->newer_ctime_sec)
+ return (1); /* Too old, skip it. */
+ if (sec == a->newer_ctime_sec) {
+ if (archive_entry_ctime_is_set(entry))
+ nsec = archive_entry_ctime_nsec(entry);
+ else
+ nsec = archive_entry_mtime_nsec(entry);
+ if (nsec < a->newer_ctime_nsec)
+ return (1); /* Too old, skip it. */
+ if (nsec == a->newer_ctime_nsec &&
+ (a->newer_ctime_filter & ARCHIVE_MATCH_EQUAL)
+ == 0)
+ return (1); /* Equal, skip it. */
+ }
+ }
+ if (a->older_ctime_filter) {
+ /* If ctime is not set, use mtime instead. */
+ if (archive_entry_ctime_is_set(entry))
+ sec = archive_entry_ctime(entry);
+ else
+ sec = archive_entry_mtime(entry);
+ if (sec > a->older_ctime_sec)
+ return (1); /* Too new, skip it. */
+ if (sec == a->older_ctime_sec) {
+ if (archive_entry_ctime_is_set(entry))
+ nsec = archive_entry_ctime_nsec(entry);
+ else
+ nsec = archive_entry_mtime_nsec(entry);
+ if (nsec > a->older_ctime_nsec)
+ return (1); /* Too new, skip it. */
+ if (nsec == a->older_ctime_nsec &&
+ (a->older_ctime_filter & ARCHIVE_MATCH_EQUAL)
+ == 0)
+ return (1); /* Eeual, skip it. */
+ }
+ }
+ if (a->newer_mtime_filter) {
+ sec = archive_entry_mtime(entry);
+ if (sec < a->newer_mtime_sec)
+ return (1); /* Too old, skip it. */
+ if (sec == a->newer_mtime_sec) {
+ nsec = archive_entry_mtime_nsec(entry);
+ if (nsec < a->newer_mtime_nsec)
+ return (1); /* Too old, skip it. */
+ if (nsec == a->newer_mtime_nsec &&
+ (a->newer_mtime_filter & ARCHIVE_MATCH_EQUAL)
+ == 0)
+ return (1); /* Equal, skip it. */
+ }
+ }
+ if (a->older_mtime_filter) {
+ sec = archive_entry_mtime(entry);
+ if (sec > a->older_mtime_sec)
+ return (1); /* Too new, skip it. */
+ nsec = archive_entry_mtime_nsec(entry);
+ if (sec == a->older_mtime_sec) {
+ if (nsec > a->older_mtime_nsec)
+ return (1); /* Too new, skip it. */
+ if (nsec == a->older_mtime_nsec &&
+ (a->older_mtime_filter & ARCHIVE_MATCH_EQUAL)
+ == 0)
+ return (1); /* Equal, skip it. */
+ }
+ }
+
+ /* If there is no excluson list, include the file. */
+ if (a->exclusion_entry_list.count == 0)
+ return (0);
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ pathname = archive_entry_pathname_w(entry);
+ a->exclusion_tree.rbt_ops = &rb_ops_wcs;
+#else
+ pathname = archive_entry_pathname(entry);
+ a->exclusion_tree.rbt_ops = &rb_ops_mbs;
+#endif
+ if (pathname == NULL)
+ return (0);
+
+ f = (struct match_file *)__archive_rb_tree_find_node(
+ &(a->exclusion_tree), pathname);
+ /* If the file wasn't rejected, include it. */
+ if (f == NULL)
+ return (0);
+
+ if (f->flag & ARCHIVE_MATCH_CTIME) {
+ sec = archive_entry_ctime(entry);
+ if (f->ctime_sec > sec) {
+ if (f->flag & ARCHIVE_MATCH_OLDER)
+ return (1);
+ } else if (f->ctime_sec < sec) {
+ if (f->flag & ARCHIVE_MATCH_NEWER)
+ return (1);
+ } else {
+ nsec = archive_entry_ctime_nsec(entry);
+ if (f->ctime_nsec > nsec) {
+ if (f->flag & ARCHIVE_MATCH_OLDER)
+ return (1);
+ } else if (f->ctime_nsec < nsec) {
+ if (f->flag & ARCHIVE_MATCH_NEWER)
+ return (1);
+ } else if (f->flag & ARCHIVE_MATCH_EQUAL)
+ return (1);
+ }
+ }
+ if (f->flag & ARCHIVE_MATCH_MTIME) {
+ sec = archive_entry_mtime(entry);
+ if (f->mtime_sec > sec) {
+ if (f->flag & ARCHIVE_MATCH_OLDER)
+ return (1);
+ } else if (f->mtime_sec < sec) {
+ if (f->flag & ARCHIVE_MATCH_NEWER)
+ return (1);
+ } else {
+ nsec = archive_entry_mtime_nsec(entry);
+ if (f->mtime_nsec > nsec) {
+ if (f->flag & ARCHIVE_MATCH_OLDER)
+ return (1);
+ } else if (f->mtime_nsec < nsec) {
+ if (f->flag & ARCHIVE_MATCH_NEWER)
+ return (1);
+ } else if (f->flag & ARCHIVE_MATCH_EQUAL)
+ return (1);
+ }
+ }
+ return (0);
+}
+
+/*
+ * Utility functions to manage inclusion owners
+ */
+
+int
+archive_match_include_uid(struct archive *_a, int64_t uid)
+{
+ struct archive_match *a;
+
+ archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_match_include_uid");
+ a = (struct archive_match *)_a;
+ return (add_owner_id(a, &(a->inclusion_uids), uid));
+}
+
+int
+archive_match_include_gid(struct archive *_a, int64_t gid)
+{
+ struct archive_match *a;
+
+ archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_match_include_gid");
+ a = (struct archive_match *)_a;
+ return (add_owner_id(a, &(a->inclusion_gids), gid));
+}
+
+int
+archive_match_include_uname(struct archive *_a, const char *uname)
+{
+ struct archive_match *a;
+
+ archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_match_include_uname");
+ a = (struct archive_match *)_a;
+ return (add_owner_name(a, &(a->inclusion_unames), 1, uname));
+}
+
+int
+archive_match_include_uname_w(struct archive *_a, const wchar_t *uname)
+{
+ struct archive_match *a;
+
+ archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_match_include_uname_w");
+ a = (struct archive_match *)_a;
+ return (add_owner_name(a, &(a->inclusion_unames), 0, uname));
+}
+
+int
+archive_match_include_gname(struct archive *_a, const char *gname)
+{
+ struct archive_match *a;
+
+ archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_match_include_gname");
+ a = (struct archive_match *)_a;
+ return (add_owner_name(a, &(a->inclusion_gnames), 1, gname));
+}
+
+int
+archive_match_include_gname_w(struct archive *_a, const wchar_t *gname)
+{
+ struct archive_match *a;
+
+ archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_match_include_gname_w");
+ a = (struct archive_match *)_a;
+ return (add_owner_name(a, &(a->inclusion_gnames), 0, gname));
+}
+
+/*
+ * Test function for owner(uid, gid, uname, gname).
+ *
+ * Returns 1 if archive entry is excluded.
+ * Returns 0 if archive entry is not excluded.
+ * Returns <0 if something error happened.
+ */
+int
+archive_match_owner_excluded(struct archive *_a,
+ struct archive_entry *entry)
+{
+ struct archive_match *a;
+
+ archive_check_magic(_a, ARCHIVE_MATCH_MAGIC,
+ ARCHIVE_STATE_NEW, "archive_match_id_excluded_ae");
+
+ a = (struct archive_match *)_a;
+ if (entry == NULL) {
+ archive_set_error(&(a->archive), EINVAL, "entry is NULL");
+ return (ARCHIVE_FAILED);
+ }
+
+ /* If we don't have inclusion id set at all, the entry is always
+ * not excluded. */
+ if ((a->setflag & ID_IS_SET) == 0)
+ return (0);
+ return (owner_excluded(a, entry));
+}
+
+static int
+add_owner_id(struct archive_match *a, struct id_array *ids, int64_t id)
+{
+ unsigned i;
+
+ if (ids->count + 1 >= ids->size) {
+ if (ids->size == 0)
+ ids->size = 8;
+ else
+ ids->size *= 2;
+ ids->ids = realloc(ids->ids, sizeof(*ids->ids) * ids->size);
+ if (ids->ids == NULL)
+ return (error_nomem(a));
+ }
+
+ /* Find an insert point. */
+ for (i = 0; i < ids->count; i++) {
+ if (ids->ids[i] >= id)
+ break;
+ }
+
+ /* Add oowner id. */
+ if (i == ids->count)
+ ids->ids[ids->count++] = id;
+ else if (ids->ids[i] != id) {
+ memmove(&(ids->ids[i+1]), &(ids->ids[i]),
+ (ids->count - i) * sizeof(ids->ids[0]));
+ ids->ids[i] = id;
+ ids->count++;
+ }
+ a->setflag |= ID_IS_SET;
+ return (ARCHIVE_OK);
+}
+
+static int
+match_owner_id(struct id_array *ids, int64_t id)
+{
+ unsigned b, m, t;
+
+ t = 0;
+ b = ids->count;
+ while (t < b) {
+ m = (t + b)>>1;
+ if (ids->ids[m] == id)
+ return (1);
+ if (ids->ids[m] < id)
+ t = m + 1;
+ else
+ b = m;
+ }
+ return (0);
+}
+
+static int
+add_owner_name(struct archive_match *a, struct match_list *list,
+ int mbs, const void *name)
+{
+ struct match *match;
+
+ match = calloc(1, sizeof(*match));
+ if (match == NULL)
+ return (error_nomem(a));
+ if (mbs)
+ archive_mstring_copy_mbs(&(match->pattern), name);
+ else
+ archive_mstring_copy_wcs(&(match->pattern), name);
+ match_list_add(list, match);
+ a->setflag |= ID_IS_SET;
+ return (ARCHIVE_OK);
+}
+
+#if !defined(_WIN32) || defined(__CYGWIN__)
+static int
+match_owner_name_mbs(struct archive_match *a, struct match_list *list,
+ const char *name)
+{
+ struct match *m;
+ const char *p;
+
+ if (name == NULL || *name == '\0')
+ return (0);
+ for (m = list->first; m; m = m->next) {
+ if (archive_mstring_get_mbs(&(a->archive), &(m->pattern), &p)
+ < 0 && errno == ENOMEM)
+ return (error_nomem(a));
+ if (p != NULL && strcmp(p, name) == 0) {
+ m->matches++;
+ return (1);
+ }
+ }
+ return (0);
+}
+#else
+static int
+match_owner_name_wcs(struct archive_match *a, struct match_list *list,
+ const wchar_t *name)
+{
+ struct match *m;
+ const wchar_t *p;
+
+ if (name == NULL || *name == L'\0')
+ return (0);
+ for (m = list->first; m; m = m->next) {
+ if (archive_mstring_get_wcs(&(a->archive), &(m->pattern), &p)
+ < 0 && errno == ENOMEM)
+ return (error_nomem(a));
+ if (p != NULL && wcscmp(p, name) == 0) {
+ m->matches++;
+ return (1);
+ }
+ }
+ return (0);
+}
+#endif
+
+/*
+ * Test if entry is excluded by uid, gid, uname or gname.
+ */
+static int
+owner_excluded(struct archive_match *a, struct archive_entry *entry)
+{
+ int r;
+
+ if (a->inclusion_uids.count) {
+ if (!match_owner_id(&(a->inclusion_uids),
+ archive_entry_uid(entry)))
+ return (1);
+ }
+
+ if (a->inclusion_gids.count) {
+ if (!match_owner_id(&(a->inclusion_gids),
+ archive_entry_gid(entry)))
+ return (1);
+ }
+
+ if (a->inclusion_unames.count) {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ r = match_owner_name_wcs(a, &(a->inclusion_unames),
+ archive_entry_uname_w(entry));
+#else
+ r = match_owner_name_mbs(a, &(a->inclusion_unames),
+ archive_entry_uname(entry));
+#endif
+ if (!r)
+ return (1);
+ else if (r < 0)
+ return (r);
+ }
+
+ if (a->inclusion_gnames.count) {
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ r = match_owner_name_wcs(a, &(a->inclusion_gnames),
+ archive_entry_gname_w(entry));
+#else
+ r = match_owner_name_mbs(a, &(a->inclusion_gnames),
+ archive_entry_gname(entry));
+#endif
+ if (!r)
+ return (1);
+ else if (r < 0)
+ return (r);
+ }
+ return (0);
+}
+
int magic, const char *fn, option_handler use_option)
{
const char *mp, *op, *vp;
+ int r;
archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn);
if (op == NULL && vp == NULL)
return (ARCHIVE_OK);
- if (op == NULL)
+ if (op == NULL) {
+ archive_set_error(a, ARCHIVE_ERRNO_MISC, "Empty option");
return (ARCHIVE_FAILED);
+ }
- return use_option(a, mp, op, vp);
+ r = use_option(a, mp, op, vp);
+ if (r == ARCHIVE_WARN - 1) {
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Unknown module name: `%s'", mp);
+ return (ARCHIVE_FAILED);
+ }
+ if (r == ARCHIVE_WARN) {
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Undefined option: `%s%s%s%s%s%s'",
+ vp?"":"!", mp?mp:"", mp?":":"", op, vp?"=":"", vp?vp:"");
+ return (ARCHIVE_FAILED);
+ }
+ return (r);
}
int
free(data);
return (ARCHIVE_FATAL);
}
+ if (r == ARCHIVE_FAILED && mod != NULL) {
+ free(data);
+ return (ARCHIVE_FAILED);
+ }
+ if (r == ARCHIVE_WARN - 1) {
+ /* The module name is wrong. */
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Unknown module name: `%s'", mod);
+ free(data);
+ return (ARCHIVE_FAILED);
+ }
+ if (r == ARCHIVE_WARN) {
+ /* The option name is wrong. No-one used this. */
+ archive_set_error(a, ARCHIVE_ERRNO_MISC,
+ "Undefined option: `%s%s%s'",
+ mod?mod:"", mod?":":"", opt);
+ free(data);
+ return (ARCHIVE_FAILED);
+ }
if (r == ARCHIVE_OK)
anyok = 1;
else
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include "lafe_platform.h"
+#include "archive_platform.h"
__FBSDID("$FreeBSD$");
#ifdef HAVE_STRING_H
#include <string.h>
#endif
+#ifdef HAVE_WCHAR_H
+#include <wchar.h>
+#endif
-#include "pathmatch.h"
+#include "archive_pathmatch.h"
/*
* Check whether a character 'c' is matched by a list specification [...]:
return (nomatch);
}
+static int
+pm_list_w(const wchar_t *start, const wchar_t *end, const wchar_t c, int flags)
+{
+ const wchar_t *p = start;
+ wchar_t rangeStart = L'\0', nextRangeStart;
+ int match = 1, nomatch = 0;
+
+ /* This will be used soon... */
+ (void)flags; /* UNUSED */
+
+ /* If this is a negated class, return success for nomatch. */
+ if ((*p == L'!' || *p == L'^') && p < end) {
+ match = 0;
+ nomatch = 1;
+ ++p;
+ }
+
+ while (p < end) {
+ nextRangeStart = L'\0';
+ switch (*p) {
+ case L'-':
+ /* Trailing or initial '-' is not special. */
+ if ((rangeStart == L'\0') || (p == end - 1)) {
+ if (*p == c)
+ return (match);
+ } else {
+ wchar_t rangeEnd = *++p;
+ if (rangeEnd == L'\\')
+ rangeEnd = *++p;
+ if ((rangeStart <= c) && (c <= rangeEnd))
+ return (match);
+ }
+ break;
+ case L'\\':
+ ++p;
+ /* Fall through */
+ default:
+ if (*p == c)
+ return (match);
+ nextRangeStart = *p; /* Possible start of range. */
+ }
+ rangeStart = nextRangeStart;
+ ++p;
+ }
+ return (nomatch);
+}
+
/*
* If s is pointing to "./", ".//", "./././" or the like, skip it.
*/
return (s);
}
+static const wchar_t *
+pm_slashskip_w(const wchar_t *s) {
+ while ((*s == L'/')
+ || (s[0] == L'.' && s[1] == L'/')
+ || (s[0] == L'.' && s[1] == L'\0'))
+ ++s;
+ return (s);
+}
+
static int
pm(const char *p, const char *s, int flags)
{
if (*p == '\0')
return (1);
while (*s) {
- if (lafe_pathmatch(p, s, flags))
+ if (archive_pathmatch(p, s, flags))
return (1);
++s;
}
}
}
+static int
+pm_w(const wchar_t *p, const wchar_t *s, int flags)
+{
+ const wchar_t *end;
+
+ /*
+ * Ignore leading './', './/', '././', etc.
+ */
+ if (s[0] == L'.' && s[1] == L'/')
+ s = pm_slashskip_w(s + 1);
+ if (p[0] == L'.' && p[1] == L'/')
+ p = pm_slashskip_w(p + 1);
+
+ for (;;) {
+ switch (*p) {
+ case L'\0':
+ if (s[0] == L'/') {
+ if (flags & PATHMATCH_NO_ANCHOR_END)
+ return (1);
+ /* "dir" == "dir/" == "dir/." */
+ s = pm_slashskip_w(s);
+ }
+ return (*s == L'\0');
+ case L'?':
+ /* ? always succeeds, unless we hit end of 's' */
+ if (*s == L'\0')
+ return (0);
+ break;
+ case L'*':
+ /* "*" == "**" == "***" ... */
+ while (*p == L'*')
+ ++p;
+ /* Trailing '*' always succeeds. */
+ if (*p == L'\0')
+ return (1);
+ while (*s) {
+ if (archive_pathmatch_w(p, s, flags))
+ return (1);
+ ++s;
+ }
+ return (0);
+ case L'[':
+ /*
+ * Find the end of the [...] character class,
+ * ignoring \] that might occur within the class.
+ */
+ end = p + 1;
+ while (*end != L'\0' && *end != L']') {
+ if (*end == L'\\' && end[1] != L'\0')
+ ++end;
+ ++end;
+ }
+ if (*end == L']') {
+ /* We found [...], try to match it. */
+ if (!pm_list_w(p + 1, end, *s, flags))
+ return (0);
+ p = end; /* Jump to trailing ']' char. */
+ break;
+ } else
+ /* No final ']', so just match '['. */
+ if (*p != *s)
+ return (0);
+ break;
+ case L'\\':
+ /* Trailing '\\' matches itself. */
+ if (p[1] == L'\0') {
+ if (*s != L'\\')
+ return (0);
+ } else {
+ ++p;
+ if (*p != *s)
+ return (0);
+ }
+ break;
+ case L'/':
+ if (*s != L'/' && *s != L'\0')
+ return (0);
+ /* Note: pattern "/\./" won't match "/";
+ * pm_slashskip() correctly stops at backslash. */
+ p = pm_slashskip_w(p);
+ s = pm_slashskip_w(s);
+ if (*p == L'\0' && (flags & PATHMATCH_NO_ANCHOR_END))
+ return (1);
+ --p; /* Counteract the increment below. */
+ --s;
+ break;
+ case L'$':
+ /* '$' is special only at end of pattern and only
+ * if PATHMATCH_NO_ANCHOR_END is specified. */
+ if (p[1] == L'\0' && (flags & PATHMATCH_NO_ANCHOR_END)){
+ /* "dir" == "dir/" == "dir/." */
+ return (*pm_slashskip_w(s) == L'\0');
+ }
+ /* Otherwise, '$' is not special. */
+ /* FALL THROUGH */
+ default:
+ if (*p != *s)
+ return (0);
+ break;
+ }
+ ++p;
+ ++s;
+ }
+}
+
/* Main entry point. */
int
-lafe_pathmatch(const char *p, const char *s, int flags)
+__archive_pathmatch(const char *p, const char *s, int flags)
{
/* Empty pattern only matches the empty string. */
if (p == NULL || *p == '\0')
/* Default: Match from beginning. */
return (pm(p, s, flags));
}
+
+int
+__archive_pathmatch_w(const wchar_t *p, const wchar_t *s, int flags)
+{
+ /* Empty pattern only matches the empty string. */
+ if (p == NULL || *p == L'\0')
+ return (s == NULL || *s == L'\0');
+
+ /* Leading '^' anchors the start of the pattern. */
+ if (*p == L'^') {
+ ++p;
+ flags &= ~PATHMATCH_NO_ANCHOR_START;
+ }
+
+ if (*p == L'/' && *s != L'/')
+ return (0);
+
+ /* Certain patterns and file names anchor implicitly. */
+ if (*p == L'*' || *p == L'/' || *p == L'/') {
+ while (*p == L'/')
+ ++p;
+ while (*s == L'/')
+ ++s;
+ return (pm_w(p, s, flags));
+ }
+
+ /* If start is unanchored, try to match start of each path element. */
+ if (flags & PATHMATCH_NO_ANCHOR_START) {
+ for ( ; s != NULL; s = wcschr(s, L'/')) {
+ if (*s == L'/')
+ s++;
+ if (pm_w(p, s, flags))
+ return (1);
+ }
+ return (0);
+ }
+
+ /* Default: Match from beginning. */
+ return (pm_w(p, s, flags));
+}
* $FreeBSD$
*/
-#ifndef LAFE_PATHMATCH_H
-#define LAFE_PATHMATCH_H
+#ifndef __LIBARCHIVE_BUILD
+#ifndef __LIBARCHIVE_TEST
+#error This header is only to be used internally to libarchive.
+#endif
+#endif
+
+#ifndef ARCHIVE_PATHMATCH_H
+#define ARCHIVE_PATHMATCH_H
/* Don't anchor at beginning unless the pattern starts with "^" */
#define PATHMATCH_NO_ANCHOR_START 1
/* Note that "^" and "$" are not special unless you set the corresponding
* flag above. */
-int lafe_pathmatch(const char *p, const char *s, int flags);
+int __archive_pathmatch(const char *p, const char *s, int flags);
+int __archive_pathmatch_w(const wchar_t *p, const wchar_t *s, int flags);
+
+#define archive_pathmatch(p, s, f) __archive_pathmatch(p, s, f)
+#define archive_pathmatch_w(p, s, f) __archive_pathmatch_w(p, s, f)
#endif
upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((2 * cf + 3 * s0 - 1) / (2 * s0))));
}
- do
+ while (numPs != 0)
{
/* Create Child */
CTX_PTR c1; /* = AllocContext(p); */
SetSuccessor(ps[--numPs], REF(c1));
c = c1;
}
- while (numPs != 0);
return c;
}
if(p->Range >= p->Bottom)
break;
else
- p->Range = -p->Low & (p->Bottom - 1);
+ p->Range = ((uint32_t)(-(int32_t)p->Low)) & (p->Bottom - 1);
}
p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream);
p->Range <<= 8;
CPpmd_Byte_Ref;
#define PPMD_SetAllBitsIn256Bytes(p) \
- { unsigned i; for (i = 0; i < 256 / sizeof(p[0]); i += 8) { \
- p[i+7] = p[i+6] = p[i+5] = p[i+4] = p[i+3] = p[i+2] = p[i+1] = p[i+0] = ~(size_t)0; }}
+ { unsigned j; for (j = 0; j < 256 / sizeof(p[0]); j += 8) { \
+ p[j+7] = p[j+6] = p[j+5] = p[j+4] = p[j+3] = p[j+2] = p[j+1] = p[j+0] = ~(size_t)0; }}
#endif
#define ARCHIVE_READ_MAGIC (0xdeb0c5U)
#define ARCHIVE_WRITE_DISK_MAGIC (0xc001b0c5U)
#define ARCHIVE_READ_DISK_MAGIC (0xbadb0c5U)
+#define ARCHIVE_MATCH_MAGIC (0xcad11c9U)
#define ARCHIVE_STATE_NEW 1U
#define ARCHIVE_STATE_HEADER 2U
const struct archive_rb_tree_ops *ops)
{
rbt->rbt_ops = ops;
- *((const struct archive_rb_node **)&rbt->rbt_root) = RB_SENTINEL_NODE;
+ *((struct archive_rb_node **)&rbt->rbt_root) = RB_SENTINEL_NODE;
}
struct archive_rb_node *
*/
if (RB_SENTINEL_P(self->rb_nodes[direction])) {
while (!RB_ROOT_P(rbt, self)) {
- if (other == RB_POSITION(self))
+ if (other == (unsigned int)RB_POSITION(self))
return RB_FATHER(self);
self = RB_FATHER(self);
}
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" $FreeBSD: head/lib/libarchive/archive_read.3 191595 2009-04-27 20:13:13Z kientzle $
+.\" $FreeBSD$
.\"
-.Dd March 23, 2011
+.Dd February 2, 2012
.Dt ARCHIVE_READ 3
.Os
.Sh NAME
.Nm archive_read
.Nd functions for reading streaming archives
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
.Sh SYNOPSIS
.In archive.h
.Sh DESCRIPTION
request -= get;
total += get;
}
- return total;
} else if (self->archive->client.seeker != NULL
&& request > 64 * 1024) {
/* If the client provided a seeker but not a skipper,
}
/* Compute the amount of zero padding needed. */
- if (a->read_data_output_offset + s <
+ if (a->read_data_output_offset + (int64_t)s <
a->read_data_offset) {
len = s;
} else if (a->read_data_output_offset <
a->read_data_offset) {
- len = a->read_data_offset -
- a->read_data_output_offset;
+ len = (size_t)(a->read_data_offset -
+ a->read_data_output_offset);
} else
len = 0;
/* Use up the copy buffer first. */
if (filter->avail > 0) {
- min = minimum(request, (int64_t)filter->avail);
+ min = (size_t)minimum(request, (int64_t)filter->avail);
filter->next += min;
filter->avail -= min;
request -= min;
/* Then use up the client buffer. */
if (filter->client_avail > 0) {
- min = minimum(request, (int64_t)filter->client_avail);
+ min = (size_t)minimum(request, (int64_t)filter->client_avail);
filter->client_next += min;
filter->client_avail -= min;
request -= min;
if (bytes_read >= request) {
filter->client_next =
((const char *)filter->client_buff) + request;
- filter->client_avail = bytes_read - request;
+ filter->client_avail = (size_t)(bytes_read - request);
filter->client_total = bytes_read;
total_bytes_skipped += request;
filter->position += request;
}
while (target_offset > actual_offset) {
to_write = nulls_size;
- if (target_offset < actual_offset + nulls_size)
+ if (target_offset < actual_offset + (int64_t)nulls_size)
to_write = (size_t)(target_offset - actual_offset);
bytes_written = write(fd, nulls, to_write);
if (bytes_written < 0) {
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
.\" SUCH DAMAGE.
.\"
-.\" $FreeBSD: head/lib/libarchive/archive_read_disk.3 190957 2009-04-12 05:04:02Z kientzle $
+.\" $FreeBSD$
.\"
-.Dd March 10, 2009
+.Dd February 2, 2012
.Dt ARCHIVE_READ_DISK 3
.Os
.Sh NAME
.Nm archive_read_finish ,
.Nm archive_read_free
.Nd functions for reading objects from disk
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
.Sh SYNOPSIS
.In archive.h
.Ft struct archive *
/*-
* Copyright (c) 2003-2009 Tim Kientzle
- * Copyright (c) 2010 Michihiro NAKAJIMA
+ * Copyright (c) 2010-2012 Michihiro NAKAJIMA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
+#ifdef HAVE_LINUX_TYPES_H
+#include <linux/types.h>
+#endif
#ifdef HAVE_LINUX_FIEMAP_H
#include <linux/fiemap.h>
#endif
#endif
static int setup_acls_posix1e(struct archive_read_disk *,
- struct archive_entry *, int fd);
+ struct archive_entry *, int *fd);
static int setup_mac_metadata(struct archive_read_disk *,
- struct archive_entry *, int fd);
+ struct archive_entry *, int *fd);
static int setup_xattrs(struct archive_read_disk *,
- struct archive_entry *, int fd);
+ struct archive_entry *, int *fd);
static int setup_sparse(struct archive_read_disk *,
- struct archive_entry *, int fd);
+ struct archive_entry *, int *fd);
int
archive_read_disk_entry_from_file(struct archive *_a,
st = &s;
}
archive_entry_copy_stat(entry, st);
+ /* Lookup uname/gname */
+ name = archive_read_disk_uname(_a, archive_entry_uid(entry));
+ if (name != NULL)
+ archive_entry_copy_uname(entry, name);
+ name = archive_read_disk_gname(_a, archive_entry_gid(entry));
+ if (name != NULL)
+ archive_entry_copy_gname(entry, name);
}
- /* Lookup uname/gname */
- name = archive_read_disk_uname(_a, archive_entry_uid(entry));
- if (name != NULL)
- archive_entry_copy_uname(entry, name);
- name = archive_read_disk_gname(_a, archive_entry_gid(entry));
- if (name != NULL)
- archive_entry_copy_gname(entry, name);
-
#ifdef HAVE_STRUCT_STAT_ST_FLAGS
/* On FreeBSD, we get flags for free with the stat. */
/* TODO: Does this belong in copy_stat()? */
* this is an extra step, it has a nice side-effect: We get an
* open file descriptor which we can use in the subsequent lookups. */
if ((S_ISREG(st->st_mode) || S_ISDIR(st->st_mode))) {
- if (fd < 0)
- fd = open(path, O_RDONLY | O_NONBLOCK);
+ if (fd < 0) {
+ if (a->tree != NULL)
+ fd = a->open_on_current_dir(a->tree, path,
+ O_RDONLY | O_NONBLOCK);
+ else
+ fd = open(path, O_RDONLY | O_NONBLOCK);
+ }
if (fd >= 0) {
unsigned long stflags;
- int r = ioctl(fd, EXT2_IOC_GETFLAGS, &stflags);
+ r = ioctl(fd, EXT2_IOC_GETFLAGS, &stflags);
if (r == 0 && stflags != 0)
archive_entry_set_fflags(entry, stflags, 0);
}
"Couldn't read link data");
return (ARCHIVE_FAILED);
}
+ if (a->tree != NULL) {
#ifdef HAVE_READLINKAT
- if (a->entry_wd_fd >= 0)
- lnklen = readlinkat(a->entry_wd_fd, path,
- linkbuffer, linkbuffer_len);
- else
+ lnklen = readlinkat(a->tree_current_dir_fd(a->tree),
+ path, linkbuffer, linkbuffer_len);
+#else
+ if (a->tree_enter_working_dir(a->tree) != 0) {
+ archive_set_error(&a->archive, errno,
+ "Couldn't read link data");
+ free(linkbuffer);
+ return (ARCHIVE_FAILED);
+ }
+ lnklen = readlink(path, linkbuffer, linkbuffer_len);
#endif /* HAVE_READLINKAT */
- lnklen = readlink(path, linkbuffer, linkbuffer_len);
+ } else
+ lnklen = readlink(path, linkbuffer, linkbuffer_len);
if (lnklen < 0) {
archive_set_error(&a->archive, errno,
"Couldn't read link data");
}
#endif /* HAVE_READLINK || HAVE_READLINKAT */
- r = setup_acls_posix1e(a, entry, fd);
- r1 = setup_xattrs(a, entry, fd);
- if (r1 < r)
- r = r1;
- r1 = setup_mac_metadata(a, entry, fd);
+ r = setup_acls_posix1e(a, entry, &fd);
+ r1 = setup_xattrs(a, entry, &fd);
if (r1 < r)
r = r1;
- r1 = setup_sparse(a, entry, fd);
+ if (a->enable_copyfile) {
+ r1 = setup_mac_metadata(a, entry, &fd);
+ if (r1 < r)
+ r = r1;
+ }
+ r1 = setup_sparse(a, entry, &fd);
if (r1 < r)
r = r1;
*/
static int
setup_mac_metadata(struct archive_read_disk *a,
- struct archive_entry *entry, int fd)
+ struct archive_entry *entry, int *fd)
{
int tempfd = -1;
int copyfile_flags = COPYFILE_NOFOLLOW | COPYFILE_ACL | COPYFILE_XATTR;
int have_attrs;
const char *name, *tempdir, *tempfile = NULL;
+ (void)fd; /* UNUSED */
name = archive_entry_sourcepath(entry);
if (name == NULL)
name = archive_entry_pathname(entry);
return (ARCHIVE_WARN);
}
+ if (a->tree != NULL) {
+ if (a->tree_enter_working_dir(a->tree) != 0) {
+ archive_set_error(&a->archive, errno,
+ "Couldn't change dir");
+ return (ARCHIVE_FAILED);
+ }
+ }
+
/* Short-circuit if there's nothing to do. */
have_attrs = copyfile(name, NULL, 0, copyfile_flags | COPYFILE_CHECK);
if (have_attrs == -1) {
*/
static int
setup_mac_metadata(struct archive_read_disk *a,
- struct archive_entry *entry, int fd)
+ struct archive_entry *entry, int *fd)
{
(void)a; /* UNUSED */
(void)entry; /* UNUSED */
static int
setup_acls_posix1e(struct archive_read_disk *a,
- struct archive_entry *entry, int fd)
+ struct archive_entry *entry, int *fd)
{
const char *accpath;
acl_t acl;
archive_entry_acl_clear(entry);
+ if (*fd < 0 && a->tree != NULL &&
+ (a->follow_symlinks || archive_entry_filetype(entry) != AE_IFLNK)){
+ *fd = a->open_on_current_dir(a->tree, accpath,
+ O_RDONLY | O_NONBLOCK);
+ if (*fd < 0) {
+ archive_set_error(&a->archive, errno,
+ "Couldn't access %s", accpath);
+ return (ARCHIVE_FAILED);
+ }
+ }
+
/* Retrieve access ACL from file. */
- if (fd >= 0)
- acl = acl_get_fd(fd);
+ if (*fd >= 0)
+ acl = acl_get_fd(*fd);
#if HAVE_ACL_GET_LINK_NP
else if (!a->follow_symlinks)
acl = acl_get_link_np(accpath, ACL_TYPE_ACCESS);
#else
static int
setup_acls_posix1e(struct archive_read_disk *a,
- struct archive_entry *entry, int fd)
+ struct archive_entry *entry, int *fd)
{
(void)a; /* UNUSED */
(void)entry; /* UNUSED */
static int
setup_xattrs(struct archive_read_disk *a,
- struct archive_entry *entry, int fd)
+ struct archive_entry *entry, int *fd)
{
char *list, *p;
const char *path;
if (path == NULL)
path = archive_entry_pathname(entry);
+ if (*fd < 0 && a->tree != NULL) {
+ if (a->follow_symlinks ||
+ archive_entry_filetype(entry) != AE_IFLNK)
+ *fd = a->open_on_current_dir(a->tree, path,
+ O_RDONLY | O_NONBLOCK);
+ if (*fd < 0) {
+ if (a->tree_enter_working_dir(a->tree) != 0) {
+ archive_set_error(&a->archive, errno,
+ "Couldn't access %s", path);
+ return (ARCHIVE_FAILED);
+ }
+ }
+ }
+
#if HAVE_FLISTXATTR
- if (fd >= 0)
- list_size = flistxattr(fd, NULL, 0);
+ if (*fd >= 0)
+ list_size = flistxattr(*fd, NULL, 0);
else if (!a->follow_symlinks)
list_size = llistxattr(path, NULL, 0);
else
list_size = listxattr(path, NULL, 0);
#elif HAVE_FLISTEA
- if (fd >= 0)
- list_size = flistea(fd, NULL, 0);
+ if (*fd >= 0)
+ list_size = flistea(*fd, NULL, 0);
else if (!a->follow_symlinks)
list_size = llistea(path, NULL, 0);
else
}
#if HAVE_FLISTXATTR
- if (fd >= 0)
- list_size = flistxattr(fd, list, list_size);
+ if (*fd >= 0)
+ list_size = flistxattr(*fd, list, list_size);
else if (!a->follow_symlinks)
list_size = llistxattr(path, list, list_size);
else
list_size = listxattr(path, list, list_size);
#elif HAVE_FLISTEA
- if (fd >= 0)
- list_size = flistea(fd, list, list_size);
+ if (*fd >= 0)
+ list_size = flistea(*fd, list, list_size);
else if (!a->follow_symlinks)
list_size = llistea(path, list, list_size);
else
if (strncmp(p, "system.", 7) == 0 ||
strncmp(p, "xfsroot.", 8) == 0)
continue;
- setup_xattr(a, entry, p, fd);
+ setup_xattr(a, entry, p, *fd);
}
free(list);
size = extattr_get_file(accpath, namespace, name, value, size);
if (size == -1) {
+ free(value);
archive_set_error(&a->archive, errno,
"Couldn't read extended attribute");
return (ARCHIVE_WARN);
static int
setup_xattrs(struct archive_read_disk *a,
- struct archive_entry *entry, int fd)
+ struct archive_entry *entry, int *fd)
{
char buff[512];
char *list, *p;
if (path == NULL)
path = archive_entry_pathname(entry);
- if (fd >= 0)
- list_size = extattr_list_fd(fd, namespace, NULL, 0);
+ if (*fd < 0 && a->tree != NULL) {
+ if (a->follow_symlinks ||
+ archive_entry_filetype(entry) != AE_IFLNK)
+ *fd = a->open_on_current_dir(a->tree, path,
+ O_RDONLY | O_NONBLOCK);
+ if (*fd < 0) {
+ if (a->tree_enter_working_dir(a->tree) != 0) {
+ archive_set_error(&a->archive, errno,
+ "Couldn't access %s", path);
+ return (ARCHIVE_FAILED);
+ }
+ }
+ }
+
+ if (*fd >= 0)
+ list_size = extattr_list_fd(*fd, namespace, NULL, 0);
else if (!a->follow_symlinks)
list_size = extattr_list_link(path, namespace, NULL, 0);
else
return (ARCHIVE_FATAL);
}
- if (fd >= 0)
- list_size = extattr_list_fd(fd, namespace, list, list_size);
+ if (*fd >= 0)
+ list_size = extattr_list_fd(*fd, namespace, list, list_size);
else if (!a->follow_symlinks)
list_size = extattr_list_link(path, namespace, list, list_size);
else
name = buff + strlen(buff);
memcpy(name, p + 1, len);
name[len] = '\0';
- setup_xattr(a, entry, namespace, name, buff, fd);
+ setup_xattr(a, entry, namespace, name, buff, *fd);
p += 1 + len;
}
*/
static int
setup_xattrs(struct archive_read_disk *a,
- struct archive_entry *entry, int fd)
+ struct archive_entry *entry, int *fd)
{
(void)a; /* UNUSED */
(void)entry; /* UNUSED */
static int
setup_sparse(struct archive_read_disk *a,
- struct archive_entry *entry, int fd)
+ struct archive_entry *entry, int *fd)
{
char buff[4096];
struct fiemap *fm;
struct fiemap_extent *fe;
int64_t size;
int count, do_fiemap;
- int initial_fd = fd;
int exit_sts = ARCHIVE_OK;
if (archive_entry_filetype(entry) != AE_IFREG
|| archive_entry_hardlink(entry) != NULL)
return (ARCHIVE_OK);
- if (fd < 0) {
+ if (*fd < 0) {
const char *path;
path = archive_entry_sourcepath(entry);
if (path == NULL)
path = archive_entry_pathname(entry);
- fd = open(path, O_RDONLY | O_NONBLOCK);
- if (fd < 0) {
+ if (a->tree != NULL)
+ *fd = a->open_on_current_dir(a->tree, path,
+ O_RDONLY | O_NONBLOCK);
+ else
+ *fd = open(path, O_RDONLY | O_NONBLOCK);
+ if (*fd < 0) {
archive_set_error(&a->archive, errno,
"Can't open `%s'", path);
return (ARCHIVE_FAILED);
for (;;) {
int i, r;
- r = ioctl(fd, FS_IOC_FIEMAP, fm);
+ r = ioctl(*fd, FS_IOC_FIEMAP, fm);
if (r < 0) {
- /* When errno is ENOTTY, it is better we should
- * return ARCHIVE_OK because an earlier version
- *(<2.6.28) cannot perfom FS_IOC_FIEMAP.
- * We should also check if errno is EOPNOTSUPP,
- * it means "Operation not supported". */
- if (errno != ENOTTY && errno != EOPNOTSUPP) {
- archive_set_error(&a->archive, errno,
- "FIEMAP failed");
- exit_sts = ARCHIVE_FAILED;
- }
+ /* When something error happens, it is better we
+ * should return ARCHIVE_OK because an earlier
+ * version(<2.6.28) cannot perfom FS_IOC_FIEMAP. */
goto exit_setup_sparse;
}
if (fm->fm_mapped_extents == 0)
break;
fe = fm->fm_extents;
- for (i = 0; i < fm->fm_mapped_extents; i++, fe++) {
+ for (i = 0; i < (int)fm->fm_mapped_extents; i++, fe++) {
if (!(fe->fe_flags & FIEMAP_EXTENT_UNWRITTEN)) {
/* The fe_length of the last block does not
* adjust itself to its size files. */
int64_t length = fe->fe_length;
- if (fe->fe_logical + length > size)
+ if (fe->fe_logical + length > (uint64_t)size)
length -= fe->fe_logical + length - size;
if (fe->fe_logical == 0 && length == size) {
/* This is not sparse. */
break;
}
exit_setup_sparse:
- if (initial_fd != fd)
- close(fd);
return (exit_sts);
}
static int
setup_sparse(struct archive_read_disk *a,
- struct archive_entry *entry, int fd)
+ struct archive_entry *entry, int *fd)
{
int64_t size;
- int initial_fd = fd;
off_t initial_off; /* FreeBSD/Solaris only, so off_t okay here */
off_t off_s, off_e; /* FreeBSD/Solaris only, so off_t okay here */
int exit_sts = ARCHIVE_OK;
return (ARCHIVE_OK);
/* Does filesystem support the reporting of hole ? */
- if (fd >= 0) {
- if (fpathconf(fd, _PC_MIN_HOLE_SIZE) <= 0)
+ if (*fd < 0 && a->tree != NULL) {
+ const char *path;
+
+ path = archive_entry_sourcepath(entry);
+ if (path == NULL)
+ path = archive_entry_pathname(entry);
+ *fd = a->open_on_current_dir(a->tree, path,
+ O_RDONLY | O_NONBLOCK);
+ if (*fd < 0) {
+ archive_set_error(&a->archive, errno,
+ "Can't open `%s'", path);
+ return (ARCHIVE_FAILED);
+ }
+ }
+
+ if (*fd >= 0) {
+ if (fpathconf(*fd, _PC_MIN_HOLE_SIZE) <= 0)
return (ARCHIVE_OK);
- initial_off = lseek(fd, 0, SEEK_CUR);
+ initial_off = lseek(*fd, 0, SEEK_CUR);
if (initial_off != 0)
- lseek(fd, 0, SEEK_SET);
+ lseek(*fd, 0, SEEK_SET);
} else {
const char *path;
path = archive_entry_sourcepath(entry);
if (path == NULL)
path = archive_entry_pathname(entry);
+
if (pathconf(path, _PC_MIN_HOLE_SIZE) <= 0)
return (ARCHIVE_OK);
- fd = open(path, O_RDONLY | O_NONBLOCK);
- if (fd < 0) {
+ *fd = open(path, O_RDONLY | O_NONBLOCK);
+ if (*fd < 0) {
archive_set_error(&a->archive, errno,
"Can't open `%s'", path);
return (ARCHIVE_FAILED);
off_s = 0;
size = archive_entry_size(entry);
while (off_s < size) {
- off_s = lseek(fd, off_s, SEEK_DATA);
+ off_s = lseek(*fd, off_s, SEEK_DATA);
if (off_s == (off_t)-1) {
if (errno == ENXIO)
break;/* no more hole */
exit_sts = ARCHIVE_FAILED;
goto exit_setup_sparse;
}
- off_e = lseek(fd, off_s, SEEK_HOLE);
- if (off_s == (off_t)-1) {
+ off_e = lseek(*fd, off_s, SEEK_HOLE);
+ if (off_e == (off_t)-1) {
if (errno == ENXIO) {
- off_e = lseek(fd, 0, SEEK_END);
+ off_e = lseek(*fd, 0, SEEK_END);
if (off_e != (off_t)-1)
break;/* no more data */
}
off_s = off_e;
}
exit_setup_sparse:
- if (initial_fd != fd)
- close(fd);
- else
- lseek(fd, initial_off, SEEK_SET);
+ lseek(*fd, initial_off, SEEK_SET);
return (exit_sts);
}
*/
static int
setup_sparse(struct archive_read_disk *a,
- struct archive_entry *entry, int fd)
+ struct archive_entry *entry, int *fd)
{
(void)a; /* UNUSED */
(void)entry; /* UNUSED */
/*-
* Copyright (c) 2003-2009 Tim Kientzle
- * Copyright (c) 2010,2011 Michihiro NAKAJIMA
+ * Copyright (c) 2010-2012 Michihiro NAKAJIMA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#ifdef HAVE_LINUX_MAGIC_H
#include <linux/magic.h>
#endif
+#ifdef HAVE_LINUX_FS_H
+#include <linux/fs.h>
+#endif
+/*
+ * Some Linux distributions have both linux/ext2_fs.h and ext2fs/ext2_fs.h.
+ * As the include guards don't agree, the order of include is important.
+ */
+#ifdef HAVE_LINUX_EXT2_FS_H
+#include <linux/ext2_fs.h> /* for Linux file flags */
+#endif
+#if defined(HAVE_EXT2FS_EXT2_FS_H) && !defined(__CYGWIN__)
+#include <ext2fs/ext2_fs.h> /* Linux file flags, broken on Cygwin */
+#endif
#ifdef HAVE_DIRECT_H
#include <direct.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
#include "archive.h"
#include "archive_string.h"
char symlink_mode;
struct filesystem *current_filesystem;
struct filesystem *filesystem_table;
+ int initial_filesystem_id;
int current_filesystem_id;
int max_filesystem_id;
int allocated_filesytem;
#define onWorkingDir 64 /* We are on the working dir where we are
* reading directory entry at this time. */
#define needsRestoreTimes 128
+#define onInitialDir 256 /* We are on the initial dir. */
static int
tree_dir_next_posix(struct tree *t);
static int setup_sparse(struct archive_read_disk *, struct archive_entry *);
static int close_and_restore_time(int fd, struct tree *,
struct restore_time *);
+static int open_on_current_dir(struct tree *, const char *, int);
static struct archive_vtable *
{
struct archive_read_disk *a;
- a = (struct archive_read_disk *)malloc(sizeof(*a));
+ a = (struct archive_read_disk *)calloc(1, sizeof(*a));
if (a == NULL)
return (NULL);
- memset(a, 0, sizeof(*a));
a->archive.magic = ARCHIVE_READ_DISK_MAGIC;
a->archive.state = ARCHIVE_STATE_NEW;
a->archive.vtable = archive_read_disk_vtable();
a->lookup_uname = trivial_lookup_uname;
a->lookup_gname = trivial_lookup_gname;
- a->entry_wd_fd = -1;
+ a->enable_copyfile = 1;
+ a->traverse_mount_points = 1;
+ a->open_on_current_dir = open_on_current_dir;
+ a->tree_current_dir_fd = tree_current_dir_fd;
+ a->tree_enter_working_dir = tree_enter_working_dir;
return (&a->archive);
}
#endif
}
+int
+archive_read_disk_set_behavior(struct archive *_a, int flags)
+{
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+ int r = ARCHIVE_OK;
+
+ archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
+ ARCHIVE_STATE_ANY, "archive_read_disk_honor_nodump");
+
+ if (flags & ARCHIVE_READDISK_RESTORE_ATIME)
+ r = archive_read_disk_set_atime_restored(_a);
+ else {
+ a->restore_time = 0;
+ if (a->tree != NULL)
+ a->tree->flags &= ~needsRestoreTimes;
+ }
+ if (flags & ARCHIVE_READDISK_HONOR_NODUMP)
+ a->honor_nodump = 1;
+ else
+ a->honor_nodump = 0;
+ if (flags & ARCHIVE_READDISK_MAC_COPYFILE)
+ a->enable_copyfile = 1;
+ else
+ a->enable_copyfile = 0;
+ if (flags & ARCHIVE_READDISK_NO_TRAVERSE_MOUNTS)
+ a->traverse_mount_points = 0;
+ else
+ a->traverse_mount_points = 1;
+ return (r);
+}
+
/*
* Trivial implementations of gname/uname lookup functions.
* These are normally overridden by the client, but these stub
flags |= O_NOATIME;
do {
#endif
-#ifdef HAVE_OPENAT
- t->entry_fd = openat(tree_current_dir_fd(t),
+ t->entry_fd = open_on_current_dir(t,
tree_current_access_path(t), flags);
-#else
- tree_enter_working_dir(t);
- t->entry_fd = open(tree_current_access_path(t), flags);
-#endif
#if defined(O_NOATIME)
/*
* When we did open the file with O_NOATIME flag,
t->entry_buff_size = t->current_filesystem->buff_size;
buffbytes = t->entry_buff_size;
- if (buffbytes > t->current_sparse->length)
+ if ((int64_t)buffbytes > t->current_sparse->length)
buffbytes = t->current_sparse->length;
/*
}
static int
-_archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
+next_entry(struct archive_read_disk *a, struct tree *t,
+ struct archive_entry *entry)
{
- struct archive_read_disk *a = (struct archive_read_disk *)_a;
- struct tree *t;
const struct stat *st; /* info to use for this entry */
const struct stat *lst;/* lstat() information */
- int descend, fd = -1, r;
-
- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
- ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
- "archive_read_next_header2");
+ const char *name;
+ int descend, r;
- t = a->tree;
- if (t->entry_fd >= 0) {
- close_and_restore_time(t->entry_fd, t, &t->restore_time);
- t->entry_fd = -1;
- }
-#if !(defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR))
- /* Restore working directory. */
- tree_enter_working_dir(t);
-#endif
st = NULL;
lst = NULL;
+ t->descend = 0;
do {
switch (tree_next(t)) {
case TREE_ERROR_FATAL:
}
} while (lst == NULL);
+#ifdef __APPLE__
+ if (a->enable_copyfile) {
+ /* If we're using copyfile(), ignore "._XXX" files. */
+ const char *bname = strrchr(tree_current_path(t), '/');
+ if (bname == NULL)
+ bname = tree_current_path(t);
+ else
+ ++bname;
+ if (bname[0] == '.' && bname[1] == '_')
+ return (ARCHIVE_RETRY);
+ }
+#endif
+
+ archive_entry_copy_pathname(entry, tree_current_path(t));
+ /*
+ * Perform path matching.
+ */
+ if (a->matching) {
+ r = archive_match_path_excluded(a->matching, entry);
+ if (r < 0) {
+ archive_set_error(&(a->archive), errno,
+ "Faild : %s", archive_error_string(a->matching));
+ return (r);
+ }
+ if (r) {
+ if (a->excluded_cb_func)
+ a->excluded_cb_func(&(a->archive),
+ a->excluded_cb_data, entry);
+ return (ARCHIVE_RETRY);
+ }
+ }
+
/*
* Distinguish 'L'/'P'/'H' symlink following.
*/
tree_enter_initial_dir(t);
return (ARCHIVE_FATAL);
}
+ if (t->initial_filesystem_id == -1)
+ t->initial_filesystem_id = t->current_filesystem_id;
+ if (!a->traverse_mount_points) {
+ if (t->initial_filesystem_id != t->current_filesystem_id)
+ return (ARCHIVE_RETRY);
+ }
t->descend = descend;
- archive_entry_set_pathname(entry, tree_current_path(t));
- archive_entry_copy_sourcepath(entry, tree_current_access_path(t));
+ /*
+ * Honor nodump flag.
+ * If the file is marked with nodump flag, do not return this entry.
+ */
+ if (a->honor_nodump) {
+#if defined(HAVE_STRUCT_STAT_ST_FLAGS) && defined(UF_NODUMP)
+ if (st->st_flags & UF_NODUMP)
+ return (ARCHIVE_RETRY);
+#elif defined(EXT2_IOC_GETFLAGS) && defined(EXT2_NODUMP_FL) &&\
+ defined(HAVE_WORKING_EXT2_IOC_GETFLAGS)
+ if (S_ISREG(st->st_mode) || S_ISDIR(st->st_mode)) {
+ unsigned long stflags;
+
+ t->entry_fd = open_on_current_dir(t,
+ tree_current_access_path(t), O_RDONLY | O_NONBLOCK);
+ if (t->entry_fd >= 0) {
+ r = ioctl(t->entry_fd, EXT2_IOC_GETFLAGS,
+ &stflags);
+ if (r == 0 && (stflags & EXT2_NODUMP_FL) != 0)
+ return (ARCHIVE_RETRY);
+ }
+ }
+#endif
+ }
+
archive_entry_copy_stat(entry, st);
- /* Save the times to be restored. */
+ /* Save the times to be restored. This must be in before
+ * calling archive_read_disk_descend() or any chance of it,
+ * especially, invokng a callback. */
t->restore_time.mtime = archive_entry_mtime(entry);
t->restore_time.mtime_nsec = archive_entry_mtime_nsec(entry);
t->restore_time.atime = archive_entry_atime(entry);
t->restore_time.filetype = archive_entry_filetype(entry);
t->restore_time.noatime = t->current_filesystem->noatime;
-#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
/*
- * Open the current file to freely gather its metadata anywhere in
- * working directory.
- * Note: A symbolic link file cannot be opened with O_NOFOLLOW.
+ * Perform time matching.
*/
- if (a->follow_symlinks || archive_entry_filetype(entry) != AE_IFLNK)
- fd = openat(tree_current_dir_fd(t), tree_current_access_path(t),
- O_RDONLY | O_NONBLOCK);
- /* Restore working directory if openat() operation failed or
- * the file is a symbolic link. */
- if (fd < 0)
- tree_enter_working_dir(t);
+ if (a->matching) {
+ r = archive_match_time_excluded(a->matching, entry);
+ if (r < 0) {
+ archive_set_error(&(a->archive), errno,
+ "Faild : %s", archive_error_string(a->matching));
+ return (r);
+ }
+ if (r) {
+ if (a->excluded_cb_func)
+ a->excluded_cb_func(&(a->archive),
+ a->excluded_cb_data, entry);
+ return (ARCHIVE_RETRY);
+ }
+ }
- /* The current direcotry fd is needed at
- * archive_read_disk_entry_from_file() function to read link data
- * with readlinkat(). */
- a->entry_wd_fd = tree_current_dir_fd(t);
-#endif
+ /* Lookup uname/gname */
+ name = archive_read_disk_uname(&(a->archive), archive_entry_uid(entry));
+ if (name != NULL)
+ archive_entry_copy_uname(entry, name);
+ name = archive_read_disk_gname(&(a->archive), archive_entry_gid(entry));
+ if (name != NULL)
+ archive_entry_copy_gname(entry, name);
+
+ /*
+ * Perform owner matching.
+ */
+ if (a->matching) {
+ r = archive_match_owner_excluded(a->matching, entry);
+ if (r < 0) {
+ archive_set_error(&(a->archive), errno,
+ "Faild : %s", archive_error_string(a->matching));
+ return (r);
+ }
+ if (r) {
+ if (a->excluded_cb_func)
+ a->excluded_cb_func(&(a->archive),
+ a->excluded_cb_data, entry);
+ return (ARCHIVE_RETRY);
+ }
+ }
+
+ /*
+ * Invoke a meta data filter callback.
+ */
+ if (a->metadata_filter_func) {
+ if (!a->metadata_filter_func(&(a->archive),
+ a->metadata_filter_data, entry))
+ return (ARCHIVE_RETRY);
+ }
/*
* Populate the archive_entry with metadata from the disk.
*/
- r = archive_read_disk_entry_from_file(&(a->archive), entry, fd, st);
+ archive_entry_copy_sourcepath(entry, tree_current_access_path(t));
+ r = archive_read_disk_entry_from_file(&(a->archive), entry,
+ t->entry_fd, st);
- /* Close the file descriptor used for reding the current file
- * metadata at archive_read_disk_entry_from_file(). */
- if (fd >= 0)
- close(fd);
+ return (r);
+}
+
+static int
+_archive_read_next_header2(struct archive *_a, struct archive_entry *entry)
+{
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+ struct tree *t;
+ int r;
+
+ archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
+ ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
+ "archive_read_next_header2");
+
+ t = a->tree;
+ if (t->entry_fd >= 0) {
+ close_and_restore_time(t->entry_fd, t, &t->restore_time);
+ t->entry_fd = -1;
+ }
+
+ for (;;) {
+ r = next_entry(a, t, entry);
+ if (t->entry_fd >= 0) {
+ close(t->entry_fd);
+ t->entry_fd = -1;
+ }
+
+ if (r == ARCHIVE_RETRY) {
+ archive_entry_clear(entry);
+ continue;
+ }
+ break;
+ }
/* Return to the initial directory. */
tree_enter_initial_dir(t);
- archive_entry_copy_sourcepath(entry, tree_current_path(t));
/*
* EOF and FATAL are persistent at this layer. By
break;
case ARCHIVE_OK:
case ARCHIVE_WARN:
+ /* Overwrite the sourcepath based on the initial directory. */
+ archive_entry_copy_sourcepath(entry, tree_current_path(t));
t->entry_total = 0;
if (archive_entry_filetype(entry) == AE_IFREG) {
t->nlink = archive_entry_nlink(entry);
return (ARCHIVE_OK);
}
+int
+archive_read_disk_set_matching(struct archive *_a, struct archive *_ma,
+ void (*_excluded_func)(struct archive *, void *, struct archive_entry *),
+ void *_client_data)
+{
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+ archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
+ ARCHIVE_STATE_ANY, "archive_read_disk_set_matching");
+ a->matching = _ma;
+ a->excluded_cb_func = _excluded_func;
+ a->excluded_cb_data = _client_data;
+ return (ARCHIVE_OK);
+}
+
+int
+archive_read_disk_set_metadata_filter_callback(struct archive *_a,
+ int (*_metadata_filter_func)(struct archive *, void *,
+ struct archive_entry *), void *_client_data)
+{
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+
+ archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_ANY,
+ "archive_read_disk_set_metadata_filter_callback");
+
+ a->metadata_filter_func = _metadata_filter_func;
+ a->metadata_filter_data = _client_data;
+ return (ARCHIVE_OK);
+}
+
+int
+archive_read_disk_can_descend(struct archive *_a)
+{
+ struct archive_read_disk *a = (struct archive_read_disk *)_a;
+ struct tree *t = a->tree;
+
+ archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
+ ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
+ "archive_read_disk_can_descend");
+
+ return (t->visit_type == TREE_REGULAR && t->descend);
+}
+
/*
* Called by the client to mark the directory just returned from
* tree_next() as needing to be visited.
struct archive_read_disk *a = (struct archive_read_disk *)_a;
struct tree *t = a->tree;
- archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC, ARCHIVE_STATE_DATA,
+ archive_check_magic(_a, ARCHIVE_READ_DISK_MAGIC,
+ ARCHIVE_STATE_HEADER | ARCHIVE_STATE_DATA,
"archive_read_disk_descend");
- if (t->visit_type != TREE_REGULAR || !t->descend) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Ignored the request descending the current object");
- return (ARCHIVE_WARN);
- }
+ if (t->visit_type != TREE_REGULAR || !t->descend)
+ return (ARCHIVE_OK);
if (tree_current_is_physical_dir(t)) {
tree_push(t, t->basename, t->current_filesystem_id,
archive_string_init(&path);
if (archive_string_append_from_wcs(&path, pathname,
wcslen(pathname)) != 0) {
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "Can't convert a path to a char string");
+ if (errno == ENOMEM)
+ archive_set_error(&a->archive, ENOMEM,
+ "Can't allocate memory");
+ else
+ archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
+ "Can't convert a path to a char string");
a->archive.state = ARCHIVE_STATE_FATAL;
ret = ARCHIVE_FATAL;
} else
t->current_filesystem->synthetic = -1;
t->current_filesystem->remote = -1;
if (tree_current_is_symblic_link_target(t)) {
-#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
+#if defined(HAVE_OPENAT)
/*
* Get file system statistics on any directory
* where current is.
xr = get_xfer_size(t, fd, NULL);
close(fd);
#else
+ if (tree_enter_working_dir(t) != 0) {
+ archive_set_error(&a->archive, errno, "fchdir failed");
+ return (ARCHIVE_FAILED);
+ }
r = statfs(tree_current_access_path(t), &sfs);
if (r == 0)
xr = get_xfer_size(t, -1, tree_current_access_path(t));
t->current_filesystem->name_max = sfs.f_namemax;
#else
/* Mac OS X does not have f_namemax in struct statfs. */
- if (tree_current_is_symblic_link_target(t))
+ if (tree_current_is_symblic_link_target(t)) {
+ if (tree_enter_working_dir(t) != 0) {
+ archive_set_error(&a->archive, errno, "fchdir failed");
+ return (ARCHIVE_FAILED);
+ }
nm = pathconf(tree_current_access_path(t), _PC_NAME_MAX);
- else
+ } else
nm = fpathconf(tree_current_dir_fd(t), _PC_NAME_MAX);
if (nm == -1)
t->current_filesystem->name_max = NAME_MAX;
int r, xr = 0;
t->current_filesystem->synthetic = -1;
+ if (tree_enter_working_dir(t) != 0) {
+ archive_set_error(&a->archive, errno, "fchdir failed");
+ return (ARCHIVE_FAILED);
+ }
if (tree_current_is_symblic_link_target(t)) {
r = statvfs(tree_current_access_path(t), &sfs);
if (r == 0)
* for pathconf() function. */
t->current_filesystem->xfer_align = sfs.f_frsize;
t->current_filesystem->max_xfer_size = -1;
+#if defined(HAVE_STRUCT_STATVFS_F_IOSIZE)
t->current_filesystem->min_xfer_size = sfs.f_iosize;
t->current_filesystem->incr_xfer_size = sfs.f_iosize;
+#else
+ t->current_filesystem->min_xfer_size = sfs.f_bsize;
+ t->current_filesystem->incr_xfer_size = sfs.f_bsize;
+#endif
}
if (sfs.f_flag & ST_LOCAL)
t->current_filesystem->remote = 0;
else
t->current_filesystem->remote = 1;
+#if defined(ST_NOATIME)
if (sfs.f_flag & ST_NOATIME)
t->current_filesystem->noatime = 1;
else
+#endif
t->current_filesystem->noatime = 0;
/* Set maximum filename length. */
int r, vr = 0, xr = 0;
if (tree_current_is_symblic_link_target(t)) {
-#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
+#if defined(HAVE_OPENAT)
/*
* Get file system statistics on any directory
* where current is.
xr = get_xfer_size(t, fd, NULL);
close(fd);
#else
+ if (tree_enter_working_dir(t) != 0) {
+ archive_set_error(&a->archive, errno, "fchdir failed");
+ return (ARCHIVE_FAILED);
+ }
vr = statvfs(tree_current_access_path(t), &svfs);
r = statfs(tree_current_access_path(t), &sfs);
if (r == 0)
r = fstatfs(tree_current_dir_fd(t), &sfs);
if (r == 0)
xr = get_xfer_size(t, tree_current_dir_fd(t), NULL);
-#elif defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
-#error "Unexpected case. Please tell us about this error."
#else
+ if (tree_enter_working_dir(t) != 0) {
+ archive_set_error(&a->archive, errno, "fchdir failed");
+ return (ARCHIVE_FAILED);
+ }
vr = statvfs(".", &svfs);
r = statfs(".", &sfs);
if (r == 0)
t->current_filesystem->synthetic = -1;/* Not supported */
t->current_filesystem->remote = -1;/* Not supported */
if (tree_current_is_symblic_link_target(t)) {
-#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
+#if defined(HAVE_OPENAT)
/*
* Get file system statistics on any directory
* where current is.
xr = get_xfer_size(t, fd, NULL);
close(fd);
#else
+ if (tree_enter_working_dir(t) != 0) {
+ archive_set_error(&a->archive, errno, "fchdir failed");
+ return (ARCHIVE_FAILED);
+ }
r = statvfs(tree_current_access_path(t), &sfs);
if (r == 0)
xr = get_xfer_size(t, -1, tree_current_access_path(t));
r = fstatvfs(tree_current_dir_fd(t), &sfs);
if (r == 0)
xr = get_xfer_size(t, tree_current_dir_fd(t), NULL);
-#elif defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
-#error "Unexpected case. Please tell us about this error."
#else
+ if (tree_enter_working_dir(t) != 0) {
+ archive_set_error(&a->archive, errno, "fchdir failed");
+ return (ARCHIVE_FAILED);
+ }
r = statvfs(".", &sfs);
if (r == 0)
xr = get_xfer_size(t, -1, ".");
#if defined(HAVE_READDIR_R)
/* Set maximum filename length. */
# if defined(_PC_NAME_MAX)
- if (tree_current_is_symblic_link_target(t))
+ if (tree_current_is_symblic_link_target(t)) {
+ if (tree_enter_working_dir(t) != 0) {
+ archive_set_error(&a->archive, errno, "fchdir failed");
+ return (ARCHIVE_FAILED);
+ }
nm = pathconf(tree_current_access_path(t), _PC_NAME_MAX);
- else
+ } else
nm = fpathconf(tree_current_dir_fd(t), _PC_NAME_MAX);
if (nm == -1)
# endif /* _PC_NAME_MAX */
return (0);
}
+static int
+open_on_current_dir(struct tree *t, const char *path, int flags)
+{
+#ifdef HAVE_OPENAT
+ return (openat(tree_current_dir_fd(t), path, flags));
+#else
+ if (tree_enter_working_dir(t) != 0)
+ return (-1);
+ return (open(path, flags));
+#endif
+}
+
/*
* Add a directory path to the current stack.
*/
tree_reopen(struct tree *t, const char *path, int restore_time)
{
t->flags = (restore_time)?needsRestoreTimes:0;
+ t->flags |= onInitialDir;
t->visit_type = 0;
t->tree_errno = 0;
t->dirname_length = 0;
t->entry_fd = -1;
t->entry_eof = 0;
t->entry_remaining_bytes = 0;
+ t->initial_filesystem_id = -1;
/* First item is set up a lot like a symlink traversal. */
tree_push(t, path, 0, 0, 0, NULL);
static int
tree_descent(struct tree *t)
{
- int r = 0;
+ int flag, new_fd, r = 0;
-#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
- int new_fd;
t->dirname_length = archive_strlen(&t->path);
- new_fd = openat(t->working_dir_fd, t->stack->name.s, O_RDONLY);
+ flag = O_RDONLY;
+#if defined(O_DIRECTORY)
+ flag |= O_DIRECTORY;
+#endif
+ new_fd = open_on_current_dir(t, t->stack->name.s, flag);
if (new_fd < 0) {
t->tree_errno = errno;
r = TREE_ERROR_DIR;
t->maxOpenCount = t->openCount;
} else
close(t->working_dir_fd);
+ /* Renew the current working directory. */
t->working_dir_fd = new_fd;
+ t->flags &= ~onWorkingDir;
}
-#else
- /* If it is a link, set up fd for the ascent. */
- if (t->stack->flags & isDirLink)
- t->stack->symlink_parent_fd = t->working_dir_fd;
- else {
- close(t->working_dir_fd);
- t->openCount--;
- }
- t->working_dir_fd = -1;
- t->dirname_length = archive_strlen(&t->path);
- if (chdir(t->stack->name.s) != 0)
- {
- t->tree_errno = errno;
- r = TREE_ERROR_DIR;
- } else {
- t->depth++;
- t->working_dir_fd = open(".", O_RDONLY);
- t->openCount++;
- if (t->openCount > t->maxOpenCount)
- t->maxOpenCount = t->openCount;
- }
-#endif
return (r);
}
tree_ascend(struct tree *t)
{
struct tree_entry *te;
- int r = 0, prev_dir_fd;
+ int new_fd, r = 0, prev_dir_fd;
te = t->stack;
prev_dir_fd = t->working_dir_fd;
-#if defined(HAVE_OPENAT) && defined(HAVE_FSTATAT) && defined(HAVE_FDOPENDIR)
if (te->flags & isDirLink)
- t->working_dir_fd = te->symlink_parent_fd;
- else {
- int new_fd = openat(t->working_dir_fd, "..", O_RDONLY);
- if (new_fd < 0) {
- t->tree_errno = errno;
- r = TREE_ERROR_FATAL;
- } else
- t->working_dir_fd = new_fd;
- }
-#else
- if (te->flags & isDirLink) {
- if (fchdir(te->symlink_parent_fd) != 0) {
- t->tree_errno = errno;
- r = TREE_ERROR_FATAL;
- } else
- t->working_dir_fd = te->symlink_parent_fd;
+ new_fd = te->symlink_parent_fd;
+ else
+ new_fd = open_on_current_dir(t, "..", O_RDONLY);
+ if (new_fd < 0) {
+ t->tree_errno = errno;
+ r = TREE_ERROR_FATAL;
} else {
- if (chdir("..") != 0) {
- t->tree_errno = errno;
- r = TREE_ERROR_FATAL;
- } else
- t->working_dir_fd = open(".", O_RDONLY);
- }
-#endif
- if (r == 0) {
+ /* Renew the current working directory. */
+ t->working_dir_fd = new_fd;
+ t->flags &= ~onWorkingDir;
/* Current directory has been changed, we should
* close an fd of previous working directory. */
close_and_restore_time(prev_dir_fd, t, &te->restore_time);
{
int r = 0;
- if (t->flags & onWorkingDir) {
+ if ((t->flags & onInitialDir) == 0) {
r = fchdir(t->initial_dir_fd);
- if (r == 0)
+ if (r == 0) {
t->flags &= ~onWorkingDir;
+ t->flags |= onInitialDir;
+ }
}
return (r);
}
*/
if (t->depth > 0 && (t->flags & onWorkingDir) == 0) {
r = fchdir(t->working_dir_fd);
- if (r == 0)
+ if (r == 0) {
+ t->flags &= ~onInitialDir;
t->flags |= onWorkingDir;
+ }
}
return (r);
}
#if defined(HAVE_FDOPENDIR)
if ((t->d = fdopendir(dup(t->working_dir_fd))) == NULL) {
#else
- if ((t->d = opendir(".")) == NULL) {
+ if (tree_enter_working_dir(t) != 0 ||
+ (t->d = opendir(".")) == NULL) {
#endif
r = tree_ascend(t); /* Undo "chdir" */
tree_pop(t);
if (fstatat(tree_current_dir_fd(t),
tree_current_access_path(t), &t->st, 0) != 0)
#else
+ if (tree_enter_working_dir(t) != 0)
+ return NULL;
if (stat(tree_current_access_path(t), &t->st) != 0)
#endif
return NULL;
tree_current_access_path(t), &t->lst,
AT_SYMLINK_NOFOLLOW) != 0)
#else
+ if (tree_enter_working_dir(t) != 0)
+ return NULL;
if (lstat(tree_current_access_path(t), &t->lst) != 0)
#endif
return NULL;
*/
if (t->flags & hasLstat) {
/* If lstat() says it's a dir, it must be a dir. */
- if (S_ISDIR(tree_current_lstat(t)->st_mode))
+ st = tree_current_lstat(t);
+ if (st == NULL)
+ return 0;
+ if (S_ISDIR(st->st_mode))
return 1;
/* Not a dir; might be a link to a dir. */
/* If it's not a link, then it's not a link to a dir. */
* If stat() says it isn't a dir, then it's not a dir.
* If stat() data is cached, this check is free, so do it first.
*/
- if ((t->flags & hasStat)
- && (!S_ISDIR(tree_current_stat(t)->st_mode)))
- return 0;
+ if (t->flags & hasStat) {
+ st = tree_current_stat(t);
+ if (st == NULL)
+ return (0);
+ if (!S_ISDIR(st->st_mode))
+ return (0);
+ }
/*
* Either stat() said it was a dir (in which case, we have
struct tree_entry *te;
for (te = t->current->parent; te != NULL; te = te->parent) {
- if (te->dev == st->st_dev && te->ino == st->st_ino)
+ if (te->dev == (int64_t)st->st_dev &&
+ te->ino == (int64_t)st->st_ino)
return (1);
}
return (0);
lst = tree_current_lstat(t);
st = tree_current_stat(t);
- return (st != NULL && st->st_dev == t->current_filesystem->dev &&
+ return (st != NULL && lst != NULL &&
+ (int64_t)st->st_dev == t->current_filesystem->dev &&
st->st_dev != lst->st_dev);
}
#define ARCHIVE_READ_DISK_PRIVATE_H_INCLUDED
struct tree;
+struct archive_entry;
struct archive_read_disk {
struct archive archive;
/* Directory traversals. */
struct tree *tree;
+ int (*open_on_current_dir)(struct tree*, const char *, int);
+ int (*tree_current_dir_fd)(struct tree*);
+ int (*tree_enter_working_dir)(struct tree*);
/* Set 1 if users request to restore atime . */
int restore_time;
- int entry_wd_fd;
+ /* Set 1 if users request to honor nodump flag . */
+ int honor_nodump;
+ /* Set 1 if users request to enable mac copyfile. */
+ int enable_copyfile;
+ /* Set 1 if users request to traverse mount points. */
+ int traverse_mount_points;
const char * (*lookup_gname)(void *private, int64_t gid);
void (*cleanup_gname)(void *private);
const char * (*lookup_uname)(void *private, int64_t uid);
void (*cleanup_uname)(void *private);
void *lookup_uname_data;
+
+ int (*metadata_filter_func)(struct archive *, void *,
+ struct archive_entry *);
+ void *metadata_filter_data;
+
+ /* ARCHIVE_MATCH object. */
+ struct archive *matching;
+ /* Callback function, this will be invoked when ARCHIVE_MATCH
+ * archive_match_*_excluded_ae return true. */
+ void (*excluded_cb_func)(struct archive *, void *,
+ struct archive_entry *);
+ void *excluded_cb_data;
};
#endif
file_skip(struct archive *a, void *client_data, int64_t request)
{
struct read_fd_data *mine = (struct read_fd_data *)client_data;
- off_t skip = (off_t)request;
- off_t old_offset, new_offset;
+ int64_t skip = request;
+ int64_t old_offset, new_offset;
int skip_bits = sizeof(skip) * 8 - 1; /* off_t is a signed type. */
if (!mine->use_lseek)
archive_string_init(&fn);
if (archive_string_append_from_wcs(&fn, wfilename,
wcslen(wfilename)) != 0) {
- archive_set_error(a, EINVAL,
- "Failed to convert a wide-character filename to"
- " a multi-byte filename");
+ if (errno == ENOMEM)
+ archive_set_error(a, errno,
+ "Can't allocate memory");
+ else
+ archive_set_error(a, EINVAL,
+ "Failed to convert a wide-character"
+ " filename to a multi-byte filename");
archive_string_free(&fn);
return (ARCHIVE_FATAL);
}
file_seek(struct archive *a, void *client_data, int64_t request, int whence)
{
struct read_file_data *mine = (struct read_file_data *)client_data;
- off_t r;
+ int64_t r;
/* We use off_t here because lseek() is declared that way. */
/* See above for notes about when off_t is less than 64 bits. */
{
struct read_memory_data *mine = (struct read_memory_data *)client_data;
+ (void)a; /* UNUSED */
switch (whence) {
case SEEK_SET:
mine->p = mine->start + offset;
/* Dev/ino of the archive being read/written. */
int skip_file_set;
- dev_t skip_file_dev;
- ino_t skip_file_ino;
+ int64_t skip_file_dev;
+ int64_t skip_file_ino;
/*
* Used by archive_read_data() to track blocks and copy
.\"
.\" $FreeBSD$
.\"
-.Dd April 13, 2009
+.Dd February 2, 2012
.Dt ARCHIVE_READ_OPTIONS 3
.Os
.Sh NAME
.Nm archive_read_set_options
.Nd functions controlling options for reading archives
.\"
+.Sh LIBRARY
+Streaming Archive Library (libarchive, -larchive)
.Sh SYNOPSIS
.Ft int
.Fo archive_read_set_filter_option
struct archive_read *a = (struct archive_read *)_a;
struct archive_format_descriptor *format;
size_t i;
- int r, rv = ARCHIVE_FAILED;
+ int r, rv = ARCHIVE_WARN;
for (i = 0; i < sizeof(a->formats)/sizeof(a->formats[0]); i++) {
format = &a->formats[i];
if (r == ARCHIVE_OK)
rv = ARCHIVE_OK;
}
+ /* If the format name didn't match, return a special code for
+ * _archive_set_option[s]. */
+ if (rv == ARCHIVE_WARN && m != NULL)
+ rv = ARCHIVE_WARN - 1;
return (rv);
}
struct archive_read *a = (struct archive_read *)_a;
struct archive_read_filter *filter;
struct archive_read_filter_bidder *bidder;
- int r, rv = ARCHIVE_FAILED;
+ int r, rv = ARCHIVE_WARN;
for (filter = a->filter; filter != NULL; filter = filter->upstream) {
bidder = filter->bidder;
if (r == ARCHIVE_OK)
rv = ARCHIVE_OK;
}
+ /* If the filter name didn't match, return a special code for
+ * _archive_set_option[s]. */
+ if (rv == ARCHIVE_WARN && m != NULL)
+ rv = ARCHIVE_WARN - 1;
return (rv);
}
if (rpm->total_in + avail_in < RPM_LEAD_SIZE)
used += avail_in;
else {
- n = RPM_LEAD_SIZE - rpm->total_in;
+ n = (size_t)(RPM_LEAD_SIZE - rpm->total_in);
used += n;
b += n;
rpm->state = ST_HEADER;
* Magic Code, so we should do this in order not to
* make a mis-detection.
*/
- if (crc32(0, (unsigned char *)p + 12, 20)
+ if (crc32(0, (const unsigned char *)p + 12, 20)
!= archive_le32dec(p + 8))
return (6);
/* Hit the header! */
free_Header(&header);
if (r != ARCHIVE_OK)
return (r);
- zip->entries_remaining = zip->numFiles;
+ zip->entries_remaining = (size_t)zip->numFiles;
zip->entry = zip->entries;
} else {
++zip->entry;
if (zip_entry->flg & ATIME_IS_SET)
archive_entry_set_atime(entry, zip_entry->atime,
zip_entry->atime_ns);
- if (zip_entry->ssIndex != -1) {
+ if (zip_entry->ssIndex != (uint32_t)-1) {
zip->entry_bytes_remaining =
zip->si.ss.unpackSizes[zip_entry->ssIndex];
archive_entry_set_size(entry, zip->entry_bytes_remaining);
if ((zip_entry->mode & AE_IFMT) == AE_IFLNK) {
unsigned char *symname = NULL;
size_t symsize = 0;
- int r;
/*
* Symbolic-name is recorded as its contents. We have to
*/
while (zip->entry_bytes_remaining > 0) {
const void *buff;
+ unsigned char *mem;
size_t size;
int64_t offset;
r = archive_read_format_7zip_read_data(a, &buff,
&size, &offset);
- if (r < ARCHIVE_WARN)
+ if (r < ARCHIVE_WARN) {
+ free(symname);
return (r);
- symname = realloc(symname, symsize + size + 1);
- if (symname == NULL) {
+ }
+ mem = realloc(symname, symsize + size + 1);
+ if (mem == NULL) {
+ free(symname);
archive_set_error(&a->archive, ENOMEM,
"Can't allocate memory for Symname");
return (ARCHIVE_FATAL);
}
+ symname = mem;
memcpy(symname+symsize, buff, size);
symsize += size;
}
return (ARCHIVE_EOF);
}
- bytes = read_stream(a, buff, zip->entry_bytes_remaining, 0);
+ bytes = read_stream(a, buff,
+ (size_t)zip->entry_bytes_remaining, 0);
if (bytes < 0)
return ((int)bytes);
if (bytes == 0) {
* If the length is at the beginning, we can skip the
* compressed data much more quickly.
*/
- bytes_skipped = skip_stream(a, zip->entry_bytes_remaining);
+ bytes_skipped = skip_stream(a, (size_t)zip->entry_bytes_remaining);
if (bytes_skipped < 0)
return (ARCHIVE_FATAL);
zip->entry_bytes_remaining = 0;
ff = &filters[fi];
#endif
r = lzma_properties_decode(&filters[fi], NULL,
- coder1->properties, coder1->propertiesSize);
+ coder1->properties, (size_t)coder1->propertiesSize);
if (r != LZMA_OK) {
set_error(a, r);
return (ARCHIVE_FAILED);
} while (zip->ppstream.avail_out &&
(zip->ppstream.avail_in || flush_bytes));
- t_avail_in = zip->ppstream.avail_in;
- t_avail_out = zip->ppstream.avail_out;
+ t_avail_in = (size_t)zip->ppstream.avail_in;
+ t_avail_out = (size_t)zip->ppstream.avail_out;
break;
}
default:
{
int r = ARCHIVE_OK;
+#if !defined(HAVE_ZLIB_H) &&\
+ !(defined(HAVE_BZLIB_H) && defined(BZ_CONFIG_ERROR))
+ (void)a;/* UNUSED */
+#endif
#ifdef HAVE_LZMA_H
if (zip->lzstream_valid)
lzma_end(&(zip->lzstream));
return (0);
if (*p != kSize)
return (-1);
- pi->sizes = calloc(pi->numPackStreams, sizeof(uint64_t));
- pi->positions = calloc(pi->numPackStreams, sizeof(uint64_t));
+ pi->sizes = calloc((size_t)pi->numPackStreams, sizeof(uint64_t));
+ pi->positions = calloc((size_t)pi->numPackStreams, sizeof(uint64_t));
if (pi->sizes == NULL || pi->positions == NULL)
return (-1);
if (*p == kEnd) {
/* PackStreamDigests[num] are not present. */
pi->digest.defineds =
- calloc(pi->numPackStreams, sizeof(*pi->digest.defineds));
+ calloc((size_t)pi->numPackStreams, sizeof(*pi->digest.defineds));
pi->digest.digests =
- calloc(pi->numPackStreams, sizeof(*pi->digest.digests));
+ calloc((size_t)pi->numPackStreams, sizeof(*pi->digest.digests));
if (pi->digest.defineds == NULL || pi->digest.digests == NULL)
return (-1);
return (0);
if (*p != kSize)
return (-1);
- if (read_Digests(a, &(pi->digest), pi->numPackStreams) < 0)
+ if (read_Digests(a, &(pi->digest), (size_t)pi->numPackStreams) < 0)
return (-1);
/*
/* Too many coders. */
return (-1);
- f->coders = calloc(f->numCoders, sizeof(*f->coders));
+ f->coders = calloc((size_t)f->numCoders, sizeof(*f->coders));
if (f->coders == NULL)
return (-1);
for (i = 0; i< f->numCoders; i++) {
a, &(f->coders[i].propertiesSize)) < 0)
return (-1);
if ((p = header_bytes(
- a, f->coders[i].propertiesSize)) == NULL)
+ a, (size_t)f->coders[i].propertiesSize)) == NULL)
return (-1);
f->coders[i].properties =
- malloc(f->coders[i].propertiesSize);
+ malloc((size_t)f->coders[i].propertiesSize);
if (f->coders[i].properties == NULL)
return (-1);
memcpy(f->coders[i].properties, p,
- f->coders[i].propertiesSize);
+ (size_t)f->coders[i].propertiesSize);
}
numInStreamsTotal += f->coders[i].numInStreams;
f->numBindPairs = numOutStreamsTotal - 1;
if (zip->header_bytes_remaining < f->numBindPairs)
return (-1);
- f->bindPairs = calloc(f->numBindPairs, sizeof(*f->bindPairs));
- if (f->bindPairs == NULL)
- return (-1);
+ if (f->numBindPairs > 0) {
+ f->bindPairs =
+ calloc((size_t)f->numBindPairs, sizeof(*f->bindPairs));
+ if (f->bindPairs == NULL)
+ return (-1);
+ } else
+ f->bindPairs = NULL;
for (i = 0; i < f->numBindPairs; i++) {
if (parse_7zip_uint64(a, &(f->bindPairs[i].inIndex)) < 0)
return (-1);
f->numPackedStreams = numInStreamsTotal - f->numBindPairs;
f->packedStreams =
- calloc(f->numPackedStreams, sizeof(*f->packedStreams));
+ calloc((size_t)f->numPackedStreams, sizeof(*f->packedStreams));
if (f->packedStreams == NULL)
return (-1);
if (f->numPackedStreams == 1) {
goto failed;
switch (*p) {
case 0:
- ci->folders = calloc(ci->numFolders, sizeof(*ci->folders));
+ ci->folders =
+ calloc((size_t)ci->numFolders, sizeof(*ci->folders));
if (ci->folders == NULL)
return (-1);
for (i = 0; i < ci->numFolders; i++) {
unsigned j;
folder->unPackSize =
- calloc(folder->numOutStreams, sizeof(*folder->unPackSize));
+ calloc((size_t)folder->numOutStreams, sizeof(*folder->unPackSize));
if (folder->unPackSize == NULL)
goto failed;
for (j = 0; j < folder->numOutStreams; j++) {
return (0);
if (*p != kCRC)
goto failed;
- if (read_Digests(a, &digest, ci->numFolders) < 0)
+ if (read_Digests(a, &digest, (size_t)ci->numFolders) < 0)
goto failed;
for (i = 0; i < ci->numFolders; i++) {
ci->folders[i].digest_defined = digest.defineds[i];
static uint64_t
folder_uncompressed_size(struct _7z_folder *f)
{
- int n = f->numOutStreams;
- unsigned pairs = f->numBindPairs;
+ int n = (int)f->numOutStreams;
+ unsigned pairs = (unsigned)f->numBindPairs;
while (--n >= 0) {
unsigned i;
for (i = 0; i < pairs; i++) {
- if (f->bindPairs[i].outIndex == n)
+ if (f->bindPairs[i].outIndex == (uint64_t)n)
break;
}
if (i >= pairs)
return (-1);
if (1000000 < f[i].numUnpackStreams)
return (-1);
- unpack_streams += f[i].numUnpackStreams;
+ unpack_streams += (size_t)f[i].numUnpackStreams;
}
if ((p = header_bytes(a, 1)) == NULL)
return (-1);
numDigests = 0;
for (i = 0; i < numFolders; i++) {
if (f[i].numUnpackStreams != 1 || !f[i].digest_defined)
- numDigests += f[i].numUnpackStreams;
+ numDigests += (uint32_t)f[i].numUnpackStreams;
}
if (type == kCRC) {
f = si->ci.folders;
for (i = 0; i < si->ci.numFolders; i++) {
f[i].packIndex = packIndex;
- packIndex += f[i].numPackedStreams;
+ packIndex += (uint32_t)f[i].numPackedStreams;
if (packIndex > si->pi.numPackStreams)
return (-1);
}
if (*p == kSubStreamsInfo) {
if (read_SubStreamsInfo(a, &(si->ss),
- si->ci.folders, si->ci.numFolders) < 0)
+ si->ci.folders, (size_t)si->ci.numFolders) < 0)
return (-1);
if ((p = header_bytes(a, 1)) == NULL)
return (-1);
if (1000000 < zip->numFiles)
return (-1);
- zip->entries = calloc(zip->numFiles, sizeof(*zip->entries));
+ zip->entries = calloc((size_t)zip->numFiles, sizeof(*zip->entries));
if (zip->entries == NULL)
return (-1);
entries = zip->entries;
switch (type) {
case kEmptyStream:
- h->emptyStreamBools = calloc(zip->numFiles,
+ h->emptyStreamBools = calloc((size_t)zip->numFiles,
sizeof(*h->emptyStreamBools));
if (h->emptyStreamBools == NULL)
return (-1);
if (read_Bools(
- a, h->emptyStreamBools, zip->numFiles) < 0)
+ a, h->emptyStreamBools, (size_t)zip->numFiles) < 0)
return (-1);
empty_streams = 0;
for (i = 0; i < zip->numFiles; i++) {
}
break;
case kEmptyFile:
+ if (empty_streams <= 0) {
+ /* Unexcepted sequence. Skip this. */
+ if (header_bytes(a, ll) == NULL)
+ return (-1);
+ break;
+ }
h->emptyFileBools = calloc(empty_streams,
sizeof(*h->emptyFileBools));
if (h->emptyFileBools == NULL)
return (-1);
break;
case kAnti:
+ if (empty_streams <= 0) {
+ /* Unexcepted sequence. Skip this. */
+ if (header_bytes(a, ll) == NULL)
+ return (-1);
+ break;
+ }
h->antiBools = calloc(empty_streams,
sizeof(*h->antiBools));
if (h->antiBools == NULL)
if ((p = header_bytes(a, 2)) == NULL)
return (-1);
allAreDefined = *p;
- h->attrBools = calloc(zip->numFiles,
+ h->attrBools = calloc((size_t)zip->numFiles,
sizeof(*h->attrBools));
if (h->attrBools == NULL)
return (-1);
if (allAreDefined)
- memset(h->attrBools, 1, zip->numFiles);
+ memset(h->attrBools, 1, (size_t)zip->numFiles);
else {
if (read_Bools(a, h->attrBools,
- zip->numFiles) < 0)
+ (size_t)zip->numFiles) < 0)
return (-1);
}
for (i = 0; i < zip->numFiles; i++) {
if ((size_t)sindex >= si->ss.unpack_streams)
return (-1);
if (entries[i].mode == 0)
- entries[i].mode = AE_IFREG | 0777;
+ entries[i].mode = AE_IFREG | 0666;
if (si->ss.digestsDefined[sindex])
entries[i].flg |= CRC32_IS_SET;
entries[i].ssIndex = sindex;
if (dir)
entries[i].mode = AE_IFDIR | 0777;
else
- entries[i].mode = AE_IFREG | 0777;
+ entries[i].mode = AE_IFREG | 0666;
} else if (dir &&
(entries[i].mode & AE_IFMT) != AE_IFDIR) {
entries[i].mode &= ~AE_IFMT;
#define EPOC_TIME ARCHIVE_LITERAL_ULL(116444736000000000)
static void
-fileTimeToUtc(uint64_t fileTime, time_t *time, long *ns)
+fileTimeToUtc(uint64_t fileTime, time_t *timep, long *ns)
{
if (fileTime >= EPOC_TIME) {
fileTime -= EPOC_TIME;
/* milli seconds base */
- *time = (time_t)(fileTime / 10000000);
+ *timep = (time_t)(fileTime / 10000000);
/* nano seconds base */
*ns = (long)(fileTime % 10000000) * 100;
} else {
- *time = 0;
+ *timep = 0;
*ns = 0;
}
}
int allAreDefined;
unsigned i;
- timeBools = calloc(zip->numFiles, sizeof(*timeBools));
+ timeBools = calloc((size_t)zip->numFiles, sizeof(*timeBools));
if (timeBools == NULL)
return (-1);
goto failed;
allAreDefined = *p;
if (allAreDefined)
- memset(timeBools, 1, zip->numFiles);
+ memset(timeBools, 1, (size_t)zip->numFiles);
else {
- if (read_Bools(a, timeBools, zip->numFiles) < 0)
+ if (read_Bools(a, timeBools, (size_t)zip->numFiles) < 0)
goto failed;
}
if (parse_7zip_uint64(a, &(h->dataIndex)) < 0)
goto failed;
if (1000000 < h->dataIndex)
- return (-1);
+ goto failed;
}
for (i = 0; i < zip->numFiles; i++) {
}
/* CRC check. */
- if (crc32(0, (unsigned char *)p + 12, 20) != archive_le32dec(p + 8)) {
+ if (crc32(0, (const unsigned char *)p + 12, 20)
+ != archive_le32dec(p + 8)) {
archive_set_error(&a->archive, -1, "Header CRC error");
return (ARCHIVE_FATAL);
}
}
__archive_read_consume(a, 32);
if (next_header_offset != 0) {
- if (bytes_avail >= next_header_offset)
+ if (bytes_avail >= (ssize_t)next_header_offset)
__archive_read_consume(a, next_header_offset);
else if (__archive_read_seek(a,
next_header_offset + zip->seek_base, SEEK_SET) < 0)
struct _7zip *zip = (struct _7zip *)a->format->data;
ssize_t bytes_avail;
- if (zip->codec == _7Z_COPY && zip->codec2 == -1) {
+ if (zip->codec == _7Z_COPY && zip->codec2 == (unsigned long)-1) {
/* Copy mode. */
/*
ssize_t bytes_avail;
int r;
- if (zip->codec == _7Z_COPY && zip->codec2 == -1) {
+ if (zip->codec == _7Z_COPY && zip->codec2 == (unsigned long)-1) {
if (minimum == 0)
minimum = 1;
if (__archive_read_ahead(a, minimum, &bytes_avail) == NULL
"Truncated 7-Zip file body");
return (ARCHIVE_FATAL);
}
- if (bytes_avail > zip->pack_stream_inbytes_remaining)
- bytes_avail = zip->pack_stream_inbytes_remaining;
+ if (bytes_avail > (ssize_t)zip->pack_stream_inbytes_remaining)
+ bytes_avail = (ssize_t)zip->pack_stream_inbytes_remaining;
zip->pack_stream_inbytes_remaining -= bytes_avail;
- if (bytes_avail > zip->folder_outbytes_remaining)
- bytes_avail = zip->folder_outbytes_remaining;
+ if (bytes_avail > (ssize_t)zip->folder_outbytes_remaining)
+ bytes_avail = (ssize_t)zip->folder_outbytes_remaining;
zip->folder_outbytes_remaining -= bytes_avail;
zip->uncompressed_buffer_bytes_remaining = bytes_avail;
return (ARCHIVE_OK);
size_t bytes_in, bytes_out;
const void *buff_in;
unsigned char *buff_out;
- int eof;
+ int end_of_data;
/*
* Note: '1' here is a performance optimization.
- zip->uncompressed_buffer_bytes_remaining;
bytes_in = bytes_avail;
if (bytes_in > zip->pack_stream_inbytes_remaining)
- bytes_in = zip->pack_stream_inbytes_remaining;
+ bytes_in = (size_t)zip->pack_stream_inbytes_remaining;
/* Drive decompression. */
r = decompress(a, zip, buff_out, &bytes_out,
buff_in, &bytes_in);
switch (r) {
case ARCHIVE_OK:
- eof = 0;
+ end_of_data = 0;
break;
case ARCHIVE_EOF:
- eof = 1;
+ end_of_data = 1;
break;
default:
return (ARCHIVE_FATAL);
}
zip->pack_stream_inbytes_remaining -= bytes_in;
if (bytes_out > zip->folder_outbytes_remaining)
- bytes_out = zip->folder_outbytes_remaining;
+ bytes_out = (size_t)zip->folder_outbytes_remaining;
zip->folder_outbytes_remaining -= bytes_out;
zip->uncompressed_buffer_bytes_remaining += bytes_out;
zip->pack_stream_bytes_unconsumed = bytes_in;
if (zip->pack_stream_inbytes_remaining == 0 &&
zip->folder_outbytes_remaining == 0)
break;
- if (eof || (bytes_in == 0 && bytes_out == 0)) {
+ if (end_of_data || (bytes_in == 0 && bytes_out == 0)) {
archive_set_error(&(a->archive),
ARCHIVE_ERRNO_MISC, "Damaged 7-Zip archive");
return (ARCHIVE_FATAL);
seek_pack(struct archive_read *a)
{
struct _7zip *zip = (struct _7zip *)a->format->data;
- uint64_t pack_offset;
+ int64_t pack_offset;
if (zip->pack_stream_remaining <= 0) {
archive_set_error(&(a->archive),
return (ARCHIVE_FATAL);
}
}
- skipped = get_uncompressed_data(a, buff, skip_bytes, 0);
+ skipped = get_uncompressed_data(
+ a, buff, (size_t)skip_bytes, 0);
if (skipped < 0)
return (skipped);
skip_bytes -= skipped;
}
coder2 = &(fc[3]);
zip->main_stream_bytes_remaining =
- folder->unPackSize[2];
+ (size_t)folder->unPackSize[2];
} else if (coder2 != NULL && coder2->codec == _7Z_X86_BCJ2 &&
zip->pack_stream_remaining == 4 &&
folder->numInStreams == 5 && folder->numOutStreams == 2) {
/* Source type 0 made by 7z */
zip->main_stream_bytes_remaining =
- folder->unPackSize[0];
+ (size_t)folder->unPackSize[0];
} else {
/* We got an unexpected form. */
archive_set_error(&(a->archive),
if ((r = seek_pack(a)) < 0)
return (r);
zip->pack_stream_bytes_unconsumed =
- zip->pack_stream_inbytes_remaining;
+ (size_t)zip->pack_stream_inbytes_remaining;
read_consume(a);
/* Read following three sub streams. */
if ((r = seek_pack(a)) < 0)
return (r);
- if (sunpack[i] == -1)
+ if (sunpack[i] == (uint64_t)-1)
zip->folder_outbytes_remaining =
zip->pack_stream_inbytes_remaining;
else
/* Allocate memory for the decorded data of a sub
* stream. */
- b[i] = malloc(zip->folder_outbytes_remaining);
+ b[i] = malloc((size_t)zip->folder_outbytes_remaining);
if (b[i] == NULL) {
archive_set_error(&a->archive, ENOMEM,
"No memory for 7-Zip decompression");
"Truncated 7-Zip file body");
return (ARCHIVE_FATAL);
}
- bytes -= skipped_bytes;
+ bytes -= (size_t)skipped_bytes;
if (zip->pack_stream_bytes_unconsumed)
read_consume(a);
}
uint32_t dest;
for (;;) {
uint8_t b;
- int index;
+ int b_index;
dest = src - (ip + (uint32_t)bufferPos);
if (prevMask == 0)
break;
- index = kMaskToBitNumber[prevMask] * 8;
- b = (uint8_t)(dest >> (24 - index));
+ b_index = kMaskToBitNumber[prevMask] * 8;
+ b = (uint8_t)(dest >> (24 - b_index));
if (!Test86MSByte(b))
break;
- src = dest ^ ((1 << (32 - index)) - 1);
+ src = dest ^ ((1 << (32 - b_index)) - 1);
}
p[4] = (uint8_t)(~(((dest >> 24) & 1) - 1));
p[3] = (uint8_t)(dest >> 16);
#define RC_READ_BYTE (*buffer++)
#define RC_TEST { if (buffer == bufferLim) return SZ_ERROR_DATA; }
#define RC_INIT2 zip->bcj2_code = 0; zip->bcj2_range = 0xFFFFFFFF; \
- { int i; for (i = 0; i < 5; i++) { RC_TEST; zip->bcj2_code = (zip->bcj2_code << 8) | RC_READ_BYTE; }}
+ { int ii; for (ii = 0; ii < 5; ii++) { RC_TEST; zip->bcj2_code = (zip->bcj2_code << 8) | RC_READ_BYTE; }}
#define NORMALIZE if (zip->bcj2_range < kTopValue) { RC_TEST; zip->bcj2_range <<= 8; zip->bcj2_code = (zip->bcj2_code << 8) | RC_READ_BYTE; }
if (zip->bcj_state == 1) {
while (limit != 0) {
- uint8_t b = buf0[inPos];
- outBuf[outPos++] = b;
- if (IsJ(zip->bcj2_prevByte, b)) {
+ uint8_t bb = buf0[inPos];
+ outBuf[outPos++] = bb;
+ if (IsJ(zip->bcj2_prevByte, bb)) {
zip->bcj_state = 2;
break;
}
inPos++;
- zip->bcj2_prevByte = b;
+ zip->bcj2_prevByte = bb;
limit--;
}
}
/*-
- * Copyright (c) 2010-2011 Michihiro NAKAJIMA
+ * Copyright (c) 2010-2012 Michihiro NAKAJIMA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
char end_of_archive;
char end_of_entry;
char end_of_entry_cleanup;
+ char read_data_invoked;
+ int64_t bytes_skipped;
unsigned char *uncompressed_buffer;
size_t uncompressed_buffer_size;
static int lzx_huffman_init(struct huffman *, size_t, int);
static void lzx_huffman_free(struct huffman *);
static int lzx_make_huffman_table(struct huffman *);
-static int inline lzx_decode_huffman(struct huffman *, unsigned);
+static inline int lzx_decode_huffman(struct huffman *, unsigned);
static int lzx_decode_huffman_tree(struct huffman *, unsigned, int);
else
ret = ARCHIVE_FATAL;
}
- } else
- archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
- "cab: unknown keyword ``%s''", key);
+ return (ret);
+ }
- return (ret);
+ /* Note: The "warn" return is just to inform the options
+ * supervisor that we didn't handle it. It will generate
+ * a suitable error if no one used this option. */
+ return (ARCHIVE_WARN);
}
static int
file->offset = archive_le32dec(p + CFFILE_uoffFolderStart);
file->folder = archive_le16dec(p + CFFILE_iFolder);
file->mtime = cab_dos_time(p + CFFILE_date_time);
- file->attr = archive_le16dec(p + CFFILE_attribs);
+ file->attr = (uint8_t)archive_le16dec(p + CFFILE_attribs);
__archive_read_consume(a, 16);
cab->cab_offset += 16;
if (file->attr & ATTR_RDONLY)
archive_entry_set_mode(entry, AE_IFREG | 0555);
else
- archive_entry_set_mode(entry, AE_IFREG | 0777);
+ archive_entry_set_mode(entry, AE_IFREG | 0666);
archive_entry_set_mtime(entry, file->mtime, 0);
cab->entry_bytes_remaining = file->uncompressed_size;
default:
break;
}
+ if (cab->read_data_invoked == 0) {
+ if (cab->bytes_skipped) {
+ if (cab->entry_cfdata == NULL) {
+ r = cab_next_cfdata(a);
+ if (r < 0)
+ return (r);
+ }
+ if (cab_consume_cfdata(a, cab->bytes_skipped) < 0)
+ return (ARCHIVE_FATAL);
+ cab->bytes_skipped = 0;
+ }
+ cab->read_data_invoked = 1;
+ }
if (cab->entry_unconsumed) {
/* Consume as much as the compressor actually used. */
- r = cab_consume_cfdata(a, cab->entry_unconsumed);
+ r = (int)cab_consume_cfdata(a, cab->entry_unconsumed);
cab->entry_unconsumed = 0;
if (r < 0)
return (r);
struct cab *cab = (struct cab *)(a->format->data);
struct cfdata *cfdata;
const void *d;
- int64_t skipped_bytes;
cfdata = cab->entry_cfdata;
- if (cfdata->uncompressed_avail == 0 &&
- cfdata->read_offset > 0) {
- /* we've already skipped some bytes before really read. */
- skipped_bytes = cfdata->read_offset;
- cfdata->read_offset = 0;
- cfdata->uncompressed_bytes_remaining += skipped_bytes;
- } else
- skipped_bytes = 0;
- do {
- /*
- * Note: '1' here is a performance optimization.
- * Recall that the decompression layer returns a count of
- * available bytes; asking for more than that forces the
- * decompressor to combine reads by copying data.
- */
- d = __archive_read_ahead(a, 1, avail);
- if (*avail <= 0) {
- *avail = truncated_error(a);
- return (NULL);
- }
- if (*avail > cfdata->uncompressed_bytes_remaining)
- *avail = cfdata->uncompressed_bytes_remaining;
- cfdata->uncompressed_avail = cfdata->uncompressed_size;
- cfdata->unconsumed = *avail;
- cfdata->sum_ptr = d;
- if (skipped_bytes > 0) {
- skipped_bytes =
- cab_minimum_consume_cfdata(a, skipped_bytes);
- if (skipped_bytes < 0) {
- *avail = ARCHIVE_FATAL;
- return (NULL);
- }
- continue;
- }
- } while (0);
-
+ /*
+ * Note: '1' here is a performance optimization.
+ * Recall that the decompression layer returns a count of
+ * available bytes; asking for more than that forces the
+ * decompressor to combine reads by copying data.
+ */
+ d = __archive_read_ahead(a, 1, avail);
+ if (*avail <= 0) {
+ *avail = truncated_error(a);
+ return (NULL);
+ }
+ if (*avail > cfdata->uncompressed_bytes_remaining)
+ *avail = cfdata->uncompressed_bytes_remaining;
+ cfdata->uncompressed_avail = cfdata->uncompressed_size;
+ cfdata->unconsumed = *avail;
+ cfdata->sum_ptr = d;
return (d);
}
return (NULL);
}
}
- uavail = cab->stream.total_out;
+ uavail = (uint16_t)cab->stream.total_out;
if (uavail < cfdata->uncompressed_size) {
archive_set_error(&a->archive, ARCHIVE_ERRNO_MISC,
}
}
- uavail = cab->xstrm.total_out;
+ uavail = (uint16_t)cab->xstrm.total_out;
/*
* Make sure a read pointer advances to next CFDATA.
*/
rbytes -= cbytes;
if (cfdata->uncompressed_avail == 0 &&
- (cab->entry_cffolder->comptype == COMPTYPE_NONE ||
- cab->entry_cffile->folder == iFoldCONTINUED_PREV_AND_NEXT ||
- cab->entry_cffile->folder == iFoldCONTINUED_FROM_PREV)) {
+ (cab->entry_cffile->folder == iFoldCONTINUED_PREV_AND_NEXT ||
+ cab->entry_cffile->folder == iFoldCONTINUED_FROM_PREV)) {
/* We have not read any data yet. */
if (cbytes == cfdata->uncompressed_bytes_remaining) {
/* Skip whole current CFDATA. */
}
continue;
}
- cfdata->read_offset += cbytes;
- cfdata->uncompressed_bytes_remaining -= cbytes;
+ cfdata->read_offset += (uint16_t)cbytes;
+ cfdata->uncompressed_bytes_remaining -= (uint16_t)cbytes;
break;
} else if (cbytes == 0) {
err = cab_next_cfdata(a);
if (avail <= 0)
return (ARCHIVE_FATAL);
if (avail > cbytes)
- avail = cbytes;
+ avail = (ssize_t)cbytes;
if (cab_minimum_consume_cfdata(a, avail) < 0)
return (ARCHIVE_FATAL);
cbytes -= avail;
else
cbytes = cfdata->unconsumed;
rbytes -= cbytes;
- cfdata->read_offset += cbytes;
- cfdata->uncompressed_bytes_remaining -= cbytes;
+ cfdata->read_offset += (uint16_t)cbytes;
+ cfdata->uncompressed_bytes_remaining -= (uint16_t)cbytes;
cfdata->unconsumed -= cbytes;
} else {
cbytes = cfdata->uncompressed_avail - cfdata->read_offset;
if (consumed_bytes < cbytes)
cbytes = consumed_bytes;
rbytes -= cbytes;
- cfdata->read_offset += cbytes;
- cfdata->uncompressed_bytes_remaining -= cbytes;
+ cfdata->read_offset += (uint16_t)cbytes;
+ cfdata->uncompressed_bytes_remaining -= (uint16_t)cbytes;
}
if (cfdata->unconsumed) {
}
if (cbytes) {
/* Compute the sum. */
- cab_checksum_update(a, cbytes);
+ cab_checksum_update(a, (size_t)cbytes);
/* Consume as much as the compressor actually used. */
__archive_read_consume(a, cbytes);
cab->cab_offset += cbytes;
- cfdata->compressed_bytes_remaining -= cbytes;
+ cfdata->compressed_bytes_remaining -= (uint16_t)cbytes;
if (cfdata->compressed_bytes_remaining == 0) {
err = cab_checksum_finish(a);
if (err < 0)