Skip to content

Commit

Permalink
fast-import: allow ls or filecopy of the root tree
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
John Keeping authored and Junio C Hamano committed Jun 23, 2013
1 parent adefdba commit e0eb6b9
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 15 deletions.
35 changes: 22 additions & 13 deletions fast-import.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)
Expand Down Expand Up @@ -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" "" */
Expand Down Expand Up @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions t/t9300-fast-import.sh
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit e0eb6b9

Please sign in to comment.