Files
IronStorage/crates/storage/src/file_lock.rs
T
hugo 874c8139a4
Dependency security audit / rustsec (push) Failing after 23s
feat(android): implement private Rust storage runtime (#90)
2026-10-08 14:36:05 +02:00

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();
}
}