117 lines
3.4 KiB
Rust
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);
|
|
}
|
|
}
|