#![forbid(unsafe_code)]
use std::fs;
use std::path::{Path, PathBuf};
#[derive(Debug, Clone, PartialEq, Eq)]
#[allow(clippy::struct_excessive_bools)]
pub struct StatePathStatus {
pub path: PathBuf,
pub exists: bool,
pub is_file: bool,
pub is_dir: bool,
pub size_bytes: u64,
pub readable: bool,
pub writable: bool,
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct StateDiagnosticsQuery {
pub config: StatePathStatus,
pub history: StatePathStatus,
pub plugins_registry: StatePathStatus,
pub memory: StatePathStatus,
}
fn parent_dir_is_writable(path: &Path) -> bool {
let mut cursor = path.parent();
while let Some(parent) = cursor {
if let Ok(metadata) = fs::metadata(parent) {
return metadata.is_dir() && !metadata.permissions().readonly();
}
cursor = parent.parent();
}
false
}
fn state_path_status(path: &Path) -> StatePathStatus {
let metadata = fs::metadata(path);
StatePathStatus {
path: path.to_path_buf(),
exists: metadata.is_ok(),
is_file: metadata.as_ref().is_ok_and(std::fs::Metadata::is_file),
is_dir: metadata.as_ref().is_ok_and(std::fs::Metadata::is_dir),
size_bytes: metadata.as_ref().map_or(0_u64, |entry| entry.len()),
readable: fs::read(path).is_ok(),
writable: if path.exists() {
fs::OpenOptions::new().append(true).open(path).is_ok()
} else {
parent_dir_is_writable(path)
},
}
}
#[must_use]
pub fn state_diagnostics_query(
config: &Path,
history: &Path,
plugins_registry: &Path,
memory: &Path,
) -> StateDiagnosticsQuery {
StateDiagnosticsQuery {
config: state_path_status(config),
history: state_path_status(history),
plugins_registry: state_path_status(plugins_registry),
memory: state_path_status(memory),
}
}