sparse-checkout: warn on globs in cone patterns

In cone mode, the sparse-checkout commmand will write patterns that
allow faster pattern matching. This matching only works if the patterns
in the sparse-checkout file are those written by that command. Users
can edit the sparse-checkout file and create patterns that cause the
cone mode matching to fail.

The cone mode patterns may end in "/*" but otherwise an un-escaped
asterisk or other glob character is invalid. Add checks to disable
cone mode when seeing these values.

A later change will properly handle escaped globs.

Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Derrick Stolee 2020-01-31 20:16:08 +00:00 committed by Junio C Hamano
parent 9e6d3e6417
commit 9abc60f801
2 changed files with 75 additions and 0 deletions

36
dir.c
View File

@ -635,6 +635,7 @@ static void add_pattern_to_hashsets(struct pattern_list *pl, struct path_pattern
struct pattern_entry *translated;
char *truncated;
char *data = NULL;
const char *prev, *cur, *next;
if (!pl->use_cone_patterns)
return;
@ -652,12 +653,47 @@ static void add_pattern_to_hashsets(struct pattern_list *pl, struct path_pattern
}
if (given->patternlen <= 2 ||
*given->pattern == '*' ||
strstr(given->pattern, "**")) {
/* Not a cone pattern. */
warning(_("unrecognized pattern: '%s'"), given->pattern);
goto clear_hashmaps;
}
prev = given->pattern;
cur = given->pattern + 1;
next = given->pattern + 2;
while (*cur) {
/* Watch for glob characters '*', '\', '[', '?' */
if (!is_glob_special(*cur))
goto increment;
/* But only if *prev != '\\' */
if (*prev == '\\')
goto increment;
/* But allow the initial '\' */
if (*cur == '\\' &&
is_glob_special(*next))
goto increment;
/* But a trailing '/' then '*' is fine */
if (*prev == '/' &&
*cur == '*' &&
*next == 0)
goto increment;
/* Not a cone pattern. */
warning(_("unrecognized pattern: '%s'"), given->pattern);
goto clear_hashmaps;
increment:
prev++;
cur++;
next++;
}
if (given->patternlen > 2 &&
!strcmp(given->pattern + given->patternlen - 2, "/*")) {
if (!(given->flags & PATTERN_FLAG_NEGATIVE)) {

View File

@ -348,4 +348,43 @@ test_expect_success 'pattern-checks: too short' '
check_read_tree_errors repo "a" "disabling cone pattern matching"
'
test_expect_success 'pattern-checks: trailing "*"' '
cat >repo/.git/info/sparse-checkout <<-\EOF &&
/*
!/*/
/a*
EOF
check_read_tree_errors repo "a" "disabling cone pattern matching"
'
test_expect_success 'pattern-checks: starting "*"' '
cat >repo/.git/info/sparse-checkout <<-\EOF &&
/*
!/*/
*eep/
EOF
check_read_tree_errors repo "a deep" "disabling cone pattern matching"
'
test_expect_success 'pattern-checks: contained glob characters' '
for c in "[a]" "\\" "?" "*"
do
cat >repo/.git/info/sparse-checkout <<-EOF &&
/*
!/*/
something$c-else/
EOF
check_read_tree_errors repo "a" "disabling cone pattern matching"
done
'
test_expect_success 'pattern-checks: escaped "*"' '
cat >repo/.git/info/sparse-checkout <<-\EOF &&
/*
!/*/
/does\*not\*exist/
EOF
check_read_tree_errors repo "a" ""
'
test_done