scan now takes an exclusive flock(2) on a lock file beside the database (its path with .lock appended) after checking its operands, before walking anything or opening the database, and holds it until it returns. A second scan against the same database exits 1 with sfdupes: another scan is running (lock held on /var/lib/sfdupes/db.sqlite.lock). report and trees never touch the lock. golang.org/x/sys becomes a direct dependency; README.md §Constraints, §Database and §Error handling are updated.
Not obvious from the diff:
The lock file is never deleted, on purpose: deleting it would let a third scan lock a new file while the second still holds the old one.
The lock is released after the database is closed, so the switch out of WAL mode happens while it is still held.
lockScanDatabase creates the database directory because it runs before openScanDatabase, which still creates it for its other callers.
Disclosures:
Deviation: the README.md smoke test keeps the database in its own temp directory; inside the scanned tree its empty lock file would join the empty1/empty2 group.
Rule suppressed: gosec G304 on opening the lock file, whose path the operator sets.
Judgement call: lock file mode 0600, since anyone who can open it can block every scan.
Partially verified: with no signal handling, release on an interrupt relies on the operating system closing the file at exit; checked by hand, not by a test.
Model: opus-5-5
`scan` now takes an exclusive `flock(2)` on a lock file beside the database (its path with `.lock` appended) after checking its operands, before walking anything or opening the database, and holds it until it returns. A second `scan` against the same database exits 1 with `sfdupes: another scan is running (lock held on /var/lib/sfdupes/db.sqlite.lock)`. `report` and `trees` never touch the lock. `golang.org/x/sys` becomes a direct dependency; `README.md` §Constraints, §Database and §Error handling are updated.
Not obvious from the diff:
- The lock file is never deleted, on purpose: deleting it would let a third scan lock a new file while the second still holds the old one.
- The lock is released after the database is closed, so the switch out of WAL mode happens while it is still held.
- `lockScanDatabase` creates the database directory because it runs before `openScanDatabase`, which still creates it for its other callers.
Disclosures:
- Deviation: the `README.md` smoke test keeps the database in its own temp directory; inside the scanned tree its empty lock file would join the `empty1`/`empty2` group.
- Rule suppressed: gosec G304 on opening the lock file, whose path the operator sets.
- Judgement call: lock file mode 0600, since anyone who can open it can block every scan.
- Partially verified: with no signal handling, release on an interrupt relies on the operating system closing the file at exit; checked by hand, not by a test.
Model: opus-5-5
scan takes an exclusive flock(2) on a lock file beside the database
(its path with .lock appended) before it walks anything or opens the
database, and holds it until it returns. A second scan against the
same database fails at once with a one-line error naming the lock
file and exits 1. report and trees never take the lock. The lock ends
with the process, so a fatal error or an interrupt releases it; the
file is never deleted. golang.org/x/sys becomes a direct dependency.
The README smoke test now keeps the database outside the scanned
tree, where its empty lock file would have joined the empty-file
group.
Model: opus-5-5
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
scannow takes an exclusiveflock(2)on a lock file beside the database (its path with.lockappended) after checking its operands, before walking anything or opening the database, and holds it until it returns. A secondscanagainst the same database exits 1 withsfdupes: another scan is running (lock held on /var/lib/sfdupes/db.sqlite.lock).reportandtreesnever touch the lock.golang.org/x/sysbecomes a direct dependency;README.md§Constraints, §Database and §Error handling are updated.Not obvious from the diff:
lockScanDatabasecreates the database directory because it runs beforeopenScanDatabase, which still creates it for its other callers.Disclosures:
README.mdsmoke test keeps the database in its own temp directory; inside the scanned tree its empty lock file would join theempty1/empty2group.Model: opus-5-5
Review passed.
Model: opus-5-5