Author SHA1 Message Date
sneak 261b13765a Rewrite TODO.md sentence by sentence (closes #135)
check / check (push) Canceled after 0s
TODO.md is the project's own task list, judged by the same rules as
README.md: short sentences, lists as bullets, nothing a newcomer reads
twice. Every completed step is kept with its date and its issue or
branch, and every fact the old entries recorded is kept too, in short
sentences. The 2026-07-22 policy-compliance checklist is folded into
the step that did the work, and the accepted divergence from the
layout policy gets a section of its own. Workflow, Status and Next
Step keep their rules unchanged.

Model: fable-5-1
2026-10-26 11:39:35 +00:00
4 changed files with 588 additions and 544 deletions
+5 -11
View File
@@ -455,17 +455,11 @@ scan and are enumerated concurrently: every operand seeds the shared walk worker
pool. Overlapping operands are harmless — an operand that duplicates another or
lies under another is dropped before walking, so every file is reached exactly
once and produces one database record. An operand under another one is kept,
though, when the walk of the outer operand does not reach it. It is then walked
on its own. The walk of the outer operand does not reach the inner one when it,
or any directory between the two, is:
- named `.zfs`;
- a symlink;
- a default exclude;
- not on a persistent filesystem (see "Rules for the walk");
- with `-x`, on a different filesystem than the outer operand.
For a regular-file operand, only the directories between the two count.
though, and walked on its own when any directory from it (from its directory,
for a regular file) up to but not including the operand covering it is a default
exclude, is not on a persistent filesystem (see "Rules for the walk"), or, with
`-x`, is on a different filesystem than that operand, because that operand's
walk does not enter such a directory and so does not reach it.
An operand that is a symlink (never followed, not even as an operand), socket,
FIFO, or device node, or a directory named `.zfs`, is not scanned. `scan` prints
+578 -428
View File
File diff suppressed because it is too large Load Diff
+5 -20
View File
@@ -48,11 +48,6 @@ const sampleWindow = 1024 * 1024
// and hash worker pools.
const workQueueDepth = 1024
// zfsDirName is the name of the directory in which ZFS shows a
// filesystem's snapshots. The walk never enters one, since it would
// list every file once per snapshot.
const zfsDirName = ".zfs"
// errInterrupted reports a scan stopped by SIGINT or SIGTERM. runScan
// has already printed its line, so run prints nothing more.
var errInterrupted = errors.New("scan interrupted")
@@ -277,10 +272,9 @@ func pruneRoots(roots []string, oneFS bool, rules walkRules,
}
// walkReaches reports whether the walk of operand above reaches r, an
// operand under it. That walk never follows a symlink. It does not
// enter a directory named .zfs, nor a default exclude in rules, nor a
// directory that device puts on a filesystem in rules that is not
// persistent, nor, with -x, one that device puts on a different
// operand under it. That walk does not enter a default exclude in
// rules, nor a directory that device puts on a filesystem in rules that
// is not persistent, nor, with -x, one that device puts on a different
// filesystem than above, when device knows above's. It reaches every
// regular file in a directory it enters, so for a regular-file operand
// the directories checked start at its directory; they end below above.
@@ -301,15 +295,6 @@ func walkReaches(above, r string, oneFS bool, rules walkRules,
return false
}
if filepath.Base(dir) == zfsDirName {
return false
}
fi, err = os.Lstat(dir)
if err == nil && fi.Mode()&fs.ModeSymlink != 0 {
return false
}
dev, ok := device(dir)
if !ok {
continue
@@ -898,7 +883,7 @@ func operandWarning(root string, fi fs.FileInfo) string {
case mode.IsRegular():
return ""
case mode.IsDir():
if filepath.Base(root) != zfsDirName {
if filepath.Base(root) != ".zfs" {
return ""
}
@@ -1168,7 +1153,7 @@ func subdirJob(ctx context.Context, p string, e fs.DirEntry,
parent dirJob, oneFS bool, rules walkRules,
events chan<- walkEvent,
) (dirJob, bool) {
if e.Name() == zfsDirName {
if e.Name() == ".zfs" {
return dirJob{}, false
}
-85
View File
@@ -1672,81 +1672,6 @@ func TestSyncScanOverlappingRoots(t *testing.T) {
}
}
// TestScanWalksOperandInZFSDirectory checks that an operand inside a
// directory named .zfs below another operand is walked on its own,
// since the walk of the other operand does not enter .zfs. The file
// under it is recorded, and a second scan keeps the record.
func TestScanWalksOperandInZFSDirectory(t *testing.T) {
t.Parallel()
dir := t.TempDir()
db := openTestDB(t)
f := writeFile(t, dir, "pool/.zfs/snapshot/daily/f", pattern(1, 10))
daily := filepath.Dir(f)
syncTree(t, db, dir, daily)
recordByPath(t, dbRecords(t, db), f)
syncTree(t, db, dir, daily)
recordByPath(t, dbRecords(t, db), f)
}
// TestScanWalksOperandBehindSymlink checks that an operand reached
// through a symlinked directory below another operand is walked on its
// own, since the walk of the other operand does not follow the symlink.
// The file under it is recorded, and a second scan keeps the record.
func TestScanWalksOperandBehindSymlink(t *testing.T) {
t.Parallel()
dir := t.TempDir()
target := t.TempDir()
db := openTestDB(t)
writeFile(t, target, "sub/f", pattern(1, 10))
link := filepath.Join(dir, "link")
err := os.Symlink(target, link)
if err != nil {
t.Fatal(err)
}
sub := filepath.Join(link, "sub")
f := filepath.Join(sub, "f")
syncTree(t, db, dir, sub)
recordByPath(t, dbRecords(t, db), f)
syncTree(t, db, dir, sub)
recordByPath(t, dbRecords(t, db), f)
}
// TestScanDropsOperandReachedBehindSymlink checks that an operand under
// another one is still dropped when both lie behind the same symlinked
// directory: the walk of the other operand starts past the symlink and
// reaches it, so the file under it is walked once.
func TestScanDropsOperandReachedBehindSymlink(t *testing.T) {
t.Parallel()
dir := t.TempDir()
target := t.TempDir()
db := openTestDB(t)
writeFile(t, target, "sub/deeper/f", pattern(1, 10))
link := filepath.Join(dir, "link")
err := os.Symlink(target, link)
if err != nil {
t.Fatal(err)
}
sub := filepath.Join(link, "sub")
st := syncTree(t, db, sub, filepath.Join(sub, "deeper"))
if st != (scanStats{walked: 1, added: 1}) {
t.Fatalf("stats = %+v, want 1 walked and added", st)
}
}
// TestScanHashesUniqueSize checks that a file whose size no other file
// shares is hashed like every other file.
func TestScanHashesUniqueSize(t *testing.T) {
@@ -2160,16 +2085,6 @@ func TestPruneRoots(t *testing.T) {
t.Fatalf("pruneRoots with %s not persistent = %q, want %q",
pqRoot, got, want)
}
// Nor does it enter a directory named .zfs, so /p/.zfs/s is kept. The
// walk of /p/.zfs/s reaches /p/.zfs/s/t, which is dropped.
got = pruneRoots([]string{"/p", "/p/.zfs/s", "/p/.zfs/s/t"}, false,
walkRules{}, device)
want = []string{"/p", "/p/.zfs/s"}
if !slices.Equal(got, want) {
t.Fatalf("pruneRoots with .zfs = %q, want %q", got, want)
}
}
func TestReportsNeverTouchFilesystem(t *testing.T) {