macro_rules! allocate_size {
($file: ty) => {
pub async fn allocated_size(file: &$file) -> Result<u64> {
unsafe {
let mut info: FILE_STANDARD_INFO = mem::zeroed();
let ret = GetFileInformationByHandleEx(
file.as_raw_handle() as HANDLE,
FileStandardInfo,
&mut info as *mut _ as *mut _,
mem::size_of::<FILE_STANDARD_INFO>() as u32,
);
if ret == 0 {
Err(Error::last_os_error())
} else {
Ok(info.AllocationSize as u64)
}
}
}
};
}
macro_rules! allocate {
($file: ty) => {
pub async fn allocate(file: &$file, len: u64) -> Result<()> {
if allocated_size(file).await? >= len {
return Ok(());
}
unsafe {
let mut info: FILE_ALLOCATION_INFO = mem::zeroed();
info.AllocationSize = len as i64;
let ret = SetFileInformationByHandle(
file.as_raw_handle() as HANDLE,
FileAllocationInfo,
&mut info as *mut _ as *mut _,
mem::size_of::<FILE_ALLOCATION_INFO>() as u32,
);
if ret == 0 {
return Err(Error::last_os_error());
}
}
if file.metadata().await?.len() < len {
file.set_len(len).await
} else {
Ok(())
}
}
};
}
macro_rules! test_mod {
($annotation:meta, $($use_stmt:item)*) => {
#[cfg(test)]
mod test {
extern crate tempfile;
use crate::TryLockError;
$(
$use_stmt
)*
#[$annotation]
async fn lock_non_reentrant() {
let tempdir = tempfile::TempDir::with_prefix("fs4").unwrap();
let path = tempdir.path().join("fs4");
let file = fs::OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(&path)
.await
.unwrap();
file.lock().unwrap();
assert!(matches!(file.try_lock(), Err(TryLockError::WouldBlock)));
file.unlock().unwrap();
file.lock_shared().unwrap();
assert!(matches!(file.try_lock(), Err(TryLockError::WouldBlock)));
}
#[$annotation]
async fn lock_layering() {
let tempdir = tempfile::TempDir::with_prefix("fs4").unwrap();
let path = tempdir.path().join("fs4");
let file = fs::OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(&path)
.await
.unwrap();
file.lock().unwrap();
file.lock_shared().unwrap();
file.lock_shared().unwrap();
assert!(
matches!(file.try_lock(), Err(TryLockError::WouldBlock)),
"the first try lock exclusive",
);
file.unlock().unwrap();
assert!(
matches!(file.try_lock(), Err(TryLockError::WouldBlock)),
"pop the first shared lock",
);
file.unlock().unwrap();
assert!(
matches!(file.try_lock(), Err(TryLockError::WouldBlock)),
"pop the second shared lock",
);
file.unlock().unwrap();
file.lock().unwrap();
}
#[$annotation]
async fn lock_layering_cleanup() {
let tempdir = tempfile::TempDir::with_prefix("fs4").unwrap();
let path = tempdir.path().join("fs4");
let file1 = fs::OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(&path)
.await
.unwrap();
let file2 = fs::OpenOptions::new()
.read(true)
.write(true)
.create(true)
.open(&path)
.await
.unwrap();
file1.lock_shared().unwrap();
assert!(matches!(file2.try_lock(), Err(TryLockError::WouldBlock)));
drop(file1);
file2.lock().unwrap();
}
}
};
}
cfg_async_std! {
pub(crate) mod async_std_impl;
}
cfg_fs_err2_tokio! {
pub(crate) mod fs_err2_tokio_impl;
}
cfg_fs_err3_tokio! {
pub(crate) mod fs_err3_tokio_impl;
}
cfg_smol! {
pub(crate) mod smol_impl;
}
cfg_tokio! {
pub(crate) mod tokio_impl;
}