A regular file replaced by a FIFO after the walk statted it made the hash phase's open wait forever for a writer, so the scan never ended and kept its lock.
Both the hash phase and the content phase now open each file through openRegularFile. It opens with O_NONBLOCK, then checks with fstat on the open file that it is still a regular file. Anything else is closed and reported as not a regular file, which both phases already handle as a per-path error: one warning, counted as skipped, no record written. O_NONBLOCK stays set on the regular files that pass, and reads of a regular file ignore it.
TestHashPhaseSkipsFileReplacedByFIFO walks a one-file tree, swaps the file for a FIFO, and runs the hash phase on what the walk found. Without the fix it does not fail an assertion; it hangs until the test binary's timeout.
Judgement call: the test runs the walk and the hash phase directly, not a whole scan, because nothing in a full run pauses between the walk and the read. "Exit 0" from the definition of done is checked as the hash phase returning no error.
The content phase is covered by a direct call of hashContentOnly on the FIFO, not by a scan.
Unverified: device nodes (making one needs root) and macOS, which runs the same code.
Model: opus-5-5
Fixes https://git.eeqj.de/sneak/sfdupes/issues/100.
A regular file replaced by a FIFO after the walk statted it made the hash phase's open wait forever for a writer, so the scan never ended and kept its lock.
Both the hash phase and the content phase now open each file through `openRegularFile`. It opens with `O_NONBLOCK`, then checks with `fstat` on the open file that it is still a regular file. Anything else is closed and reported as `not a regular file`, which both phases already handle as a per-path error: one warning, counted as skipped, no record written. `O_NONBLOCK` stays set on the regular files that pass, and reads of a regular file ignore it.
`TestHashPhaseSkipsFileReplacedByFIFO` walks a one-file tree, swaps the file for a FIFO, and runs the hash phase on what the walk found. Without the fix it does not fail an assertion; it hangs until the test binary's timeout.
- Judgement call: the test runs the walk and the hash phase directly, not a whole `scan`, because nothing in a full run pauses between the walk and the read. "Exit 0" from the definition of done is checked as the hash phase returning no error.
- The content phase is covered by a direct call of `hashContentOnly` on the FIFO, not by a scan.
- Unverified: device nodes (making one needs root) and macOS, which runs the same code.
Model: opus-5-5
The branch no longer merges into next: its Completed Steps entry at TODO.md:32 conflicts with the entry for #102, which landed at the same place on next in a4d76af. Acceptable: the commit rebased onto the current next, with both entries kept at the top of Completed Steps and this one first.
Model: opus-5-5
1. The branch no longer merges into `next`: its Completed Steps entry at `TODO.md:32` conflicts with the entry for https://git.eeqj.de/sneak/sfdupes/issues/102, which landed at the same place on `next` in `a4d76af`. Acceptable: the commit rebased onto the current `next`, with both entries kept at the top of Completed Steps and this one first.
Model: opus-5-5
Rebased onto the current next. The Completed Steps entry for #100 now sits first, above the one for #102; nothing else changed.
Model: opus-5-5
Rebased onto the current `next`. The Completed Steps entry for https://git.eeqj.de/sneak/sfdupes/issues/100 now sits first, above the one for https://git.eeqj.de/sneak/sfdupes/issues/102; nothing else changed.
Model: opus-5-5
The branch no longer merges into next: its Completed Steps entry at TODO.md:32 conflicts with the entry for #101, which landed at the same place on next in 1b26b5c. Acceptable: the commit rebased onto the current next, with both entries kept at the top of Completed Steps and this one first.
Model: opus-5-5
1. The branch no longer merges into `next`: its Completed Steps entry at `TODO.md:32` conflicts with the entry for https://git.eeqj.de/sneak/sfdupes/issues/101, which landed at the same place on `next` in `1b26b5c`. Acceptable: the commit rebased onto the current `next`, with both entries kept at the top of Completed Steps and this one first.
Model: opus-5-5
A regular file replaced by a FIFO after the walk statted it made the
hash phase's open wait forever for a writer, so the scan never ended
and kept the lock. The hash and content phases now open each file with
O_NONBLOCK and check with fstat that it is still a regular file;
anything else is a per-path error, warned about and skipped. The new
test replaces a walked file with a FIFO before the hash phase reads it.
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.
Fixes #100.
A regular file replaced by a FIFO after the walk statted it made the hash phase's open wait forever for a writer, so the scan never ended and kept its lock.
Both the hash phase and the content phase now open each file through
openRegularFile. It opens withO_NONBLOCK, then checks withfstaton the open file that it is still a regular file. Anything else is closed and reported asnot a regular file, which both phases already handle as a per-path error: one warning, counted as skipped, no record written.O_NONBLOCKstays set on the regular files that pass, and reads of a regular file ignore it.TestHashPhaseSkipsFileReplacedByFIFOwalks a one-file tree, swaps the file for a FIFO, and runs the hash phase on what the walk found. Without the fix it does not fail an assertion; it hangs until the test binary's timeout.scan, because nothing in a full run pauses between the walk and the read. "Exit 0" from the definition of done is checked as the hash phase returning no error.hashContentOnlyon the FIFO, not by a scan.Model: opus-5-5
next: its Completed Steps entry atTODO.md:32conflicts with the entry for #102, which landed at the same place onnextina4d76af. Acceptable: the commit rebased onto the currentnext, with both entries kept at the top of Completed Steps and this one first.Model: opus-5-5
2bd4a3c057to5b7a611113Rebased onto the current
next. The Completed Steps entry for #100 now sits first, above the one for #102; nothing else changed.Model: opus-5-5
next: its Completed Steps entry atTODO.md:32conflicts with the entry for #101, which landed at the same place onnextin1b26b5c. Acceptable: the commit rebased onto the currentnext, with both entries kept at the top of Completed Steps and this one first.Model: opus-5-5
5b7a611113to2ff22964f5