diff options
Diffstat (limited to 'contrib/libarchive/libarchive_fe/matching.c')
-rw-r--r-- | contrib/libarchive/libarchive_fe/matching.c | 281 |
1 files changed, 281 insertions, 0 deletions
diff --git a/contrib/libarchive/libarchive_fe/matching.c b/contrib/libarchive/libarchive_fe/matching.c new file mode 100644 index 000000000000..5a4834c190d3 --- /dev/null +++ b/contrib/libarchive/libarchive_fe/matching.c @@ -0,0 +1,281 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "lafe_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 "err.h" +#include "line_reader.h" +#include "matching.h" +#include "pathmatch.h" + +struct match { + struct match *next; + int matches; + char pattern[1]; +}; + +struct lafe_matching { + struct match *exclusions; + int exclusions_count; + struct match *inclusions; + int inclusions_count; + int inclusions_unmatched_count; +}; + +static void add_pattern(struct match **list, const char *pattern); +static void initialize_matching(struct lafe_matching **); +static int match_exclusion(struct match *, const char *pathname); +static int match_inclusion(struct match *, const char *pathname); + +/* + * 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. + */ + +/* + * Utility functions to manage exclusion/inclusion patterns + */ + +int +lafe_exclude(struct lafe_matching **matching, const char *pattern) +{ + + if (*matching == NULL) + initialize_matching(matching); + add_pattern(&((*matching)->exclusions), pattern); + (*matching)->exclusions_count++; + return (0); +} + +int +lafe_exclude_from_file(struct lafe_matching **matching, const char *pathname) +{ + struct lafe_line_reader *lr; + const char *p; + int ret = 0; + + lr = lafe_line_reader(pathname, 0); + while ((p = lafe_line_reader_next(lr)) != NULL) { + if (lafe_exclude(matching, p) != 0) + ret = -1; + } + lafe_line_reader_free(lr); + return (ret); +} + +int +lafe_include(struct lafe_matching **matching, const char *pattern) +{ + + if (*matching == NULL) + initialize_matching(matching); + add_pattern(&((*matching)->inclusions), pattern); + (*matching)->inclusions_count++; + (*matching)->inclusions_unmatched_count++; + return (0); +} + +int +lafe_include_from_file(struct lafe_matching **matching, const char *pathname, + int nullSeparator) +{ + struct lafe_line_reader *lr; + const char *p; + int ret = 0; + + lr = lafe_line_reader(pathname, nullSeparator); + while ((p = lafe_line_reader_next(lr)) != NULL) { + if (lafe_include(matching, p) != 0) + ret = -1; + } + lafe_line_reader_free(lr); + return (ret); +} + +static void +add_pattern(struct match **list, const char *pattern) +{ + struct match *match; + size_t len; + + len = strlen(pattern); + match = malloc(sizeof(*match) + len + 1); + if (match == NULL) + lafe_errc(1, errno, "Out of memory"); + strcpy(match->pattern, pattern); + /* Both "foo/" and "foo" should match "foo/bar". */ + if (len && match->pattern[len - 1] == '/') + match->pattern[len - 1] = '\0'; + match->next = *list; + *list = match; + match->matches = 0; +} + + +int +lafe_excluded(struct lafe_matching *matching, const char *pathname) +{ + struct match *match; + struct match *matched; + + if (matching == 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 = matching->inclusions; match != NULL; match = match->next){ + if (match->matches == 0 + && match_inclusion(match, pathname)) { + matching->inclusions_unmatched_count--; + match->matches++; + matched = match; + } + } + + /* Exclusions take priority */ + for (match = matching->exclusions; match != NULL; match = match->next){ + if (match_exclusion(match, pathname)) + return (1); + } + + /* 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 = matching->inclusions; match != NULL; match = match->next){ + /* We looked at previously-unmatched inclusions already. */ + if (match->matches > 0 + && match_inclusion(match, pathname)) { + match->matches++; + return (0); + } + } + + /* If there were inclusions, default is to exclude. */ + if (matching->inclusions != 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_exclusion(struct match *match, const char *pathname) +{ + return (lafe_pathmatch(match->pattern, + pathname, + PATHMATCH_NO_ANCHOR_START | PATHMATCH_NO_ANCHOR_END)); +} + +/* + * Again, mimic gtar: inclusions are always anchored (have to match + * the beginning of the path) even though exclusions are not anchored. + */ +static int +match_inclusion(struct match *match, const char *pathname) +{ + return (lafe_pathmatch(match->pattern, pathname, PATHMATCH_NO_ANCHOR_END)); +} + +void +lafe_cleanup_exclusions(struct lafe_matching **matching) +{ + struct match *p, *q; + + if (*matching == NULL) + return; + + for (p = (*matching)->inclusions; p != NULL; ) { + q = p; + p = p->next; + free(q); + } + + for (p = (*matching)->exclusions; p != NULL; ) { + q = p; + p = p->next; + free(q); + } + + free(*matching); + *matching = NULL; +} + +static void +initialize_matching(struct lafe_matching **matching) +{ + *matching = calloc(sizeof(**matching), 1); + if (*matching == NULL) + lafe_errc(1, errno, "No memory"); +} + +int +lafe_unmatched_inclusions(struct lafe_matching *matching) +{ + + if (matching == NULL) + return (0); + return (matching->inclusions_unmatched_count); +} + +int +lafe_unmatched_inclusions_warn(struct lafe_matching *matching, const char *msg) +{ + struct match *p; + + if (matching == NULL) + return (0); + + for (p = matching->inclusions; p != NULL; p = p->next) { + if (p->matches == 0) + lafe_warnc(0, "%s: %s", p->pattern, msg); + } + + return (matching->inclusions_unmatched_count); +} |