http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/3781b52f/thirdparty/libarchive-3.3.2/libarchive/archive_match.c
----------------------------------------------------------------------
diff --git a/thirdparty/libarchive-3.3.2/libarchive/archive_match.c b/thirdparty/libarchive-3.3.2/libarchive/archive_match.c
new file mode 100644
index 0000000..be72066
--- /dev/null
+++ b/thirdparty/libarchive-3.3.2/libarchive/archive_match.c
@@ -0,0 +1,1846 @@
+/*-
+ * 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_getdate.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 *);
+
+#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
+}
+
+/*
+ * Utility 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);
+ r = archive_read_support_format_empty(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_read_free(ar);
+ if (r == ARCHIVE_EOF) {
+ return (ARCHIVE_OK);
+ } else {
+ archive_copy_error(&(a->archive), 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 an error occurred, 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_DATAA 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 functions 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
+ (void)rb_ops_wcs;
+ 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 condition.
+ * 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); /* Equal, 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 exclusion 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
+ (void)rb_ops_wcs;
+ 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) {
+ void *p;
+
+ if (ids->size == 0)
+ ids->size = 8;
+ else
+ ids->size *= 2;
+ p = realloc(ids->ids, sizeof(*ids->ids) * ids->size);
+ if (p == NULL)
+ return (error_nomem(a));
+ ids->ids = (int64_t *)p;
+ }
+
+ /* Find an insert point. */
+ for (i = 0; i < ids->count; i++) {
+ if (ids->ids[i] >= id)
+ break;
+ }
+
+ /* Add owner 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 = (unsigned)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);
+}
+
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/3781b52f/thirdparty/libarchive-3.3.2/libarchive/archive_openssl_evp_private.h
----------------------------------------------------------------------
diff --git a/thirdparty/libarchive-3.3.2/libarchive/archive_openssl_evp_private.h b/thirdparty/libarchive-3.3.2/libarchive/archive_openssl_evp_private.h
new file mode 100644
index 0000000..43a3ccc
--- /dev/null
+++ b/thirdparty/libarchive-3.3.2/libarchive/archive_openssl_evp_private.h
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef ARCHIVE_OPENSSL_EVP_PRIVATE_H_INCLUDED
+#define ARCHIVE_OPENSSL_EVP_PRIVATE_H_INCLUDED
+
+#include <openssl/evp.h>
+#include <openssl/opensslv.h>
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+#include <stdlib.h> /* malloc, free */
+#include <string.h> /* memset */
+static inline EVP_MD_CTX *EVP_MD_CTX_new(void)
+{
+ EVP_MD_CTX *ctx = (EVP_MD_CTX *)calloc(1, sizeof(EVP_MD_CTX));
+ return ctx;
+}
+
+static inline void EVP_MD_CTX_free(EVP_MD_CTX *ctx)
+{
+ EVP_MD_CTX_cleanup(ctx);
+ memset(ctx, 0, sizeof(*ctx));
+ free(ctx);
+}
+#endif
+
+#endif
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/3781b52f/thirdparty/libarchive-3.3.2/libarchive/archive_openssl_hmac_private.h
----------------------------------------------------------------------
diff --git a/thirdparty/libarchive-3.3.2/libarchive/archive_openssl_hmac_private.h b/thirdparty/libarchive-3.3.2/libarchive/archive_openssl_hmac_private.h
new file mode 100644
index 0000000..59f95b8
--- /dev/null
+++ b/thirdparty/libarchive-3.3.2/libarchive/archive_openssl_hmac_private.h
@@ -0,0 +1,48 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef ARCHIVE_OPENSSL_HMAC_PRIVATE_H_INCLUDED
+#define ARCHIVE_OPENSSL_HMAC_PRIVATE_H_INCLUDED
+
+#include <openssl/hmac.h>
+#include <openssl/opensslv.h>
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+#include <stdlib.h> /* malloc, free */
+#include <string.h> /* memset */
+static inline HMAC_CTX *HMAC_CTX_new(void)
+{
+ HMAC_CTX *ctx = (HMAC_CTX *)calloc(1, sizeof(HMAC_CTX));
+ return ctx;
+}
+
+static inline void HMAC_CTX_free(HMAC_CTX *ctx)
+{
+ HMAC_CTX_cleanup(ctx);
+ memset(ctx, 0, sizeof(*ctx));
+ free(ctx);
+}
+#endif
+
+#endif
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/3781b52f/thirdparty/libarchive-3.3.2/libarchive/archive_options.c
----------------------------------------------------------------------
diff --git a/thirdparty/libarchive-3.3.2/libarchive/archive_options.c b/thirdparty/libarchive-3.3.2/libarchive/archive_options.c
new file mode 100644
index 0000000..6496025
--- /dev/null
+++ b/thirdparty/libarchive-3.3.2/libarchive/archive_options.c
@@ -0,0 +1,218 @@
+/*-
+ * Copyright (c) 2011 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#include "archive_options_private.h"
+
+static const char *
+parse_option(const char **str,
+ const char **mod, const char **opt, const char **val);
+
+int
+_archive_set_option(struct archive *a,
+ const char *m, const char *o, const char *v,
+ 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);
+
+ mp = (m != NULL && m[0] != '\0') ? m : NULL;
+ op = (o != NULL && o[0] != '\0') ? o : NULL;
+ vp = (v != NULL && v[0] != '\0') ? v : NULL;
+
+ if (op == NULL && vp == NULL)
+ return (ARCHIVE_OK);
+ if (op == NULL) {
+ archive_set_error(a, ARCHIVE_ERRNO_MISC, "Empty option");
+ return (ARCHIVE_FAILED);
+ }
+
+ 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
+_archive_set_either_option(struct archive *a, const char *m, const char *o, const char *v,
+ option_handler use_format_option, option_handler use_filter_option)
+{
+ int r1, r2;
+
+ if (o == NULL && v == NULL)
+ return (ARCHIVE_OK);
+ if (o == NULL)
+ return (ARCHIVE_FAILED);
+
+ r1 = use_format_option(a, m, o, v);
+ if (r1 == ARCHIVE_FATAL)
+ return (ARCHIVE_FATAL);
+
+ r2 = use_filter_option(a, m, o, v);
+ if (r2 == ARCHIVE_FATAL)
+ return (ARCHIVE_FATAL);
+
+ if (r2 == ARCHIVE_WARN - 1)
+ return r1;
+ return r1 > r2 ? r1 : r2;
+}
+
+int
+_archive_set_options(struct archive *a, const char *options,
+ int magic, const char *fn, option_handler use_option)
+{
+ int allok = 1, anyok = 0, ignore_mod_err = 0, r;
+ char *data;
+ const char *s, *mod, *opt, *val;
+
+ archive_check_magic(a, magic, ARCHIVE_STATE_NEW, fn);
+
+ if (options == NULL || options[0] == '\0')
+ return ARCHIVE_OK;
+
+ if ((data = strdup(options)) == NULL) {
+ archive_set_error(a,
+ ENOMEM, "Out of memory adding file to list");
+ return (ARCHIVE_FATAL);
+ }
+ s = (const char *)data;
+
+ do {
+ mod = opt = val = NULL;
+
+ parse_option(&s, &mod, &opt, &val);
+ if (mod == NULL && opt != NULL &&
+ strcmp("__ignore_wrong_module_name__", opt) == 0) {
+ /* Ignore module name error */
+ if (val != NULL) {
+ ignore_mod_err = 1;
+ anyok = 1;
+ }
+ continue;
+ }
+
+ r = use_option(a, mod, opt, val);
+ if (r == ARCHIVE_FATAL) {
+ free(data);
+ return (ARCHIVE_FATAL);
+ }
+ if (r == ARCHIVE_FAILED && mod != NULL) {
+ free(data);
+ return (ARCHIVE_FAILED);
+ }
+ if (r == ARCHIVE_WARN - 1) {
+ if (ignore_mod_err)
+ continue;
+ /* 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
+ allok = 0;
+ } while (s != NULL);
+
+ free(data);
+ return allok ? ARCHIVE_OK : anyok ? ARCHIVE_WARN : ARCHIVE_FAILED;
+}
+
+static const char *
+parse_option(const char **s, const char **m, const char **o, const char **v)
+{
+ const char *end, *mod, *opt, *val;
+ char *p;
+
+ end = NULL;
+ mod = NULL;
+ opt = *s;
+ val = "1";
+
+ p = strchr(opt, ',');
+
+ if (p != NULL) {
+ *p = '\0';
+ end = ((const char *)p) + 1;
+ }
+
+ if (0 == strlen(opt)) {
+ *s = end;
+ *m = NULL;
+ *o = NULL;
+ *v = NULL;
+ return end;
+ }
+
+ p = strchr(opt, ':');
+ if (p != NULL) {
+ *p = '\0';
+ mod = opt;
+ opt = ++p;
+ }
+
+ p = strchr(opt, '=');
+ if (p != NULL) {
+ *p = '\0';
+ val = ++p;
+ } else if (opt[0] == '!') {
+ ++opt;
+ val = NULL;
+ }
+
+ *s = end;
+ *m = mod;
+ *o = opt;
+ *v = val;
+
+ return end;
+}
+
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/3781b52f/thirdparty/libarchive-3.3.2/libarchive/archive_options_private.h
----------------------------------------------------------------------
diff --git a/thirdparty/libarchive-3.3.2/libarchive/archive_options_private.h b/thirdparty/libarchive-3.3.2/libarchive/archive_options_private.h
new file mode 100644
index 0000000..6ef0165
--- /dev/null
+++ b/thirdparty/libarchive-3.3.2/libarchive/archive_options_private.h
@@ -0,0 +1,47 @@
+/*-
+ * Copyright (c) 2011 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#include "archive_private.h"
+
+typedef int (*option_handler)(struct archive *a,
+ const char *mod, const char *opt, const char *val);
+
+int
+_archive_set_option(struct archive *a,
+ const char *mod, const char *opt, const char *val,
+ int magic, const char *fn, option_handler use_option);
+
+int
+_archive_set_options(struct archive *a, const char *options,
+ int magic, const char *fn, option_handler use_option);
+
+int
+_archive_set_either_option(struct archive *a,
+ const char *m, const char *o, const char *v,
+ option_handler use_format_option, option_handler use_filter_option);
+
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/3781b52f/thirdparty/libarchive-3.3.2/libarchive/archive_pack_dev.c
----------------------------------------------------------------------
diff --git a/thirdparty/libarchive-3.3.2/libarchive/archive_pack_dev.c b/thirdparty/libarchive-3.3.2/libarchive/archive_pack_dev.c
new file mode 100644
index 0000000..098881b
--- /dev/null
+++ b/thirdparty/libarchive-3.3.2/libarchive/archive_pack_dev.c
@@ -0,0 +1,329 @@
+/* $NetBSD: pack_dev.c,v 1.12 2013/06/14 16:28:20 tsutsui Exp $ */
+
+/*-
+ * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Charles M. Hannum.
+ *
+ * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Originally from NetBSD's mknod(8) source. */
+
+#include "archive_platform.h"
+
+#if HAVE_SYS_CDEFS_H
+#include <sys/cdefs.h>
+#endif
+#if !defined(lint)
+__RCSID("$NetBSD$");
+#endif /* not lint */
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#include <stdio.h>
+#ifdef HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "archive_pack_dev.h"
+
+static pack_t pack_netbsd;
+static pack_t pack_freebsd;
+static pack_t pack_8_8;
+static pack_t pack_12_20;
+static pack_t pack_14_18;
+static pack_t pack_8_24;
+static pack_t pack_bsdos;
+static int compare_format(const void *, const void *);
+
+static const char iMajorError[] = "invalid major number";
+static const char iMinorError[] = "invalid minor number";
+static const char tooManyFields[] = "too many fields for format";
+
+/* This is blatantly stolen from libarchive/archive_entry.c,
+ * in an attempt to get this to play nice on MinGW... */
+#if !defined(HAVE_MAJOR) && !defined(major)
+/* Replacement for major/minor/makedev. */
+#define major(x) ((int)(0x00ff & ((x) >> 8)))
+#define minor(x) ((int)(0xffff00ff & (x)))
+#define makedev(maj,min) ((0xff00 & ((maj)<<8)) | (0xffff00ff & (min)))
+#endif
+
+/* Play games to come up with a suitable makedev() definition. */
+#ifdef __QNXNTO__
+/* QNX. <sigh> */
+#include <sys/netmgr.h>
+#define apd_makedev(maj, min) makedev(ND_LOCAL_NODE, (maj), (min))
+#elif defined makedev
+/* There's a "makedev" macro. */
+#define apd_makedev(maj, min) makedev((maj), (min))
+#elif defined mkdev || ((defined _WIN32 || defined __WIN32__) && !defined(__CYGWIN__))
+/* Windows. <sigh> */
+#define apd_makedev(maj, min) mkdev((maj), (min))
+#else
+/* There's a "makedev" function. */
+#define apd_makedev(maj, min) makedev((maj), (min))
+#endif
+
+/* exported */
+dev_t
+pack_native(int n, unsigned long numbers[], const char **error)
+{
+ dev_t dev = 0;
+
+ if (n == 2) {
+ dev = apd_makedev(numbers[0], numbers[1]);
+ if ((unsigned long)major(dev) != numbers[0])
+ *error = iMajorError;
+ else if ((unsigned long)minor(dev) != numbers[1])
+ *error = iMinorError;
+ } else
+ *error = tooManyFields;
+ return (dev);
+}
+
+
+static dev_t
+pack_netbsd(int n, unsigned long numbers[], const char **error)
+{
+ dev_t dev = 0;
+
+ if (n == 2) {
+ dev = makedev_netbsd(numbers[0], numbers[1]);
+ if ((unsigned long)major_netbsd(dev) != numbers[0])
+ *error = iMajorError;
+ else if ((unsigned long)minor_netbsd(dev) != numbers[1])
+ *error = iMinorError;
+ } else
+ *error = tooManyFields;
+ return (dev);
+}
+
+
+#define major_freebsd(x) ((int32_t)(((x) & 0x0000ff00) >> 8))
+#define minor_freebsd(x) ((int32_t)(((x) & 0xffff00ff) >> 0))
+#define makedev_freebsd(x,y) ((dev_t)((((x) << 8) & 0x0000ff00) | \
+ (((y) << 0) & 0xffff00ff)))
+
+static dev_t
+pack_freebsd(int n, unsigned long numbers[], const char **error)
+{
+ dev_t dev = 0;
+
+ if (n == 2) {
+ dev = makedev_freebsd(numbers[0], numbers[1]);
+ if ((unsigned long)major_freebsd(dev) != numbers[0])
+ *error = iMajorError;
+ if ((unsigned long)minor_freebsd(dev) != numbers[1])
+ *error = iMinorError;
+ } else
+ *error = tooManyFields;
+ return (dev);
+}
+
+
+#define major_8_8(x) ((int32_t)(((x) & 0x0000ff00) >> 8))
+#define minor_8_8(x) ((int32_t)(((x) & 0x000000ff) >> 0))
+#define makedev_8_8(x,y) ((dev_t)((((x) << 8) & 0x0000ff00) | \
+ (((y) << 0) & 0x000000ff)))
+
+static dev_t
+pack_8_8(int n, unsigned long numbers[], const char **error)
+{
+ dev_t dev = 0;
+
+ if (n == 2) {
+ dev = makedev_8_8(numbers[0], numbers[1]);
+ if ((unsigned long)major_8_8(dev) != numbers[0])
+ *error = iMajorError;
+ if ((unsigned long)minor_8_8(dev) != numbers[1])
+ *error = iMinorError;
+ } else
+ *error = tooManyFields;
+ return (dev);
+}
+
+
+#define major_12_20(x) ((int32_t)(((x) & 0xfff00000) >> 20))
+#define minor_12_20(x) ((int32_t)(((x) & 0x000fffff) >> 0))
+#define makedev_12_20(x,y) ((dev_t)((((x) << 20) & 0xfff00000) | \
+ (((y) << 0) & 0x000fffff)))
+
+static dev_t
+pack_12_20(int n, unsigned long numbers[], const char **error)
+{
+ dev_t dev = 0;
+
+ if (n == 2) {
+ dev = makedev_12_20(numbers[0], numbers[1]);
+ if ((unsigned long)major_12_20(dev) != numbers[0])
+ *error = iMajorError;
+ if ((unsigned long)minor_12_20(dev) != numbers[1])
+ *error = iMinorError;
+ } else
+ *error = tooManyFields;
+ return (dev);
+}
+
+
+#define major_14_18(x) ((int32_t)(((x) & 0xfffc0000) >> 18))
+#define minor_14_18(x) ((int32_t)(((x) & 0x0003ffff) >> 0))
+#define makedev_14_18(x,y) ((dev_t)((((x) << 18) & 0xfffc0000) | \
+ (((y) << 0) & 0x0003ffff)))
+
+static dev_t
+pack_14_18(int n, unsigned long numbers[], const char **error)
+{
+ dev_t dev = 0;
+
+ if (n == 2) {
+ dev = makedev_14_18(numbers[0], numbers[1]);
+ if ((unsigned long)major_14_18(dev) != numbers[0])
+ *error = iMajorError;
+ if ((unsigned long)minor_14_18(dev) != numbers[1])
+ *error = iMinorError;
+ } else
+ *error = tooManyFields;
+ return (dev);
+}
+
+
+#define major_8_24(x) ((int32_t)(((x) & 0xff000000) >> 24))
+#define minor_8_24(x) ((int32_t)(((x) & 0x00ffffff) >> 0))
+#define makedev_8_24(x,y) ((dev_t)((((x) << 24) & 0xff000000) | \
+ (((y) << 0) & 0x00ffffff)))
+
+static dev_t
+pack_8_24(int n, unsigned long numbers[], const char **error)
+{
+ dev_t dev = 0;
+
+ if (n == 2) {
+ dev = makedev_8_24(numbers[0], numbers[1]);
+ if ((unsigned long)major_8_24(dev) != numbers[0])
+ *error = iMajorError;
+ if ((unsigned long)minor_8_24(dev) != numbers[1])
+ *error = iMinorError;
+ } else
+ *error = tooManyFields;
+ return (dev);
+}
+
+
+#define major_12_12_8(x) ((int32_t)(((x) & 0xfff00000) >> 20))
+#define unit_12_12_8(x) ((int32_t)(((x) & 0x000fff00) >> 8))
+#define subunit_12_12_8(x) ((int32_t)(((x) & 0x000000ff) >> 0))
+#define makedev_12_12_8(x,y,z) ((dev_t)((((x) << 20) & 0xfff00000) | \
+ (((y) << 8) & 0x000fff00) | \
+ (((z) << 0) & 0x000000ff)))
+
+static dev_t
+pack_bsdos(int n, unsigned long numbers[], const char **error)
+{
+ dev_t dev = 0;
+
+ if (n == 2) {
+ dev = makedev_12_20(numbers[0], numbers[1]);
+ if ((unsigned long)major_12_20(dev) != numbers[0])
+ *error = iMajorError;
+ if ((unsigned long)minor_12_20(dev) != numbers[1])
+ *error = iMinorError;
+ } else if (n == 3) {
+ dev = makedev_12_12_8(numbers[0], numbers[1], numbers[2]);
+ if ((unsigned long)major_12_12_8(dev) != numbers[0])
+ *error = iMajorError;
+ if ((unsigned long)unit_12_12_8(dev) != numbers[1])
+ *error = "invalid unit number";
+ if ((unsigned long)subunit_12_12_8(dev) != numbers[2])
+ *error = "invalid subunit number";
+ } else
+ *error = tooManyFields;
+ return (dev);
+}
+
+
+ /* list of formats and pack functions */
+ /* this list must be sorted lexically */
+static const struct format {
+ const char *name;
+ pack_t *pack;
+} formats[] = {
+ {"386bsd", pack_8_8},
+ {"4bsd", pack_8_8},
+ {"bsdos", pack_bsdos},
+ {"freebsd", pack_freebsd},
+ {"hpux", pack_8_24},
+ {"isc", pack_8_8},
+ {"linux", pack_8_8},
+ {"native", pack_native},
+ {"netbsd", pack_netbsd},
+ {"osf1", pack_12_20},
+ {"sco", pack_8_8},
+ {"solaris", pack_14_18},
+ {"sunos", pack_8_8},
+ {"svr3", pack_8_8},
+ {"svr4", pack_14_18},
+ {"ultrix", pack_8_8},
+};
+
+static int
+compare_format(const void *key, const void *element)
+{
+ const char *name;
+ const struct format *format;
+
+ name = key;
+ format = element;
+
+ return (strcmp(name, format->name));
+}
+
+
+pack_t *
+pack_find(const char *name)
+{
+ struct format *format;
+
+ format = bsearch(name, formats,
+ sizeof(formats)/sizeof(formats[0]),
+ sizeof(formats[0]), compare_format);
+ if (format == 0)
+ return (NULL);
+ return (format->pack);
+}
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/3781b52f/thirdparty/libarchive-3.3.2/libarchive/archive_pack_dev.h
----------------------------------------------------------------------
diff --git a/thirdparty/libarchive-3.3.2/libarchive/archive_pack_dev.h b/thirdparty/libarchive-3.3.2/libarchive/archive_pack_dev.h
new file mode 100644
index 0000000..749fd3d
--- /dev/null
+++ b/thirdparty/libarchive-3.3.2/libarchive/archive_pack_dev.h
@@ -0,0 +1,49 @@
+/* $NetBSD: pack_dev.h,v 1.8 2013/06/14 16:28:20 tsutsui Exp $ */
+
+/*-
+ * Copyright (c) 1998, 2001 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Charles M. Hannum.
+ *
+ * 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 NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Originally from NetBSD's mknod(8) source. */
+
+#ifndef _PACK_DEV_H
+#define _PACK_DEV_H
+
+typedef dev_t pack_t(int, unsigned long [], const char **);
+
+pack_t *pack_find(const char *);
+pack_t pack_native;
+
+#define major_netbsd(x) ((int32_t)((((x) & 0x000fff00) >> 8)))
+#define minor_netbsd(x) ((int32_t)((((x) & 0xfff00000) >> 12) | \
+ (((x) & 0x000000ff) >> 0)))
+#define makedev_netbsd(x,y) ((dev_t)((((x) << 8) & 0x000fff00) | \
+ (((y) << 12) & 0xfff00000) | \
+ (((y) << 0) & 0x000000ff)))
+
+#endif /* _PACK_DEV_H */
http://git-wip-us.apache.org/repos/asf/nifi-minifi-cpp/blob/3781b52f/thirdparty/libarchive-3.3.2/libarchive/archive_pathmatch.c
----------------------------------------------------------------------
diff --git a/thirdparty/libarchive-3.3.2/libarchive/archive_pathmatch.c b/thirdparty/libarchive-3.3.2/libarchive/archive_pathmatch.c
new file mode 100644
index 0000000..619e2b6
--- /dev/null
+++ b/thirdparty/libarchive-3.3.2/libarchive/archive_pathmatch.c
@@ -0,0 +1,459 @@
+/*-
+ * Copyright (c) 2003-2007 Tim Kientzle
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer
+ * in this position and unchanged.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "archive_platform.h"
+__FBSDID("$FreeBSD$");
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+#ifdef HAVE_WCHAR_H
+#include <wchar.h>
+#endif
+
+#include "archive_pathmatch.h"
+
+/*
+ * Check whether a character 'c' is matched by a list specification [...]:
+ * * Leading '!' or '^' negates the class.
+ * * <char>-<char> is a range of characters
+ * * \<char> removes any special meaning for <char>
+ *
+ * Some interesting boundary cases:
+ * a-d-e is one range (a-d) followed by two single characters - and e.
+ * \a-\d is same as a-d
+ * a\-d is three single characters: a, d, -
+ * Trailing - is not special (so [a-] is two characters a and -).
+ * Initial - is not special ([a-] is same as [-a] is same as [\\-a])
+ * This function never sees a trailing \.
+ * [] always fails
+ * [!] always succeeds
+ */
+static int
+pm_list(const char *start, const char *end, const char c, int flags)
+{
+ const char *p = start;
+ char rangeStart = '\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 == '!' || *p == '^') && p < end) {
+ match = 0;
+ nomatch = 1;
+ ++p;
+ }
+
+ while (p < end) {
+ nextRangeStart = '\0';
+ switch (*p) {
+ case '-':
+ /* Trailing or initial '-' is not special. */
+ if ((rangeStart == '\0') || (p == end - 1)) {
+ if (*p == c)
+ return (match);
+ } else {
+ char rangeEnd = *++p;
+ if (rangeEnd == '\\')
+ rangeEnd = *++p;
+ if ((rangeStart <= c) && (c <= rangeEnd))
+ return (match);
+ }
+ break;
+ case '\\':
+ ++p;
+ /* Fall through */
+ default:
+ if (*p == c)
+ return (match);
+ nextRangeStart = *p; /* Possible start of range. */
+ }
+ rangeStart = nextRangeStart;
+ ++p;
+ }
+ 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.
+ */
+static const char *
+pm_slashskip(const char *s) {
+ while ((*s == '/')
+ || (s[0] == '.' && s[1] == '/')
+ || (s[0] == '.' && s[1] == '\0'))
+ ++s;
+ 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)
+{
+ const char *end;
+
+ /*
+ * Ignore leading './', './/', '././', etc.
+ */
+ if (s[0] == '.' && s[1] == '/')
+ s = pm_slashskip(s + 1);
+ if (p[0] == '.' && p[1] == '/')
+ p = pm_slashskip(p + 1);
+
+ for (;;) {
+ switch (*p) {
+ case '\0':
+ if (s[0] == '/') {
+ if (flags & PATHMATCH_NO_ANCHOR_END)
+ return (1);
+ /* "dir" == "dir/" == "dir/." */
+ s = pm_slashskip(s);
+ }
+ return (*s == '\0');
+ case '?':
+ /* ? always succeeds, unless we hit end of 's' */
+ if (*s == '\0')
+ return (0);
+ break;
+ case '*':
+ /* "*" == "**" == "***" ... */
+ while (*p == '*')
+ ++p;
+ /* Trailing '*' always succeeds. */
+ if (*p == '\0')
+ return (1);
+ while (*s) {
+ if (archive_pathmatch(p, s, flags))
+ return (1);
+ ++s;
+ }
+ return (0);
+ case '[':
+ /*
+ * Find the end of the [...] character class,
+ * ignoring \] that might occur within the class.
+ */
+ end = p + 1;
+ while (*end != '\0' && *end != ']') {
+ if (*end == '\\' && end[1] != '\0')
+ ++end;
+ ++end;
+ }
+ if (*end == ']') {
+ /* We found [...], try to match it. */
+ if (!pm_list(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 '\\':
+ /* Trailing '\\' matches itself. */
+ if (p[1] == '\0') {
+ if (*s != '\\')
+ return (0);
+ } else {
+ ++p;
+ if (*p != *s)
+ return (0);
+ }
+ break;
+ case '/':
+ if (*s != '/' && *s != '\0')
+ return (0);
+ /* Note: pattern "/\./" won't match "/";
+ * pm_slashskip() correctly stops at backslash. */
+ p = pm_slashskip(p);
+ s = pm_slashskip(s);
+ if (*p == '\0' && (flags & PATHMATCH_NO_ANCHOR_END))
+ return (1);
+ --p; /* Counteract the increment below. */
+ --s;
+ break;
+ case '$':
+ /* '$' is special only at end of pattern and only
+ * if PATHMATCH_NO_ANCHOR_END is specified. */
+ if (p[1] == '\0' && (flags & PATHMATCH_NO_ANCHOR_END)){
+ /* "dir" == "dir/" == "dir/." */
+ return (*pm_slashskip(s) == '\0');
+ }
+ /* Otherwise, '$' is not special. */
+ /* FALL THROUGH */
+ default:
+ if (*p != *s)
+ return (0);
+ break;
+ }
+ ++p;
+ ++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
+__archive_pathmatch(const char *p, const char *s, int flags)
+{
+ /* Empty pattern only matches the empty string. */
+ if (p == NULL || *p == '\0')
+ return (s == NULL || *s == '\0');
+
+ /* Leading '^' anchors the start of the pattern. */
+ if (*p == '^') {
+ ++p;
+ flags &= ~PATHMATCH_NO_ANCHOR_START;
+ }
+
+ if (*p == '/' && *s != '/')
+ return (0);
+
+ /* Certain patterns anchor implicitly. */
+ if (*p == '*' || *p == '/') {
+ while (*p == '/')
+ ++p;
+ while (*s == '/')
+ ++s;
+ return (pm(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 = strchr(s, '/')) {
+ if (*s == '/')
+ s++;
+ if (pm(p, s, flags))
+ return (1);
+ }
+ return (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 anchor implicitly. */
+ if (*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));
+}
|