Same with patch inline: Index: Makefile =================================================================== RCS file: /cvs/src/usr.sbin/mtree/Makefile,v retrieving revision 1.9 diff -u -p -r1.9 Makefile --- Makefile 15 Apr 2013 06:25:18 -0000 1.9 +++ Makefile 20 Jun 2014 12:45:35 -0000 @@ -3,6 +3,6 @@ PROG= mtree #CFLAGS+=-DDEBUG MAN= mtree.8 -SRCS= compare.c crc.c create.c misc.c mtree.c spec.c verify.c +SRCS= compare.c crc.c create.c excludes.c misc.c mtree.c spec.c verify.c .include <bsd.prog.mk> Index: create.c =================================================================== RCS file: /cvs/src/usr.sbin/mtree/create.c,v retrieving revision 1.29 diff -u -p -r1.29 create.c --- create.c 22 Aug 2013 04:43:41 -0000 1.29 +++ create.c 20 Jun 2014 12:45:35 -0000 @@ -58,6 +58,7 @@ extern int ftsoptions; extern int dflag, iflag, nflag, sflag; extern u_int keys; extern char fullpath[MAXPATHLEN]; +extern char *excludefile; static gid_t gid; static uid_t uid; @@ -82,6 +83,8 @@ cwalk(void) (void)printf( "#\t user: %s\n#\tmachine: %s\n#\t tree: %s\n#\t date: %s", getlogin(), host, fullpath, ctime(&clock)); + if (excludefile) + printf("#\texclude: %s\n", excludefile); argv[0] = "."; argv[1] = NULL; @@ -90,6 +93,10 @@ cwalk(void) while ((p = fts_read(t))) { if (iflag) indent = p->fts_level * 4; + if (check_excludes(p->fts_name, p->fts_path)) { + fts_set(t, p, FTS_SKIP); + continue; + } switch(p->fts_info) { case FTS_D: if (!dflag) Index: excludes.c =================================================================== RCS file: excludes.c diff -N excludes.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ excludes.c 20 Jun 2014 12:45:35 -0000 @@ -0,0 +1,118 @@ +/* + * Copyright 2000 Massachusetts Institute of Technology + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby + * granted, provided that both the above copyright notice and this + * permission notice appear in all copies, that both the above + * copyright notice and this permission notice appear in all + * supporting documentation, and that the name of M.I.T. not be used + * in advertising or publicity pertaining to distribution of the + * software without specific, written prior permission. M.I.T. makes + * no representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied + * warranty. + * + * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS + * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT + * SHALL M.I.T. 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 <sys/types.h> +#include <sys/queue.h> +#include <err.h> +#include <fnmatch.h> +#include <fts.h> +#include <stdio.h> +#include <stdlib.h> +#include "mtree.h" +#include "extern.h" + +/* + * We're assuming that there won't be a whole lot of excludes, + * so it's OK to use a stupid algorithm. + */ +struct exclude { + LIST_ENTRY(exclude) link; + const char *glob; + int pathname; +}; +static LIST_HEAD(, exclude) excludes; + +void +init_excludes(void) +{ + LIST_INIT(&excludes); +} + +int +read_excludes_file(const char *name) +{ + FILE *fp; + char *buf, *lbuf; + struct exclude *e; + size_t len; + + + fp = fopen(name, "r"); + if (fp == NULL) { + return 1; + } + + lbuf = NULL; + while ((buf = fgetln(fp, &len))) { + if (buf[len - 1] == '\n') { + if (len == 1) + continue; + buf[len - 1] = '\0'; + } else { + len++; + if ((lbuf = malloc(len)) == NULL) + err(1, NULL); + memcpy(lbuf, buf, len - 1); + lbuf[len - 1] = '\0'; + buf = lbuf; + } + + if ((e = malloc(sizeof *e)) == NULL) + err(1, NULL); + if ((e->glob = malloc(len)) == NULL) + err(1, NULL); + memcpy((char *) e->glob, buf, len); + if (strchr(e->glob, '/')) + e->pathname = 1; + else + e->pathname = 0; + LIST_INSERT_HEAD(&excludes, e, link); + } + free(lbuf); + fclose(fp); + + return 0; +} + +int +check_excludes(const char *fname, const char *path) +{ + struct exclude *e; + + /* Remove leading dot-slash before path match */ + if ((path[0] == '.') && (path[1] == '/')) + path += 2; + + LIST_FOREACH(e, &excludes, link) { + if ((e->pathname && !fnmatch(e->glob, path, FNM_PATHNAME)) + || !fnmatch(e->glob, fname, FNM_PATHNAME)) + return 1; + } + return 0; +} Index: extern.h =================================================================== RCS file: /cvs/src/usr.sbin/mtree/extern.h,v retrieving revision 1.8 diff -u -p -r1.8 extern.h --- extern.h 10 Aug 2005 00:42:09 -0000 1.8 +++ extern.h 20 Jun 2014 12:45:35 -0000 @@ -46,3 +46,6 @@ u_int parsekey(char *, int *); char *rlink(char *); struct _node *spec(void); int verify(void); +int check_excludes(const char *, const char*); +void init_excludes(void); +int read_excludes_file(const char*); Index: mtree.8 =================================================================== RCS file: /cvs/src/usr.sbin/mtree/mtree.8,v retrieving revision 1.37 diff -u -p -r1.37 mtree.8 --- mtree.8 10 Jan 2014 20:20:34 -0000 1.37 +++ mtree.8 20 Jun 2014 12:45:35 -0000 @@ -45,6 +45,7 @@ .Op Fl k Ar keywords .Op Fl p Ar path .Op Fl s Ar seed +.Op Fl X Ar exclude-list .Ek .Sh DESCRIPTION The utility @@ -147,6 +148,20 @@ option except a status of 2 is returned did not match the specification. .It Fl x Don't descend below mount points in the file hierarchy. +.It Fl X Ar exclude-list +The specified file contains +.Xr fnmatch 3 +patterns matching files to be excluded from +the specification, one to a line. +If the pattern contains a +.Ql \&/ +character, it will be matched against entire pathnames (relative to +the starting directory); otherwise, +it will be matched against basenames only. +No comments are allowed in +the +.Ar exclude-list +file. .El .Pp Specifications are mostly composed of Index: mtree.c =================================================================== RCS file: /cvs/src/usr.sbin/mtree/mtree.c,v retrieving revision 1.21 diff -u -p -r1.21 mtree.c --- mtree.c 27 Nov 2013 13:32:02 -0000 1.21 +++ mtree.c 20 Jun 2014 12:45:35 -0000 @@ -46,6 +46,7 @@ int cflag, dflag, eflag, iflag, lflag, n uflag, Uflag; u_int keys; char fullpath[MAXPATHLEN]; +char *excludefile = NULL; static void usage(void); @@ -60,7 +61,7 @@ main(int argc, char *argv[]) dir = NULL; keys = KEYDEFAULT; - while ((ch = getopt(argc, argv, "cdef:iK:k:lnp:qrs:tUux")) != -1) + while ((ch = getopt(argc, argv, "cdef:iK:k:lnp:qrs:tUuxX:")) != -1) switch(ch) { case 'c': cflag = 1; @@ -123,6 +124,10 @@ main(int argc, char *argv[]) case 'x': ftsoptions |= FTS_XDEV; break; + case 'X': + if ((excludefile = realpath(optarg, NULL)) == NULL) + err(1, "%s", optarg); + break; case '?': default: usage(); @@ -133,6 +138,15 @@ main(int argc, char *argv[]) if (argc) usage(); + if (excludefile) { + init_excludes(); + if (read_excludes_file(excludefile)) { + warn("%s", excludefile); + free(excludefile); + excludefile = NULL; + } + } + if (dir && chdir(dir)) error("%s: %s", dir, strerror(errno)); @@ -158,6 +172,6 @@ usage(void) (void)fprintf(stderr, "usage: mtree [-cdeilnqrtUux] [-f spec] [-K keywords] " "[-k keywords] [-p path]\n" - " [-s seed]\n"); + " [-s seed] [-X excludes]\n"); exit(1); } Index: verify.c =================================================================== RCS file: /cvs/src/usr.sbin/mtree/verify.c,v retrieving revision 1.19 diff -u -p -r1.19 verify.c --- verify.c 27 Oct 2009 23:59:53 -0000 1.19 +++ verify.c 20 Jun 2014 12:45:35 -0000 @@ -79,6 +79,10 @@ vwalk(void) level = root; specdepth = rval = 0; while ((p = fts_read(t))) { + if (check_excludes(p->fts_name, p->fts_path)) { + fts_set(t, p, FTS_SKIP); + continue; + } switch(p->fts_info) { case FTS_D: break;
-- Manuel Giraud