From: Junio C Hamano Date: Wed, 3 Apr 2013 16:34:04 +0000 (-0700) Subject: Merge branch 'jc/directory-attrs-regression-fix' X-Git-Tag: v1.8.3-rc0~128 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/f30366b27a91dbc18328bccf3067cdfad4f0cfbc Merge branch 'jc/directory-attrs-regression-fix' Fix 1.8.1.x regression that stopped matching "dir" (without trailing slash) to a directory "dir". * jc/directory-attrs-regression-fix: t: check that a pattern without trailing slash matches a directory dir.c::match_pathname(): pay attention to the length of string parameters dir.c::match_pathname(): adjust patternlen when shifting pattern dir.c::match_basename(): pay attention to the length of string parameters attr.c::path_matches(): special case paths that end with a slash attr.c::path_matches(): the basename is part of the pathname --- f30366b27a91dbc18328bccf3067cdfad4f0cfbc diff --cc dir.c index 57394e452e,8fea94e185..1e42b2b150 --- a/dir.c +++ b/dir.c @@@ -37,28 -34,33 +37,57 @@@ int fnmatch_icase(const char *pattern, return fnmatch(pattern, string, flags | (ignore_case ? FNM_CASEFOLD : 0)); } +inline int git_fnmatch(const char *pattern, const char *string, + int flags, int prefix) +{ + int fnm_flags = 0; + if (flags & GFNM_PATHNAME) + fnm_flags |= FNM_PATHNAME; + if (prefix > 0) { + if (strncmp(pattern, string, prefix)) + return FNM_NOMATCH; + pattern += prefix; + string += prefix; + } + if (flags & GFNM_ONESTAR) { + int pattern_len = strlen(++pattern); + int string_len = strlen(string); + return string_len < pattern_len || + strcmp(pattern, + string + string_len - pattern_len); + } + return fnmatch(pattern, string, fnm_flags); +} + + static int fnmatch_icase_mem(const char *pattern, int patternlen, + const char *string, int stringlen, + int flags) + { + int match_status; + struct strbuf pat_buf = STRBUF_INIT; + struct strbuf str_buf = STRBUF_INIT; + const char *use_pat = pattern; + const char *use_str = string; + + if (pattern[patternlen]) { + strbuf_add(&pat_buf, pattern, patternlen); + use_pat = pat_buf.buf; + } + if (string[stringlen]) { + strbuf_add(&str_buf, string, stringlen); + use_str = str_buf.buf; + } + - match_status = fnmatch_icase(use_pat, use_str, flags); ++ if (ignore_case) ++ flags |= WM_CASEFOLD; ++ match_status = wildmatch(use_pat, use_str, flags, NULL); + + strbuf_release(&pat_buf); + strbuf_release(&str_buf); + + return match_status; + } + static size_t common_prefix_len(const char **pathspec) { const char *n, *first; @@@ -680,26 -624,30 +715,35 @@@ int match_pathname(const char *pathname if (strncmp_icase(pattern, name, prefix)) return 0; pattern += prefix; + patternlen -= prefix; name += prefix; namelen -= prefix; + + /* + * If the whole pattern did not have a wildcard, + * then our prefix match is all we need; we + * do not need to call fnmatch at all. + */ + if (!patternlen && !namelen) + return 1; } - return wildmatch(pattern, name, - WM_PATHNAME | (ignore_case ? WM_CASEFOLD : 0), - NULL) == 0; + return fnmatch_icase_mem(pattern, patternlen, + name, namelen, - FNM_PATHNAME) == 0; ++ WM_PATHNAME) == 0; } -/* Scan the list and let the last match determine the fate. - * Return 1 for exclude, 0 for include and -1 for undecided. +/* + * Scan the given exclude list in reverse to see whether pathname + * should be ignored. The first match (i.e. the last on the list), if + * any, determines the fate. Returns the exclude_list element which + * matched, or NULL for undecided. */ -int excluded_from_list(const char *pathname, - int pathlen, const char *basename, int *dtype, - struct exclude_list *el) +static struct exclude *last_exclude_matching_from_list(const char *pathname, + int pathlen, + const char *basename, + int *dtype, + struct exclude_list *el) { int i;