Skip to content

Commit

Permalink
Return correct Error for try_* functions on Windows (#38)
Browse files Browse the repository at this point in the history
* Avoid unconditonally returning WouldBlock for try_* functions on Windows

* Add test for reporting correct error on Windows for try_* fns
  • Loading branch information
nathaniel-daniel committed Jan 23, 2023
1 parent 8ad7940 commit 3213736
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 4 deletions.
17 changes: 13 additions & 4 deletions src/sys/windows/rw_lock.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use std::io::{self, Error, ErrorKind};
use std::os::windows::io::AsRawHandle;

use windows_sys::Win32::Foundation::ERROR_LOCK_VIOLATION;
use windows_sys::Win32::Foundation::HANDLE;
use windows_sys::Win32::Storage::FileSystem::{
LockFileEx, LOCKFILE_EXCLUSIVE_LOCK, LOCKFILE_FAIL_IMMEDIATELY,
Expand Down Expand Up @@ -36,8 +37,12 @@ impl<T: AsRawHandle> RwLock<T> {
let overlapped = Overlapped::zero();
let flags = LOCKFILE_FAIL_IMMEDIATELY;

syscall(unsafe { LockFileEx(handle, flags, 0, 1, 0, overlapped.raw()) })
.map_err(|_| Error::from(ErrorKind::WouldBlock))?;
syscall(unsafe { LockFileEx(handle, flags, 0, 1, 0, overlapped.raw()) }).map_err(
|error| match error.raw_os_error().map(|error_code| error_code as u32) {
Some(ERROR_LOCK_VIOLATION) => Error::from(ErrorKind::WouldBlock),
_ => error,
},
)?;
Ok(RwLockReadGuard { lock: self })
}

Expand All @@ -57,8 +62,12 @@ impl<T: AsRawHandle> RwLock<T> {
let overlapped = Overlapped::zero();
let flags = LOCKFILE_FAIL_IMMEDIATELY | LOCKFILE_EXCLUSIVE_LOCK;

syscall(unsafe { LockFileEx(handle, flags, 0, 1, 0, overlapped.raw()) })
.map_err(|_| Error::from(ErrorKind::WouldBlock))?;
syscall(unsafe { LockFileEx(handle, flags, 0, 1, 0, overlapped.raw()) }).map_err(
|error| match error.raw_os_error().map(|error_code| error_code as u32) {
Some(ERROR_LOCK_VIOLATION) => Error::from(ErrorKind::WouldBlock),
_ => error,
},
)?;
Ok(RwLockWriteGuard { lock: self })
}

Expand Down
29 changes: 29 additions & 0 deletions tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,32 @@ fn write_and_read_lock() {

drop(g0);
}

#[cfg(windows)]
mod windows {
use super::*;
use std::os::windows::fs::OpenOptionsExt;

#[test]
fn try_lock_error() {
let dir = tempdir().unwrap();
let path = dir.path().join("lockfile");

// On Windows, opening with an access_mode as 0 will prevent all locking operations from succeeding, simulating an I/O error.
let mut l0 = RwLock::new(
File::options()
.create(true)
.read(true)
.write(true)
.access_mode(0)
.open(path)
.unwrap(),
);

let err1 = l0.try_read().unwrap_err();
assert!(matches!(err1.kind(), ErrorKind::PermissionDenied));

let err2 = l0.try_write().unwrap_err();
assert!(matches!(err2.kind(), ErrorKind::PermissionDenied));
}
}

0 comments on commit 3213736

Please sign in to comment.