diff --git a/src/sfs.rs b/src/sfs.rs index efd0dad..4c4d5f2 100644 --- a/src/sfs.rs +++ b/src/sfs.rs @@ -4,6 +4,7 @@ use core::cell::{RefCell, RefMut}; use core::mem::{uninitialized, size_of}; use core::slice; use core::fmt::{Debug, Formatter, Error}; +use core::any::Any; use dirty::Dirty; use structs::*; use vfs::{self, Device}; @@ -354,6 +355,25 @@ impl vfs::INode for INode { Ok(()) } + fn link(&mut self, name: &str, other:&mut vfs::INode) -> vfs::Result<()> { + let fs = self.fs.upgrade().unwrap(); + let info = self.info().unwrap(); + assert_eq!(info.type_, vfs::FileType::Dir); + assert!(info.nlinks>0); + assert!(self.get_file_inode_id(name).is_none(), "file name exist"); + let child = other.downcast_mut::().unwrap(); + assert!(Rc::ptr_eq(&fs,&child.fs.upgrade().unwrap())); + assert!(child.info().unwrap().type_!=vfs::FileType::Dir); + let entry = DiskEntry { + id: child.id as u32, + name: Str256::from(name), + }; + let old_size=self._size(); + self._resize(old_size + BLKSIZE).unwrap(); + self._write_at(old_size, entry.as_buf()).unwrap(); + child.nlinks_inc(); + Ok(()) + } fn lookup(&self, path: &str) -> vfs::Result> { let fs = self.fs.upgrade().unwrap(); let info = self.info().unwrap(); @@ -390,6 +410,12 @@ impl vfs::INode for INode { fn fs(&self) -> Weak { self.fs.clone() } + fn as_any_ref(&self) -> &Any { + self + } + fn as_any_mut(&mut self) -> &mut Any { + self + } } impl Drop for INode { diff --git a/src/tests.rs b/src/tests.rs index c550f2d..f2ac9f6 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -181,6 +181,21 @@ fn kernel_image_file_unlink(){ sfs.sync().unwrap(); } + +#[test] +fn hard_link(){ + let sfs = _create_new_sfs(); + let root = sfs.root_inode(); + let file1 = root.borrow_mut().create("file1", FileType::File).unwrap(); + use core::ops::DerefMut; + root.borrow_mut().link("file2",file1.borrow_mut().deref_mut()).unwrap(); + let file2 = root.borrow_mut().lookup("file2").unwrap(); + file1.borrow_mut().resize(100); + assert_eq!(file2.borrow().info().unwrap().size,100); + + sfs.sync().unwrap(); +} + #[test] fn nlinks(){ let sfs = _create_new_sfs(); @@ -192,8 +207,17 @@ fn nlinks(){ let dir1 = root.borrow_mut().create("dir1", FileType::Dir).unwrap(); assert_eq!(dir1.borrow().info().unwrap().nlinks,2); assert_eq!(root.borrow().info().unwrap().nlinks,3); + use core::ops::DerefMut; + dir1.borrow_mut().link("file2",file1.borrow_mut().deref_mut()).unwrap(); + assert_eq!(dir1.borrow().info().unwrap().nlinks,2); + assert_eq!(root.borrow().info().unwrap().nlinks,3); + assert_eq!(file1.borrow().info().unwrap().nlinks,2); root.borrow_mut().unlink("file1").unwrap(); + assert_eq!(file1.borrow().info().unwrap().nlinks,1); + assert_eq!(root.borrow().info().unwrap().nlinks,3); + dir1.borrow_mut().unlink("file2").unwrap(); assert_eq!(file1.borrow().info().unwrap().nlinks,0); + assert_eq!(dir1.borrow().info().unwrap().nlinks,2); assert_eq!(root.borrow().info().unwrap().nlinks,3); root.borrow_mut().unlink("dir1").unwrap(); assert_eq!(dir1.borrow().info().unwrap().nlinks,0); diff --git a/src/vfs.rs b/src/vfs.rs index 1b5396c..84e7f9d 100644 --- a/src/vfs.rs +++ b/src/vfs.rs @@ -3,6 +3,7 @@ use core::cell::RefCell; use core::mem::size_of; use core; use core::fmt::Debug; +use core::any::Any; /// Interface for FS to read & write /// TODO: use std::io::{Read, Write} @@ -12,7 +13,7 @@ pub trait Device { } /// Abstract operations on a inode. -pub trait INode: Debug { +pub trait INode: Debug + Any { fn open(&mut self, flags: u32) -> Result<()>; fn close(&mut self) -> Result<()>; fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result; @@ -23,12 +24,28 @@ pub trait INode: Debug { // fn reclaim(&mut self) -> Result<()>; fn resize(&mut self, len: usize) -> Result<()>; fn create(&mut self, name: &str, type_: FileType) -> Result; - // since we do not have link, unlink==remove fn unlink(&mut self, name: &str) -> Result<()>; + /// user of the vfs api should call borrow_mut by itself + fn link(&mut self, name: &str, other:&mut INode) -> Result<()>; fn lookup(&self, path: &str) -> Result; fn list(&self) -> Result>; // fn io_ctrl(&mut self, op: u32, data: &[u8]) -> Result<()>; fn fs(&self) -> Weak; + /// this is used to implement dynamics cast + /// simply return self in the implement of the function + fn as_any_ref(&self) -> &Any; + /// this is used to implement dynamics cast + /// simply return self in the implement of the function + fn as_any_mut(&mut self) -> &mut Any; +} + +impl INode{ + pub fn downcast_ref(&self) -> Option<&T> { + self.as_any_ref().downcast_ref::() + } + pub fn downcast_mut(&mut self) -> Option<&mut T> { + self.as_any_mut().downcast_mut::() + } } #[derive(Debug, Eq, PartialEq)]