aboutsummaryrefslogtreecommitdiffstats
path: root/exclude.c
diff options
context:
space:
mode:
authorWayne Davison <wayned@samba.org>2003-05-01 19:33:54 +0000
committerWayne Davison <wayned@samba.org>2003-05-01 19:33:54 +0000
commit170381c0524611c671d68e1ac3c690f4b4811389 (patch)
treeac8babc6bace557e2336885b03a33709e1e2b89a /exclude.c
parent8113a033dd61d6cd0eb8b2b19de5d0be057a9421 (diff)
downloadandroid_external_rsync-170381c0524611c671d68e1ac3c690f4b4811389.tar.gz
android_external_rsync-170381c0524611c671d68e1ac3c690f4b4811389.tar.bz2
android_external_rsync-170381c0524611c671d68e1ac3c690f4b4811389.zip
Fixed some matching bugs; made the logic of the matching code a little
clearer by using defined flags; added several comments; optimized the matching of an anchored literal string.
Diffstat (limited to 'exclude.c')
-rw-r--r--exclude.c63
1 files changed, 52 insertions, 11 deletions
diff --git a/exclude.c b/exclude.c
index eba9f025..135f6cae 100644
--- a/exclude.c
+++ b/exclude.c
@@ -35,6 +35,7 @@ static struct exclude_struct **exclude_list;
static struct exclude_struct *make_exclude(const char *pattern, int include)
{
struct exclude_struct *ret;
+ char *cp;
ret = (struct exclude_struct *)malloc(sizeof(*ret));
if (!ret) out_of_memory("make_exclude");
@@ -55,8 +56,7 @@ static struct exclude_struct *make_exclude(const char *pattern, int include)
if (!ret->pattern) out_of_memory("make_exclude");
if (strpbrk(pattern, "*[?")) {
- ret->regular_exp = 1;
- ret->fnmatch_flags = FNM_PATHNAME;
+ ret->match_flags |= MATCHFLG_WILD;
if (strstr(pattern, "**")) {
static int tested;
if (!tested) {
@@ -64,7 +64,10 @@ static struct exclude_struct *make_exclude(const char *pattern, int include)
if (fnmatch("a/b/*","a/b/c/d",FNM_PATHNAME)==0)
rprintf(FERROR,"WARNING: fnmatch FNM_PATHNAME is broken on your system\n");
}
- ret->fnmatch_flags = 0;
+ ret->match_flags |= MATCHFLG_WILD2;
+ /* If the pattern starts with **, note that. */
+ if (*pattern == '*' && pattern[1] == '*')
+ ret->match_flags |= MATCHFLG_WILD2_PREFIX;
}
}
@@ -73,9 +76,8 @@ static struct exclude_struct *make_exclude(const char *pattern, int include)
ret->directory = 1;
}
- if (!strchr(ret->pattern,'/')) {
- ret->local = 1;
- }
+ for (cp = ret->pattern; (cp = strchr(cp, '/')) != NULL; cp++)
+ ret->slash_cnt++;
return ret;
}
@@ -94,28 +96,67 @@ static int check_one_exclude(char *name, struct exclude_struct *ex,
int match_start = 0;
char *pattern = ex->pattern;
- if (ex->local && (p=strrchr(name,'/')))
+ /* If the pattern does not have any slashes AND it does not have
+ * a "**" (which could match a slash), then we just match the
+ * name portion of the path. */
+ if (!ex->slash_cnt && !(ex->match_flags & MATCHFLG_WILD2) &&
+ (p = strrchr(name,'/')) != NULL)
name = p+1;
if (!name[0]) return 0;
if (ex->directory && !S_ISDIR(st->st_mode)) return 0;
- if (*pattern == '/' && *name != '/') {
+ if (*pattern == '/') {
match_start = 1;
pattern++;
+ if (*name == '/')
+ name++;
}
- if (ex->regular_exp) {
- if (fnmatch(pattern, name, ex->fnmatch_flags) == 0) {
+ if (ex->match_flags & MATCHFLG_WILD) {
+ int fnmatch_flags = (ex->match_flags & MATCHFLG_WILD2)?
+ 0 : FNM_PATHNAME;
+ /* A non-anchored match with an infix slash and no "**"
+ * needs to match the last slash_cnt+1 name elements. */
+ if (!match_start && ex->slash_cnt &&
+ !(ex->match_flags & MATCHFLG_WILD2)) {
+ int cnt = ex->slash_cnt + 1;
+ for (p = name + strlen(name) - 1; p >= name; p--) {
+ if (*p == '/' && !--cnt)
+ break;
+ }
+ name = p+1;
+ }
+ if (fnmatch(pattern, name, fnmatch_flags) == 0)
return 1;
+ if (ex->match_flags & MATCHFLG_WILD2_PREFIX) {
+ /* If the **-prefixed pattern has a '/' as the next
+ * character, then try to match the rest of the
+ * pattern at the root. */
+ if (pattern[2] == '/' &&
+ fnmatch(pattern+3, name, fnmatch_flags) == 0)
+ return 1;
}
+ else if (!match_start && ex->match_flags & MATCHFLG_WILD2) {
+ /* A non-anchored match with an infix or trailing "**"
+ * (but not a prefixed "**") needs to try matching
+ * after every slash. */
+ while ((name = strchr(name, '/')) != NULL) {
+ name++;
+ if (fnmatch(pattern, name, fnmatch_flags) == 0)
+ return 1;
+ }
+ }
+ } else if (match_start) {
+ if (strcmp(name,pattern) == 0)
+ return 1;
} else {
int l1 = strlen(name);
int l2 = strlen(pattern);
if (l2 <= l1 &&
strcmp(name+(l1-l2),pattern) == 0 &&
- (l1==l2 || (!match_start && name[l1-(l2+1)] == '/'))) {
+ (l1==l2 || name[l1-(l2+1)] == '/')) {
return 1;
}
}