handle empty trees during 'import' and 'checkout'; spotted by sthen@
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113
diff --git a/lib/object_parse.c b/lib/object_parse.c
old mode 100640
new mode 100644
index 4066dbb..a037ceb
--- a/lib/object_parse.c
+++ b/lib/object_parse.c
@@ -728,15 +728,15 @@ got_object_parse_tree(struct got_tree_object **tree, uint8_t *buf, size_t len)
TAILQ_INIT(&pathlist);
- if (remain == 0)
- return got_error(GOT_ERR_BAD_OBJ_DATA);
-
*tree = calloc(1, sizeof(**tree));
if (*tree == NULL)
return got_error_from_errno("calloc");
SIMPLEQ_INIT(&(*tree)->entries.head);
+ if (remain == 0)
+ return NULL; /* tree is empty */
+
while (remain > 0) {
struct got_tree_entry *te;
struct got_pathlist_entry *new = NULL;
diff --git a/lib/repository.c b/lib/repository.c
index b32361c..22355c1 100644
--- a/lib/repository.c
+++ b/lib/repository.c
@@ -1492,8 +1492,12 @@ write_tree(struct got_object_id **new_tree_id, const char *path_dir,
if (de->d_type == DT_DIR) {
err = import_subdir(&new_te, de, path_dir,
ignores, repo, progress_cb, progress_arg);
- if (err)
- goto done;
+ if (err) {
+ if (err->code != GOT_ERR_NO_TREE_ENTRY)
+ goto done;
+ err = NULL;
+ continue;
+ }
} else if (de->d_type == DT_REG) {
err = import_file(&new_te, de, path_dir, repo);
if (err)
@@ -1506,6 +1510,11 @@ write_tree(struct got_object_id **new_tree_id, const char *path_dir,
goto done;
}
+ if (TAILQ_EMPTY(&paths)) {
+ err = got_error(GOT_ERR_NO_TREE_ENTRY);
+ goto done;
+ }
+
TAILQ_FOREACH(pe, &paths, entry) {
struct got_tree_entry *te = pe->data;
char *path;
diff --git a/regress/cmdline/import.sh b/regress/cmdline/import.sh
index ce3cb34..42ff367 100755
--- a/regress/cmdline/import.sh
+++ b/regress/cmdline/import.sh
@@ -196,10 +196,52 @@ function test_import_ignores {
diff -u $testroot/stdout.expected $testroot/stdout
fi
test_done "$testroot" "$ret"
+}
+
+function test_import_empty_dir {
+ local testname=import_empty_dir
+ local testroot=`mktemp -p /tmp -d got-test-$testname-XXXXXXXX`
+
+ got init $testroot/repo
+
+ mkdir $testroot/tree
+ mkdir -p $testroot/tree/empty $testroot/tree/notempty
+ echo "alpha" > $testroot/tree/notempty/alpha
+
+ got import -m 'init' -r $testroot/repo $testroot/tree > $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+ local head_commit=`git_show_head $testroot/repo`
+ echo "A $testroot/tree/notempty/alpha" >> $testroot/stdout.expected
+ echo "Created branch refs/heads/master with commit $head_commit" \
+ >> $testroot/stdout.expected
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ test_done "$testroot" "$ret"
+ return 1
+ fi
+
+ # Verify that Got did not import the empty directory
+ echo "notempty/" > $testroot/stdout.expected
+ echo "notempty/alpha" >> $testroot/stdout.expected
+
+ got tree -r $testroot/repo -R > $testroot/stdout
+ cmp -s $testroot/stdout.expected $testroot/stdout
+ ret="$?"
+ if [ "$ret" != "0" ]; then
+ diff -u $testroot/stdout.expected $testroot/stdout
+ fi
+ test_done "$testroot" "$ret"
}
run_test test_import_basic
run_test test_import_requires_new_branch
run_test test_import_ignores
+run_test test_import_empty_dir