ableos/ableos/src/filesystem/ext2.rs

169 lines
4.8 KiB
Rust

/*
* Copyright (c) 2022, Umut İnan Erdoğan <umutinanerdogan@pm.me>
*
* SPDX-License-Identifier: MPL-2.0
*/
use alloc::sync::{Arc, Weak};
use ext2::fs::{sync::Synced, Ext2};
use ext2::sector::SectorSize;
use ext2::sys::inode::TypePerm;
use ext2::volume::Volume;
use crate::handle::{Handle, HandleResource};
use super::errors::FsError;
use super::vfs::{add_fs_node, find_fs_node, DirectoryEntry, FsFlags};
use super::{FsNode, FsResult as Result, StorageDevice};
pub struct Ext2StorageDevice<S, V>
where
S: SectorSize,
V: Volume<u8, S>,
{
fs: Synced<Ext2<S, V>>,
device_handle: Handle,
root: Arc<FsNode>,
}
impl<S, V> Ext2StorageDevice<S, V>
where
S: SectorSize,
V: Volume<u8, S>,
{
pub fn new(volume: V) -> Result<Self> {
let fs = Synced::new(volume).map_err(|e| e.into())?;
let root_inode = fs.root_inode();
let device_handle = Handle::new(HandleResource::StorageDevice);
let root = Arc::new(FsNode::new(
FsFlags::DIRECTORY,
root_inode.size(),
2,
device_handle,
Weak::new(),
));
add_fs_node(root.clone());
Ok(Self {
fs,
device_handle,
root,
})
}
}
impl<S, V> StorageDevice for Ext2StorageDevice<S, V>
where
S: SectorSize + Send,
V: Volume<u8, S> + Send,
{
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: &[u8]) -> Result<()> {
todo!()
}
fn read_dir(&self, node: &FsNode, index: usize) -> Result<DirectoryEntry> {
let inode = self
.fs
.inode_nth(node.inode() as usize)
.ok_or_else(|| FsError::InodeNotFound)?;
let mut dir = inode.directory().ok_or_else(|| FsError::NotADirectory)?;
let entry = dir
.nth(index)
.ok_or_else(|| FsError::InodeNotFound)?
.map_err(|e| e.into())?;
let entry_inode = self
.fs
.inode_nth(entry.inode)
.ok_or_else(|| FsError::InodeNotFound)?;
let entry_node_handle =
find_fs_node(entry.inode, self.device_handle).unwrap_or_else(|| {
add_fs_node(Arc::new(FsNode::new(
ext2_type_to_fs_flags(entry_inode.type_perm()),
inode.size(),
entry.inode,
self.device_handle,
Weak::new(),
)))
});
Ok(DirectoryEntry::new(
entry.file_name_string(),
entry_node_handle,
))
}
fn find_dir(&self, node: &FsNode, name: &str) -> Result<Handle> {
let inode = self
.fs
.inode_nth(node.inode() as usize)
.ok_or_else(|| FsError::InodeNotFound)?;
let dir = inode.directory().ok_or_else(|| FsError::NotADirectory)?;
let mut found_node = Err(FsError::NotFound);
for entry in dir {
if entry.is_err() {
continue;
}
let entry = entry.unwrap();
if entry.file_name_string() == name {
found_node = Ok(
find_fs_node(entry.inode, self.device_handle).unwrap_or_else(|| {
add_fs_node(Arc::new(FsNode::new(
ext2_type_to_fs_flags(inode.type_perm()),
inode.size(),
entry.inode,
self.device_handle,
Weak::new(),
)))
}),
);
}
}
found_node
}
fn root_node(&self) -> Arc<FsNode> {
self.root.clone()
}
fn device_handle(&self) -> Handle {
self.device_handle
}
}
fn ext2_type_to_fs_flags(type_perm: TypePerm) -> FsFlags {
let is_directory = type_perm & TypePerm::DIRECTORY == TypePerm::DIRECTORY;
let is_symlink = type_perm & TypePerm::SYMLINK == TypePerm::SYMLINK;
let t = if is_directory {
FsFlags::DIRECTORY
} else {
FsFlags::FILE
};
let s = if is_symlink {
FsFlags::SYMBOLIC_LINK
} else {
FsFlags::empty()
};
t | s
}