Commit 18831e78bad91827323e1c4ee3401a275fdccc6c

Stefan Sperling 2019-02-10T16:32:21

fix another path ordering bug during status/update crawl

diff --git a/lib/fileindex.c b/lib/fileindex.c
index 69121f8..85b4399 100644
--- a/lib/fileindex.c
+++ b/lib/fileindex.c
@@ -605,25 +605,6 @@ walk_tree(struct got_tree_entry **next, struct got_fileindex *fileindex,
 	return NULL;
 }
 
-/*
- * Decide whether a fileindex entry path is equivalent to a tree entry path,
- * and if it is not, then decide which of the two should be processed first.
- */
-static int
-cmp_entries(const char *ie_path, const char *parent_path,
-    size_t parent_len, const char *te_name)
-{
-	int cmp = strncmp(ie_path, parent_path, parent_len);
-	if (cmp == 0) {
-		const char *ie_name = ie_path + parent_len;
-		while (ie_name[0] == '/')
-			ie_name++;
-		cmp = strcmp(ie_name, te_name);
-	}
-	return cmp;
-
-}
-
 static const struct got_error *
 diff_fileindex_tree(struct got_fileindex *fileindex,
     struct got_fileindex_entry **ie, struct got_tree_object *tree,
@@ -640,8 +621,14 @@ diff_fileindex_tree(struct got_fileindex *fileindex,
 	te = SIMPLEQ_FIRST(&entries->head);
 	while ((*ie && got_path_is_child((*ie)->path, path, path_len)) || te) {
 		if (te && *ie) {
-			int cmp = cmp_entries((*ie)->path, path, path_len,
-			    te->name);
+			char *te_path;
+			int cmp;
+			if (asprintf(&te_path, "%s/%s", path, te->name) == -1) {
+				err = got_error_from_errno();
+				break;
+			}
+			cmp = got_path_cmp((*ie)->path, te_path);
+			free(te_path);
 			if (cmp == 0) {
 				err = cb->diff_old_new(cb_arg, *ie, te,
 				    path);
@@ -799,10 +786,16 @@ diff_fileindex_dir(struct got_fileindex *fileindex,
 	dle = TAILQ_FIRST(&dirlist);
 	while ((*ie && got_path_is_child((*ie)->path, path, path_len)) || dle) {
 		if (dle && *ie) {
+			char *de_path;
 			int cmp;
 			de = dle->data;
-			cmp = cmp_entries((*ie)->path, path, path_len,
-			    de->d_name);
+			if (asprintf(&de_path, "%s/%s", path,
+			    de->d_name) == -1) {
+				err = got_error_from_errno();
+				goto done;
+			}
+			cmp = got_path_cmp((*ie)->path, de_path);
+			free(de_path);
 			if (cmp == 0) {
 				err = cb->diff_old_new(cb_arg, *ie, de, path);
 				if (err)
diff --git a/regress/cmdline/status.sh b/regress/cmdline/status.sh
index 024aa63..e1df9d4 100755
--- a/regress/cmdline/status.sh
+++ b/regress/cmdline/status.sh
@@ -202,8 +202,57 @@ function test_status_shows_local_mods_after_update {
 	test_done "$testroot" "$ret"
 }
 
+function test_status_unversioned_subdirs {
+	local testroot=`test_init status_unversioned_subdirs 1`
+
+	mkdir $testroot/repo/cdfs/
+	touch $testroot/repo/cdfs/Makefile
+	mkdir $testroot/repo/common/
+	touch $testroot/repo/common/Makefile
+	mkdir $testroot/repo/iso/
+	touch $testroot/repo/iso/Makefile
+	mkdir $testroot/repo/ramdisk/
+	touch $testroot/repo/ramdisk/Makefile
+	touch $testroot/repo/ramdisk/list.local
+	mkdir $testroot/repo/ramdisk_cd/
+	touch $testroot/repo/ramdisk_cd/Makefile
+	touch $testroot/repo/ramdisk_cd/list.local
+	(cd $testroot/repo && git add .)
+	git_commit $testroot/repo -m "first commit"
+
+	got checkout $testroot/repo $testroot/wt > /dev/null
+	ret="$?"
+	if [ "$ret" != "0" ]; then
+		test_done "$testroot" "$ret"
+		return 1
+	fi
+
+	mkdir $testroot/wt/cdfs/obj
+	mkdir $testroot/wt/ramdisk/obj
+	mkdir $testroot/wt/ramdisk_cd/obj
+	mkdir $testroot/wt/iso/obj
+
+	echo -n > $testroot/stdout.expected
+
+	# This used to erroneously print:
+	#
+	# !  ramdisk_cd/Makefile
+	# !  ramdisk_cd/list.local
+	# ?  ramdisk_cd/Makefile
+	# ?  ramdisk_cd/list.local
+	(cd $testroot/wt && got status > $testroot/stdout)
+
+	cmp $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_status_basic
 run_test test_status_subdir_no_mods
 run_test test_status_subdir_no_mods2
 run_test test_status_obstructed
 run_test test_status_shows_local_mods_after_update
+run_test test_status_unversioned_subdirs
diff --git a/regress/cmdline/update.sh b/regress/cmdline/update.sh
index 0a6f228..f950162 100755
--- a/regress/cmdline/update.sh
+++ b/regress/cmdline/update.sh
@@ -510,14 +510,14 @@ function test_update_creates_missing_parent {
 	git_commit $testroot/repo -m "restructuring snake tree"
 
 	echo "D  Makefile" > $testroot/stdout.expected
-	echo "D  snake.6" >> $testroot/stdout.expected
-	echo "D  snake.c" >> $testroot/stdout.expected
 	echo "A  snake/Makefile" >> $testroot/stdout.expected
 	echo "A  snake/move.c" >> $testroot/stdout.expected
 	echo "A  snake/pathnames.h" >> $testroot/stdout.expected
 	echo "A  snake/snake.6" >> $testroot/stdout.expected
 	echo "A  snake/snake.c" >> $testroot/stdout.expected
 	echo "A  snake/snake.h" >> $testroot/stdout.expected
+	echo "D  snake.6" >> $testroot/stdout.expected
+	echo "D  snake.c" >> $testroot/stdout.expected
 	echo "A  snscore/Makefile" >> $testroot/stdout.expected
 	echo "A  snscore/snscore.c" >> $testroot/stdout.expected
 	echo -n "Updated to commit " >> $testroot/stdout.expected