vfs: implement filename validation
This commit is contained in:
parent
77b6403c68
commit
d597197ca2
@ -11,7 +11,10 @@ use libk::{
|
||||
block,
|
||||
error::Error,
|
||||
time::real_time,
|
||||
vfs::{CommonImpl, DirectoryImpl, DirectoryOpenPosition, Metadata, Node, NodeFlags, NodeRef},
|
||||
vfs::{
|
||||
CommonImpl, DirectoryImpl, DirectoryOpenPosition, Filename, Metadata, Node, NodeFlags,
|
||||
NodeRef,
|
||||
},
|
||||
};
|
||||
use walk::{DirentIter, DirentIterMut};
|
||||
use yggdrasil_abi::io::{DirectoryEntry, FileMode, FileType};
|
||||
@ -38,11 +41,11 @@ impl DirentName<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> TryFrom<&'a str> for DirentName<'a> {
|
||||
impl<'a> TryFrom<&'a Filename> for DirentName<'a> {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: &'a str) -> Result<Self, Self::Error> {
|
||||
if value.len() >= 255 || value.is_empty() || value.contains('/') {
|
||||
fn try_from(value: &'a Filename) -> Result<Self, Self::Error> {
|
||||
if value.len() >= 255 {
|
||||
return Err(Error::InvalidArgument);
|
||||
}
|
||||
Ok(Self(value))
|
||||
@ -359,7 +362,7 @@ impl DirectoryImpl for DirectoryNode {
|
||||
Err(Error::NotImplemented)
|
||||
}
|
||||
|
||||
fn lookup(&self, _node: &NodeRef, name: &str) -> Result<NodeRef, Error> {
|
||||
fn lookup(&self, _node: &NodeRef, name: &Filename) -> Result<NodeRef, Error> {
|
||||
let name = DirentName::try_from(name)?;
|
||||
block!(self.lookup_entry(name).await)?
|
||||
}
|
||||
@ -375,7 +378,12 @@ impl DirectoryImpl for DirectoryNode {
|
||||
block!(InodeAccess::allocate(&self.fs, ty, mode, Some(self.inode.ino())).await)?
|
||||
}
|
||||
|
||||
fn attach_node(&self, _parent: &NodeRef, child: &NodeRef, name: &str) -> Result<(), Error> {
|
||||
fn attach_node(
|
||||
&self,
|
||||
_parent: &NodeRef,
|
||||
child: &NodeRef,
|
||||
name: &Filename,
|
||||
) -> Result<(), Error> {
|
||||
if self.fs.force_readonly {
|
||||
return Err(Error::ReadOnly);
|
||||
}
|
||||
@ -391,7 +399,12 @@ impl DirectoryImpl for DirectoryNode {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn unlink_node(&self, _parent: &NodeRef, child: &NodeRef, name: &str) -> Result<(), Error> {
|
||||
fn unlink_node(
|
||||
&self,
|
||||
_parent: &NodeRef,
|
||||
child: &NodeRef,
|
||||
name: &Filename,
|
||||
) -> Result<(), Error> {
|
||||
if self.fs.force_readonly {
|
||||
return Err(Error::ReadOnly);
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ use alloc::sync::Arc;
|
||||
use block::BlockAllocator;
|
||||
use dir::DirectoryNode;
|
||||
use file::FileNode;
|
||||
use libk::vfs::{impls::fixed_path_symlink, AccessToken, Filesystem, Metadata, NodeRef};
|
||||
use libk::vfs::{impls::fixed_path_symlink, AccessToken, Filename, Filesystem, Metadata, NodeRef};
|
||||
use libk_util::sync::IrqSafeSpinlock;
|
||||
use tar::TarEntry;
|
||||
use yggdrasil_abi::{
|
||||
@ -80,8 +80,10 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
|
||||
assert!(!element.is_empty());
|
||||
assert!(!element.contains('/'));
|
||||
|
||||
let filename = Filename::new(element)?;
|
||||
|
||||
// let node = at.lookup(element);
|
||||
let node = at.lookup_or_load(element, access);
|
||||
let node = at.lookup_or_load(filename, access);
|
||||
let node = match node {
|
||||
Ok(node) => node,
|
||||
Err(Error::DoesNotExist) => {
|
||||
@ -90,7 +92,7 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
|
||||
}
|
||||
|
||||
let node = DirectoryNode::<A>::new(self.clone(), Metadata::now_root(mode));
|
||||
at.add_child(element, node.clone())?;
|
||||
at.add_child(filename, node.clone())?;
|
||||
|
||||
node
|
||||
}
|
||||
@ -140,6 +142,7 @@ impl<A: BlockAllocator> MemoryFilesystem<A> {
|
||||
let (dirname, filename) = path.split_right();
|
||||
let parent = self.make_path(&root, dirname, true, FileMode::new(0o755))?;
|
||||
let node = self.create_node_initial(hdr)?;
|
||||
let filename = Filename::new(filename)?;
|
||||
|
||||
parent.add_child(filename, node)?;
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
//! Device virtual file system
|
||||
|
||||
use alloc::{string::String, sync::Arc};
|
||||
use alloc::sync::Arc;
|
||||
use libk_util::OneTimeInit;
|
||||
use yggdrasil_abi::{error::Error, io::FileMode};
|
||||
|
||||
@ -8,6 +8,7 @@ use crate::{
|
||||
device::{block::BlockDevice, char::CharDevice},
|
||||
vfs::{
|
||||
impls::{fixed_path_symlink, MemoryDirectory},
|
||||
path::OwnedFilename,
|
||||
AccessToken, Metadata, Node, NodeFlags, NodeRef,
|
||||
},
|
||||
};
|
||||
@ -29,21 +30,24 @@ pub fn root() -> &'static NodeRef {
|
||||
DEVFS_ROOT.get()
|
||||
}
|
||||
|
||||
pub fn redirect(name: &str, destination: &str) -> Result<(), Error> {
|
||||
pub fn redirect<S: AsRef<str>>(name: S, destination: &str) -> Result<(), Error> {
|
||||
let name = name.as_ref();
|
||||
log::info!("Redirect {name} -> {destination}");
|
||||
|
||||
let root = DEVFS_ROOT.get();
|
||||
root.remove_file(name, unsafe { AccessToken::authorized() })
|
||||
let filename = OwnedFilename::new(name)?;
|
||||
root.remove_file(filename.as_ref(), unsafe { AccessToken::authorized() })
|
||||
.ok();
|
||||
root.add_child(name, fixed_path_symlink(destination))
|
||||
root.add_child(filename, fixed_path_symlink(destination))
|
||||
}
|
||||
|
||||
/// Adds a character device with a custom name
|
||||
pub fn add_named_char_device(
|
||||
pub fn add_named_char_device<S: AsRef<str>>(
|
||||
dev: Arc<dyn CharDevice>,
|
||||
name: String,
|
||||
name: S,
|
||||
mode: FileMode,
|
||||
) -> Result<(), Error> {
|
||||
let name = name.as_ref();
|
||||
log::info!("Add char device: {}", name);
|
||||
|
||||
let node = Node::char(
|
||||
@ -53,16 +57,17 @@ pub fn add_named_char_device(
|
||||
None,
|
||||
);
|
||||
|
||||
DEVFS_ROOT.get().add_child(name, node)
|
||||
let filename = OwnedFilename::new(name)?;
|
||||
DEVFS_ROOT.get().add_child(filename, node)
|
||||
}
|
||||
|
||||
/// Adds a block device with a custom name
|
||||
pub fn add_named_block_device<S: Into<String>>(
|
||||
pub fn add_named_block_device<S: AsRef<str>>(
|
||||
dev: Arc<dyn BlockDevice>,
|
||||
name: S,
|
||||
mode: FileMode,
|
||||
) -> Result<NodeRef, Error> {
|
||||
let name = name.into();
|
||||
let name = name.as_ref();
|
||||
log::info!("Add block device: {}", name);
|
||||
|
||||
let node = Node::block(
|
||||
@ -72,7 +77,8 @@ pub fn add_named_block_device<S: Into<String>>(
|
||||
None,
|
||||
);
|
||||
|
||||
DEVFS_ROOT.get().add_child(name, node.clone())?;
|
||||
let filename = OwnedFilename::new(name)?;
|
||||
DEVFS_ROOT.get().add_child(filename, node.clone())?;
|
||||
|
||||
Ok(node)
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ use yggdrasil_abi::{
|
||||
|
||||
use crate::{
|
||||
fs::sysfs::object::KObject,
|
||||
vfs::{CommonImpl, InstanceData, Metadata, Node, NodeFlags, NodeRef, RegularImpl},
|
||||
vfs::{CommonImpl, Filename, InstanceData, Metadata, Node, NodeFlags, NodeRef, RegularImpl},
|
||||
};
|
||||
|
||||
use super::Attribute;
|
||||
@ -123,7 +123,8 @@ impl<V: BytesAttributeOps> Attribute<V::Data> for BytesAttribute<V> {
|
||||
))
|
||||
}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
V::NAME
|
||||
// TODO implement this properly
|
||||
fn name(&self) -> &Filename {
|
||||
unsafe { Filename::from_str_unchecked(V::NAME) }
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use alloc::sync::Arc;
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
use crate::vfs::NodeRef;
|
||||
use crate::vfs::{Filename, NodeRef};
|
||||
|
||||
use super::object::KObject;
|
||||
|
||||
@ -10,7 +10,7 @@ mod string;
|
||||
|
||||
pub trait Attribute<D>: Sync + Send {
|
||||
fn instantiate(&self, parent: &Arc<KObject<D>>) -> Result<NodeRef, Error>;
|
||||
fn name(&self) -> &str;
|
||||
fn name(&self) -> &Filename;
|
||||
}
|
||||
|
||||
pub use bytes::{BytesAttribute, BytesAttributeOps};
|
||||
|
@ -13,7 +13,7 @@ use yggdrasil_abi::{
|
||||
|
||||
use crate::{
|
||||
fs::sysfs::object::KObject,
|
||||
vfs::{CommonImpl, InstanceData, Metadata, Node, NodeFlags, NodeRef, RegularImpl},
|
||||
vfs::{CommonImpl, Filename, InstanceData, Metadata, Node, NodeFlags, NodeRef, RegularImpl},
|
||||
};
|
||||
|
||||
use super::Attribute;
|
||||
@ -191,7 +191,8 @@ impl<V: StringAttributeOps> Attribute<V::Data> for StringAttribute<V> {
|
||||
))
|
||||
}
|
||||
|
||||
fn name(&self) -> &str {
|
||||
V::NAME
|
||||
// TODO implement this properly
|
||||
fn name(&self) -> &Filename {
|
||||
unsafe { Filename::from_str_unchecked(V::NAME) }
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use alloc::{string::String, sync::Arc};
|
||||
use alloc::sync::Arc;
|
||||
use libk_util::OneTimeInit;
|
||||
use yggdrasil_abi::{error::Error, io::FileMode};
|
||||
|
||||
use crate::vfs::{impls::MemoryDirectory, Metadata, Node, NodeFlags};
|
||||
use crate::vfs::{impls::MemoryDirectory, path::OwnedFilename, Metadata, Node, NodeFlags};
|
||||
|
||||
use super::attribute::Attribute;
|
||||
|
||||
@ -28,12 +28,13 @@ impl<D> KObject<D> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_object<S: Into<String>, T>(
|
||||
pub fn add_object<S: AsRef<str>, T>(
|
||||
&self,
|
||||
name: S,
|
||||
child: Arc<KObject<T>>,
|
||||
) -> Result<(), Error> {
|
||||
self.node.add_child(name, child.node.clone())
|
||||
let filename = OwnedFilename::new(name)?;
|
||||
self.node.add_child(filename, child.node.clone())
|
||||
}
|
||||
|
||||
pub(super) fn data(&self) -> &D {
|
||||
|
@ -6,10 +6,10 @@ use yggdrasil_abi::{
|
||||
|
||||
use crate::vfs::{
|
||||
node::{AccessToken, CreateInfo},
|
||||
FileRef, NodeRef,
|
||||
FileRef, Filename, NodeRef,
|
||||
};
|
||||
|
||||
use super::Node;
|
||||
use super::{path::OwnedFilename, Node};
|
||||
|
||||
/// Describes a general filesystem access
|
||||
pub enum Action {
|
||||
@ -189,15 +189,16 @@ impl IoContext {
|
||||
// let create_mode = mode & !self.umask;
|
||||
let (parent, name) = path.split_right();
|
||||
let parent = self.find(at, parent, true)?;
|
||||
let filename = OwnedFilename::new(name)?;
|
||||
let create_info = CreateInfo {
|
||||
name: name.into(),
|
||||
name: filename,
|
||||
mode: mode & !self.umask,
|
||||
uid: self.uid,
|
||||
gid: self.gid,
|
||||
ty: FileType::File,
|
||||
};
|
||||
let access = self.check_access(&parent, AccessMode::WRITE)?;
|
||||
parent.create(&create_info, access)?
|
||||
parent.create(create_info, access)?
|
||||
}
|
||||
Err(err) => return Err(err),
|
||||
};
|
||||
@ -232,15 +233,16 @@ impl IoContext {
|
||||
let (parent, name) = path.split_right();
|
||||
let parent = self.find(at, parent, true)?;
|
||||
let access = self.check_access(&parent, AccessMode::WRITE)?;
|
||||
let filename = OwnedFilename::new(name)?;
|
||||
let create_info = CreateInfo {
|
||||
name: name.into(),
|
||||
name: filename,
|
||||
ty: FileType::Directory,
|
||||
uid: self.uid,
|
||||
gid: self.gid,
|
||||
mode: mode & !self.umask,
|
||||
};
|
||||
|
||||
parent.create(&create_info, access)
|
||||
parent.create(create_info, access)
|
||||
}
|
||||
|
||||
/// Creates an arbitrary node at given path
|
||||
@ -255,7 +257,8 @@ impl IoContext {
|
||||
let parent = self.find(at, parent, true)?;
|
||||
let access = self.check_access(&parent, AccessMode::WRITE)?;
|
||||
|
||||
parent.create_node(node, name, access)?;
|
||||
let filename = Filename::new(name)?;
|
||||
parent.create_node(node, filename, access)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -281,7 +284,8 @@ impl IoContext {
|
||||
// parent.remove_directory(name, access)
|
||||
todo!()
|
||||
} else {
|
||||
parent.remove_file(name, access)
|
||||
let filename = Filename::new(name)?;
|
||||
parent.remove_file(filename, access)
|
||||
}
|
||||
}
|
||||
|
||||
@ -330,6 +334,9 @@ impl IoContext {
|
||||
(node, dst_name)
|
||||
};
|
||||
|
||||
let src_name = Filename::new(src_name)?;
|
||||
let dst_name = Filename::new(dst_name)?;
|
||||
|
||||
let access = self.check_access(&src_node, AccessMode::READ | AccessMode::WRITE)?
|
||||
+ self.check_access(&dst_node, AccessMode::WRITE)?;
|
||||
|
||||
@ -485,7 +492,8 @@ impl IoContext {
|
||||
}
|
||||
|
||||
let access = self.check_access(&node, AccessMode::EXEC)?;
|
||||
let child = node.lookup_or_load(name, access)?.flatten_hardlink()?;
|
||||
let filename = Filename::new(name)?;
|
||||
let child = node.lookup_or_load(filename, access)?.flatten_hardlink()?;
|
||||
|
||||
let follow_links = follow_link || !tail.is_empty();
|
||||
|
||||
@ -538,7 +546,8 @@ impl IoContext {
|
||||
}
|
||||
|
||||
let access = self.check_access(&at, AccessMode::EXEC)?;
|
||||
let node = at.lookup_or_load(element, access)?.flatten_hardlink()?;
|
||||
let filename = Filename::new(element)?;
|
||||
let node = at.lookup_or_load(filename, access)?.flatten_hardlink()?;
|
||||
let node = self._resolve(node, follow_links)?;
|
||||
|
||||
if rest.is_empty() {
|
||||
|
@ -31,6 +31,7 @@ pub use node::{
|
||||
impls, AccessToken, CommonImpl, CreateInfo, DirectoryImpl, Metadata, Node, NodeFlags, NodeRef,
|
||||
RegularImpl, SymlinkImpl,
|
||||
};
|
||||
pub use path::{Filename, OwnedFilename};
|
||||
pub use poll::FdPoll;
|
||||
pub use pty::{PseudoTerminalMaster, PseudoTerminalSlave};
|
||||
pub use shared_memory::SharedMemory;
|
||||
|
@ -1,5 +1,5 @@
|
||||
//! Various helper node implementations for convenience
|
||||
use core::{marker::PhantomData, str::FromStr};
|
||||
use core::{fmt, marker::PhantomData, str::FromStr};
|
||||
|
||||
use alloc::{
|
||||
string::{String, ToString},
|
||||
@ -13,7 +13,7 @@ use yggdrasil_abi::{
|
||||
io::{FileMode, FileType, OpenOptions},
|
||||
};
|
||||
|
||||
use crate::vfs::{DirectoryOpenPosition, InstanceData};
|
||||
use crate::vfs::{path::OwnedFilename, DirectoryOpenPosition, InstanceData};
|
||||
|
||||
use super::{
|
||||
traits::HardlinkImpl, CommonImpl, DirectoryImpl, Metadata, Node, NodeFlags, NodeRef,
|
||||
@ -464,7 +464,10 @@ pub fn read_fn_node<R: ReadFn + 'static>(read: R) -> NodeRef {
|
||||
}
|
||||
|
||||
/// Creates an in-memory directory from the iterator
|
||||
pub fn mdir<S: Into<String>, I: IntoIterator<Item = (S, NodeRef)>>(it: I) -> NodeRef {
|
||||
pub fn mdir<S: TryInto<OwnedFilename>, I: IntoIterator<Item = (S, NodeRef)>>(it: I) -> NodeRef
|
||||
where
|
||||
S::Error: fmt::Debug,
|
||||
{
|
||||
let dir = Node::directory(
|
||||
MemoryDirectory,
|
||||
NodeFlags::IN_MEMORY_PROPS | NodeFlags::IN_MEMORY_SIZE,
|
||||
@ -472,7 +475,7 @@ pub fn mdir<S: Into<String>, I: IntoIterator<Item = (S, NodeRef)>>(it: I) -> Nod
|
||||
None,
|
||||
);
|
||||
for (name, node) in it {
|
||||
dir.add_child(name, node).unwrap();
|
||||
dir.add_child(name.try_into().unwrap(), node).unwrap();
|
||||
}
|
||||
dir
|
||||
}
|
||||
|
@ -37,6 +37,7 @@ use crate::{
|
||||
};
|
||||
|
||||
use super::{
|
||||
path::OwnedFilename,
|
||||
pty::{PseudoTerminalMaster, PseudoTerminalSlave},
|
||||
Filesystem,
|
||||
};
|
||||
@ -60,7 +61,7 @@ bitflags! {
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct CreateInfo {
|
||||
/// New entry name
|
||||
pub name: String,
|
||||
pub name: OwnedFilename,
|
||||
/// User ID of the entry
|
||||
pub uid: UserId,
|
||||
/// Group ID of the entry
|
||||
@ -74,7 +75,7 @@ pub struct CreateInfo {
|
||||
pub(crate) struct DirectoryData {
|
||||
pub(crate) imp: Box<dyn DirectoryImpl>,
|
||||
pub(crate) mountpoint: IrqSafeSpinlock<Option<NodeRef>>,
|
||||
pub(crate) children: IrqSafeSpinlock<Vec<(String, NodeRef)>>,
|
||||
pub(crate) children: IrqSafeSpinlock<Vec<(OwnedFilename, NodeRef)>>,
|
||||
}
|
||||
|
||||
pub(crate) struct SymlinkData {
|
||||
|
@ -6,7 +6,11 @@ use yggdrasil_abi::{
|
||||
io::{DeviceRequest, DirectoryEntry, FileMode, GroupId, OpenOptions, UserId},
|
||||
};
|
||||
|
||||
use crate::vfs::file::{File, FileRef};
|
||||
use crate::vfs::{
|
||||
file::{File, FileRef},
|
||||
path::OwnedFilename,
|
||||
Filename,
|
||||
};
|
||||
|
||||
use super::{AccessToken, CreateInfo, DirectoryData, Metadata, Node, NodeFlags, NodeImpl, NodeRef};
|
||||
|
||||
@ -75,7 +79,7 @@ impl Node {
|
||||
/// filesystem.
|
||||
pub fn lookup_or_load(
|
||||
self: &NodeRef,
|
||||
name: &str,
|
||||
name: &Filename,
|
||||
_check: AccessToken,
|
||||
) -> Result<NodeRef, Error> {
|
||||
let dir = self.as_directory()?;
|
||||
@ -99,7 +103,7 @@ impl Node {
|
||||
}
|
||||
|
||||
/// Creates an entry within a directory with given [CreateInfo].
|
||||
pub fn create(self: &NodeRef, info: &CreateInfo, check: AccessToken) -> Result<NodeRef, Error> {
|
||||
pub fn create(self: &NodeRef, info: CreateInfo, check: AccessToken) -> Result<NodeRef, Error> {
|
||||
let directory = self.as_directory()?;
|
||||
let node = directory.imp.create_node(self, info.ty)?;
|
||||
|
||||
@ -111,31 +115,32 @@ impl Node {
|
||||
check.clone(),
|
||||
)?;
|
||||
|
||||
self.create_node(node, &info.name, check)
|
||||
self.create_node(node, info.name, check)
|
||||
}
|
||||
|
||||
/// Attaches a pre-created node to its parent
|
||||
pub fn create_node(
|
||||
pub fn create_node<F: Into<OwnedFilename>>(
|
||||
self: &NodeRef,
|
||||
node: NodeRef,
|
||||
name: &str,
|
||||
name: F,
|
||||
_check: AccessToken,
|
||||
) -> Result<NodeRef, Error> {
|
||||
let filename = name.into();
|
||||
let directory = self.as_directory()?;
|
||||
|
||||
match directory.imp.attach_node(self, &node, name) {
|
||||
match directory.imp.attach_node(self, &node, filename.as_ref()) {
|
||||
Ok(_) | Err(Error::NotImplemented) => (),
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
|
||||
// Attach the created node to the directory in memory cache
|
||||
self.add_child(name, node.clone())?;
|
||||
self.add_child(filename, node.clone())?;
|
||||
|
||||
Ok(node)
|
||||
}
|
||||
|
||||
/// Removes a regular file, device or symlink from the directory
|
||||
pub fn remove_file(self: &NodeRef, name: &str, check: AccessToken) -> Result<(), Error> {
|
||||
pub fn remove_file(self: &NodeRef, name: &Filename, check: AccessToken) -> Result<(), Error> {
|
||||
let directory = self.as_directory()?;
|
||||
let child = self.lookup_or_load(name, check)?;
|
||||
|
||||
@ -166,12 +171,10 @@ impl Node {
|
||||
pub fn move_node(
|
||||
source: &NodeRef,
|
||||
destination: &NodeRef,
|
||||
source_name: &str,
|
||||
destination_name: &str,
|
||||
source_name: &Filename,
|
||||
destination_name: &Filename,
|
||||
access: AccessToken,
|
||||
) -> Result<(), Error> {
|
||||
// TODO sanity checks: source and destination is not the same
|
||||
// filenames are valid
|
||||
if !Self::is_same_filesystem(source, destination) {
|
||||
return Err(Error::CrossDeviceLink);
|
||||
}
|
||||
@ -295,7 +298,7 @@ impl Node {
|
||||
}
|
||||
|
||||
impl DirectoryData {
|
||||
fn remove_child(&self, name: &str) {
|
||||
fn remove_child(&self, name: &Filename) {
|
||||
let mut children = self.children.lock();
|
||||
|
||||
children.retain(|(t, child)| {
|
||||
|
@ -6,7 +6,10 @@ use yggdrasil_abi::{
|
||||
io::{DirectoryEntry, FileType, OpenOptions},
|
||||
};
|
||||
|
||||
use crate::vfs::file::{DirectoryOpenPosition, InstanceData};
|
||||
use crate::vfs::{
|
||||
file::{DirectoryOpenPosition, InstanceData},
|
||||
Filename,
|
||||
};
|
||||
|
||||
use super::{Metadata, NodeRef};
|
||||
|
||||
@ -124,7 +127,7 @@ pub trait DirectoryImpl: CommonImpl {
|
||||
}
|
||||
|
||||
/// Associates the given node with the directory, creating an entry for it inside
|
||||
fn attach_node(&self, parent: &NodeRef, child: &NodeRef, name: &str) -> Result<(), Error> {
|
||||
fn attach_node(&self, parent: &NodeRef, child: &NodeRef, name: &Filename) -> Result<(), Error> {
|
||||
let _ = parent;
|
||||
let _ = child;
|
||||
let _ = name;
|
||||
@ -132,7 +135,7 @@ pub trait DirectoryImpl: CommonImpl {
|
||||
}
|
||||
|
||||
/// Removes an entry of the directory with given name
|
||||
fn unlink_node(&self, parent: &NodeRef, child: &NodeRef, name: &str) -> Result<(), Error> {
|
||||
fn unlink_node(&self, parent: &NodeRef, child: &NodeRef, name: &Filename) -> Result<(), Error> {
|
||||
let _ = parent;
|
||||
let _ = child;
|
||||
let _ = name;
|
||||
@ -140,7 +143,7 @@ pub trait DirectoryImpl: CommonImpl {
|
||||
}
|
||||
|
||||
/// Fetches the child of the directory with given name
|
||||
fn lookup(&self, node: &NodeRef, name: &str) -> Result<NodeRef, Error> {
|
||||
fn lookup(&self, node: &NodeRef, name: &Filename) -> Result<NodeRef, Error> {
|
||||
let _ = node;
|
||||
let _ = name;
|
||||
Err(Error::NotImplemented)
|
||||
|
@ -1,6 +1,6 @@
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
use alloc::string::String;
|
||||
use crate::vfs::path::OwnedFilename;
|
||||
|
||||
use super::{Node, NodeRef};
|
||||
|
||||
@ -22,7 +22,7 @@ impl Node {
|
||||
}
|
||||
|
||||
/// Adds an entry to the directory tree cache
|
||||
pub fn add_child<S: Into<String>>(
|
||||
pub fn add_child<S: Into<OwnedFilename>>(
|
||||
self: &NodeRef,
|
||||
name: S,
|
||||
child: NodeRef,
|
||||
|
@ -0,0 +1,167 @@
|
||||
use core::{borrow::Borrow, fmt, mem, ops::Deref};
|
||||
|
||||
use alloc::{boxed::Box, string::String};
|
||||
|
||||
use yggdrasil_abi::error::Error;
|
||||
|
||||
#[derive(PartialEq, Eq, Debug, Hash, PartialOrd, Ord)]
|
||||
#[repr(transparent)]
|
||||
pub struct Filename(str);
|
||||
|
||||
#[derive(Clone, PartialEq, Eq, Debug, Hash, PartialOrd, Ord)]
|
||||
#[repr(transparent)]
|
||||
pub struct OwnedFilename(Box<str>);
|
||||
|
||||
impl Filename {
|
||||
pub const DOT: &'static Filename = unsafe { Self::from_str_unchecked(".") };
|
||||
pub const DOT_DOT: &'static Filename = unsafe { Self::from_str_unchecked("..") };
|
||||
|
||||
pub fn is_dot_or_dotdot(&self) -> bool {
|
||||
matches!(&self.0, "." | "..")
|
||||
}
|
||||
|
||||
pub fn new(name: &str) -> Result<&Self, Error> {
|
||||
if !name.is_empty() && !name.contains('/') {
|
||||
Ok(unsafe { Self::from_str_unchecked(name) })
|
||||
} else {
|
||||
Err(Error::InvalidArgument)
|
||||
}
|
||||
}
|
||||
|
||||
/// # Safety
|
||||
///
|
||||
/// The function is memory safe, but is still marked unsafe because it does not check
|
||||
/// the filename validity invariants.
|
||||
#[inline(always)]
|
||||
pub const unsafe fn from_str_unchecked(name: &str) -> &Self {
|
||||
mem::transmute(name)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for Filename {
|
||||
fn as_ref(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Filename {
|
||||
type Target = str;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Filename {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Display::fmt(&self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
impl OwnedFilename {
|
||||
pub fn new<S: AsRef<str>>(filename: S) -> Result<Self, Error> {
|
||||
Filename::new(filename.as_ref()).map(Self::from)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<str> for OwnedFilename {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Filename> for OwnedFilename {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &Filename {
|
||||
unsafe { Filename::from_str_unchecked(&self.0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for OwnedFilename {
|
||||
type Target = str;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for OwnedFilename {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||
Self::new(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<String> for OwnedFilename {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||
Self::new(&value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Filename> for OwnedFilename {
|
||||
#[inline]
|
||||
fn from(value: &Filename) -> Self {
|
||||
Self(value.0.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl Borrow<Filename> for OwnedFilename {
|
||||
fn borrow(&self) -> &Filename {
|
||||
unsafe { Filename::from_str_unchecked(&self.0) }
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<Filename> for OwnedFilename {
|
||||
fn eq(&self, other: &Filename) -> bool {
|
||||
*self.0 == other.0
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for OwnedFilename {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
fmt::Display::fmt(&*self.0, f)
|
||||
}
|
||||
}
|
||||
|
||||
// impl<'a> TryFrom<&'a str> for Filename<'a> {
|
||||
// type Error = Error;
|
||||
//
|
||||
// fn try_from(value: &'a str) -> Result<Self, Self::Error> {
|
||||
// if !value.contains('/') && !value.is_empty() {
|
||||
// Ok(Self(value))
|
||||
// } else {
|
||||
// Err(Error::InvalidArgument)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl Deref for Filename<'_> {
|
||||
// type Target = str;
|
||||
//
|
||||
// fn deref(&self) -> &Self::Target {
|
||||
// self.0
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl OwnedFilename {
|
||||
// pub fn dot() -> Self {
|
||||
// Self(".".into())
|
||||
// }
|
||||
//
|
||||
// pub fn dotdot() -> Self {
|
||||
// Self("..".into())
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// impl Deref for OwnedFilename {
|
||||
// type Target = str;
|
||||
//
|
||||
// fn deref(&self) -> &Self::Target {
|
||||
// &*self.0
|
||||
// }
|
||||
// }
|
@ -9,7 +9,7 @@ use libk::{
|
||||
device::char::CharDevice,
|
||||
fs::devfs,
|
||||
random,
|
||||
vfs::{impls::read_fn_node, FileReadiness},
|
||||
vfs::{impls::read_fn_node, FileReadiness, OwnedFilename},
|
||||
};
|
||||
|
||||
struct Null;
|
||||
@ -87,10 +87,10 @@ pub fn add_pseudo_devices() -> Result<(), Error> {
|
||||
});
|
||||
|
||||
let root = devfs::root();
|
||||
root.add_child("urandom", urandom)?;
|
||||
root.add_child(OwnedFilename::new("urandom").unwrap(), urandom)?;
|
||||
|
||||
devfs::add_named_char_device(Arc::new(Null), "null".into(), FileMode::new(0o666))?;
|
||||
devfs::add_named_char_device(Arc::new(Zero), "zero".into(), FileMode::new(0o666))?;
|
||||
devfs::add_named_char_device(Arc::new(Null), "null", FileMode::new(0o666))?;
|
||||
devfs::add_named_char_device(Arc::new(Zero), "zero", FileMode::new(0o666))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use libk::{
|
||||
fs::devfs,
|
||||
random,
|
||||
task::{binary::LoadOptions, process::Process, runtime, thread::Thread},
|
||||
vfs::{impls::fn_hardlink, IoContext, NodeRef},
|
||||
vfs::{impls::fn_hardlink, IoContext, NodeRef, OwnedFilename},
|
||||
};
|
||||
use memfs::MemoryFilesystem;
|
||||
|
||||
@ -35,7 +35,7 @@ pub fn kinit() -> Result<(), Error> {
|
||||
|
||||
devfs::root()
|
||||
.add_child(
|
||||
"tty",
|
||||
OwnedFilename::new("tty").unwrap(),
|
||||
fn_hardlink(|| {
|
||||
let thread = Thread::current();
|
||||
let process = thread.process();
|
||||
|
@ -36,7 +36,7 @@
|
||||
#![no_main]
|
||||
|
||||
use abi::{error::Error, io::FileMode};
|
||||
use alloc::{borrow::ToOwned, string::String};
|
||||
use alloc::string::String;
|
||||
use arch::Platform;
|
||||
use git_version::git_version;
|
||||
use kernel_arch::{Architecture, ArchitectureImpl};
|
||||
@ -148,11 +148,9 @@ pub fn kernel_main() -> ! {
|
||||
CPU_INIT_FENCE.wait_all(ArchitectureImpl::cpu_count());
|
||||
|
||||
// Add keyboard device
|
||||
if let Err(error) = devfs::add_named_char_device(
|
||||
ygg_driver_input::setup(),
|
||||
"kbd".to_owned(),
|
||||
FileMode::new(0o660),
|
||||
) {
|
||||
if let Err(error) =
|
||||
devfs::add_named_char_device(ygg_driver_input::setup(), "kbd", FileMode::new(0o660))
|
||||
{
|
||||
log::error!("Couldn't add keyboard device: {error:?}");
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user