match_pathname's declaration in dir.h does not have any description to discourage the use of this function elsewhere as this function is highly tied to how excluded_from_list and path_matches work. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> --- attr.c | 35 +++------------------------ dir.c | 85 +++++++++++++++++++++++++++++++++++++++++------------------------- dir.h | 3 +++ 3 files changed, 59 insertions(+), 64 deletions(-) diff --git a/attr.c b/attr.c index a28ce0d..2fc6353 100644 --- a/attr.c +++ b/attr.c @@ -659,8 +659,6 @@ static int path_matches(const char *pathname, int pathlen, { const char *pattern = pat->pattern; int prefix = pat->nowildcardlen; - const char *name; - int namelen; if (pat->flags & EXC_FLAG_NODIR) { return match_basename(basename, @@ -668,36 +666,9 @@ static int path_matches(const char *pathname, int pathlen, pattern, prefix, pat->patternlen, pat->flags); } - /* - * match with FNM_PATHNAME; the pattern has base implicitly - * in front of it. - */ - if (*pattern == '/') { - pattern++; - prefix--; - } - - /* - * note: unlike excluded_from_list, baselen here does not - * count the trailing slash, and base[] does not end with - * a trailing slash, either. - */ - if (pathlen < baselen + 1 || - (baselen && pathname[baselen] != '/') || - strncmp_icase(pathname, base, baselen)) - return 0; - - namelen = baselen ? pathlen - baselen - 1 : pathlen; - name = pathname + pathlen - namelen; - - /* - * if the non-wildcard part is longer than the remaining - * pathname, surely it cannot match. - */ - if (!namelen || prefix > namelen) - return 0; - - return fnmatch_icase(pattern, name, FNM_PATHNAME) == 0; + return match_pathname(pathname, pathlen, + base, baselen, + pattern, prefix, pat->patternlen, pat->flags); } static int macroexpand_one(int attr_nr, int rem); diff --git a/dir.c b/dir.c index 42c42cd..ee8e711 100644 --- a/dir.c +++ b/dir.c @@ -549,6 +549,53 @@ int match_basename(const char *basename, int basenamelen, return 0; } +int match_pathname(const char *pathname, int pathlen, + const char *base, int baselen, + const char *pattern, int prefix, int patternlen, + int flags) +{ + const char *name; + int namelen; + + /* + * match with FNM_PATHNAME; the pattern has base implicitly + * in front of it. + */ + if (*pattern == '/') { + pattern++; + prefix--; + } + + /* + * baselen does not count the trailing slash. base[] may or + * may not end with a trailing slash though. + */ + if (pathlen < baselen + 1 || + (baselen && pathname[baselen] != '/') || + strncmp_icase(pathname, base, baselen)) + return 0; + + namelen = baselen ? pathlen - baselen - 1 : pathlen; + name = pathname + pathlen - namelen; + + if (prefix) { + /* + * if the non-wildcard part is longer than the + * remaining pathname, surely it cannot match. + */ + if (prefix > namelen) + return 0; + + if (strncmp_icase(pattern, name, prefix)) + return 0; + pattern += prefix; + name += prefix; + namelen -= prefix; + } + + return fnmatch_icase(pattern, name, FNM_PATHNAME) == 0; +} + /* Scan the list and let the last match determine the fate. * Return 1 for exclude, 0 for include and -1 for undecided. */ @@ -563,9 +610,9 @@ int excluded_from_list(const char *pathname, for (i = el->nr - 1; 0 <= i; i--) { struct exclude *x = el->excludes[i]; - const char *name, *exclude = x->pattern; + const char *exclude = x->pattern; int to_exclude = x->flags & EXC_FLAG_NEGATIVE ? 0 : 1; - int namelen, prefix = x->nowildcardlen; + int prefix = x->nowildcardlen; if (x->flags & EXC_FLAG_MUSTBEDIR) { if (*dtype == DT_UNKNOWN) @@ -583,36 +630,10 @@ int excluded_from_list(const char *pathname, continue; } - /* match with FNM_PATHNAME: - * exclude has base (baselen long) implicitly in front of it. - */ - if (*exclude == '/') { - exclude++; - prefix--; - } - - if (pathlen < x->baselen || - (x->baselen && pathname[x->baselen-1] != '/') || - strncmp_icase(pathname, x->base, x->baselen)) - continue; - - namelen = x->baselen ? pathlen - x->baselen : pathlen; - name = pathname + pathlen - namelen; - - /* if the non-wildcard part is longer than the - remaining pathname, surely it cannot match */ - if (prefix > namelen) - continue; - - if (prefix) { - if (strncmp_icase(exclude, name, prefix)) - continue; - exclude += prefix; - name += prefix; - namelen -= prefix; - } - - if (!fnmatch_icase(exclude, name, FNM_PATHNAME)) + assert(x->baselen == 0 || x->base[x->baselen - 1] == '/'); + if (match_pathname(pathname, pathlen, + x->base, x->baselen ? x->baselen - 1 : 0, + exclude, prefix, x->patternlen, x->flags)) return to_exclude; } return -1; /* undecided */ diff --git a/dir.h b/dir.h index d416c5a..11d054a 100644 --- a/dir.h +++ b/dir.h @@ -80,6 +80,9 @@ extern int excluded_from_list(const char *pathname, int pathlen, const char *bas int *dtype, struct exclude_list *el); extern int match_basename(const char *, int, const char *, int, int, int); +extern int match_pathname(const char *, int, + const char *, int, + const char *, int, int, int); struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len); /* -- 1.8.0.rc2.11.g2b79d01 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html