diff --git a/src/sfs.rs b/src/sfs.rs index b3a9751..afd8875 100644 --- a/src/sfs.rs +++ b/src/sfs.rs @@ -17,14 +17,14 @@ pub trait Device { // Helper functions - fn read_block(&mut self, id: BlockId, offset: usize, buf: &mut [u8]) -> Result<(),()> { + fn read_block(&mut self, id: BlockId, offset: usize, buf: &mut [u8]) -> Result<(), ()> { debug_assert!(offset + buf.len() <= BLKSIZE); match self.read_at(id * BLKSIZE + offset, buf) { Some(len) if len == buf.len() => Ok(()), _ => Err(()), } } - fn write_block(&mut self, id: BlockId, offset: usize, buf: &[u8]) -> Result<(),()> { + fn write_block(&mut self, id: BlockId, offset: usize, buf: &[u8]) -> Result<(), ()> { debug_assert!(offset + buf.len() <= BLKSIZE); match self.write_at(id * BLKSIZE + offset, buf) { Some(len) if len == buf.len() => Ok(()), @@ -36,11 +36,14 @@ pub trait Device { /// Load struct `T` from given block in device /// Workaround: It should be inside the trait `Device`. But that would cause compile error. fn load_struct(device: &mut Device, id: BlockId) -> T { - let mut s: T = unsafe{ uninitialized() }; + let mut s: T = unsafe { uninitialized() }; device.read_block(id, 0, s.as_buf_mut()).unwrap(); s } +type Ptr = Rc>; +type WeakPtr = Weak>; + /// inode for sfs pub struct INode { /// on-disk inode @@ -48,7 +51,7 @@ pub struct INode { /// inode number id: INodeId, /// Weak reference to SFS, used by almost all operations - fs: Weak>, + fs: WeakPtr, } impl Debug for INode { @@ -71,10 +74,10 @@ impl INode { fs.borrow_mut().device.read_block( self.disk_inode.indirect as usize, ENTRY_SIZE * (id - NDIRECT), - disk_block_id.as_buf_mut() + disk_block_id.as_buf_mut(), ).unwrap(); Some(disk_block_id as BlockId) - }, + } id => unimplemented!("double indirect blocks is not supported"), } } @@ -99,10 +102,10 @@ impl vfs::INode for INode { // Read for each block let mut buf_offset = 0usize; - for BlockRange{block, begin, end} in iter { + for BlockRange { block, begin, end } in iter { if let Some(disk_block_id) = self.disk_block_id(block) { let len = end - begin; - fs.device.read_block(disk_block_id, begin, &mut buf[buf_offset .. buf_offset + len]); + fs.device.read_block(disk_block_id, begin, &mut buf[buf_offset..buf_offset + len]); buf_offset += len; } else { // Failed this time @@ -122,10 +125,10 @@ impl vfs::INode for INode { // Read for each block let mut buf_offset = 0usize; - for BlockRange{block, begin, end} in iter { + for BlockRange { block, begin, end } in iter { if let Some(disk_block_id) = self.disk_block_id(block) { let len = end - begin; - fs.device.write_block(disk_block_id, begin, &buf[buf_offset .. buf_offset + len]); + fs.device.write_block(disk_block_id, begin, &buf[buf_offset..buf_offset + len]); buf_offset += len; } else { // Failed this time @@ -134,6 +137,15 @@ impl vfs::INode for INode { } Some(buf_offset) } + fn info(&mut self) -> Result { + if self.disk_inode.type_ != FileType::File { + return Err(()); + } + Ok(vfs::FileInfo { + size: self.disk_inode.size as usize, + mode: 0, + }) + } fn sync(&mut self) -> Result<(), ()> { if self.disk_inode.dirty() { let fs0 = self.fs.upgrade().unwrap(); @@ -143,6 +155,9 @@ impl vfs::INode for INode { } Ok(()) } + fn type_(&self) -> Result { + Ok(self.disk_inode.type_.clone() as u32) + } } /// Given a range and iterate sub-range for each block @@ -166,9 +181,9 @@ impl Iterator for BlockIter { } let block = self.begin / BLKSIZE; let begin = self.begin % BLKSIZE; - let end = if block == self.end / BLKSIZE {self.end % BLKSIZE} else {BLKSIZE}; + let end = if block == self.end / BLKSIZE { self.end % BLKSIZE } else { BLKSIZE }; self.begin += end - begin; - Some(BlockRange {block, begin, end}) + Some(BlockRange { block, begin, end }) } } @@ -180,16 +195,16 @@ pub struct SimpleFileSystem { /// blocks in use are mared 0 free_map: BitSet, /// inode list - inodes: BTreeMap>, + inodes: BTreeMap>, /// device device: Box, /// Pointer to self, used by INodes - self_ptr: Weak>, + self_ptr: WeakPtr, } impl SimpleFileSystem { /// Create a new SFS with device - pub fn new(mut device: Box) -> Option>> { + pub fn new(mut device: Box) -> Option> { let super_block = load_struct::(device.as_mut(), BLKN_SUPER); if super_block.check() == false { return None; @@ -198,7 +213,7 @@ impl SimpleFileSystem { let mut fs = Rc::new(RefCell::new(SimpleFileSystem { super_block: Dirty::new(super_block), free_map: BitSet::new(), - inodes: BTreeMap::>::new(), + inodes: BTreeMap::>::new(), device, self_ptr: Weak::default(), })); @@ -223,17 +238,17 @@ impl SimpleFileSystem { /// Get inode by id. Load if not in memory. /// ** Must ensure it's a valid INode ** - fn get_inode(&mut self, id: INodeId) -> Rc { + fn get_inode(&mut self, id: INodeId) -> Ptr { assert!(!self.free_map.contains(id)); // Load if not in memory. if !self.inodes.contains_key(&id) { let disk_inode = load_struct::(self.device.as_mut(), id); - let inode = Rc::new(INode { + let inode = Rc::new(RefCell::new(INode { disk_inode: Dirty::new(disk_inode), id, fs: self.self_ptr.clone(), - }); + })); self.inodes.insert(id, inode.clone()); inode } else { @@ -260,7 +275,7 @@ impl vfs::FileSystem for SimpleFileSystem { Ok(()) } - fn root_inode(&mut self) -> Rc { + fn root_inode(&mut self) -> Ptr { self.get_inode(BLKN_ROOT) } @@ -280,7 +295,7 @@ trait BitsetAlloc { impl BitsetAlloc for BitSet { fn alloc(&mut self) -> Option { // TODO: more efficient - let id = (0 .. self.len()).find(|&i| self.contains(i)); + let id = (0..self.len()).find(|&i| self.contains(i)); if let Some(id) = id { self.remove(id); } diff --git a/src/structs.rs b/src/structs.rs index b24566c..867551b 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -2,9 +2,11 @@ use core::slice; use core::mem::size_of_val; +use core::fmt::{Debug, Formatter, Error}; /// On-disk superblock #[repr(C, packed)] +#[derive(Debug)] pub struct SuperBlock { /// magic number, should be SFS_MAGIC pub magic: u32, @@ -13,7 +15,7 @@ pub struct SuperBlock { /// number of unused blocks in fs pub unused_blocks: u32, /// information for sfs - pub info: [u8; MAX_INFO_LEN + 1], + pub info: Str32, } /// inode (on disk) @@ -43,11 +45,32 @@ pub struct IndirectBlock { /// file entry (on disk) #[repr(C, packed)] +#[derive(Debug)] pub struct DiskEntry { /// inode number pub id: u32, /// file name - pub name: [u8; MAX_FNAME_LEN + 1], + pub name: Str256, +} + +#[repr(C)] +pub struct Str256(pub [u8; 256]); +#[repr(C)] +pub struct Str32(pub [u8; 32]); + +impl Debug for Str256 { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + use alloc::String; + let len = self.0.iter().enumerate().find(|(i, &b)| b == 0).unwrap().0; + write!(f, "{}", String::from_utf8_lossy(&self.0[0 .. len])) + } +} +impl Debug for Str32 { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + use alloc::String; + let len = self.0.iter().enumerate().find(|(i, &b)| b == 0).unwrap().0; + write!(f, "{}", String::from_utf8_lossy(&self.0[0 .. len])) + } } impl SuperBlock { @@ -68,6 +91,7 @@ pub trait AsBuf { impl AsBuf for SuperBlock {} impl AsBuf for DiskINode {} +impl AsBuf for DiskEntry {} impl AsBuf for BlockId {} /* @@ -104,7 +128,7 @@ pub const BLK_NENTRY: usize = BLKSIZE / ENTRY_SIZE; /// file types #[repr(u16)] -#[derive(Debug)] +#[derive(Debug, Eq, PartialEq, Copy, Clone)] pub enum FileType { Invalid = 0, File = 1, Dir = 2, Link = 3, } diff --git a/src/tests.rs b/src/tests.rs index 589ec40..6190d03 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -28,6 +28,15 @@ fn test() { .expect("failed to open sfs.img"); let sfs = SimpleFileSystem::new(Box::new(file)) .expect("failed to create SFS"); - let root = sfs.borrow_mut().root_inode(); + let mut root = sfs.borrow_mut().root_inode(); println!("{:?}", root); + + use super::structs::{DiskEntry, AsBuf}; + use super::vfs::INode; + use std::mem::uninitialized; + let mut entry: DiskEntry = unsafe{uninitialized()}; + for i in 0 .. 23 { + root.borrow_mut().read_at(i * 4096, entry.as_buf_mut()); + println!("{:?}", entry); + } } \ No newline at end of file diff --git a/src/vfs.rs b/src/vfs.rs index 989f417..bb6d7ce 100644 --- a/src/vfs.rs +++ b/src/vfs.rs @@ -1,4 +1,5 @@ use alloc::rc::{Rc, Weak}; +use core::cell::RefCell; /// Abstract operations on a inode. pub trait INode { @@ -6,11 +7,11 @@ pub trait INode { fn close(&mut self) -> Result<(), ()>; fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> Option; fn write_at(&mut self, offset: usize, buf: &[u8]) -> Option; -// fn fstat(&mut self, buf: &[u8]) -> Result<(), ()>; + fn info(&mut self) -> Result; fn sync(&mut self) -> Result<(), ()>; // fn name_file(&mut self) -> Result<(), ()>; // fn reclaim(&mut self) -> Result<(), ()>; -// fn get_type(&mut self) -> Result; + fn type_(&self) -> Result; // fn try_seek(&mut self, offset: u64) -> Result<(), ()>; // fn truncate(&mut self, len: u64) -> Result<(), ()>; // fn create(&mut self, name: &'static str, excl: bool) -> Result<(), ()>; @@ -18,11 +19,16 @@ pub trait INode { // fn io_ctrl(&mut self, op: u32, data: &[u8]) -> Result<(), ()>; } +pub struct FileInfo { + pub size: usize, + pub mode: u32, +} + /// Abstract filesystem pub trait FileSystem { type INode: INode; fn sync(&mut self) -> Result<(), ()>; - fn root_inode(&mut self) -> Rc; + fn root_inode(&mut self) -> Rc>; fn unmount(&mut self) -> Result<(), ()>; fn cleanup(&mut self); } \ No newline at end of file