//! File handle for process use alloc::{string::String, sync::Arc}; use rcore_fs::vfs::{FsError, INode, Metadata, Result}; #[derive(Clone)] pub struct FileHandle { inode: Arc, offset: u64, options: OpenOptions, } #[derive(Debug, Clone)] pub struct OpenOptions { pub read: bool, pub write: bool, /// Before each write, the file offset is positioned at the end of the file. pub append: bool, } #[derive(Debug)] pub enum SeekFrom { Start(u64), End(i64), Current(i64), } impl FileHandle { pub fn new(inode: Arc, options: OpenOptions) -> Self { FileHandle { inode, offset: 0, options, } } pub fn read(&mut self, buf: &mut [u8]) -> Result { let len = self.read_at(self.offset as usize, buf)?; self.offset += len as u64; Ok(len) } pub fn read_at(&mut self, offset: usize, buf: &mut [u8]) -> Result { if !self.options.read { return Err(FsError::InvalidParam); // FIXME: => EBADF } let len = self.inode.read_at(offset, buf)?; Ok(len) } pub fn write(&mut self, buf: &[u8]) -> Result { let offset = match self.options.append { true => self.inode.metadata()?.size as u64, false => self.offset, } as usize; let len = self.write_at(offset, buf)?; self.offset = (offset + len) as u64; Ok(len) } pub fn write_at(&mut self, offset: usize, buf: &[u8]) -> Result { if !self.options.write { return Err(FsError::InvalidParam); // FIXME: => EBADF } let len = self.inode.write_at(offset, buf)?; Ok(len) } pub fn seek(&mut self, pos: SeekFrom) -> Result { self.offset = match pos { SeekFrom::Start(offset) => offset, SeekFrom::End(offset) => (self.inode.metadata()?.size as i64 + offset) as u64, SeekFrom::Current(offset) => (self.offset as i64 + offset) as u64, }; Ok(self.offset) } pub fn set_len(&mut self, len: u64) -> Result<()> { if !self.options.write { return Err(FsError::InvalidParam); // FIXME: => EBADF } self.inode.resize(len as usize)?; Ok(()) } pub fn sync_all(&mut self) -> Result<()> { self.inode.sync_all() } pub fn sync_data(&mut self) -> Result<()> { self.inode.sync_data() } pub fn metadata(&self) -> Result { self.inode.metadata() } pub fn lookup_follow(&self, path: &str, max_follow: usize) -> Result> { self.inode.lookup_follow(path, max_follow) } pub fn read_entry(&mut self) -> Result { if !self.options.read { return Err(FsError::InvalidParam); // FIXME: => EBADF } let name = self.inode.get_entry(self.offset as usize)?; self.offset += 1; Ok(name) } }