fs.rs
1 use anyhow::Result; 2 use std::path::Path; 3 4 /// Write data to a file with restrictive permissions (0o600 on Unix). 5 /// 6 /// Uses atomic temp-file-then-rename to avoid TOCTOU races where the file 7 /// exists with default permissions before being restricted. 8 /// 9 /// Args: 10 /// * `path` - Destination file path. 11 /// * `data` - Bytes to write. 12 pub fn write_sensitive_file(path: &Path, data: impl AsRef<[u8]>) -> Result<()> { 13 #[cfg(unix)] 14 { 15 use std::io::Write; 16 use std::os::unix::fs::PermissionsExt; 17 18 let parent = path 19 .parent() 20 .ok_or_else(|| anyhow::anyhow!("No parent directory for {:?}", path))?; 21 22 let mut tmp = tempfile::NamedTempFile::new_in(parent)?; 23 // NamedTempFile creates with 0o600 by default on most systems, 24 // but we set it explicitly via the persisted file permissions. 25 tmp.write_all(data.as_ref())?; 26 tmp.flush()?; 27 28 let tmp_path = tmp.into_temp_path(); 29 std::fs::set_permissions(&tmp_path, std::fs::Permissions::from_mode(0o600))?; 30 tmp_path.persist(path)?; 31 32 Ok(()) 33 } 34 35 #[cfg(not(unix))] 36 { 37 log::warn!("Restrictive file permissions not enforced on this platform"); 38 std::fs::write(path, data)?; 39 Ok(()) 40 } 41 } 42 43 /// Create a directory with restrictive permissions (0o700 on Unix). 44 /// 45 /// Args: 46 /// * `path` - Directory path to create (including parents). 47 pub fn create_restricted_dir(path: &Path) -> Result<()> { 48 #[cfg(unix)] 49 { 50 use std::os::unix::fs::{DirBuilderExt, PermissionsExt}; 51 // Create parents with default permissions first 52 if let Some(parent) = path.parent() { 53 std::fs::create_dir_all(parent)?; 54 } 55 std::fs::DirBuilder::new() 56 .mode(0o700) 57 .create(path) 58 .or_else(|e| { 59 if e.kind() == std::io::ErrorKind::AlreadyExists { 60 // Tighten permissions on existing directory 61 std::fs::set_permissions(path, std::fs::Permissions::from_mode(0o700))?; 62 Ok(()) 63 } else { 64 Err(e.into()) 65 } 66 }) 67 } 68 69 #[cfg(not(unix))] 70 { 71 log::warn!("Restrictive directory permissions not enforced on this platform"); 72 std::fs::create_dir_all(path)?; 73 Ok(()) 74 } 75 }