Commit 6069042fcbf7a555c344fa1f020fac9b72d27aad

Carlos Martín Nieto 2014-11-05T16:51:39

ignore: don't leak rules into higher directories A rule "src" in src/.gitignore must only match subdirectories of src/. The current code does not include this context in the match rule and would thus consider this rule to match the top-level src/ directory instead of the intended src/src/. Keep track fo the context in which the rule was defined so we can perform a prefix match.

diff --git a/src/attr_file.c b/src/attr_file.c
index 5620752..e3692ce 100644
--- a/src/attr_file.c
+++ b/src/attr_file.c
@@ -347,6 +347,21 @@ bool git_attr_fnmatch__match(
 	const char *filename;
 	int flags = 0;
 
+	/*
+	 * If the rule was generated in a subdirectory, we must only
+	 * use it for paths inside that directory. We can thus return
+	 * a non-match if the prefixes don't match.
+	 */
+	if (match->containing_dir) {
+		if (match->flags & GIT_ATTR_FNMATCH_ICASE) {
+			if (git__strncasecmp(path->path, match->containing_dir, match->containing_dir_length))
+				return 0;
+		} else {
+			if (git__prefixcmp(path->path, match->containing_dir))
+				return 0;
+		}
+	}
+
 	if (match->flags & GIT_ATTR_FNMATCH_ICASE)
 		flags |= FNM_CASEFOLD;
 	if (match->flags & GIT_ATTR_FNMATCH_LEADINGDIR)
@@ -588,6 +603,17 @@ int git_attr_fnmatch__parse(
 		/* leave FULLPATH match on, however */
 	}
 
+	if (context) {
+		char *slash = strchr(context, '/');
+		size_t len;
+		if (slash) {
+			/* include the slash for easier matching */
+			len = slash - context + 1;
+			spec->containing_dir = git_pool_strndup(pool, context, len);
+			spec->containing_dir_length = len;
+		}
+	}
+
 	if ((spec->flags & GIT_ATTR_FNMATCH_FULLPATH) != 0 &&
 		context != NULL && git_path_root(pattern) < 0)
 	{
diff --git a/src/attr_file.h b/src/attr_file.h
index 87cde7e..93de84d 100644
--- a/src/attr_file.h
+++ b/src/attr_file.h
@@ -52,6 +52,8 @@ extern const char *git_attr__unset;
 typedef struct {
 	char *pattern;
 	size_t length;
+	char *containing_dir;
+	size_t containing_dir_length;
 	unsigned int flags;
 } git_attr_fnmatch;