Files
riscv64-kernel/src/virtual_fs.rs
2026-03-17 18:29:00 +01:00

135 lines
3.5 KiB
Rust

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<Error = ()> + Read + Write + Seek + Debug {
fn close(&mut self) {}
}
pub trait VirtualFileSystem: Debug {
fn open(&mut self, path: &Path) -> Result<Box<dyn VirtualNode + '_>, ()>;
}
#[derive(Debug)]
pub struct MainFileSystem {
root: Box<dyn VirtualFileSystem>,
mounts: HashMap<PathBuf, Box<dyn VirtualFileSystem>>,
}
impl MainFileSystem {
pub fn mount(&mut self, path: PathBuf, fs: Box<dyn VirtualFileSystem>) {
self.mounts.insert(path, fs);
}
}
impl VirtualFileSystem for MainFileSystem {
fn open(&mut self, path: &Path) -> Result<Box<dyn VirtualNode + '_>, ()> {
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<MainFileSystem> = 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<u64, Self::Error> {
self.position = match pos {
io::SeekFrom::Start(v) => v,
io::SeekFrom::End(v) => {
((crate::vga::WIDTH * crate::vga::HEIGHT * size_of::<crate::draw::Color>()) 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<usize, ()> {
todo!()
}
}
impl Write for VGAVirtualNode {
fn write(&mut self, buf: &[u8]) -> Result<usize, ()> {
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<Box<dyn VirtualNode + '_>, ()> {
if !path.is_empty() {
Err(())
} else {
Ok(Box::new(VGAVirtualNode { position: 0 }))
}
}
}