fix(qbzd): gate the instance lock per OS

lock.rs imported std::os::unix and called libc::flock unconditionally, so
a workspace test run could not compile on Windows.

The Windows arm locks ONE byte at offset 1 GiB rather than the whole file.
Byte-range locks are mandatory there, not advisory like flock: measured on
this box, a whole-file lock from offset 0 makes the losing instance's
read_to_string fail with ERROR_LOCK_VIOLATION, so AlreadyRunning would
always carry None - the pid is the only reason that variant exists. With
the lock byte past any content the pid still reads back, the same handle
conflict is still detected, and the lock still releases when the File
drops. Reserving a region past EOF is what SQLite's Windows VFS does.

Only ERROR_LOCK_VIOLATION means contention; a filesystem that does not
implement byte-range locks answers ERROR_INVALID_FUNCTION and must surface
as Io, not as a daemon that is not running. The unix arm keeps its
existing any-failure-means-busy behaviour unchanged.

cc
This commit is contained in:
vicrodh committed 2026-08-26 23:07:02 -06:00
1 parent 57f900bec4
commit f06ffc7141
3 files changed
+81 -7

No files matched your search

+11 -1
View File
@@ -42,7 +42,6 @@ futures-util = { workspace = true } # remote_stream.r
# new direct deps (versions already in lock where noted)
tiny_http = "0.12" # in lock via qbz-cast
toml = "0.9" # in lock transitively
libc = "0.2" # flock
urlencoding = "2" # OAuth redirect_url encode + callback decode (in lock via qbz)
open = "5" # system-browser launch for `qbzd login` (in lock via qbz)
clap = { version = "4", features = ["derive"] }
@@ -52,5 +51,16 @@ clap_complete = "4"
# The `crossterm` backend is a DEFAULT feature; re-exported as ratatui::crossterm.
ratatui = "0.30"
[target.'cfg(unix)'.dependencies]
libc = "0.2" # flock in src/lock.rs
[target.'cfg(windows)'.dependencies]
# LockFileEx (+ OVERLAPPED, hence Win32_System_IO) for the instance lock.
windows-sys = { version = "0.61", features = [
"Win32_Foundation",
"Win32_Storage_FileSystem",
"Win32_System_IO",
] }
[dev-dependencies]
tempfile = "3"