@matheusbsbs / matheus-bagliano / commits / e9de487aa3
Fork 0

sparse-checkout: sanitize for nested folders

If a user provides folders A/ and A/B/ for inclusion in a cone-mode sparse-checkout file, the parsing logic will notice that A/ appears both as a "parent" type pattern and as a "recursive" type pattern. This is unexpected and hence will complain via a warning and revert to the old logic for checking sparse-checkout patterns. Prevent this from happening accidentally by sanitizing the folders for this type of inclusion in the 'git sparse-checkout' builtin. This happens in two ways: 1. Do not include any parent patterns that also appear as recursive patterns. 2. Do not include any recursive patterns deeper than other recursive patterns. In order to minimize duplicate code for scanning parents, create hashmap_contains_parent() method. It takes a strbuf buffer to avoid reallocating a buffer when calling in a tight loop. Helped-by: Eric Wong <e@80x24.org> Helped-by: Johannes Schindelin <Johannes.Schindelin@gmx.de> Signed-off-by: Derrick Stolee <dstolee@microsoft.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Derrick Stolee committed Nov 21, 2019 at 22:04 UTC e9de487aa36aa75b5c9068c6bd07cfb8bf2ee955
2 files changed +29 -4
builtin/sparse-checkout.c
+18 -4
@@ -81,9 +81,17 @@ static void write_cone_to_file(FILE *fp, struct pattern_list *pl)
81 struct pattern_entry *pe;
82 struct hashmap_iter iter;
83 struct string_list sl = STRING_LIST_INIT_DUP;
84 + struct strbuf parent_pattern = STRBUF_INIT;
85
85 - hashmap_for_each_entry(&pl->parent_hashmap, &iter, pe, ent)
86 - string_list_insert(&sl, pe->pattern);
86 + hashmap_for_each_entry(&pl->parent_hashmap, &iter, pe, ent) {
87 + if (hashmap_get_entry(&pl->recursive_hashmap, pe, ent, NULL))
88 + continue;
89 +
90 + if (!hashmap_contains_parent(&pl->recursive_hashmap,
91 + pe->pattern,
92 + &parent_pattern))
93 + string_list_insert(&sl, pe->pattern);
94 + }
95
96 string_list_sort(&sl);
97 string_list_remove_duplicates(&sl, 0);
@@ -99,8 +107,14 @@ static void write_cone_to_file(FILE *fp, struct pattern_list *pl)
107
108 string_list_clear(&sl, 0);
109
102 - hashmap_for_each_entry(&pl->recursive_hashmap, &iter, pe, ent)
103 - string_list_insert(&sl, pe->pattern);
110 + hashmap_for_each_entry(&pl->recursive_hashmap, &iter, pe, ent) {
111 + if (!hashmap_contains_parent(&pl->recursive_hashmap,
112 + pe->pattern,
113 + &parent_pattern))
114 + string_list_insert(&sl, pe->pattern);
115 + }
116 +
117 + strbuf_release(&parent_pattern);
118
119 string_list_sort(&sl);
120 string_list_remove_duplicates(&sl, 0);
t/t1091-sparse-checkout-builtin.sh
+11
@@ -237,4 +237,15 @@ test_expect_success 'cone mode: init and set' '
237 test_cmp expect dir
238 '
239
240 +test_expect_success 'cone mode: set with nested folders' '
241 + git -C repo sparse-checkout set deep deep/deeper1/deepest 2>err &&
242 + test_line_count = 0 err &&
243 + cat >expect <<-EOF &&
244 + /*
245 + !/*/
246 + /deep/
247 + EOF
248 + test_cmp repo/.git/info/sparse-checkout expect
249 +'
250 +
251 test_done