Commit 251d8771214e91f7118182aed166f649e3914e28

Patrick Steinhardt 2018-04-06T12:24:10

attr_file: fix handling of directory patterns with trailing spaces When comparing whether a path matches a directory rule, we pass the both the path and directory name to `fnmatch` with `GIT_ATTR_FNMATCH_DIRECTORY` being set. `fnmatch` expects the pattern to contain no trailing directory '/', which is why we try to always strip patterns of trailing slashes. We do not handle that case correctly though when the pattern itself has trailing spaces, causing the match to fail. Fix the issue by stripping trailing spaces and tabs for a rule previous to checking whether the pattern is a directory pattern with a trailing '/'. This replaces the whitespace-stripping in our ignore file parsing code, which was stripping whitespaces too late. Add a test to catch future breakage.

diff --git a/src/attr_file.c b/src/attr_file.c
index 55d0c38..f46cce3 100644
--- a/src/attr_file.c
+++ b/src/attr_file.c
@@ -633,6 +633,11 @@ int git_attr_fnmatch__parse(
 		if (--spec->length == 0)
 			return GIT_ENOTFOUND;
 
+	/* Remove trailing spaces. */
+	while (pattern[spec->length - 1] == ' ' || pattern[spec->length - 1] == '\t')
+		if (--spec->length == 0)
+			return GIT_ENOTFOUND;
+
 	if (pattern[spec->length - 1] == '/') {
 		spec->length--;
 		spec->flags = spec->flags | GIT_ATTR_FNMATCH_DIRECTORY;
diff --git a/src/ignore.c b/src/ignore.c
index dddd7e8..76b9972 100644
--- a/src/ignore.c
+++ b/src/ignore.c
@@ -213,16 +213,6 @@ static int parse_ignore_file(
 			if (ignore_case)
 				match->flags |= GIT_ATTR_FNMATCH_ICASE;
 
-			while (match->length > 0) {
-				if (match->pattern[match->length - 1] == ' ' ||
-				    match->pattern[match->length - 1] == '\t') {
-					match->pattern[match->length - 1] = 0;
-					match->length --;
-				} else {
-					break;
-				}
-			}
-
 			scan = git__next_line(scan);
 
 			/*
diff --git a/tests/attr/ignore.c b/tests/attr/ignore.c
index d241c03..165e2ba 100644
--- a/tests/attr/ignore.c
+++ b/tests/attr/ignore.c
@@ -61,6 +61,22 @@ void test_attr_ignore__ignore_space(void)
 	assert_is_ignored(true, "NewFolder/NewFolder/File.txt");
 }
 
+void test_attr_ignore__ignore_dir(void)
+{
+	cl_git_rewritefile("attr/.gitignore", "dir/\n");
+
+	assert_is_ignored(true, "dir");
+	assert_is_ignored(true, "dir/file");
+}
+
+void test_attr_ignore__ignore_dir_with_trailing_space(void)
+{
+	cl_git_rewritefile("attr/.gitignore", "dir/ \n");
+
+	assert_is_ignored(true, "dir");
+	assert_is_ignored(true, "dir/file");
+}
+
 void test_attr_ignore__ignore_root(void)
 {
 	cl_git_rewritefile("attr/.gitignore", "/\n\n/NewFolder\n/NewFolder/NewFolder");