From e53d855fa69d4e0450d3e344c74790af552bf7a7 Mon Sep 17 00:00:00 2001 From: TheOddGarlic Date: Thu, 4 Aug 2022 10:19:35 +0300 Subject: [PATCH] vfs+ext2: initial FsNode::read() implementation The VFS side of things for read() should be done, however due to my limited ext2 knowledge, I've not implemented partially reading a file, and in this state only full files can be read. --- ableos/src/filesystem/errors.rs | 2 ++ ableos/src/filesystem/ext2.rs | 19 ++++++++++++++++--- ableos/src/filesystem/mod.rs | 27 ++++++++++++++++++++++----- 3 files changed, 40 insertions(+), 8 deletions(-) diff --git a/ableos/src/filesystem/errors.rs b/ableos/src/filesystem/errors.rs index db6c8874..4e54c84c 100644 --- a/ableos/src/filesystem/errors.rs +++ b/ableos/src/filesystem/errors.rs @@ -7,6 +7,8 @@ pub enum FsError { InodeNotFound, InvalidDevice, + IsDirectory, + EndOfFile, UnsupportedOperation, } diff --git a/ableos/src/filesystem/ext2.rs b/ableos/src/filesystem/ext2.rs index c983dec7..bf590c4a 100644 --- a/ableos/src/filesystem/ext2.rs +++ b/ableos/src/filesystem/ext2.rs @@ -51,11 +51,24 @@ where Ok(()) } - fn read(&self, _node: &FsNode, _offset: usize, _size: usize) -> Result> { - todo!() + fn read(&self, node: &FsNode, offset: usize, size: usize, buffer: &mut Vec) -> Result<()> { + let inode = self + .fs + .inode_nth(node.inode as usize) + .ok_or_else(|| FsError::InodeNotFound)?; + + // FIXME: I don't really know how Ext2 works, so for now we don't + // support non-zero offsets and buffer sizes that don't match + // the file length. We always read the whole file. + if offset > 0 || size != inode.size() { + Err(FsError::UnsupportedOperation)?; + } + + inode.read_to_end(buffer).map_err(|e| e.into())?; + Ok(()) } - fn write(&self, _node: &FsNode, _offset: usize, _buffer: Box<[u8]>) -> Result<()> { + fn write(&self, _node: &FsNode, _offset: usize, _buffer: &[u8]) -> Result<()> { todo!() } diff --git a/ableos/src/filesystem/mod.rs b/ableos/src/filesystem/mod.rs index 78f7d307..96be6596 100644 --- a/ableos/src/filesystem/mod.rs +++ b/ableos/src/filesystem/mod.rs @@ -7,6 +7,8 @@ pub mod errors; pub mod ext2; +use core::cmp; + use alloc::sync::{Weak, Arc}; use bitflags::bitflags; @@ -17,14 +19,15 @@ use FsResult as Result; pub type FsResult = core::result::Result; +/// The methods on this trait are to be used internally. pub trait StorageDevice where Self: Send, { fn open(&self, node: Arc /* TODO: flags */) -> Result; fn release(&self, node: FsNode) -> Result<()>; - fn read(&self, node: &FsNode, offset: usize, size: usize) -> Result>; - fn write(&self, node: &FsNode, offset: usize, buffer: Box<[u8]>) -> Result<()>; + fn read(&self, node: &FsNode, offset: usize, size: usize, buffer: &mut Vec) -> Result<()>; + fn write(&self, node: &FsNode, offset: usize, buffer: &[u8]) -> Result<()>; fn read_dir(&self, node: &FsNode, index: usize) -> Result; fn find_dir(&self, node: &FsNode, name: &str) -> Result; } @@ -94,19 +97,29 @@ impl FsNode { /// This method reads from the VFS node without opening a new file /// descriptor. This is intended to be used internally, if you're trying to /// read a file then you probably want to read from a file descriptor. - pub fn read(&self, offset: usize, size: usize) -> Result> { + pub fn read(&self, offset: usize, size: usize, buffer: &mut Vec) -> Result { let state = KERNEL_STATE.lock(); let device = state .get_storage_device(self.device_handle) .ok_or_else(|| FsError::InvalidDevice)?; - device.read(self, offset, size) + if self.is_dir() { + Err(FsError::IsDirectory)?; + } + + if offset > self.length { + Err(FsError::EndOfFile)?; + } + + let readable_size = cmp::min(size, self.length - offset); + device.read(self, offset, readable_size, buffer)?; + Ok(readable_size) } /// This method writes to the VFS node without opening a new file /// descriptor. This is intended to be used internally, if you're trying to /// write to a file then you probably want to write to a file descriptor. - pub fn write(&self, offset: usize, buffer: Box<[u8]>) -> Result<()> { + pub fn write(&self, offset: usize, buffer: &[u8]) -> Result<()> { let state = KERNEL_STATE.lock(); let device = state .get_storage_device(self.device_handle) @@ -132,6 +145,10 @@ impl FsNode { device.find_dir(self, name) } + + pub fn is_dir(&self) -> bool { + (self.flags & FsFlags::DIRECTORY) == FsFlags::DIRECTORY + } } impl Drop for FsNode {