summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Steinhardt <ps@pks.im>2019-06-07 11:12:54 +0200
committerPatrick Steinhardt <ps@pks.im>2019-06-13 11:03:46 +0200
commitb3b6a39d928cf4ecda54468cc5029013363654d7 (patch)
tree653bccaae832563b9e8d1d50e14fd02bf54a3678
parent10ac298c62b40a205e771f50f9171c900c0e50dd (diff)
downloadlibgit2-b3b6a39d928cf4ecda54468cc5029013363654d7.tar.gz
attr_file: account for escaped escapes when searching trailing space
When determining the trailing space length, we need to honor whether spaces are escaped or not. Currently, we do not check whether the escape itself is escaped, though, which might generate an off-by-one in that case as we will simply treat the space as escaped. Fix this by checking whether the backslashes preceding the space are themselves escaped.
-rw-r--r--src/attr_file.c18
-rw-r--r--tests/ignore/path.c17
2 files changed, 32 insertions, 3 deletions
diff --git a/src/attr_file.c b/src/attr_file.c
index 510ed10dd..08b6c3f29 100644
--- a/src/attr_file.c
+++ b/src/attr_file.c
@@ -565,10 +565,22 @@ void git_attr_path__free(git_attr_path *info)
*/
static size_t trailing_space_length(const char *p, size_t len)
{
- size_t n;
+ size_t n, i;
for (n = len; n; n--) {
- if ((p[n-1] != ' ' && p[n-1] != '\t') ||
- (n > 1 && p[n-2] == '\\'))
+ if (p[n-1] != ' ' && p[n-1] != '\t')
+ break;
+
+ /*
+ * Count escape-characters before space. In case where it's an
+ * even number of escape characters, then the escape char itself
+ * is escaped and the whitespace is an unescaped whitespace.
+ * Otherwise, the last escape char is not escaped and the
+ * whitespace in an escaped whitespace.
+ */
+ i = n;
+ while (i > 1 && p[i-2] == '\\')
+ i--;
+ if ((n - i) % 2)
break;
}
return len - n;
diff --git a/tests/ignore/path.c b/tests/ignore/path.c
index 0c22582ac..bfed297c2 100644
--- a/tests/ignore/path.c
+++ b/tests/ignore/path.c
@@ -521,3 +521,20 @@ void test_ignore_path__escaped_slash(void)
assert_is_ignored(true, "inter\\mittent");
assert_is_ignored(true, "trailing\\");
}
+
+void test_ignore_path__escaped_space(void)
+{
+ cl_git_rewritefile(
+ "attr/.gitignore",
+ "foo\\\\ \n"
+ "bar\\\\\\ \n");
+ assert_is_ignored(true, "foo\\");
+ assert_is_ignored(false, "foo\\ ");
+ assert_is_ignored(false, "foo\\\\ ");
+ assert_is_ignored(false, "foo\\\\");
+ assert_is_ignored(true, "bar\\ ");
+ assert_is_ignored(false, "bar\\\\");
+ assert_is_ignored(false, "bar\\\\ ");
+ assert_is_ignored(false, "bar\\\\\\");
+ assert_is_ignored(false, "bar\\\\\\ ");
+}