fast-import: allow ls or filecopy of the root tree
authorJohn Keeping <john@keeping.me.uk>
Sun, 23 Jun 2013 14:58:21 +0000 (15:58 +0100)
committerJunio C Hamano <gitster@pobox.com>
Sun, 23 Jun 2013 21:22:28 +0000 (14:22 -0700)
Commit 178e1de (fast-import: don't allow 'ls' of path with empty
components, 2012-03-09) restricted paths which:

. contain an empty directory component (e.g. foo//bar is invalid),
. end with a directory separator (e.g. foo/ is invalid),
. start with a directory separator (e.g. /foo is invalid).

However, the implementation also caught the empty path, which should
represent the root tree. Relax this restriction so that the empty path
is explicitly allowed and refers to the root tree.

Reported-by: Dave Abrahams <dave@boostpro.com>
Signed-off-by: John Keeping <john@keeping.me.uk>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
fast-import.c
t/t9300-fast-import.sh
index ea1b3217fed57776eadb008f0659ad2f2dff515d..5da07e83e533b8cacb168ec8d45ef942004e6d65 100644 (file)
@@ -1629,7 +1629,8 @@ static int tree_content_remove(
 static int tree_content_get(
        struct tree_entry *root,
        const char *p,
-       struct tree_entry *leaf)
+       struct tree_entry *leaf,
+       int allow_root)
 {
        struct tree_content *t;
        const char *slash1;
@@ -1641,31 +1642,39 @@ static int tree_content_get(
                n = slash1 - p;
        else
                n = strlen(p);
-       if (!n)
+       if (!n && !allow_root)
                die("Empty path component found in input");
 
        if (!root->tree)
                load_tree(root);
+
+       if (!n) {
+               e = root;
+               goto found_entry;
+       }
+
        t = root->tree;
        for (i = 0; i < t->entry_count; i++) {
                e = t->entries[i];
                if (e->name->str_len == n && !strncmp_icase(p, e->name->str_dat, n)) {
-                       if (!slash1) {
-                               memcpy(leaf, e, sizeof(*leaf));
-                               if (e->tree && is_null_sha1(e->versions[1].sha1))
-                                       leaf->tree = dup_tree_content(e->tree);
-                               else
-                                       leaf->tree = NULL;
-                               return 1;
-                       }
+                       if (!slash1)
+                               goto found_entry;
                        if (!S_ISDIR(e->versions[1].mode))
                                return 0;
                        if (!e->tree)
                                load_tree(e);
-                       return tree_content_get(e, slash1 + 1, leaf);
+                       return tree_content_get(e, slash1 + 1, leaf, 0);
                }
        }
        return 0;
+
+found_entry:
+       memcpy(leaf, e, sizeof(*leaf));
+       if (e->tree && is_null_sha1(e->versions[1].sha1))
+               leaf->tree = dup_tree_content(e->tree);
+       else
+               leaf->tree = NULL;
+       return 1;
 }
 
 static int update_branch(struct branch *b)
@@ -2415,7 +2424,7 @@ static void file_change_cr(struct branch *b, int rename)
        if (rename)
                tree_content_remove(&b->branch_tree, s, &leaf);
        else
-               tree_content_get(&b->branch_tree, s, &leaf);
+               tree_content_get(&b->branch_tree, s, &leaf, 1);
        if (!leaf.versions[1].mode)
                die("Path %s not in branch", s);
        if (!*d) {      /* C "path/to/subdir" "" */
@@ -3067,7 +3076,7 @@ static void parse_ls(struct branch *b)
                        die("Garbage after path in: %s", command_buf.buf);
                p = uq.buf;
        }
-       tree_content_get(root, p, &leaf);
+       tree_content_get(root, p, &leaf, 1);
        /*
         * A directory in preparation would have a sha1 of zero
         * until it is saved.  Save, for simplicity.
index f4b93557a6f76a9691ee81d57557d0c2192e5087..04385a7250fa0f5c68a469ef72b68953aafb78d7 100755 (executable)
@@ -1253,7 +1253,7 @@ test_expect_success \
         git diff-tree -C --find-copies-harder -r N4 N6 >actual &&
         compare_diff_raw expect actual'
 
-test_expect_failure \
+test_expect_success \
        'N: copy root by path' \
        'cat >expect <<-\EOF &&
        :100755 100755 f1fb5da718392694d0076d677d6d0e364c79b0bc f1fb5da718392694d0076d677d6d0e364c79b0bc C100   file2/newf      oldroot/file2/newf
@@ -2988,7 +2988,7 @@ test_expect_success 'S: ls with garbage after sha1 must fail' '
 ###
 # Setup is carried over from series S.
 
-test_expect_failure 'T: ls root tree' '
+test_expect_success 'T: ls root tree' '
        sed -e "s/Z\$//" >expect <<-EOF &&
        040000 tree $(git rev-parse S^{tree})   Z
        EOF