2022-08-03 04:53:02 -05:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2022, Umut İnan Erdoğan <umutinanerdogan@pm.me>
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: MPL-2.0
|
|
|
|
*/
|
|
|
|
|
|
|
|
pub mod errors;
|
|
|
|
|
|
|
|
use alloc::rc::Weak;
|
|
|
|
use bitflags::bitflags;
|
2022-03-11 13:51:47 -06:00
|
|
|
use ext2::{
|
|
|
|
fs::{
|
|
|
|
sync::{Inode, Synced},
|
|
|
|
Ext2,
|
2022-02-09 07:08:40 -06:00
|
|
|
},
|
2022-03-11 13:51:47 -06:00
|
|
|
sector::{SectorSize, Size1024},
|
|
|
|
volume::Volume,
|
2022-02-09 07:08:40 -06:00
|
|
|
};
|
2022-04-11 15:51:54 -05:00
|
|
|
use spin::Lazy;
|
2022-02-09 07:08:40 -06:00
|
|
|
|
2022-08-03 04:53:02 -05:00
|
|
|
use crate::handle::Handle;
|
|
|
|
|
|
|
|
use self::errors::FsError;
|
2022-08-03 06:23:58 -05:00
|
|
|
use FsResult as Result;
|
2022-08-03 04:53:02 -05:00
|
|
|
|
2022-08-03 06:23:58 -05:00
|
|
|
pub type FsResult<T> = core::result::Result<T, FsError>;
|
|
|
|
|
|
|
|
pub type FsOpenOperation = fn(node: &FsNode /* TODO: flags */) -> Result<Handle>;
|
|
|
|
pub type FsCloseOperation = fn(node: &FsNode) -> Result<()>;
|
|
|
|
pub type FsReadOperation = fn(node: &FsNode, offset: u32, size: u32)
|
|
|
|
-> Result<Box<[u8]>>;
|
|
|
|
pub type FsWriteOperation = fn(node: &FsNode, offset: u32, buffer: Box<[u8]>)
|
|
|
|
-> Result<()>;
|
|
|
|
pub type FsReaddirOperation = fn(node: &FsNode, index: u32) -> Result<DirectoryEntry>;
|
|
|
|
pub type FsFinddirOperation = fn(node: &FsNode, name: &str) -> Result<FsNode>;
|
2022-08-03 04:53:02 -05:00
|
|
|
|
|
|
|
/// A VFS node, that can either be a file or a directory.
|
|
|
|
pub struct FsNode {
|
|
|
|
// FIXME: move the file name into the directory listing to implement hard
|
|
|
|
// links
|
|
|
|
name: String,
|
|
|
|
flags: FsNodeFlags,
|
|
|
|
length: u32, // in bytes
|
|
|
|
inode: u32, // implementation specific identifier for the node
|
|
|
|
device_handle: Handle, // uniquely assigned device handle
|
|
|
|
ptr: Weak<FsNode>, // used by mountpoints and symlinks
|
|
|
|
open: Option<FsOpenOperation>,
|
|
|
|
close: Option<FsCloseOperation>,
|
|
|
|
read: Option<FsReadOperation>,
|
|
|
|
write: Option<FsWriteOperation>,
|
2022-08-03 06:23:58 -05:00
|
|
|
readdir: Option<FsReaddirOperation>,
|
|
|
|
finddir: Option<FsFinddirOperation>,
|
2022-08-03 04:53:02 -05:00
|
|
|
// todo: permissions mask
|
|
|
|
// todo: owning user/group
|
|
|
|
}
|
|
|
|
|
|
|
|
impl FsNode {
|
|
|
|
// TODO: make this take flags
|
2022-08-03 06:23:58 -05:00
|
|
|
fn open(&self) -> Result<Handle> {
|
2022-08-03 04:53:02 -05:00
|
|
|
if let Some(open) = self.open {
|
2022-08-03 06:23:58 -05:00
|
|
|
open(self)
|
2022-08-03 04:53:02 -05:00
|
|
|
} else {
|
|
|
|
Err(FsError::UnsupportedOperation)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-03 06:23:58 -05:00
|
|
|
fn close(&self) -> Result<()> {
|
2022-08-03 04:53:02 -05:00
|
|
|
if let Some(close) = self.close {
|
2022-08-03 06:23:58 -05:00
|
|
|
close(self)
|
2022-08-03 04:53:02 -05:00
|
|
|
} else {
|
|
|
|
Err(FsError::UnsupportedOperation)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-03 06:23:58 -05:00
|
|
|
fn read(&self, offset: u32, size: u32) -> Result<Box<[u8]>> {
|
2022-08-03 04:53:02 -05:00
|
|
|
if let Some(read) = self.read {
|
2022-08-03 06:23:58 -05:00
|
|
|
read(self, offset, size)
|
2022-08-03 04:53:02 -05:00
|
|
|
} else {
|
|
|
|
Err(FsError::UnsupportedOperation)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-03 06:23:58 -05:00
|
|
|
fn write(&self, offset: u32, buffer: Box<[u8]>) -> Result<()> {
|
2022-08-03 04:53:02 -05:00
|
|
|
if let Some(write) = self.write {
|
2022-08-03 06:23:58 -05:00
|
|
|
write(self, offset, buffer)
|
|
|
|
} else {
|
|
|
|
Err(FsError::UnsupportedOperation)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn readdir(&self, index: u32) -> Result<DirectoryEntry> {
|
|
|
|
if let Some(readdir) = self.readdir {
|
|
|
|
readdir(self, index)
|
|
|
|
} else {
|
|
|
|
Err(FsError::UnsupportedOperation)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn finddir(&self, name: &str) -> Result<FsNode> {
|
|
|
|
if let Some(finddir) = self.finddir {
|
|
|
|
finddir(self, name)
|
2022-08-03 04:53:02 -05:00
|
|
|
} else {
|
|
|
|
Err(FsError::UnsupportedOperation)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bitflags! {
|
|
|
|
/// Flags associated with VFS nodes.
|
|
|
|
///
|
|
|
|
/// 0x00000MST
|
|
|
|
/// T is set to 0 for files, 1 for directories
|
|
|
|
/// S is set when the node is a symbolic link
|
|
|
|
/// M is set if the node is an active mount point
|
|
|
|
pub struct FsNodeFlags: u8 {
|
|
|
|
const FILE = 0b00000000;
|
|
|
|
const DIRECTORY = 0b00000001;
|
|
|
|
const SYMBOLIC_LINK = 0b00000010;
|
|
|
|
const MOUNT_POINT = 0b00000100;
|
|
|
|
}
|
2022-08-03 06:23:58 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct DirectoryEntry {
|
|
|
|
name: String,
|
|
|
|
inode: u32,
|
2022-08-03 04:53:02 -05:00
|
|
|
}
|
|
|
|
|
2022-04-11 17:23:11 -05:00
|
|
|
pub static FILE_SYSTEM: Lazy<spin::Mutex<Synced<Ext2<Size1024, Vec<u8>>>>> =
|
|
|
|
Lazy::new(|| spin::Mutex::new(load_fs()));
|
2022-02-09 07:08:40 -06:00
|
|
|
|
2022-04-11 15:51:54 -05:00
|
|
|
pub fn walk<S: SectorSize, V: Volume<u8, S>>(
|
|
|
|
fs: &Synced<Ext2<S, V>>,
|
2022-02-09 07:08:40 -06:00
|
|
|
inode: Inode<S, V>,
|
|
|
|
name: String,
|
|
|
|
) {
|
2022-04-11 15:51:54 -05:00
|
|
|
if let Some(dir) = inode.directory() {
|
2022-02-09 07:08:40 -06:00
|
|
|
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),
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2022-04-11 15:51:54 -05:00
|
|
|
}
|
2022-02-09 07:08:40 -06:00
|
|
|
}
|
2022-04-11 15:51:54 -05:00
|
|
|
|
2022-04-11 17:23:11 -05:00
|
|
|
fn load_fs() -> Synced<Ext2<Size1024, Vec<u8>>> {
|
|
|
|
let mut volume = Vec::new();
|
|
|
|
volume.extend_from_slice(include_bytes!("../../../userland/root_fs/ext2.img"));
|
|
|
|
|
|
|
|
Synced::<Ext2<Size1024, _>>::new(volume).unwrap()
|
|
|
|
}
|