]> git.ipfire.org Git - thirdparty/git.git/commitdiff
sparse-checkout: unquote C-style strings over --stdin
authorDerrick Stolee <dstolee@microsoft.com>
Fri, 31 Jan 2020 20:16:11 +0000 (20:16 +0000)
committerJunio C Hamano <gitster@pobox.com>
Fri, 31 Jan 2020 21:05:29 +0000 (13:05 -0800)
If a user somehow creates a directory with an asterisk (*) or backslash
(\), then the "git sparse-checkout set" command will struggle to provide
the correct pattern in the sparse-checkout file. When not in cone mode,
the provided pattern is written directly into the sparse-checkout file.
However, in cone mode we expect a list of paths to directories and then
we convert those into patterns.

Even more specifically, the goal is to always allow the following from
the root of a repo:

  git ls-tree --name-only -d HEAD | git sparse-checkout set --stdin

The ls-tree command provides directory names with an unescaped asterisk.
It also quotes the directories that contain an escaped backslash. We
must remove these quotes, then keep the escaped backslashes.

Use unquote_c_style() when parsing lines from stdin. Command-line
arguments will be parsed as-is, assuming the user can do the correct
level of escaping from their environment to match the exact directory
names.

Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/sparse-checkout.c
t/t1091-sparse-checkout-builtin.sh

index cc86b8a0147d74a0afcb12cf6b3940cb0d561a92..6083aa10f27cac3221255dda6931c9dd89c296a6 100644 (file)
@@ -442,8 +442,21 @@ static int sparse_checkout_set(int argc, const char **argv, const char *prefix)
                pl.use_cone_patterns = 1;
 
                if (set_opts.use_stdin) {
-                       while (!strbuf_getline(&line, stdin))
+                       struct strbuf unquoted = STRBUF_INIT;
+                       while (!strbuf_getline(&line, stdin)) {
+                               if (line.buf[0] == '"') {
+                                       strbuf_reset(&unquoted);
+                                       if (unquote_c_style(&unquoted, line.buf, NULL))
+                                               die(_("unable to unquote C-style string '%s'"),
+                                               line.buf);
+
+                                       strbuf_swap(&unquoted, &line);
+                               }
+
                                strbuf_to_cone_pattern(&line, &pl);
+                       }
+
+                       strbuf_release(&unquoted);
                } else {
                        for (i = 0; i < argc; i++) {
                                strbuf_setlen(&line, 0);
index fb8718e64a49046fe3b74590b768e23c630a405b..a46a310740a7f26006a37ecba4703a0c42abc493 100755 (executable)
@@ -405,7 +405,19 @@ test_expect_success BSLASHPSPEC 'pattern-checks: escaped "*"' '
        /zdoes\*not\*exist/
        EOF
        test_cmp expect escaped/.git/info/sparse-checkout &&
-       check_read_tree_errors escaped "a zbad\\dir zdoes*exist"
+       check_read_tree_errors escaped "a zbad\\dir zdoes*exist" &&
+       git -C escaped ls-tree -d --name-only HEAD | git -C escaped sparse-checkout set --stdin &&
+       cat >expect <<-\EOF &&
+       /*
+       !/*/
+       /deep/
+       /folder1/
+       /folder2/
+       /zbad\\dir/
+       /zdoes\*exist/
+       EOF
+       test_cmp expect escaped/.git/info/sparse-checkout &&
+       check_files escaped "a deep folder1 folder2 zbad\\dir zdoes*exist"
 '
 
 test_done