1use std::fs::{self, File, OpenOptions};
7use std::io::Write;
8use std::path::Path;
9use std::sync::atomic::{AtomicU64, Ordering};
10
11use crate::error::Result;
12
13static TMP_COUNTER: AtomicU64 = AtomicU64::new(0);
17
18pub fn ensure_dir_0700(dir: &Path) -> Result<()> {
20 fs::create_dir_all(dir)?;
21 #[cfg(unix)]
22 {
23 use std::os::unix::fs::PermissionsExt;
24 let _ = fs::set_permissions(dir, fs::Permissions::from_mode(0o700));
25 }
26 Ok(())
27}
28
29pub fn atomic_write_0600(path: &Path, bytes: &[u8]) -> Result<()> {
31 if let Some(parent) = path.parent() {
32 ensure_dir_0700(parent)?;
33 }
34 let counter = TMP_COUNTER.fetch_add(1, Ordering::Relaxed);
38 let tmp = path.with_extension(format!("tmp.write.{}.{}", std::process::id(), counter));
39 {
40 let mut file = open_0600(&tmp)?;
41 file.write_all(bytes)?;
42 file.sync_all()?;
43 }
44 fs::rename(&tmp, path)?;
45 #[cfg(unix)]
46 {
47 use std::os::unix::fs::PermissionsExt;
48 let _ = fs::set_permissions(path, fs::Permissions::from_mode(0o600));
49 }
50 Ok(())
51}
52
53fn open_0600(path: &Path) -> Result<File> {
54 let mut opts = OpenOptions::new();
55 opts.write(true).create(true).truncate(true);
56 #[cfg(unix)]
57 {
58 use std::os::unix::fs::OpenOptionsExt;
59 opts.mode(0o600);
60 }
61 opts.open(path).map_err(Into::into)
62}