use crate::fs::{FsBackend, FsEntry, FsError}; /// Virtual Filesystem (VFS) interface for Prometeu. /// /// The VFS provides a sandboxed, unified path interface for user applications. /// Instead of interacting directly with the host's disk, the VM uses /// normalized paths (e.g., `/user/save.dat`). /// /// The actual storage is provided by an `FsBackend`, which can be a real /// directory on disk, an in-memory map, or even a network resource. pub struct VirtualFS { /// The active storage implementation. backend: Option>, } impl VirtualFS { pub fn new() -> Self { Self { backend: None } } pub fn mount(&mut self, mut backend: Box) -> Result<(), FsError> { backend.mount()?; self.backend = Some(backend); Ok(()) } pub fn unmount(&mut self) { if let Some(mut backend) = self.backend.take() { backend.unmount(); } } pub fn is_mounted(&self) -> bool { self.backend.is_some() } fn normalize_path(&self, path: &str) -> String { let mut normalized = path.replace('\\', "/"); if !normalized.starts_with('/') { normalized = format!("/{}", normalized); } normalized } pub fn list_dir(&self, path: &str) -> Result, FsError> { let normalized = self.normalize_path(path); let backend = self.backend.as_ref().ok_or(FsError::NotMounted)?; backend.list_dir(&normalized) } pub fn read_file(&self, path: &str) -> Result, FsError> { let normalized = self.normalize_path(path); let backend = self.backend.as_ref().ok_or(FsError::NotMounted)?; backend.read_file(&normalized) } pub fn write_file(&mut self, path: &str, data: &[u8]) -> Result<(), FsError> { let normalized = self.normalize_path(path); let backend = self.backend.as_mut().ok_or(FsError::NotMounted)?; backend.write_file(&normalized, data) } pub fn delete(&mut self, path: &str) -> Result<(), FsError> { let normalized = self.normalize_path(path); let backend = self.backend.as_mut().ok_or(FsError::NotMounted)?; backend.delete(&normalized) } pub fn exists(&self, path: &str) -> bool { let normalized = self.normalize_path(path); self.backend.as_ref().map(|b| b.exists(&normalized)).unwrap_or(false) } pub fn is_healthy(&self) -> bool { self.backend.as_ref().map(|b| b.is_healthy()).unwrap_or(false) } } #[cfg(test)] mod tests { use super::*; use std::collections::HashMap; struct MockBackend { files: HashMap>, healthy: bool, } impl MockBackend { fn new() -> Self { Self { files: HashMap::new(), healthy: true, } } } impl FsBackend for MockBackend { fn mount(&mut self) -> Result<(), FsError> { Ok(()) } fn unmount(&mut self) {} fn list_dir(&self, _path: &str) -> Result, FsError> { Ok(self.files.keys().map(|name| FsEntry { name: name.clone(), is_dir: false, size: 0, }).collect()) } fn read_file(&self, path: &str) -> Result, FsError> { self.files.get(path).cloned().ok_or(FsError::NotFound) } fn write_file(&mut self, path: &str, data: &[u8]) -> Result<(), FsError> { self.files.insert(path.to_string(), data.to_vec()); Ok(()) } fn delete(&mut self, path: &str) -> Result<(), FsError> { self.files.remove(path); Ok(()) } fn exists(&self, path: &str) -> bool { self.files.contains_key(path) } fn is_healthy(&self) -> bool { self.healthy } } #[test] fn test_virtual_fs_operations() { let mut vfs = VirtualFS::new(); let backend = MockBackend::new(); vfs.mount(Box::new(backend)).unwrap(); let test_file = "/user/test.txt"; let content = b"hello world"; vfs.write_file(test_file, content).unwrap(); assert!(vfs.exists(test_file)); let read_content = vfs.read_file(test_file).unwrap(); assert_eq!(read_content, content); vfs.delete(test_file).unwrap(); assert!(!vfs.exists(test_file)); } #[test] fn test_virtual_fs_health() { let mut vfs = VirtualFS::new(); let mut backend = MockBackend::new(); backend.healthy = false; vfs.mount(Box::new(backend)).unwrap(); assert!(!vfs.is_healthy()); } }