"GOT", but the "O" is a cute, smiling pufferfish. Index | Thread | Search

From:
Stefan Sperling <stsp@stsp.name>
Subject:
status walk regression fix
To:
gameoftrees@openbsd.org
Date:
Tue, 12 Oct 2021 14:41:16 +0200

Download raw body.

Thread
  • Stefan Sperling:

    status walk regression fix

My commit which made 'got status' skip ignore directories has introduced
a regression. In my /usr/src tree I see a missing file being reported:

$ got status
!  gnu/llvm/utils/lit/tests/Inputs/exec-discovery-in-tree/obj/lit.site.cfg
?  sys/dev/acpi/pchgpio.c.orig
?  sys/dev/pci/if_iwx.c.orig
?  sys/dev/pci/if_iwx.c.rej
?  sys/dev/pci/if_iwxvar.h.orig
$ 

The missing file does exist on disk, however. It ends up being reported as
missing because the 'obj' dir is ignored and therefore not visited.

What happens internally is that we detect the path 'obj/lit.site.cfg' as
missing from directory gnu/llvm/utils/lit/tests/Inputs/exec-discovery-in-tree,
which is obviously bogus.

(Curiously, this file only exists in the Git repository, not in CVS.
In CVS it was at the same path without the 'obj' dir:
gnu/llvm/utils/lit/tests/Inputs/exec-discovery-in-tree/lit.site.cfg
and this file was removed from CVS with the llvm 8.0.1 upgrade).

I could reproduce this problem in the test suite by tweaking an existing
test slightly:

test_status_cvsignore --- /tmp/got-test-status_cvsignore-BrSSQK9f/stdout.expected       Tue Oct 12 14:37:07 2021
+++ /tmp/got-test-status_cvsignore-BrSSQK9f/stdout      Tue Oct 12 14:37:08 2021
@@ -2,3 +2,4 @@
 ?  epsilon/.cvsignore
 ?  epsilon/boo
 ?  foop
+!  gamma/delta
test failed; leaving test data in /tmp/got-test-status_cvsignore-BrSSQK9f

To fix this we need to traverse any ignored directory which contains a file
which is tracked by the file index. Fortunately, looking up such files can be
done efficiently by walking the file index RB tree.  Patch below.  ok?

diff 79b1ba5c34990019a1e23d9bbac6188c342d4550 8b9504f54dfa79e560860c0a8f03116992f0c051
blob - fba8eb73431c038f4a91c744d8f6f0c55855c7e0
blob + 91a35e46fce2547ae0c44ba7edf82da9edd9e097
--- lib/fileindex.c
+++ lib/fileindex.c
@@ -987,6 +987,30 @@ free_dirlist(struct got_pathlist_head *dirlist)
 	got_pathlist_free(dirlist);
 }
 
+static int
+have_tracked_file_in_dir(struct got_fileindex *fileindex, const char *path)
+{
+	struct got_fileindex_entry *ie;
+	size_t path_len = strlen(path);
+	int cmp;
+
+	ie = RB_ROOT(&fileindex->entries);
+	while (ie) {
+		if (got_path_is_child(ie->path, path, path_len))
+			return 1;
+		cmp = got_path_cmp(path, ie->path, path_len,
+		    got_fileindex_entry_path_len(ie));
+		if (cmp < 0)
+			ie = RB_LEFT(ie, entry);
+		else if (cmp > 0)
+			ie = RB_RIGHT(ie, entry);
+		else
+			break;
+	}
+
+	return 0;
+}
+
 static const struct got_error *
 walk_dir(struct got_pathlist_entry **next, struct got_fileindex *fileindex,
     struct got_fileindex_entry **ie, struct got_pathlist_entry *dle, int fd,
@@ -1013,6 +1037,11 @@ walk_dir(struct got_pathlist_entry **next, struct got_
 	} else
 		type = de->d_type;
 
+	/* Must traverse ignored directories if they contain tracked files. */
+	if (type == DT_DIR && ignore &&
+	    have_tracked_file_in_dir(fileindex, path))
+		ignore = 0;
+
 	if (type == DT_DIR && !ignore) {
 		char *subpath;
 		char *subdirpath;
blob - 8b67476fd9377314c10033f7fe555651af4cda1a
blob + 9e581724fe4e03c1b4d098200691d364a658da87
--- regress/cmdline/status.sh
+++ regress/cmdline/status.sh
@@ -531,6 +531,7 @@ test_status_cvsignore() {
 	mkdir -p $testroot/wt/epsilon/new/
 	echo "unversioned file" > $testroot/wt/epsilon/new/foo
 	echo "**/foo" > $testroot/wt/.cvsignore
+	echo "**/gamma" >> $testroot/wt/.cvsignore
 	echo "bar" > $testroot/wt/epsilon/.cvsignore
 	echo "moo" >> $testroot/wt/epsilon/.cvsignore