summaryrefslogtreecommitdiffstats
path: root/usr.bin/tar/matching.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/tar/matching.c')
-rw-r--r--usr.bin/tar/matching.c364
1 files changed, 83 insertions, 281 deletions
diff --git a/usr.bin/tar/matching.c b/usr.bin/tar/matching.c
index 36bc84b..184d29a 100644
--- a/usr.bin/tar/matching.c
+++ b/usr.bin/tar/matching.c
@@ -36,7 +36,10 @@ __FBSDID("$FreeBSD$");
#include <string.h>
#endif
-#include "bsdtar.h"
+#include "err.h"
+#include "line_reader.h"
+#include "matching.h"
+#include "pathmatch.h"
struct match {
struct match *next;
@@ -44,7 +47,7 @@ struct match {
char pattern[1];
};
-struct matching {
+struct lafe_matching {
struct match *exclusions;
int exclusions_count;
struct match *inclusions;
@@ -52,14 +55,10 @@ struct matching {
int inclusions_unmatched_count;
};
-
-static void add_pattern(struct bsdtar *, struct match **list,
- const char *pattern);
-static int bsdtar_fnmatch(const char *p, const char *s);
-static void initialize_matching(struct bsdtar *);
+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);
-static int pathmatch(const char *p, const char *s);
/*
* The matching logic here needs to be re-thought. I started out to
@@ -73,55 +72,74 @@ static int pathmatch(const char *p, const char *s);
*/
int
-exclude(struct bsdtar *bsdtar, const char *pattern)
+lafe_exclude(struct lafe_matching **matching, const char *pattern)
{
- struct matching *matching;
- if (bsdtar->matching == NULL)
- initialize_matching(bsdtar);
- matching = bsdtar->matching;
- add_pattern(bsdtar, &(matching->exclusions), pattern);
- matching->exclusions_count++;
+ if (*matching == NULL)
+ initialize_matching(matching);
+ add_pattern(&((*matching)->exclusions), pattern);
+ (*matching)->exclusions_count++;
return (0);
}
int
-exclude_from_file(struct bsdtar *bsdtar, const char *pathname)
+lafe_exclude_from_file(struct lafe_matching **matching, const char *pathname)
{
- return (process_lines(bsdtar, pathname, &exclude));
+ struct lafe_line_reader *lr;
+ const char *p;
+ int ret = 0;
+
+ lr = lafe_line_reader(pathname, '\n');
+ while ((p = lafe_line_reader_next(lr)) != NULL) {
+ if (lafe_exclude(matching, p) != 0)
+ ret = -1;
+ }
+ lafe_line_reader_free(lr);
+ return (ret);
}
int
-include(struct bsdtar *bsdtar, const char *pattern)
+lafe_include(struct lafe_matching **matching, const char *pattern)
{
- struct matching *matching;
-
- if (bsdtar->matching == NULL)
- initialize_matching(bsdtar);
- matching = bsdtar->matching;
- add_pattern(bsdtar, &(matching->inclusions), pattern);
- matching->inclusions_count++;
- matching->inclusions_unmatched_count++;
+
+ if (*matching == NULL)
+ initialize_matching(matching);
+ add_pattern(&((*matching)->inclusions), pattern);
+ (*matching)->inclusions_count++;
+ (*matching)->inclusions_unmatched_count++;
return (0);
}
int
-include_from_file(struct bsdtar *bsdtar, const char *pathname)
+lafe_include_from_file(struct lafe_matching **matching, const char *pathname,
+ int nullSeparator)
{
- return (process_lines(bsdtar, pathname, &include));
+ 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 bsdtar *bsdtar, struct match **list, const char *pattern)
+add_pattern(struct match **list, const char *pattern)
{
struct match *match;
+ size_t len;
- match = malloc(sizeof(*match) + strlen(pattern) + 1);
+ len = strlen(pattern);
+ match = malloc(sizeof(*match) + len + 1);
if (match == NULL)
- bsdtar_errc(bsdtar, 1, errno, "Out of memory");
+ bsdtar_errc(1, errno, "Out of memory");
strcpy(match->pattern, pattern);
/* Both "foo/" and "foo" should match "foo/bar". */
- if (match->pattern[strlen(match->pattern)-1] == '/')
+ if (len && match->pattern[len - 1] == '/')
match->pattern[strlen(match->pattern)-1] = '\0';
match->next = *list;
*list = match;
@@ -130,13 +148,11 @@ add_pattern(struct bsdtar *bsdtar, struct match **list, const char *pattern)
int
-excluded(struct bsdtar *bsdtar, const char *pathname)
+lafe_excluded(struct lafe_matching *matching, const char *pathname)
{
- struct matching *matching;
struct match *match;
struct match *matched;
- matching = bsdtar->matching;
if (matching == NULL)
return (0);
@@ -191,288 +207,74 @@ excluded(struct bsdtar *bsdtar, const char *pathname)
static int
match_exclusion(struct match *match, const char *pathname)
{
- const char *p;
-
- if (*match->pattern == '*' || *match->pattern == '/')
- return (pathmatch(match->pattern, pathname) == 0);
-
- for (p = pathname; p != NULL; p = strchr(p, '/')) {
- if (*p == '/')
- p++;
- if (pathmatch(match->pattern, p) == 0)
- return (1);
- }
- return (0);
+ 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.
*/
-int
+static int
match_inclusion(struct match *match, const char *pathname)
{
- return (pathmatch(match->pattern, pathname) == 0);
+ return (lafe_pathmatch(match->pattern, pathname, PATHMATCH_NO_ANCHOR_END));
}
void
-cleanup_exclusions(struct bsdtar *bsdtar)
+lafe_cleanup_exclusions(struct lafe_matching **matching)
{
struct match *p, *q;
- if (bsdtar->matching) {
- p = bsdtar->matching->inclusions;
- while (p != NULL) {
- q = p;
- p = p->next;
- free(q);
- }
- p = bsdtar->matching->exclusions;
- while (p != NULL) {
- q = p;
- p = p->next;
- free(q);
- }
- free(bsdtar->matching);
+ 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 bsdtar *bsdtar)
+initialize_matching(struct lafe_matching **matching)
{
- bsdtar->matching = malloc(sizeof(*bsdtar->matching));
- if (bsdtar->matching == NULL)
- bsdtar_errc(bsdtar, 1, errno, "No memory");
- memset(bsdtar->matching, 0, sizeof(*bsdtar->matching));
+ *matching = calloc(sizeof(**matching), 1);
+ if (*matching == NULL)
+ bsdtar_errc(1, errno, "No memory");
}
int
-unmatched_inclusions(struct bsdtar *bsdtar)
+lafe_unmatched_inclusions(struct lafe_matching *matching)
{
- struct matching *matching;
- matching = bsdtar->matching;
if (matching == NULL)
return (0);
return (matching->inclusions_unmatched_count);
}
-
int
-unmatched_inclusions_warn(struct bsdtar *bsdtar, const char *msg)
+lafe_unmatched_inclusions_warn(struct lafe_matching *matching, const char *msg)
{
- struct matching *matching;
struct match *p;
- matching = bsdtar->matching;
if (matching == NULL)
return (0);
- p = matching->inclusions;
- while (p != NULL) {
- if (p->matches == 0) {
- bsdtar->return_value = 1;
- bsdtar_warnc(bsdtar, 0, "%s: %s",
- p->pattern, msg);
- }
- p = p->next;
- }
- return (matching->inclusions_unmatched_count);
-}
-
-/*
- * TODO: Extend this so that the following matches work:
- * "foo//bar" == "foo/bar"
- * "foo/./bar" == "foo/bar"
- * "./foo" == "foo"
- *
- * The POSIX fnmatch() function doesn't handle any of these, but
- * all are common situations that arise when paths are generated within
- * large scripts. E.g., the following is quite common:
- * MYPATH=foo/ TARGET=$MYPATH/bar
- * It may be worthwhile to edit such paths at write time as well,
- * especially when such editing may avoid the need for long pathname
- * extensions.
- */
-static int
-pathmatch(const char *pattern, const char *string)
-{
- /*
- * Strip leading "./" or ".//" so that, e.g.,
- * "foo" matches "./foo". In particular, this
- * opens up an optimization for the writer to
- * elide leading "./".
- */
- if (pattern[0] == '.' && pattern[1] == '/') {
- pattern += 2;
- while (pattern[0] == '/')
- ++pattern;
+ for (p = matching->inclusions; p != NULL; p = p->next) {
+ if (p->matches == 0)
+ bsdtar_warnc(0, "%s: %s", p->pattern, msg);
}
- if (string[0] == '.' && string[1] == '/') {
- string += 2;
- while (string[0] == '/')
- ++string;
- }
- return (bsdtar_fnmatch(pattern, string));
-}
-
-#if defined(HAVE_FNMATCH) && defined(HAVE_FNM_LEADING_DIR)
-
-/* Use system fnmatch() if it suits our needs. */
-/* On Linux, _GNU_SOURCE must be defined to get FNM_LEADING_DIR. */
-#define _GNU_SOURCE
-#include <fnmatch.h>
-static int
-bsdtar_fnmatch(const char *pattern, const char *string)
-{
- return (fnmatch(pattern, string, FNM_LEADING_DIR));
-}
-
-#else
-/*
- * The following was hacked from BSD C library
- * code: src/lib/libc/gen/fnmatch.c,v 1.15 2002/02/01
- *
- * In particular, most of the flags were ripped out: this always
- * behaves like FNM_LEADING_DIR is set and other flags specified
- * by POSIX are unset.
- *
- * Normally, I would not conditionally compile something like this: If
- * I have to support it anyway, everyone may as well use it. ;-)
- * However, the full POSIX spec for fnmatch() includes a lot of
- * advanced character handling that I'm not ready to put in here, so
- * it's probably best if people use a local version when it's available.
- */
-
-/*
- * Copyright (c) 1989, 1993, 1994
- * The Regents of the University of California. All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Guido van Rossum.
- *
- * 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.
- * 4. Neither the name of the University nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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.
- */
-
-static int
-bsdtar_fnmatch(const char *pattern, const char *string)
-{
- const char *saved_pattern;
- int negate, matched;
- char c;
-
- for (;;) {
- switch (c = *pattern++) {
- case '\0':
- if (*string == '/' || *string == '\0')
- return (0);
- return (1);
- case '?':
- if (*string == '\0')
- return (1);
- ++string;
- break;
- case '*':
- c = *pattern;
- /* Collapse multiple stars. */
- while (c == '*')
- c = *++pattern;
-
- /* Optimize for pattern with * at end. */
- if (c == '\0')
- return (0);
-
- /* General case, use recursion. */
- while (*string != '\0') {
- if (!bsdtar_fnmatch(pattern, string))
- return (0);
- ++string;
- }
- return (1);
- case '[':
- if (*string == '\0')
- return (1);
- saved_pattern = pattern;
- if (*pattern == '!' || *pattern == '^') {
- negate = 1;
- ++pattern;
- } else
- negate = 0;
- matched = 0;
- c = *pattern++;
- do {
- if (c == '\\')
- c = *pattern++;
- if (c == '\0') {
- pattern = saved_pattern;
- c = '[';
- goto norm;
- }
- if (*pattern == '-') {
- char c2 = *(pattern + 1);
- if (c2 == '\0') {
- pattern = saved_pattern;
- c = '[';
- goto norm;
- }
- if (c2 == ']') {
- /* [a-] is not a range. */
- if (c == *string
- || '-' == *string)
- matched = 1;
- pattern ++;
- } else {
- if (c <= *string
- && *string <= c2)
- matched = 1;
- pattern += 2;
- }
- } else if (c == *string)
- matched = 1;
- c = *pattern++;
- } while (c != ']');
- if (matched == negate)
- return (1);
- ++string;
- break;
- case '\\':
- if ((c = *pattern++) == '\0') {
- c = '\\';
- --pattern;
- }
- /* FALLTHROUGH */
- default:
- norm:
- if (c != *string)
- return (1);
- string++;
- break;
- }
- }
- /* NOTREACHED */
+ return (matching->inclusions_unmatched_count);
}
-
-#endif
OpenPOWER on IntegriCloud