use std::fs::File;
use std::os::windows::io::AsRawHandle;
use windows_sys::Win32::Foundation::{FALSE, HANDLE};
use windows_sys::Win32::Storage::FileSystem::{
LockFileEx, UnlockFileEx, LOCKFILE_EXCLUSIVE_LOCK, LOCKFILE_FAIL_IMMEDIATELY,
};
use windows_sys::Win32::System::IO::OVERLAPPED;
use crate::backend::LockBackend;
use crate::error::Result;
use crate::lock::{LockKind, LockMode};
#[inline]
fn flags(kind: LockKind, mode: LockMode) -> u32 {
let mut f: u32 = 0;
if kind == LockKind::Exclusive {
f |= LOCKFILE_EXCLUSIVE_LOCK;
}
if mode == LockMode::NonBlocking {
f |= LOCKFILE_FAIL_IMMEDIATELY;
}
f
}
#[inline]
fn overlapped() -> OVERLAPPED {
unsafe { std::mem::zeroed() }
}
pub(crate) fn lock(
file: &File,
kind: LockKind,
mode: LockMode,
_backend: LockBackend,
) -> Result<()> {
let handle = file.as_raw_handle() as HANDLE;
let flags = flags(kind, mode);
let mut ol = overlapped();
let ok = unsafe { LockFileEx(handle, flags, 0, u32::MAX, u32::MAX, &mut ol) };
if ok != FALSE {
Ok(())
} else {
Err(std::io::Error::last_os_error().into())
}
}
pub(crate) fn unlock(file: &File, _backend: LockBackend) -> Result<()> {
let handle = file.as_raw_handle() as HANDLE;
let mut ol = overlapped();
let ok = unsafe { UnlockFileEx(handle, 0, u32::MAX, u32::MAX, &mut ol) };
if ok != FALSE {
Ok(())
} else {
Err(std::io::Error::last_os_error().into())
}
}
pub(crate) fn upgrade(file: &File, mode: LockMode, backend: LockBackend) -> Result<()> {
unlock(file, backend)?;
lock(file, LockKind::Exclusive, mode, backend)
}
pub(crate) fn downgrade(file: &File, backend: LockBackend) -> Result<()> {
lock(file, LockKind::Shared, LockMode::Blocking, backend)?;
unlock(file, backend)
}