use core::{cell::LazyCell, fmt::Debug}; use alloc::boxed::Box; use bffs::{ Fat32FileSystem, path::{Path, PathBuf}, }; use hashbrown::HashMap; use io::{IoBase, Read, Seek, Write}; pub mod keyboard; pub mod null; pub mod stdin; pub mod virtual_stdin; use crate::{ fs::Disk, tty::TTY0, vga::Vga, virtual_fs::{keyboard::KeyboardBuffer, null::Null, virtual_stdin::VirtualStdin}, }; pub trait VirtualNode: IoBase + Read + Write + Seek + Debug { fn close(&mut self) {} } pub trait VirtualFileSystem: Debug { fn open(&mut self, path: &Path) -> Result, ()>; } #[derive(Debug)] pub struct MainFileSystem { root: Box, mounts: HashMap>, } impl MainFileSystem { pub fn mount(&mut self, path: PathBuf, fs: Box) { self.mounts.insert(path, fs); } } impl VirtualFileSystem for MainFileSystem { fn open(&mut self, path: &Path) -> Result, ()> { let mut max = &mut self.root; let mut max_path = Path::new("/"); let mut path_remaining = path; for (mount, fs) in self.mounts.iter_mut() { if path.starts_with(mount) && mount.starts_with(max_path) { max = fs; max_path = mount; path_remaining = path.without(mount); } } max.open(path_remaining) } } pub static mut FILE_SYSTEM: LazyCell = LazyCell::new(|| MainFileSystem { root: Box::new(Fat32FileSystem::new(Disk::new(1024 * 1024 * 16)).unwrap()), mounts: HashMap::new(), }); pub unsafe fn init_file_system() { unsafe { FILE_SYSTEM.mount("/dev/fb0".into(), Box::new(VGAFileSystem)); FILE_SYSTEM.mount("/dev/tty0".into(), Box::new(TTY0.clone())); FILE_SYSTEM.mount("/dev/null".into(), Box::new(Null)); FILE_SYSTEM.mount( "/dev/input/keyboard".into(), Box::new(KeyboardBuffer::new()), ); FILE_SYSTEM.mount("/dev/stdin".into(), Box::new(VirtualStdin::new())); } } #[derive(Debug)] struct VGAFileSystem; #[derive(Debug)] struct VGAVirtualNode { position: u64, } impl VirtualNode for VGAVirtualNode {} impl IoBase for VGAVirtualNode { type Error = (); } impl Seek for VGAVirtualNode { fn seek(&mut self, pos: io::SeekFrom) -> Result { self.position = match pos { io::SeekFrom::Start(v) => v, io::SeekFrom::End(v) => { ((crate::vga::WIDTH * crate::vga::HEIGHT * size_of::()) as i64 + v) as u64 } io::SeekFrom::Current(v) => (self.position as i64 + v) as u64, }; Ok(self.position) } } impl Read for VGAVirtualNode { fn read(&mut self, _buf: &mut [u8]) -> Result { todo!() } } impl Write for VGAVirtualNode { fn write(&mut self, buf: &[u8]) -> Result { let start = self.position; buf.iter().for_each(|val| { unsafe { Vga::write_u8_unsafe(self.position as usize, *val) }; self.position += 1; }); Ok((self.position - start) as usize) } fn flush(&mut self) -> Result<(), Self::Error> { todo!() } } impl VirtualFileSystem for VGAFileSystem { fn open(&mut self, path: &Path) -> Result, ()> { if !path.is_empty() { Err(()) } else { Ok(Box::new(VGAVirtualNode { position: 0 })) } } }