62 lines
2.0 KiB
Rust
62 lines
2.0 KiB
Rust
//! Android's pinned std lacks file locks; retain identical advisory-lock semantics.
|
|
use std::{fs::File, io};
|
|
|
|
pub(crate) fn lock(file: &File) -> io::Result<()> {
|
|
#[cfg(target_os = "android")]
|
|
return rustix::fs::flock(file, rustix::fs::FlockOperation::LockExclusive).map_err(Into::into);
|
|
#[cfg(not(target_os = "android"))]
|
|
file.lock()
|
|
}
|
|
|
|
pub(crate) fn try_lock(file: &File) -> io::Result<()> {
|
|
#[cfg(target_os = "android")]
|
|
return rustix::fs::flock(file, rustix::fs::FlockOperation::NonBlockingLockExclusive)
|
|
.map_err(Into::into);
|
|
#[cfg(not(target_os = "android"))]
|
|
file.try_lock().map_err(|error| match error {
|
|
std::fs::TryLockError::WouldBlock => io::ErrorKind::WouldBlock.into(),
|
|
std::fs::TryLockError::Error(error) => error,
|
|
})
|
|
}
|
|
|
|
#[cfg(unix)]
|
|
pub(crate) fn directory(directory: &cap_std::fs::Dir) -> io::Result<File> {
|
|
let file = directory.open(".")?.into_std();
|
|
lock(&file)?;
|
|
Ok(file)
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
#[test]
|
|
fn independent_owners_contend_until_the_lock_is_dropped() {
|
|
let temp = tempfile::tempdir().unwrap();
|
|
let path = temp.path().join("owner.lock");
|
|
let first = File::create(&path).unwrap();
|
|
let second = File::open(&path).unwrap();
|
|
lock(&first).unwrap();
|
|
assert_eq!(
|
|
try_lock(&second).unwrap_err().kind(),
|
|
io::ErrorKind::WouldBlock
|
|
);
|
|
drop(first);
|
|
try_lock(&second).unwrap();
|
|
}
|
|
#[cfg(unix)]
|
|
#[test]
|
|
fn directory_gate_covers_file_creation_before_its_owner_lock() {
|
|
let root = tempfile::tempdir().unwrap();
|
|
let dir =
|
|
cap_std::fs::Dir::open_ambient_dir(root.path(), cap_std::ambient_authority()).unwrap();
|
|
let first = directory(&dir).unwrap();
|
|
let second = dir.open(".").unwrap().into_std();
|
|
assert_eq!(
|
|
try_lock(&second).unwrap_err().kind(),
|
|
io::ErrorKind::WouldBlock
|
|
);
|
|
drop(first);
|
|
try_lock(&second).unwrap();
|
|
}
|
|
}
|