Until M 040000 <tree> "" syntax was introduced in commit 2794ad5 (fast-import: Allow filemodify to set the root, 2010-10-10), it was impossible for the root entry to refer to an unloaded tree. Update various functions to take that possibility into account. Otherwise M 040000 <tree> "" M 100644 :1 "foo" and similar commands (using D, C, or R after resetting the root tree) segfault. Signed-off-by: Jonathan Nieder <jrnieder@xxxxxxxxx> --- fast-import.c | 20 ++++++++++++++++---- t/t9300-fast-import.sh | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 4 deletions(-) diff --git a/fast-import.c b/fast-import.c index 8f68a89..aaf47c5 100644 --- a/fast-import.c +++ b/fast-import.c @@ -1444,7 +1444,7 @@ static int tree_content_set( const uint16_t mode, struct tree_content *subtree) { - struct tree_content *t = root->tree; + struct tree_content *t; const char *slash1; unsigned int i, n; struct tree_entry *e; @@ -1468,6 +1468,9 @@ static int tree_content_set( if (!slash1 && !S_ISDIR(mode) && subtree) die("Non-directories cannot have subtrees"); + if (!root->tree) + load_tree(root); + t = root->tree; for (i = 0; i < t->entry_count; i++) { e = t->entries[i]; if (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) { @@ -1523,7 +1526,7 @@ static int tree_content_remove( const char *p, struct tree_entry *backup_leaf) { - struct tree_content *t = root->tree; + struct tree_content *t; const char *slash1; unsigned int i, n; struct tree_entry *e; @@ -1534,6 +1537,9 @@ static int tree_content_remove( else n = strlen(p); + if (!root->tree) + load_tree(root); + t = root->tree; for (i = 0; i < t->entry_count; i++) { e = t->entries[i]; if (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) { @@ -1581,7 +1587,7 @@ static int tree_content_get( const char *p, struct tree_entry *leaf) { - struct tree_content *t = root->tree; + struct tree_content *t; const char *slash1; unsigned int i, n; struct tree_entry *e; @@ -1592,6 +1598,9 @@ static int tree_content_get( else n = strlen(p); + if (!root->tree) + load_tree(root); + t = root->tree; for (i = 0; i < t->entry_count; i++) { e = t->entries[i]; if (e->name->str_len == n && !strncmp(p, e->name->str_dat, n)) { @@ -2056,13 +2065,16 @@ static uintmax_t do_change_note_fanout( char *fullpath, unsigned int fullpath_len, unsigned char fanout) { - struct tree_content *t = root->tree; + struct tree_content *t; struct tree_entry *e, leaf; unsigned int i, tmp_hex_sha1_len, tmp_fullpath_len; uintmax_t num_notes = 0; unsigned char sha1[20]; char realpath[60]; + if (!root->tree); + load_tree(root); + t = root->tree; for (i = 0; t && i < t->entry_count; i++) { e = t->entries[i]; tmp_hex_sha1_len = hex_sha1_len + e->name->str_len; diff --git a/t/t9300-fast-import.sh b/t/t9300-fast-import.sh index 3c0cf05..de95a6e 100755 --- a/t/t9300-fast-import.sh +++ b/t/t9300-fast-import.sh @@ -928,6 +928,43 @@ test_expect_success \ git diff-tree -C --find-copies-harder -r N5^^ N5 >actual && compare_diff_raw expect actual' +test_expect_success \ + 'N: copy to root by id and modify' \ + 'echo "hello, world" >expect.foo && + echo hello >expect.bar && + git fast-import <<-SETUP_END && + commit refs/heads/N7 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + hello, tree + COMMIT + + deleteall + M 644 inline foo/bar + data <<EOF + hello + EOF + SETUP_END + + tree=$(git rev-parse --verify N7:) && + git fast-import <<-INPUT_END && + commit refs/heads/N8 + committer $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL> $GIT_COMMITTER_DATE + data <<COMMIT + copy to root by id and modify + COMMIT + + M 040000 $tree "" + M 644 inline foo/foo + data <<EOF + hello, world + EOF + INPUT_END + git show N8:foo/foo >actual.foo && + git show N8:foo/bar >actual.bar && + test_cmp expect.foo actual.foo && + test_cmp expect.bar actual.bar' + ### ### series O ### -- 1.7.2.3 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html