//! Two read-only filesystem backends under one mount-scoped trait. use super::*; use os_vfs_traits::{Error, FileSystem, Kind, Metadata, Mount}; #[derive(Clone, Copy, Debug, PartialEq, Eq)] struct HelloFs {fault: bool, corrupt: bool} impl FileSystem for HelloFs { fn root(&self) -> u64 { 1 } fn lookup(&self, parent: u64, name: &[u8]) -> Result { if parent == 1 && name == b"hello" { Ok(2) } else { Err(Error::NoEntry) } } fn metadata(&self, inode: u64) -> Result { match inode { 1 => Ok(Metadata {inode: 1, kind: Kind::Directory, size: 0, allocated_bytes: 0, read_only: true}), 2 => Ok(Metadata {inode: 2, kind: Kind::Regular, size: if self.corrupt { 513 } else { 5 }, allocated_bytes: 512, read_only: true}), _ => Err(Error::NoEntry), } } fn read_at(&self, inode: u64, offset: u64, output: &mut [u8]) -> Result { if inode != 2 { return Err(Error::NoEntry); } if self.fault { output[0] = b'X'; return Err(Error::ReadFault); } let bytes = b"hello"; let begin = offset as usize; let actual = output.len().min(bytes.len().saturating_sub(begin)); output[..actual].copy_from_slice(&bytes[begin..begin + actual]); Ok(actual) } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] struct WorldFs; impl FileSystem for WorldFs { fn root(&self) -> u64 { 10 } fn lookup(&self, parent: u64, name: &[u8]) -> Result { if parent == 10 && name == b"world" { Ok(20) } else { Err(Error::NoEntry) } } fn metadata(&self, inode: u64) -> Result { match inode { 10 => Ok(Metadata {inode: 10, kind: Kind::Directory, size: 0, allocated_bytes: 0, read_only: true}), 20 => Ok(Metadata {inode: 20, kind: Kind::Regular, size: 5, allocated_bytes: 512, read_only: true}), _ => Err(Error::NoEntry), } } fn read_at(&self, inode: u64, offset: u64, output: &mut [u8]) -> Result { if inode != 20 { return Err(Error::NoEntry); } let bytes = b"world"; let begin = offset as usize; let actual = output.len().min(bytes.len().saturating_sub(begin)); output[..actual].copy_from_slice(&bytes[begin..begin + actual]); Ok(actual) } } pub fn run(allocator: &mut memory::FrameAllocator) -> Result<(), &'static str> { let frames_before = allocator.remaining_pages(); let mut hello = Mount::new(3, 7, HelloFs {fault: false, corrupt: false}) .map_err(|_| "k1585-mount-hello")?; let first = hello.lookup(hello.root(), b"hello") .map_err(|_| "k1585-lookup-hello")?; let mut output = [b'!'; 8]; if hello.metadata(first).map(|value| value.size) != Ok(5) || hello.read_at(first, 0, &mut output) != Ok(5) || &output != b"hello!!!" { return Err("k1585-read-hello"); } write_line("TURKOS/OS/K1585-FS: BACKEND-A=HELLO"); let world = Mount::new(4, 8, WorldFs).map_err(|_| "k1585-mount-world")?; let second = world.lookup(world.root(), b"world") .map_err(|_| "k1585-lookup-world")?; let mut other = [0u8; 5]; if world.read_at(second, 0, &mut other) != Ok(5) || &other != b"world" || second.volume() != 4 { return Err("k1585-read-world"); } write_line("TURKOS/OS/K1585-FS: BACKEND-B=WORLD"); if hello.remount() != Ok(8) || hello.metadata(first) != Err(Error::Stale) || hello.read_at(first, 0, &mut output) != Err(Error::Stale) || &output != b"hello!!!" { return Err("k1585-stale-token"); } write_line("TURKOS/OS/K1585-FS: STALE=REJECTED"); let faulty = Mount::new(5, 1, HelloFs {fault: true, corrupt: false}) .map_err(|_| "k1585-mount-fault")?; let faulty_file = faulty.lookup(faulty.root(), b"hello") .map_err(|_| "k1585-lookup-fault")?; let mut canary = [b'!'; 5]; if faulty.read_at(faulty_file, 1, &mut canary) != Err(Error::ReadFault) || canary != [b'!'; 5] { return Err("k1585-read-fault"); } write_line("TURKOS/OS/K1585-FS: READ-FAULT=UNCHANGED"); let corrupt = Mount::new(6, 1, HelloFs {fault: false, corrupt: true}) .map_err(|_| "k1585-mount-corrupt")?; if corrupt.lookup(corrupt.root(), b"hello") != Err(Error::CorruptMetadata) || allocator.remaining_pages() != frames_before { return Err("k1585-corrupt-metadata"); } write_line("TURKOS/OS/K1585-FS: CORRUPT=REJECTED FRAMES=UNCHANGED"); Ok(()) }