diff --git a/Cargo.lock b/Cargo.lock index b7ba37c..fbaec04 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -56,6 +56,15 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" +[[package]] +name = "fat32" +version = "0.1.0" +dependencies = [ + "error", + "libcommon", + "vfs", +] + [[package]] name = "fdt-rs" version = "0.4.3" diff --git a/Cargo.toml b/Cargo.toml index f6808aa..cff3b78 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ edition = "2018" members = [ "fs/vfs", "fs/memfs", + "fs/fat32", "libcommon", "kernel", "libusr", diff --git a/Makefile b/Makefile index acc052e..11eec56 100644 --- a/Makefile +++ b/Makefile @@ -107,6 +107,7 @@ endif test: cd fs/vfs && cargo test cd fs/memfs && cargo test + cd fs/fat32 && cargo test clean: cargo clean diff --git a/fs/fat32/Cargo.toml b/fs/fat32/Cargo.toml new file mode 100644 index 0000000..cee876c --- /dev/null +++ b/fs/fat32/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "fat32" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +vfs = { path = "../vfs" } +libcommon = { path = "../../libcommon" } +error = { path = "../../error" } diff --git a/fs/fat32/src/dir.rs b/fs/fat32/src/dir.rs new file mode 100644 index 0000000..de63679 --- /dev/null +++ b/fs/fat32/src/dir.rs @@ -0,0 +1,218 @@ +use crate::{Bpb, FileInode}; +use alloc::{borrow::ToOwned, boxed::Box, string::String}; +use core::ffi::c_void; +use error::Errno; +use libcommon::{read_le16, read_le32}; +use vfs::{BlockDevice, Vnode, VnodeImpl, VnodeKind, VnodeRef}; + +pub struct DirectoryInode { + pub cluster: u32, +} + +pub struct FatIterator<'a> { + dev: &'a dyn BlockDevice, + sector: u32, + sector_off: usize, + len: u32, + lfn: [u8; 128], + lfn_len: u8, + buf: [u8; 512], +} + +#[derive(Debug)] +pub struct Dirent { + pub name: String, + pub size: u32, + pub attrs: u8, + pub cluster: u32, +} + +impl VnodeImpl for DirectoryInode { + fn create( + &mut self, + _parent: VnodeRef, + _name: &str, + _kind: VnodeKind, + ) -> Result { + todo!() + } + + fn remove(&mut self, _parent: VnodeRef, _name: &str) -> Result<(), Errno> { + todo!() + } + + fn lookup(&mut self, parent: VnodeRef, name: &str) -> Result { + let fs = parent.fs().unwrap(); + let dirent = { + let dev = fs.clone().dev().unwrap(); + let fs_data = fs.data(); + let bpb: &Bpb = fs_data.as_ref().and_then(|e| e.downcast_ref()).unwrap(); + let sector = bpb.cluster_base_sector(self.cluster); + + FatIterator::new(dev, sector, bpb.sectors_per_cluster) + .find(|ent| ent.name == name) + .ok_or(Errno::DoesNotExist) + }?; + + let kind = if dirent.attrs & 0x10 != 0 { + VnodeKind::Directory + } else { + VnodeKind::Regular + }; + + let vnode = Vnode::new(&dirent.name, kind, Vnode::SEEKABLE); + if kind == VnodeKind::Directory { + vnode.set_data(Box::new(DirectoryInode { + cluster: dirent.cluster, + })); + } else { + vnode.set_data(Box::new(FileInode { + cluster: dirent.cluster, + size: dirent.size, + })); + } + Ok(vnode) + } + + fn open(&mut self, _node: VnodeRef) -> Result { + todo!() + } + + fn close(&mut self, _node: VnodeRef) -> Result<(), Errno> { + todo!() + } + + fn read(&mut self, _node: VnodeRef, _pos: usize, _data: &mut [u8]) -> Result { + todo!() + } + + fn write(&mut self, _node: VnodeRef, _pos: usize, _data: &[u8]) -> Result { + todo!() + } + + fn truncate(&mut self, _node: VnodeRef, _size: usize) -> Result<(), Errno> { + todo!() + } + + fn size(&mut self, _node: VnodeRef) -> Result { + todo!() + } + + fn ioctl(&mut self, _node: VnodeRef, _cmd: u64, _value: *mut c_void) -> Result { + todo!() + } +} + +impl Iterator for FatIterator<'_> { + type Item = Dirent; + + fn next(&mut self) -> Option { + loop { + if self.len == 0 { + return None; + } + + if self.sector_off == 0 { + self.dev + .read(self.sector as usize * 512, &mut self.buf) + .unwrap(); + } + + while self.sector_off < 512 { + let off = self.sector_off; + if self.buf[off] == 0 { + self.len = 0; + return None; + } + self.sector_off += 32; + + // Check for LFN entries + if self.buf[off + 11] == 0x0F { + let lfn_order = self.buf[off]; + let lfn_index = (lfn_order & 0x3F) as usize; + assert!(lfn_index > 0); + let mut lfn8 = [0u8; 13]; + + for j in 0..5 { + lfn8[j] = self.buf[off + 1 + j * 2]; + } + for j in 0..6 { + lfn8[j + 5] = self.buf[off + 14 + j * 2]; + } + for j in 0..2 { + lfn8[j + 11] = self.buf[off + 28 + j * 2]; + } + + let len = lfn8.iter().position(|&c| c == 0).unwrap_or(13); + let off = (lfn_index - 1) * 13; + + if lfn_order & 0x40 != 0 { + // Last entry + self.lfn_len = (off + len) as u8; + } else { + assert_eq!(len, 13); + } + self.lfn[off..off + len].copy_from_slice(&lfn8[..len]); + } else { + let size = read_le32(&self.buf[off + 28..]); + let attrs = self.buf[off + 11]; + let cluster = ((read_le16(&self.buf[off + 20..]) as u32) << 16) + | (read_le16(&self.buf[off + 26..]) as u32); + + if self.lfn_len != 0 { + let len = self.lfn_len as usize; + self.lfn_len = 0; + return Some(Dirent { + name: core::str::from_utf8(&self.lfn[..len as usize]) + .unwrap() + .to_owned(), + attrs, + size, + cluster, + }); + } else { + let len = self.buf[off..off + 11] + .iter() + .position(|&c| (c == 0) || (c == b' ')) + .unwrap_or(11); + let name = + core::str::from_utf8(&self.buf[off..off + core::cmp::min(len, 8)]) + .unwrap() + .to_owned(); + let ext = if len > 8 { + ".".to_owned() + + core::str::from_utf8(&self.buf[off + 8..off + len]).unwrap() + } else { + "".to_owned() + }; + + return Some(Dirent { + name: name + &ext, + attrs, + size, + cluster, + }); + } + } + } + + self.sector_off = 0; + self.len -= 1; + self.sector += 1; + } + } +} + +impl FatIterator<'_> { + pub fn new(dev: &'static dyn BlockDevice, sector: u32, sectors_per_cluster: u8) -> Self { + Self { + dev, + sector, + len: sectors_per_cluster as u32, + sector_off: 0, + lfn_len: 0, + lfn: [0; 128], + buf: [0; 512], + } + } +} diff --git a/fs/fat32/src/file.rs b/fs/fat32/src/file.rs new file mode 100644 index 0000000..afe07d0 --- /dev/null +++ b/fs/fat32/src/file.rs @@ -0,0 +1,80 @@ +use vfs::{VnodeImpl, VnodeRef, VnodeKind}; +use core::ffi::c_void; +use error::Errno; +use crate::Bpb; + +pub struct FileInode { + pub cluster: u32, + pub size: u32 +} + +impl VnodeImpl for FileInode { + fn create(&mut self, _at: VnodeRef, _name: &str, _kind: VnodeKind) -> Result { + panic!() + } + + fn remove(&mut self, _parent: VnodeRef, _name: &str) -> Result<(), Errno> { + panic!() + } + + fn lookup(&mut self, _parent: VnodeRef, _name: &str) -> Result { + panic!() + } + + fn open(&mut self, _node: VnodeRef) -> Result { + Ok(0) + } + + fn close(&mut self, _node: VnodeRef) -> Result<(), Errno> { + todo!() + } + + fn read(&mut self, node: VnodeRef, pos: usize, data: &mut [u8]) -> Result { + let size = self.size as usize; + if pos >= size { + return Ok(0); + } + + let fs = node.fs().unwrap(); + let dev = fs.clone().dev().unwrap(); + let fs_data = fs.data(); + let bpb: &Bpb = fs_data.as_ref().and_then(|e| e.downcast_ref()).unwrap(); + let base_sector = bpb.cluster_base_sector(self.cluster); + + let mut rem = core::cmp::min(size - pos, data.len()); + let mut off = 0usize; + let mut buf = [0; 512]; + + while rem != 0 { + let sector_index = (pos + off) / 512; + let sector_offset = (pos + off) % 512; + let count = core::cmp::min(rem, 512 - sector_offset); + + dev.read((base_sector as usize + sector_index) * 512, &mut buf)?; + let src = &buf[sector_offset..sector_offset + count]; + let dst = &mut data[off..off + count]; + dst.copy_from_slice(src); + + rem -= count; + off += count; + } + + Ok(off) + } + + fn write(&mut self, _node: VnodeRef, _pos: usize, _data: &[u8]) -> Result { + todo!() + } + + fn truncate(&mut self, _node: VnodeRef, _size: usize) -> Result<(), Errno> { + todo!() + } + + fn size(&mut self, _node: VnodeRef) -> Result { + todo!() + } + + fn ioctl(&mut self, _node: VnodeRef, _cmd: u64, _value: *mut c_void) -> Result { + todo!() + } +} diff --git a/fs/fat32/src/lib.rs b/fs/fat32/src/lib.rs new file mode 100644 index 0000000..a2367b8 --- /dev/null +++ b/fs/fat32/src/lib.rs @@ -0,0 +1,163 @@ +#![no_std] + +#[cfg(test)] +#[macro_use] +extern crate std; + +extern crate alloc; + +use alloc::{rc::Rc, boxed::Box}; +use core::any::Any; +use core::cell::{Ref, RefCell}; +use error::Errno; +use libcommon::{read_le16, read_le32}; +use vfs::{BlockDevice, Filesystem, Vnode, VnodeKind, VnodeRef}; + +pub mod dir; +pub use dir::{Dirent as FatEntry, FatIterator, DirectoryInode}; +pub mod file; +pub use file::FileInode; + +#[derive(Debug)] +struct Bpb { + sectors_per_cluster: u8, + reserved_sectors: u16, + fat_count: u8, + sectors_per_fat: u32, +} + +pub struct Fat32 { + bpb: RefCell, + root: RefCell>, + dev: &'static dyn BlockDevice, +} + +impl Bpb { + pub const fn cluster_base_sector(&self, cluster: u32) -> u32 { + let first_data_sector = self.reserved_sectors as u32 + + (self.fat_count as u32 * self.sectors_per_fat as u32); + ((cluster - 2) * self.sectors_per_cluster as u32) + first_data_sector + } +} + +impl Filesystem for Fat32 { + fn root(self: Rc) -> Result { + self.root.borrow().clone().ok_or(Errno::DoesNotExist) + } + + fn dev(self: Rc) -> Option<&'static dyn BlockDevice> { + Some(self.dev) + } + + fn data(&self) -> Option> { + Some(self.bpb.borrow()) + } +} + +impl Fat32 { + fn create_node(self: Rc, name: &str, kind: VnodeKind, cluster: u32) -> VnodeRef { + let res = Vnode::new(name, kind, Vnode::SEEKABLE); + + res.set_fs(self.clone()); + res.set_data(match kind { + VnodeKind::Directory => Box::new(DirectoryInode { cluster }), + _ => todo!(), + }); + res + } + + pub fn open(dev: &'static dyn BlockDevice) -> Result, Errno> { + let mut buf = [0u8; 512]; + + dev.read(0, &mut buf)?; + + if buf[0x42] != 0x28 && buf[0x42] != 0x29 { + panic!("Not a FAT32"); + } + + let root_cluster = read_le32(&buf[44..]); + + let res = Rc::new(Self { + bpb: RefCell::new(Bpb { + fat_count: buf[16], + reserved_sectors: read_le16(&buf[14..]), + sectors_per_cluster: buf[13], + sectors_per_fat: read_le32(&buf[36..]), + }), + dev, + root: RefCell::new(None), + }); + + *res.root.borrow_mut() = Some(res.clone().create_node( + "", + VnodeKind::Directory, + root_cluster, + )); + + Ok(res) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use std::cell::RefCell; + use std::fs::File; + use std::io::{Read, Seek, SeekFrom}; + use libcommon::{Read as LRead}; + use vfs::Ioctx; + + struct FileBlockDevice { + file: RefCell>, + } + + impl FileBlockDevice { + pub const fn new() -> Self { + Self { + file: RefCell::new(None), + } + } + + pub fn open(&self, path: &str) { + *self.file.borrow_mut() = Some(File::open(path).unwrap()); + } + } + + impl BlockDevice for FileBlockDevice { + fn read(&self, pos: usize, buf: &mut [u8]) -> Result<(), Errno> { + let mut borrow = self.file.borrow_mut(); + let file = borrow.as_mut().unwrap(); + file.seek(SeekFrom::Start(pos as u64)).unwrap(); + if file.read(buf).unwrap() != buf.len() { + Err(Errno::InvalidArgument) + } else { + Ok(()) + } + } + + fn write(&self, _pos: usize, _buf: &[u8]) -> Result<(), Errno> { + todo!() + } + } + + unsafe impl Sync for FileBlockDevice {} + + #[test] + fn test_fat32_open() { + static DEV: FileBlockDevice = FileBlockDevice::new(); + + DEV.open("test/test0.img"); + + let fs = Fat32::open(&DEV).unwrap(); + let root = fs.root().unwrap(); + let ioctx = Ioctx::new(root); + + let mut buf = [0u8; 512]; + let node0 = ioctx.find(None, "FILENAME.TXT").unwrap(); + let mut file = node0.open().unwrap(); + + let count = file.read(&mut buf).unwrap(); + assert_eq!(count, 15); + assert_eq!(&buf[..15], b"This is a file\n"); + } +} diff --git a/fs/fat32/test/test0.img b/fs/fat32/test/test0.img new file mode 100644 index 0000000..c9dc2e7 Binary files /dev/null and b/fs/fat32/test/test0.img differ diff --git a/fs/memfs/src/bvec.rs b/fs/memfs/src/bvec.rs index da34fc0..87c1bd8 100644 --- a/fs/memfs/src/bvec.rs +++ b/fs/memfs/src/bvec.rs @@ -40,14 +40,16 @@ impl<'a, A: BlockAllocator + Copy> Bvec<'a, A> { } #[cfg(feature = "cow")] - pub fn is_cow(&self) -> bool { - !self.cow_source.is_null() + pub unsafe fn new_copy_on_write(alloc: A, cow_source: *const u8, cow_len: usize) -> Self { + let mut res = Bvec::new(alloc); + res.cow_source = cow_source; + res.size = cow_len; + res } #[cfg(feature = "cow")] - pub unsafe fn setup_cow(&mut self, src: *const u8, size: usize) { - self.cow_source = src; - self.size = size; + pub fn is_cow(&self) -> bool { + !self.cow_source.is_null() } pub const fn size(&self) -> usize { @@ -305,12 +307,13 @@ mod cow_tests { #[test] fn bvec_write_copy_simple() { - let mut bvec = Bvec::new(TestAlloc {}); + //let mut bvec = Bvec::new(TestAlloc {}); let mut buf = [0u8; 512]; let source_data = b"This is initial data\n"; - unsafe { - bvec.setup_cow(source_data.as_ptr(), source_data.len()); - } + //unsafe { + // bvec.setup_cow(source_data.as_ptr(), source_data.len()); + //} + let mut bvec = unsafe { Bvec::new_copy_on_write(TestAlloc {}, source_data.as_ptr(), source_data.len()) }; assert!(bvec.is_cow()); assert_eq!(bvec.size(), source_data.len()); assert_eq!(bvec.capacity, 0); @@ -327,15 +330,12 @@ mod cow_tests { #[test] fn bvec_write_copy_l0() { - let mut bvec = Bvec::new(TestAlloc {}); let mut source_data = [0u8; 4096 * 2 - 2]; let mut buf = [0u8; 512]; for i in 0..source_data.len() { source_data[i] = (i & 0xFF) as u8; } - unsafe { - bvec.setup_cow(source_data.as_ptr(), source_data.len()); - } + let mut bvec = unsafe { Bvec::new_copy_on_write(TestAlloc {}, source_data.as_ptr(), source_data.len()) }; assert!(bvec.is_cow()); assert_eq!(bvec.size(), source_data.len()); assert_eq!(bvec.capacity, 0); diff --git a/fs/memfs/src/lib.rs b/fs/memfs/src/lib.rs index ba9bd9f..400d6cf 100644 --- a/fs/memfs/src/lib.rs +++ b/fs/memfs/src/lib.rs @@ -12,11 +12,12 @@ extern crate alloc; extern crate std; use alloc::{boxed::Box, rc::Rc}; -use core::cell::RefCell; +use core::cell::{RefCell, Ref}; use core::ffi::c_void; use error::Errno; -use libcommon::path_component_left; -use vfs::{node::VnodeData, Filesystem, Vnode, VnodeImpl, VnodeKind, VnodeRef}; +use libcommon::*; +use vfs::{Filesystem, Vnode, VnodeImpl, VnodeKind, VnodeRef, BlockDevice}; +use core::any::Any; pub mod block; pub use block::{BlockAllocator, BlockRef}; @@ -36,14 +37,17 @@ pub struct FileInode<'a, A: BlockAllocator + Copy + 'static> { pub struct DirInode; -struct SetupFileParam { - data: &'static [u8], -} - -const FILE_SETUP_COW: u64 = 0x1001; - impl<'a, A: BlockAllocator + Copy + 'static> VnodeImpl for FileInode<'a, A> { - fn create(&mut self, _parent: VnodeRef, _node: VnodeRef) -> Result<(), Errno> { + fn create( + &mut self, + _parent: VnodeRef, + _name: &str, + _kind: VnodeKind, + ) -> Result { + panic!() + } + + fn lookup(&mut self, _parent: VnodeRef, _name: &str) -> Result { panic!() } @@ -75,24 +79,23 @@ impl<'a, A: BlockAllocator + Copy + 'static> VnodeImpl for FileInode<'a, A> { Ok(self.data.size()) } - fn ioctl(&mut self, _node: VnodeRef, cmd: u64, value: *mut c_void) -> Result { - match cmd { - #[cfg(feature = "cow")] - FILE_SETUP_COW => { - let data = unsafe { (value as *mut SetupFileParam).as_ref().unwrap() }; - unsafe { - self.data.setup_cow(data.data.as_ptr(), data.data.len()); - } - Ok(0) - } - _ => Err(Errno::InvalidArgument), - } + fn ioctl(&mut self, _node: VnodeRef, _cmd: u64, _value: *mut c_void) -> Result { + todo!() } } impl VnodeImpl for DirInode { - fn create(&mut self, _parent: VnodeRef, _node: VnodeRef) -> Result<(), Errno> { - Ok(()) + fn create( + &mut self, + _parent: VnodeRef, + _name: &str, + _kind: VnodeKind, + ) -> Result { + todo!() + } + + fn lookup(&mut self, _parent: VnodeRef, _name: &str) -> Result { + panic!() } fn remove(&mut self, _parent: VnodeRef, _name: &str) -> Result<(), Errno> { @@ -133,20 +136,28 @@ impl Filesystem for Ramfs { self.root.borrow().clone().ok_or(Errno::DoesNotExist) } - fn create_node(self: Rc, name: &str, kind: VnodeKind) -> Result { - let node = Vnode::new(name, kind, Vnode::SEEKABLE); - let data: Box = match kind { - VnodeKind::Regular => Box::new(FileInode { - data: Bvec::new(self.alloc), - }), - VnodeKind::Directory => Box::new(DirInode {}), - }; - node.set_data(VnodeData { - fs: self, - node: data, - }); - Ok(node) + fn data(&self) -> Option> { + None } + + fn dev(self: Rc) -> Option<&'static dyn BlockDevice> { + None + } + + // fn create_node(self: Rc, name: &str, kind: VnodeKind) -> Result { + // let node = Vnode::new(name, kind, Vnode::SEEKABLE); + // let data: Box = match kind { + // VnodeKind::Regular => Box::new(FileInode { + // data: Bvec::new(self.alloc), + // }), + // VnodeKind::Directory => Box::new(DirInode {}), + // }; + // node.set_data(VnodeData { + // fs: self, + // node: data, + // }); + // Ok(node) + // } } impl Ramfs { @@ -159,22 +170,28 @@ impl Ramfs { Ok(res) } + fn create_node_initial(self: Rc, name: &str, kind: VnodeKind) -> VnodeRef { + let node = Vnode::new(name, kind, Vnode::SEEKABLE); + node.set_fs(self.clone()); + match kind { + VnodeKind::Directory => node.set_data(Box::new(DirInode {})), + VnodeKind::Regular => {} + }; + node + } + fn make_path( self: Rc, at: VnodeRef, path: &str, - kind: VnodeKind, do_create: bool, ) -> Result { + if path.is_empty() { + return Ok(at); + } let (element, rest) = path_component_left(path); assert!(!element.is_empty()); - let node_kind = if rest.is_empty() { - kind - } else { - VnodeKind::Directory - }; - let node = at.lookup(element); let node = match node { Some(node) => node, @@ -182,7 +199,10 @@ impl Ramfs { if !do_create { return Err(Errno::DoesNotExist); } - let node = self.clone().create_node(element, node_kind)?; + // TODO use at.create() instead? + let node = self + .clone() + .create_node_initial(element, VnodeKind::Directory); at.attach(node.clone()); node } @@ -191,38 +211,45 @@ impl Ramfs { if rest.is_empty() { Ok(node) } else { - self.make_path(node, rest, kind, do_create) + self.make_path(node, rest, do_create) } } unsafe fn load_tar(self: Rc, base: *const u8, size: usize) -> Result { - let root = self.clone().create_node("", VnodeKind::Directory)?; + let root = self.clone().create_node_initial("", VnodeKind::Directory); // 1. Create all the paths in TAR for block in TarIterator::new(base, base.add(size)) { - let node = - self.clone() - .make_path(root.clone(), block.path()?, block.node_kind(), true)?; + let (dirname, basename) = path_component_right(block.path()?); + + let parent = self.clone().make_path(root.clone(), dirname, true)?; + let node = self + .clone() + .create_node_initial(basename, block.node_kind()); assert_eq!(node.kind(), block.node_kind()); + parent.attach(node); } // 2. Setup data blocks for block in TarIterator::new(base, base.add(size)) { if block.is_file() { - let node = self.clone().make_path( - root.clone(), - block.path()?, - block.node_kind(), - false, - )?; + // Will not create any dirs + let node = self.clone().make_path(root.clone(), block.path()?, false)?; + assert_eq!(node.kind(), block.node_kind()); #[cfg(feature = "cow")] { - let mut param = SetupFileParam { data: block.data() }; - node.ioctl(FILE_SETUP_COW, &mut param as *mut _ as *mut _)?; + let data = block.data(); + node.set_data(Box::new(FileInode { + data: Bvec::new_copy_on_write(self.alloc, data.as_ptr(), data.len()), + })); } #[cfg(not(feature = "cow"))] { + node.set_data(Box::new(FileInode { + data: Bvec::new(self.alloc) + })); + let size = block.size(); node.truncate(size)?; if node.write(0, block.data())? != size { diff --git a/fs/vfs/src/file.rs b/fs/vfs/src/file.rs index f4d8dad..e0e1e22 100644 --- a/fs/vfs/src/file.rs +++ b/fs/vfs/src/file.rs @@ -79,23 +79,28 @@ impl File { #[cfg(test)] mod tests { use super::*; - use crate::{node::VnodeData, Filesystem, Vnode, VnodeImpl, VnodeKind, VnodeRef}; + use crate::{Vnode, VnodeImpl, VnodeKind, VnodeRef}; use alloc::boxed::Box; use alloc::rc::Rc; use core::ffi::c_void; pub struct DummyInode; - pub struct DummyFs; impl VnodeImpl for DummyInode { - fn create(&mut self, _at: VnodeRef, _node: VnodeRef) -> Result<(), Errno> { - Err(Errno::NotImplemented) + fn create(&mut self, _at: VnodeRef, name: &str, kind: VnodeKind) -> Result { + let node = Vnode::new(name, kind, 0); + node.set_data(Box::new(DummyInode {})); + Ok(node) } fn remove(&mut self, _at: VnodeRef, _name: &str) -> Result<(), Errno> { Err(Errno::NotImplemented) } + fn lookup(&mut self, _at: VnodeRef, _name: &str) -> Result { + todo!() + } + fn open(&mut self, _node: VnodeRef) -> Result { Ok(0) } @@ -138,25 +143,10 @@ mod tests { } } - impl Filesystem for DummyFs { - fn root(self: Rc) -> Result { - todo!() - } - - fn create_node(self: Rc, name: &str, kind: VnodeKind) -> Result { - let node = Vnode::new(name, kind, 0); - node.set_data(VnodeData { - node: Box::new(DummyInode {}), - fs: self, - }); - Ok(node) - } - } - #[test] fn test_normal_read() { - let fs = Rc::new(DummyFs {}); - let node = fs.create_node("", VnodeKind::Regular).unwrap(); + let node = Vnode::new("", VnodeKind::Regular, 0); + node.set_data(Box::new(DummyInode {})); let mut file = node.open().unwrap(); match &file.inner { diff --git a/fs/vfs/src/fs.rs b/fs/vfs/src/fs.rs index 40f6f2c..dc69bba 100644 --- a/fs/vfs/src/fs.rs +++ b/fs/vfs/src/fs.rs @@ -1,8 +1,11 @@ -use crate::{VnodeKind, VnodeRef}; +use crate::{VnodeRef, BlockDevice}; +use core::cell::Ref; +use core::any::Any; use alloc::rc::Rc; use error::Errno; pub trait Filesystem { fn root(self: Rc) -> Result; - fn create_node(self: Rc, name: &str, kind: VnodeKind) -> Result; + fn dev(self: Rc) -> Option<&'static dyn BlockDevice>; + fn data<'a>(&'a self) -> Option>; } diff --git a/fs/vfs/src/ioctx.rs b/fs/vfs/src/ioctx.rs index 63a1b28..6946e1e 100644 --- a/fs/vfs/src/ioctx.rs +++ b/fs/vfs/src/ioctx.rs @@ -40,7 +40,7 @@ impl Ioctx { } assert!(!element.is_empty()); - let node = at.lookup(element).ok_or(Errno::DoesNotExist)?; + let node = at.lookup_or_load(element)?; if rest.is_empty() { Ok(node) @@ -62,55 +62,58 @@ impl Ioctx { self._find(at, path) } - pub fn mkdir(&self, at: Option, path: &str, mode: FileMode) -> Result<(), Errno> { + pub fn mkdir(&self, at: Option, path: &str, mode: FileMode) -> Result { let (parent, name) = path_component_right(path); - let parent_node = self.find(at, parent)?; - - parent_node.mkdir(name, mode).map(|_| ()) + self.find(at, parent)?.mkdir(name, mode) } } #[cfg(test)] mod tests { use super::*; - use crate::{node::VnodeData, Filesystem, Vnode, VnodeImpl, VnodeKind}; + use crate::{Vnode, VnodeImpl, VnodeKind}; use alloc::{boxed::Box, rc::Rc}; use core::ffi::c_void; pub struct DummyInode; - pub struct DummyFs; impl VnodeImpl for DummyInode { - fn create(&mut self, _at: VnodeRef, _node: VnodeRef) -> Result<(), Errno> { - Err(Errno::NotImplemented) + fn create(&mut self, _at: VnodeRef, name: &str, kind: VnodeKind) -> Result { + let vnode = Vnode::new(name, kind, 0); + vnode.set_data(Box::new(DummyInode {})); + Ok(vnode) } fn remove(&mut self, _at: VnodeRef, _name: &str) -> Result<(), Errno> { - Err(Errno::NotImplemented) + todo!() + } + + fn lookup(&mut self, _at: VnodeRef, _name: &str) -> Result { + Err(Errno::DoesNotExist) } fn open(&mut self, _node: VnodeRef) -> Result { - Err(Errno::NotImplemented) + todo!() } fn close(&mut self, _node: VnodeRef) -> Result<(), Errno> { - Err(Errno::NotImplemented) + todo!() } fn read(&mut self, _node: VnodeRef, _pos: usize, _data: &mut [u8]) -> Result { - Err(Errno::NotImplemented) + todo!() } fn write(&mut self, _node: VnodeRef, _pos: usize, _data: &[u8]) -> Result { - Err(Errno::NotImplemented) + todo!() } fn truncate(&mut self, _node: VnodeRef, _size: usize) -> Result<(), Errno> { - Err(Errno::NotImplemented) + todo!() } fn size(&mut self, _node: VnodeRef) -> Result { - Err(Errno::NotImplemented) + todo!() } fn ioctl( @@ -119,23 +122,8 @@ mod tests { _cmd: u64, _value: *mut c_void, ) -> Result { - Err(Errno::NotImplemented) - } - } - - impl Filesystem for DummyFs { - fn root(self: Rc) -> Result { todo!() } - - fn create_node(self: Rc, name: &str, kind: VnodeKind) -> Result { - let node = Vnode::new(name, kind, 0); - node.set_data(VnodeData { - node: Box::new(DummyInode {}), - fs: self, - }); - Ok(node) - } } #[test] @@ -220,14 +208,10 @@ mod tests { #[test] fn test_mkdir() { - let fs = Rc::new(DummyFs {}); let root = Vnode::new("", VnodeKind::Directory, 0); let ioctx = Ioctx::new(root.clone()); - root.set_data(VnodeData { - node: Box::new(DummyInode {}), - fs: fs.clone(), - }); + root.set_data(Box::new(DummyInode {})); assert!(ioctx.mkdir(None, "/dir0", FileMode::default_dir()).is_ok()); assert_eq!( diff --git a/fs/vfs/src/node.rs b/fs/vfs/src/node.rs index d01c422..748564a 100644 --- a/fs/vfs/src/node.rs +++ b/fs/vfs/src/node.rs @@ -18,13 +18,6 @@ pub struct TreeNode { children: Vec, } -pub struct VnodeData { - // Filesystem itself - pub fs: Rc, - // Something like "inode" struct + "ops" table - pub node: Box, -} - pub struct VnodeProps { mode: FileMode, } @@ -37,12 +30,15 @@ pub struct Vnode { kind: VnodeKind, flags: u32, - pub data: RefCell>, + fs: RefCell>>, + data: RefCell>>, } pub trait VnodeImpl { - fn create(&mut self, at: VnodeRef, node: VnodeRef) -> Result<(), Errno>; + // Directory-only operations + fn create(&mut self, at: VnodeRef, name: &str, kind: VnodeKind) -> Result; fn remove(&mut self, at: VnodeRef, name: &str) -> Result<(), Errno>; + fn lookup(&mut self, at: VnodeRef, name: &str) -> Result; fn open(&mut self, node: VnodeRef /* TODO open mode */) -> Result; fn close(&mut self, node: VnodeRef) -> Result<(), Errno>; @@ -70,18 +66,27 @@ impl Vnode { parent: None, children: Vec::new(), }), + fs: RefCell::new(None), data: RefCell::new(None), }) } - pub fn set_data(&self, data: VnodeData) { + pub fn set_data(&self, data: Box) { *self.data.borrow_mut() = Some(data); } - pub fn data(&self) -> RefMut> { + pub fn set_fs(&self, fs: Rc) { + *self.fs.borrow_mut() = Some(fs); + } + + pub fn data(&self) -> RefMut>> { self.data.borrow_mut() } + pub fn fs(&self) -> Option> { + self.fs.borrow().clone() + } + pub fn is_directory(&self) -> bool { self.kind == VnodeKind::Directory } @@ -134,26 +139,40 @@ impl Vnode { .cloned() } + pub fn lookup_or_load(self: &VnodeRef, name: &str) -> Result { + if let Some(node) = self.lookup(name) { + return Ok(node); + } + + if let Some(ref mut data) = *self.data() { + let vnode = data.lookup(self.clone(), name)?; + if let Some(fs) = self.fs() { + vnode.set_fs(fs); + } + self.attach(vnode.clone()); + Ok(vnode) + } else { + Err(Errno::NotImplemented) + } + } + pub fn mkdir(self: &VnodeRef, name: &str, mode: FileMode) -> Result { if self.kind != VnodeKind::Directory { return Err(Errno::NotADirectory); } - if self.lookup(name).is_some() { - return Err(Errno::AlreadyExists); - } + match self.lookup_or_load(name) { + Err(Errno::DoesNotExist) => {}, + Ok(_) => return Err(Errno::AlreadyExists), + e => return e, + }; - if let Some(ref mut data) = *self.data.borrow_mut() { - let vnode = data.fs.clone().create_node(name, VnodeKind::Directory)?; - - vnode.props.borrow_mut().mode = mode; - - if let Err(err) = data.node.create(self.clone(), vnode.clone()) { - if err != Errno::NotImplemented { - return Err(err); - } + if let Some(ref mut data) = *self.data() { + let vnode = data.create(self.clone(), name, VnodeKind::Directory)?; + if let Some(fs) = self.fs() { + vnode.set_fs(fs); } - + vnode.props.borrow_mut().mode = mode; self.attach(vnode.clone()); Ok(vnode) } else { @@ -166,15 +185,9 @@ impl Vnode { return Err(Errno::NotADirectory); } - if let Some(ref mut data) = *self.data.borrow_mut() { + if let Some(ref mut data) = *self.data() { let vnode = self.lookup(name).ok_or(Errno::DoesNotExist)?; - - if let Err(err) = data.node.remove(self.clone(), name) { - if err != Errno::NotImplemented { - return Err(err); - } - } - + data.remove(self.clone(), name)?; vnode.detach(); Ok(()) } else { @@ -187,8 +200,8 @@ impl Vnode { return Err(Errno::IsADirectory); } - if let Some(ref mut data) = *self.data.borrow_mut() { - let pos = data.node.open(self.clone())?; + if let Some(ref mut data) = *self.data() { + let pos = data.open(self.clone())?; Ok(File::normal(self.clone(), pos)) } else { Err(Errno::NotImplemented) @@ -200,8 +213,8 @@ impl Vnode { return Err(Errno::IsADirectory); } - if let Some(ref mut data) = *self.data.borrow_mut() { - data.node.read(self.clone(), pos, buf) + if let Some(ref mut data) = *self.data() { + data.read(self.clone(), pos, buf) } else { Err(Errno::NotImplemented) } @@ -212,8 +225,8 @@ impl Vnode { return Err(Errno::IsADirectory); } - if let Some(ref mut data) = *self.data.borrow_mut() { - data.node.write(self.clone(), pos, buf) + if let Some(ref mut data) = *self.data() { + data.write(self.clone(), pos, buf) } else { Err(Errno::NotImplemented) } @@ -224,24 +237,24 @@ impl Vnode { return Err(Errno::IsADirectory); } - if let Some(ref mut data) = *self.data.borrow_mut() { - data.node.truncate(self.clone(), size) + if let Some(ref mut data) = *self.data() { + data.truncate(self.clone(), size) } else { Err(Errno::NotImplemented) } } pub fn size(self: &VnodeRef) -> Result { - if let Some(ref mut data) = *self.data.borrow_mut() { - data.node.size(self.clone()) + if let Some(ref mut data) = *self.data() { + data.size(self.clone()) } else { Err(Errno::NotImplemented) } } pub fn ioctl(self: &VnodeRef, cmd: u64, value: *mut c_void) -> Result { - if let Some(ref mut data) = *self.data.borrow_mut() { - data.node.ioctl(self.clone(), cmd, value) + if let Some(ref mut data) = *self.data() { + data.ioctl(self.clone(), cmd, value) } else { Err(Errno::NotImplemented) } @@ -257,18 +270,22 @@ impl fmt::Debug for Vnode { #[cfg(test)] mod tests { use super::*; - use crate::Filesystem; pub struct DummyInode; - pub struct DummyFs; impl VnodeImpl for DummyInode { - fn create(&mut self, _at: VnodeRef, _node: VnodeRef) -> Result<(), Errno> { - Err(Errno::NotImplemented) + fn create(&mut self, _at: VnodeRef, name: &str, kind: VnodeKind) -> Result { + let node = Vnode::new(name, kind, 0); + node.set_data(Box::new(DummyInode {})); + Ok(node) } fn remove(&mut self, _at: VnodeRef, _name: &str) -> Result<(), Errno> { - Err(Errno::NotImplemented) + Ok(()) + } + + fn lookup(&mut self, _at: VnodeRef, _name: &str) -> Result { + Err(Errno::DoesNotExist) } fn open(&mut self, _node: VnodeRef) -> Result { @@ -305,21 +322,6 @@ mod tests { } } - impl Filesystem for DummyFs { - fn root(self: Rc) -> Result { - todo!() - } - - fn create_node(self: Rc, name: &str, kind: VnodeKind) -> Result { - let node = Vnode::new(name, kind, 0); - node.set_data(VnodeData { - node: Box::new(DummyInode {}), - fs: self, - }); - Ok(node) - } - } - #[test] fn test_parent() { let root = Vnode::new("", VnodeKind::Directory, 0); @@ -333,13 +335,9 @@ mod tests { #[test] fn test_mkdir_unlink() { - let fs = Rc::new(DummyFs {}); let root = Vnode::new("", VnodeKind::Directory, 0); - root.set_data(VnodeData { - node: Box::new(DummyInode {}), - fs: fs.clone(), - }); + root.set_data(Box::new(DummyInode {})); let node = root.mkdir("test", FileMode::default_dir()).unwrap(); diff --git a/kernel/src/arch/aarch64/mach_rpi3/mod.rs b/kernel/src/arch/aarch64/mach_rpi3/mod.rs index fccd42a..fe4d7cb 100644 --- a/kernel/src/arch/aarch64/mach_rpi3/mod.rs +++ b/kernel/src/arch/aarch64/mach_rpi3/mod.rs @@ -59,7 +59,7 @@ pub fn local_timer() -> &'static GenericTimer { } static IRQCHIP: Bcm283xIrqchip = Bcm283xIrqchip::new(); -static EMMC: MassMediaController = unsafe { MassMediaController::new(EMMC_BASE) }; +pub static EMMC: MassMediaController = unsafe { MassMediaController::new(EMMC_BASE) }; static UART: Pl011 = unsafe { Pl011::new(UART_BASE, UART_IRQ) }; pub(self) static BCM_MBOX: Bcm283xMailbox = unsafe { Bcm283xMailbox::new(BCM_MBOX_BASE) }; static LOCAL_TIMER: GenericTimer = GenericTimer::new(LOCAL_TIMER_IRQ); diff --git a/libcommon/src/lib.rs b/libcommon/src/lib.rs index 8757a18..961a822 100644 --- a/libcommon/src/lib.rs +++ b/libcommon/src/lib.rs @@ -30,12 +30,20 @@ pub fn path_component_left(path: &str) -> (&str, &str) { } pub fn path_component_right(path: &str) -> (&str, &str) { - if let Some((left, right)) = path.rsplit_once('/') { + if let Some((left, right)) = path.trim_end_matches('/').rsplit_once('/') { (left.trim_end_matches('/'), right) } else { - (path, "") + ("", path) } } +pub fn read_le32(src: &[u8]) -> u32 { + (src[0] as u32) | ((src[1] as u32) << 8) | ((src[2] as u32) << 16) | ((src[3] as u32) << 24) +} + +pub fn read_le16(src: &[u8]) -> u16 { + (src[0] as u16) | ((src[1] as u16) << 8) +} + #[cfg(test)] mod tests {}