file_guard/os/
windows.rs

1//! Provides low-level support operations for file locking on Windows platforms.
2use std::fs::File;
3use std::io::{self, Error, ErrorKind};
4use std::mem::MaybeUninit;
5use std::ops::Deref;
6use std::os::windows::io::AsRawHandle;
7
8use winapi::shared::minwindef::DWORD;
9use winapi::shared::winerror::ERROR_LOCK_VIOLATION;
10use winapi::um::fileapi::{LockFileEx, UnlockFileEx};
11use winapi::um::minwinbase::{LOCKFILE_EXCLUSIVE_LOCK, LOCKFILE_FAIL_IMMEDIATELY, OVERLAPPED};
12use winapi::um::winnt::HANDLE;
13
14use crate::{FileGuard, Lock};
15
16/// Acquires and releases a file lock.
17///
18/// # Safety
19///
20/// When used to unlock, this does not guarantee that an exclusive lock is
21/// already held.
22pub unsafe fn raw_file_lock(
23    f: &File,
24    lock: Option<Lock>,
25    off: usize,
26    len: usize,
27    wait: bool,
28) -> io::Result<()> {
29    if len == 0 {
30        return Err(ErrorKind::InvalidInput.into());
31    }
32
33    let mut ov: OVERLAPPED = MaybeUninit::zeroed().assume_init();
34    let s = ov.u.s_mut();
35    s.Offset = (off & 0xffffffff) as DWORD;
36    s.OffsetHigh = (off >> 16 >> 16) as DWORD;
37
38    let lenlow = (len & 0xffffffff) as DWORD;
39    let lenhigh = (len >> 16 >> 16) as DWORD;
40
41    let rc = if let Some(lock) = lock {
42        let mut flags = if wait { 0 } else { LOCKFILE_FAIL_IMMEDIATELY };
43        if lock == Lock::Exclusive {
44            flags |= LOCKFILE_EXCLUSIVE_LOCK;
45        }
46        LockFileEx(f.as_raw_handle() as HANDLE, flags, 0, lenlow, lenhigh, &mut ov)
47    } else {
48        UnlockFileEx(f.as_raw_handle() as HANDLE, 0, lenlow, lenhigh, &mut ov)
49    };
50
51    if rc == 0 {
52        let e = Error::last_os_error();
53        if e.raw_os_error() == Some(ERROR_LOCK_VIOLATION as i32) {
54            Err(ErrorKind::WouldBlock.into())
55        } else {
56            Err(e)
57        }
58    } else {
59        Ok(())
60    }
61}
62
63/// Downgrades a file lock from exclusive to shared.
64///
65/// # Safety
66///
67/// This does not guarantee that an exclusive lock is already held.
68pub unsafe fn raw_file_downgrade(f: &File, off: usize, len: usize) -> io::Result<()> {
69    // Add a shared lock.
70    raw_file_lock(f, Some(Lock::Shared), off, len, false)?;
71    // Removed the exclusive lock.
72    raw_file_lock(f, None, off, len, false)
73}
74
75/// Windows-specific extensions to [`FileGuard`].
76///
77/// [`FileGuard`]: ../../struct.FileGuard.html
78pub trait FileGuardExt {}
79
80impl<T> FileGuardExt for FileGuard<T> where T: Deref<Target = File> {}