diff options
Diffstat (limited to 'usr.bin/tar')
-rw-r--r-- | usr.bin/tar/bsdtar_platform.h | 1 | ||||
-rw-r--r-- | usr.bin/tar/configure.ac.in | 6 | ||||
-rw-r--r-- | usr.bin/tar/matching.c | 172 |
3 files changed, 170 insertions, 9 deletions
diff --git a/usr.bin/tar/bsdtar_platform.h b/usr.bin/tar/bsdtar_platform.h index b17cebf..e4728e3 100644 --- a/usr.bin/tar/bsdtar_platform.h +++ b/usr.bin/tar/bsdtar_platform.h @@ -50,6 +50,7 @@ #define HAVE_FCHDIR 1 #define HAVE_FCNTL_H 1 #define HAVE_FNMATCH 1 +#define HAVE_FNM_LEADING_DIR 1 #define HAVE_FTRUNCATE 1 #define HAVE_GETOPT_LONG 1 #define HAVE_INTTYPES_H 1 diff --git a/usr.bin/tar/configure.ac.in b/usr.bin/tar/configure.ac.in index 47e6767..cf7971a 100644 --- a/usr.bin/tar/configure.ac.in +++ b/usr.bin/tar/configure.ac.in @@ -28,9 +28,13 @@ AC_TYPE_SIZE_T AC_CHECK_TYPE(id_t, [unsigned long]) AC_CHECK_MEMBERS([struct stat.st_rdev, struct stat.st_mtimespec.tv_nsec, struct stat.st_mtim.tv_nsec]) AC_CHECK_DECL([D_MD_ORDER], - [AC_DEFINE(HAVE_D_MD_ORDER, 1, [D_MD_ORDER is a valid argument to nl_langinfo])], + [AC_DEFINE(HAVE_D_MD_ORDER, 1, [Define to 1 if nl_langinfo supports D_MD_ORDER])], [], [#include <langinfo.h>]) +AC_CHECK_DECL([FNM_LEADING_DIR], + [AC_DEFINE(HAVE_FNM_LEADING_DIR, 1, [Define to 1 if fnmatch(3) supports the FNM_LEADING_DIR flag])], + [], + [#include <fnmatch.h>]) # Checks for library functions. AC_FUNC_FNMATCH diff --git a/usr.bin/tar/matching.c b/usr.bin/tar/matching.c index ff0daee..084ec4d 100644 --- a/usr.bin/tar/matching.c +++ b/usr.bin/tar/matching.c @@ -28,7 +28,6 @@ __FBSDID("$FreeBSD$"); #include <errno.h> -#include <fnmatch.h> #include <stdlib.h> #include <string.h> @@ -51,6 +50,7 @@ struct matching { 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 int match_exclusion(struct match *, const char *pathname); static int match_inclusion(struct match *, const char *pathname); @@ -183,10 +183,6 @@ excluded(struct bsdtar *bsdtar, const char *pathname) * This is a little odd, but it matches the default behavior of * gtar. In particular, 'a*b' will match 'foo/a1111/222b/bar' * - * XXX TODO: fnmatch isn't the most portable thing around, and even - * worse, FNM_LEADING_DIR is a non-POSIX extension. <sigh> Thus, the - * following two functions need to eventually be replaced with code - * that does not rely on fnmatch(). */ int match_exclusion(struct match *match, const char *pathname) @@ -194,12 +190,12 @@ match_exclusion(struct match *match, const char *pathname) const char *p; if (*match->pattern == '*' || *match->pattern == '/') - return (fnmatch(match->pattern, pathname, FNM_LEADING_DIR) == 0); + return (bsdtar_fnmatch(match->pattern, pathname) == 0); for (p = pathname; p != NULL; p = strchr(p, '/')) { if (*p == '/') p++; - if (fnmatch(match->pattern, p, FNM_LEADING_DIR) == 0) + if (bsdtar_fnmatch(match->pattern, p) == 0) return (1); } return (0); @@ -212,7 +208,7 @@ match_exclusion(struct match *match, const char *pathname) int match_inclusion(struct match *match, const char *pathname) { - return (fnmatch(match->pattern, pathname, FNM_LEADING_DIR) == 0); + return (bsdtar_fnmatch(match->pattern, pathname) == 0); } void @@ -256,3 +252,163 @@ unmatched_inclusions(struct bsdtar *bsdtar) return (0); return (matching->inclusions_unmatched_count); } + + + +#if defined(HAVE_FNMATCH) && defined(HAVE_FNM_LEADING_DIR) + +/* Use system fnmatch() if it suits our needs. */ +#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 */ +} + +#endif |