Skip to main content

interlink/
state.rs

1//! Atomic local state replacement shared by session queues and peer settings.
2
3use std::fs::{File, OpenOptions};
4use std::io::Write;
5use std::path::Path;
6
7use anyhow::{Context, Result};
8use fs2::FileExt;
9use tempfile::NamedTempFile;
10
11pub fn atomic_write(path: &Path, bytes: &[u8]) -> Result<()> {
12    let parent = path
13        .parent()
14        .filter(|p| !p.as_os_str().is_empty())
15        .unwrap_or_else(|| Path::new("."));
16    std::fs::create_dir_all(parent)?;
17    let mut temp = NamedTempFile::new_in(parent)?;
18    if let Ok(metadata) = std::fs::metadata(path) {
19        temp.as_file().set_permissions(metadata.permissions())?;
20    }
21    temp.write_all(bytes)?;
22    temp.as_file().sync_all()?;
23    temp.persist(path)
24        .with_context(|| format!("replacing {}", path.display()))?;
25    #[cfg(unix)]
26    File::open(parent)?.sync_all()?;
27    Ok(())
28}
29
30pub fn lock(path: &Path) -> Result<File> {
31    if let Some(parent) = path.parent() {
32        std::fs::create_dir_all(parent)?;
33    }
34    let file = OpenOptions::new()
35        .create(true)
36        .truncate(false)
37        .write(true)
38        .open(path)?;
39    file.lock_exclusive()?;
40    Ok(file)
41}