1use 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
16pub 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
63pub unsafe fn raw_file_downgrade(f: &File, off: usize, len: usize) -> io::Result<()> {
69 raw_file_lock(f, Some(Lock::Shared), off, len, false)?;
71 raw_file_lock(f, None, off, len, false)
73}
74
75pub trait FileGuardExt {}
79
80impl<T> FileGuardExt for FileGuard<T> where T: Deref<Target = File> {}