fs: implement GetMetadata, CreateDirectory, Remove

This commit is contained in:
Mark Poliakov 2023-07-22 16:21:31 +03:00
parent 8642556b33
commit ba3819ee8e
7 changed files with 212 additions and 21 deletions

View File

@ -5,7 +5,7 @@ use alloc::boxed::Box;
use vfs::{Vnode, VnodeImpl, VnodeKind, VnodeRef, DIR_POSITION_FROM_CACHE};
use yggdrasil_abi::{
error::Error,
io::{FileMode, OpenOptions},
io::{FileAttr, FileMode, FileType, OpenOptions},
};
use crate::{block::BlockAllocator, bvec::BVec, file::FileNode};
@ -15,7 +15,7 @@ pub(crate) struct DirectoryNode<A: BlockAllocator> {
}
impl<A: BlockAllocator> VnodeImpl for DirectoryNode<A> {
fn create(&mut self, _at: &VnodeRef, name: &str, kind: VnodeKind) -> Result<VnodeRef, Error> {
fn create(&mut self, at: &VnodeRef, name: &str, kind: VnodeKind) -> Result<VnodeRef, Error> {
let child = Vnode::new(name, kind);
match kind {
VnodeKind::Directory => child.set_data(Box::new(Self { _pd: PhantomData })),
@ -24,6 +24,7 @@ impl<A: BlockAllocator> VnodeImpl for DirectoryNode<A> {
})),
_ => todo!(),
}
child.set_fs(at.fs().unwrap());
Ok(child)
}
@ -35,6 +36,22 @@ impl<A: BlockAllocator> VnodeImpl for DirectoryNode<A> {
) -> Result<u64, Error> {
Ok(DIR_POSITION_FROM_CACHE)
}
fn remove(&mut self, _at: &VnodeRef, _name: &str) -> Result<(), Error> {
Ok(())
}
fn size(&mut self, node: &VnodeRef) -> Result<u64, Error> {
Ok(node.children().len() as u64)
}
fn metadata(&mut self, _node: &VnodeRef) -> Result<FileAttr, Error> {
Ok(FileAttr {
size: 0,
mode: FileMode::default_dir(),
ty: FileType::Directory,
})
}
}
impl<A: BlockAllocator> DirectoryNode<A> {

View File

@ -1,7 +1,7 @@
use vfs::{VnodeImpl, VnodeRef};
use yggdrasil_abi::{
error::Error,
io::{FileMode, OpenOptions},
io::{FileAttr, FileMode, FileType, OpenOptions},
};
use crate::{block::BlockAllocator, bvec::BVec};
@ -34,4 +34,12 @@ impl<A: BlockAllocator> VnodeImpl for FileNode<A> {
fn size(&mut self, _node: &VnodeRef) -> Result<u64, Error> {
Ok(self.data.size() as u64)
}
fn metadata(&mut self, _node: &VnodeRef) -> Result<FileAttr, Error> {
Ok(FileAttr {
size: self.data.size() as u64,
mode: FileMode::default_file(),
ty: FileType::File,
})
}
}

View File

@ -1,6 +1,6 @@
use yggdrasil_abi::{
error::Error,
io::{FileMode, OpenOptions},
io::{FileAttr, FileMode, FileType, OpenOptions},
};
use crate::{node::VnodeImpl, VnodeRef};
@ -41,4 +41,12 @@ impl VnodeImpl for CharDeviceWrapper {
fn write(&mut self, _node: &VnodeRef, _pos: u64, data: &[u8]) -> Result<usize, Error> {
self.device.write(true, data)
}
fn metadata(&mut self, _node: &VnodeRef) -> Result<FileAttr, Error> {
Ok(FileAttr {
size: 0,
ty: FileType::Char,
mode: FileMode::default_file(),
})
}
}

View File

@ -1,5 +1,5 @@
use core::{
cell::{RefCell, RefMut},
cell::{Ref, RefCell, RefMut},
fmt,
};
@ -11,7 +11,7 @@ use alloc::{
};
use yggdrasil_abi::{
error::Error,
io::{FileMode, FileType, OpenOptions},
io::{FileAttr, FileMode, FileType, OpenOptions},
};
use crate::{
@ -49,33 +49,37 @@ pub struct Vnode {
target: RefCell<Option<VnodeRef>>,
}
#[allow(unused_variables)]
pub trait VnodeImpl {
fn create(&mut self, _at: &VnodeRef, _name: &str, _kind: VnodeKind) -> Result<VnodeRef, Error> {
fn create(&mut self, at: &VnodeRef, name: &str, kind: VnodeKind) -> Result<VnodeRef, Error> {
Err(Error::NotImplemented)
}
fn open(
&mut self,
_node: &VnodeRef,
_opts: OpenOptions,
_mode: FileMode,
) -> Result<u64, Error> {
fn remove(&mut self, at: &VnodeRef, name: &str) -> Result<(), Error> {
Err(Error::NotImplemented)
}
fn close(&mut self, _node: &VnodeRef) -> Result<(), Error> {
fn open(&mut self, node: &VnodeRef, opts: OpenOptions, mode: FileMode) -> Result<u64, Error> {
Err(Error::NotImplemented)
}
fn read(&mut self, _node: &VnodeRef, _pos: u64, _data: &mut [u8]) -> Result<usize, Error> {
fn close(&mut self, node: &VnodeRef) -> Result<(), Error> {
Err(Error::NotImplemented)
}
fn write(&mut self, _node: &VnodeRef, _pos: u64, _data: &[u8]) -> Result<usize, Error> {
fn read(&mut self, node: &VnodeRef, pos: u64, data: &mut [u8]) -> Result<usize, Error> {
Err(Error::NotImplemented)
}
fn size(&mut self, _node: &VnodeRef) -> Result<u64, Error> {
fn write(&mut self, node: &VnodeRef, pos: u64, data: &[u8]) -> Result<usize, Error> {
Err(Error::NotImplemented)
}
fn size(&mut self, node: &VnodeRef) -> Result<u64, Error> {
Err(Error::NotImplemented)
}
fn metadata(&mut self, node: &VnodeRef) -> Result<FileAttr, Error> {
Err(Error::NotImplemented)
}
}
@ -132,6 +136,11 @@ impl Vnode {
}
}
#[inline]
pub fn is_root(&self) -> bool {
self.tree.borrow().parent.is_none()
}
pub fn set_data(&self, data: Box<dyn VnodeImpl>) {
self.data.borrow_mut().replace(data);
}
@ -164,11 +173,25 @@ impl Vnode {
parent_borrow.children.push(child);
}
pub fn remove_child(self: &VnodeRef, name: &str) {
self.children_mut().retain(|node| node.name() != name);
}
pub fn child_at(self: &VnodeRef, index: usize) -> Option<VnodeRef> {
let tree = self.tree.borrow();
tree.children.get(index).cloned()
}
pub fn children(&self) -> Ref<Vec<VnodeRef>> {
let tree = self.tree.borrow();
Ref::map(tree, |t| &t.children)
}
pub fn children_mut(&self) -> RefMut<Vec<VnodeRef>> {
let tree = self.tree.borrow_mut();
RefMut::map(tree, |t| &mut t.children)
}
pub fn dump(&self, f: &mut fmt::Formatter<'_>, depth: usize, indent: bool) -> fmt::Result {
if indent {
for _ in 0..depth {
@ -298,6 +321,37 @@ impl Vnode {
}
}
pub fn remove(self: &VnodeRef, node: VnodeRef, recurse: bool) -> Result<(), Error> {
let name = node.name();
if self.kind != VnodeKind::Directory {
todo!();
}
if name.contains('/') {
todo!();
}
if node.kind() == VnodeKind::Directory {
if recurse {
todo!();
}
// Check if remove target is not empty
if node.size()? != 0 {
return Err(Error::DirectoryNotEmpty);
}
}
if let Some(ref mut data) = *self.data() {
data.remove(self, name)?;
}
// Unlink node from cache
self.remove_child(name);
Ok(())
}
pub fn write(self: &VnodeRef, pos: u64, buf: &[u8]) -> Result<usize, Error> {
if self.kind == VnodeKind::Directory {
todo!();
@ -371,6 +425,14 @@ impl Vnode {
Ok(())
}
pub fn metadata(self: &VnodeRef) -> Result<FileAttr, Error> {
if let Some(ref mut data) = *self.data() {
data.metadata(self)
} else {
todo!()
}
}
}
impl fmt::Debug for Vnode {

View File

@ -1,9 +1,14 @@
//! Device virtual file system
use core::sync::atomic::{AtomicUsize, Ordering};
use abi::error::Error;
use abi::{
error::Error,
io::{FileAttr, FileMode, FileType, OpenOptions},
};
use alloc::{boxed::Box, format, string::String};
use vfs::{CharDevice, CharDeviceWrapper, Vnode, VnodeKind, VnodeRef};
use vfs::{
CharDevice, CharDeviceWrapper, Vnode, VnodeImpl, VnodeKind, VnodeRef, DIR_POSITION_FROM_CACHE,
};
use crate::util::OneTimeInit;
@ -14,11 +19,33 @@ pub enum CharDeviceType {
TtySerial,
}
struct DevfsDirectory;
impl VnodeImpl for DevfsDirectory {
fn open(
&mut self,
_node: &VnodeRef,
_opts: OpenOptions,
_mode: FileMode,
) -> Result<u64, Error> {
Ok(DIR_POSITION_FROM_CACHE)
}
fn metadata(&mut self, _node: &VnodeRef) -> Result<FileAttr, Error> {
Ok(FileAttr {
size: 0,
mode: FileMode::default_dir(),
ty: FileType::Directory,
})
}
}
static DEVFS_ROOT: OneTimeInit<VnodeRef> = OneTimeInit::new();
/// Sets up the device filesystem
pub fn init() {
let node = Vnode::new("", VnodeKind::Directory);
node.set_data(Box::new(DevfsDirectory));
DEVFS_ROOT.init(node);
}

View File

@ -35,6 +35,16 @@ pub(super) fn arg_user_ref<'a, T: Sized>(addr: usize) -> Result<&'a T, Error> {
Ok(value)
}
pub(super) fn arg_user_mut<'a, T: Sized>(addr: usize) -> Result<&'a mut T, Error> {
let layout = Layout::new::<T>();
if addr % layout.align() != 0 {
todo!("Misaligned argument");
}
// TODO check that addr actually points to mapped (and user-accessible) memory
let value = unsafe { core::mem::transmute::<_, &'a mut T>(addr) };
Ok(value)
}
pub(super) fn arg_user_slice_mut<'a, T: Sized>(
base: usize,
count: usize,

View File

@ -3,10 +3,11 @@ use core::{mem::MaybeUninit, time::Duration};
use abi::{
error::Error,
io::{DirectoryEntry, FileMode, OpenOptions, RawFd},
io::{DirectoryEntry, FileAttr, FileMode, OpenOptions, RawFd},
syscall::SyscallFunction,
};
use vfs::{Read, ReadDirectory, Write};
use alloc::rc::Rc;
use vfs::{Read, ReadDirectory, VnodeKind, Write};
use yggdrasil_abi::{
error::SyscallResult,
io::{MountOptions, UnmountOptions},
@ -185,6 +186,64 @@ fn syscall_handler(func: SyscallFunction, args: &[u64]) -> Result<usize, Error>
file_borrow.read_dir_entries(buffer)
}
SyscallFunction::CreateDirectory => {
let at = arg_option_fd(args[0] as u32);
let path = arg_user_str(args[1] as usize, args[2] as usize)?;
let mode = FileMode::from(args[3] as u32);
let proc = Process::current();
let mut io = proc.io.lock();
// TODO handle at
assert!(at.is_none());
let (parent, name) = abi::path::split_right(path);
let parent_node = io.ioctx().find(None, parent, true, true)?;
parent_node.create(name, VnodeKind::Directory)?;
Ok(0)
}
SyscallFunction::Remove => {
let at = arg_option_fd(args[0] as u32);
let path = arg_user_str(args[1] as usize, args[2] as usize)?;
let recurse = args[3] != 0;
let proc = Process::current();
let mut io = proc.io.lock();
assert!(at.is_none());
let node = io.ioctx().find(None, path, false, false)?;
if node.is_root() || Rc::ptr_eq(io.ioctx().root(), &node) {
todo!();
}
let (_, filename) = abi::path::split_right(path);
let parent = node.parent();
parent.remove(node, recurse)?;
Ok(0)
}
SyscallFunction::GetMetadata => {
let at = arg_option_fd(args[0] as u32);
let path = arg_user_str(args[1] as usize, args[2] as usize)?;
let buffer = arg_user_mut::<MaybeUninit<FileAttr>>(args[3] as usize)?;
let follow = args[4] != 0;
let proc = Process::current();
let mut io = proc.io.lock();
assert!(at.is_none());
let node = io.ioctx().find(None, path, follow, true)?;
let metadata = node.metadata()?;
buffer.write(metadata);
Ok(0)
}
}
}