use std::fs::File;
use std::io::{self, Write};
use std::path::Path;
use std::sync::atomic::{AtomicU64, Ordering};
static COUNTER: AtomicU64 = AtomicU64::new(0);
pub fn write_atomic(path: impl AsRef<Path>, contents: impl AsRef<[u8]>) -> io::Result<()> {
write_bytes(path.as_ref(), contents.as_ref())
}
fn write_bytes(path: &Path, contents: &[u8]) -> io::Result<()> {
let name = path
.file_name()
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "path has no file name"))?;
let mut temp_name = std::ffi::OsString::from(".");
temp_name.push(name);
temp_name.push(format!(
".{}-{}.tmp",
std::process::id(),
COUNTER.fetch_add(1, Ordering::Relaxed)
));
let temp = path.with_file_name(temp_name);
let result = File::create(&temp)
.and_then(|mut file| file.write_all(contents).and_then(|()| file.sync_all()))
.and_then(|()| std::fs::rename(&temp, path));
if result.is_err() {
let _ = std::fs::remove_file(&temp);
}
result
}
#[cfg(test)]
#[path = "write_atomic.test.rs"]
mod tests;