Non-regular and .zfs operands are silently ignored, and their records are deleted #9

Open
opened 2026-08-09 03:44:16 +02:00 by clawbot · 0 comments
Collaborator

seedRoot's default: branch (scan.go:581-583) returns nil for an operand that is a symlink, socket, FIFO or device node — no warning, no skip counter. scan.go:562-564 does the same for a directory operand literally named .zfs.

Two problems follow.

First, silence. sfdupes scan /srv/data where /srv/data is a symlink to the real tree prints scan: 0 files seen (0 added, 0 updated, 0 removed, 0 unchanged), 0 skipped and exits 0. README §Rules for the walk requires that any skipped path "print a one-line warning to stderr, skip the path, and continue" — the skip is correct, the silence is not. Symlinked operands are an ordinary mistake to make.

Second, and worse: the operand stays in roots, so loadIndex (scan.go:193-215) treats every existing database record beneath that path as in-scope, and updatePhase deletes all of them because nothing verified them this run. A single mistyped symlink operand therefore wipes the records for that whole subtree.

Definition of done

  1. A non-regular, non-directory operand emits a one-line stderr warning naming the path and its type, and counts as skipped in the summary.
  2. An operand that is itself named .zfs does the same.
  3. An operand that produced no walkable root is removed from the in-scope set, so records beneath it are left untouched rather than deleted.
  4. Exit status stays 0 — this is a per-path skip, not a fatal error. A nonexistent operand remains fatal (exit 1) as README §scan mode specifies.
  5. Tests: a symlink operand asserts the warning text, the 1 skipped summary, exit 0, and that pre-existing records beneath the symlink target survive; a .zfs operand asserts the same.
  6. make check green.
`seedRoot`'s `default:` branch (`scan.go:581-583`) returns `nil` for an operand that is a symlink, socket, FIFO or device node — no warning, no skip counter. `scan.go:562-564` does the same for a directory operand literally named `.zfs`. Two problems follow. First, silence. `sfdupes scan /srv/data` where `/srv/data` is a symlink to the real tree prints `scan: 0 files seen (0 added, 0 updated, 0 removed, 0 unchanged), 0 skipped` and exits 0. README §Rules for the walk requires that any skipped path "print a one-line warning to stderr, skip the path, and continue" — the skip is correct, the silence is not. Symlinked operands are an ordinary mistake to make. Second, and worse: the operand stays in `roots`, so `loadIndex` (`scan.go:193-215`) treats every existing database record beneath that path as in-scope, and `updatePhase` deletes all of them because nothing verified them this run. A single mistyped symlink operand therefore wipes the records for that whole subtree. ## Definition of done 1. A non-regular, non-directory operand emits a one-line stderr warning naming the path and its type, and counts as skipped in the summary. 2. An operand that is itself named `.zfs` does the same. 3. An operand that produced no walkable root is removed from the in-scope set, so records beneath it are left untouched rather than deleted. 4. Exit status stays 0 — this is a per-path skip, not a fatal error. A nonexistent operand remains fatal (exit 1) as README §scan mode specifies. 5. Tests: a symlink operand asserts the warning text, the `1 skipped` summary, exit 0, and that pre-existing records beneath the symlink target survive; a `.zfs` operand asserts the same. 6. `make check` green.
clawbot added this to the 1.0.0 milestone 2026-08-09 03:44:16 +02:00
Sign in to join this conversation.