summaryrefslogtreecommitdiffstats
path: root/usr.bin/tar
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin/tar')
-rw-r--r--usr.bin/tar/bsdtar_platform.h1
-rw-r--r--usr.bin/tar/configure.ac.in6
-rw-r--r--usr.bin/tar/matching.c172
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
OpenPOWER on IntegriCloud