summaryrefslogtreecommitdiffstats
path: root/usr.bin/tar
diff options
context:
space:
mode:
authorkientzle <kientzle@FreeBSD.org>2008-08-18 04:58:54 +0000
committerkientzle <kientzle@FreeBSD.org>2008-08-18 04:58:54 +0000
commitbcf5f4ae388cfb02d90c9ced7c2d75c212de4ae4 (patch)
treea40e6fb6b990a6d47331212976479a1a41bfb384 /usr.bin/tar
parentd35c84c137e0eba240707bd36806a2a868607152 (diff)
downloadFreeBSD-src-bcf5f4ae388cfb02d90c9ced7c2d75c212de4ae4.zip
FreeBSD-src-bcf5f4ae388cfb02d90c9ced7c2d75c212de4ae4.tar.gz
Strip leading "./" or ".//" from patterns and filenames
so that "./foo" matches "foo" (and vice versa). This is related to PR bin/119141. PR: bin/119141 MFC after: 4 days
Diffstat (limited to 'usr.bin/tar')
-rw-r--r--usr.bin/tar/matching.c42
1 files changed, 39 insertions, 3 deletions
diff --git a/usr.bin/tar/matching.c b/usr.bin/tar/matching.c
index 406564a..03cd050 100644
--- a/usr.bin/tar/matching.c
+++ b/usr.bin/tar/matching.c
@@ -59,6 +59,7 @@ 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);
+static int pathmatch(const char *p, const char *s);
/*
* The matching logic here needs to be re-thought. I started out to
@@ -193,12 +194,12 @@ match_exclusion(struct match *match, const char *pathname)
const char *p;
if (*match->pattern == '*' || *match->pattern == '/')
- return (bsdtar_fnmatch(match->pattern, pathname) == 0);
+ return (pathmatch(match->pattern, pathname) == 0);
for (p = pathname; p != NULL; p = strchr(p, '/')) {
if (*p == '/')
p++;
- if (bsdtar_fnmatch(match->pattern, p) == 0)
+ if (pathmatch(match->pattern, p) == 0)
return (1);
}
return (0);
@@ -211,7 +212,7 @@ match_exclusion(struct match *match, const char *pathname)
int
match_inclusion(struct match *match, const char *pathname)
{
- return (bsdtar_fnmatch(match->pattern, pathname) == 0);
+ return (pathmatch(match->pattern, pathname) == 0);
}
void
@@ -279,6 +280,41 @@ unmatched_inclusions_warn(struct bsdtar *bsdtar, const char *msg)
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;
+ }
+ if (string[0] == '.' && string[1] == '/') {
+ string += 2;
+ while (string[0] == '/')
+ ++string;
+ }
+ return (bsdtar_fnmatch(pattern, string, FNM_LEADING_DIR));
+}
#if defined(HAVE_FNMATCH) && defined(HAVE_FNM_LEADING_DIR)
OpenPOWER on IntegriCloud