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.
This commit is contained in:
TheOddGarlic 2022-08-04 10:19:35 +03:00
parent 600a81adf7
commit 91c1783b99
3 changed files with 40 additions and 8 deletions

View file

@ -7,6 +7,8 @@
pub enum FsError {
InodeNotFound,
InvalidDevice,
IsDirectory,
EndOfFile,
UnsupportedOperation,
}

View file

@ -51,11 +51,24 @@ where
Ok(())
}
fn read(&self, _node: &FsNode, _offset: usize, _size: usize) -> Result<Box<[u8]>> {
todo!()
fn read(&self, node: &FsNode, offset: usize, size: usize, buffer: &mut Vec<u8>) -> 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!()
}

View file

@ -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<T> = core::result::Result<T, FsError>;
/// The methods on this trait are to be used internally.
pub trait StorageDevice
where
Self: Send,
{
fn open(&self, node: Arc<FsNode> /* TODO: flags */) -> Result<FileDescriptor>;
fn release(&self, node: FsNode) -> Result<()>;
fn read(&self, node: &FsNode, offset: usize, size: usize) -> Result<Box<[u8]>>;
fn write(&self, node: &FsNode, offset: usize, buffer: Box<[u8]>) -> Result<()>;
fn read(&self, node: &FsNode, offset: usize, size: usize, buffer: &mut Vec<u8>) -> Result<()>;
fn write(&self, node: &FsNode, offset: usize, buffer: &[u8]) -> Result<()>;
fn read_dir(&self, node: &FsNode, index: usize) -> Result<DirectoryEntry>;
fn find_dir(&self, node: &FsNode, name: &str) -> Result<FsNode>;
}
@ -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<Box<[u8]>> {
pub fn read(&self, offset: usize, size: usize, buffer: &mut Vec<u8>) -> Result<usize> {
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 {