remove warning+add FsError, pt4

master
Ben Pig Chu 6 years ago
parent c194e34582
commit f2fa73b28a

@ -26,10 +26,9 @@ impl Device {
} }
} }
/// Load struct `T` from given block in device /// Load struct `T` from given block in device
fn load_struct<T: AsBuf>(&mut self, id: BlockId) -> T { fn load_struct<T: AsBuf>(&mut self, id: BlockId) -> vfs::Result<T> {
let mut s: T = unsafe { uninitialized() }; let mut s: T = unsafe { uninitialized() };
self.read_block(id, 0, s.as_buf_mut()).unwrap(); self.read_block(id, 0, s.as_buf_mut()).map(|_|{s})
s
} }
} }
@ -122,7 +121,7 @@ impl INodeImpl {
/// remove a page in middle of file and insert the last page here, useful for dirent remove /// remove a page in middle of file and insert the last page here, useful for dirent remove
/// should be only used in unlink /// should be only used in unlink
fn remove_dirent_page(&self, id: usize) -> vfs::Result<()> { fn remove_dirent_page(&self, id: usize) -> vfs::Result<()> {
assert!(id < self.disk_inode.read().blocks as usize); debug_assert!(id < self.disk_inode.read().blocks as usize);
let to_remove = self.get_disk_block_id(id)?; let to_remove = self.get_disk_block_id(id)?;
let current_last = self.get_disk_block_id(self.disk_inode.read().blocks as usize - 1)?; let current_last = self.get_disk_block_id(self.disk_inode.read().blocks as usize - 1)?;
self.set_disk_block_id(id, current_last)?; self.set_disk_block_id(id, current_last)?;
@ -199,6 +198,7 @@ impl INodeImpl {
_ => panic!("Unknown file type"), _ => panic!("Unknown file type"),
} as u32 } as u32
} }
// Note: the _\w*_at method always return begin>size?0:begin<end?0:(min(size,end)-begin) when success
/// Read/Write content, no matter what type it is /// Read/Write content, no matter what type it is
fn _io_at<F>(&self, begin: usize, end: usize, mut f: F) -> vfs::Result<usize> fn _io_at<F>(&self, begin: usize, end: usize, mut f: F) -> vfs::Result<usize>
where F: FnMut(&mut Box<Device>, &BlockRange, usize) -> vfs::Result<()> where F: FnMut(&mut Box<Device>, &BlockRange, usize) -> vfs::Result<()>
@ -232,13 +232,11 @@ impl INodeImpl {
}) })
} }
/// Clean content, no matter what type it is /// Clean content, no matter what type it is
fn _clean_at(&self, begin: usize, end: usize) -> vfs::Result<()> { fn _clean_at(&self, begin: usize, end: usize) -> vfs::Result<usize> {
static ZEROS: [u8; BLKSIZE] = [0; BLKSIZE]; static ZEROS: [u8; BLKSIZE] = [0; BLKSIZE];
let size = self._io_at(begin, end, |device, range, _| { self._io_at(begin, end, |device, range, _| {
device.write_block(range.block, range.begin, &ZEROS[..range.len()]) device.write_block(range.block, range.begin, &ZEROS[..range.len()])
})?; })
assert_eq!(size, end - begin);
Ok(())
} }
fn nlinks_inc(&self) { fn nlinks_inc(&self) {
self.disk_inode.write().nlinks += 1; self.disk_inode.write().nlinks += 1;
@ -297,7 +295,9 @@ impl vfs::INode for INodeImpl {
if info.type_!=vfs::FileType::Dir { if info.type_!=vfs::FileType::Dir {
return Err(FsError::NotDir); return Err(FsError::NotDir);
} }
assert!(info.nlinks > 0); if info.nlinks <= 0 {
return Err(FsError::DirRemoved)
}
// Ensure the name is not exist // Ensure the name is not exist
if !self.get_file_inode_id(name).is_none() { if !self.get_file_inode_id(name).is_none() {
@ -331,6 +331,9 @@ impl vfs::INode for INodeImpl {
if info.type_!=vfs::FileType::Dir { if info.type_!=vfs::FileType::Dir {
return Err(FsError::NotDir) return Err(FsError::NotDir)
} }
if info.nlinks <= 0 {
return Err(FsError::DirRemoved)
}
if name == "." { if name == "." {
return Err(FsError::IsDir) return Err(FsError::IsDir)
} }
@ -344,7 +347,10 @@ impl vfs::INode for INodeImpl {
let type_ = inode.disk_inode.read().type_; let type_ = inode.disk_inode.read().type_;
if type_ == FileType::Dir { if type_ == FileType::Dir {
// only . and .. // only . and ..
assert_eq!(inode.disk_inode.read().blocks, 2); assert!(inode.disk_inode.read().blocks >= 2);
if inode.disk_inode.read().blocks > 2 {
return Err(FsError::DirNotEmpty)
}
} }
inode.nlinks_dec(); inode.nlinks_dec();
if type_ == FileType::Dir { if type_ == FileType::Dir {
@ -360,7 +366,9 @@ impl vfs::INode for INodeImpl {
if info.type_!=vfs::FileType::Dir { if info.type_!=vfs::FileType::Dir {
return Err(FsError::NotDir) return Err(FsError::NotDir)
} }
assert!(info.nlinks > 0); if info.nlinks <= 0 {
return Err(FsError::DirRemoved)
}
if !self.get_file_inode_id(name).is_none() { if !self.get_file_inode_id(name).is_none() {
return Err(FsError::EntryExist); return Err(FsError::EntryExist);
} }
@ -386,7 +394,15 @@ impl vfs::INode for INodeImpl {
if info.type_!=vfs::FileType::Dir { if info.type_!=vfs::FileType::Dir {
return Err(FsError::NotDir) return Err(FsError::NotDir)
} }
assert!(info.nlinks > 0); if info.nlinks <= 0 {
return Err(FsError::DirRemoved)
}
if old_name == "." {
return Err(FsError::IsDir)
}
if old_name == ".." {
return Err(FsError::IsDir)
}
if !self.get_file_inode_id(new_name).is_none() { if !self.get_file_inode_id(new_name).is_none() {
return Err(FsError::EntryExist); return Err(FsError::EntryExist);
@ -408,7 +424,16 @@ impl vfs::INode for INodeImpl {
if info.type_!=vfs::FileType::Dir { if info.type_!=vfs::FileType::Dir {
return Err(FsError::NotDir) return Err(FsError::NotDir)
} }
assert!(info.nlinks > 0); if info.nlinks <= 0 {
return Err(FsError::DirRemoved)
}
if old_name == "." {
return Err(FsError::IsDir)
}
if old_name == ".." {
return Err(FsError::IsDir)
}
let dest = target.downcast_ref::<INodeImpl>().ok_or(FsError::NotSameFs)?; let dest = target.downcast_ref::<INodeImpl>().ok_or(FsError::NotSameFs)?;
if !Arc::ptr_eq(&self.fs, &dest.fs) { if !Arc::ptr_eq(&self.fs, &dest.fs) {
return Err(FsError::NotSameFs); return Err(FsError::NotSameFs);
@ -416,7 +441,9 @@ impl vfs::INode for INodeImpl {
if dest.info()?.type_ != vfs::FileType::Dir { if dest.info()?.type_ != vfs::FileType::Dir {
return Err(FsError::NotDir) return Err(FsError::NotDir)
} }
assert!(dest.info()?.nlinks > 0); if dest.info()?.nlinks <= 0 {
return Err(FsError::DirRemoved)
}
if !self.get_file_inode_id(new_name).is_none() { if !self.get_file_inode_id(new_name).is_none() {
return Err(FsError::EntryExist); return Err(FsError::EntryExist);
@ -472,7 +499,7 @@ impl vfs::INode for INodeImpl {
impl Drop for INodeImpl { impl Drop for INodeImpl {
/// Auto sync when drop /// Auto sync when drop
fn drop(&mut self) { fn drop(&mut self) {
self.sync().expect("failed to sync"); self.sync().expect("Failed to sync when dropping the SimpleFileSystem Inode");
if self.disk_inode.read().nlinks <= 0 { if self.disk_inode.read().nlinks <= 0 {
self._resize(0).unwrap(); self._resize(0).unwrap();
self.disk_inode.write().sync(); self.disk_inode.write().sync();
@ -504,9 +531,11 @@ pub struct SimpleFileSystem {
impl SimpleFileSystem { impl SimpleFileSystem {
/// Load SFS from device /// Load SFS from device
pub fn open(mut device: Box<Device>) -> vfs::Result<Arc<Self>> { pub fn open(mut device: Box<Device>) -> vfs::Result<Arc<Self>> {
let super_block = device.load_struct::<SuperBlock>(BLKN_SUPER); let super_block = device.load_struct::<SuperBlock>(BLKN_SUPER).unwrap();
assert!(super_block.check(), "not a valid SFS"); if !super_block.check() {
let free_map = device.load_struct::<[u8; BLKSIZE]>(BLKN_FREEMAP); return Err(FsError::WrongFs);
}
let free_map = device.load_struct::<[u8; BLKSIZE]>(BLKN_FREEMAP).unwrap();
Ok(SimpleFileSystem { Ok(SimpleFileSystem {
super_block: RwLock::new(Dirty::new(super_block)), super_block: RwLock::new(Dirty::new(super_block)),
@ -574,7 +603,7 @@ impl SimpleFileSystem {
free_map.set(block_id, true); free_map.set(block_id, true);
return None return None
} }
super_block.unused_blocks -= 1; // will panic if underflow super_block.unused_blocks -= 1; // will not underflow
} }
id id
} }
@ -609,7 +638,7 @@ impl SimpleFileSystem {
} }
} }
// Load if not in set, or is weak ref. // Load if not in set, or is weak ref.
let disk_inode = Dirty::new(self.device.lock().load_struct::<DiskINode>(id)); let disk_inode = Dirty::new(self.device.lock().load_struct::<DiskINode>(id).unwrap());
self._new_inode(id, disk_inode) self._new_inode(id, disk_inode)
} }
/// Create a new INode file /// Create a new INode file
@ -675,7 +704,7 @@ impl Drop for SimpleFileSystem {
/// Auto sync when drop /// Auto sync when drop
fn drop(&mut self) { fn drop(&mut self) {
use vfs::FileSystem; use vfs::FileSystem;
self.sync().expect("failed to sync"); self.sync().expect("Failed to sync when dropping the SimpleFileSystem");
} }
} }

@ -10,7 +10,7 @@ pub trait Device: Send {
fn write_at(&mut self, offset: usize, buf: &[u8]) -> Option<usize>; fn write_at(&mut self, offset: usize, buf: &[u8]) -> Option<usize>;
} }
/// Abstract operations on a inode. /// Abstract operations on a inode.
pub trait INode: Debug + Any + Sync + Send { pub trait INode: Debug + Any + Sync + Send {
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize>; fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize>;
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize>; fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize>;
@ -45,9 +45,9 @@ impl INode {
if info.type_ != FileType::Dir { if info.type_ != FileType::Dir {
return Err(FsError::NotDir); return Err(FsError::NotDir);
} }
Ok((0..info.size).map(|i| { (0..info.size).map(|i| {
self.get_entry(i).unwrap() self.get_entry(i)
}).collect()) }).collect()
} }
pub fn lookup(&self, path: &str) -> Result<Arc<INode>> { pub fn lookup(&self, path: &str) -> Result<Arc<INode>> {
if self.info()?.type_ != FileType::Dir { if self.info()?.type_ != FileType::Dir {
@ -103,10 +103,11 @@ pub struct FsInfo {
pub max_file_size: usize, pub max_file_size: usize,
} }
// Note: IOError/NoMemory always lead to a panic since it's hard to recover from it.
// We also panic when we can not parse the fs on disk normally
#[derive(Debug)] #[derive(Debug)]
pub enum FsError { pub enum FsError {
NotSupported,//E_UNIMP NotSupported,//E_UNIMP, or E_INVAL
NotFile,//E_ISDIR NotFile,//E_ISDIR
IsDir,//E_ISDIR, used only in link IsDir,//E_ISDIR, used only in link
NotDir,//E_NOTDIR NotDir,//E_NOTDIR
@ -115,12 +116,14 @@ pub enum FsError {
NotSameFs,//E_XDEV NotSameFs,//E_XDEV
InvalidParam,//E_INVAL InvalidParam,//E_INVAL
NoDeviceSpace,//E_NOSPC, but is defined and not used in the original ucore, which uses E_NO_MEM NoDeviceSpace,//E_NOSPC, but is defined and not used in the original ucore, which uses E_NO_MEM
//and something else DirRemoved,//E_NOENT, when the current dir was remove by a previous unlink
DirNotEmpty,//E_NOTEMPTY
WrongFs,//E_INVAL, when we find the content on disk is wrong when opening the device
} }
pub type Result<T> = result::Result<T,FsError>; pub type Result<T> = result::Result<T,FsError>;
/// Abstract filesystem /// Abstract filesystem
pub trait FileSystem: Sync { pub trait FileSystem: Sync {
fn sync(&self) -> Result<()>; fn sync(&self) -> Result<()>;
fn root_inode(&self) -> Arc<INode>; fn root_inode(&self) -> Arc<INode>;

Loading…
Cancel
Save