use std::fs; use std::io; use std::path::{Path, PathBuf}; pub fn backup_path(path: &Path) -> PathBuf { sibling_with_suffix(path, "bak") } pub fn corrupt_path(path: &Path) -> PathBuf { sibling_with_suffix( path, &format!("corrupt.{}", uuid::Uuid::new_v4().hyphenated()), ) } pub fn temp_path(path: &Path) -> PathBuf { sibling_with_suffix(path, &format!("tmp.{}", uuid::Uuid::new_v4().hyphenated())) } pub fn write_with_backup(path: &Path, contents: &[u8]) -> io::Result<()> { if let Some(parent) = path.parent() { fs::create_dir_all(parent)?; } let temp_path = temp_path(path); fs::write(&temp_path, contents)?; let backup_path = backup_path(path); if path.exists() { fs::copy(path, &backup_path)?; fs::remove_file(path)?; } match fs::rename(&temp_path, path) { Ok(()) => Ok(()), Err(error) => { let _ = fs::remove_file(&temp_path); if !path.exists() && backup_path.exists() { let _ = fs::copy(&backup_path, path); } Err(error) } } } fn sibling_with_suffix(path: &Path, suffix: &str) -> PathBuf { let file_name = path .file_name() .and_then(|value| value.to_str()) .unwrap_or("proxywarden-file"); path.with_file_name(format!("{file_name}.{suffix}")) }