*/
#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 <errno.h>
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
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] == '/')
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);
int
match_inclusion(struct match *match, const char *pathname)
{
- return (bsdtar_fnmatch(match->pattern, pathname) == 0);
+ return (pathmatch(match->pattern, pathname) == 0);
}
void
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)
* 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)
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]) {
* 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)
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;
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");
* 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.
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);
}
--- /dev/null
+$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("<O)R!F<F]M(&UE;6)E<B!N86UE
+"<PH`
+`
+end
--- /dev/null
+$FreeBSD: src/usr.bin/tar/test/test_patterns.tgz.out.uu,v 1.1 2008/08/15 06:12:02 kientzle Exp $
+begin 644 test_patterns.tgz.out
+==&UP+V9O;R]B87(O"G1M<"]F;V\O8F%R+V)A>@H`
+`
+end
--- /dev/null
+$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*<NAFA$G?=:F)"QIY?K
+M9:C[U,IP;%?WW0Y-<UI9_SR4^6F/&=DY_UW=Y[H#V_(O4_ZE$T?^_[#(_Y[K
+M&^E_1.^WS'^9'@HCN1I:(O_W_&>Z`]OR?\Y_C!7Y`P``````````````?.,!
+(*>E$>P`H````
+`
+end