fs: implement GetMetadata, CreateDirectory, Remove
This commit is contained in:
parent
8642556b33
commit
ba3819ee8e
@ -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> {
|
||||
|
@ -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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user