forked from AbleOS/ableos
159 lines
4.5 KiB
Rust
159 lines
4.5 KiB
Rust
/*
|
|
* Copyright (c) 2022, Umut İnan Erdoğan <umutinanerdogan@pm.me>
|
|
*
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
*/
|
|
|
|
use alloc::sync::Weak;
|
|
use ext2::fs::{sync::Synced, Ext2};
|
|
use ext2::sector::SectorSize;
|
|
use ext2::sys::inode::TypePerm;
|
|
use ext2::volume::Volume;
|
|
|
|
use crate::handle::Handle;
|
|
|
|
use super::errors::FsError;
|
|
use super::{DirectoryEntry, FsFlags, 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,
|
|
}
|
|
|
|
impl<S, V> Ext2StorageDevice<S, V>
|
|
where
|
|
S: SectorSize,
|
|
V: Volume<u8, S>,
|
|
{
|
|
pub fn new(volume: V, device_handle: Handle) -> Result<Self> {
|
|
Ok(Self {
|
|
fs: Synced::new(volume).map_err(|e| e.into())?,
|
|
device_handle,
|
|
})
|
|
}
|
|
}
|
|
|
|
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())?;
|
|
|
|
Ok(DirectoryEntry::new(entry.file_name_string(), entry.inode))
|
|
}
|
|
|
|
fn find_dir(&self, node: &FsNode, name: &str) -> Result<FsNode> {
|
|
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 {
|
|
let inode = self
|
|
.fs
|
|
.inode_nth(entry.inode as usize)
|
|
.ok_or_else(|| FsError::InodeNotFound)?;
|
|
let flags = ext2_type_to_fs_flags(inode.type_perm());
|
|
found_node = Ok(FsNode::new(
|
|
flags,
|
|
inode.size(),
|
|
entry.inode,
|
|
self.device_handle,
|
|
Weak::new(),
|
|
))
|
|
}
|
|
}
|
|
|
|
found_node
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
// fn load_fs() -> Arc<Mutex<Ext2<Size1024, Vec<u8>>>> {
|
|
// let mut volume = Vec::new();
|
|
// volume.extend_from_slice(include_bytes!("../../../userland/root_fs/ext2.img"));
|
|
|
|
// Arc::<Ext2<Size1024, _>>::new(volume).unwrap()
|
|
// }
|
|
|
|
// pub fn walk<S: SectorSize, V: Volume<u8, S>>(
|
|
// fs: &Synced<Ext2<S, V>>,
|
|
// inode: Inode<S, V>,
|
|
// name: String,
|
|
// ) {
|
|
// if let Some(dir) = inode.directory() {
|
|
// for entry in dir {
|
|
// assert!(entry.is_ok());
|
|
// let entry = entry.unwrap();
|
|
// let entry_name = String::from_utf8_lossy(&entry.name);
|
|
|
|
// println!("{}/{} => {}", name, entry_name, entry.inode,);
|
|
// if entry_name != "." && entry_name != ".." {
|
|
// walk(
|
|
// fs,
|
|
// fs.inode_nth(entry.inode).unwrap(),
|
|
// format!("{}/{}", name, entry_name),
|
|
// );
|
|
// }
|
|
// }
|
|
// }
|
|
// }
|