2026-03-24 13:40:35 +00:00

117 lines
3.4 KiB
Rust

use prometeu_system::fs::{FsBackend, FsEntry, FsError};
use std::fs;
use std::path::PathBuf;
pub struct HostDirBackend {
root: PathBuf,
}
impl HostDirBackend {
pub fn new(root: impl Into<PathBuf>) -> Self {
Self { root: root.into() }
}
fn resolve(&self, path: &str) -> PathBuf {
let path = path.trim_start_matches('/');
self.root.join(path)
}
}
impl FsBackend for HostDirBackend {
fn mount(&mut self) -> Result<(), FsError> {
if !self.root.exists() {
return Err(FsError::NotFound);
}
for dir in &["system", "apps", "media", "user"] {
let path = self.root.join(dir);
if !path.exists() {
fs::create_dir_all(&path).map_err(|e| FsError::IOError(e.to_string()))?;
}
}
Ok(())
}
fn unmount(&mut self) {}
fn list_dir(&self, path: &str) -> Result<Vec<FsEntry>, FsError> {
let full_path = self.resolve(path);
let entries = fs::read_dir(full_path).map_err(|e| FsError::IOError(e.to_string()))?;
let mut result = Vec::new();
for entry in entries {
let entry = entry.map_err(|e| FsError::IOError(e.to_string()))?;
let metadata = entry.metadata().map_err(|e| FsError::IOError(e.to_string()))?;
result.push(FsEntry {
name: entry.file_name().to_string_lossy().into_owned(),
is_dir: metadata.is_dir(),
size: metadata.len(),
});
}
Ok(result)
}
fn read_file(&self, path: &str) -> Result<Vec<u8>, FsError> {
let full_path = self.resolve(path);
fs::read(full_path).map_err(|e| match e.kind() {
std::io::ErrorKind::NotFound => FsError::NotFound,
_ => FsError::IOError(e.to_string()),
})
}
fn write_file(&mut self, path: &str, data: &[u8]) -> Result<(), FsError> {
let full_path = self.resolve(path);
if let Some(parent) = full_path.parent() {
fs::create_dir_all(parent).map_err(|e| FsError::IOError(e.to_string()))?;
}
fs::write(full_path, data).map_err(|e| FsError::IOError(e.to_string()))
}
fn delete(&mut self, path: &str) -> Result<(), FsError> {
let full_path = self.resolve(path);
if full_path.is_dir() {
fs::remove_dir_all(full_path).map_err(|e| FsError::IOError(e.to_string()))
} else {
fs::remove_file(full_path).map_err(|e| FsError::IOError(e.to_string()))
}
}
fn exists(&self, path: &str) -> bool {
self.resolve(path).exists()
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::env;
use std::fs;
fn get_temp_dir(name: &str) -> PathBuf {
let mut path = env::temp_dir();
path.push(format!(
"prometeu_host_test_{}_{}",
name,
std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_nanos()
));
fs::create_dir_all(&path).unwrap();
path
}
#[test]
fn test_host_dir_backend_mount_and_dirs() {
let root = get_temp_dir("mount");
let mut backend = HostDirBackend::new(root.clone());
backend.mount().unwrap();
assert!(root.join("system").is_dir());
assert!(root.join("apps").is_dir());
assert!(root.join("media").is_dir());
assert!(root.join("user").is_dir());
let _ = fs::remove_dir_all(root);
}
}