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 { pub enum FsError {
InodeNotFound, InodeNotFound,
InvalidDevice, InvalidDevice,
IsDirectory,
EndOfFile,
UnsupportedOperation, UnsupportedOperation,
} }

View file

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

View file

@ -7,6 +7,8 @@
pub mod errors; pub mod errors;
pub mod ext2; pub mod ext2;
use core::cmp;
use alloc::sync::{Weak, Arc}; use alloc::sync::{Weak, Arc};
use bitflags::bitflags; use bitflags::bitflags;
@ -17,14 +19,15 @@ use FsResult as Result;
pub type FsResult<T> = core::result::Result<T, FsError>; pub type FsResult<T> = core::result::Result<T, FsError>;
/// The methods on this trait are to be used internally.
pub trait StorageDevice pub trait StorageDevice
where where
Self: Send, Self: Send,
{ {
fn open(&self, node: Arc<FsNode> /* TODO: flags */) -> Result<FileDescriptor>; fn open(&self, node: Arc<FsNode> /* TODO: flags */) -> Result<FileDescriptor>;
fn release(&self, node: FsNode) -> Result<()>; fn release(&self, node: FsNode) -> Result<()>;
fn read(&self, node: &FsNode, offset: usize, size: usize) -> Result<Box<[u8]>>; fn read(&self, node: &FsNode, offset: usize, size: usize, buffer: &mut Vec<u8>) -> Result<()>;
fn write(&self, node: &FsNode, offset: usize, buffer: Box<[u8]>) -> Result<()>; fn write(&self, node: &FsNode, offset: usize, buffer: &[u8]) -> Result<()>;
fn read_dir(&self, node: &FsNode, index: usize) -> Result<DirectoryEntry>; fn read_dir(&self, node: &FsNode, index: usize) -> Result<DirectoryEntry>;
fn find_dir(&self, node: &FsNode, name: &str) -> Result<FsNode>; 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 /// 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 /// 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. /// 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 state = KERNEL_STATE.lock();
let device = state let device = state
.get_storage_device(self.device_handle) .get_storage_device(self.device_handle)
.ok_or_else(|| FsError::InvalidDevice)?; .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 /// 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 /// 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. /// 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 state = KERNEL_STATE.lock();
let device = state let device = state
.get_storage_device(self.device_handle) .get_storage_device(self.device_handle)
@ -132,6 +145,10 @@ impl FsNode {
device.find_dir(self, name) device.find_dir(self, name)
} }
pub fn is_dir(&self) -> bool {
(self.flags & FsFlags::DIRECTORY) == FsFlags::DIRECTORY
}
} }
impl Drop for FsNode { impl Drop for FsNode {