svn commit: r203593 - head/usr.bin/tar

Tim Kientzle kientzle at FreeBSD.org
Sun Feb 7 02:00:26 UTC 2010


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 <stdio.h>
 
+#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 <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#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 <string.h>
 #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 <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 */
+	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 <string.h>
+#endif
+
+#include "pathmatch.h"
+
+/*
+ * Check whether a character 'c' is matched by a list specification [...]:
+ *    * Leading '!' negates the class.
+ *    * <char>-<char> is a range of characters
+ *    * \<char> removes any special meaning for <char>
+ *
+ * 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 ***


More information about the svn-src-all mailing list