improve docs for vfs. add poll and ioctl.

master
WangRunji 6 years ago
parent acff8d5586
commit d7a2006cc3

@ -156,6 +156,13 @@ impl vfs::INode for INodeImpl {
let len = self.file.write_at(buf, offset)?; let len = self.file.write_at(buf, offset)?;
Ok(len) Ok(len)
} }
fn poll(&self) -> vfs::Result<vfs::PollStatus> {
Ok(vfs::PollStatus {
read: true,
write: true,
error: false
})
}
/// 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.
fn metadata(&self) -> vfs::Result<vfs::Metadata> { fn metadata(&self) -> vfs::Result<vfs::Metadata> {
let disk_inode = self.disk_inode.read(); let disk_inode = self.disk_inode.read();
@ -404,6 +411,9 @@ impl vfs::INode for INodeImpl {
let entry = self.file.read_direntry(id)?; let entry = self.file.read_direntry(id)?;
Ok(String::from(entry.name.as_ref())) Ok(String::from(entry.name.as_ref()))
} }
fn io_control(&self, _cmd: u32, _data: u32) -> vfs::Result<()> {
Err(FsError::NotSupported)
}
fn fs(&self) -> Arc<vfs::FileSystem> { fn fs(&self) -> Arc<vfs::FileSystem> {
self.fs.clone() self.fs.clone()
} }

@ -398,6 +398,13 @@ impl vfs::INode for INodeImpl {
} }
self._write_at(offset, buf) self._write_at(offset, buf)
} }
fn poll(&self) -> vfs::Result<vfs::PollStatus> {
Ok(vfs::PollStatus {
read: true,
write: true,
error: false
})
}
/// 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.
fn metadata(&self) -> vfs::Result<vfs::Metadata> { fn metadata(&self) -> vfs::Result<vfs::Metadata> {
let disk_inode = self.disk_inode.read(); let disk_inode = self.disk_inode.read();
@ -484,6 +491,36 @@ impl vfs::INode for INodeImpl {
Ok(inode) Ok(inode)
} }
fn link(&self, name: &str, other: &Arc<INode>) -> vfs::Result<()> {
let info = self.metadata()?;
if info.type_ != vfs::FileType::Dir {
return Err(FsError::NotDir);
}
if info.nlinks <= 0 {
return Err(FsError::DirRemoved);
}
if !self.get_file_inode_id(name).is_none() {
return Err(FsError::EntryExist);
}
let child = other
.downcast_ref::<INodeImpl>()
.ok_or(FsError::NotSameFs)?;
if !Arc::ptr_eq(&self.fs, &child.fs) {
return Err(FsError::NotSameFs);
}
if child.metadata()?.type_ == vfs::FileType::Dir {
return Err(FsError::IsDir);
}
let entry = DiskEntry {
id: child.id as u32,
name: Str256::from(name),
};
let old_size = self._size();
self._resize(old_size + BLKSIZE)?;
self._write_at(old_size, entry.as_buf()).unwrap();
child.nlinks_inc();
Ok(())
}
fn unlink(&self, name: &str) -> vfs::Result<()> { fn unlink(&self, name: &str) -> vfs::Result<()> {
let info = self.metadata()?; let info = self.metadata()?;
if info.type_ != vfs::FileType::Dir { if info.type_ != vfs::FileType::Dir {
@ -521,36 +558,6 @@ impl vfs::INode for INodeImpl {
Ok(()) Ok(())
} }
fn link(&self, name: &str, other: &Arc<INode>) -> vfs::Result<()> {
let info = self.metadata()?;
if info.type_ != vfs::FileType::Dir {
return Err(FsError::NotDir);
}
if info.nlinks <= 0 {
return Err(FsError::DirRemoved);
}
if !self.get_file_inode_id(name).is_none() {
return Err(FsError::EntryExist);
}
let child = other
.downcast_ref::<INodeImpl>()
.ok_or(FsError::NotSameFs)?;
if !Arc::ptr_eq(&self.fs, &child.fs) {
return Err(FsError::NotSameFs);
}
if child.metadata()?.type_ == vfs::FileType::Dir {
return Err(FsError::IsDir);
}
let entry = DiskEntry {
id: child.id as u32,
name: Str256::from(name),
};
let old_size = self._size();
self._resize(old_size + BLKSIZE)?;
self._write_at(old_size, entry.as_buf()).unwrap();
child.nlinks_inc();
Ok(())
}
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.metadata()?; let info = self.metadata()?;
if info.type_ != vfs::FileType::Dir { if info.type_ != vfs::FileType::Dir {
@ -635,6 +642,9 @@ impl vfs::INode for INodeImpl {
.unwrap(); .unwrap();
Ok(String::from(entry.name.as_ref())) Ok(String::from(entry.name.as_ref()))
} }
fn io_control(&self, _cmd: u32, _data: u32) -> vfs::Result<()> {
Err(FsError::NotSupported)
}
fn fs(&self) -> Arc<vfs::FileSystem> { fn fs(&self) -> Arc<vfs::FileSystem> {
self.fs.clone() self.fs.clone()
} }

@ -4,40 +4,69 @@ use core::fmt;
use core::result; use core::result;
use core::str; use core::str;
/// Abstract operations on a inode. /// Abstract file system object such as file or directory.
pub trait INode: Any + Sync + Send { pub trait INode: Any + Sync + Send {
/// Read bytes at `offset` into `buf`, return the number of bytes read.
fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize>; fn read_at(&self, offset: usize, buf: &mut [u8]) -> Result<usize>;
/// Write bytes at `offset` from `buf`, return the number of bytes written.
fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize>; fn write_at(&self, offset: usize, buf: &[u8]) -> Result<usize>;
/// Poll the events, return a bitmap of events.
fn poll(&self) -> Result<PollStatus>;
/// Get metadata of the INode
fn metadata(&self) -> Result<Metadata>; fn metadata(&self) -> Result<Metadata>;
/// Set metadata of the INode
fn set_metadata(&self, metadata: &Metadata) -> Result<()>; fn set_metadata(&self, metadata: &Metadata) -> Result<()>;
/// Sync all data and metadata /// Sync all data and metadata
fn sync_all(&self) -> Result<()>; fn sync_all(&self) -> Result<()>;
/// Sync data (not include metadata) /// Sync data (not include metadata)
fn sync_data(&self) -> Result<()>; fn sync_data(&self) -> Result<()>;
/// Resize the file
fn resize(&self, len: usize) -> Result<()>; fn resize(&self, len: usize) -> Result<()>;
/// Create a new INode in the directory
fn create(&self, name: &str, type_: FileType, mode: u32) -> Result<Arc<INode>>; fn create(&self, name: &str, type_: FileType, mode: u32) -> Result<Arc<INode>>;
fn unlink(&self, name: &str) -> Result<()>;
/// user of the vfs api should call borrow_mut by itself /// Create a hard link `name` to `other`
fn link(&self, name: &str, other: &Arc<INode>) -> Result<()>; fn link(&self, name: &str, other: &Arc<INode>) -> Result<()>;
/// Delete a hard link `name`
fn unlink(&self, name: &str) -> Result<()>;
/// Move INode `self/old_name` to `target/new_name`. /// Move INode `self/old_name` to `target/new_name`.
/// If `target` equals `self`, do rename. /// If `target` equals `self`, do rename.
fn move_(&self, old_name: &str, target: &Arc<INode>, new_name: &str) -> Result<()>; fn move_(&self, old_name: &str, target: &Arc<INode>, new_name: &str) -> Result<()>;
/// lookup with only one layer
/// Find the INode `name` in the directory
fn find(&self, name: &str) -> Result<Arc<INode>>; fn find(&self, name: &str) -> Result<Arc<INode>>;
/// like list()[id]
/// only get one item in list, often faster than list /// Get the name of directory entry
fn get_entry(&self, id: usize) -> Result<String>; fn get_entry(&self, id: usize) -> Result<String>;
// fn io_ctrl(&mut self, op: u32, data: &[u8]) -> Result<()>;
/// Control device
fn io_control(&self, cmd: u32, data: u32) -> Result<()>;
/// Get the file system of the INode
fn fs(&self) -> Arc<FileSystem>; fn fs(&self) -> Arc<FileSystem>;
/// this is used to implement dynamics cast
/// simply return self in the implement of the function /// This is used to implement dynamics cast.
/// Simply return self in the implement of the function.
fn as_any_ref(&self) -> &Any; fn as_any_ref(&self) -> &Any;
} }
impl INode { impl INode {
/// Downcast the INode to specific struct
pub fn downcast_ref<T: INode>(&self) -> Option<&T> { pub fn downcast_ref<T: INode>(&self) -> Option<&T> {
self.as_any_ref().downcast_ref::<T>() self.as_any_ref().downcast_ref::<T>()
} }
/// Get all directory entries as a Vec
pub fn list(&self) -> Result<Vec<String>> { pub fn list(&self) -> Result<Vec<String>> {
let info = self.metadata()?; let info = self.metadata()?;
if info.type_ != FileType::Dir { if info.type_ != FileType::Dir {
@ -80,39 +109,40 @@ impl INode {
rest_path = String::from(&rest_path[pos + 1..]); rest_path = String::from(&rest_path[pos + 1..]);
} }
}; };
match result.find(&name) { let inode = result.find(&name)?;
Err(error) => return Err(error), // Handle symlink
Ok(inode) => { if inode.metadata()?.type_ == FileType::SymLink && follow_times > 0 {
// Handle symlink follow_times -= 1;
if inode.metadata()?.type_ == FileType::SymLink && follow_times > 0 { let mut content = [0u8; 256];
follow_times -= 1; let len = inode.read_at(0, &mut content)?;
let mut content = [0u8; 256]; let path = str::from_utf8(&content[..len])
let len = inode.read_at(0, &mut content)?; .map_err(|_| FsError::NotDir)?;
if let Ok(path) = str::from_utf8(&content[..len]) { // result remains unchanged
// result remains unchanged rest_path = {
rest_path = { let mut new_path = String::from(path);
let mut new_path = String::from(path); if let Some('/') = new_path.chars().last() {
if let Some('/') = new_path.chars().last() { new_path += &rest_path;
new_path += &rest_path;
} else {
new_path += "/";
new_path += &rest_path;
}
new_path
};
} else {
return Err(FsError::NotDir);
}
} else { } else {
result = inode new_path += "/";
new_path += &rest_path;
} }
} new_path
}; };
} else {
result = inode
}
} }
Ok(result) Ok(result)
} }
} }
#[derive(Debug, Default)]
pub struct PollStatus {
pub read: bool,
pub write: bool,
pub error: bool,
}
/// Metadata of INode /// Metadata of INode
/// ///
/// Ref: [http://pubs.opengroup.org/onlinepubs/009604499/basedefs/sys/stat.h.html] /// Ref: [http://pubs.opengroup.org/onlinepubs/009604499/basedefs/sys/stat.h.html]
@ -223,9 +253,14 @@ impl std::error::Error for FsError {}
pub type Result<T> = result::Result<T, FsError>; pub type Result<T> = result::Result<T, FsError>;
/// Abstract filesystem /// Abstract file system
pub trait FileSystem: Sync { pub trait FileSystem: Sync {
/// Sync all data to the storage
fn sync(&self) -> Result<()>; fn sync(&self) -> Result<()>;
/// Get the root INode of the file system
fn root_inode(&self) -> Arc<INode>; fn root_inode(&self) -> Arc<INode>;
/// Get the file system information
fn info(&self) -> FsInfo; fn info(&self) -> FsInfo;
} }

Loading…
Cancel
Save