use std::env;
use std::fs::{self, File, OpenOptions};
use std::io::Write;
use std::path::{Path, PathBuf};
pub fn non_empty_env_path(var: &str) -> Option<PathBuf> {
env::var(var)
.ok()
.map(|v| v.trim().to_string())
.filter(|s| !s.is_empty())
.map(PathBuf::from)
}
pub fn set_private_dir_perms(path: &Path) {
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let _ = fs::set_permissions(path, fs::Permissions::from_mode(0o700));
}
#[cfg(not(unix))]
let _ = path;
}
pub fn set_private_file_perms(path: &Path) {
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let _ = fs::set_permissions(path, fs::Permissions::from_mode(0o600));
}
#[cfg(not(unix))]
let _ = path;
}
pub fn create_private_dir_all(path: &Path) -> std::io::Result<()> {
if let Ok(meta) = fs::symlink_metadata(path)
&& meta.file_type().is_symlink()
{
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
format!("Refusing to create directory at symlink path: {}", path.display()),
));
}
fs::create_dir_all(path)?;
set_private_dir_perms(path);
Ok(())
}
pub fn open_private_file_for_write(path: &Path) -> std::io::Result<File> {
if let Ok(meta) = fs::symlink_metadata(path)
&& meta.file_type().is_symlink()
{
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
format!("Refusing to open symlink for writing: {}", path.display()),
));
}
let mut opts = OpenOptions::new();
opts.write(true).create(true).truncate(true);
#[cfg(unix)]
{
use std::os::unix::fs::OpenOptionsExt;
opts.mode(0o600);
}
let file = opts.open(path)?;
#[cfg(unix)]
{
use std::os::unix::fs::PermissionsExt;
let _ = file.set_permissions(fs::Permissions::from_mode(0o600));
}
Ok(file)
}
pub fn write_private_file(path: &Path, contents: impl AsRef<[u8]>) -> std::io::Result<()> {
let mut file = open_private_file_for_write(path)?;
file.write_all(contents.as_ref())?;
file.flush()?;
Ok(())
}