use std::fs::File;
use std::io;
use std::path::{Path, PathBuf};
use std::sync::atomic::{AtomicU64, Ordering};
#[derive(Debug)]
pub struct FileLock {
_file: File,
}
fn sidecar(path: &Path) -> PathBuf {
let mut name = path.file_name().unwrap_or_default().to_os_string();
name.push(".lock");
path.with_file_name(name)
}
pub fn lock(path: &Path) -> io::Result<FileLock> {
if let Some(dir) = path.parent() {
std::fs::create_dir_all(dir)?;
}
let file = std::fs::OpenOptions::new()
.read(true)
.write(true)
.create(true)
.truncate(false)
.open(sidecar(path))?;
file.lock()?;
Ok(FileLock { _file: file })
}
pub fn unique_tmp(path: &Path) -> PathBuf {
static N: AtomicU64 = AtomicU64::new(0);
let mut name = path.file_name().unwrap_or_default().to_os_string();
name.push(format!(
".{}.{}.tmp",
std::process::id(),
N.fetch_add(1, Ordering::Relaxed)
));
path.with_file_name(name)
}
pub struct TmpGuard(Option<PathBuf>);
impl TmpGuard {
pub fn new(p: PathBuf) -> Self {
Self(Some(p))
}
pub fn path(&self) -> &Path {
self.0.as_deref().expect("armed")
}
pub fn disarm(mut self) {
self.0 = None;
}
}
impl Drop for TmpGuard {
fn drop(&mut self) {
if let Some(p) = self.0.take() {
let _ = std::fs::remove_file(p);
}
}
}