Add Path/PathBuf + GetRandom

This commit is contained in:
Mark Poliakov 2023-12-05 12:24:04 +02:00
parent 50c182293e
commit 0604df7720
11 changed files with 339 additions and 47 deletions

View File

@ -7,9 +7,9 @@ edition = "2021"
[dependencies]
core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" }
alloc = { version = "1.0.0", optional = true, package = "rustc-std-workspace-alloc" }
compiler_builtins = { version = "0.1", optional = true }
[features]
default = []
rustc-dep-of-std = ["core", "alloc", "compiler_builtins/rustc-dep-of-std"]
alloc = []
rustc-dep-of-std = ["core", "compiler_builtins/rustc-dep-of-std"]

View File

@ -30,6 +30,12 @@ primitive_enum!(
Interrupted = 12,
#[doc = "Operation has not completed yet"]
WouldBlock = 13,
#[doc = "Entry/file cannot be written to"]
ReadOnly = 14,
#[doc = "Requested operation cannot be performed or is invalid"]
InvalidOperation = 15,
#[doc = "No permission to access the entry/file"]
PermissionDenied = 16,
}
);

View File

@ -10,17 +10,29 @@ pub use terminal::{
TerminalInputOptions, TerminalLineOptions, TerminalOptions, TerminalOutputOptions, TerminalSize,
};
use crate::{transparent_wrapper, util::FixedString};
/// Raw file descriptor representation
#[derive(Clone, Copy, PartialEq, Debug, PartialOrd, Ord, Eq)]
#[repr(transparent)]
pub struct RawFd(pub u32);
transparent_wrapper! {
#[doc = "Unique per-user number"]
pub struct UserId(u32)
}
transparent_wrapper! {
#[doc = "Unique per-group number"]
pub struct GroupId(u32)
}
/// Raw directory entry representation
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, PartialEq)]
#[repr(C)]
pub struct DirectoryEntry {
/// Name of the entry
pub name: [u8; 256],
pub name: FixedString<256>,
/// Type of the entry
pub ty: FileType,
}
@ -78,3 +90,39 @@ impl From<u32> for RawFd {
Self(value)
}
}
impl UserId {
/// Root user identifier
pub const fn root() -> Self {
Self(0)
}
/// Returns `true` if the UserId represents a root user
pub const fn is_root(&self) -> bool {
self.0 == 0
}
}
impl From<u32> for UserId {
fn from(value: u32) -> Self {
Self(value)
}
}
impl GroupId {
/// Root group identifier
pub const fn root() -> Self {
Self(0)
}
/// Returns `true` if the GroupId represents a root group
pub const fn is_root(&self) -> bool {
self.0 == 0
}
}
impl From<u32> for GroupId {
fn from(value: u32) -> Self {
Self(value)
}
}

View File

@ -3,8 +3,12 @@
#![feature(trace_macros, const_trait_impl)]
#![deny(missing_docs)]
#[cfg(feature = "alloc")]
extern crate alloc;
pub(crate) mod macros;
pub mod pass;
pub mod util;
pub mod arch;
pub mod error;

View File

