diff --git a/src/dirty.rs b/src/dirty.rs index 6dea50e..f73601f 100644 --- a/src/dirty.rs +++ b/src/dirty.rs @@ -1,4 +1,5 @@ use core::ops::{Deref, DerefMut}; +use core::fmt::{Debug, Formatter, Error}; /// Dirty wraps a value of type T with functions similiar to that of a Read/Write /// lock but simply sets a dirty flag on write(), reset on read() @@ -60,3 +61,10 @@ impl Drop for Dirty { } } +impl Debug for Dirty { + fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { + let tag = if self.dirty {"Dirty"} else {"Clean"}; + write!(f, "[{}] {:?}", tag, self.value) + } +} + diff --git a/src/sfs.rs b/src/sfs.rs index 83a2c1f..adb4055 100644 --- a/src/sfs.rs +++ b/src/sfs.rs @@ -44,7 +44,6 @@ trait DeviceExt: Device { impl DeviceExt for Device {} type Ptr = Rc>; -type WeakPtr = Weak>; /// inode for sfs pub struct INode { @@ -58,7 +57,7 @@ pub struct INode { impl Debug for INode { fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { - write!(f, "{:?}", *self.disk_inode) + write!(f, "INode {{ id: {}, disk: {:?} }}", self.id, self.disk_inode) } } @@ -105,7 +104,7 @@ impl INode { } } /// Only for Dir - fn get_file_inode_id(&mut self, name: &'static str) -> Option { + fn get_file_inode_id(&self, name: &'static str) -> Option { (0 .. self.disk_inode.blocks) .map(|i| { use vfs::INode; @@ -153,7 +152,7 @@ impl vfs::INode for INode { fn close(&mut self) -> vfs::Result<()> { self.sync() } - fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> vfs::Result { + fn read_at(&self, offset: usize, buf: &mut [u8]) -> vfs::Result { let fs = self.fs.upgrade().unwrap(); let iter = BlockIter { @@ -171,7 +170,7 @@ impl vfs::INode for INode { } Ok(buf_offset) } - fn write_at(&mut self, offset: usize, buf: &[u8]) -> vfs::Result { + fn write_at(&self, offset: usize, buf: &[u8]) -> vfs::Result { let fs = self.fs.upgrade().unwrap(); let iter = BlockIter { @@ -189,7 +188,7 @@ impl vfs::INode for INode { } Ok(buf_offset) } - fn info(&mut self) -> vfs::Result { + fn info(&self) -> vfs::Result { Ok(vfs::FileInfo { size: self.disk_inode.size as usize, mode: 0, @@ -269,7 +268,7 @@ impl vfs::INode for INode { Ok(inode) } - fn loopup(&mut self, path: &'static str) -> vfs::Result> { + fn lookup(&self, path: &'static str) -> vfs::Result> { let fs = self.fs.upgrade().unwrap(); let info = self.info().unwrap(); assert_eq!(info.type_, vfs::FileType::Dir); @@ -288,7 +287,7 @@ impl vfs::INode for INode { let type_ = inode.borrow().disk_inode.type_; match type_ { FileType::File => if rest_path == "" {Ok(inode)} else {Err(())}, - FileType::Dir => inode.borrow_mut().loopup(rest_path), + FileType::Dir => inode.borrow_mut().lookup(rest_path), _ => unimplemented!(), } } @@ -441,46 +440,43 @@ impl SimpleFileSystem { self.super_block.borrow_mut().unused_blocks += 1; } + /// Create a new INode struct, then insert it to self.inodes + /// Private used for load or create INode + fn _new_inode(&self, id: INodeId, disk_inode: Dirty) -> Ptr { + let inode = Rc::new(RefCell::new(INode { + disk_inode, + id, + fs: self.self_ptr.clone(), + })); + self.inodes.borrow_mut().insert(id, inode.clone()); + inode + } /// Get inode by id. Load if not in memory. /// ** Must ensure it's a valid INode ** fn get_inode(&self, id: INodeId) -> Ptr { assert!(!self.free_map.borrow().contains(id)); - let mut inodes = self.inodes.borrow_mut(); // Load if not in memory. - if !inodes.contains_key(&id) { - let disk_inode = self.device.borrow_mut().load_struct::(id); - let inode = Rc::new(RefCell::new(INode { - disk_inode: Dirty::new(disk_inode), - id, - fs: self.self_ptr.clone(), - })); - inodes.insert(id, inode.clone()); - inode + if !self.inodes.borrow().contains_key(&id) { + let disk_inode = Dirty::new(self.device.borrow_mut().load_struct::(id)); + self._new_inode(id, disk_inode) } else { - inodes.get(&id).unwrap().clone() + self.inodes.borrow_mut().get(&id).unwrap().clone() } } /// Create a new INode file fn new_inode_file(&self) -> vfs::Result> { let id = self.alloc_block().unwrap(); - Ok(Rc::new(RefCell::new(INode { - disk_inode: Dirty::new_dirty(DiskINode::new_file()), - id, - fs: self.self_ptr.clone(), - }))) + let disk_inode = Dirty::new_dirty(DiskINode::new_file()); + Ok(self._new_inode(id, disk_inode)) } /// Create a new INode dir fn new_inode_dir(&self, parent: INodeId) -> vfs::Result> { let id = self.alloc_block().unwrap(); - let mut inode = INode { - disk_inode: Dirty::new_dirty(DiskINode::new_dir()), - id, - fs: self.self_ptr.clone(), - }; - inode.init_dir(parent).unwrap(); - - Ok(Rc::new(RefCell::new(inode))) + let disk_inode = Dirty::new_dirty(DiskINode::new_dir()); + let inode = self._new_inode(id, disk_inode); + inode.borrow_mut().init_dir(parent).unwrap(); + Ok(inode) } } diff --git a/src/tests.rs b/src/tests.rs index fe9b131..39fff5c 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -4,6 +4,7 @@ use std::boxed::Box; use super::sfs::*; use super::vfs::*; use super::vfs::INode; +use std::rc::Rc; impl Device for File { fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> Option { @@ -23,14 +24,35 @@ impl Device for File { } } -#[test] -fn test() { +fn _open_sample_file() -> Rc { let file = File::open("sfs.img") .expect("failed to open sfs.img"); - let sfs = SimpleFileSystem::open(Box::new(file)) - .expect("failed to create SFS"); + SimpleFileSystem::open(Box::new(file)) + .expect("failed to open SFS") +} + +fn _create_new_sfs() -> Rc { + let file = OpenOptions::new() + .read(true).write(true).create(true).open("test.img") + .expect("failed to create file"); + SimpleFileSystem::create(Box::new(file), 16 * 4096) +} + +#[test] +fn open_sample_file() { + _open_sample_file(); +} + +#[test] +fn create_new_sfs() { + _create_new_sfs(); +} + +#[test] +fn print_root() { + let sfs = _open_sample_file(); let root = sfs.root_inode(); - println!("{:?}", root); + println!("{:?}", root.borrow()); use super::structs::{DiskEntry, AsBuf}; use std::mem::uninitialized; @@ -42,12 +64,28 @@ fn test() { } #[test] -fn create() { - let file = OpenOptions::new() - .read(true).write(true).create(true).open("test.img") - .expect("failed to create file"); - let sfs = SimpleFileSystem::create(Box::new(file), 16 * 4096); +fn create_file() { + let sfs = _create_new_sfs(); + let root = sfs.root_inode(); + let file1 = root.borrow_mut().create("file1").unwrap(); + + assert_eq!(file1.borrow().info().unwrap(), FileInfo { + size: 0, + type_: FileType::File, + mode: 0, + }); + + sfs.sync().unwrap(); +} + +#[test] +fn lookup() { + let sfs = _create_new_sfs(); let root = sfs.root_inode(); let file1 = root.borrow_mut().create("file1").unwrap(); + let found = root.borrow().lookup("file1").expect("lookup not found"); + println!("{:?}", found.borrow()); + println!("{:?}", file1.borrow()); + assert!(Rc::ptr_eq(&found, &file1), "found wrong INode"); sfs.sync().unwrap(); } \ No newline at end of file diff --git a/src/vfs.rs b/src/vfs.rs index ebf6746..d5cf004 100644 --- a/src/vfs.rs +++ b/src/vfs.rs @@ -2,25 +2,26 @@ use alloc::rc::{Rc, Weak}; use core::cell::RefCell; use core::mem::size_of; use core; +use core::fmt::Debug; /// Abstract operations on a inode. -pub trait INode { +pub trait INode: Debug { fn open(&mut self, flags: u32) -> Result<()>; fn close(&mut self) -> Result<()>; - fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> Result; - fn write_at(&mut self, offset: usize, buf: &[u8]) -> Result; - fn info(&mut self) -> Result; + fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result; + fn write_at(&self, offset: usize, buf: &[u8]) -> Result; + fn info(&self) -> Result; fn sync(&mut self) -> Result<()>; // fn name_file(&mut self) -> Result<()>; // fn reclaim(&mut self) -> Result<()>; // fn try_seek(&mut self, offset: u64) -> Result<()>; fn resize(&mut self, len: usize) -> Result<()>; fn create(&mut self, name: &'static str) -> Result>>; - fn loopup(&mut self, path: &'static str) -> Result>>; + fn lookup(&self, path: &'static str) -> Result>>; // fn io_ctrl(&mut self, op: u32, data: &[u8]) -> Result<()>; } -#[derive(Debug)] +#[derive(Debug, Eq, PartialEq)] pub struct FileInfo { pub size: usize, pub mode: u32,