Commit b4e5432ff032c7d05c82ad2871e27f990493d6b7

Edward Thomson 2014-11-05T10:47:19

Merge pull request #2688 from libgit2/cmn/ignore-file-trailing-cr ignore: consider files with a CR in their names

diff --git a/src/attr_file.c b/src/attr_file.c
index 07ffacb..5620752 100644
--- a/src/attr_file.c
+++ b/src/attr_file.c
@@ -543,7 +543,7 @@ int git_attr_fnmatch__parse(
 	for (scan = pattern; *scan != '\0'; ++scan) {
 		/* scan until (non-escaped) white space */
 		if (git__isspace(*scan) && *(scan - 1) != '\\') {
-			if (!allow_space || (*scan != ' ' && *scan != '\t'))
+			if (!allow_space || (*scan != ' ' && *scan != '\t' && *scan != '\r'))
 				break;
 		}
 
@@ -564,6 +564,15 @@ int git_attr_fnmatch__parse(
 	if ((spec->length = scan - pattern) == 0)
 		return GIT_ENOTFOUND;
 
+	/*
+	 * Remove one trailing \r in case this is a CRLF delimited
+	 * file, in the case of Icon\r\r\n, we still leave the first
+	 * \r there to match against.
+	 */
+	if (pattern[spec->length - 1] == '\r')
+		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/tests/status/ignore.c b/tests/status/ignore.c
index b2af790..7cf8803 100644
--- a/tests/status/ignore.c
+++ b/tests/status/ignore.c
@@ -883,3 +883,35 @@ void test_status_ignore__negative_ignores_without_trailing_slash_inside_ignores(
 	cl_assert(found_parent_child2_file);
 }
 
+void test_status_ignore__filename_with_cr(void)
+{
+	int ignored;
+
+	g_repo = cl_git_sandbox_init("empty_standard_repo");
+	cl_git_mkfile("empty_standard_repo/.gitignore", "Icon\r\r\n");
+
+	cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Icon\r"));
+	cl_assert_equal_i(1, ignored);
+
+	cl_git_mkfile("empty_standard_repo/.gitignore", "Ico\rn\n");
+	cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Ico\rn"));
+	cl_assert_equal_i(1, ignored);
+
+	cl_git_mkfile("empty_standard_repo/.gitignore", "Ico\rn\r\n");
+	cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Ico\rn"));
+	cl_assert_equal_i(1, ignored);
+	cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Ico\rn\r"));
+	cl_assert_equal_i(0, ignored);
+
+	cl_git_mkfile("empty_standard_repo/.gitignore", "Ico\rn\r\r\n");
+	cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Ico\rn\r"));
+	cl_assert_equal_i(1, ignored);
+	cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Icon\r"));
+	cl_assert_equal_i(0, ignored);
+
+	cl_git_mkfile("empty_standard_repo/.gitignore", "Icon\r\n");
+	cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Icon\r"));
+	cl_assert_equal_i(0, ignored);
+	cl_git_pass(git_ignore_path_is_ignored(&ignored, g_repo, "Icon"));
+	cl_assert_equal_i(1, ignored);
+}