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:
parent
600a81adf7
commit
91c1783b99
|
@ -7,6 +7,8 @@
|
||||||
pub enum FsError {
|
pub enum FsError {
|
||||||
InodeNotFound,
|
InodeNotFound,
|
||||||
InvalidDevice,
|
InvalidDevice,
|
||||||
|
IsDirectory,
|
||||||
|
EndOfFile,
|
||||||
UnsupportedOperation,
|
UnsupportedOperation,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Reference in a new issue