From: Tim Kientzle Date: Tue, 19 Aug 2008 22:33:06 +0000 (-0400) Subject: IFC X-Git-Tag: v2.6.0~110 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=f3f868f20aab973dafc3bc79a6eb99e29a60cf2f;p=thirdparty%2Flibarchive.git IFC SVN-Revision: 182 --- diff --git a/tar/matching.c b/tar/matching.c index 952055fe8..b1031f287 100644 --- a/tar/matching.c +++ b/tar/matching.c @@ -24,7 +24,7 @@ */ #include "bsdtar_platform.h" -__FBSDID("$FreeBSD: src/usr.bin/tar/matching.c,v 1.13 2008/05/26 17:10:10 kientzle Exp $"); +__FBSDID("$FreeBSD: src/usr.bin/tar/matching.c,v 1.16 2008/08/18 18:13:40 kientzle Exp $"); #ifdef HAVE_ERRNO_H #include @@ -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 @@ -118,8 +119,6 @@ add_pattern(struct bsdtar *bsdtar, struct match **list, const char *pattern) match = malloc(sizeof(*match) + strlen(pattern) + 1); if (match == NULL) bsdtar_errc(bsdtar, 1, errno, "Out of memory"); - if (pattern[0] == '/') - pattern++; strcpy(match->pattern, pattern); /* Both "foo/" and "foo" should match "foo/bar". */ if (match->pattern[strlen(match->pattern)-1] == '/') @@ -195,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); @@ -213,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 @@ -281,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)); +} #if defined(HAVE_FNMATCH) && defined(HAVE_FNM_LEADING_DIR) diff --git a/tar/test/test_copy.c b/tar/test/test_copy.c index b2eef8cf7..a64f2c886 100644 --- a/tar/test/test_copy.c +++ b/tar/test/test_copy.c @@ -23,7 +23,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "test.h" -__FBSDID("$FreeBSD: src/usr.bin/tar/test/test_copy.c,v 1.2 2008/05/26 17:10:10 kientzle Exp $"); +__FBSDID("$FreeBSD: src/usr.bin/tar/test/test_copy.c,v 1.3 2008/08/15 06:12:02 kientzle Exp $"); static void create_tree(void) @@ -196,6 +196,9 @@ verify_tree(int limit) char dir[2]; dir[0] = *dp; dir[1] = '\0'; d = opendir(dir); + failure("Unable to open dir '%s'", dir); + if (!assert(d != NULL)) + continue; while ((de = readdir(d)) != NULL) { p = de->d_name; switch(dp[0]) { diff --git a/tar/test/test_option_T.c b/tar/test/test_option_T.c index 6c9007b24..e0a220b05 100644 --- a/tar/test/test_option_T.c +++ b/tar/test/test_option_T.c @@ -23,7 +23,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "test.h" -__FBSDID("$FreeBSD: src/usr.bin/tar/test/test_option_T.c,v 1.2 2008/05/26 17:10:10 kientzle Exp $"); +__FBSDID("$FreeBSD: src/usr.bin/tar/test/test_option_T.c,v 1.3 2008/08/15 06:12:02 kientzle Exp $"); static int touch(const char *fn) @@ -40,6 +40,7 @@ touch(const char *fn) DEFINE_TEST(test_option_T) { FILE *f; + int r; /* Create a simple dir heirarchy; bail if anything fails. */ if (!assertEqualInt(0, mkdir("d1", 0755))) return; @@ -67,8 +68,10 @@ DEFINE_TEST(test_option_T) fclose(f); /* Use -c -T to archive up the files. */ - systemf("%s -c -f test1.tar -T filelist > test1.out 2> test1.err", + r = systemf("%s -c -f test1.tar -T filelist > test1.out 2> test1.err", testprog); + failure("Failure here probably means that tar can't archive zero-length files without reading them"); + assert(r == 0); assertEmptyFile("test1.out"); assertEmptyFile("test1.err"); diff --git a/tar/test/test_patterns.c b/tar/test/test_patterns.c index e7b1679fd..b3e61d75a 100644 --- a/tar/test/test_patterns.c +++ b/tar/test/test_patterns.c @@ -23,11 +23,14 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "test.h" -__FBSDID("$FreeBSD$"); +__FBSDID("$FreeBSD: src/usr.bin/tar/test/test_patterns.c,v 1.2 2008/08/15 06:12:02 kientzle Exp $"); DEFINE_TEST(test_patterns) { int fd, r; + const char *reffile1 = "test_patterns.tgz"; + const char *reffile1_out = "test_patterns.tgz.out"; + const char *reffile1_err = "test_patterns.tgz.err"; /* * Test basic command-line pattern handling. @@ -44,4 +47,14 @@ DEFINE_TEST(test_patterns) r = systemf("%s zxfv tar1.tgz foo bar > tar1b.out 2> tar1b.err", testprog); failure("tar should return non-zero because a file was given on the command line that's not in the archive"); assert(r != 0); + + extract_reference_file(reffile1); + extract_reference_file(reffile1_out); + extract_reference_file(reffile1_err); + + r = systemf("%s tf %s /tmp/foo/bar > tar2a.out 2> tar2a.err", + testprog, reffile1); + assertEqualInt(r, 0); + assertEqualFile("tar2a.out", reffile1_out); + assertEqualFile("tar2a.err", reffile1_err); } diff --git a/tar/test/test_patterns.tgz.err.uu b/tar/test/test_patterns.tgz.err.uu new file mode 100644 index 000000000..258082a4c --- /dev/null +++ b/tar/test/test_patterns.tgz.err.uu @@ -0,0 +1,6 @@ +$FreeBSD: src/usr.bin/tar/test/test_patterns.tgz.err.uu,v 1.1 2008/08/15 06:12:02 kientzle Exp $ +begin 644 test_patterns.tgz.err +M8G-D=&%R.B!296UO=FEN9R!L96%D:6YG("@H` +` +end diff --git a/tar/test/test_patterns.tgz.uu b/tar/test/test_patterns.tgz.uu new file mode 100644 index 000000000..1171e58dc --- /dev/null +++ b/tar/test/test_patterns.tgz.uu @@ -0,0 +1,9 @@ +$FreeBSD: src/usr.bin/tar/test/test_patterns.tgz.uu,v 1.1 2008/08/15 06:12:02 kientzle Exp $ +begin 644 test_patterns.tgz +M'XL(`,P5I4@``^W3T0J",!3&<1]E;[!SYC:?Q\`H2`PS@IZ^F5AV(PFMJ__O +MYB@;>.:W8X?V;/==9XM\1*0*P:2J59"QCN8ZO:A*4*Z`]OR?\Y_C!7Y`P``````````````?.,! +(*>E$>P`H```` +` +end