refactor: new VFS design
This commit is contained in:
+56
-12
@@ -1,27 +1,30 @@
|
||||
use crate::{BlockAllocator, Bvec, FileInode};
|
||||
use alloc::boxed::Box;
|
||||
use libsys::{error::Errno, stat::Stat};
|
||||
use vfs::{Vnode, VnodeImpl, VnodeKind, VnodeRef};
|
||||
use libsys::{error::Errno, stat::{Stat, DirectoryEntry, OpenFlags}, ioctl::IoctlCmd};
|
||||
use vfs::{Vnode, VnodeCommon, VnodeDirectory, VnodeRef, VnodeCreateKind, VnodeData};
|
||||
use core::cell::RefCell;
|
||||
|
||||
pub struct DirInode<A: BlockAllocator + Copy + 'static> {
|
||||
alloc: A,
|
||||
}
|
||||
|
||||
#[auto_inode]
|
||||
impl<A: BlockAllocator + Copy + 'static> VnodeImpl for DirInode<A> {
|
||||
impl<A: BlockAllocator + Copy + 'static> VnodeDirectory for DirInode<A> {
|
||||
fn create(
|
||||
&mut self,
|
||||
_parent: VnodeRef,
|
||||
name: &str,
|
||||
kind: VnodeKind,
|
||||
kind: VnodeCreateKind,
|
||||
) -> Result<VnodeRef, Errno> {
|
||||
let vnode = Vnode::new(name, kind, Vnode::SEEKABLE | Vnode::CACHE_READDIR);
|
||||
match kind {
|
||||
VnodeKind::Directory => vnode.set_data(Box::new(DirInode { alloc: self.alloc })),
|
||||
VnodeKind::Regular => vnode.set_data(Box::new(FileInode::new(Bvec::new(self.alloc)))),
|
||||
_ => todo!(),
|
||||
}
|
||||
Ok(vnode)
|
||||
let data = match kind {
|
||||
VnodeCreateKind::Directory => VnodeData::Directory(RefCell::new(Some(Box::new(DirInode { alloc: self.alloc })))),
|
||||
VnodeCreateKind::File => VnodeData::File(RefCell::new(Some(Box::new(FileInode::new(Bvec::new(self.alloc)))))),
|
||||
_ => todo!()
|
||||
};
|
||||
Ok(Vnode::new(name, data, Vnode::SEEKABLE | Vnode::CACHE_READDIR))
|
||||
// match kind {
|
||||
// _ => todo!(),
|
||||
// }
|
||||
// Ok(vnode)
|
||||
}
|
||||
|
||||
fn lookup(&mut self, _parent: VnodeRef, _name: &str) -> Result<VnodeRef, Errno> {
|
||||
@@ -32,6 +35,18 @@ impl<A: BlockAllocator + Copy + 'static> VnodeImpl for DirInode<A> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Read directory entries into target buffer
|
||||
fn readdir(
|
||||
&mut self,
|
||||
node: VnodeRef,
|
||||
pos: usize,
|
||||
data: &mut [DirectoryEntry],
|
||||
) -> Result<usize, Errno> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: BlockAllocator + Copy + 'static> VnodeCommon for DirInode<A> {
|
||||
fn stat(&mut self, node: VnodeRef) -> Result<Stat, Errno> {
|
||||
let props = node.props();
|
||||
Ok(Stat {
|
||||
@@ -40,6 +55,35 @@ impl<A: BlockAllocator + Copy + 'static> VnodeImpl for DirInode<A> {
|
||||
mode: props.mode,
|
||||
})
|
||||
}
|
||||
|
||||
/// Performs filetype-specific request
|
||||
fn ioctl(
|
||||
&mut self,
|
||||
node: VnodeRef,
|
||||
cmd: IoctlCmd,
|
||||
ptr: usize,
|
||||
len: usize,
|
||||
) -> Result<usize, Errno> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Reports the size of this filesystem object in bytes
|
||||
fn size(&mut self, node: VnodeRef) -> Result<usize, Errno> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Returns `true` if node is ready for an operation
|
||||
fn is_ready(&mut self, node: VnodeRef, write: bool) -> Result<bool, Errno> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn open(&mut self, _node: VnodeRef, _flags: OpenFlags) -> Result<usize, Errno> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn close(&mut self, _node: VnodeRef) -> Result<(), Errno> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: BlockAllocator + Copy + 'static> DirInode<A> {
|
||||
|
||||
+35
-16
@@ -2,15 +2,16 @@ use crate::{BlockAllocator, Bvec};
|
||||
use libsys::{
|
||||
error::Errno,
|
||||
stat::{OpenFlags, Stat},
|
||||
ioctl::IoctlCmd
|
||||
};
|
||||
use vfs::{VnodeImpl, VnodeKind, VnodeRef};
|
||||
use vfs::{VnodeCommon, VnodeFile, VnodeRef};
|
||||
|
||||
pub struct FileInode<'a, A: BlockAllocator + Copy + 'static> {
|
||||
data: Bvec<'a, A>,
|
||||
}
|
||||
|
||||
#[auto_inode]
|
||||
impl<'a, A: BlockAllocator + Copy + 'static> VnodeImpl for FileInode<'a, A> {
|
||||
// #[auto_inode]
|
||||
impl<'a, A: BlockAllocator + Copy + 'static> VnodeCommon for FileInode<'a, A> {
|
||||
fn open(&mut self, _node: VnodeRef, _mode: OpenFlags) -> Result<usize, Errno> {
|
||||
Ok(0)
|
||||
}
|
||||
@@ -18,19 +19,6 @@ impl<'a, A: BlockAllocator + Copy + 'static> VnodeImpl for FileInode<'a, A> {
|
||||
fn close(&mut self, _node: VnodeRef) -> Result<(), Errno> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read(&mut self, _node: VnodeRef, pos: usize, data: &mut [u8]) -> Result<usize, Errno> {
|
||||
self.data.read(pos, data)
|
||||
}
|
||||
|
||||
fn write(&mut self, _node: VnodeRef, pos: usize, data: &[u8]) -> Result<usize, Errno> {
|
||||
self.data.write(pos, data)
|
||||
}
|
||||
|
||||
fn truncate(&mut self, _node: VnodeRef, size: usize) -> Result<(), Errno> {
|
||||
self.data.resize((size + 4095) / 4096)
|
||||
}
|
||||
|
||||
fn size(&mut self, _node: VnodeRef) -> Result<usize, Errno> {
|
||||
Ok(self.data.size())
|
||||
}
|
||||
@@ -43,6 +31,37 @@ impl<'a, A: BlockAllocator + Copy + 'static> VnodeImpl for FileInode<'a, A> {
|
||||
mode: props.mode
|
||||
})
|
||||
}
|
||||
|
||||
/// Performs filetype-specific request
|
||||
fn ioctl(
|
||||
&mut self,
|
||||
node: VnodeRef,
|
||||
cmd: IoctlCmd,
|
||||
ptr: usize,
|
||||
len: usize,
|
||||
) -> Result<usize, Errno> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Returns `true` if node is ready for an operation
|
||||
fn is_ready(&mut self, node: VnodeRef, write: bool) -> Result<bool, Errno> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, A: BlockAllocator + Copy + 'static> VnodeFile for FileInode<'a, A> {
|
||||
fn read(&mut self, _node: VnodeRef, pos: usize, data: &mut [u8]) -> Result<usize, Errno> {
|
||||
self.data.read(pos, data)
|
||||
}
|
||||
|
||||
fn write(&mut self, _node: VnodeRef, pos: usize, data: &[u8]) -> Result<usize, Errno> {
|
||||
self.data.write(pos, data)
|
||||
}
|
||||
|
||||
fn truncate(&mut self, _node: VnodeRef, size: usize) -> Result<(), Errno> {
|
||||
self.data.resize((size + 4095) / 4096)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl<'a, A: BlockAllocator + Copy + 'static> FileInode<'a, A> {
|
||||
|
||||
+29
-32
@@ -1,8 +1,4 @@
|
||||
#![feature(
|
||||
const_fn_trait_bound,
|
||||
const_mut_refs,
|
||||
maybe_uninit_uninit_array
|
||||
)]
|
||||
#![feature(const_fn_trait_bound, const_mut_refs, maybe_uninit_uninit_array)]
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
@@ -21,14 +17,14 @@ use libsys::{
|
||||
path::{path_component_left, path_component_right},
|
||||
stat::FileMode,
|
||||
};
|
||||
use vfs::{BlockDevice, Filesystem, Vnode, VnodeKind, VnodeRef};
|
||||
use vfs::{BlockDevice, Filesystem, Vnode, VnodeCreateKind, VnodeData, VnodeRef};
|
||||
|
||||
mod block;
|
||||
pub use block::{BlockAllocator, BlockRef};
|
||||
mod bvec;
|
||||
use bvec::Bvec;
|
||||
mod tar;
|
||||
use tar::{TarIterator, Tar};
|
||||
use tar::{Tar, TarIterator};
|
||||
mod file;
|
||||
use file::FileInode;
|
||||
mod dir;
|
||||
@@ -67,16 +63,17 @@ impl<A: BlockAllocator + Copy + 'static> Ramfs<A> {
|
||||
}
|
||||
|
||||
fn create_node_initial(self: Rc<Self>, name: &str, tar: &Tar) -> VnodeRef {
|
||||
let kind = tar.node_kind();
|
||||
let node = Vnode::new(name, kind, Vnode::SEEKABLE | Vnode::CACHE_READDIR);
|
||||
let kind = tar.node_create_kind();
|
||||
let data = match kind {
|
||||
VnodeCreateKind::Directory => {
|
||||
VnodeData::Directory(RefCell::new(Some(Box::new(DirInode::new(self.alloc)))))
|
||||
}
|
||||
VnodeCreateKind::File => VnodeData::File(RefCell::new(None)),
|
||||
_ => todo!(),
|
||||
};
|
||||
let node = Vnode::new(name, data, Vnode::SEEKABLE | Vnode::CACHE_READDIR);
|
||||
node.props_mut().mode = tar.mode();
|
||||
node.set_fs(self.clone());
|
||||
match kind {
|
||||
VnodeKind::Directory => node.set_data(Box::new(DirInode::new(self.alloc))),
|
||||
VnodeKind::Regular => {}
|
||||
VnodeKind::Char => todo!(),
|
||||
VnodeKind::Block => todo!(),
|
||||
};
|
||||
node
|
||||
}
|
||||
|
||||
@@ -100,7 +97,8 @@ impl<A: BlockAllocator + Copy + 'static> Ramfs<A> {
|
||||
return Err(Errno::DoesNotExist);
|
||||
}
|
||||
// TODO file modes
|
||||
at.create(element, FileMode::default_dir(), VnodeKind::Directory)?
|
||||
at.create(element, FileMode::default_dir(), VnodeCreateKind::Directory)?
|
||||
// todo!();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -112,9 +110,10 @@ impl<A: BlockAllocator + Copy + 'static> Ramfs<A> {
|
||||
}
|
||||
|
||||
unsafe fn load_tar(self: Rc<Self>, base: *const u8, size: usize) -> Result<VnodeRef, Errno> {
|
||||
let root = Vnode::new("", VnodeKind::Directory, Vnode::SEEKABLE | Vnode::CACHE_READDIR);
|
||||
let root_data =
|
||||
VnodeData::Directory(RefCell::new(Some(Box::new(DirInode::new(self.alloc)))));
|
||||
let root = Vnode::new("", root_data, Vnode::SEEKABLE | Vnode::CACHE_READDIR);
|
||||
root.set_fs(self.clone());
|
||||
root.set_data(Box::new(DirInode::new(self.alloc)));
|
||||
root.props_mut().mode = FileMode::default_dir();
|
||||
|
||||
// 1. Create all the paths in TAR
|
||||
@@ -122,10 +121,7 @@ impl<A: BlockAllocator + Copy + 'static> Ramfs<A> {
|
||||
let (dirname, basename) = path_component_right(block.path()?);
|
||||
|
||||
let parent = self.clone().make_path(root.clone(), dirname, true)?;
|
||||
let node = self
|
||||
.clone()
|
||||
.create_node_initial(basename, block);
|
||||
assert_eq!(node.kind(), block.node_kind());
|
||||
let node = self.clone().create_node_initial(basename, block);
|
||||
parent.attach(node);
|
||||
}
|
||||
|
||||
@@ -134,16 +130,17 @@ impl<A: BlockAllocator + Copy + 'static> Ramfs<A> {
|
||||
if block.is_file() {
|
||||
// Will not create any dirs
|
||||
let node = self.clone().make_path(root.clone(), block.path()?, false)?;
|
||||
assert_eq!(node.kind(), block.node_kind());
|
||||
|
||||
#[cfg(feature = "cow")]
|
||||
{
|
||||
let data = block.data();
|
||||
node.set_data(Box::new(FileInode::new(Bvec::new_copy_on_write(
|
||||
self.alloc,
|
||||
data.as_ptr(),
|
||||
data.len(),
|
||||
))));
|
||||
node.as_file()
|
||||
.unwrap()
|
||||
.replace(Some(Box::new(FileInode::new(Bvec::new_copy_on_write(
|
||||
self.alloc,
|
||||
data.as_ptr(),
|
||||
data.len(),
|
||||
)))));
|
||||
}
|
||||
#[cfg(not(feature = "cow"))]
|
||||
{
|
||||
@@ -166,7 +163,7 @@ impl<A: BlockAllocator + Copy + 'static> Ramfs<A> {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use alloc::boxed::Box;
|
||||
use libcommon::Read;
|
||||
use libsys::{traits::Read, stat::{UserId, GroupId, OpenFlags}};
|
||||
use vfs::Ioctx;
|
||||
|
||||
#[test]
|
||||
@@ -188,15 +185,15 @@ mod tests {
|
||||
let fs = unsafe { Ramfs::open(data.as_ptr(), data.bytes().len(), A {}).unwrap() };
|
||||
|
||||
let root = fs.root().unwrap();
|
||||
let ioctx = Ioctx::new(root.clone());
|
||||
let ioctx = Ioctx::new(root.clone(), UserId::root(), GroupId::root());
|
||||
|
||||
assert!(Rc::ptr_eq(&ioctx.find(None, "/", true).unwrap(), &root));
|
||||
|
||||
let node = ioctx.find(None, "/test1.txt", true).unwrap();
|
||||
let mut file = node.open().unwrap();
|
||||
let mut file = node.open(OpenFlags::O_RDONLY).unwrap();
|
||||
let mut buf = [0u8; 1024];
|
||||
|
||||
assert_eq!(file.read(&mut buf).unwrap(), 20);
|
||||
assert_eq!(file.borrow_mut().read(&mut buf).unwrap(), 20);
|
||||
let s = core::str::from_utf8(&buf[..20]).unwrap();
|
||||
assert_eq!(s, "This is a test file\n");
|
||||
}
|
||||
|
||||
+7
-7
@@ -1,5 +1,5 @@
|
||||
use libsys::{error::Errno, stat::FileMode};
|
||||
use vfs::VnodeKind;
|
||||
use vfs::{VnodeData, VnodeCreateKind};
|
||||
|
||||
#[repr(packed)]
|
||||
#[allow(dead_code)]
|
||||
@@ -73,18 +73,18 @@ impl Tar {
|
||||
core::str::from_utf8(&self.name[..zero_index]).map_err(|_| Errno::InvalidArgument)
|
||||
}
|
||||
|
||||
pub fn node_kind(&self) -> VnodeKind {
|
||||
pub fn node_create_kind(&self) -> VnodeCreateKind {
|
||||
match self.type_ {
|
||||
0 | b'0' => VnodeKind::Regular,
|
||||
b'5' => VnodeKind::Directory,
|
||||
0 | b'0' => VnodeCreateKind::File,
|
||||
b'5' => VnodeCreateKind::Directory,
|
||||
p => panic!("Unrecognized tar entry type: '{}'", p as char),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mode(&self) -> FileMode {
|
||||
let t = match self.node_kind() {
|
||||
VnodeKind::Regular => FileMode::S_IFREG,
|
||||
VnodeKind::Directory => FileMode::S_IFDIR,
|
||||
let t = match self.node_create_kind() {
|
||||
VnodeCreateKind::File => FileMode::S_IFREG,
|
||||
VnodeCreateKind::Directory => FileMode::S_IFDIR,
|
||||
_ => todo!()
|
||||
};
|
||||
FileMode::from_bits(from_octal(&self.mode) as u32).unwrap() | t
|
||||
|
||||
+48
-48
@@ -1,4 +1,4 @@
|
||||
use crate::{VnodeImpl, VnodeKind, VnodeRef};
|
||||
use crate::{VnodeData, VnodeRef};
|
||||
use libsys::{error::Errno, ioctl::IoctlCmd, stat::OpenFlags};
|
||||
|
||||
/// Generic character device trait
|
||||
@@ -22,50 +22,50 @@ pub trait CharDevice {
|
||||
/// Returns `true` if the device is ready for an operation
|
||||
fn is_ready(&self, write: bool) -> Result<bool, Errno>;
|
||||
}
|
||||
|
||||
/// Wrapper struct to attach [VnodeImpl] implementation
|
||||
/// to [CharDevice]s
|
||||
pub struct CharDeviceWrapper {
|
||||
device: &'static dyn CharDevice,
|
||||
}
|
||||
|
||||
#[auto_inode(error)]
|
||||
impl VnodeImpl for CharDeviceWrapper {
|
||||
fn open(&mut self, _node: VnodeRef, _opts: OpenFlags) -> Result<usize, Errno> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn close(&mut self, _node: VnodeRef) -> Result<(), Errno> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read(&mut self, _node: VnodeRef, _pos: usize, data: &mut [u8]) -> Result<usize, Errno> {
|
||||
self.device.read(true, data)
|
||||
}
|
||||
|
||||
fn write(&mut self, _node: VnodeRef, _pos: usize, data: &[u8]) -> Result<usize, Errno> {
|
||||
self.device.write(true, data)
|
||||
}
|
||||
|
||||
fn is_ready(&mut self, _node: VnodeRef, write: bool) -> Result<bool, Errno> {
|
||||
self.device.is_ready(write)
|
||||
}
|
||||
|
||||
fn ioctl(
|
||||
&mut self,
|
||||
_node: VnodeRef,
|
||||
cmd: IoctlCmd,
|
||||
ptr: usize,
|
||||
len: usize,
|
||||
) -> Result<usize, Errno> {
|
||||
self.device.ioctl(cmd, ptr, len)
|
||||
}
|
||||
}
|
||||
|
||||
impl CharDeviceWrapper {
|
||||
/// Creates a wrapper for static [CharDevice] trait object to
|
||||
/// auto-implement [VnodeImpl] trait for the device
|
||||
pub const fn new(device: &'static dyn CharDevice) -> Self {
|
||||
Self { device }
|
||||
}
|
||||
}
|
||||
//
|
||||
// /// Wrapper struct to attach [VnodeImpl] implementation
|
||||
// /// to [CharDevice]s
|
||||
// pub struct CharDeviceWrapper {
|
||||
// device: &'static dyn CharDevice,
|
||||
// }
|
||||
//
|
||||
// // #[auto_inode(error)]
|
||||
// impl VnodeCommon for CharDeviceWrapper {
|
||||
// fn open(&mut self, _node: VnodeRef, _opts: OpenFlags) -> Result<usize, Errno> {
|
||||
// Ok(0)
|
||||
// }
|
||||
//
|
||||
// fn close(&mut self, _node: VnodeRef) -> Result<(), Errno> {
|
||||
// Ok(())
|
||||
// }
|
||||
//
|
||||
// fn read(&mut self, _node: VnodeRef, _pos: usize, data: &mut [u8]) -> Result<usize, Errno> {
|
||||
// self.device.read(true, data)
|
||||
// }
|
||||
//
|
||||
// fn write(&mut self, _node: VnodeRef, _pos: usize, data: &[u8]) -> Result<usize, Errno> {
|
||||
// self.device.write(true, data)
|
||||
// }
|
||||
//
|
||||
// fn is_ready(&mut self, _node: VnodeRef, write: bool) -> Result<bool, Errno> {
|
||||
// self.device.is_ready(write)
|
||||
// }
|
||||
//
|
||||
// fn ioctl(
|
||||
// &mut self,
|
||||
// _node: VnodeRef,
|
||||
// cmd: IoctlCmd,
|
||||
// ptr: usize,
|
||||
// len: usize,
|
||||
// ) -> Result<usize, Errno> {
|
||||
// self.device.ioctl(cmd, ptr, len)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl CharDeviceWrapper {
|
||||
// /// Creates a wrapper for static [CharDevice] trait object to
|
||||
// /// auto-implement [VnodeImpl] trait for the device
|
||||
// pub const fn new(device: &'static dyn CharDevice) -> Self {
|
||||
// Self { device }
|
||||
// }
|
||||
// }
|
||||
|
||||
+52
-23
@@ -1,4 +1,4 @@
|
||||
use crate::{VnodeKind, VnodeRef, Vnode};
|
||||
use crate::{Vnode, VnodeData, VnodeRef};
|
||||
use alloc::rc::Rc;
|
||||
use core::cell::RefCell;
|
||||
use core::cmp::min;
|
||||
@@ -39,9 +39,10 @@ impl Read for File {
|
||||
match &mut self.inner {
|
||||
FileInner::Normal(inner) => {
|
||||
let count = inner.vnode.read(inner.pos, data)?;
|
||||
if inner.vnode.kind() != VnodeKind::Char {
|
||||
inner.pos += count;
|
||||
}
|
||||
// TODO
|
||||
// if inner.vnode.kind() != VnodeKind::Char {
|
||||
inner.pos += count;
|
||||
// }
|
||||
Ok(count)
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
@@ -58,9 +59,10 @@ impl Write for File {
|
||||
match &mut self.inner {
|
||||
FileInner::Normal(inner) => {
|
||||
let count = inner.vnode.write(inner.pos, data)?;
|
||||
if inner.vnode.kind() != VnodeKind::Char {
|
||||
inner.pos += count;
|
||||
}
|
||||
// TODO
|
||||
// if inner.vnode.kind() != VnodeKind::Char {
|
||||
inner.pos += count;
|
||||
// }
|
||||
Ok(count)
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
@@ -134,7 +136,10 @@ impl File {
|
||||
}
|
||||
}
|
||||
|
||||
fn cache_readdir(inner: &mut NormalFile, entries: &mut [DirectoryEntry]) -> Result<usize, Errno> {
|
||||
fn cache_readdir(
|
||||
inner: &mut NormalFile,
|
||||
entries: &mut [DirectoryEntry],
|
||||
) -> Result<usize, Errno> {
|
||||
let mut count = entries.len();
|
||||
let mut offset = 0usize;
|
||||
|
||||
@@ -177,7 +182,7 @@ impl File {
|
||||
pub fn readdir(&mut self, entries: &mut [DirectoryEntry]) -> Result<usize, Errno> {
|
||||
match &mut self.inner {
|
||||
FileInner::Normal(inner) => {
|
||||
assert_eq!(inner.vnode.kind(), VnodeKind::Directory);
|
||||
// assert_eq!(inner.vnode.kind(), VnodeKind::Directory);
|
||||
|
||||
if inner.vnode.flags() & Vnode::CACHE_READDIR != 0 {
|
||||
Self::cache_readdir(inner, entries)
|
||||
@@ -204,24 +209,38 @@ impl Drop for File {
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{Vnode, VnodeImpl, VnodeKind, VnodeRef};
|
||||
use libsys::{stat::OpenFlags, ioctl::IoctlCmd, stat::Stat};
|
||||
use alloc::boxed::Box;
|
||||
use alloc::rc::Rc;
|
||||
use crate::node::{VnodeCommon, VnodeFile};
|
||||
use libsys::{ioctl::IoctlCmd, stat::OpenFlags, stat::Stat};
|
||||
|
||||
struct DummyInode;
|
||||
|
||||
#[auto_inode]
|
||||
impl VnodeImpl for DummyInode {
|
||||
fn create(
|
||||
impl VnodeCommon for DummyInode {
|
||||
/// Performs filetype-specific request
|
||||
fn ioctl(
|
||||
&mut self,
|
||||
_at: VnodeRef,
|
||||
name: &str,
|
||||
kind: VnodeKind,
|
||||
) -> Result<VnodeRef, Errno> {
|
||||
let node = Vnode::new(name, kind, 0);
|
||||
node.set_data(Box::new(DummyInode {}));
|
||||
Ok(node)
|
||||
node: VnodeRef,
|
||||
cmd: IoctlCmd,
|
||||
ptr: usize,
|
||||
len: usize,
|
||||
) -> Result<usize, Errno> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Retrieves file status
|
||||
fn stat(&mut self, node: VnodeRef) -> Result<Stat, Errno> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Reports the size of this filesystem object in bytes
|
||||
fn size(&mut self, node: VnodeRef) -> Result<usize, Errno> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Returns `true` if node is ready for an operation
|
||||
fn is_ready(&mut self, node: VnodeRef, write: bool) -> Result<bool, Errno> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn open(&mut self, _node: VnodeRef, _flags: OpenFlags) -> Result<usize, Errno> {
|
||||
@@ -232,6 +251,9 @@ mod tests {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl VnodeFile for DummyInode {
|
||||
fn read(&mut self, _node: VnodeRef, pos: usize, data: &mut [u8]) -> Result<usize, Errno> {
|
||||
#[cfg(test)]
|
||||
println!("read {} at {}", data.len(), pos);
|
||||
@@ -249,12 +271,19 @@ mod tests {
|
||||
fn write(&mut self, _node: VnodeRef, _pos: usize, _data: &[u8]) -> Result<usize, Errno> {
|
||||
Err(Errno::NotImplemented)
|
||||
}
|
||||
|
||||
fn truncate(&mut self, node: VnodeRef, size: usize) -> Result<(), Errno> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_normal_read() {
|
||||
let node = Vnode::new("", VnodeKind::Regular, 0);
|
||||
node.set_data(Box::new(DummyInode {}));
|
||||
let node = Vnode::new(
|
||||
"",
|
||||
VnodeData::File(RefCell::new(Some(Box::new(DummyInode {})))),
|
||||
0,
|
||||
);
|
||||
let mut file = node.open(OpenFlags::O_RDONLY).unwrap();
|
||||
let mut buf = [0u8; 4096];
|
||||
|
||||
|
||||
+209
-206
@@ -1,4 +1,4 @@
|
||||
use crate::{FileRef, VnodeKind, VnodeRef};
|
||||
use crate::{FileRef, VnodeData, VnodeRef, VnodeCreateKind};
|
||||
use libsys::{
|
||||
error::Errno,
|
||||
path::{path_component_left, path_component_right},
|
||||
@@ -34,9 +34,10 @@ impl Ioctx {
|
||||
loop {
|
||||
(element, rest) = path_component_left(rest);
|
||||
|
||||
if !at.is_directory() {
|
||||
return Err(Errno::NotADirectory);
|
||||
}
|
||||
at.as_directory()?;
|
||||
// if !at.is_directory() {
|
||||
// return Err(Errno::NotADirectory);
|
||||
// }
|
||||
|
||||
match element {
|
||||
".." => {
|
||||
@@ -48,7 +49,7 @@ impl Ioctx {
|
||||
}
|
||||
|
||||
while let Some(target) = at.target() {
|
||||
assert!(at.kind() == VnodeKind::Directory);
|
||||
// assert!(at.kind() == VnodeKind::Directory);
|
||||
at = target;
|
||||
}
|
||||
|
||||
@@ -60,7 +61,7 @@ impl Ioctx {
|
||||
let mut node = at.lookup_or_load(element)?;
|
||||
|
||||
while let Some(target) = node.target() {
|
||||
assert!(node.kind() == VnodeKind::Directory);
|
||||
// assert!(node.kind() == VnodeKind::Directory);
|
||||
node = target;
|
||||
}
|
||||
|
||||
@@ -97,12 +98,13 @@ impl Ioctx {
|
||||
path: &str,
|
||||
mode: FileMode,
|
||||
) -> Result<VnodeRef, Errno> {
|
||||
let (parent, name) = path_component_right(path);
|
||||
self.find(at, parent, true)?.create(
|
||||
name.trim_start_matches('/'),
|
||||
mode,
|
||||
VnodeKind::Directory,
|
||||
)
|
||||
todo!()
|
||||
// let (parent, name) = path_component_right(path);
|
||||
// self.find(at, parent, true)?.create(
|
||||
// name.trim_start_matches('/'),
|
||||
// mode,
|
||||
// VnodeKind::Directory,
|
||||
// )
|
||||
}
|
||||
|
||||
/// Opens (and possibly creates) a filesystem path for access
|
||||
@@ -117,7 +119,7 @@ impl Ioctx {
|
||||
Err(Errno::DoesNotExist) => {
|
||||
let (parent, name) = path_component_right(path);
|
||||
let at = self.find(at, parent, true)?;
|
||||
at.create(name, mode, VnodeKind::Regular)
|
||||
at.create(name, mode, VnodeCreateKind::File)
|
||||
}
|
||||
o => o,
|
||||
}?;
|
||||
@@ -127,199 +129,200 @@ impl Ioctx {
|
||||
|
||||
/// Changes current working directory of the process
|
||||
pub fn chdir(&mut self, path: &str) -> Result<(), Errno> {
|
||||
let node = self.find(None, path, true)?;
|
||||
if !node.is_directory() {
|
||||
return Err(Errno::NotADirectory);
|
||||
}
|
||||
self.cwd = node;
|
||||
Ok(())
|
||||
todo!()
|
||||
// let node = self.find(None, path, true)?;
|
||||
// if !node.is_directory() {
|
||||
// return Err(Errno::NotADirectory);
|
||||
// }
|
||||
// self.cwd = node;
|
||||
// Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{Vnode, VnodeImpl, VnodeKind};
|
||||
use alloc::{boxed::Box, rc::Rc};
|
||||
use libsys::{ioctl::IoctlCmd, stat::OpenFlags, stat::Stat};
|
||||
|
||||
pub struct DummyInode;
|
||||
|
||||
#[auto_inode]
|
||||
impl VnodeImpl for DummyInode {
|
||||
fn create(
|
||||
&mut self,
|
||||
_at: VnodeRef,
|
||||
name: &str,
|
||||
kind: VnodeKind,
|
||||
) -> Result<VnodeRef, Errno> {
|
||||
let vnode = Vnode::new(name, kind, 0);
|
||||
vnode.set_data(Box::new(DummyInode {}));
|
||||
Ok(vnode)
|
||||
}
|
||||
|
||||
fn lookup(&mut self, _at: VnodeRef, _name: &str) -> Result<VnodeRef, Errno> {
|
||||
Err(Errno::DoesNotExist)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_existing_absolute() {
|
||||
let root = Vnode::new("", VnodeKind::Directory, 0);
|
||||
let d0 = Vnode::new("dir0", VnodeKind::Directory, 0);
|
||||
let d1 = Vnode::new("dir1", VnodeKind::Directory, 0);
|
||||
let d0d0 = Vnode::new("dir0", VnodeKind::Directory, 0);
|
||||
let d0f0 = Vnode::new("file0", VnodeKind::Regular, 0);
|
||||
let d1f0 = Vnode::new("file0", VnodeKind::Regular, 0);
|
||||
|
||||
root.attach(d0.clone());
|
||||
root.attach(d1.clone());
|
||||
d0.attach(d0d0.clone());
|
||||
d0.attach(d0f0.clone());
|
||||
d1.attach(d1f0.clone());
|
||||
|
||||
let ioctx = Ioctx::new(root.clone());
|
||||
|
||||
assert!(Rc::ptr_eq(&root, &ioctx.find(None, "/", false).unwrap()));
|
||||
assert!(Rc::ptr_eq(&root, &ioctx.find(None, "/.", false).unwrap()));
|
||||
assert!(Rc::ptr_eq(&root, &ioctx.find(None, "/./.", false).unwrap()));
|
||||
assert!(Rc::ptr_eq(
|
||||
&root,
|
||||
&ioctx.find(None, "/.///.", false).unwrap()
|
||||
));
|
||||
assert!(Rc::ptr_eq(&root, &ioctx.find(None, "/..", false).unwrap()));
|
||||
assert!(Rc::ptr_eq(&root, &ioctx.find(None, "/../", false).unwrap()));
|
||||
assert!(Rc::ptr_eq(
|
||||
&root,
|
||||
&ioctx.find(None, "/../.", false).unwrap()
|
||||
));
|
||||
assert!(Rc::ptr_eq(
|
||||
&root,
|
||||
&ioctx.find(None, "/../..", false).unwrap()
|
||||
));
|
||||
|
||||
assert!(Rc::ptr_eq(&d0, &ioctx.find(None, "/dir0", false).unwrap()));
|
||||
assert!(Rc::ptr_eq(&d1, &ioctx.find(None, "/dir1", false).unwrap()));
|
||||
assert!(Rc::ptr_eq(
|
||||
&d0,
|
||||
&ioctx.find(None, "/dir1/../dir0", false).unwrap()
|
||||
));
|
||||
assert!(Rc::ptr_eq(
|
||||
&d1,
|
||||
&ioctx
|
||||
.find(None, "/dir1/../dir0/./../../.././dir1", false)
|
||||
.unwrap()
|
||||
));
|
||||
|
||||
assert!(Rc::ptr_eq(
|
||||
&d0d0,
|
||||
&ioctx.find(None, "/dir0/dir0", false).unwrap()
|
||||
));
|
||||
assert!(Rc::ptr_eq(
|
||||
&d0d0,
|
||||
&ioctx.find(None, "/dir0/dir0/.", false).unwrap()
|
||||
));
|
||||
assert!(Rc::ptr_eq(
|
||||
&d0,
|
||||
&ioctx.find(None, "/dir0/dir0/..", false).unwrap()
|
||||
));
|
||||
assert!(Rc::ptr_eq(
|
||||
&d0,
|
||||
&ioctx.find(None, "/dir0/dir0/../", false).unwrap()
|
||||
));
|
||||
assert!(Rc::ptr_eq(
|
||||
&d0,
|
||||
&ioctx.find(None, "/dir0/dir0/../.", false).unwrap()
|
||||
));
|
||||
|
||||
assert!(Rc::ptr_eq(
|
||||
&d0f0,
|
||||
&ioctx.find(None, "/dir0/file0", false).unwrap()
|
||||
));
|
||||
assert!(Rc::ptr_eq(
|
||||
&d0f0,
|
||||
&ioctx.find(None, "/dir1/../dir0/./file0", false).unwrap()
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_rejects_file_dots() {
|
||||
let root = Vnode::new("", VnodeKind::Directory, 0);
|
||||
let d0 = Vnode::new("dir0", VnodeKind::Directory, 0);
|
||||
let d0f0 = Vnode::new("file0", VnodeKind::Regular, 0);
|
||||
|
||||
root.attach(d0.clone());
|
||||
d0.attach(d0f0.clone());
|
||||
|
||||
let ioctx = Ioctx::new(root.clone());
|
||||
|
||||
assert_eq!(
|
||||
ioctx.find(None, "/dir0/file0/.", false).unwrap_err(),
|
||||
Errno::NotADirectory
|
||||
);
|
||||
assert_eq!(
|
||||
ioctx.find(None, "/dir0/file0/..", false).unwrap_err(),
|
||||
Errno::NotADirectory
|
||||
);
|
||||
|
||||
// TODO handle this case
|
||||
// assert_eq!(ioctx.find(None, "/dir0/file0/").unwrap_err(), Errno::NotADirectory);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mkdir() {
|
||||
let root = Vnode::new("", VnodeKind::Directory, 0);
|
||||
let ioctx = Ioctx::new(root.clone());
|
||||
|
||||
root.set_data(Box::new(DummyInode {}));
|
||||
|
||||
assert!(ioctx.mkdir(None, "/dir0", FileMode::default_dir()).is_ok());
|
||||
assert_eq!(
|
||||
ioctx
|
||||
.mkdir(None, "/dir0", FileMode::default_dir())
|
||||
.unwrap_err(),
|
||||
Errno::AlreadyExists
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_find_mount() {
|
||||
let root_outer = Vnode::new("", VnodeKind::Directory, 0);
|
||||
let dir0 = Vnode::new("dir0", VnodeKind::Directory, 0);
|
||||
let root_inner = Vnode::new("", VnodeKind::Directory, 0);
|
||||
let dir1 = Vnode::new("dir1", VnodeKind::Directory, 0);
|
||||
|
||||
root_outer.clone().attach(dir0.clone());
|
||||
root_inner.clone().attach(dir1.clone());
|
||||
|
||||
let ioctx = Ioctx::new(root_outer.clone());
|
||||
|
||||
assert_eq!(
|
||||
ioctx.find(None, "/dir0/dir1", false).unwrap_err(),
|
||||
Errno::DoesNotExist
|
||||
);
|
||||
|
||||
dir0.mount(root_inner.clone()).unwrap();
|
||||
|
||||
assert!(Rc::ptr_eq(
|
||||
&root_inner,
|
||||
&ioctx.find(None, "/dir0", false).unwrap()
|
||||
));
|
||||
assert!(Rc::ptr_eq(
|
||||
&dir1,
|
||||
&ioctx.find(None, "/dir0/dir1", false).unwrap()
|
||||
));
|
||||
assert!(Rc::ptr_eq(
|
||||
&root_inner,
|
||||
&ioctx.find(None, "/dir0/dir1/..", false).unwrap()
|
||||
));
|
||||
assert!(Rc::ptr_eq(
|
||||
&dir0,
|
||||
&ioctx.find(None, "/dir0/dir1/../..", false).unwrap()
|
||||
));
|
||||
assert!(Rc::ptr_eq(
|
||||
&root_outer,
|
||||
&ioctx.find(None, "/dir0/dir1/../../..", false).unwrap()
|
||||
));
|
||||
}
|
||||
}
|
||||
// #[cfg(test)]
|
||||
// mod tests {
|
||||
// use super::*;
|
||||
// use crate::{Vnode, VnodeImpl, VnodeKind};
|
||||
// use alloc::{boxed::Box, rc::Rc};
|
||||
// use libsys::{ioctl::IoctlCmd, stat::OpenFlags, stat::Stat};
|
||||
//
|
||||
// pub struct DummyInode;
|
||||
//
|
||||
// #[auto_inode]
|
||||
// impl VnodeImpl for DummyInode {
|
||||
// fn create(
|
||||
// &mut self,
|
||||
// _at: VnodeRef,
|
||||
// name: &str,
|
||||
// kind: VnodeKind,
|
||||
// ) -> Result<VnodeRef, Errno> {
|
||||
// let vnode = Vnode::new(name, kind, 0);
|
||||
// vnode.set_data(Box::new(DummyInode {}));
|
||||
// Ok(vnode)
|
||||
// }
|
||||
//
|
||||
// fn lookup(&mut self, _at: VnodeRef, _name: &str) -> Result<VnodeRef, Errno> {
|
||||
// Err(Errno::DoesNotExist)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn test_find_existing_absolute() {
|
||||
// let root = Vnode::new("", VnodeKind::Directory, 0);
|
||||
// let d0 = Vnode::new("dir0", VnodeKind::Directory, 0);
|
||||
// let d1 = Vnode::new("dir1", VnodeKind::Directory, 0);
|
||||
// let d0d0 = Vnode::new("dir0", VnodeKind::Directory, 0);
|
||||
// let d0f0 = Vnode::new("file0", VnodeKind::Regular, 0);
|
||||
// let d1f0 = Vnode::new("file0", VnodeKind::Regular, 0);
|
||||
//
|
||||
// root.attach(d0.clone());
|
||||
// root.attach(d1.clone());
|
||||
// d0.attach(d0d0.clone());
|
||||
// d0.attach(d0f0.clone());
|
||||
// d1.attach(d1f0.clone());
|
||||
//
|
||||
// let ioctx = Ioctx::new(root.clone());
|
||||
//
|
||||
// assert!(Rc::ptr_eq(&root, &ioctx.find(None, "/", false).unwrap()));
|
||||
// assert!(Rc::ptr_eq(&root, &ioctx.find(None, "/.", false).unwrap()));
|
||||
// assert!(Rc::ptr_eq(&root, &ioctx.find(None, "/./.", false).unwrap()));
|
||||
// assert!(Rc::ptr_eq(
|
||||
// &root,
|
||||
// &ioctx.find(None, "/.///.", false).unwrap()
|
||||
// ));
|
||||
// assert!(Rc::ptr_eq(&root, &ioctx.find(None, "/..", false).unwrap()));
|
||||
// assert!(Rc::ptr_eq(&root, &ioctx.find(None, "/../", false).unwrap()));
|
||||
// assert!(Rc::ptr_eq(
|
||||
// &root,
|
||||
// &ioctx.find(None, "/../.", false).unwrap()
|
||||
// ));
|
||||
// assert!(Rc::ptr_eq(
|
||||
// &root,
|
||||
// &ioctx.find(None, "/../..", false).unwrap()
|
||||
// ));
|
||||
//
|
||||
// assert!(Rc::ptr_eq(&d0, &ioctx.find(None, "/dir0", false).unwrap()));
|
||||
// assert!(Rc::ptr_eq(&d1, &ioctx.find(None, "/dir1", false).unwrap()));
|
||||
// assert!(Rc::ptr_eq(
|
||||
// &d0,
|
||||
// &ioctx.find(None, "/dir1/../dir0", false).unwrap()
|
||||
// ));
|
||||
// assert!(Rc::ptr_eq(
|
||||
// &d1,
|
||||
// &ioctx
|
||||
// .find(None, "/dir1/../dir0/./../../.././dir1", false)
|
||||
// .unwrap()
|
||||
// ));
|
||||
//
|
||||
// assert!(Rc::ptr_eq(
|
||||
// &d0d0,
|
||||
// &ioctx.find(None, "/dir0/dir0", false).unwrap()
|
||||
// ));
|
||||
// assert!(Rc::ptr_eq(
|
||||
// &d0d0,
|
||||
// &ioctx.find(None, "/dir0/dir0/.", false).unwrap()
|
||||
// ));
|
||||
// assert!(Rc::ptr_eq(
|
||||
// &d0,
|
||||
// &ioctx.find(None, "/dir0/dir0/..", false).unwrap()
|
||||
// ));
|
||||
// assert!(Rc::ptr_eq(
|
||||
// &d0,
|
||||
// &ioctx.find(None, "/dir0/dir0/../", false).unwrap()
|
||||
// ));
|
||||
// assert!(Rc::ptr_eq(
|
||||
// &d0,
|
||||
// &ioctx.find(None, "/dir0/dir0/../.", false).unwrap()
|
||||
// ));
|
||||
//
|
||||
// assert!(Rc::ptr_eq(
|
||||
// &d0f0,
|
||||
// &ioctx.find(None, "/dir0/file0", false).unwrap()
|
||||
// ));
|
||||
// assert!(Rc::ptr_eq(
|
||||
// &d0f0,
|
||||
// &ioctx.find(None, "/dir1/../dir0/./file0", false).unwrap()
|
||||
// ));
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn test_find_rejects_file_dots() {
|
||||
// let root = Vnode::new("", VnodeKind::Directory, 0);
|
||||
// let d0 = Vnode::new("dir0", VnodeKind::Directory, 0);
|
||||
// let d0f0 = Vnode::new("file0", VnodeKind::Regular, 0);
|
||||
//
|
||||
// root.attach(d0.clone());
|
||||
// d0.attach(d0f0.clone());
|
||||
//
|
||||
// let ioctx = Ioctx::new(root.clone());
|
||||
//
|
||||
// assert_eq!(
|
||||
// ioctx.find(None, "/dir0/file0/.", false).unwrap_err(),
|
||||
// Errno::NotADirectory
|
||||
// );
|
||||
// assert_eq!(
|
||||
// ioctx.find(None, "/dir0/file0/..", false).unwrap_err(),
|
||||
// Errno::NotADirectory
|
||||
// );
|
||||
//
|
||||
// // TODO handle this case
|
||||
// // assert_eq!(ioctx.find(None, "/dir0/file0/").unwrap_err(), Errno::NotADirectory);
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn test_mkdir() {
|
||||
// let root = Vnode::new("", VnodeKind::Directory, 0);
|
||||
// let ioctx = Ioctx::new(root.clone());
|
||||
//
|
||||
// root.set_data(Box::new(DummyInode {}));
|
||||
//
|
||||
// assert!(ioctx.mkdir(None, "/dir0", FileMode::default_dir()).is_ok());
|
||||
// assert_eq!(
|
||||
// ioctx
|
||||
// .mkdir(None, "/dir0", FileMode::default_dir())
|
||||
// .unwrap_err(),
|
||||
// Errno::AlreadyExists
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// #[test]
|
||||
// fn test_find_mount() {
|
||||
// let root_outer = Vnode::new("", VnodeKind::Directory, 0);
|
||||
// let dir0 = Vnode::new("dir0", VnodeKind::Directory, 0);
|
||||
// let root_inner = Vnode::new("", VnodeKind::Directory, 0);
|
||||
// let dir1 = Vnode::new("dir1", VnodeKind::Directory, 0);
|
||||
//
|
||||
// root_outer.clone().attach(dir0.clone());
|
||||
// root_inner.clone().attach(dir1.clone());
|
||||
//
|
||||
// let ioctx = Ioctx::new(root_outer.clone());
|
||||
//
|
||||
// assert_eq!(
|
||||
// ioctx.find(None, "/dir0/dir1", false).unwrap_err(),
|
||||
// Errno::DoesNotExist
|
||||
// );
|
||||
//
|
||||
// dir0.mount(root_inner.clone()).unwrap();
|
||||
//
|
||||
// assert!(Rc::ptr_eq(
|
||||
// &root_inner,
|
||||
// &ioctx.find(None, "/dir0", false).unwrap()
|
||||
// ));
|
||||
// assert!(Rc::ptr_eq(
|
||||
// &dir1,
|
||||
// &ioctx.find(None, "/dir0/dir1", false).unwrap()
|
||||
// ));
|
||||
// assert!(Rc::ptr_eq(
|
||||
// &root_inner,
|
||||
// &ioctx.find(None, "/dir0/dir1/..", false).unwrap()
|
||||
// ));
|
||||
// assert!(Rc::ptr_eq(
|
||||
// &dir0,
|
||||
// &ioctx.find(None, "/dir0/dir1/../..", false).unwrap()
|
||||
// ));
|
||||
// assert!(Rc::ptr_eq(
|
||||
// &root_outer,
|
||||
// &ioctx.find(None, "/dir0/dir1/../../..", false).unwrap()
|
||||
// ));
|
||||
// }
|
||||
// }
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
//! Virtual filesystem API and facilities
|
||||
#![warn(missing_docs)]
|
||||
#![feature(const_fn_trait_bound)]
|
||||
#![feature(const_fn_trait_bound, const_discriminant)]
|
||||
#![no_std]
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -20,10 +20,10 @@ pub use block::BlockDevice;
|
||||
mod fs;
|
||||
pub use fs::Filesystem;
|
||||
mod node;
|
||||
pub use node::{Vnode, VnodeImpl, VnodeKind, VnodeRef};
|
||||
pub use node::{Vnode, VnodeData, VnodeRef, VnodeCreateKind, VnodeCommon, VnodeFile, VnodeDirectory};
|
||||
mod ioctx;
|
||||
pub use ioctx::Ioctx;
|
||||
mod file;
|
||||
pub use file::{File, FileRef};
|
||||
mod char;
|
||||
pub use crate::char::{CharDevice, CharDeviceWrapper};
|
||||
pub use crate::char::CharDevice;
|
||||
|
||||
+338
-195
@@ -1,7 +1,9 @@
|
||||
use crate::{File, FileRef, Filesystem, Ioctx};
|
||||
use crate::{File, FileRef, Filesystem, Ioctx, CharDevice, BlockDevice};
|
||||
use alloc::{borrow::ToOwned, boxed::Box, rc::Rc, string::String, vec::Vec};
|
||||
use core::borrow::BorrowMut;
|
||||
use core::cell::{Ref, RefCell, RefMut};
|
||||
use core::fmt;
|
||||
use core::mem::Discriminant;
|
||||
use libsys::{
|
||||
error::Errno,
|
||||
ioctl::IoctlCmd,
|
||||
@@ -10,20 +12,75 @@ use libsys::{
|
||||
|
||||
/// Convenience type alias for [Rc<Vnode>]
|
||||
pub type VnodeRef = Rc<Vnode>;
|
||||
pub type VnodeKind = Discriminant<VnodeData>;
|
||||
|
||||
/// List of possible vnode types
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum VnodeKind {
|
||||
/// Node is a directory with create/lookup/remove operations
|
||||
Directory,
|
||||
/// Node is a regular file
|
||||
Regular,
|
||||
/// Node is a character device
|
||||
Char,
|
||||
/// Node is a block device
|
||||
Block,
|
||||
pub trait VnodeCommon {
|
||||
/// Performs filetype-specific request
|
||||
fn ioctl(
|
||||
&mut self,
|
||||
node: VnodeRef,
|
||||
cmd: IoctlCmd,
|
||||
ptr: usize,
|
||||
len: usize,
|
||||
) -> Result<usize, Errno>;
|
||||
|
||||
/// Retrieves file status
|
||||
fn stat(&mut self, node: VnodeRef) -> Result<Stat, Errno>;
|
||||
|
||||
/// Reports the size of this filesystem object in bytes
|
||||
fn size(&mut self, node: VnodeRef) -> Result<usize, Errno>;
|
||||
|
||||
/// Returns `true` if node is ready for an operation
|
||||
fn is_ready(&mut self, node: VnodeRef, write: bool) -> Result<bool, Errno>;
|
||||
|
||||
/// Opens a vnode for access. Returns initial file position.
|
||||
fn open(&mut self, node: VnodeRef, opts: OpenFlags) -> Result<usize, Errno>;
|
||||
/// Closes a vnode
|
||||
fn close(&mut self, node: VnodeRef) -> Result<(), Errno>;
|
||||
}
|
||||
|
||||
pub trait VnodeFile: VnodeCommon {
|
||||
/// Changes file's underlying storage size
|
||||
fn truncate(&mut self, node: VnodeRef, size: usize) -> Result<(), Errno>;
|
||||
/// Reads `data.len()` bytes into the buffer from file offset `pos`
|
||||
fn read(&mut self, node: VnodeRef, pos: usize, data: &mut [u8]) -> Result<usize, Errno>;
|
||||
/// Writes `data.len()` bytes from the buffer to file offset `pos`.
|
||||
/// Resizes the file storage if necessary.
|
||||
fn write(&mut self, node: VnodeRef, pos: usize, data: &[u8]) -> Result<usize, Errno>;
|
||||
}
|
||||
|
||||
pub trait VnodeDirectory: VnodeCommon {
|
||||
fn create(
|
||||
&mut self,
|
||||
at: VnodeRef,
|
||||
name: &str,
|
||||
kind: VnodeCreateKind,
|
||||
) -> Result<VnodeRef, Errno>;
|
||||
fn remove(&mut self, at: VnodeRef, name: &str) -> Result<(), Errno>;
|
||||
fn lookup(&mut self, at: VnodeRef, name: &str) -> Result<VnodeRef, Errno>;
|
||||
|
||||
/// Read directory entries into target buffer
|
||||
fn readdir(
|
||||
&mut self,
|
||||
node: VnodeRef,
|
||||
pos: usize,
|
||||
data: &mut [DirectoryEntry],
|
||||
) -> Result<usize, Errno>;
|
||||
}
|
||||
|
||||
// /// List of possible vnode types
|
||||
// #[derive(Debug, Clone, Copy, PartialEq)]
|
||||
// pub enum VnodeKind {
|
||||
// /// Node is a directory with create/lookup/remove operations
|
||||
// Directory,
|
||||
// /// Node is a regular file
|
||||
// Regular,
|
||||
// /// Node is a character device
|
||||
// Char,
|
||||
// /// Node is a block device
|
||||
// Block,
|
||||
// }
|
||||
|
||||
pub(crate) struct TreeNode {
|
||||
parent: Option<VnodeRef>,
|
||||
children: Vec<VnodeRef>,
|
||||
@@ -35,6 +92,18 @@ pub struct VnodeProps {
|
||||
pub mode: FileMode,
|
||||
}
|
||||
|
||||
pub enum VnodeData {
|
||||
Directory(RefCell<Option<Box<dyn VnodeDirectory>>>),
|
||||
File(RefCell<Option<Box<dyn VnodeFile>>>),
|
||||
Char(&'static dyn CharDevice)
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum VnodeCreateKind {
|
||||
Directory,
|
||||
File,
|
||||
}
|
||||
|
||||
/// Virtual filesystem node struct, generalizes access to
|
||||
/// underlying real filesystems
|
||||
pub struct Vnode {
|
||||
@@ -42,64 +111,13 @@ pub struct Vnode {
|
||||
tree: RefCell<TreeNode>,
|
||||
props: RefCell<VnodeProps>,
|
||||
|
||||
kind: VnodeKind,
|
||||
// kind: VnodeKind,
|
||||
data: VnodeData,
|
||||
flags: u32,
|
||||
|
||||
target: RefCell<Option<VnodeRef>>,
|
||||
fs: RefCell<Option<Rc<dyn Filesystem>>>,
|
||||
data: RefCell<Option<Box<dyn VnodeImpl>>>,
|
||||
}
|
||||
|
||||
/// Interface for "inode" of a real filesystem
|
||||
pub trait VnodeImpl {
|
||||
// Directory-only operations
|
||||
/// Creates a new vnode, sets it up, attaches it (in real FS) to `at` with `name` and
|
||||
/// returns it
|
||||
fn create(&mut self, at: VnodeRef, name: &str, kind: VnodeKind) -> Result<VnodeRef, Errno>;
|
||||
/// Removes the filesystem inode from its parent by erasing its directory entry
|
||||
fn remove(&mut self, at: VnodeRef, name: &str) -> Result<(), Errno>;
|
||||
/// Looks up a corresponding directory entry for `name`. If present, loads its inode from
|
||||
/// storage medium and returns a new vnode associated with it.
|
||||
fn lookup(&mut self, at: VnodeRef, name: &str) -> Result<VnodeRef, Errno>;
|
||||
|
||||
/// Opens a vnode for access. Returns initial file position.
|
||||
fn open(&mut self, node: VnodeRef, opts: OpenFlags) -> Result<usize, Errno>;
|
||||
/// Closes a vnode
|
||||
fn close(&mut self, node: VnodeRef) -> Result<(), Errno>;
|
||||
|
||||
/// Changes file's underlying storage size
|
||||
fn truncate(&mut self, node: VnodeRef, size: usize) -> Result<(), Errno>;
|
||||
/// Reads `data.len()` bytes into the buffer from file offset `pos`
|
||||
fn read(&mut self, node: VnodeRef, pos: usize, data: &mut [u8]) -> Result<usize, Errno>;
|
||||
/// Writes `data.len()` bytes from the buffer to file offset `pos`.
|
||||
/// Resizes the file storage if necessary.
|
||||
fn write(&mut self, node: VnodeRef, pos: usize, data: &[u8]) -> Result<usize, Errno>;
|
||||
|
||||
/// Read directory entries into target buffer
|
||||
fn readdir(
|
||||
&mut self,
|
||||
node: VnodeRef,
|
||||
pos: usize,
|
||||
data: &mut [DirectoryEntry],
|
||||
) -> Result<usize, Errno>;
|
||||
|
||||
/// Retrieves file status
|
||||
fn stat(&mut self, node: VnodeRef) -> Result<Stat, Errno>;
|
||||
|
||||
/// Reports the size of this filesystem object in bytes
|
||||
fn size(&mut self, node: VnodeRef) -> Result<usize, Errno>;
|
||||
|
||||
/// Returns `true` if node is ready for an operation
|
||||
fn is_ready(&mut self, node: VnodeRef, write: bool) -> Result<bool, Errno>;
|
||||
|
||||
/// Performs filetype-specific request
|
||||
fn ioctl(
|
||||
&mut self,
|
||||
node: VnodeRef,
|
||||
cmd: IoctlCmd,
|
||||
ptr: usize,
|
||||
len: usize,
|
||||
) -> Result<usize, Errno>;
|
||||
// data: RefCell<Option<Box<dyn VnodeImpl>>>,
|
||||
}
|
||||
|
||||
impl Vnode {
|
||||
@@ -114,10 +132,10 @@ impl Vnode {
|
||||
|
||||
/// Constructs a new [Vnode], wrapping it in [Rc]. The resulting node
|
||||
/// then needs to have [Vnode::set_data()] called on it to be usable.
|
||||
pub fn new(name: &str, kind: VnodeKind, flags: u32) -> VnodeRef {
|
||||
pub fn new(name: &str, data: VnodeData, flags: u32) -> VnodeRef {
|
||||
Rc::new(Self {
|
||||
name: name.to_owned(),
|
||||
kind,
|
||||
data,
|
||||
flags,
|
||||
props: RefCell::new(VnodeProps {
|
||||
mode: FileMode::empty(),
|
||||
@@ -128,7 +146,6 @@ impl Vnode {
|
||||
}),
|
||||
target: RefCell::new(None),
|
||||
fs: RefCell::new(None),
|
||||
data: RefCell::new(None),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -147,19 +164,28 @@ impl Vnode {
|
||||
self.props.borrow()
|
||||
}
|
||||
|
||||
/// Sets an associated [VnodeImpl] for the [Vnode]
|
||||
pub fn set_data(&self, data: Box<dyn VnodeImpl>) {
|
||||
*self.data.borrow_mut() = Some(data);
|
||||
}
|
||||
// /// Sets an associated [VnodeImpl] for the [Vnode]
|
||||
// pub fn set_data(&self, data: Box<dyn VnodeImpl>) {
|
||||
// *self.data.borrow_mut() = Some(data);
|
||||
// }
|
||||
|
||||
/// Sets an associated [Filesystem] for the [Vnode]
|
||||
pub fn set_fs(&self, fs: Rc<dyn Filesystem>) {
|
||||
*self.fs.borrow_mut() = Some(fs);
|
||||
}
|
||||
|
||||
/// Returns a reference to the associated [VnodeImpl]
|
||||
pub fn data(&self) -> RefMut<Option<Box<dyn VnodeImpl>>> {
|
||||
self.data.borrow_mut()
|
||||
pub fn as_directory(&self) -> Result<&RefCell<Option<Box<dyn VnodeDirectory>>>, Errno> {
|
||||
match &self.data {
|
||||
VnodeData::Directory(data) => Ok(data),
|
||||
_ => Err(Errno::NotADirectory),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn as_file(&self) -> Result<&RefCell<Option<Box<dyn VnodeFile>>>, Errno> {
|
||||
match &self.data {
|
||||
VnodeData::File(data) => Ok(data),
|
||||
_ => Err(Errno::IsADirectory),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the associated [Fileystem]
|
||||
@@ -167,11 +193,6 @@ impl Vnode {
|
||||
self.fs.borrow().clone()
|
||||
}
|
||||
|
||||
/// Returns `true` if the vnode represents a directory
|
||||
pub fn is_directory(&self) -> bool {
|
||||
self.kind == VnodeKind::Directory
|
||||
}
|
||||
|
||||
/// Returns `true` if the vnode allows arbitrary seeking
|
||||
pub fn is_seekable(&self) -> bool {
|
||||
self.flags & Self::SEEKABLE != 0
|
||||
@@ -180,7 +201,7 @@ impl Vnode {
|
||||
/// Returns kind of the vnode
|
||||
#[inline(always)]
|
||||
pub const fn kind(&self) -> VnodeKind {
|
||||
self.kind
|
||||
core::mem::discriminant(&self.data)
|
||||
}
|
||||
|
||||
/// Returns flags of the vnode
|
||||
@@ -220,12 +241,9 @@ impl Vnode {
|
||||
|
||||
/// Attaches some filesystem's root directory node at another directory
|
||||
pub fn mount(self: &VnodeRef, root: VnodeRef) -> Result<(), Errno> {
|
||||
if !self.is_directory() {
|
||||
return Err(Errno::NotADirectory);
|
||||
}
|
||||
if !root.is_directory() {
|
||||
return Err(Errno::NotADirectory);
|
||||
}
|
||||
let dir = self.as_directory()?;
|
||||
let root_dir = root.as_directory()?;
|
||||
|
||||
if self.target.borrow().is_some() {
|
||||
return Err(Errno::Busy);
|
||||
}
|
||||
@@ -252,7 +270,7 @@ impl Vnode {
|
||||
|
||||
/// Looks up a child `name` in in-memory tree cache
|
||||
pub fn lookup(self: &VnodeRef, name: &str) -> Option<VnodeRef> {
|
||||
assert!(self.is_directory());
|
||||
// assert!(self.is_directory());
|
||||
self.tree
|
||||
.borrow()
|
||||
.children
|
||||
@@ -267,7 +285,8 @@ impl Vnode {
|
||||
limit: usize,
|
||||
mut f: F,
|
||||
) -> usize {
|
||||
assert!(self.is_directory());
|
||||
// TODO
|
||||
// assert!(self.is_directory());
|
||||
let mut count = 0;
|
||||
for (index, item) in self
|
||||
.tree
|
||||
@@ -287,10 +306,12 @@ impl Vnode {
|
||||
/// Looks up a child `name` in `self`. Will first try looking up a cached
|
||||
/// vnode and will load it from disk if it's missing.
|
||||
pub fn lookup_or_load(self: &VnodeRef, name: &str) -> Result<VnodeRef, Errno> {
|
||||
let dir = self.as_directory()?;
|
||||
|
||||
if let Some(node) = self.lookup(name) {
|
||||
Ok(node)
|
||||
} else if let Some(ref mut data) = *self.data() {
|
||||
let vnode = data.lookup(self.clone(), name)?;
|
||||
} else if let Some(ref mut dir) = *dir.borrow_mut() {
|
||||
let vnode = dir.lookup(self.clone(), name)?;
|
||||
if let Some(fs) = self.fs() {
|
||||
vnode.set_fs(fs);
|
||||
}
|
||||
@@ -306,11 +327,10 @@ impl Vnode {
|
||||
self: &VnodeRef,
|
||||
name: &str,
|
||||
mode: FileMode,
|
||||
kind: VnodeKind,
|
||||
kind: VnodeCreateKind,
|
||||
) -> Result<VnodeRef, Errno> {
|
||||
if self.kind != VnodeKind::Directory {
|
||||
return Err(Errno::NotADirectory);
|
||||
}
|
||||
let dir = self.as_directory()?;
|
||||
|
||||
if name.contains('/') {
|
||||
return Err(Errno::InvalidArgument);
|
||||
}
|
||||
@@ -321,8 +341,8 @@ impl Vnode {
|
||||
e => return e,
|
||||
};
|
||||
|
||||
if let Some(ref mut data) = *self.data() {
|
||||
let vnode = data.create(self.clone(), name, kind)?;
|
||||
if let Some(ref mut dir) = *dir.borrow_mut() {
|
||||
let vnode = dir.create(self.clone(), name, kind)?;
|
||||
if let Some(fs) = self.fs() {
|
||||
vnode.set_fs(fs);
|
||||
}
|
||||
@@ -336,16 +356,14 @@ impl Vnode {
|
||||
|
||||
/// Removes a directory entry `name` from `self`
|
||||
pub fn unlink(self: &VnodeRef, name: &str) -> Result<(), Errno> {
|
||||
if self.kind != VnodeKind::Directory {
|
||||
return Err(Errno::NotADirectory);
|
||||
}
|
||||
let dir = self.as_directory()?;
|
||||
if name.contains('/') {
|
||||
return Err(Errno::InvalidArgument);
|
||||
}
|
||||
|
||||
if let Some(ref mut data) = *self.data() {
|
||||
if let Some(ref mut dir) = *dir.borrow_mut() {
|
||||
let vnode = self.lookup(name).ok_or(Errno::DoesNotExist)?;
|
||||
data.remove(self.clone(), name)?;
|
||||
dir.remove(self.clone(), name)?;
|
||||
vnode.detach();
|
||||
Ok(())
|
||||
} else {
|
||||
@@ -356,93 +374,152 @@ impl Vnode {
|
||||
/// Opens a vnode for access
|
||||
pub fn open(self: &VnodeRef, flags: OpenFlags) -> Result<FileRef, Errno> {
|
||||
let mut open_flags = 0;
|
||||
if flags.contains(OpenFlags::O_DIRECTORY) {
|
||||
if self.kind != VnodeKind::Directory {
|
||||
return Err(Errno::NotADirectory);
|
||||
}
|
||||
if flags & OpenFlags::O_ACCESS != OpenFlags::O_RDONLY {
|
||||
return Err(Errno::IsADirectory);
|
||||
}
|
||||
|
||||
open_flags = File::READ;
|
||||
} else {
|
||||
if self.kind == VnodeKind::Directory {
|
||||
return Err(Errno::IsADirectory);
|
||||
}
|
||||
|
||||
match flags & OpenFlags::O_ACCESS {
|
||||
OpenFlags::O_RDONLY => open_flags |= File::READ,
|
||||
OpenFlags::O_WRONLY => open_flags |= File::WRITE,
|
||||
OpenFlags::O_RDWR => open_flags |= File::READ | File::WRITE,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
if flags.contains(OpenFlags::O_CLOEXEC) {
|
||||
open_flags |= File::CLOEXEC;
|
||||
}
|
||||
|
||||
if self.kind == VnodeKind::Directory && self.flags & Vnode::CACHE_READDIR != 0 {
|
||||
Ok(File::normal(self.clone(), File::POS_CACHE_DOT, open_flags))
|
||||
} else if let Some(ref mut data) = *self.data() {
|
||||
let pos = data.open(self.clone(), flags)?;
|
||||
Ok(File::normal(self.clone(), pos, open_flags))
|
||||
} else {
|
||||
Err(Errno::NotImplemented)
|
||||
match flags & OpenFlags::O_ACCESS {
|
||||
OpenFlags::O_RDONLY => open_flags |= File::READ,
|
||||
OpenFlags::O_WRONLY => open_flags |= File::WRITE,
|
||||
OpenFlags::O_RDWR => open_flags |= File::READ | File::WRITE,
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
|
||||
match &self.data {
|
||||
VnodeData::Directory(dir) => {
|
||||
if !flags.contains(OpenFlags::O_DIRECTORY) {
|
||||
return Err(Errno::NotADirectory);
|
||||
}
|
||||
|
||||
if self.flags & Vnode::CACHE_READDIR != 0 {
|
||||
Ok(File::normal(self.clone(), File::POS_CACHE_DOT, open_flags))
|
||||
} else {
|
||||
todo!()
|
||||
}
|
||||
},
|
||||
VnodeData::File(file) => {
|
||||
if flags.contains(OpenFlags::O_DIRECTORY) {
|
||||
return Err(Errno::IsADirectory);
|
||||
}
|
||||
|
||||
if let Some(ref mut file) = *file.borrow_mut() {
|
||||
let pos = file.open(self.clone(), flags)?;
|
||||
Ok(File::normal(self.clone(), pos, open_flags))
|
||||
} else {
|
||||
Err(Errno::NotImplemented)
|
||||
}
|
||||
},
|
||||
VnodeData::Char(chr) => {
|
||||
if flags.contains(OpenFlags::O_DIRECTORY) {
|
||||
return Err(Errno::IsADirectory);
|
||||
}
|
||||
|
||||
Ok(File::normal(self.clone(), 0, open_flags))
|
||||
// if let Some(ref mut chr) = *chr.borrow_mut() {
|
||||
// let pos = file.open(self.clone(), flags)?;
|
||||
// Ok(File::normal(self.clone(), pos, open_flags))
|
||||
// } else {
|
||||
// Err(Errno::NotImplemented)
|
||||
// }
|
||||
}
|
||||
_ => todo!()
|
||||
}
|
||||
|
||||
// if flags.contains(OpenFlags::O_DIRECTORY) {
|
||||
// let dir = self.as_directory()?;
|
||||
|
||||
// todo!()
|
||||
// // if self.kind != VnodeKind::Directory {
|
||||
// // return Err(Errno::NotADirectory);
|
||||
// // }
|
||||
// // if flags & OpenFlags::O_ACCESS != OpenFlags::O_RDONLY {
|
||||
// // return Err(Errno::IsADirectory);
|
||||
// // }
|
||||
|
||||
// // open_flags = File::READ;
|
||||
// } else {
|
||||
// let file = self.as_file()?;
|
||||
|
||||
// }
|
||||
|
||||
// if self.kind == VnodeKind::Directory && self.flags & Vnode::CACHE_READDIR != 0 {
|
||||
// Ok(File::normal(self.clone(), File::POS_CACHE_DOT, open_flags))
|
||||
// } else if let Some(ref mut data) = *self.data() {
|
||||
// } else {
|
||||
// }
|
||||
}
|
||||
|
||||
/// Closes a vnode
|
||||
pub fn close(self: &VnodeRef) -> Result<(), Errno> {
|
||||
if self.kind == VnodeKind::Directory && self.flags & Vnode::CACHE_READDIR != 0 {
|
||||
Ok(())
|
||||
} else if let Some(ref mut data) = *self.data() {
|
||||
data.close(self.clone())
|
||||
} else {
|
||||
Err(Errno::NotImplemented)
|
||||
match &self.data {
|
||||
VnodeData::Directory(dir) => {
|
||||
if let Some(ref mut dir) = *dir.borrow_mut() {
|
||||
return dir.close(self.clone());
|
||||
}
|
||||
},
|
||||
VnodeData::File(file) => {
|
||||
if let Some(ref mut file) = *file.borrow_mut() {
|
||||
return file.close(self.clone());
|
||||
}
|
||||
},
|
||||
_ => {}
|
||||
}
|
||||
|
||||
Err(Errno::NotImplemented)
|
||||
}
|
||||
|
||||
/// Reads data from offset `pos` into `buf`
|
||||
pub fn read(self: &VnodeRef, pos: usize, buf: &mut [u8]) -> Result<usize, Errno> {
|
||||
if self.kind == VnodeKind::Directory {
|
||||
Err(Errno::IsADirectory)
|
||||
} else if let Some(ref mut data) = *self.data() {
|
||||
data.read(self.clone(), pos, buf)
|
||||
} else {
|
||||
Err(Errno::NotImplemented)
|
||||
match &self.data {
|
||||
VnodeData::File(file) => {
|
||||
file.borrow_mut().as_mut().ok_or(Errno::NotImplemented)?.read(self.clone(), pos, buf)
|
||||
}
|
||||
VnodeData::Char(chr) => {
|
||||
chr.read(true, buf)
|
||||
}
|
||||
_ => todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Writes data from `buf` to offset `pos`
|
||||
pub fn write(self: &VnodeRef, pos: usize, buf: &[u8]) -> Result<usize, Errno> {
|
||||
if self.kind == VnodeKind::Directory {
|
||||
Err(Errno::IsADirectory)
|
||||
} else if let Some(ref mut data) = *self.data() {
|
||||
data.write(self.clone(), pos, buf)
|
||||
} else {
|
||||
Err(Errno::NotImplemented)
|
||||
match &self.data {
|
||||
VnodeData::File(file) => {
|
||||
file.borrow_mut().as_mut().ok_or(Errno::NotImplemented)?.write(self.clone(), pos, buf)
|
||||
}
|
||||
VnodeData::Char(chr) => {
|
||||
chr.write(true, buf)
|
||||
}
|
||||
_ => todo!()
|
||||
}
|
||||
}
|
||||
|
||||
/// Resizes the vnode data
|
||||
pub fn truncate(self: &VnodeRef, size: usize) -> Result<(), Errno> {
|
||||
if self.kind != VnodeKind::Regular {
|
||||
Err(Errno::IsADirectory)
|
||||
} else if let Some(ref mut data) = *self.data() {
|
||||
data.truncate(self.clone(), size)
|
||||
} else {
|
||||
Err(Errno::NotImplemented)
|
||||
}
|
||||
todo!()
|
||||
// if self.kind != VnodeKind::Regular {
|
||||
// Err(Errno::IsADirectory)
|
||||
// } else if let Some(ref mut data) = *self.data() {
|
||||
// data.truncate(self.clone(), size)
|
||||
// } else {
|
||||
// Err(Errno::NotImplemented)
|
||||
// }
|
||||
}
|
||||
|
||||
/// Returns current vnode data size
|
||||
pub fn size(self: &VnodeRef) -> Result<usize, Errno> {
|
||||
if let Some(ref mut data) = *self.data() {
|
||||
data.size(self.clone())
|
||||
} else {
|
||||
Err(Errno::NotImplemented)
|
||||
match &self.data {
|
||||
VnodeData::File(file) => {
|
||||
file.borrow_mut().as_mut().ok_or(Errno::NotADirectory)?.size(self.clone())
|
||||
},
|
||||
_ => todo!()
|
||||
}
|
||||
// if let Some(ref mut data) = *self.data() {
|
||||
// data.size(self.clone())
|
||||
// } else {
|
||||
// Err(Errno::NotImplemented)
|
||||
// }
|
||||
}
|
||||
|
||||
/// Reports file status
|
||||
@@ -454,29 +531,42 @@ impl Vnode {
|
||||
size: 0,
|
||||
mode: props.mode,
|
||||
})
|
||||
} else if let Some(ref mut data) = *self.data() {
|
||||
data.stat(self.clone())
|
||||
} else {
|
||||
Err(Errno::NotImplemented)
|
||||
match &self.data {
|
||||
VnodeData::File(file) => file.borrow_mut().as_mut().ok_or(Errno::NotADirectory)?.stat(self.clone()),
|
||||
VnodeData::Directory(dir) => dir.borrow_mut().as_mut().ok_or(Errno::NotImplemented)?.stat(self.clone()),
|
||||
_ => todo!()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Performs node-specific requests
|
||||
pub fn ioctl(self: &VnodeRef, cmd: IoctlCmd, ptr: usize, len: usize) -> Result<usize, Errno> {
|
||||
if let Some(ref mut data) = *self.data() {
|
||||
data.ioctl(self.clone(), cmd, ptr, len)
|
||||
} else {
|
||||
Err(Errno::NotImplemented)
|
||||
match &self.data {
|
||||
VnodeData::File(file) => {
|
||||
todo!()
|
||||
// file.borrow_mut().as_mut().ok_or(Errno::NotADirectory)?.size(self.clone())
|
||||
},
|
||||
VnodeData::Char(chr) => {
|
||||
chr.ioctl(cmd, ptr, len)
|
||||
},
|
||||
_ => todo!()
|
||||
}
|
||||
// if let Some(ref mut data) = *self.data() {
|
||||
// data.ioctl(self.clone(), cmd, ptr, len)
|
||||
// } else {
|
||||
// Err(Errno::NotImplemented)
|
||||
// }
|
||||
}
|
||||
|
||||
/// Returns `true` if the node is ready for operation
|
||||
pub fn is_ready(self: &VnodeRef, write: bool) -> Result<bool, Errno> {
|
||||
if let Some(ref mut data) = *self.data() {
|
||||
data.is_ready(self.clone(), write)
|
||||
} else {
|
||||
Err(Errno::NotImplemented)
|
||||
}
|
||||
todo!()
|
||||
// if let Some(ref mut data) = *self.data() {
|
||||
// data.is_ready(self.clone(), write)
|
||||
// } else {
|
||||
// Err(Errno::NotImplemented)
|
||||
// }
|
||||
}
|
||||
|
||||
/// Checks if given [Ioctx] has `access` permissions to the vnode
|
||||
@@ -525,32 +615,81 @@ mod tests {
|
||||
use libsys::{ioctl::IoctlCmd, stat::OpenFlags, stat::Stat};
|
||||
pub struct DummyInode;
|
||||
|
||||
#[auto_inode]
|
||||
impl VnodeImpl for DummyInode {
|
||||
fn create(
|
||||
// TODO derive macro for this
|
||||
impl VnodeCommon for DummyInode {
|
||||
/// Performs filetype-specific request
|
||||
fn ioctl(
|
||||
&mut self,
|
||||
_at: VnodeRef,
|
||||
name: &str,
|
||||
kind: VnodeKind,
|
||||
) -> Result<VnodeRef, Errno> {
|
||||
let node = Vnode::new(name, kind, 0);
|
||||
node.set_data(Box::new(DummyInode {}));
|
||||
Ok(node)
|
||||
node: VnodeRef,
|
||||
cmd: IoctlCmd,
|
||||
ptr: usize,
|
||||
len: usize,
|
||||
) -> Result<usize, Errno> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn remove(&mut self, _at: VnodeRef, _name: &str) -> Result<(), Errno> {
|
||||
/// Retrieves file status
|
||||
fn stat(&mut self, node: VnodeRef) -> Result<Stat, Errno> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Reports the size of this filesystem object in bytes
|
||||
fn size(&mut self, node: VnodeRef) -> Result<usize, Errno> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Returns `true` if node is ready for an operation
|
||||
fn is_ready(&mut self, node: VnodeRef, write: bool) -> Result<bool, Errno> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn open(&mut self, _node: VnodeRef, _flags: OpenFlags) -> Result<usize, Errno> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn close(&mut self, _node: VnodeRef) -> Result<(), Errno> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn lookup(&mut self, _at: VnodeRef, _name: &str) -> Result<VnodeRef, Errno> {
|
||||
}
|
||||
|
||||
impl VnodeDirectory for DummyInode {
|
||||
fn create(
|
||||
&mut self,
|
||||
at: VnodeRef,
|
||||
name: &str,
|
||||
kind: VnodeCreateKind,
|
||||
) -> Result<VnodeRef, Errno> {
|
||||
let data = match kind {
|
||||
VnodeCreateKind::Directory => {
|
||||
VnodeData::Directory(RefCell::new(Some(Box::new(DummyInode {}))))
|
||||
}
|
||||
_ => todo!(),
|
||||
};
|
||||
Ok(Vnode::new(name, data, 0))
|
||||
}
|
||||
fn remove(&mut self, at: VnodeRef, name: &str) -> Result<(), Errno> {
|
||||
Ok(())
|
||||
}
|
||||
fn lookup(&mut self, at: VnodeRef, name: &str) -> Result<VnodeRef, Errno> {
|
||||
Err(Errno::DoesNotExist)
|
||||
}
|
||||
|
||||
/// Read directory entries into target buffer
|
||||
fn readdir(
|
||||
&mut self,
|
||||
node: VnodeRef,
|
||||
pos: usize,
|
||||
data: &mut [DirectoryEntry],
|
||||
) -> Result<usize, Errno> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_parent() {
|
||||
let root = Vnode::new("", VnodeKind::Directory, 0);
|
||||
let node = Vnode::new("dir0", VnodeKind::Directory, 0);
|
||||
let root = Vnode::new("", VnodeData::Directory(RefCell::new(None)), 0);
|
||||
let node = Vnode::new("dir0", VnodeData::Directory(RefCell::new(None)), 0);
|
||||
|
||||
root.attach(node.clone());
|
||||
|
||||
@@ -560,23 +699,27 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_mkdir_unlink() {
|
||||
let root = Vnode::new("", VnodeKind::Directory, 0);
|
||||
|
||||
root.set_data(Box::new(DummyInode {}));
|
||||
let root = Vnode::new(
|
||||
"",
|
||||
VnodeData::Directory(RefCell::new(Some(Box::new(DummyInode {})))),
|
||||
0,
|
||||
);
|
||||
|
||||
let node = root
|
||||
.create("test", FileMode::default_dir(), VnodeKind::Directory)
|
||||
.create("test", FileMode::default_dir(), VnodeCreateKind::Directory)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
root.create("test", FileMode::default_dir(), VnodeKind::Directory)
|
||||
root.create("test", FileMode::default_dir(), VnodeCreateKind::Directory)
|
||||
.unwrap_err(),
|
||||
Errno::AlreadyExists
|
||||
);
|
||||
|
||||
assert_eq!(node.props.borrow().mode, FileMode::default_dir());
|
||||
assert!(Rc::ptr_eq(&node, &root.lookup("test").unwrap()));
|
||||
assert!(node.data.borrow().is_some());
|
||||
let inner = node.as_directory().unwrap();
|
||||
assert!(matches!(*inner.borrow_mut(), Some(_)));
|
||||
// assert!(node.data.borrow().is_some());
|
||||
|
||||
root.unlink("test").unwrap();
|
||||
|
||||
@@ -585,9 +728,9 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_lookup_attach_detach() {
|
||||
let root = Vnode::new("", VnodeKind::Directory, 0);
|
||||
let dir0 = Vnode::new("dir0", VnodeKind::Directory, 0);
|
||||
let dir1 = Vnode::new("dir1", VnodeKind::Directory, 0);
|
||||
let root = Vnode::new("", VnodeData::Directory(RefCell::new(None)), 0);
|
||||
let dir0 = Vnode::new("dir0", VnodeData::Directory(RefCell::new(None)), 0);
|
||||
let dir1 = Vnode::new("dir1", VnodeData::Directory(RefCell::new(None)), 0);
|
||||
|
||||
root.attach(dir0.clone());
|
||||
root.attach(dir1.clone());
|
||||
|
||||
@@ -3,7 +3,8 @@ use crate::util::InitOnce;
|
||||
use alloc::boxed::Box;
|
||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
use libsys::{stat::FileMode, error::Errno};
|
||||
use vfs::{CharDevice, CharDeviceWrapper, Vnode, VnodeKind, VnodeRef};
|
||||
use vfs::{CharDevice, Vnode, VnodeData, VnodeRef};
|
||||
use core::cell::RefCell;
|
||||
|
||||
/// Possible character device kinds
|
||||
#[derive(Debug)]
|
||||
@@ -16,7 +17,8 @@ static DEVFS_ROOT: InitOnce<VnodeRef> = InitOnce::new();
|
||||
|
||||
/// Initializes devfs
|
||||
pub fn init() {
|
||||
let node = Vnode::new("", VnodeKind::Directory, Vnode::CACHE_READDIR | Vnode::CACHE_STAT);
|
||||
let node = Vnode::new("", VnodeData::Directory(RefCell::new(None)), Vnode::CACHE_READDIR | Vnode::CACHE_STAT);
|
||||
// let node = Vnode::new("", VnodeKind::Directory, Vnode::CACHE_READDIR | Vnode::CACHE_STAT);
|
||||
node.props_mut().mode = FileMode::default_dir();
|
||||
DEVFS_ROOT.init(node);
|
||||
}
|
||||
@@ -29,9 +31,10 @@ pub fn root() -> &'static VnodeRef {
|
||||
pub fn add_named_char_device(dev: &'static dyn CharDevice, name: &str) -> Result<(), Errno> {
|
||||
infoln!("Add char device: {}", name);
|
||||
|
||||
let node = Vnode::new(name, VnodeKind::Char, Vnode::CACHE_STAT);
|
||||
node.props_mut().mode = FileMode::from_bits(0o600).unwrap() | FileMode::S_IFCHR;
|
||||
node.set_data(Box::new(CharDeviceWrapper::new(dev)));
|
||||
let node = Vnode::new(name, VnodeData::Char(dev), Vnode::CACHE_STAT);
|
||||
// let node = Vnode::new(name, VnodeKind::Char, Vnode::CACHE_STAT);
|
||||
// node.set_data(Box::new(CharDeviceWrapper::new(dev)));
|
||||
node.props_mut().mode = FileMode::from_bits(0o600).unwrap() | FileMode::S_IFCHR;
|
||||
|
||||
DEVFS_ROOT.get().attach(node);
|
||||
|
||||
|
||||
+69
-26
@@ -1,27 +1,26 @@
|
||||
use crate::debug::{self, Level};
|
||||
use crate::util::InitOnce;
|
||||
use alloc::boxed::Box;
|
||||
use core::cell::RefCell;
|
||||
use core::fmt::{self, Write};
|
||||
use core::str::FromStr;
|
||||
use core::sync::atomic::{AtomicUsize, Ordering};
|
||||
use fs_macros::auto_inode;
|
||||
use libsys::{
|
||||
error::Errno,
|
||||
stat::{FileMode, OpenFlags, Stat},
|
||||
ioctl::IoctlCmd,
|
||||
};
|
||||
use vfs::{CharDevice, CharDeviceWrapper, Vnode, VnodeImpl, VnodeKind, VnodeRef};
|
||||
use core::fmt::{self, Write};
|
||||
use core::str::FromStr;
|
||||
use crate::debug::{self, Level};
|
||||
use vfs::{CharDevice, Vnode, VnodeCommon, VnodeData, VnodeFile, VnodeRef};
|
||||
|
||||
struct NodeData<
|
||||
R: Fn(&mut [u8]) -> Result<usize, Errno>,
|
||||
W: Fn(&[u8]) -> Result<usize, Errno>,
|
||||
> {
|
||||
struct NodeData<R: Fn(&mut [u8]) -> Result<usize, Errno>, W: Fn(&[u8]) -> Result<usize, Errno>> {
|
||||
read_func: R,
|
||||
write_func: W,
|
||||
}
|
||||
|
||||
struct BufferWriter<'a> {
|
||||
dst: &'a mut [u8],
|
||||
pos: usize
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
impl<'a> fmt::Write for BufferWriter<'a> {
|
||||
@@ -47,11 +46,8 @@ impl<'a> BufferWriter<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
#[auto_inode]
|
||||
impl<
|
||||
R: Fn(&mut [u8]) -> Result<usize, Errno>,
|
||||
W: Fn(&[u8]) -> Result<usize, Errno>,
|
||||
> VnodeImpl for NodeData<R, W>
|
||||
impl<R: Fn(&mut [u8]) -> Result<usize, Errno>, W: Fn(&[u8]) -> Result<usize, Errno>> VnodeCommon
|
||||
for NodeData<R, W>
|
||||
{
|
||||
fn open(&mut self, _node: VnodeRef, _mode: OpenFlags) -> Result<usize, Errno> {
|
||||
Ok(0)
|
||||
@@ -60,7 +56,35 @@ impl<
|
||||
fn close(&mut self, _node: VnodeRef) -> Result<(), Errno> {
|
||||
Ok(())
|
||||
}
|
||||
/// Performs filetype-specific request
|
||||
fn ioctl(
|
||||
&mut self,
|
||||
node: VnodeRef,
|
||||
cmd: IoctlCmd,
|
||||
ptr: usize,
|
||||
len: usize,
|
||||
) -> Result<usize, Errno> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Retrieves file status
|
||||
fn stat(&mut self, node: VnodeRef) -> Result<Stat, Errno> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Reports the size of this filesystem object in bytes
|
||||
fn size(&mut self, node: VnodeRef) -> Result<usize, Errno> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Returns `true` if node is ready for an operation
|
||||
fn is_ready(&mut self, node: VnodeRef, write: bool) -> Result<bool, Errno> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Fn(&mut [u8]) -> Result<usize, Errno>, W: Fn(&[u8]) -> Result<usize, Errno>> VnodeFile
|
||||
for NodeData<R, W> {
|
||||
fn read(&mut self, _node: VnodeRef, pos: usize, data: &mut [u8]) -> Result<usize, Errno> {
|
||||
if pos != 0 {
|
||||
// TODO handle this
|
||||
@@ -76,12 +100,13 @@ impl<
|
||||
}
|
||||
(self.write_func)(data)
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
R: Fn(&mut [u8]) -> Result<usize, Errno>,
|
||||
W: Fn(&[u8]) -> Result<usize, Errno>,
|
||||
> NodeData<R, W>
|
||||
fn truncate(&mut self, node: VnodeRef, size: usize) -> Result<(), Errno> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
impl<R: Fn(&mut [u8]) -> Result<usize, Errno>, W: Fn(&[u8]) -> Result<usize, Errno>>
|
||||
NodeData<R, W>
|
||||
{
|
||||
pub const fn new(read_func: R, write_func: W) -> Self {
|
||||
Self {
|
||||
@@ -100,9 +125,12 @@ where
|
||||
R: Fn(&mut [u8]) -> Result<usize, Errno> + 'static,
|
||||
W: Fn(&[u8]) -> Result<usize, Errno> + 'static,
|
||||
{
|
||||
let node = Vnode::new(name, VnodeKind::Regular, Vnode::CACHE_STAT);
|
||||
let node = Vnode::new(
|
||||
name,
|
||||
VnodeData::File(RefCell::new(Some(Box::new(NodeData::new(read, write))))),
|
||||
Vnode::CACHE_STAT,
|
||||
);
|
||||
node.props_mut().mode = mode | FileMode::S_IFREG;
|
||||
node.set_data(Box::new(NodeData::new(read, write)));
|
||||
|
||||
if let Some(parent) = parent {
|
||||
parent.attach(node);
|
||||
@@ -116,15 +144,30 @@ where
|
||||
R: Fn(&mut [u8]) -> Result<usize, Errno> + 'static,
|
||||
W: Fn(&[u8]) -> Result<usize, Errno> + 'static,
|
||||
{
|
||||
add_generic_node(parent, name, FileMode::from_bits(0o600).unwrap(), read, write)
|
||||
add_generic_node(
|
||||
parent,
|
||||
name,
|
||||
FileMode::from_bits(0o600).unwrap(),
|
||||
read,
|
||||
write,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn add_read_node<R>(parent: Option<VnodeRef>, name: &str, read: R) where R: Fn(&mut [u8]) -> Result<usize, Errno> + 'static {
|
||||
add_generic_node(parent, name, FileMode::from_bits(0o400).unwrap(), read, |_| Err(Errno::ReadOnly))
|
||||
pub fn add_read_node<R>(parent: Option<VnodeRef>, name: &str, read: R)
|
||||
where
|
||||
R: Fn(&mut [u8]) -> Result<usize, Errno> + 'static,
|
||||
{
|
||||
add_generic_node(
|
||||
parent,
|
||||
name,
|
||||
FileMode::from_bits(0o400).unwrap(),
|
||||
read,
|
||||
|_| Err(Errno::ReadOnly),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn add_directory(parent: Option<VnodeRef>, name: &str) -> Result<VnodeRef, Errno> {
|
||||
let node = Vnode::new(name, VnodeKind::Directory, Vnode::CACHE_READDIR | Vnode::CACHE_STAT);
|
||||
let node = Vnode::new(name, VnodeData::Directory(RefCell::new(None)), Vnode::CACHE_READDIR | Vnode::CACHE_STAT);
|
||||
node.props_mut().mode = FileMode::from_bits(0o500).unwrap() | FileMode::S_IFDIR;
|
||||
|
||||
if let Some(parent) = parent {
|
||||
@@ -141,7 +184,7 @@ pub fn root() -> &'static VnodeRef {
|
||||
}
|
||||
|
||||
pub fn init() {
|
||||
let node = Vnode::new("", VnodeKind::Directory, Vnode::CACHE_READDIR | Vnode::CACHE_STAT);
|
||||
let node = Vnode::new("", VnodeData::Directory(RefCell::new(None)), Vnode::CACHE_READDIR | Vnode::CACHE_STAT);
|
||||
node.props_mut().mode = FileMode::default_dir();
|
||||
SYSFS_ROOT.init(node);
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Process file descriptors and I/O context
|
||||
use alloc::collections::BTreeMap;
|
||||
use libsys::{error::Errno, stat::{FileDescriptor, UserId, GroupId}};
|
||||
use vfs::{FileRef, Ioctx, VnodeRef, VnodeKind};
|
||||
use vfs::{FileRef, Ioctx, VnodeRef, VnodeData};
|
||||
|
||||
/// Process I/O context. Contains file tables, root/cwd info etc.
|
||||
pub struct ProcessIo {
|
||||
@@ -24,7 +24,7 @@ impl ProcessIo {
|
||||
|
||||
/// Sets controlling terminal for the process
|
||||
pub fn set_ctty(&mut self, node: VnodeRef) {
|
||||
assert_eq!(node.kind(), VnodeKind::Char);
|
||||
// assert_eq!(node.kind(), VnodeKind::Char);
|
||||
self.ctty = Some(node);
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -29,8 +29,9 @@ impl<T> InitOnce<T> {
|
||||
/// Returns the initialized value. Will panic if the value has not
|
||||
/// yet been initialized.
|
||||
#[allow(clippy::mut_from_ref)]
|
||||
#[track_caller]
|
||||
pub fn get(&self) -> &mut T {
|
||||
assert!(self.is_initialized(), "Access to uninitialized InitOnce<T>");
|
||||
assert!(self.is_initialized(), "Access to uninitialized InitOnce<T>: {:?}", core::panic::Location::caller());
|
||||
unsafe { (*self.inner.get()).assume_init_mut() }
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user