filelocks
Platform-native advisory file locking for Rust — blocking and non-blocking, shared and exclusive, with an OFD/LockFileEx backend for network shares.
Features
- Shared (read) locks — multiple holders allowed simultaneously
- Exclusive (write) locks — mutual exclusion among cooperating lock users
- Blocking — park the thread until the lock is free
- Non-blocking — return
Err(Error::WouldBlock)immediately - Two backends —
flockfor local Unix files, OFD/LockFileExfor network shares - Upgrade / downgrade — change lock kind without re-opening the file
- RAII guard — lock released automatically on drop
- Unsafe code confined to the two
sys/back-end modules
Platform / backend matrix
| Backend | Linux / Android | Apple platforms | illumos | Other Unix | Windows |
|---|---|---|---|---|---|
Flock |
flock(2) |
flock(2) |
flock(2) |
flock(2) |
LockFileEx |
Fcntl |
OFD locks F_OFD_SETLK(W) |
OFD locks F_OFD_SETLK(W) |
OFD locks F_OFD_SETLK(W) |
Error::Unsupported |
LockFileEx |
Use Fcntl for files that may reside on NFS or CIFS/SMB mounts. On Unix
targets without open-file-description lock support, this crate returns
Error::Unsupported instead of falling back to POSIX record locks.
⚠ Why no POSIX fallback? POSIX locks are per-process. Closing any file descriptor to the same inode from the same process can release all POSIX locks that process holds on that file. That cannot faithfully model this crate's per-guard RAII semantics.
📌 flock vs fcntl are independent: the Linux kernel tracks them in separate tables. An active
flocklock does not prevent afcntllock from being acquired by a different file description (and vice versa). Never mix the two backends across cooperating processes.
Usage
# Cargo.toml
[]
= "0.1"
Local files (default flock backend)
use OpenOptions;
use ;
let file = new
.read.write.create
.open?;
match lock
Network mounts — NFS / CIFS (fcntl backend)
use OpenOptions;
use ;
let file = new
.read.write.create
.open?;
let guard = new
.backend // OFD locks on supported Unix, LockFileEx on Windows
.lock?;
// guard released on drop
Upgrade / downgrade
let mut guard = new
.backend
.lock?;
// promote to exclusive (non-blocking — may return WouldBlock)
guard.upgrade?;
// demote back to shared
guard.downgrade?;
API overview
// Acquisition
FileLock::lock(file, kind, mode) → Result<FileLock> (Flock backend)
LockOptions::new().backend(b).lock(…) → Result<FileLock> (any backend)
// Inspection
guard.kind() → LockKind
guard.backend() → LockBackend
guard.file() → &File
guard.file_mut() → &mut File
// Lock management
guard.upgrade(mode) → Result<()>
guard.downgrade() → Result<()>
guard.unlock() → Result<File, (File, Error)> (explicit unlock)
guard.into_file() → File (no explicit unlock)
Error handling
use Error;
match result
License
MIT OR Apache-2.0