diff --git a/kernel/driver/fs/ext2/src/dir/mod.rs b/kernel/driver/fs/ext2/src/dir/mod.rs index f33366b7..108627d2 100644 --- a/kernel/driver/fs/ext2/src/dir/mod.rs +++ b/kernel/driver/fs/ext2/src/dir/mod.rs @@ -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 { - if value.len() >= 255 || value.is_empty() || value.contains('/') { + fn try_from(value: &'a Filename) -> Result { + 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 { + fn lookup(&self, _node: &NodeRef, name: &Filename) -> Result { 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); } diff --git a/kernel/driver/fs/memfs/src/lib.rs b/kernel/driver/fs/memfs/src/lib.rs index 1bd5f4ce..ca948667 100644 --- a/kernel/driver/fs/memfs/src/lib.rs +++ b/kernel/driver/fs/memfs/src/lib.rs @@ -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 MemoryFilesystem { 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 MemoryFilesystem { } let node = DirectoryNode::::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 MemoryFilesystem { 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)?; } diff --git a/kernel/libk/src/fs/devfs.rs b/kernel/libk/src/fs/devfs.rs index b8181dfe..7402cda6 100644 --- a/kernel/libk/src/fs/devfs.rs +++ b/kernel/libk/src/fs/devfs.rs @@ -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>(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>( dev: Arc, - 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>( +pub fn add_named_block_device>( dev: Arc, name: S, mode: FileMode, ) -> Result { - 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>( None, ); - DEVFS_ROOT.get().add_child(name, node.clone())?; + let filename = OwnedFilename::new(name)?; + DEVFS_ROOT.get().add_child(filename, node.clone())?; Ok(node) } diff --git a/kernel/libk/src/fs/sysfs/attribute/bytes.rs b/kernel/libk/src/fs/sysfs/attribute/bytes.rs index a1b4e39f..dd4b7109 100644 --- a/kernel/libk/src/fs/sysfs/attribute/bytes.rs +++ b/kernel/libk/src/fs/sysfs/attribute/bytes.rs @@ -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 Attribute for BytesAttribute { )) } - fn name(&self) -> &str { - V::NAME + // TODO implement this properly + fn name(&self) -> &Filename { + unsafe { Filename::from_str_unchecked(V::NAME) } } } diff --git a/kernel/libk/src/fs/sysfs/attribute/mod.rs b/kernel/libk/src/fs/sysfs/attribute/mod.rs index cecbd61e..5617f452 100644 --- a/kernel/libk/src/fs/sysfs/attribute/mod.rs +++ b/kernel/libk/src/fs/sysfs/attribute/mod.rs @@ -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: Sync + Send { fn instantiate(&self, parent: &Arc>) -> Result; - fn name(&self) -> &str; + fn name(&self) -> &Filename; } pub use bytes::{BytesAttribute, BytesAttributeOps}; diff --git a/kernel/libk/src/fs/sysfs/attribute/string.rs b/kernel/libk/src/fs/sysfs/attribute/string.rs index 3906ca6e..1a73a1d2 100644 --- a/kernel/libk/src/fs/sysfs/attribute/string.rs +++ b/kernel/libk/src/fs/sysfs/attribute/string.rs @@ -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 Attribute for StringAttribute { )) } - fn name(&self) -> &str { - V::NAME + // TODO implement this properly + fn name(&self) -> &Filename { + unsafe { Filename::from_str_unchecked(V::NAME) } } } diff --git a/kernel/libk/src/fs/sysfs/object.rs b/kernel/libk/src/fs/sysfs/object.rs index f87274f2..7e52d80b 100644 --- a/kernel/libk/src/fs/sysfs/object.rs +++ b/kernel/libk/src/fs/sysfs/object.rs @@ -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 KObject { Ok(()) } - pub fn add_object, T>( + pub fn add_object, T>( &self, name: S, child: Arc>, ) -> 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 { diff --git a/kernel/libk/src/vfs/ioctx.rs b/kernel/libk/src/vfs/ioctx.rs index 4af88393..1b5c9819 100644 --- a/kernel/libk/src/vfs/ioctx.rs +++ b/kernel/libk/src/vfs/ioctx.rs @@ -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() { diff --git a/kernel/libk/src/vfs/mod.rs b/kernel/libk/src/vfs/mod.rs index 03726d71..cf45f8be 100644 --- a/kernel/libk/src/vfs/mod.rs +++ b/kernel/libk/src/vfs/mod.rs @@ -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; diff --git a/kernel/libk/src/vfs/node/impls.rs b/kernel/libk/src/vfs/node/impls.rs index 292c147a..02b3d8db 100644 --- a/kernel/libk/src/vfs/node/impls.rs +++ b/kernel/libk/src/vfs/node/impls.rs @@ -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(read: R) -> NodeRef { } /// Creates an in-memory directory from the iterator -pub fn mdir, I: IntoIterator>(it: I) -> NodeRef { +pub fn mdir, I: IntoIterator>(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, I: IntoIterator>(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 } diff --git a/kernel/libk/src/vfs/node/mod.rs b/kernel/libk/src/vfs/node/mod.rs index 2ed5a19f..44599688 100644 --- a/kernel/libk/src/vfs/node/mod.rs +++ b/kernel/libk/src/vfs/node/mod.rs @@ -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, pub(crate) mountpoint: IrqSafeSpinlock>, - pub(crate) children: IrqSafeSpinlock>, + pub(crate) children: IrqSafeSpinlock>, } pub(crate) struct SymlinkData { diff --git a/kernel/libk/src/vfs/node/ops.rs b/kernel/libk/src/vfs/node/ops.rs index e698ec21..872e6425 100644 --- a/kernel/libk/src/vfs/node/ops.rs +++ b/kernel/libk/src/vfs/node/ops.rs @@ -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 { 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 { + pub fn create(self: &NodeRef, info: CreateInfo, check: AccessToken) -> Result { 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>( self: &NodeRef, node: NodeRef, - name: &str, + name: F, _check: AccessToken, ) -> Result { + 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)| { diff --git a/kernel/libk/src/vfs/node/traits.rs b/kernel/libk/src/vfs/node/traits.rs index 0904f0f7..2607e8d1 100644 --- a/kernel/libk/src/vfs/node/traits.rs +++ b/kernel/libk/src/vfs/node/traits.rs @@ -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 { + fn lookup(&self, node: &NodeRef, name: &Filename) -> Result { let _ = node; let _ = name; Err(Error::NotImplemented) diff --git a/kernel/libk/src/vfs/node/tree.rs b/kernel/libk/src/vfs/node/tree.rs index 5e701fa1..5c7b16d5 100644 --- a/kernel/libk/src/vfs/node/tree.rs +++ b/kernel/libk/src/vfs/node/tree.rs @@ -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>( + pub fn add_child>( self: &NodeRef, name: S, child: NodeRef, diff --git a/kernel/libk/src/vfs/path.rs b/kernel/libk/src/vfs/path.rs index e69de29b..c39971c7 100644 --- a/kernel/libk/src/vfs/path.rs +++ b/kernel/libk/src/vfs/path.rs @@ -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); + +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 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>(filename: S) -> Result { + Filename::new(filename.as_ref()).map(Self::from) + } +} + +impl AsRef for OwnedFilename { + #[inline] + fn as_ref(&self) -> &str { + &self.0 + } +} + +impl AsRef 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::new(value) + } +} + +impl TryFrom for OwnedFilename { + type Error = Error; + + fn try_from(value: String) -> Result { + Self::new(&value) + } +} + +impl From<&Filename> for OwnedFilename { + #[inline] + fn from(value: &Filename) -> Self { + Self(value.0.into()) + } +} + +impl Borrow for OwnedFilename { + fn borrow(&self) -> &Filename { + unsafe { Filename::from_str_unchecked(&self.0) } + } +} + +impl PartialEq 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 { +// 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 +// } +// } diff --git a/kernel/src/fs/pseudo.rs b/kernel/src/fs/pseudo.rs index d20a065a..239b89d2 100644 --- a/kernel/src/fs/pseudo.rs +++ b/kernel/src/fs/pseudo.rs @@ -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(()) } diff --git a/kernel/src/init.rs b/kernel/src/init.rs index 611f9ff0..f4e0b2a3 100644 --- a/kernel/src/init.rs +++ b/kernel/src/init.rs @@ -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(); diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 3a3dae15..0fc18cc0 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -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:?}"); }