Commit 1c3018eb by Carlos Martín Nieto

ignore: fix directory limits when searching for star-star

In order to match the star-star, we disable the flag that's looking for
a single path element, but that leads to searching for the pattern in
the middle of elements in the input string.

Mark when we're handing a star-star so we jump over the elements in our
attempt to match the part of the pattern that comes after the star-star.

While here, tighten up the check so we don't allow invalid rules
through.
parent 0f362716
...@@ -69,7 +69,8 @@ p_fnmatchx(const char *pattern, const char *string, int flags, size_t recurs) ...@@ -69,7 +69,8 @@ p_fnmatchx(const char *pattern, const char *string, int flags, size_t recurs)
if (recurs-- == 0) if (recurs-- == 0)
return FNM_NORES; return FNM_NORES;
for (stringstart = string;;) for (stringstart = string;;) {
bool match_slash = false;
switch (c = *pattern++) { switch (c = *pattern++) {
case EOS: case EOS:
if ((flags & FNM_LEADING_DIR) && *string == '/') if ((flags & FNM_LEADING_DIR) && *string == '/')
...@@ -93,11 +94,17 @@ p_fnmatchx(const char *pattern, const char *string, int flags, size_t recurs) ...@@ -93,11 +94,17 @@ p_fnmatchx(const char *pattern, const char *string, int flags, size_t recurs)
* It will be restored if/when we recurse below. * It will be restored if/when we recurse below.
*/ */
if (c == '*') { if (c == '*') {
flags &= ~FNM_PATHNAME;
while (c == '*')
c = *++pattern; c = *++pattern;
if (c == '/') /* star-star-slash is at the end, match by default */
if (c == EOS)
return 0;
/* Double-star must be at end or between slashes */
if (c != '/')
return (FNM_NOMATCH);
c = *++pattern; c = *++pattern;
flags &= ~FNM_PATHNAME;
match_slash = true;
} }
if (*string == '.' && (flags & FNM_PERIOD) && if (*string == '.' && (flags & FNM_PERIOD) &&
...@@ -128,8 +135,18 @@ p_fnmatchx(const char *pattern, const char *string, int flags, size_t recurs) ...@@ -128,8 +135,18 @@ p_fnmatchx(const char *pattern, const char *string, int flags, size_t recurs)
return e; return e;
if (test == '/' && (flags & FNM_PATHNAME)) if (test == '/' && (flags & FNM_PATHNAME))
break; break;
/* searching for star-star, so we jump over entire dirs */
if (match_slash) {
const char *slash;
if (!(slash = strchr(string, '/')))
break;
string = slash + 1;
} else {
++string; ++string;
} }
}
return (FNM_NOMATCH); return (FNM_NOMATCH);
case '[': case '[':
if (*string == EOS) if (*string == EOS)
...@@ -170,6 +187,7 @@ p_fnmatchx(const char *pattern, const char *string, int flags, size_t recurs) ...@@ -170,6 +187,7 @@ p_fnmatchx(const char *pattern, const char *string, int flags, size_t recurs)
++string; ++string;
break; break;
} }
}
/* NOTREACHED */ /* NOTREACHED */
} }
......
...@@ -134,13 +134,25 @@ void test_attr_ignore__leading_stars(void) ...@@ -134,13 +134,25 @@ void test_attr_ignore__leading_stars(void)
void test_attr_ignore__globs_and_path_delimiters(void) void test_attr_ignore__globs_and_path_delimiters(void)
{ {
cl_git_rewritefile("attr/.gitignore", "foo/bar/**");
assert_is_ignored(true, "foo/bar/baz");
assert_is_ignored(true, "foo/bar/baz/quux");
cl_git_rewritefile("attr/.gitignore", "_*/");
assert_is_ignored(true, "sub/_test/a/file");
assert_is_ignored(false, "test_folder/file");
assert_is_ignored(true, "_test/file");
assert_is_ignored(true, "_test/a/file");
cl_git_rewritefile("attr/.gitignore", "**/_*/"); cl_git_rewritefile("attr/.gitignore", "**/_*/");
assert_is_ignored(true, "sub/_test/a/file");
assert_is_ignored(false, "test_folder/file"); assert_is_ignored(false, "test_folder/file");
assert_is_ignored(true, "_test/file"); assert_is_ignored(true, "_test/file");
assert_is_ignored(true, "_test/a/file"); assert_is_ignored(true, "_test/a/file");
cl_git_rewritefile("attr/.gitignore", "**/_*/foo/bar/*ux"); cl_git_rewritefile("attr/.gitignore", "**/_*/foo/bar/*ux");
assert_is_ignored(true, "sub/_test/foo/bar/qux/file");
assert_is_ignored(true, "_test/foo/bar/qux/file"); assert_is_ignored(true, "_test/foo/bar/qux/file");
assert_is_ignored(true, "_test/foo/bar/crux/file"); assert_is_ignored(true, "_test/foo/bar/crux/file");
assert_is_ignored(false, "_test/foo/bar/code/file"); assert_is_ignored(false, "_test/foo/bar/code/file");
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment