make the fs not that panicful

master
Ben Pig Chu 6 years ago
parent 978c3a70ca
commit e7b39bbb41

@ -6,7 +6,7 @@ use core::fmt::{Debug, Formatter, Error};
use core::any::Any; use core::any::Any;
use dirty::Dirty; use dirty::Dirty;
use structs::*; use structs::*;
use vfs::{self, Device, INode, FileSystem}; use vfs::{self, Device, INode, FileSystem, FsError};
use util::*; use util::*;
use spin::{Mutex, RwLock}; use spin::{Mutex, RwLock};
@ -249,11 +249,15 @@ impl INodeImpl {
impl vfs::INode for INodeImpl { impl vfs::INode for INodeImpl {
fn read_at(&self, offset: usize, buf: &mut [u8]) -> vfs::Result<usize> { fn read_at(&self, offset: usize, buf: &mut [u8]) -> vfs::Result<usize> {
assert_eq!(self.disk_inode.read().type_, FileType::File, "read_at is only available on file"); if(self.disk_inode.read().type_!=FileType::File){
return Err(FsError::NotFile);
}
self._read_at(offset, buf) self._read_at(offset, buf)
} }
fn write_at(&self, offset: usize, buf: &[u8]) -> vfs::Result<usize> { fn write_at(&self, offset: usize, buf: &[u8]) -> vfs::Result<usize> {
assert_eq!(self.disk_inode.read().type_, FileType::File, "write_at is only available on file"); if(self.disk_inode.read().type_!=FileType::File){
return Err(FsError::NotFile);
}
self._write_at(offset, buf) self._write_at(offset, buf)
} }
/// the size returned here is logical size(entry num for directory), not the disk space used. /// the size returned here is logical size(entry num for directory), not the disk space used.
@ -280,16 +284,22 @@ impl vfs::INode for INodeImpl {
Ok(()) Ok(())
} }
fn resize(&self, len: usize) -> vfs::Result<()> { fn resize(&self, len: usize) -> vfs::Result<()> {
assert_eq!(self.disk_inode.read().type_, FileType::File, "resize is only available on file"); if(self.disk_inode.read().type_!=FileType::File){
return Err(FsError::NotFile);
}
self._resize(len) self._resize(len)
} }
fn create(&self, name: &str, type_: vfs::FileType) -> vfs::Result<Arc<vfs::INode>> { fn create(&self, name: &str, type_: vfs::FileType) -> vfs::Result<Arc<vfs::INode>> {
let info = self.info()?; let info = self.info()?;
assert_eq!(info.type_, vfs::FileType::Dir); if(info.type_!=vfs::FileType::Dir){
return Err(FsError::NotDir);
}
assert!(info.nlinks > 0); assert!(info.nlinks > 0);
// Ensure the name is not exist // Ensure the name is not exist
assert!(self.get_file_inode_id(name).is_none(), "file name exist"); if(!self.get_file_inode_id(name).is_none()){
return Err(FsError::EntryExist);
}
// Create new INode // Create new INode
let inode = match type_ { let inode = match type_ {
@ -314,12 +324,14 @@ impl vfs::INode for INodeImpl {
Ok(inode) Ok(inode)
} }
fn unlink(&self, name: &str) -> vfs::Result<()> { fn unlink(&self, name: &str) -> vfs::Result<()> {
let info = self.info()?;
if(info.type_!=vfs::FileType::Dir){
return Err(FsError::NotDir)
}
assert!(name != "."); assert!(name != ".");
assert!(name != ".."); assert!(name != "..");
let info = self.info()?;
assert_eq!(info.type_, vfs::FileType::Dir);
let (inode_id, entry_id) = self.get_file_inode_and_entry_id(name).ok_or(())?; let (inode_id, entry_id) = self.get_file_inode_and_entry_id(name).ok_or(FsError::EntryNotFound)?;
let inode = self.fs.get_inode(inode_id); let inode = self.fs.get_inode(inode_id);
let type_ = inode.disk_inode.read().type_; let type_ = inode.disk_inode.read().type_;
@ -338,12 +350,20 @@ impl vfs::INode for INodeImpl {
} }
fn link(&self, name: &str, other: &Arc<INode>) -> vfs::Result<()> { fn link(&self, name: &str, other: &Arc<INode>) -> vfs::Result<()> {
let info = self.info()?; let info = self.info()?;
assert_eq!(info.type_, vfs::FileType::Dir); if(info.type_!=vfs::FileType::Dir){
return Err(FsError::NotDir)
}
assert!(info.nlinks > 0); assert!(info.nlinks > 0);
assert!(self.get_file_inode_id(name).is_none(), "file name exist"); if(!self.get_file_inode_id(name).is_none()){
let child = other.downcast_ref::<INodeImpl>().unwrap(); return Err(FsError::EntryExist);
assert!(Arc::ptr_eq(&self.fs, &child.fs)); }
assert!(child.info()?.type_ != vfs::FileType::Dir); let child = other.downcast_ref::<INodeImpl>().ok_or(FsError::NotSameFs)?;
if(!Arc::ptr_eq(&self.fs, &child.fs)){
return Err(FsError::NotSameFs);
}
if(child.info()?.type_ == vfs::FileType::Dir){
return Err(FsError::IsDir);
}
let entry = DiskEntry { let entry = DiskEntry {
id: child.id as u32, id: child.id as u32,
name: Str256::from(name), name: Str256::from(name),
@ -356,12 +376,16 @@ impl vfs::INode for INodeImpl {
} }
fn rename(&self, old_name: &str, new_name: &str) -> vfs::Result<()> { fn rename(&self, old_name: &str, new_name: &str) -> vfs::Result<()> {
let info = self.info()?; let info = self.info()?;
assert_eq!(info.type_, vfs::FileType::Dir); if(info.type_!=vfs::FileType::Dir){
return Err(FsError::NotDir)
}
assert!(info.nlinks > 0); assert!(info.nlinks > 0);
assert!(self.get_file_inode_id(new_name).is_none(), "file name exist"); if(!self.get_file_inode_id(new_name).is_none()){
return Err(FsError::EntryExist);
}
let (_, entry_id) = self.get_file_inode_and_entry_id(old_name).ok_or(())?; let (_, entry_id) = self.get_file_inode_and_entry_id(old_name).ok_or(FsError::EntryNotFound)?;
// in place modify name // in place modify name
let mut entry: DiskEntry = unsafe { uninitialized() }; let mut entry: DiskEntry = unsafe { uninitialized() };
@ -374,16 +398,24 @@ impl vfs::INode for INodeImpl {
} }
fn move_(&self, old_name: &str, target: &Arc<INode>, new_name: &str) -> vfs::Result<()> { fn move_(&self, old_name: &str, target: &Arc<INode>, new_name: &str) -> vfs::Result<()> {
let info = self.info()?; let info = self.info()?;
assert_eq!(info.type_, vfs::FileType::Dir); if(info.type_!=vfs::FileType::Dir){
return Err(FsError::NotDir)
}
assert!(info.nlinks > 0); assert!(info.nlinks > 0);
let dest = target.downcast_ref::<INodeImpl>().unwrap(); let dest = target.downcast_ref::<INodeImpl>().ok_or(FsError::NotSameFs)?;
assert!(Arc::ptr_eq(&self.fs, &dest.fs)); if(!Arc::ptr_eq(&self.fs, &dest.fs)){
assert!(dest.info()?.type_ == vfs::FileType::Dir); return Err(FsError::NotSameFs);
}
if(dest.info()?.type_ != vfs::FileType::Dir){
return Err(FsError::NotDir)
}
assert!(dest.info()?.nlinks > 0); assert!(dest.info()?.nlinks > 0);
assert!(dest.get_file_inode_id(new_name).is_none(), "file name exist"); if(!self.get_file_inode_id(new_name).is_none()){
return Err(FsError::EntryExist);
}
let (inode_id, entry_id) = self.get_file_inode_and_entry_id(old_name).ok_or(())?; let (inode_id, entry_id) = self.get_file_inode_and_entry_id(old_name).ok_or(FsError::EntryNotFound)?;
let inode = self.fs.get_inode(inode_id); let inode = self.fs.get_inode(inode_id);
let entry = DiskEntry { let entry = DiskEntry {
@ -405,12 +437,16 @@ impl vfs::INode for INodeImpl {
} }
fn find(&self, name: &str) -> vfs::Result<Arc<vfs::INode>> { fn find(&self, name: &str) -> vfs::Result<Arc<vfs::INode>> {
let info = self.info()?; let info = self.info()?;
assert_eq!(info.type_, vfs::FileType::Dir); if(info.type_!=vfs::FileType::Dir){
let inode_id = self.get_file_inode_id(name).ok_or(())?; return Err(FsError::NotDir)
}
let inode_id = self.get_file_inode_id(name).ok_or(FsError::EntryNotFound)?;
Ok(self.fs.get_inode(inode_id)) Ok(self.fs.get_inode(inode_id))
} }
fn get_entry(&self, id: usize) -> vfs::Result<String> { fn get_entry(&self, id: usize) -> vfs::Result<String> {
assert_eq!(self.disk_inode.read().type_, FileType::Dir); if(self.disk_inode.read().type_!=FileType::Dir){
return Err(FsError::NotDir)
}
assert!(id < self.disk_inode.read().blocks as usize); assert!(id < self.disk_inode.read().blocks as usize);
let mut entry: DiskEntry = unsafe { uninitialized() }; let mut entry: DiskEntry = unsafe { uninitialized() };
self._read_at(id as usize * BLKSIZE, entry.as_buf_mut())?; self._read_at(id as usize * BLKSIZE, entry.as_buf_mut())?;

@ -1,6 +1,7 @@
use alloc::{vec::Vec, string::String, sync::Arc}; use alloc::{vec::Vec, string::String, sync::Arc};
use core::fmt::Debug; use core::fmt::Debug;
use core::any::Any; use core::any::Any;
use core::result;
/// Interface for FS to read & write /// Interface for FS to read & write
/// TODO: use std::io::{Read, Write} /// TODO: use std::io::{Read, Write}
@ -40,18 +41,24 @@ impl INode {
self.as_any_ref().downcast_ref::<T>() self.as_any_ref().downcast_ref::<T>()
} }
pub fn list(&self) -> Result<Vec<String>> { pub fn list(&self) -> Result<Vec<String>> {
let info = self.info().unwrap(); let info = self.info()?;
assert_eq!(info.type_, FileType::Dir); if(info.type_ != FileType::Dir){
return Err(FsError::NotDir);
}
Ok((0..info.size).map(|i| { Ok((0..info.size).map(|i| {
self.get_entry(i).unwrap() self.get_entry(i).unwrap()
}).collect()) }).collect())
} }
pub fn lookup(&self, path: &str) -> Result<Arc<INode>> { pub fn lookup(&self, path: &str) -> Result<Arc<INode>> {
assert_eq!(self.info().unwrap().type_, FileType::Dir); if(self.info()?.type_ != FileType::Dir){
return Err(FsError::NotDir);
}
let mut result = self.find(".")?; let mut result = self.find(".")?;
let mut rest_path = path; let mut rest_path = path;
while rest_path != "" { while rest_path != "" {
assert_eq!(result.info()?.type_, FileType::Dir); if(result.info()?.type_!= FileType::Dir){
return Err(FsError::NotDir);
}
let name; let name;
match rest_path.find('/') { match rest_path.find('/') {
None => { None => {
@ -64,7 +71,7 @@ impl INode {
} }
}; };
match result.find(name) { match result.find(name) {
Err(_) => return Err(()), Err(error) => return Err(error),
Ok(inode) => result = inode, Ok(inode) => result = inode,
}; };
} }
@ -96,7 +103,21 @@ pub struct FsInfo {
pub max_file_size: usize, pub max_file_size: usize,
} }
pub type Result<T> = core::result::Result<T, ()>;
#[derive(Debug)]
pub enum FsError {
NotSupported,//E_UNIMP
NotFile,//E_ISDIR
IsDir,//E_ISDIR, used only in link
NotDir,//E_NOTDIR
EntryNotFound,//E_NOENT
EntryExist,//E_EXIST
NotSameFs,//E_XDEV
//and something else
}
pub type Result<T> = result::Result<T,FsError>;
/// Abstract filesystem /// Abstract filesystem
pub trait FileSystem: Sync { pub trait FileSystem: Sync {

Loading…
Cancel
Save