chj_unix_util/
file_lock.rs1use std::{fs::File, os::unix::fs::OpenOptionsExt, path::Path};
2
3use nix::errno::Errno;
4use ouroboros::self_referencing;
5
6use crate::unix::{easy_flock_nonblocking, FlockGuard};
7
8#[self_referencing]
9pub struct FileLock {
10 file: File,
11
12 #[borrows(mut file)]
13 #[covariant]
14 flock_guard: FlockGuard<'this>,
15}
16
17#[derive(thiserror::Error, Debug)]
18pub enum FileLockError {
19 #[error("opening file path")]
20 OpenError(#[from] std::io::Error),
21 #[error("calling flock")]
22 FlockError(#[from] Errno),
23 #[error("lock already taken")]
24 AlreadyLocked,
25}
26
27impl FileLock {
28 pub fn leak(&mut self) {
29 self.with_flock_guard_mut(|g| g.leak());
30 }
31}
32
33pub fn file_lock_nonblocking<P: AsRef<Path>>(
37 path: P,
38 exclusive: bool,
39) -> Result<FileLock, FileLockError> {
40 let mut opts = File::options();
41 opts.read(true);
42 opts.write(true);
43 opts.truncate(false);
44 opts.create(true);
45 opts.mode(0o600); let file = opts.open(path.as_ref())?;
47 FileLock::try_new(file, |file| {
48 if let Some(flock_guard) = easy_flock_nonblocking(file, exclusive)? {
49 Ok(flock_guard)
50 } else {
51 Err(FileLockError::AlreadyLocked)
52 }
53 })
54}