Compare commits

1 Commits
Author SHA1 Message Date
sneak cf34b59632 Warn about and skip non-regular and .zfs operands, keeping their records (closes #9)
check / check (push) Successful in 1m11s
A symlink, socket, FIFO or device-node operand, or a directory operand
named .zfs, was ignored without a word and stayed in the scanned
operands, so the update phase deleted every record stored beneath it.
Such an operand now gets a one-line warning naming the path and what it
is, counts as skipped in the summary, and is dropped before the
database index is loaded, so the records beneath it count as outside
the scanned operands and are not deleted, unless it lies under another
operand. The exit status stays 0. An operand that turns into one of
these between that check and the walk is warned about and skipped by
the walk instead. README "scan mode" and "Rules for the walk" say so.

Model: opus-5-5
2026-10-03 15:02:56 +00:00
3 changed files with 7 additions and 37 deletions
+7 -7
View File
@@ -267,13 +267,13 @@ 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 a one-line warning naming the path and what it
is, counts it as skipped, and drops it from the scanned operands before
reading the database. Another operand beneath it is still scanned. The
records stored beneath it are not deleted: they are treated like any
other record outside the scanned operands, including the content-phase
exception below. If it lies under another operand, they are under that
operand instead, and are deleted like any other record there that this
scan did not verify. This is not an error: a scan whose every operand
is dropped walks nothing and exits 0.
reading the database. The records stored beneath it are not deleted:
they are treated like any other record outside the scanned operands,
including the content-phase exception below. If it lies under another
operand, they are under that operand instead, and are deleted like any
other record there that this scan did not verify. This is not an
error: a scan whose every operand is dropped walks nothing and
exits 0.
`scan` synchronizes the database with the filesystem state under the
scanned operands:
-28
View File
@@ -423,34 +423,6 @@ func TestRunScanSkipsSymlinkOperand(t *testing.T) {
filepath.Join(link, "sub", "f"))
}
func TestRunScanWalksOperandUnderSymlinkOperand(t *testing.T) {
path := testDBPath(t)
t.Setenv(databaseEnv, path)
dir := t.TempDir()
writeFile(t, dir, "target/sub/f", pattern(1, 10))
link := filepath.Join(dir, "link")
err := os.Symlink(filepath.Join(dir, "target"), link)
if err != nil {
t.Fatal(err)
}
// link is dropped as a symlink, but link/sub must still be scanned,
// not dropped as lying under link.
scanOK(t, link, filepath.Join(link, "sub"))
db, err := openDB(path, reportParams)
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { _ = db.Close() })
recordByPath(t, dbRecords(t, db), filepath.Join(link, "sub", "f"))
}
func TestRunScanSkipsZFSOperand(t *testing.T) {
path := testDBPath(t)
t.Setenv(databaseEnv, path)
-2
View File
@@ -219,8 +219,6 @@ func syncScan(ctx context.Context, db *sql.DB, roots []string,
) (scanStats, error) {
s := &scanState{db: db}
// Types are checked before pruning so that an operand under a
// dropped one is still scanned, not dropped as lying under it.
roots = pruneRoots(s.walkableRoots(roots))
err := s.loadIndex(ctx, roots)