use std::fs;
use std::io::Write;
use std::path::Path;
use crate::InstallError;
pub fn read_or_empty(path: &Path) -> Result<String, InstallError> {
match fs::read_to_string(path) {
Ok(s) => Ok(s),
Err(e) if e.kind() == std::io::ErrorKind::NotFound => Ok(String::new()),
Err(e) => Err(InstallError::Io {
path: path.to_path_buf(),
source: e,
}),
}
}
pub fn ensure_parent(path: &Path) -> Result<(), InstallError> {
let Some(parent) = path.parent() else {
return Ok(());
};
if parent.as_os_str().is_empty() {
return Ok(());
}
fs::create_dir_all(parent).map_err(|e| InstallError::Io {
path: parent.to_path_buf(),
source: e,
})
}
pub fn atomic_write(path: &Path, contents: &[u8], mode: u32) -> Result<(), InstallError> {
let dir = path.parent().unwrap_or_else(|| Path::new("."));
let mut tf = tempfile::NamedTempFile::new_in(dir).map_err(|e| InstallError::Io {
path: dir.to_path_buf(),
source: e,
})?;
tf.write_all(contents).map_err(|e| InstallError::Io {
path: tf.path().to_path_buf(),
source: e,
})?;
tf.flush().map_err(|e| InstallError::Io {
path: tf.path().to_path_buf(),
source: e,
})?;
apply_mode(tf.path(), mode)?;
tf.persist(path).map_err(|e| InstallError::Io {
path: path.to_path_buf(),
source: e.error,
})?;
Ok(())
}
#[cfg(unix)]
pub fn current_mode(path: &Path) -> Option<u32> {
use std::os::unix::fs::PermissionsExt;
fs::metadata(path).ok().map(|m| m.permissions().mode())
}
#[cfg(not(unix))]
pub fn current_mode(_path: &Path) -> Option<u32> {
None
}
pub fn apply_mode(path: &Path, mode: u32) -> Result<(), InstallError> {
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let perms = std::fs::Permissions::from_mode(mode);
fs::set_permissions(path, perms).map_err(|e| InstallError::Io {
path: path.to_path_buf(),
source: e,
})?;
}
#[cfg(not(unix))]
{
let _ = (path, mode);
}
Ok(())
}
pub fn write_if_changed(path: &Path, existing: &str, merged: &str) -> Result<bool, InstallError> {
if merged == existing {
return Ok(false);
}
ensure_parent(path)?;
let mode = current_mode(path).unwrap_or(0o644);
atomic_write(path, merged.as_bytes(), mode)?;
Ok(true)
}