use std::{ fs::{Permissions, ReadDir}, io::{ErrorKind, Write}, path::Path, }; use anyhow::Context; use crate::proc; pub fn is_dir(p: &Path) -> anyhow::Result { log::trace!("is_dir: {}", p.display()); Ok(match std::fs::metadata(p) { Ok(m) if m.is_dir() => true, Ok(_) => false, Err(e) if e.kind() == ErrorKind::NotFound => false, Err(e) => return Err(e).with_context(|| format!("Could not stat {p:?}")), }) } pub fn is_file(p: &Path) -> anyhow::Result { log::trace!("is_file: {}", p.display()); Ok(match std::fs::metadata(p) { Ok(m) if m.is_file() => true, Ok(_) => false, Err(e) if e.kind() == ErrorKind::NotFound => false, Err(e) => return Err(e).with_context(|| format!("Could not stat {p:?}")), }) } pub fn is_file_with_permissions(p: &Path, permissions: Permissions) -> anyhow::Result { log::trace!("is_file_with_permissions: {}", p.display()); Ok(match std::fs::metadata(p) { Ok(m) if m.is_file() => { log::trace!("Verifying {:?} == {:?}", m.permissions(), permissions); m.permissions() == permissions } Ok(_) => false, Err(e) if e.kind() == ErrorKind::NotFound => false, Err(e) => return Err(e).with_context(|| format!("Could not stat {p:?}")), }) } pub fn create_dir(p: &Path) -> anyhow::Result<()> { log::info!("Creating directory : {}", p.display()); std::fs::create_dir(p).with_context(|| format!("Could not create directory {p:?}")) } pub fn write_file_string(p: &Path, contents: &str, permissions: Permissions) -> anyhow::Result<()> { log::info!("Writing contents to {}", p.display()); let mut file = std::fs::File::create(p).with_context(|| { format!( "Could not create (or open existing) file at {}", p.display() ) })?; file.set_permissions(permissions) .with_context(|| format!("Could not set permissions on file {}", p.display()))?; file.write_all(contents.as_bytes()) .with_context(|| format!("Could not write to file {}", p.display()))?; Ok(()) } pub fn root_create_dir(p: &Path) -> anyhow::Result<()> { let mut cmd = proc::Command::new("mkdir"); cmd.arg(p.display().to_string()); let _ = cmd.sudo().try_spawn_to_string()?; Ok(()) } pub fn remove_file(path: &Path) -> anyhow::Result<()> { log::info!("Deleting file {}", path.display()); std::fs::remove_file(path).with_context(|| format!("Could not delete file {}", path.display())) } pub fn root_create_dir_recursive(p: &Path) -> anyhow::Result<()> { let mut cmd = proc::Command::new("mkdir"); cmd.arg("-p"); cmd.arg(p.display().to_string()); let _ = cmd.sudo().try_spawn_to_string()?; Ok(()) } pub fn create_dir_recursive(p: &Path) -> anyhow::Result<()> { let mut cmd = proc::Command::new("mkdir"); cmd.arg("-p"); cmd.arg(p.display().to_string()); let _ = cmd.try_spawn_to_string()?; Ok(()) } pub fn remove_dir_recursive(p: &Path) -> anyhow::Result<()> { std::fs::remove_dir_all(p) .with_context(|| format!("Could not remove directory {}", p.display())) } pub fn list_dir(p: &Path) -> anyhow::Result { std::fs::read_dir(p).with_context(|| format!("Could not read directory {}", p.display())) } pub fn set_permissions(p: &Path, permissions: Permissions) -> anyhow::Result<()> { log::trace!("set_permissions: {}", p.display()); std::fs::set_permissions(p, permissions.clone()).with_context(|| { format!( "Could not set permissions on {} to {permissions:?}", p.display() ) }) } pub fn metadata(p: &Path) -> anyhow::Result { log::trace!("get_metadata: {}", p.display()); std::fs::metadata(p).with_context(|| format!("Could not get metadata for {}", p.display())) } #[cfg(target_family = "unix")] pub fn user_only_dir_permissions() -> Permissions { use std::os::unix::fs::PermissionsExt; PermissionsExt::from_mode(0o040700) } #[cfg(target_family = "unix")] pub fn user_only_file_permissions() -> Permissions { use std::os::unix::fs::PermissionsExt; PermissionsExt::from_mode(0o100600) } pub fn read_to_string(path: &Path) -> anyhow::Result { log::trace!("read_file: {}", path.display()); std::fs::read_to_string(path) .with_context(|| format!("Could not read file: {}", path.display())) } #[cfg(target_family = "unix")] pub fn create_link(from: &Path, to: &Path) -> anyhow::Result<()> { std::os::unix::fs::symlink(to, from).with_context(|| { format!( "Could not create symbolic link from {from} to {to}", from = from.display(), to = to.display() ) }) } pub fn rename(from: &Path, to: &Path) -> anyhow::Result<()> { std::fs::rename(from, to) .with_context(|| format!("Could not rename {} to {}", from.display(), to.display())) }