From 560e4370bd809346663a32578cc1837dc66ab1ae Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Sat, 20 Jan 2018 21:47:01 -0800 Subject: [PATCH] cpdup - Enhance -X operation * Enhance -X operation. When the cpignore file is specified as an absolute path, it may contain wildcards which match against the concatenated source path and directory element (as specified in the source), instead of just match against directory elements. * Thus an absolute cpignore file may contain full paths and wildcards. For example, if you: cpdup -X $cwd/mycpignore /tmp /fubar And $cwd/mycpignore (specified with an absolute path) contains: /tmp/xyz/swap* Then cpdup will not copy files that match against /tmp/xyz/swap*. If you specify a relative path for the cpignore file, or use the -x option (instead of -X cpignorefile), operation remains as before and only matches against the directory element. --- bin/cpdup/cpdup.1 | 10 +++++++++ bin/cpdup/cpdup.c | 53 +++++++++++++++++++++++++++++++++++++++++++++-- bin/cpdup/misc.c | 6 ++++-- 3 files changed, 65 insertions(+), 4 deletions(-) diff --git a/bin/cpdup/cpdup.1 b/bin/cpdup/cpdup.1 index b705835928..d19205ac35 100644 --- a/bin/cpdup/cpdup.1 +++ b/bin/cpdup/cpdup.1 @@ -248,6 +248,16 @@ Works the same as but allows you to specify the name of the exclusion file. This file is automatically excluded from the copy. Only one exclusion file may be specified. +.Pp +When an absolute path is used, the same exclusive file is read for +every directory and may contain full paths or wildcarded paths based +on the full source path as specified on the cpdup command line. +.Pp +When a relative path is used (or +.Fl x +is specified), the exclusion file is only applicable to the directory +it resides in and only path elements (the directory elements) are matched +against it. .El .Sh REMOTE COPYING .Nm diff --git a/bin/cpdup/cpdup.c b/bin/cpdup/cpdup.c index 993f64a216..4137681e5a 100644 --- a/bin/cpdup/cpdup.c +++ b/bin/cpdup/cpdup.c @@ -110,6 +110,7 @@ static void InitList(List *list); static void ResetList(List *list); static Node *IterateList(List *list, Node *node, int n); static int AddList(List *list, const char *name, int n, struct stat *st); +static int CheckList(List *list, const char *path, const char *name); static int getbool(const char *str); static char *SplitRemote(char **pathp); static int ChgrpAllowed(gid_t g); @@ -1439,8 +1440,13 @@ ScanDir(List *list, struct HostConf *host, const char *path, /* * ignore . and .. */ - if (strcmp(den->d_name, ".") != 0 && strcmp(den->d_name, "..") != 0) + if (strcmp(den->d_name, ".") != 0 && strcmp(den->d_name, "..") != 0) { + if (UseCpFile && UseCpFile[0] == '/') { + if (CheckList(list, path, den->d_name) == 0) + continue; + } AddList(list, den->d_name, n, statptr); + } } hc_closedir(host, dir); @@ -1586,7 +1592,6 @@ AddList(List *list, const char *name, int n, struct stat *st) * Scan against wildcards. Only a node value of 1 can be a wildcard * ( usually scanned from .cpignore ) */ - for (node = list->li_Hash[0]; node; node = node->no_HNext) { if (strcmp(name, node->no_Name) == 0 || (n != 1 && node->no_Value == 1 && @@ -1623,6 +1628,50 @@ AddList(List *list, const char *name, int n, struct stat *st) return(n); } +/* + * Match against n=1 (cpignore) entries + * + * Returns 0 on match, non-zero if no match + */ +static int +CheckList(List *list, const char *path, const char *name) +{ + char *fpath = NULL; + Node *node; + int hv; + + asprintf(&fpath, "%s/%s", path, name); + + /* + * Scan against wildcards. Only a node value of 1 can be a wildcard + * ( usually scanned from .cpignore ) + */ + for (node = list->li_Hash[0]; node; node = node->no_HNext) { + if (node->no_Value != 1) + continue; + if (fnmatch(node->no_Name, fpath, 0) == 0) { + free(fpath); + return 0; + } + } + + /* + * Look for exact match + */ + hv = shash(fpath); + for (node = list->li_Hash[hv]; node; node = node->no_HNext) { + if (node->no_Value != 1) + continue; + if (strcmp(fpath, node->no_Name) == 0) { + free(fpath); + return 0; + } + } + + free(fpath); + return 1; +} + static int shash(const char *s) { diff --git a/bin/cpdup/misc.c b/bin/cpdup/misc.c index 692d70c4e0..9a5f2e0403 100644 --- a/bin/cpdup/misc.c +++ b/bin/cpdup/misc.c @@ -199,8 +199,10 @@ fatal(const char *ctl, ...) " to be the same.\n" " -VV same as -V but ignore mtime entirely\n" " -x use .cpignore as exclusion file\n" - " -X file specify exclusion file\n" - " Version 1.19 by Matt Dillon, Dima Ruban, & Oliver Fromme\n" + " -X file specify exclusion file (cna match full source\n" + " patch if the exclusion file is specified via\n" + " an absolute path.\n" + " Version 1.20 by Matt Dillon, Dima Ruban, & Oliver Fromme\n" ); exit(0); } else { -- 2.41.0