@ -61,6 +61,12 @@ macro_rules! bitflags_impl_common {
pub const fn contains(self, bits: $name) -> bool {
self.0 & bits.bits() == bits.bits()
}
/// Returns `true` if the value contains any of the bits in `bits`
#[inline]
pub const fn contains_any(self, bits: $name) -> bool {
self.0 & bits.bits() != 0
}
}
impl From<$repr> for $name {
@ -189,3 +195,31 @@ macro_rules! bitflags {
$crate::bitflags_impl_default!($name, $repr$(, $struct_default)?);
};
}
/// Generates a #[repr(transparent)] wrapper for a value with Debug, Copy, Eq, Ord, Hash derived +
/// Into<T> implemented
#[macro_export]
macro_rules! transparent_wrapper {
($(#[$struct_meta:meta])* $vis:vis struct $name:ident ( $ty:ty )) => {
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
$(#[$struct_meta])* $vis struct $name ($ty);
impl $name {
/// Constructs the value from its raw representation.
///
/// # Safety
///
/// Unsafe: the actual subset of values represented by this type may not include all
/// the raw values.
pub unsafe fn from_raw(value: $ty) -> $name {
$name(value)
}
}
impl From<$name> for $ty {
fn from(value: $name) -> $ty {
value.0
}
}
};
}

View File

@ -1,29 +0,0 @@
//! Filesystem path definitions and manipulation functions
/// Parent directory path element
pub const PARENT_NAME: &str = "..";
/// Path element that refers to itself
pub const SELF_NAME: &str = ".";
/// String representation of a path separator
pub const SEPARATOR_STR: &str = "/";
/// Character that separates the path elements
pub const SEPARATOR: char = '/';
/// Splits a path, returning the first element and the rest
pub fn split_left(path: &str) -> (&str, &str) {
if let Some((left, right)) = path.split_once(SEPARATOR) {
(left, right.trim_start_matches(SEPARATOR))
} else {
(path, "")
}
}
/// Splits a path, returning the last element and the path preceding it
pub fn split_right(path: &str) -> (&str, &str) {
if let Some((left, right)) = path.trim_end_matches(SEPARATOR).rsplit_once(SEPARATOR) {
(left.trim_end_matches(SEPARATOR), right)
} else {
("", path)
}
}

11
src/path/mod.rs Normal file
View File

@ -0,0 +1,11 @@
//! Filesystem path definitions and manipulation functions
#![allow(missing_docs)]
mod path;
#[cfg(feature = "alloc")]
mod path_buf;
pub use path::Path;
#[cfg(feature = "alloc")]
pub use path_buf::PathBuf;

87
src/path/path.rs Normal file
View File

@ -0,0 +1,87 @@
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
pub struct Path(str);
impl Path {
pub const SEPARATOR: char = '/';
pub const SEPARATOR_STR: &'static str = "/";
/// Parent directory path element
pub const PARENT_NAME: &'static str = "..";
/// Path element that refers to itself
pub const SELF_NAME: &'static str = ".";
pub fn from_str(s: &str) -> &Self {
unsafe { core::mem::transmute(s) }
}
pub fn empty() -> &'static Self {
Self::from_str("")
}
pub fn trim_start_separators(&self) -> &Self {
Self::from_str(self.0.trim_start_matches(Self::SEPARATOR))
}
pub fn trim_end_separators(&self) -> &Self {
Self::from_str(self.0.trim_end_matches(Self::SEPARATOR))
}
pub fn display(&self) -> &str {
&self.0
}
pub fn split_right(&self) -> (&Path, &str) {
if let Some((left, right)) = self
.0
.trim_end_matches(Self::SEPARATOR)
.rsplit_once(Self::SEPARATOR)
{
(
Path::from_str(left.trim_end_matches(Self::SEPARATOR)),
right,
)
} else {
(Path::empty(), &self.0)
}
}
pub fn split_left(&self) -> (&str, &Path) {
if let Some((left, right)) = self.0.split_once(Self::SEPARATOR) {
(
left,
Path::from_str(right.trim_start_matches(Self::SEPARATOR)),
)
} else {
(&self.0, Path::empty())
}
}
#[inline]
pub fn is_absolute(&self) -> bool {
self.0.starts_with(Self::SEPARATOR)
}
#[inline]
pub fn is_empty(&self) -> bool {
self.0.is_empty()
}
}
impl AsRef<str> for Path {
fn as_ref(&self) -> &str {
&self.0
}
}
impl AsRef<Path> for Path {
fn as_ref(&self) -> &Path {
self
}
}
impl AsRef<Path> for str {
fn as_ref(&self) -> &Path {
Path::from_str(self)
}
}

67
src/path/path_buf.rs Normal file
View File

@ -0,0 +1,67 @@
use crate::path::Path;
use alloc::{
borrow::{Borrow, ToOwned},
string::String,
};
use core::ops::Deref;
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct PathBuf(String);
impl PathBuf {
pub fn new() -> Self {
Self(String::new())
}
pub fn from_str(s: &str) -> Self {
Self(String::from(s))
}
pub fn push<P: AsRef<Path>>(&mut self, path: P) {
todo!()
}
pub fn display(&self) -> &str {
self.0.as_str()
}
}
impl Deref for PathBuf {
type Target = Path;
fn deref(&self) -> &Self::Target {
Path::from_str(self.0.as_str())
}
}
impl AsRef<Path> for PathBuf {
fn as_ref(&self) -> &Path {
Path::from_str(self.0.as_str())
}
}
impl From<&Path> for PathBuf {
fn from(value: &Path) -> Self {
Self::from_str(value.as_ref())
}
}
impl From<&str> for PathBuf {
fn from(value: &str) -> Self {
Self::from_str(value)
}
}
impl ToOwned for Path {
type Owned = PathBuf;
fn to_owned(&self) -> Self::Owned {
PathBuf::from(self)
}
}
impl Borrow<Path> for PathBuf {
fn borrow(&self) -> &Path {
Path::from_str(self.0.as_str())
}
}

View File

@ -4,30 +4,30 @@ use crate::primitive_enum;
primitive_enum!(
#[doc = "Describes a system call issued to the kernel"]
pub enum SyscallFunction: usize {
#[doc = "Terminate the caller thread"]
Exit = 1,
#[doc = "Suspend the caller task for some time"]
Nanosleep = 2,
Nanosleep = 1,
#[doc = "Map a virtual memory region"]
MapMemory = 3,
MapMemory = 2,
#[doc = "Release a virtual memory region"]
UnmapMemory = 4,
UnmapMemory = 3,
#[doc = "Write data to a file descriptor"]
Write = 5,
Write = 4,
#[doc = "Read data from a file descriptor"]
Read = 6,
Read = 5,
#[doc = "Open a file"]
Open = 7,
Open = 6,
#[doc = "Close a file descriptor"]
Close = 8,
Close = 7,
#[doc = "Open a directory for reading"]
OpenDirectory = 9,
OpenDirectory = 8,
#[doc = "Read entries from a directory descriptor"]
ReadDirectory = 10,
ReadDirectory = 9,
#[doc = "Create a directory"]
CreateDirectory = 11,
#[doc = "Remove a file, directory or other entry"]
Remove = 12,
CreateDirectory = 10,
#[doc = "Remove a file"]
Remove = 11,
#[doc = "Remove a directory"]
RemoveDirectory = 12,
#[doc = "Retrieves metadata for a filesystem entry"]
GetMetadata = 13,
#[doc = "Seek a file descriptor to the specified position"]
@ -60,6 +60,10 @@ primitive_enum!(
SetSignalEntry = 51,
#[doc = "Exit from a syscall handler"]
ExitSignal = 52,
#[doc = "Terminate the caller thread"]
ExitThread = 53,
#[doc = "Terminate the caller process"]
ExitProcess = 54,
#[doc = "Mount a filesystem"]
Mount = 101,
@ -68,5 +72,7 @@ primitive_enum!(
#[doc = "Print a message to the kernel's debug trace output"]
DebugTrace = 128,
#[doc = "Fetches bytes of random data"]
GetRandom = 129,
}
);

58
src/util.rs Normal file
View File

@ -0,0 +1,58 @@
//! Misc utilities for the ABI crate
use crate::error::Error;
use core::{fmt, str::FromStr};
/// Helper struct to hold a fixed-size string of UTF-8 characters
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct FixedString<const N: usize> {
data: [u8; N],
len: usize,
}
impl<const N: usize> FixedString<N> {
/// Returns an empty [FixedString]
pub const fn empty() -> Self {
Self {
data: [0; N],
len: 0,
}
}
}
impl<const N: usize> fmt::Debug for FixedString<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.as_ref(), f)
}
}
impl<const N: usize> AsRef<str> for FixedString<N> {
fn as_ref(&self) -> &str {
// Safety: totally safe, the FixedString can only be constructed from a &str or be empty
unsafe { core::str::from_utf8_unchecked(&self.data[..self.len]) }
}
}
impl<const N: usize> FromStr for FixedString<N> {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.len() >= N {
return Err(Error::InvalidArgument);
}
let len = s.len();
let mut data = [0; N];
data[..len].copy_from_slice(s.as_bytes());
Ok(Self { data, len })
}
}
impl<const N: usize> PartialEq<&str> for FixedString<N> {
fn eq(&self, other: &&str) -> bool {
&self.data[..self.len] == other.as_bytes()
}
fn ne(&self, other: &&str) -> bool {
&self.data[..self.len] != other.as_bytes()
}
}