scan: skip OS default excludes, and record nothing on filesystems that are not persistent (closes #124)
check / check (push) Waiting to run

scan never records or reads anything on a filesystem that is not
persistent (tmpfs, proc, sysfs and the like), however it reaches it; no
flag turns this off. It notes each such filesystem's device ID as it
starts: on Linux from /proc/self/mountinfo, on macOS by lstat of each
listed mount point. Below an operand the walk also skips the default
excludes, a path list per system (Linux, macOS, and Windows, not used
yet); --no-default-excludes turns off only those. A default exclude that
is itself an operand gets no skip line. The tests stop at once, saying
why, when TMPDIR is not on a persistent filesystem.

Judgement call: an unreadable mount list fails the scan, and no flag gets round it.
Judgement call: a file on such a filesystem below an operand gets the same line as a directory.
Judgement call: such an operand that another operand's walk also reaches is named twice.
Unverified: whether macOS's mount list gives the device lstat reports, so macOS keeps lstat, and a hidden mount there can still add another filesystem's device.
Unverified: the macOS code is never built or run here; bind mounts need root to test.

Model: opus-5-5
This commit is contained in:
2026-10-17 01:11:21 +00:00
parent 68f6bde5ee
commit 08323879ec
11 changed files with 1294 additions and 169 deletions
+29 -8
View File
@@ -782,7 +782,8 @@ func collectWalk(t *testing.T, roots []string, oneFS bool,
errs int
)
for ev := range startWalk(t.Context(), roots, oneFS, workers) {
for ev := range startWalk(t.Context(), roots, oneFS, walkRules{},
workers) {
if ev.fail {
errs++
@@ -1004,7 +1005,8 @@ func callSubdirJob(t *testing.T, p string, e fs.DirEntry,
t.Helper()
events := make(chan walkEvent, 1)
job, ok := subdirJob(t.Context(), p, e, parent, oneFS, events)
job, ok := subdirJob(t.Context(), p, e, parent, oneFS, walkRules{},
events)
close(events)
var evs []walkEvent
@@ -1152,7 +1154,7 @@ func syncOneFilesystem(t *testing.T, db *sql.DB, roots []string,
return dev, ok
}
roots = pruneRoots(roots, true, device)
roots = pruneRoots(roots, true, walkRules{}, device)
ctx := t.Context()
s := &scanState{db: db}
@@ -1162,7 +1164,7 @@ func syncOneFilesystem(t *testing.T, db *sql.DB, roots []string,
t.Fatal(err)
}
jobs, subdirs, events := startWalkWorkers(ctx, 2, true)
jobs, subdirs, events := startWalkWorkers(ctx, 2, true, walkRules{})
// seedRoot emits a regular-file operand itself and returns a job
// only for a directory operand.
@@ -1463,7 +1465,7 @@ const smokeTreeFiles = 15
func syncTree(t *testing.T, db *sql.DB, roots ...string) scanStats {
t.Helper()
st, err := syncScan(t.Context(), db, roots, 4, false)
st, err := syncScan(t.Context(), db, roots, 4, false, walkRules{})
if err != nil {
t.Fatalf("syncScan: %v", err)
}
@@ -2412,7 +2414,7 @@ func TestPruneRoots(t *testing.T) {
// Duplicates and operands under other operands are dropped; /cc is
// not under /c (sibling with a shared prefix).
got := pruneRoots([]string{"/a/b", "/a", "/c", "/a", "/a/b/c", "/cc"},
false, device)
false, walkRules{}, device)
want := []string{"/a", "/c", "/cc"}
if !slices.Equal(got, want) {
@@ -2421,7 +2423,7 @@ func TestPruneRoots(t *testing.T) {
nested := []string{"/p/q/r", pqRoot, "/p", "/p", "/p/s", "/p/t"}
got = pruneRoots(nested, false, device)
got = pruneRoots(nested, false, walkRules{}, device)
want = []string{"/p"}
if !slices.Equal(got, want) {
@@ -2429,12 +2431,31 @@ func TestPruneRoots(t *testing.T) {
}
// With -x, /p/q, on another filesystem than /p, is kept as well.
got = pruneRoots(nested, true, device)
got = pruneRoots(nested, true, walkRules{}, device)
want = []string{"/p", pqRoot}
if !slices.Equal(got, want) {
t.Fatalf("pruneRoots with -x = %q, want %q", got, want)
}
// The walk of /p does not enter /p/q when it is a default exclude, so
// /p/q is kept, without -x too; /p/q/r lies under it and is dropped.
got = pruneRoots(nested, false, walkRules{excludes: []string{pqRoot}},
device)
if !slices.Equal(got, want) {
t.Fatalf("pruneRoots excluding %s = %q, want %q", pqRoot, got, want)
}
// Nor does it enter /p/q when the filesystem of /p/q is not
// persistent, so /p/q/r/m, of no known device, is kept.
got = pruneRoots([]string{"/p", "/p/q/r/m"}, false,
walkRules{nonPersistent: map[uint64]string{2: "tmpfs"}}, device)
want = []string{"/p", "/p/q/r/m"}
if !slices.Equal(got, want) {
t.Fatalf("pruneRoots with %s not persistent = %q, want %q",
pqRoot, got, want)
}
}
func TestReportsNeverTouchFilesystem(t *testing.T) {