From d7a2006cc316c98b7050aec63a2770dd690a4a80 Mon Sep 17 00:00:00 2001 From: WangRunji Date: Thu, 4 Apr 2019 12:14:30 +0800 Subject: [PATCH] improve docs for vfs. add poll and ioctl. --- rcore-fs-sefs/src/lib.rs | 10 ++++ rcore-fs-sfs/src/lib.rs | 70 ++++++++++++++----------- rcore-fs/src/vfs.rs | 107 ++++++++++++++++++++++++++------------- 3 files changed, 121 insertions(+), 66 deletions(-) diff --git a/rcore-fs-sefs/src/lib.rs b/rcore-fs-sefs/src/lib.rs index 961b187..4f03118 100644 --- a/rcore-fs-sefs/src/lib.rs +++ b/rcore-fs-sefs/src/lib.rs @@ -156,6 +156,13 @@ impl vfs::INode for INodeImpl { let len = self.file.write_at(buf, offset)?; Ok(len) } + fn poll(&self) -> vfs::Result { + 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. fn metadata(&self) -> vfs::Result { let disk_inode = self.disk_inode.read(); @@ -404,6 +411,9 @@ impl vfs::INode for INodeImpl { let entry = self.file.read_direntry(id)?; Ok(String::from(entry.name.as_ref())) } + fn io_control(&self, _cmd: u32, _data: u32) -> vfs::Result<()> { + Err(FsError::NotSupported) + } fn fs(&self) -> Arc { self.fs.clone() } diff --git a/rcore-fs-sfs/src/lib.rs b/rcore-fs-sfs/src/lib.rs index bc7c3df..3c6f3c5 100644 --- a/rcore-fs-sfs/src/lib.rs +++ b/rcore-fs-sfs/src/lib.rs @@ -398,6 +398,13 @@ impl vfs::INode for INodeImpl { } self._write_at(offset, buf) } + fn poll(&self) -> vfs::Result { + 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. fn metadata(&self) -> vfs::Result { let disk_inode = self.disk_inode.read(); @@ -484,6 +491,36 @@ impl vfs::INode for INodeImpl { Ok(inode) } + fn link(&self, name: &str, other: &Arc) -> 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::() + .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<()> { let info = self.metadata()?; if info.type_ != vfs::FileType::Dir { @@ -521,36 +558,6 @@ impl vfs::INode for INodeImpl { Ok(()) } - fn link(&self, name: &str, other: &Arc) -> 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::() - .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, new_name: &str) -> vfs::Result<()> { let info = self.metadata()?; if info.type_ != vfs::FileType::Dir { @@ -635,6 +642,9 @@ impl vfs::INode for INodeImpl { .unwrap(); Ok(String::from(entry.name.as_ref())) } + fn io_control(&self, _cmd: u32, _data: u32) -> vfs::Result<()> { + Err(FsError::NotSupported) + } fn fs(&self) -> Arc { self.fs.clone() } diff --git a/rcore-fs/src/vfs.rs b/rcore-fs/src/vfs.rs index 1a44053..97dbad9 100644 --- a/rcore-fs/src/vfs.rs +++ b/rcore-fs/src/vfs.rs @@ -4,40 +4,69 @@ use core::fmt; use core::result; use core::str; -/// Abstract operations on a inode. +/// Abstract file system object such as file or directory. 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; + + /// Write bytes at `offset` from `buf`, return the number of bytes written. fn write_at(&self, offset: usize, buf: &[u8]) -> Result; + + /// Poll the events, return a bitmap of events. + fn poll(&self) -> Result; + + /// Get metadata of the INode fn metadata(&self) -> Result; + + /// Set metadata of the INode fn set_metadata(&self, metadata: &Metadata) -> Result<()>; + /// Sync all data and metadata fn sync_all(&self) -> Result<()>; + /// Sync data (not include metadata) fn sync_data(&self) -> Result<()>; + + /// Resize the file fn resize(&self, len: usize) -> Result<()>; + + /// Create a new INode in the directory fn create(&self, name: &str, type_: FileType, mode: u32) -> Result>; - 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) -> Result<()>; + + /// Delete a hard link `name` + fn unlink(&self, name: &str) -> Result<()>; + /// Move INode `self/old_name` to `target/new_name`. /// If `target` equals `self`, do rename. fn move_(&self, old_name: &str, target: &Arc, new_name: &str) -> Result<()>; - /// lookup with only one layer + + /// Find the INode `name` in the directory fn find(&self, name: &str) -> Result>; - /// 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; - // 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; - /// 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; } impl INode { + /// Downcast the INode to specific struct pub fn downcast_ref(&self) -> Option<&T> { self.as_any_ref().downcast_ref::() } + + /// Get all directory entries as a Vec pub fn list(&self) -> Result> { let info = self.metadata()?; if info.type_ != FileType::Dir { @@ -80,39 +109,40 @@ impl INode { rest_path = String::from(&rest_path[pos + 1..]); } }; - match result.find(&name) { - Err(error) => return Err(error), - Ok(inode) => { - // Handle symlink - if inode.metadata()?.type_ == FileType::SymLink && follow_times > 0 { - follow_times -= 1; - let mut content = [0u8; 256]; - let len = inode.read_at(0, &mut content)?; - if let Ok(path) = str::from_utf8(&content[..len]) { - // result remains unchanged - rest_path = { - let mut new_path = String::from(path); - if let Some('/') = new_path.chars().last() { - new_path += &rest_path; - } else { - new_path += "/"; - new_path += &rest_path; - } - new_path - }; - } else { - return Err(FsError::NotDir); - } + let inode = result.find(&name)?; + // Handle symlink + if inode.metadata()?.type_ == FileType::SymLink && follow_times > 0 { + follow_times -= 1; + let mut content = [0u8; 256]; + let len = inode.read_at(0, &mut content)?; + let path = str::from_utf8(&content[..len]) + .map_err(|_| FsError::NotDir)?; + // result remains unchanged + rest_path = { + let mut new_path = String::from(path); + if let Some('/') = new_path.chars().last() { + new_path += &rest_path; } else { - result = inode + new_path += "/"; + new_path += &rest_path; } - } - }; + new_path + }; + } else { + result = inode + } } Ok(result) } } +#[derive(Debug, Default)] +pub struct PollStatus { + pub read: bool, + pub write: bool, + pub error: bool, +} + /// Metadata of INode /// /// 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 = result::Result; -/// Abstract filesystem +/// Abstract file system pub trait FileSystem: Sync { + /// Sync all data to the storage fn sync(&self) -> Result<()>; + + /// Get the root INode of the file system fn root_inode(&self) -> Arc; + + /// Get the file system information fn info(&self) -> FsInfo; }