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 pathnamemaint
						commit
						f30366b27a
					
				
							
								
								
									
										25
									
								
								attr.c
								
								
								
								
							
							
						
						
									
										25
									
								
								attr.c
								
								
								
								
							|  | @ -657,24 +657,24 @@ static void prepare_attr_stack(const char *path, int dirlen) | |||
| } | ||||
|  | ||||
| static int path_matches(const char *pathname, int pathlen, | ||||
| 			const char *basename, | ||||
| 			int basename_offset, | ||||
| 			const struct pattern *pat, | ||||
| 			const char *base, int baselen) | ||||
| { | ||||
| 	const char *pattern = pat->pattern; | ||||
| 	int prefix = pat->nowildcardlen; | ||||
| 	int isdir = (pathlen && pathname[pathlen - 1] == '/'); | ||||
|  | ||||
| 	if ((pat->flags & EXC_FLAG_MUSTBEDIR) && | ||||
| 	    ((!pathlen) || (pathname[pathlen-1] != '/'))) | ||||
| 	if ((pat->flags & EXC_FLAG_MUSTBEDIR) && !isdir) | ||||
| 		return 0; | ||||
|  | ||||
| 	if (pat->flags & EXC_FLAG_NODIR) { | ||||
| 		return match_basename(basename, | ||||
| 				      pathlen - (basename - pathname), | ||||
| 		return match_basename(pathname + basename_offset, | ||||
| 				      pathlen - basename_offset - isdir, | ||||
| 				      pattern, prefix, | ||||
| 				      pat->patternlen, pat->flags); | ||||
| 	} | ||||
| 	return match_pathname(pathname, pathlen, | ||||
| 	return match_pathname(pathname, pathlen - isdir, | ||||
| 			      base, baselen, | ||||
| 			      pattern, prefix, pat->patternlen, pat->flags); | ||||
| } | ||||
|  | @ -703,7 +703,7 @@ static int fill_one(const char *what, struct match_attr *a, int rem) | |||
| 	return rem; | ||||
| } | ||||
|  | ||||
| static int fill(const char *path, int pathlen, const char *basename, | ||||
| static int fill(const char *path, int pathlen, int basename_offset, | ||||
| 		struct attr_stack *stk, int rem) | ||||
| { | ||||
| 	int i; | ||||
|  | @ -713,7 +713,7 @@ static int fill(const char *path, int pathlen, const char *basename, | |||
| 		struct match_attr *a = stk->attrs[i]; | ||||
| 		if (a->is_macro) | ||||
| 			continue; | ||||
| 		if (path_matches(path, pathlen, basename, | ||||
| 		if (path_matches(path, pathlen, basename_offset, | ||||
| 				 &a->u.pat, base, stk->originlen)) | ||||
| 			rem = fill_one("fill", a, rem); | ||||
| 	} | ||||
|  | @ -752,7 +752,8 @@ static void collect_all_attrs(const char *path) | |||
| { | ||||
| 	struct attr_stack *stk; | ||||
| 	int i, pathlen, rem, dirlen; | ||||
| 	const char *basename, *cp, *last_slash = NULL; | ||||
| 	const char *cp, *last_slash = NULL; | ||||
| 	int basename_offset; | ||||
|  | ||||
| 	for (cp = path; *cp; cp++) { | ||||
| 		if (*cp == '/' && cp[1]) | ||||
|  | @ -760,10 +761,10 @@ static void collect_all_attrs(const char *path) | |||
| 	} | ||||
| 	pathlen = cp - path; | ||||
| 	if (last_slash) { | ||||
| 		basename = last_slash + 1; | ||||
| 		basename_offset = last_slash + 1 - path; | ||||
| 		dirlen = last_slash - path; | ||||
| 	} else { | ||||
| 		basename = path; | ||||
| 		basename_offset = 0; | ||||
| 		dirlen = 0; | ||||
| 	} | ||||
|  | ||||
|  | @ -773,7 +774,7 @@ static void collect_all_attrs(const char *path) | |||
|  | ||||
| 	rem = attr_nr; | ||||
| 	for (stk = attr_stack; 0 < rem && stk; stk = stk->prev) | ||||
| 		rem = fill(path, pathlen, basename, stk, rem); | ||||
| 		rem = fill(path, pathlen, basename_offset, stk, rem); | ||||
| } | ||||
|  | ||||
| int git_check_attr(const char *path, int num, struct git_attr_check *check) | ||||
|  |  | |||
							
								
								
									
										58
									
								
								dir.c
								
								
								
								
							
							
						
						
									
										58
									
								
								dir.c
								
								
								
								
							|  | @ -59,6 +59,35 @@ inline int git_fnmatch(const char *pattern, const char *string, | |||
| 	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; | ||||
| 	} | ||||
|  | ||||
| 	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; | ||||
|  | @ -626,15 +655,20 @@ int match_basename(const char *basename, int basenamelen, | |||
| 		   int flags) | ||||
| { | ||||
| 	if (prefix == patternlen) { | ||||
| 		if (!strcmp_icase(pattern, basename)) | ||||
| 		if (patternlen == basenamelen && | ||||
| 		    !strncmp_icase(pattern, basename, basenamelen)) | ||||
| 			return 1; | ||||
| 	} else if (flags & EXC_FLAG_ENDSWITH) { | ||||
| 		/* "*literal" matching against "fooliteral" */ | ||||
| 		if (patternlen - 1 <= basenamelen && | ||||
| 		    !strcmp_icase(pattern + 1, | ||||
| 				  basename + basenamelen - patternlen + 1)) | ||||
| 		    !strncmp_icase(pattern + 1, | ||||
| 				   basename + basenamelen - (patternlen - 1), | ||||
| 				   patternlen - 1)) | ||||
| 			return 1; | ||||
| 	} else { | ||||
| 		if (fnmatch_icase(pattern, basename, 0) == 0) | ||||
| 		if (fnmatch_icase_mem(pattern, patternlen, | ||||
| 				      basename, basenamelen, | ||||
| 				      0) == 0) | ||||
| 			return 1; | ||||
| 	} | ||||
| 	return 0; | ||||
|  | @ -654,6 +688,7 @@ int match_pathname(const char *pathname, int pathlen, | |||
| 	 */ | ||||
| 	if (*pattern == '/') { | ||||
| 		pattern++; | ||||
| 		patternlen--; | ||||
| 		prefix--; | ||||
| 	} | ||||
|  | ||||
|  | @ -680,13 +715,22 @@ int match_pathname(const char *pathname, int pathlen, | |||
| 		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, | ||||
| 				 WM_PATHNAME) == 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  |  | |||
|  | @ -27,6 +27,25 @@ test_expect_success 'setup' ' | |||
| 	echo ignored-only-if-dir/ export-ignore >>.git/info/attributes && | ||||
| 	git add ignored-only-if-dir && | ||||
|  | ||||
| 	mkdir -p ignored-without-slash && | ||||
| 	echo "ignored without slash" >ignored-without-slash/foo && | ||||
| 	git add ignored-without-slash/foo && | ||||
| 	echo "ignored-without-slash export-ignore" >>.git/info/attributes && | ||||
|  | ||||
| 	mkdir -p wildcard-without-slash && | ||||
| 	echo "ignored without slash" >wildcard-without-slash/foo && | ||||
| 	git add wildcard-without-slash/foo && | ||||
| 	echo "wild*-without-slash export-ignore" >>.git/info/attributes && | ||||
|  | ||||
| 	mkdir -p deep/and/slashless && | ||||
| 	echo "ignored without slash" >deep/and/slashless/foo && | ||||
| 	git add deep/and/slashless/foo && | ||||
| 	echo "deep/and/slashless export-ignore" >>.git/info/attributes && | ||||
|  | ||||
| 	mkdir -p deep/with/wildcard && | ||||
| 	echo "ignored without slash" >deep/with/wildcard/foo && | ||||
| 	git add deep/with/wildcard/foo && | ||||
| 	echo "deep/*t*/wildcard export-ignore" >>.git/info/attributes && | ||||
|  | ||||
| 	mkdir -p one-level-lower/two-levels-lower/ignored-only-if-dir && | ||||
| 	echo ignored by ignored dir >one-level-lower/two-levels-lower/ignored-only-if-dir/ignored-by-ignored-dir && | ||||
|  | @ -49,6 +68,14 @@ test_expect_exists	archive/not-ignored-dir/ignored-only-if-dir | |||
| test_expect_exists	archive/not-ignored-dir/ | ||||
| test_expect_missing	archive/ignored-only-if-dir/ | ||||
| test_expect_missing	archive/ignored-ony-if-dir/ignored-by-ignored-dir | ||||
| test_expect_missing	archive/ignored-without-slash/ && | ||||
| test_expect_missing	archive/ignored-without-slash/foo && | ||||
| test_expect_missing	archive/wildcard-without-slash/ | ||||
| test_expect_missing	archive/wildcard-without-slash/foo && | ||||
| test_expect_missing	archive/deep/and/slashless/ && | ||||
| test_expect_missing	archive/deep/and/slashless/foo && | ||||
| test_expect_missing	archive/deep/with/wildcard/ && | ||||
| test_expect_missing	archive/deep/with/wildcard/foo && | ||||
| test_expect_exists	archive/one-level-lower/ | ||||
| test_expect_missing	archive/one-level-lower/two-levels-lower/ignored-only-if-dir/ | ||||
| test_expect_missing	archive/one-level-lower/two-levels-lower/ignored-ony-if-dir/ignored-by-ignored-dir | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Junio C Hamano
						Junio C Hamano