From owner-svn-src-head@FreeBSD.ORG Sun Feb 7 02:00:26 2010 Return-Path: Delivered-To: svn-src-head@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34]) by hub.freebsd.org (Postfix) with ESMTP id 70AD5106566B; Sun, 7 Feb 2010 02:00:26 +0000 (UTC) (envelope-from kientzle@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:4f8:fff6::2c]) by mx1.freebsd.org (Postfix) with ESMTP id 5F3318FC0C; Sun, 7 Feb 2010 02:00:26 +0000 (UTC) Received: from svn.freebsd.org (localhost [127.0.0.1]) by svn.freebsd.org (8.14.3/8.14.3) with ESMTP id o1720QmL004685; Sun, 7 Feb 2010 02:00:26 GMT (envelope-from kientzle@svn.freebsd.org) Received: (from kientzle@localhost) by svn.freebsd.org (8.14.3/8.14.3/Submit) id o1720QPj004674; Sun, 7 Feb 2010 02:00:26 GMT (envelope-from kientzle@svn.freebsd.org) Message-Id: <201002070200.o1720QPj004674@svn.freebsd.org> From: Tim Kientzle Date: Sun, 7 Feb 2010 02:00:26 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Cc: Subject: svn commit: r203593 - head/usr.bin/tar X-BeenThere: svn-src-head@freebsd.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: SVN commit messages for the src tree for head/-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sun, 07 Feb 2010 02:00:26 -0000 Author: kientzle Date: Sun Feb 7 02:00:26 2010 New Revision: 203593 URL: http://svn.freebsd.org/changeset/base/203593 Log: Merge a bunch of refactoring from Joerg Sonnenberger to isolate common code used by tar and cpio (and useful to other libarchive clients). The functions here are prefixed with "lafe" (libarchive front-end) to indicate their use. Added: head/usr.bin/tar/line_reader.c (contents, props changed) head/usr.bin/tar/line_reader.h (contents, props changed) head/usr.bin/tar/matching.h (contents, props changed) head/usr.bin/tar/pathmatch.c (contents, props changed) head/usr.bin/tar/pathmatch.h (contents, props changed) Modified: head/usr.bin/tar/Makefile head/usr.bin/tar/bsdtar.c head/usr.bin/tar/bsdtar.h head/usr.bin/tar/config_freebsd.h head/usr.bin/tar/matching.c head/usr.bin/tar/read.c head/usr.bin/tar/util.c head/usr.bin/tar/write.c Modified: head/usr.bin/tar/Makefile ============================================================================== --- head/usr.bin/tar/Makefile Sun Feb 7 01:54:14 2010 (r203592) +++ head/usr.bin/tar/Makefile Sun Feb 7 02:00:26 2010 (r203593) @@ -7,7 +7,9 @@ SRCS= bsdtar.c \ cmdline.c \ err.c \ getdate.c \ + line_reader.c \ matching.c \ + pathmatch.c \ read.c \ subst.c \ tree.c \ Modified: head/usr.bin/tar/bsdtar.c ============================================================================== --- head/usr.bin/tar/bsdtar.c Sun Feb 7 01:54:14 2010 (r203592) +++ head/usr.bin/tar/bsdtar.c Sun Feb 7 02:00:26 2010 (r203593) @@ -66,6 +66,7 @@ __FBSDID("$FreeBSD$"); #include "bsdtar.h" #include "err.h" +#include "matching.h" /* * Per POSIX.1-1988, tar defaults to reading/writing archives to/from @@ -248,7 +249,7 @@ main(int argc, char **argv) bsdtar->option_chroot = 1; break; case OPTION_EXCLUDE: /* GNU tar */ - if (exclude(bsdtar, bsdtar->optarg)) + if (lafe_exclude(&bsdtar->matching, bsdtar->optarg)) bsdtar_errc(1, 0, "Couldn't exclude %s\n", bsdtar->optarg); break; @@ -294,7 +295,7 @@ main(int argc, char **argv) * noone else needs this to filter entries * when transforming archives. */ - if (include(bsdtar, bsdtar->optarg)) + if (lafe_include(&bsdtar->matching, bsdtar->optarg)) bsdtar_errc(1, 0, "Failed to add %s to inclusion list", bsdtar->optarg); @@ -484,7 +485,7 @@ main(int argc, char **argv) bsdtar->option_interactive = 1; break; case 'X': /* GNU tar */ - if (exclude_from_file(bsdtar, bsdtar->optarg)) + if (lafe_exclude_from_file(&bsdtar->matching, bsdtar->optarg)) bsdtar_errc(1, 0, "failed to process exclusions from file %s", bsdtar->optarg); @@ -607,7 +608,7 @@ main(int argc, char **argv) break; } - cleanup_exclusions(bsdtar); + lafe_cleanup_exclusions(&bsdtar->matching); #if HAVE_REGEX_H cleanup_substitution(bsdtar); #endif Modified: head/usr.bin/tar/bsdtar.h ============================================================================== --- head/usr.bin/tar/bsdtar.h Sun Feb 7 01:54:14 2010 (r203592) +++ head/usr.bin/tar/bsdtar.h Sun Feb 7 02:00:26 2010 (r203593) @@ -28,6 +28,8 @@ #include "bsdtar_platform.h" #include +#include "matching.h" + #define DEFAULT_BYTES_PER_BLOCK (20*512) /* @@ -77,7 +79,6 @@ struct bsdtar { int fd; /* Miscellaneous state information */ - struct archive *archive; int argc; char **argv; const char *optarg; @@ -97,7 +98,7 @@ struct bsdtar { struct archive_dir *archive_dir; /* for write.c */ struct name_cache *gname_cache; /* for write.c */ char *buff; /* for write.c */ - struct matching *matching; /* for matching.c */ + struct lafe_matching *matching; /* for matching.c */ struct security *security; /* for read.c */ struct name_cache *uname_cache; /* for write.c */ struct siginfo_data *siginfo; /* for siginfo.c */ @@ -134,18 +135,10 @@ enum { }; int bsdtar_getopt(struct bsdtar *); -void cleanup_exclusions(struct bsdtar *); void do_chdir(struct bsdtar *); int edit_pathname(struct bsdtar *, struct archive_entry *); -int exclude(struct bsdtar *, const char *pattern); -int exclude_from_file(struct bsdtar *, const char *pathname); -int excluded(struct bsdtar *, const char *pathname); -int include(struct bsdtar *, const char *pattern); -int include_from_file(struct bsdtar *, const char *pathname); int need_report(void); int pathcmp(const char *a, const char *b); -int process_lines(struct bsdtar *bsdtar, const char *pathname, - int (*process)(struct bsdtar *, const char *)); void safe_fprintf(FILE *, const char *fmt, ...); void set_chdir(struct bsdtar *, const char *newdir); const char *tar_i64toa(int64_t); @@ -154,8 +147,6 @@ void tar_mode_r(struct bsdtar *bsdtar); void tar_mode_t(struct bsdtar *bsdtar); void tar_mode_u(struct bsdtar *bsdtar); void tar_mode_x(struct bsdtar *bsdtar); -int unmatched_inclusions(struct bsdtar *bsdtar); -int unmatched_inclusions_warn(struct bsdtar *bsdtar, const char *msg); void usage(void); int yes(const char *fmt, ...); Modified: head/usr.bin/tar/config_freebsd.h ============================================================================== --- head/usr.bin/tar/config_freebsd.h Sun Feb 7 01:54:14 2010 (r203592) +++ head/usr.bin/tar/config_freebsd.h Sun Feb 7 02:00:26 2010 (r203593) @@ -37,9 +37,6 @@ #undef HAVE_EXT2FS_EXT2_FS_H #define HAVE_FCHDIR 1 #define HAVE_FCNTL_H 1 -#define HAVE_FNMATCH 1 -#define HAVE_FNMATCH_H 1 -#define HAVE_FNM_LEADING_DIR 1 #define HAVE_GRP_H 1 #define HAVE_LANGINFO_H 1 #define HAVE_LIBARCHIVE 1 Added: head/usr.bin/tar/line_reader.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/usr.bin/tar/line_reader.c Sun Feb 7 02:00:26 2010 (r203593) @@ -0,0 +1,171 @@ +/*- + * Copyright (c) 2008 Tim Kientzle + * All rights reserved. + * + * 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 + * in this position and unchanged. + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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. + */ + +#include "bsdtar_platform.h" +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include "err.h" +#include "line_reader.h" + +#if defined(_WIN32) && !defined(__CYGWIN__) && !defined(__BORLANDC__) +#define strdup _strdup +#endif + +/* + * Read lines from file and do something with each one. If option_null + * is set, lines are terminated with zero bytes; otherwise, they're + * terminated with newlines. + * + * This uses a self-sizing buffer to handle arbitrarily-long lines. + */ +struct lafe_line_reader { + FILE *f; + char *buff, *buff_end, *line_start, *line_end, *p; + char *pathname; + size_t buff_length; + int nullSeparator; /* Lines separated by null, not CR/CRLF/etc. */ + int ret; +}; + +struct lafe_line_reader * +lafe_line_reader(const char *pathname, int nullSeparator) +{ + struct lafe_line_reader *lr; + + lr = calloc(1, sizeof(*lr)); + if (lr == NULL) + bsdtar_errc(1, ENOMEM, "Can't open %s", pathname); + + lr->nullSeparator = nullSeparator; + lr->pathname = strdup(pathname); + + if (strcmp(pathname, "-") == 0) + lr->f = stdin; + else + lr->f = fopen(pathname, "r"); + if (lr->f == NULL) + bsdtar_errc(1, errno, "Couldn't open %s", pathname); + lr->buff_length = 8192; + lr->buff = malloc(lr->buff_length); + if (lr->buff == NULL) + bsdtar_errc(1, ENOMEM, "Can't read %s", pathname); + lr->line_start = lr->line_end = lr->buff_end = lr->buff; + + return (lr); +} + +const char * +lafe_line_reader_next(struct lafe_line_reader *lr) +{ + size_t bytes_wanted, bytes_read, new_buff_size; + char *line_start, *p; + + for (;;) { + /* If there's a line in the buffer, return it immediately. */ + while (lr->line_end < lr->buff_end) { + if (lr->nullSeparator) { + if (*lr->line_end == '\0') { + line_start = lr->line_start; + lr->line_start = lr->line_end + 1; + lr->line_end = lr->line_start; + return (line_start); + } + } else if (*lr->line_end == '\x0a' || *lr->line_end == '\x0d') { + *lr->line_end = '\0'; + line_start = lr->line_start; + lr->line_start = lr->line_end + 1; + lr->line_end = lr->line_start; + if (line_start[0] != '\0') + return (line_start); + } + lr->line_end++; + } + + /* If we're at end-of-file, process the final data. */ + if (lr->f == NULL) { + /* If there's more text, return one last line. */ + if (lr->line_end > lr->line_start) { + *lr->line_end = '\0'; + line_start = lr->line_start; + lr->line_start = lr->line_end + 1; + lr->line_end = lr->line_start; + return (line_start); + } + /* Otherwise, we're done. */ + return (NULL); + } + + /* Buffer only has part of a line. */ + if (lr->line_start > lr->buff) { + /* Move a leftover fractional line to the beginning. */ + memmove(lr->buff, lr->line_start, + lr->buff_end - lr->line_start); + lr->buff_end -= lr->line_start - lr->buff; + lr->line_end -= lr->line_start - lr->buff; + lr->line_start = lr->buff; + } else { + /* Line is too big; enlarge the buffer. */ + new_buff_size = lr->buff_length * 2; + if (new_buff_size <= lr->buff_length) + bsdtar_errc(1, ENOMEM, + "Line too long in %s", lr->pathname); + lr->buff_length = new_buff_size; + p = realloc(lr->buff, new_buff_size); + if (p == NULL) + bsdtar_errc(1, ENOMEM, + "Line too long in %s", lr->pathname); + lr->buff_end = p + (lr->buff_end - lr->buff); + lr->line_end = p + (lr->line_end - lr->buff); + lr->line_start = lr->buff = p; + } + + /* Get some more data into the buffer. */ + bytes_wanted = lr->buff + lr->buff_length - lr->buff_end; + bytes_read = fread(lr->buff_end, 1, bytes_wanted, lr->f); + lr->buff_end += bytes_read; + + if (ferror(lr->f)) + bsdtar_errc(1, errno, "Can't read %s", lr->pathname); + if (feof(lr->f)) { + if (lr->f != stdin) + fclose(lr->f); + lr->f = NULL; + } + } +} + +void +lafe_line_reader_free(struct lafe_line_reader *lr) +{ + free(lr->buff); + free(lr->pathname); + free(lr); +} Added: head/usr.bin/tar/line_reader.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/usr.bin/tar/line_reader.h Sun Feb 7 02:00:26 2010 (r203593) @@ -0,0 +1,37 @@ +/*- + * Copyright (c) 2009 Joerg Sonnenberger + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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. + * + * $FreeBSD$ + */ + +#ifndef LAFE_LINE_READER_H +#define LAFE_LINE_READER_H + +struct lafe_line_reader; + +struct lafe_line_reader *lafe_line_reader(const char *, int nullSeparator); +const char *lafe_line_reader_next(struct lafe_line_reader *); +void lafe_line_reader_free(struct lafe_line_reader *); + +#endif Modified: head/usr.bin/tar/matching.c ============================================================================== --- head/usr.bin/tar/matching.c Sun Feb 7 01:54:14 2010 (r203592) +++ head/usr.bin/tar/matching.c Sun Feb 7 02:00:26 2010 (r203593) @@ -36,8 +36,10 @@ __FBSDID("$FreeBSD$"); #include #endif -#include "bsdtar.h" #include "err.h" +#include "line_reader.h" +#include "matching.h" +#include "pathmatch.h" struct match { struct match *next; @@ -45,7 +47,7 @@ struct match { char pattern[1]; }; -struct matching { +struct lafe_matching { struct match *exclusions; int exclusions_count; struct match *inclusions; @@ -53,14 +55,10 @@ struct matching { int inclusions_unmatched_count; }; - -static void add_pattern(struct match **list, - const char *pattern); -static int bsdtar_fnmatch(const char *p, const char *s); -static void initialize_matching(struct bsdtar *); +static void add_pattern(struct match **list, const char *pattern); +static void initialize_matching(struct lafe_matching **); 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 @@ -74,55 +72,74 @@ static int pathmatch(const char *p, cons */ int -exclude(struct bsdtar *bsdtar, const char *pattern) +lafe_exclude(struct lafe_matching **matching, const char *pattern) { - struct matching *matching; - if (bsdtar->matching == NULL) - initialize_matching(bsdtar); - matching = bsdtar->matching; - add_pattern(&(matching->exclusions), pattern); - matching->exclusions_count++; + if (*matching == NULL) + initialize_matching(matching); + add_pattern(&((*matching)->exclusions), pattern); + (*matching)->exclusions_count++; return (0); } int -exclude_from_file(struct bsdtar *bsdtar, const char *pathname) +lafe_exclude_from_file(struct lafe_matching **matching, const char *pathname) { - return (process_lines(bsdtar, pathname, &exclude)); + struct lafe_line_reader *lr; + const char *p; + int ret = 0; + + lr = lafe_line_reader(pathname, '\n'); + while ((p = lafe_line_reader_next(lr)) != NULL) { + if (lafe_exclude(matching, p) != 0) + ret = -1; + } + lafe_line_reader_free(lr); + return (ret); } int -include(struct bsdtar *bsdtar, const char *pattern) +lafe_include(struct lafe_matching **matching, const char *pattern) { - struct matching *matching; - if (bsdtar->matching == NULL) - initialize_matching(bsdtar); - matching = bsdtar->matching; - add_pattern(&(matching->inclusions), pattern); - matching->inclusions_count++; - matching->inclusions_unmatched_count++; + if (*matching == NULL) + initialize_matching(matching); + add_pattern(&((*matching)->inclusions), pattern); + (*matching)->inclusions_count++; + (*matching)->inclusions_unmatched_count++; return (0); } int -include_from_file(struct bsdtar *bsdtar, const char *pathname) +lafe_include_from_file(struct lafe_matching **matching, const char *pathname, + int nullSeparator) { - return (process_lines(bsdtar, pathname, &include)); + struct lafe_line_reader *lr; + const char *p; + int ret = 0; + + lr = lafe_line_reader(pathname, nullSeparator); + while ((p = lafe_line_reader_next(lr)) != NULL) { + if (lafe_include(matching, p) != 0) + ret = -1; + } + lafe_line_reader_free(lr); + return (ret); } static void add_pattern(struct match **list, const char *pattern) { struct match *match; + size_t len; - match = malloc(sizeof(*match) + strlen(pattern) + 1); + len = strlen(pattern); + match = malloc(sizeof(*match) + len + 1); if (match == NULL) bsdtar_errc(1, errno, "Out of memory"); strcpy(match->pattern, pattern); /* Both "foo/" and "foo" should match "foo/bar". */ - if (match->pattern[strlen(match->pattern)-1] == '/') + if (len && match->pattern[len - 1] == '/') match->pattern[strlen(match->pattern)-1] = '\0'; match->next = *list; *list = match; @@ -131,13 +148,11 @@ add_pattern(struct match **list, const c int -excluded(struct bsdtar *bsdtar, const char *pathname) +lafe_excluded(struct lafe_matching *matching, const char *pathname) { - struct matching *matching; struct match *match; struct match *matched; - matching = bsdtar->matching; if (matching == NULL) return (0); @@ -192,288 +207,74 @@ excluded(struct bsdtar *bsdtar, const ch static int match_exclusion(struct match *match, const char *pathname) { - const char *p; - - if (*match->pattern == '*' || *match->pattern == '/') - return (pathmatch(match->pattern, pathname) == 0); - - for (p = pathname; p != NULL; p = strchr(p, '/')) { - if (*p == '/') - p++; - if (pathmatch(match->pattern, p) == 0) - return (1); - } - return (0); + return (lafe_pathmatch(match->pattern, + pathname, + PATHMATCH_NO_ANCHOR_START | PATHMATCH_NO_ANCHOR_END)); } /* * Again, mimic gtar: inclusions are always anchored (have to match * the beginning of the path) even though exclusions are not anchored. */ -int +static int match_inclusion(struct match *match, const char *pathname) { - return (pathmatch(match->pattern, pathname) == 0); + return (lafe_pathmatch(match->pattern, pathname, PATHMATCH_NO_ANCHOR_END)); } void -cleanup_exclusions(struct bsdtar *bsdtar) +lafe_cleanup_exclusions(struct lafe_matching **matching) { struct match *p, *q; - if (bsdtar->matching) { - p = bsdtar->matching->inclusions; - while (p != NULL) { - q = p; - p = p->next; - free(q); - } - p = bsdtar->matching->exclusions; - while (p != NULL) { - q = p; - p = p->next; - free(q); - } - free(bsdtar->matching); + if (*matching == NULL) + return; + + for (p = (*matching)->inclusions; p != NULL; ) { + q = p; + p = p->next; + free(q); } + + for (p = (*matching)->exclusions; p != NULL; ) { + q = p; + p = p->next; + free(q); + } + + free(*matching); + *matching = NULL; } static void -initialize_matching(struct bsdtar *bsdtar) +initialize_matching(struct lafe_matching **matching) { - bsdtar->matching = malloc(sizeof(*bsdtar->matching)); - if (bsdtar->matching == NULL) + *matching = calloc(sizeof(**matching), 1); + if (*matching == NULL) bsdtar_errc(1, errno, "No memory"); - memset(bsdtar->matching, 0, sizeof(*bsdtar->matching)); } int -unmatched_inclusions(struct bsdtar *bsdtar) +lafe_unmatched_inclusions(struct lafe_matching *matching) { - struct matching *matching; - matching = bsdtar->matching; if (matching == NULL) return (0); return (matching->inclusions_unmatched_count); } - int -unmatched_inclusions_warn(struct bsdtar *bsdtar, const char *msg) +lafe_unmatched_inclusions_warn(struct lafe_matching *matching, const char *msg) { - struct matching *matching; struct match *p; - matching = bsdtar->matching; if (matching == NULL) return (0); - p = matching->inclusions; - while (p != NULL) { - if (p->matches == 0) { - bsdtar->return_value = 1; - bsdtar_warnc(0, "%s: %s", - p->pattern, msg); - } - p = p->next; + for (p = matching->inclusions; p != NULL; p = p->next) { + if (p->matches == 0) + bsdtar_warnc(0, "%s: %s", p->pattern, 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) - -/* Use system fnmatch() if it suits our needs. */ -/* On Linux, _GNU_SOURCE must be defined to get FNM_LEADING_DIR. */ -#define _GNU_SOURCE -#include -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 */ + return (matching->inclusions_unmatched_count); } - -#endif Added: head/usr.bin/tar/matching.h ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/usr.bin/tar/matching.h Sun Feb 7 02:00:26 2010 (r203593) @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * 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 + * in this position and unchanged. + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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. + * + * $FreeBSD$ + */ + +#ifndef MATCHING_H +#define MATCHING_H + +struct lafe_matching; + +int lafe_exclude(struct lafe_matching **matching, const char *pattern); +int lafe_exclude_from_file(struct lafe_matching **matching, + const char *pathname); +int lafe_include(struct lafe_matching **matching, const char *pattern); +int lafe_include_from_file(struct lafe_matching **matching, + const char *pathname, int nullSeparator); + +int lafe_excluded(struct lafe_matching *, const char *pathname); +void lafe_cleanup_exclusions(struct lafe_matching **); +int lafe_unmatched_inclusions(struct lafe_matching *); +int lafe_unmatched_inclusions_warn(struct lafe_matching *, const char *msg); + +#endif Added: head/usr.bin/tar/pathmatch.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ head/usr.bin/tar/pathmatch.c Sun Feb 7 02:00:26 2010 (r203593) @@ -0,0 +1,255 @@ +/*- + * Copyright (c) 2003-2007 Tim Kientzle + * All rights reserved. + * + * 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 + * in this position and unchanged. + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``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 AUTHOR(S) 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. + */ + +#include "bsdtar_platform.h" +__FBSDID("$FreeBSD$"); + +#ifdef HAVE_STRING_H +#include +#endif + +#include "pathmatch.h" + +/* + * Check whether a character 'c' is matched by a list specification [...]: + * * Leading '!' negates the class. + * * - is a range of characters + * * \ removes any special meaning for + * + * Some interesting boundary cases: + * a-d-e is one range (a-d) followed by two single characters - and e. + * \a-\d is same as a-d + * a\-d is three single characters: a, d, - + * Trailing - is not special (so [a-] is two characters a and -). + * Initial - is not special ([a-] is same as [-a] is same as [\\-a]) + * This function never sees a trailing \. + * [] always fails + * [!] always succeeds + */ +static int +pm_list(const char *start, const char *end, const char c, int flags) +{ + const char *p = start; + char rangeStart = '\0', nextRangeStart; + int match = 1, nomatch = 0; + + /* This will be used soon... */ + (void)flags; /* UNUSED */ + + /* If this is a negated class, return success for nomatch. */ + if (*p == '!' && p < end) { + match = 0; + nomatch = 1; + ++p; + } + + while (p < end) { + nextRangeStart = '\0'; + switch (*p) { + case '-': + /* Trailing or initial '-' is not special. */ + if ((rangeStart == '\0') || (p == end - 1)) { + if (*p == c) + return (match); + } else { + char rangeEnd = *++p; + if (rangeEnd == '\\') + rangeEnd = *++p; + if ((rangeStart <= c) && (c <= rangeEnd)) + return (match); + } + break; + case '\\': + ++p; + /* Fall through */ + default: + if (*p == c) + return (match); + nextRangeStart = *p; /* Possible start of range. */ + } + rangeStart = nextRangeStart; + ++p; + } + return (nomatch); +} + +/* + * If s is pointing to "./", ".//", "./././" or the like, skip it. + */ +static const char * +pm_slashskip(const char *s) { + while ((*s == '/') + || (s[0] == '.' && s[1] == '/') + || (s[0] == '.' && s[1] == '\0')) + ++s; + return (s); +} + +static int +pm(const char *p, const char *s, int flags) +{ + const char *end; + + /* + * Ignore leading './', './/', '././', etc. + */ + if (s[0] == '.' && s[1] == '/') + s = pm_slashskip(s + 1); + if (p[0] == '.' && p[1] == '/') + p = pm_slashskip(p + 1); + + for (;;) { + switch (*p) { + case '\0': + if (s[0] == '/') { + if (flags & PATHMATCH_NO_ANCHOR_END) + return (1); + /* "dir" == "dir/" == "dir/." */ + s = pm_slashskip(s); + } + return (*s == '\0'); + case '?': + /* ? always succeds, unless we hit end of 's' */ + if (*s == '\0') + return (0); *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***