fs2-rs
fs2-rs copied to clipboard
Windows corner case: "access denied" when opened in append mode
Consider the following test program:
extern crate fs2;
use fs2::FileExt;
use std::fs;
fn main() {
let f = fs::OpenOptions::new()
.create(true)
.append(true)
.open("myfile.txt").expect("error creating");
f.lock_exclusive().expect("error locking");
}
On Linux, it works fine. On Windows 10, it fails:
Finished dev [unoptimized + debuginfo] target(s) in 0.99s
Running `target\debug\examples\debug.exe`
thread 'main' panicked at 'error locking: Os { code: 5, kind: PermissionDenied, message: "Access is denied." }', libcore
\result.rs:945:5
note: Run with `RUST_BACKTRACE=1` for a backtrace.
error: process didn't exit successfully: `target\debug\examples\debug.exe` (exit code: 101)
If I use .write(true)
instead of .append(true)
, it works fine. If I add .read(true)
, it also work. This seems to be because LockFileEx requires either the GENERIC_READ
or GENERIC_WRITE
permission on the underlying handle, while in std::fs on Windows activating .append(true)
means that the underlying handle doesn't have the full set of GENERIC_WRITE
bits.
This basically seems to be how the Windows API works, so I don't think fs2 can make the surprising behavior go away, but I think it could be helpful to have this described somewhere in the fs2 API docs. I am happy to write the words — do you have any suggestions as to where the best place to put some relevant language would be?
Ref: rust-lang #54118.
Note that Windows has an alternative way of locking files by not passing FILE_SHARE_READ
or FILE_SHARE_WRITE
when opening the file, which is compatible with whatever access flags you pass, and that lock is actually enforced all the time and cannot be bypassed.
Same as @zooba, not working on Windows
@raycoe I'm not sure if fs2 is maintained any more, the last commit was >5 years ago and several important PR's have been left open for nearly as long.
You may consider fs4 as an alternative. It is a fork of fs2 that is now actively maintained and supports async. They also switched out the libc backend to rustix.