diff --git a/build.rs b/build.rs index dc57811..d4b8708 100644 --- a/build.rs +++ b/build.rs @@ -3,6 +3,17 @@ use std::{ path::Path, }; +const RENAMES: &[(&str, &str)] = &[ + ("CUsizeResult", "size_t"), + ("CIsizeResult", "ssize_t"), + ("CEofResult", "int"), + ("CIntCountResult", "int"), + ("CIntZeroResult", "int"), + ("CFdResult", "int"), + ("COffsetResult", "off_t"), + ("CPidResult", "pid_t"), +]; + fn include_dir(d: &DirEntry) -> bool { d.metadata().map(|m| m.is_dir()).unwrap_or(false) && d.path() @@ -26,7 +37,12 @@ fn generate_header>(config_path: P) { .with_extension("h"); let mod_path = config_path.with_file_name("mod.rs"); - let config = cbindgen::Config::from_file(config_path).unwrap(); + let mut config = cbindgen::Config::from_file(config_path).unwrap(); + + config + .export + .rename + .extend(RENAMES.into_iter().map(|&(x, y)| (x.into(), y.into()))); cbindgen::Builder::new() .with_config(config) diff --git a/src/allocator.rs b/src/allocator.rs index e49e450..8b3a20d 100644 --- a/src/allocator.rs +++ b/src/allocator.rs @@ -1,4 +1,81 @@ +use core::{ + alloc::{GlobalAlloc, Layout}, + intrinsics, + ptr::NonNull, +}; + use libyalloc::global::GlobalAllocator; +use yggdrasil_rt::memcpy; + +use crate::{error::EResult, header::errno::ENOMEM, util::NonNullExt}; #[global_allocator] pub static GLOBAL_ALLOCATOR: GlobalAllocator = GlobalAllocator; + +const ALIGN: usize = 16; +const OFFSET: usize = ALIGN; + +unsafe fn get_allocation(ptr: NonNull) -> (NonNull, Layout) { + assert!(usize::from(ptr.addr()) > 0x10); + let real_ptr = ptr.sub_ext(OFFSET); + let size = *real_ptr.cast::().as_ref(); + let layout = Layout::from_size_align(size.try_into().unwrap(), ALIGN).unwrap(); + (real_ptr, layout) +} + +// TODO checked_add here +pub fn c_allocate(size: usize) -> EResult> { + let size = (size + ALIGN - 1) & !(ALIGN - 1); + let layout = Layout::from_size_align(size + OFFSET, ALIGN).unwrap(); + + let ptr = match NonNull::new(unsafe { GlobalAllocator.alloc(layout) }) { + Some(ptr) => ptr, + None => return EResult::Err(ENOMEM), + }; + + // Store allocation size + unsafe { + *ptr.cast::().as_mut() = layout.size().try_into().unwrap(); + } + + unsafe { EResult::Ok(ptr.add_ext(OFFSET)) } +} + +pub fn c_allocate_zeroed(nmemb: usize, size: usize) -> EResult> { + match nmemb.checked_mul(size) { + Some(size) => { + let ptr = c_allocate(size)?; + unsafe { + intrinsics::write_bytes(ptr.as_ptr(), 0, size); + } + EResult::Ok(ptr) + } + None => EResult::Err(ENOMEM), + } +} + +pub unsafe fn c_reallocate(old_ptr: Option>, size: usize) -> EResult> { + match old_ptr { + Some(old_ptr) => { + // TODO libyalloc realloc + let (real_old_ptr, old_layout) = get_allocation(old_ptr); + let new_ptr = c_allocate(size)?; + + memcpy( + new_ptr.cast().as_ptr(), + old_ptr.cast().as_ptr(), + old_layout.size() - OFFSET, + ); + + GlobalAllocator.dealloc(real_old_ptr.as_ptr(), old_layout); + + EResult::Ok(new_ptr) + } + None => c_allocate(size), + } +} + +pub unsafe fn c_free(ptr: NonNull) { + let (real_ptr, layout) = get_allocation(ptr); + GlobalAllocator.dealloc(real_ptr.as_ptr(), layout); +} diff --git a/src/error.rs b/src/error.rs index 9cebef6..2cd5bab 100644 --- a/src/error.rs +++ b/src/error.rs @@ -2,138 +2,378 @@ use core::{ convert::Infallible, ffi::c_int, ops::{ControlFlow, FromResidual, Try}, + ptr::{null_mut, NonNull}, }; -use crate::header::{errno::Errno, stdio::EOF}; +use yggdrasil_rt::io::RawFd; -pub trait CZeroResult { - fn into_zero_status(self) -> c_int; - fn into_eof_status(self) -> c_int; +use crate::header::{ + errno::{Errno, EBADF}, + stdio::EOF, + sys_types::{off_t, pid_t}, +}; + +/// On success: count +/// On failure: 0 +/// +/// Examples: +/// +/// fwrite()/fread() functions +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[repr(transparent)] +pub struct CUsizeResult(pub usize); + +/// On success: count +/// On failure: -1 +/// +/// Examples: +/// +/// read() +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[repr(transparent)] +pub struct CIsizeResult(pub isize); + +/// On success: count +/// On failure: -1 +/// +/// Examples: +/// +/// printf() family of functions +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[repr(transparent)] +pub struct CIntCountResult(pub c_int); + +/// On success: 0 +/// On failure: -1 +/// +/// Examples: +/// +/// ftrylockfile() +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[repr(transparent)] +pub struct CIntZeroResult(c_int); + +/// On success: file descriptor +/// On failure: -1 +/// +/// Examples: +/// +/// open()/fileno() +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[repr(transparent)] +pub struct CFdResult(c_int); + +/// On success: pid_t +/// On failure: -1 +/// +/// Examples: +/// +/// fork() +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[repr(transparent)] +pub struct CPidResult(pid_t); + +/// On success: some non-EOF value +/// On failure: EOF +/// +/// Examples: +/// +/// fputc()/fgetc() +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[repr(transparent)] +pub struct CEofResult(pub c_int); + +/// On success: a valid off_t +/// On failure: -1 +/// +/// Examples: +/// +/// ftello() +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[repr(transparent)] +pub struct COffsetResult(pub off_t); + +/// On success: NonNull ptr +/// On failure: NULL +/// +/// Examples: +/// +/// malloc()/fgets() +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +#[repr(transparent)] +pub struct CPtrResult(*mut T); + +impl FromResidual> for CUsizeResult { + fn from_residual(residual: EResult) -> Self { + let err = residual.unwrap_err(); + unsafe { + errno = err; + } + Self(0) + } } -pub trait CSizeResult { - fn into_size_status(self) -> usize; +impl CIsizeResult { + pub const ERR: Self = Self(-1); + + pub fn success(value: usize) -> Self { + Self(value.try_into().unwrap()) + } } -pub trait TryFromExt: Sized { - fn e_try_from(value: T) -> EResult; +impl FromResidual> for CIsizeResult { + fn from_residual(residual: EResult) -> Self { + let err = residual.unwrap_err(); + unsafe { + errno = err; + } + Self(-1) + } } -pub trait OptionExt { - fn e_ok_or(self, err: yggdrasil_rt::Error) -> EResult; +impl FromResidual> for CIntCountResult { + fn from_residual(residual: EResult) -> Self { + let err = residual.unwrap_err(); + unsafe { + errno = err; + } + Self(-1) + } } -// TODO thread_local -#[no_mangle] -pub static mut errno: Errno = Errno(0); - -pub enum EResult { - Ok(T), - Err(yggdrasil_rt::Error), - Errno(Errno), +impl CIntZeroResult { + pub const ERR: Self = Self(-1); + pub const OK: Self = Self(0); } -impl From> for EResult { - fn from(value: Result) -> Self { - match value { - Ok(value) => Self::Ok(value), - Err(error) => Self::Err(error), +impl FromResidual> for CIntZeroResult { + fn from_residual(residual: EResult) -> Self { + let err = residual.unwrap_err(); + unsafe { + errno = err; + } + Self::ERR + } +} + +impl CFdResult { + pub const ERR: Self = Self(-1); + + pub fn success(fd: RawFd) -> Self { + Self(fd.0.try_into().unwrap()) + } +} + +impl FromResidual> for CFdResult { + fn from_residual(residual: EResult) -> Self { + let err = residual.unwrap_err(); + unsafe { + errno = err; + } + Self::ERR + } +} + +impl CEofResult { + pub const ERR: Self = Self(EOF); + + pub fn ok(&self) -> Option { + match self.0 { + EOF => None, + v => Some(v), } } } +impl FromResidual> for CEofResult { + fn from_residual(residual: EResult) -> Self { + let err = residual.unwrap_err(); + unsafe { + errno = err; + } + Self::ERR + } +} + +impl COffsetResult { + pub const ERR: Self = Self(-1); + + pub fn ok(self) -> Option { + if self.0 >= 0 { + Some(self.0) + } else { + None + } + } + + pub fn success(value: u64) -> Self { + Self(value.try_into().unwrap()) + } +} + +impl FromResidual> for COffsetResult { + fn from_residual(residual: EResult) -> Self { + let err = residual.unwrap_err(); + unsafe { + errno = err; + } + Self::ERR + } +} + +impl CPidResult { + pub const ERR: Self = Self(-1); + + pub fn success(pid: u32) -> Self { + Self(pid.try_into().unwrap()) + } +} + +impl FromResidual> for CPidResult { + fn from_residual(residual: EResult) -> Self { + let err = residual.unwrap_err(); + unsafe { + errno = err; + } + Self::ERR + } +} + +impl CPtrResult { + pub const ERR: Self = Self(null_mut()); + + pub const fn success(value: NonNull) -> Self { + Self(value.as_ptr()) + } +} + +impl FromResidual> for CPtrResult { + fn from_residual(residual: EResult) -> Self { + let err = residual.unwrap_err(); + unsafe { + errno = err; + } + Self::ERR + } +} + +///////////////// + +#[must_use = "ErrnoResult must be converted into its output type with proper errno set"] +pub enum EResult { + Ok(T), + Err(Errno), +} + impl EResult { - pub fn into_set_errno(self) -> EResult { + pub fn is_ok(&self) -> bool { + matches!(self, Self::Ok(_)) + } + + pub fn is_err(&self) -> bool { + matches!(self, Self::Err(_)) + } + + pub fn ok(self) -> Option { match self { - Self::Ok(value) => Self::Ok(value), - Self::Errno(e) => Self::Errno(e), + Self::Ok(value) => Some(value), + Self::Err(_) => None, + } + } + + pub fn unwrap(self) -> T { + todo!() + } + + pub fn unwrap_err(self) -> Errno { + match self { + Self::Ok(_) => panic!("Expected an error"), + Self::Err(err) => err, + } + } + + pub fn into_result E>(self, map_err: F, set_errno: bool) -> Result { + match self { + Self::Ok(value) => Ok(value), Self::Err(err) => { - let e = Errno::from(err); - unsafe { - errno = e; + if set_errno { + unsafe { + errno = err; + } } - Self::Errno(e) + Err(map_err(err)) } } } } -impl CZeroResult for Result<(), Errno> { - fn into_zero_status(self) -> c_int { - match self { - Self::Ok(_) => 0, - Self::Err(_) => -1, - } - } - - fn into_eof_status(self) -> c_int { - match self { - Self::Ok(_) => 0, - Self::Err(_) => EOF, - } - } -} - -impl CSizeResult for Result { - fn into_size_status(self) -> usize { - match self { - Self::Ok(value) => value, - Self::Err(_) => 0, - } - } -} - -impl FromResidual for EResult { - fn from_residual(residual: Errno) -> Self { - Self::Errno(residual) - } -} - -impl FromResidual for EResult { - fn from_residual(residual: yggdrasil_rt::Error) -> Self { - Self::Err(residual) - } -} - -impl FromResidual> for EResult { - fn from_residual(_residual: Result) -> Self { - todo!() - } -} - impl Try for EResult { type Output = T; - type Residual = Result; + type Residual = EResult; fn branch(self) -> ControlFlow { - match self.into_set_errno() { + match self { Self::Ok(value) => ControlFlow::Continue(value), - Self::Errno(e) => ControlFlow::Break(Err(e)), - Self::Err(_error) => unreachable!(), + Self::Err(err) => ControlFlow::Break(EResult::Err(err)), } } - fn from_output(_output: Self::Output) -> Self { - todo!() + fn from_output(output: Self::Output) -> Self { + Self::Ok(output) } } +impl FromResidual> for EResult { + fn from_residual(residual: EResult) -> Self { + let err = residual.unwrap_err(); + Self::Err(err) + } +} + +impl FromResidual> for EResult { + fn from_residual(residual: Result) -> Self { + let err = residual.unwrap_err(); + Self::Err(err.into()) + } +} + +impl> FromResidual> for Result { + fn from_residual(residual: EResult) -> Self { + let err = residual.unwrap_err(); + Err(err.into()) + } +} + +/////////////////////////////////////////////// + +pub trait OptionExt { + fn e_ok_or(self, err: Errno) -> EResult; +} + impl OptionExt for Option { - fn e_ok_or(self, err: yggdrasil_rt::Error) -> EResult { + fn e_ok_or(self, err: Errno) -> EResult { match self { - Some(value) => EResult::Ok(value), + Some(val) => EResult::Ok(val), None => EResult::Err(err), } } } -pub fn set_errno_result(e: Errno) -> Result { - set_errno(e); - Err(e) +/////////////////////////////////////////////// + +pub trait TryFromExt: Sized { + fn e_try_from(value: T) -> EResult; } -pub fn set_errno(e: Errno) { - unsafe { - errno = e; +impl TryFromExt for RawFd { + fn e_try_from(value: c_int) -> EResult { + match value { + 0.. => EResult::Ok(Self(value.try_into().unwrap())), + _ => EResult::Err(EBADF), + } } } + +// TODO thread_local +#[no_mangle] +pub static mut errno: Errno = Errno(0); diff --git a/src/file.rs b/src/file.rs index 907d238..27f3e94 100644 --- a/src/file.rs +++ b/src/file.rs @@ -10,8 +10,7 @@ use yggdrasil_rt::{ }; use crate::{ - error::{self, EResult}, - header::errno::{Errno, EBADF}, + error::{EResult, TryFromExt}, io::{AsRawFd, AsRawFdOpt, FromRawFd, IntoRawFd, Read, Seek, Write}, }; @@ -36,42 +35,41 @@ impl RawFile { pathname: P, opts: OpenOptions, mode: FileMode, - ) -> Result { - let fd = - EResult::from(unsafe { syscall::open(at, pathname.as_ref().as_str(), opts, mode) })?; - Ok(Self { fd }) + ) -> EResult { + let fd = unsafe { syscall::open(at, pathname.as_ref().as_str(), opts, mode) }?; + EResult::Ok(Self { fd }) } - pub unsafe fn close(self: &mut Self) -> Result<(), Errno> { - EResult::from(unsafe { syscall::close(self.fd) })?; + pub unsafe fn close(self: &mut Self) -> EResult<()> { + unsafe { syscall::close(self.fd) }?; self.fd = RawFd::NONE; - Ok(()) + EResult::Ok(()) } } impl Write for RawFile { - fn write(&mut self, data: &[u8]) -> Result { - let count = EResult::from(unsafe { syscall::write(self.fd, data) })?; - Ok(count) + fn write(&mut self, data: &[u8]) -> EResult { + let count = unsafe { syscall::write(self.fd, data) }?; + EResult::Ok(count) } - fn flush(&mut self) -> Result<(), Errno> { + fn flush(&mut self) -> EResult<()> { // TODO fsync - Ok(()) + EResult::Ok(()) } } impl Read for RawFile { - fn read(&mut self, data: &mut [u8]) -> Result { - let count = EResult::from(unsafe { syscall::read(self.fd, data) })?; - Ok(count) + fn read(&mut self, data: &mut [u8]) -> EResult { + let count = unsafe { syscall::read(self.fd, data) }?; + EResult::Ok(count) } } impl Seek for RawFile { - fn seek(&mut self, off: SeekFrom) -> Result { - let pos = EResult::from(unsafe { syscall::seek(self.fd, off) })?; - Ok(pos) + fn seek(&mut self, off: SeekFrom) -> EResult { + let pos = unsafe { syscall::seek(self.fd, off) }?; + EResult::Ok(pos) } } @@ -93,17 +91,10 @@ impl IntoRawFd for RawFile { } } -impl TryFrom for RawFile { - type Error = Errno; - - fn try_from(value: c_int) -> Result { - if value >= 0 { - Ok(Self { - fd: RawFd(value as _), - }) - } else { - error::set_errno_result(EBADF) - } +impl TryFromExt for RawFile { + fn e_try_from(value: c_int) -> EResult { + let fd = RawFd::e_try_from(value)?; + EResult::Ok(unsafe { Self::from_raw_fd(fd) }) } } @@ -115,15 +106,15 @@ impl ManagedFile { pathname: P, opts: OpenOptions, mode: FileMode, - ) -> Result { + ) -> EResult { let inner = RawFile::open_at(at, pathname, opts, mode)?; - Ok(Self { + EResult::Ok(Self { inner, reference: false, }) } - pub unsafe fn close(self: &mut Self) -> Result<(), Errno> { + pub unsafe fn close(self: &mut Self) -> EResult<()> { if self.reference { unreachable!("Cannot close a reference ManagedFile"); } @@ -183,7 +174,7 @@ impl FileBacking { } } - pub unsafe fn close(self: &mut Self) -> Result<(), Errno> { + pub unsafe fn close(self: &mut Self) -> EResult<()> { match self { Self::File(file) => ManagedFile::close(file), } @@ -199,13 +190,13 @@ impl AsRawFdOpt for FileBacking { } impl Write for FileBacking { - fn write(&mut self, data: &[u8]) -> Result { + fn write(&mut self, data: &[u8]) -> EResult { match self { Self::File(file) => file.write(data), } } - fn flush(&mut self) -> Result<(), Errno> { + fn flush(&mut self) -> EResult<()> { match self { Self::File(file) => file.flush(), } @@ -213,7 +204,7 @@ impl Write for FileBacking { } impl Read for FileBacking { - fn read(&mut self, data: &mut [u8]) -> Result { + fn read(&mut self, data: &mut [u8]) -> EResult { match self { Self::File(file) => file.read(data), } @@ -221,7 +212,7 @@ impl Read for FileBacking { } impl Seek for FileBacking { - fn seek(&mut self, off: SeekFrom) -> Result { + fn seek(&mut self, off: SeekFrom) -> EResult { match self { Self::File(file) => file.seek(off), } diff --git a/src/header/dirent/mod.rs b/src/header/dirent/mod.rs index 99c8ae2..7688757 100644 --- a/src/header/dirent/mod.rs +++ b/src/header/dirent/mod.rs @@ -1,15 +1,19 @@ use core::{ ffi::{c_char, c_int, c_long, CStr}, mem::MaybeUninit, - ptr::null_mut, + ptr::NonNull, }; use alloc::boxed::Box; use yggdrasil_rt::io::{DirectoryEntry, RawFd}; -use crate::{error, io::dir::DirReader, util::Nullable}; +use crate::{ + error::{CIntZeroResult, CPtrResult, EResult, TryFromExt}, + io::{dir::DirReader, FromRawFd}, + util::Nullable, +}; -use super::{errno::EBADF, sys_types::ino_t}; +use super::{errno::ESUCCESS, sys_types::ino_t}; #[derive(Debug)] #[repr(C)] @@ -28,6 +32,26 @@ pub struct dirent { pub type __scandir_filter_fn_t = extern "C" fn(*const dirent) -> c_int; pub type __scandir_compar_fn_t = extern "C" fn(*mut *const dirent, *mut *const dirent) -> c_int; +impl DIR { + unsafe fn close(mut dir_ptr: NonNull) -> EResult<()> { + let dir = dir_ptr.as_mut(); + let result = dir.reader.close(); + drop(Box::from_raw(dir_ptr.as_ptr())); + result + } + + fn read_entry(&mut self) -> EResult> { + match self.reader.read_entry() { + EResult::Ok(Some(entry)) => { + self.buffer.write(dirent::from(entry)); + EResult::Ok(unsafe { NonNull::new_unchecked(self.buffer.as_mut_ptr()) }) + } + EResult::Ok(None) => EResult::Err(ESUCCESS), + EResult::Err(err) => EResult::Err(err), + } + } +} + impl From for dirent { fn from(value: DirectoryEntry) -> Self { let mut d_name = [0; 256]; @@ -52,49 +76,34 @@ impl From for dirent { // Primary stuff #[no_mangle] -unsafe extern "C" fn opendir(pathname: *const c_char) -> *mut DIR { +unsafe extern "C" fn opendir(pathname: *const c_char) -> CPtrResult { pathname.ensure(); let pathname = CStr::from_ptr(pathname).to_str().unwrap(); - - match DirReader::open_at(None, pathname) { - Ok(reader) => Box::into_raw(Box::new(DIR { - reader, - buffer: MaybeUninit::uninit(), - })), - Err(_) => null_mut(), - } -} - -#[no_mangle] -unsafe extern "C" fn fdopendir(fd: c_int) -> *mut DIR { - if fd < 0 { - error::set_errno(EBADF); - return null_mut(); - } - - let reader = DirReader::from_raw_fd(RawFd(fd as _)); - - Box::into_raw(Box::new(DIR { + let reader = DirReader::open_at(None, pathname)?; + let dir = NonNull::from(Box::leak(Box::new(DIR { reader, buffer: MaybeUninit::uninit(), - })) + }))); + CPtrResult::success(dir) } #[no_mangle] -unsafe extern "C" fn closedir(dir: *mut DIR) -> c_int { - let result = { - let dir = dir.as_mut().unwrap(); +unsafe extern "C" fn fdopendir(fd: c_int) -> CPtrResult { + let fd = RawFd::e_try_from(fd)?; + let reader = DirReader::from_raw_fd(fd); + let dir = NonNull::from(Box::leak(Box::new(DIR { + reader, + buffer: MaybeUninit::uninit(), + }))); + CPtrResult::success(dir) +} - match dir.reader.close() { - Ok(_) => 0, - Err(_) => -1, - } - }; - - drop(Box::from_raw(dir)); - - result +#[no_mangle] +unsafe extern "C" fn closedir(dir: *mut DIR) -> CIntZeroResult { + let dir = NonNull::new(dir).unwrap(); + DIR::close(dir)?; + CIntZeroResult::OK } #[no_mangle] @@ -105,16 +114,10 @@ unsafe extern "C" fn dirfd(dir: *mut DIR) -> c_int { } #[no_mangle] -unsafe extern "C" fn readdir(dir: *mut DIR) -> *mut dirent { +unsafe extern "C" fn readdir(dir: *mut DIR) -> CPtrResult { let dir = dir.as_mut().unwrap(); - - match dir.reader.read_entry() { - Ok(Some(entry)) => { - dir.buffer.write(dirent::from(entry)); - dir.buffer.as_mut_ptr() - } - Ok(None) | Err(_) => null_mut(), - } + let dirent = dir.read_entry()?; + CPtrResult::success(dirent) } // Deprecated diff --git a/src/header/fcntl/mod.rs b/src/header/fcntl/mod.rs index 6dd7d46..94a39ab 100644 --- a/src/header/fcntl/mod.rs +++ b/src/header/fcntl/mod.rs @@ -2,13 +2,16 @@ use core::ffi::{c_char, c_int, c_short, CStr, VaList}; use yggdrasil_rt::io::{FileMode, OpenOptions}; -use crate::{error, file::RawFile, header::errno::EINVAL, io::IntoRawFd, util::Nullable}; - -use super::{ - errno::Errno, - sys_types::{mode_t, off_t, pid_t}, +use crate::{ + error::{CFdResult, CIntCountResult, EResult, TryFromExt}, + file::RawFile, + header::errno::EINVAL, + io::IntoRawFd, + util::{self, Nullable}, }; +use super::sys_types::{mode_t, off_t, pid_t}; + /* TODO: int posix_fadvise(int, off_t, off_t, int); @@ -75,13 +78,13 @@ enum OpenMode { Directory, } -fn open_opts(opts: c_int, ap: &mut VaList) -> Result { +fn open_opts(opts: c_int, ap: &mut VaList) -> EResult { if opts & O_DIRECTORY != 0 { if opts & !O_DIRECTORY != 0 { todo!(); } - return Ok(OpenMode::Directory); + return EResult::Ok(OpenMode::Directory); } let need_mode = opts & O_CREAT != 0; @@ -94,7 +97,7 @@ fn open_opts(opts: c_int, ap: &mut VaList) -> Result { O_EXEC => todo!(), O_SEARCH => todo!(), _ => { - return error::set_errno_result(EINVAL); + return EResult::Err(EINVAL); } } @@ -124,7 +127,7 @@ fn open_opts(opts: c_int, ap: &mut VaList) -> Result { FileMode::empty() }; - Ok(OpenMode::File(res, mode)) + EResult::Ok(OpenMode::File(res, mode)) } #[no_mangle] @@ -133,41 +136,38 @@ unsafe extern "C" fn creat(pathname: *const c_char, mode: mode_t) -> c_int { } #[no_mangle] -unsafe extern "C" fn fcntl(fd: c_int, cmd: c_int, args: ...) -> c_int { - let Ok(file) = RawFile::try_from(fd) else { - return -1; - }; +unsafe extern "C" fn fcntl(fd: c_int, cmd: c_int, args: ...) -> CIntCountResult { + let file = RawFile::e_try_from(fd)?; match cmd { - F_GETFD => 0, - F_SETFD => 0, _ => todo!("fcntl({}, {}, ...)", fd, cmd), } } -#[no_mangle] -unsafe extern "C" fn open(pathname: *const c_char, opts: c_int, mut args: ...) -> c_int { +unsafe fn vopenat(atfd: c_int, pathname: *const c_char, opts: c_int, mut ap: VaList) -> CFdResult { + let atfd = util::at_fd(atfd)?; pathname.ensure(); let pathname = CStr::from_ptr(pathname).to_str().unwrap(); - let mut args = args.as_va_list(); - let result = match open_opts(opts, &mut args) { - Ok(OpenMode::File(opts, mode)) => { - RawFile::open_at(None, pathname, opts, mode).map(RawFile::into_raw_fd) - } - Ok(OpenMode::Directory) => { - todo!(); - } - Err(_) => return -1, + let fd = match open_opts(opts, &mut ap)? { + OpenMode::File(opts, mode) => RawFile::open_at(atfd, pathname, opts, mode)?.into_raw_fd(), + OpenMode::Directory => todo!(), }; - match result { - Ok(fd) => fd.0.try_into().unwrap(), - Err(_) => -1, - } + CFdResult::success(fd) } #[no_mangle] -unsafe extern "C" fn openat(atfd: c_int, pathname: *const c_char, opts: c_int, ...) -> c_int { - todo!() +unsafe extern "C" fn open(pathname: *const c_char, opts: c_int, mut args: ...) -> CFdResult { + vopenat(AT_FDCWD, pathname, opts, args.as_va_list()) +} + +#[no_mangle] +unsafe extern "C" fn openat( + atfd: c_int, + pathname: *const c_char, + opts: c_int, + mut args: ... +) -> CFdResult { + vopenat(atfd, pathname, opts, args.as_va_list()) } diff --git a/src/header/stdio/file.rs b/src/header/stdio/file.rs index f6fb956..aefca4b 100644 --- a/src/header/stdio/file.rs +++ b/src/header/stdio/file.rs @@ -1,6 +1,6 @@ use core::{ ffi::{c_char, c_int, c_long, c_void, CStr}, - ptr::null_mut, + ptr::{null_mut, NonNull}, }; use alloc::boxed::Box; @@ -10,11 +10,11 @@ use yggdrasil_rt::{ }; use crate::{ - error::{self, CSizeResult, CZeroResult}, - header::{ - errno::{Errno, EBADF}, - sys_types::off_t, + error::{ + CEofResult, CFdResult, CIntZeroResult, COffsetResult, CPtrResult, CUsizeResult, EResult, + OptionExt, }, + header::{errno::EBADF, sys_types::off_t}, io::{AsRawFdOpt, Read, Seek, Write}, }; @@ -22,7 +22,7 @@ use super::{ fpos_t, FileFlags, FileOpenSource, FILE, SEEK_CUR, SEEK_END, SEEK_SET, _IOFBF, _IOLBF, _IONBF, }; -fn open_inner(source: O, mode_str: &[u8]) -> Result<*mut FILE, Errno> { +fn open_inner(source: O, mode_str: &[u8]) -> EResult> { let opts = match mode_str { b"r" | b"rb" => OpenOptions::READ, b"r+" | b"rb+" => OpenOptions::READ | OpenOptions::WRITE, @@ -40,16 +40,12 @@ fn open_inner(source: O, mode_str: &[u8]) -> Result<*mut FILE _ => todo!(), }; - match source.open_with(opts) { - Ok(file) => { - let file = Box::into_raw(Box::new(file)); - unsafe { - super::register_file(file); - } - Ok(file) - } - Err(err) => Err(err), + let file = source.open_with(opts)?; + let file = NonNull::from(Box::leak(Box::new(file))); + unsafe { + super::register_file(file); } + EResult::Ok(file) } #[no_mangle] @@ -58,7 +54,7 @@ pub unsafe extern "C" fn ctermid(buffer: *mut c_char) -> *mut c_char { } #[no_mangle] -pub unsafe extern "C" fn fopen(pathname: *const c_char, mode: *const c_char) -> *mut FILE { +pub unsafe extern "C" fn fopen(pathname: *const c_char, mode: *const c_char) -> CPtrResult { if pathname.is_null() || mode.is_null() { panic!(); } @@ -66,19 +62,21 @@ pub unsafe extern "C" fn fopen(pathname: *const c_char, mode: *const c_char) -> let pathname = pathname.to_str().unwrap(); let mode = CStr::from_ptr(mode); - let res = open_inner(Path::from_str(pathname), mode.to_bytes()).unwrap_or(null_mut()); - yggdrasil_rt::debug_trace!("fopen({:?}, {:?}) -> {:p}", pathname, mode, res); - res + let file = open_inner(Path::from_str(pathname), mode.to_bytes())?; + + CPtrResult::success(file) } #[no_mangle] -pub unsafe extern "C" fn fdopen(fd: c_int, mode: *const c_char) -> *mut FILE { +pub unsafe extern "C" fn fdopen(fd: c_int, mode: *const c_char) -> CPtrResult { if fd < 0 || mode.is_null() { panic!(); } let mode = CStr::from_ptr(mode); - open_inner(RawFd(fd as u32), mode.to_bytes()).unwrap_or(null_mut()) + let stream = open_inner(RawFd(fd as u32), mode.to_bytes())?; + + CPtrResult::success(stream) } #[no_mangle] @@ -109,28 +107,22 @@ pub unsafe extern "C" fn clearerr(stream: *mut FILE) { } #[no_mangle] -pub unsafe extern "C" fn fclose(stream: *mut FILE) -> c_int { - if stream.is_null() { - panic!(); - } +pub unsafe extern "C" fn fclose(stream: *mut FILE) -> CEofResult { + let stream = NonNull::new(stream).unwrap(); if !super::deregister_file(stream) { yggdrasil_rt::debug_trace!("fclose() non-registered file: {:p}", stream); } - stream.close().into_eof_status() + FILE::close(stream)?; + CEofResult(0) } #[no_mangle] -pub unsafe extern "C" fn fileno(stream: *mut FILE) -> c_int { +pub unsafe extern "C" fn fileno(stream: *mut FILE) -> CFdResult { let stream = stream.as_mut().unwrap(); - match stream.as_raw_fd_opt() { - Some(RawFd(fd)) => fd as _, - None => { - error::set_errno(EBADF); - -1 - } - } + let fd = stream.as_raw_fd_opt().e_ok_or(EBADF)?; + CFdResult::success(fd) } #[no_mangle] @@ -139,14 +131,15 @@ pub unsafe extern "C" fn fwrite( size: usize, nmemb: usize, stream: *mut FILE, -) -> usize { +) -> CUsizeResult { if ptr.is_null() { panic!(); } let stream = stream.as_mut().unwrap(); let data = core::slice::from_raw_parts(ptr as *const u8, size * nmemb); - stream.write(data).into_size_status() / size + let count = stream.write(data)?; + CUsizeResult(count / size) } #[no_mangle] @@ -155,32 +148,35 @@ pub unsafe extern "C" fn fread( size: usize, nmemb: usize, stream: *mut FILE, -) -> usize { +) -> CUsizeResult { if ptr.is_null() { panic!(); } let stream = stream.as_mut().unwrap(); let data = core::slice::from_raw_parts_mut(ptr as *mut u8, size * nmemb); - stream.read(data).into_size_status() / size + let count = stream.read(data)?; + CUsizeResult(count / size) } #[no_mangle] -pub unsafe extern "C" fn fflush(stream: *mut FILE) -> c_int { +pub unsafe extern "C" fn fflush(stream: *mut FILE) -> CEofResult { if let Some(stream) = stream.as_mut() { - stream.flush().into_eof_status() + stream.flush()?; } else { - super::fflush_all().into_eof_status() + super::fflush_all()?; } + + CEofResult(0) } #[no_mangle] -pub unsafe extern "C" fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) -> c_int { +pub unsafe extern "C" fn fseek(stream: *mut FILE, offset: c_long, whence: c_int) -> CIntZeroResult { fseeko(stream, offset.try_into().unwrap(), whence) } #[no_mangle] -pub unsafe extern "C" fn fseeko(stream: *mut FILE, offset: off_t, whence: c_int) -> c_int { +pub unsafe extern "C" fn fseeko(stream: *mut FILE, offset: off_t, whence: c_int) -> CIntZeroResult { let stream = stream.as_mut().unwrap(); let off = match whence { SEEK_SET => SeekFrom::Start(offset.try_into().unwrap()), @@ -190,24 +186,24 @@ pub unsafe extern "C" fn fseeko(stream: *mut FILE, offset: off_t, whence: c_int) _ => todo!(), }; - match stream.seek(off) { - Ok(_) => 0, - Err(_) => -1, - } + stream.seek(off)?; + + CIntZeroResult::OK } #[no_mangle] pub unsafe extern "C" fn ftell(stream: *mut FILE) -> c_long { - ftello(stream).try_into().unwrap() + match ftello(stream).ok() { + Some(off) => off, + None => -1, + } } #[no_mangle] -pub unsafe extern "C" fn ftello(stream: *mut FILE) -> off_t { +pub unsafe extern "C" fn ftello(stream: *mut FILE) -> COffsetResult { let stream = stream.as_mut().unwrap(); - match stream.stream_position() { - Ok(p) => p.try_into().unwrap(), - Err(_) => -1, - } + let pos = stream.stream_position()?; + COffsetResult::success(pos) } #[no_mangle] @@ -216,26 +212,20 @@ pub unsafe extern "C" fn rewind(stream: *mut FILE) { } #[no_mangle] -pub unsafe extern "C" fn fgetpos(stream: *mut FILE, pos: *mut fpos_t) -> c_int { +pub unsafe extern "C" fn fgetpos(stream: *mut FILE, pos: *mut fpos_t) -> CIntZeroResult { let stream = stream.as_mut().unwrap(); - let pos = pos.as_mut().unwrap(); - match stream.stream_position() { - Ok(p) => { - *pos = p; - 0 - } - Err(_) => -1, - } + let dst = pos.as_mut().unwrap(); + let pos = stream.stream_position()?; + *dst = pos; + CIntZeroResult::OK } #[no_mangle] -pub unsafe extern "C" fn fsetpos(stream: *mut FILE, pos: *const fpos_t) -> c_int { +pub unsafe extern "C" fn fsetpos(stream: *mut FILE, pos: *const fpos_t) -> CIntZeroResult { let stream = stream.as_mut().unwrap(); let pos = pos.as_ref().unwrap(); - match stream.seek(SeekFrom::Start(*pos as _)) { - Ok(_) => 0, - Err(_) => -1, - } + stream.seek(SeekFrom::Start(*pos))?; + CIntZeroResult::OK } #[no_mangle] @@ -244,9 +234,10 @@ pub unsafe extern "C" fn setvbuf( buf: *mut c_char, mode: c_int, size: usize, -) -> c_int { +) -> CIntZeroResult { let stream = stream.as_mut().unwrap(); - stream.setvbuf(mode, buf, size).into_eof_status() + stream.setvbuf(mode, buf, size)?; + CIntZeroResult::OK } #[no_mangle] @@ -266,17 +257,24 @@ pub unsafe extern "C" fn setlinebuf(stream: *mut FILE) { } #[no_mangle] -unsafe extern "C" fn fmemopen(buffer: *mut c_void, size: usize, mode: *mut c_char) -> *mut FILE { +unsafe extern "C" fn fmemopen( + buffer: *mut c_void, + size: usize, + mode: *mut c_char, +) -> CPtrResult { todo!() } #[no_mangle] -unsafe extern "C" fn open_memstream(bufptr: *mut *mut c_char, sizeptr: *mut usize) -> *mut FILE { +unsafe extern "C" fn open_memstream( + bufptr: *mut *mut c_char, + sizeptr: *mut usize, +) -> CPtrResult { todo!() } #[no_mangle] -unsafe extern "C" fn popen(command: *const c_char, mode: *const c_char) -> *mut FILE { +unsafe extern "C" fn popen(command: *const c_char, mode: *const c_char) -> CPtrResult { todo!() } diff --git a/src/header/stdio/get_put.rs b/src/header/stdio/get_put.rs index 25f7a36..b05e92f 100644 --- a/src/header/stdio/get_put.rs +++ b/src/header/stdio/get_put.rs @@ -1,18 +1,20 @@ use core::{ ffi::{c_char, c_int, CStr}, - ptr::null_mut, + ptr::{null_mut, NonNull}, }; use crate::{ - error, - header::stdlib::realloc, + allocator, + error::{self, CEofResult, CIsizeResult, CPtrResult, EResult}, + header::errno::ESUCCESS, io::{Read, Write}, + util::NonNullExt, }; use super::{ stderr, stdin, stdout, unlocked::{flockfile, fputc_unlocked, fputs_unlocked, funlockfile}, - EOF, FILE, + FILE, }; #[no_mangle] @@ -34,101 +36,91 @@ unsafe extern "C" fn perror(msg: *const c_char) { // Chars #[no_mangle] -unsafe extern "C" fn fputc(c: c_int, stream: *mut FILE) -> c_int { +unsafe extern "C" fn fputc(c: c_int, stream: *mut FILE) -> CEofResult { let stream = stream.as_mut().unwrap(); let c = c as u8; - match stream.write(&[c]) { - Ok(_) => c as c_int, - Err(_) => EOF, - } + stream.write_all(&[c])?; + + CEofResult(c as c_int) } #[no_mangle] -unsafe extern "C" fn putc(c: c_int, stream: *mut FILE) -> c_int { +unsafe extern "C" fn putc(c: c_int, stream: *mut FILE) -> CEofResult { fputc(c, stream) } #[no_mangle] -unsafe extern "C" fn putchar(c: c_int) -> c_int { +unsafe extern "C" fn putchar(c: c_int) -> CEofResult { fputc(c, stdout) } // Strings #[no_mangle] -unsafe extern "C" fn puts(s: *const c_char) -> c_int { +unsafe extern "C" fn puts(s: *const c_char) -> CEofResult { let r = fputs(s, stdout); - if r < 0 { + if r.0 < 0 { return r; } fputc(b'\n' as _, stdout) } #[no_mangle] -unsafe extern "C" fn fputs(s: *const c_char, stream: *mut FILE) -> c_int { +unsafe extern "C" fn fputs(s: *const c_char, stream: *mut FILE) -> CEofResult { let stream = stream.as_mut().unwrap(); if s.is_null() { panic!(); } let s = CStr::from_ptr(s); - - match stream.write(s.to_bytes()) { - Ok(_) => 0, - Err(_) => EOF, - } + stream.write_all(s.to_bytes())?; + CEofResult(0) } #[no_mangle] -unsafe extern "C" fn fgetc(stream: *mut FILE) -> c_int { +unsafe extern "C" fn fgetc(stream: *mut FILE) -> CEofResult { let stream = stream.as_mut().unwrap(); let mut buf = [0]; - match stream.read(&mut buf) { - Ok(1) => buf[0] as c_int, - Ok(_) => EOF, - Err(_) => EOF, - } + stream.read_exact(&mut buf)?; + CEofResult(buf[0] as _) } #[no_mangle] -unsafe extern "C" fn getc(stream: *mut FILE) -> c_int { +unsafe extern "C" fn getc(stream: *mut FILE) -> CEofResult { fgetc(stream) } #[no_mangle] -unsafe extern "C" fn getchar() -> c_int { +unsafe extern "C" fn getchar() -> CEofResult { fgetc(stdin) } #[no_mangle] -unsafe extern "C" fn fgets(s: *mut c_char, size: c_int, stream: *mut FILE) -> *mut c_char { +unsafe extern "C" fn fgets(s: *mut c_char, size: c_int, stream: *mut FILE) -> CPtrResult { let stream = stream.as_mut().unwrap(); + let mut s = NonNull::new(s).unwrap(); if size <= 0 { - return null_mut(); + return CPtrResult::ERR; } // Nothing to read if size == 1 { - *s = 0; - return s; + *s.as_mut() = 0; + return CPtrResult::success(s); } let size = size as usize; let mut pos = 0; let mut buf = [0]; + let slice = NonNull::slice_from_raw_parts(s, size).as_mut(); while pos < size - 1 { - let ch = match stream.read(&mut buf) { - Ok(1) => buf[0], - Ok(_) => { - break; - } - Err(err) => { - return null_mut(); - } + let ch = match stream.read(&mut buf)? { + 1 => buf[0], + _ => break, }; - *s.add(pos) = ch as _; + slice[pos] = ch as _; pos += 1; if ch == b'\n' { @@ -137,49 +129,101 @@ unsafe extern "C" fn fgets(s: *mut c_char, size: c_int, stream: *mut FILE) -> *m } if pos == 0 { - null_mut() + CPtrResult::ERR } else { - *s.add(pos) = 0; - s + slice[pos] = 0; + CPtrResult::success(s) } } #[no_mangle] -unsafe extern "C" fn ungetc(c: c_int, stream: *mut FILE) -> c_int { +unsafe extern "C" fn ungetc(c: c_int, stream: *mut FILE) -> CEofResult { let stream = stream.as_mut().unwrap(); - if stream.ungetc(c as _) { - c - } else { - EOF - } + stream.ungetc(c as _)?; + CEofResult(c) } // Line struct MallocBufferWriter { - buffer: *mut c_char, - position: usize, + buffer: Option>, capacity: usize, + position: usize, } impl MallocBufferWriter { - fn putc(&mut self, ch: c_int) -> bool { + unsafe fn new(buffer: Option>, mut capacity: usize) -> Self { + if buffer.is_none() { + capacity = 0; + } + Self { + buffer, + capacity, + position: 0, + } + } + + fn try_reserve(&mut self) -> EResult<&mut c_char> { if self.position == self.capacity { - // Extend the buffer self.capacity = (self.capacity + 64) & !63; - self.buffer = unsafe { realloc(self.buffer as _, self.capacity) as _ }; - if self.buffer.is_null() { - // ENOMEM is set - return false; + self.buffer = Some( + unsafe { allocator::c_reallocate(self.buffer.map(NonNull::cast), self.capacity) }? + .cast(), + ); + } + let buffer = self.buffer.unwrap(); + EResult::Ok(unsafe { buffer.add_ext(self.position).as_mut() }) + } + + fn putc(&mut self, ch: c_int) -> EResult<()> { + let item = self.try_reserve()?; + *item = ch as _; + self.position += 1; + EResult::Ok(()) + } +} + +fn getdelim_inner( + buffer: Option>, + capacity: usize, + delim: c_int, + stream: &mut FILE, +) -> (MallocBufferWriter, EResult<()>) { + let mut writer = unsafe { MallocBufferWriter::new(buffer, capacity) }; + let mut buf = [0]; + + loop { + let ch = match stream.read(&mut buf) { + EResult::Ok(1) => buf[0] as c_int, + EResult::Ok(_) => break, + EResult::Err(err) => return (writer, EResult::Err(err)), + }; + + match writer.putc(ch) { + EResult::Ok(()) => (), + EResult::Err(err) => { + return (writer, EResult::Err(err)); } } - unsafe { - *self.buffer.add(self.position) = ch as _; + if ch == delim { + break; } - self.position += 1; - true } + + if writer.position == 0 { + // EOF reached before anything could be read + return (writer, EResult::Err(ESUCCESS)); + } + + match writer.putc(0) { + EResult::Ok(()) => (), + EResult::Err(err) => { + return (writer, EResult::Err(err)); + } + } + + (writer, EResult::Ok(())) } #[no_mangle] @@ -188,52 +232,32 @@ unsafe extern "C" fn getdelim( n: *mut usize, delim: c_int, stream: *mut FILE, -) -> isize { +) -> CIsizeResult { let lineptr = lineptr.as_mut().unwrap(); + + let buffer = NonNull::new(*lineptr); let n = n.as_mut().unwrap(); - let mut capacity = *n; + let stream = stream.as_mut().unwrap(); - if lineptr.is_null() { - capacity = 0; + let (writer, result) = getdelim_inner(buffer, *n, delim, stream); + + match writer.buffer { + Some(buffer) => *lineptr = buffer.as_ptr(), + None => *lineptr = null_mut(), } - - let mut writer = MallocBufferWriter { - buffer: *lineptr, - position: 0, - capacity, - }; - - loop { - let ch = fgetc(stream); - if ch == EOF { - if writer.position == 0 { - // EOF and no data read - return -1; - } - break; - } - - if !writer.putc(ch) { - return -1; - } - - if ch == delim { - break; - } - } - - if !writer.putc(0) { - return -1; - } - - *lineptr = writer.buffer; *n = writer.capacity; - // Minus the '\0' - (writer.position - 1).try_into().unwrap() + result?; + assert_ne!(writer.position, 0); + + CIsizeResult::success(writer.position - 1) } #[no_mangle] -unsafe extern "C" fn getline(lineptr: *mut *mut c_char, n: *mut usize, stream: *mut FILE) -> isize { +unsafe extern "C" fn getline( + lineptr: *mut *mut c_char, + n: *mut usize, + stream: *mut FILE, +) -> CIsizeResult { getdelim(lineptr, n, b'\n' as _, stream) } diff --git a/src/header/stdio/mod.rs b/src/header/stdio/mod.rs index ac7fcb6..7db94ef 100644 --- a/src/header/stdio/mod.rs +++ b/src/header/stdio/mod.rs @@ -1,6 +1,7 @@ use core::{ ffi::{c_char, c_int}, - fmt, ptr, + fmt, + ptr::{self, NonNull}, }; use alloc::{boxed::Box, collections::BTreeSet, vec::Vec}; @@ -20,7 +21,7 @@ use crate::{ sync::{Mutex, RawMutex}, }; -use super::errno::Errno; +use super::errno::{EINVAL, ENOMEM, ESUCCESS}; // TODO: // L_ctermid @@ -42,7 +43,7 @@ mod scanf; mod unlocked; pub trait FileOpenSource { - fn open_with(self, opts: OpenOptions) -> Result; + fn open_with(self, opts: OpenOptions) -> EResult; } pub enum BufferingMode { @@ -126,16 +127,16 @@ impl FILE { Self::from_backing(inner, flags, buffering) } - pub unsafe fn close(self: *mut Self) -> Result<(), Errno> { + pub unsafe fn close(mut ptr: NonNull) -> EResult<()> { // TODO lock needed? - let r = self.as_mut().unwrap(); - r.flush()?; + let file = ptr.as_mut(); + file.flush()?; - if r.flags.contains(FileFlags::BUILTIN) { + if file.flags.contains(FileFlags::BUILTIN) { todo!() } else { // Drop the file - let mut this = Box::from_raw(self); + let mut this = Box::from_raw(file); let result = FileBacking::close(&mut this.inner); drop(this); result @@ -162,41 +163,36 @@ impl FILE { self.flags.contains(flag) } - pub fn setvbuf( - &mut self, - mode: c_int, - buffer: *mut c_char, - capacity: usize, - ) -> Result<(), Errno> { + pub fn setvbuf(&mut self, mode: c_int, buffer: *mut c_char, capacity: usize) -> EResult<()> { locked_op!(self, self.setvbuf_unlocked(mode, buffer, capacity)) } - pub unsafe fn write_unlocked(&mut self, data: &[u8]) -> Result { + pub unsafe fn write_unlocked(&mut self, data: &[u8]) -> EResult { self.set_direction(Direction::Write)?; match self.output.write(data) { - Ok(amount) => Ok(amount), - Err(err) => { + EResult::Ok(amount) => EResult::Ok(amount), + EResult::Err(err) => { self.flags |= FileFlags::ERROR; - Err(err) + EResult::Err(err) } } } - pub unsafe fn flush_unlocked(&mut self) -> Result<(), Errno> { + pub unsafe fn flush_unlocked(&mut self) -> EResult<()> { match self.output.flush() { - Ok(()) => { + EResult::Ok(()) => { self.last_operation = None; - Ok(()) + EResult::Ok(()) } - Err(err) => { + EResult::Err(err) => { self.flags |= FileFlags::ERROR; - Err(err) + EResult::Err(err) } } } - pub unsafe fn read_unlocked(&mut self, data: &mut [u8]) -> Result { + pub unsafe fn read_unlocked(&mut self, data: &mut [u8]) -> EResult { self.set_direction(Direction::Read)?; if !self.ungetc.is_empty() { @@ -204,7 +200,7 @@ impl FILE { let amount = core::cmp::min(self.ungetc.len(), data.len()); data[..amount].copy_from_slice(&self.ungetc[..amount]); self.ungetc.drain(..amount); - return Ok(amount); + return EResult::Ok(amount); } if self.read_buffer.is_some() { @@ -212,23 +208,23 @@ impl FILE { let len = core::cmp::min(data.len(), buf.len()); data[..len].copy_from_slice(&buf[..len]); self.consume(len); - Ok(len) + EResult::Ok(len) } else { match self.inner.read(data) { - Ok(0) => { + EResult::Ok(0) => { self.flags |= FileFlags::EOF; - Ok(0) + EResult::Ok(0) } - Ok(n) => Ok(n), - Err(err) => { + EResult::Ok(n) => EResult::Ok(n), + EResult::Err(err) => { self.flags |= FileFlags::ERROR; - Err(err) + EResult::Err(err) } } } } - pub fn ungetc(&mut self, ch: u8) -> bool { + pub fn ungetc(&mut self, ch: u8) -> EResult<()> { locked_op!(self, self.ungetc_unlocked(ch)) } @@ -236,8 +232,11 @@ impl FILE { self.lock.lock(); } - pub fn try_lock(&mut self) -> bool { - self.lock.try_lock() + pub fn try_lock(&mut self) -> EResult<()> { + match self.lock.try_lock() { + true => EResult::Ok(()), + false => EResult::Err(ESUCCESS), + } } pub unsafe fn unlock(&mut self) { @@ -259,7 +258,7 @@ impl FILE { mode: c_int, buffer: *mut c_char, capacity: usize, - ) -> Result<(), Errno> { + ) -> EResult<()> { let mode = BufferingMode::e_try_from(mode)?; if self.last_operation.is_some() { @@ -306,84 +305,83 @@ impl FILE { } } - Ok(()) + EResult::Ok(()) } - unsafe fn seek_unlocked(&mut self, off: SeekFrom) -> Result { + unsafe fn seek_unlocked(&mut self, off: SeekFrom) -> EResult { self.flush_unlocked()?; self.ungetc.clear(); match self.inner.seek(off) { - Ok(pos) => { + EResult::Ok(pos) => { self.flags &= !FileFlags::EOF; - Ok(pos) + EResult::Ok(pos) } - Err(err) => { + EResult::Err(err) => { self.flags |= FileFlags::ERROR; - Err(err) + EResult::Err(err) } } } - unsafe fn set_direction(&mut self, direction: Direction) -> Result<(), Errno> { + unsafe fn set_direction(&mut self, direction: Direction) -> EResult<()> { match self.last_operation.replace(direction) { Some(dir) if dir != direction => { self.flags |= FileFlags::ERROR; todo!() } - _ => Ok(()), + _ => EResult::Ok(()), } } - unsafe fn ungetc_unlocked(&mut self, ch: u8) -> bool { + unsafe fn ungetc_unlocked(&mut self, ch: u8) -> EResult<()> { // ungetc() for write doesn't make any sense - if self.set_direction(Direction::Read).is_err() { - return false; - } + self.set_direction(Direction::Read)?; if self.ungetc.len() == UNGETC_MAX { - return false; + return EResult::Err(ENOMEM); } self.ungetc.push(ch); - true + EResult::Ok(()) } } impl fmt::Write for FILE { fn write_str(&mut self, s: &str) -> fmt::Result { - self.write_all(s.as_bytes()).map_err(|_| fmt::Error) + self.write_all(s.as_bytes()) + .into_result(|_| fmt::Error, true) } } impl Write for FILE { - fn write(&mut self, data: &[u8]) -> Result { + fn write(&mut self, data: &[u8]) -> EResult { locked_op!(self, self.write_unlocked(data)) } - fn flush(&mut self) -> Result<(), Errno> { + fn flush(&mut self) -> EResult<()> { locked_op!(self, self.flush_unlocked()) } } impl Read for FILE { - fn read(&mut self, data: &mut [u8]) -> Result { + fn read(&mut self, data: &mut [u8]) -> EResult { locked_op!(self, self.read_unlocked(data)) } } // NOTE assumes file is locked impl BufRead for FILE { - fn fill_buf(&mut self) -> Result<&[u8], Errno> { + fn fill_buf(&mut self) -> EResult<&[u8]> { let buffer = self.read_buffer.as_mut().unwrap(); match buffer.fill_from(&mut self.inner) { - Ok(slice) => { + EResult::Ok(slice) => { if slice.len() == 0 { self.flags |= FileFlags::EOF; } - Ok(slice) + EResult::Ok(slice) } - Err(err) => { + EResult::Err(err) => { self.flags |= FileFlags::ERROR; - Err(err) + EResult::Err(err) } } } @@ -395,7 +393,7 @@ impl BufRead for FILE { } impl Seek for FILE { - fn seek(&mut self, off: SeekFrom) -> Result { + fn seek(&mut self, off: SeekFrom) -> EResult { locked_op!(self, self.seek_unlocked(off)) } } @@ -407,7 +405,7 @@ impl AsRawFdOpt for FILE { } impl FileOpenSource for &Path { - fn open_with(self, opts: OpenOptions) -> Result { + fn open_with(self, opts: OpenOptions) -> EResult { let f = ManagedFile::open_at(None, self, opts, FileMode::default_file())?; let mut flags = FileFlags::empty(); if opts.contains(OpenOptions::READ) { @@ -416,12 +414,12 @@ impl FileOpenSource for &Path { if opts.contains(OpenOptions::WRITE) { flags |= FileFlags::WRITE; } - Ok(unsafe { FILE::from_managed_file(f, flags) }) + EResult::Ok(unsafe { FILE::from_managed_file(f, flags) }) } } impl FileOpenSource for RawFd { - fn open_with(self, opts: OpenOptions) -> Result { + fn open_with(self, opts: OpenOptions) -> EResult { let f = unsafe { RawFile::from_raw_fd(self) }; let mut flags = FileFlags::empty(); if opts.contains(OpenOptions::READ) { @@ -430,7 +428,7 @@ impl FileOpenSource for RawFd { if opts.contains(OpenOptions::WRITE) { flags |= FileFlags::WRITE; } - Ok(unsafe { FILE::from_raw_file(f, flags) }) + EResult::Ok(unsafe { FILE::from_raw_file(f, flags) }) } } @@ -440,7 +438,7 @@ impl TryFromExt for BufferingMode { _IOFBF => EResult::Ok(Self::Full), _IOLBF => EResult::Ok(Self::Line), _IONBF => EResult::Ok(Self::None), - _ => EResult::Err(yggdrasil_rt::Error::InvalidArgument), + _ => EResult::Err(EINVAL), } } } @@ -470,28 +468,28 @@ pub const BUFSIZ: usize = 8192; const UNGETC_MAX: usize = 128; -pub static OPEN_FILES: Mutex> = Mutex::new(BTreeSet::new()); +pub static OPEN_FILES: Mutex>> = Mutex::new(BTreeSet::new()); -pub unsafe fn register_file(file: *mut FILE) { +pub unsafe fn register_file(file: NonNull) { OPEN_FILES.lock().insert(file); } -pub unsafe fn deregister_file(file: *mut FILE) -> bool { +pub unsafe fn deregister_file(file: NonNull) -> bool { OPEN_FILES.lock().remove(&file) } pub unsafe fn setup_default_files() { - let stdin_ = Box::into_raw(Box::new(FILE::new_builtin( + let stdin_ = Box::leak(Box::new(FILE::new_builtin( RawFd::STDIN, FileFlags::READ, BufferingMode::Line, ))); - let stdout_ = Box::into_raw(Box::new(FILE::new_builtin( + let stdout_ = Box::leak(Box::new(FILE::new_builtin( RawFd::STDOUT, FileFlags::WRITE, BufferingMode::Line, ))); - let stderr_ = Box::into_raw(Box::new(FILE::new_builtin( + let stderr_ = Box::leak(Box::new(FILE::new_builtin( RawFd::STDERR, FileFlags::WRITE, BufferingMode::None, @@ -502,32 +500,34 @@ pub unsafe fn setup_default_files() { stderr = stderr_; let mut open_files = OPEN_FILES.lock(); - open_files.insert(stdin); - open_files.insert(stdout); - open_files.insert(stderr); + open_files.insert(NonNull::from(stdin_)); + open_files.insert(NonNull::from(stdout_)); + open_files.insert(NonNull::from(stderr_)); } -pub fn fflush_all() -> Result<(), Errno> { +pub fn fflush_all() -> EResult<()> { let open_files = OPEN_FILES.lock(); - for &file in open_files.iter() { + for file in open_files.iter() { + let mut file = *file; unsafe { - file.as_mut().unwrap().flush()?; + file.as_mut().flush()?; } } - Ok(()) + EResult::Ok(()) } -pub unsafe fn fflush_all_unlocked() -> Result<(), Errno> { +pub unsafe fn fflush_all_unlocked() -> EResult<()> { let open_files = OPEN_FILES.lock(); - for &file in open_files.iter() { - file.as_mut().unwrap().flush_unlocked()?; + for file in open_files.iter() { + let mut file = *file; + file.as_mut().flush_unlocked()?; } - Ok(()) + EResult::Ok(()) } pub unsafe fn cleanup() { let mut open_files = OPEN_FILES.lock(); while let Some(file) = open_files.pop_first() { - file.close().ok(); + FILE::close(file).ok(); } } diff --git a/src/header/stdio/printf/float.rs b/src/header/stdio/printf/float.rs index 7dc3520..97fe922 100644 --- a/src/header/stdio/printf/float.rs +++ b/src/header/stdio/printf/float.rs @@ -2,10 +2,7 @@ use core::{ffi::c_double, fmt, num::FpCategory}; use alloc::{format, string::String}; -use crate::{ - header::errno::{Errno, EINVAL}, - io::Write, -}; +use crate::{error::EResult, header::errno::EINVAL, io::Write}; use super::format::FmtOpts; @@ -37,7 +34,7 @@ fn fmt_float_exp( output: &mut W, precision: usize, opts: &FmtOpts, -) -> Result { +) -> EResult { let mut exp2 = exp; let mut exp_len = 1; while exp2 >= 10 { @@ -48,12 +45,14 @@ fn fmt_float_exp( let string = fmt_float_string(val, precision); let f_len = output.write(string.as_bytes())?; + let e_len = match write!(output, "{}{:+03}", exp_fmt as char, exp) { Ok(count) => count, - Err(_) => return Err(EINVAL), + // TODO proper error code + Err(_) => return EResult::Err(EINVAL), }; - Ok(f_len + 2 + 2.max(exp_len)) + EResult::Ok(f_len + 2 + 2.max(exp_len)) } fn fmt_float_string(val: c_double, precision: usize) -> String { @@ -67,12 +66,12 @@ fn fmt_float_finite( output: &mut W, precision: usize, opts: &FmtOpts, -) -> Result { +) -> EResult { let s = fmt_float_string(val, precision); let lpad = opts.left_pad(output, s.len())?; let flen = output.write(s.as_bytes())?; let rpad = opts.right_pad(output, s.len())?; - Ok(lpad + flen + rpad) + EResult::Ok(lpad + flen + rpad) } fn fmt_float_nonfinite( @@ -80,7 +79,7 @@ fn fmt_float_nonfinite( output: &mut W, upper: bool, opts: &FmtOpts, -) -> Result { +) -> EResult { let mut len = 0; if val.is_sign_negative() { len += output.write(b"-")?; @@ -102,7 +101,7 @@ fn fmt_float_nonfinite( let flen = output.write(nonfinite_str)?; let rpad = opts.right_pad(output, len + nonfinite_str.len())?; - Ok(len + lpad + flen + rpad) + EResult::Ok(len + lpad + flen + rpad) } pub fn fmt_float( @@ -110,7 +109,7 @@ pub fn fmt_float( output: &mut W, upper: bool, opts: &FmtOpts, -) -> Result { +) -> EResult { if val.is_finite() { fmt_float_finite(val, output, 6, opts) } else { @@ -123,7 +122,7 @@ pub fn fmt_float_scientific( output: &mut W, upper: bool, opts: &FmtOpts, -) -> Result { +) -> EResult { if val.is_finite() { let (val, exp) = float_exp(val); let exp_fmt = match upper { @@ -143,7 +142,7 @@ pub fn fmt_float_any( output: &mut W, upper: bool, opts: &FmtOpts, -) -> Result { +) -> EResult { if val.is_finite() { let (log, exp) = float_exp(val); let exp_fmt = match upper { diff --git a/src/header/stdio/printf/format.rs b/src/header/stdio/printf/format.rs index 1190f89..0018430 100644 --- a/src/header/stdio/printf/format.rs +++ b/src/header/stdio/printf/format.rs @@ -8,7 +8,7 @@ use core::{ use alloc::string::String; -use crate::{header::errno::Errno, io::Write, types::wchar_t}; +use crate::{error::EResult, io::Write, types::wchar_t}; use super::float::{fmt_float, fmt_float_any, fmt_float_scientific}; @@ -144,35 +144,27 @@ impl FmtSize { } impl FmtOpts { - fn pad(&self, output: &mut W, len: usize) -> Result { + fn pad(&self, output: &mut W, len: usize) -> EResult { let pad = self.width - core::cmp::min(self.width, len); for _ in 0..pad { output.write(&[self.pad_char])?; } - Ok(pad) + EResult::Ok(pad) } - pub fn left_pad( - &self, - output: &mut W, - len: usize, - ) -> Result { + pub fn left_pad(&self, output: &mut W, len: usize) -> EResult { if !self.left_adjust { self.pad(output, len) } else { - Ok(0) + EResult::Ok(0) } } - pub fn right_pad( - &self, - output: &mut W, - len: usize, - ) -> Result { + pub fn right_pad(&self, output: &mut W, len: usize) -> EResult { if self.left_adjust { self.pad(output, len) } else { - Ok(0) + EResult::Ok(0) } } @@ -181,7 +173,7 @@ impl FmtOpts { spec: FmtSpec, output: &mut W, ap: &mut VaList, - ) -> Result { + ) -> EResult { let mut buffer = [0; 64]; let len = match spec { @@ -214,7 +206,7 @@ impl FmtOpts { let lpad = self.left_pad(output, bytes.len())?; let len = output.write(bytes)?; let rpad = self.right_pad(output, bytes.len())?; - return Ok(lpad + len + rpad); + return EResult::Ok(lpad + len + rpad); } } FmtSpec::String if self.size == FmtSize::Long => { @@ -242,7 +234,7 @@ impl FmtOpts { let lpad = self.left_pad(output, bytes.len())?; let len = output.write(bytes)?; let rpad = self.right_pad(output, bytes.len())?; - return Ok(lpad + len + rpad); + return EResult::Ok(lpad + len + rpad); } } FmtSpec::Char if self.size == FmtSize::Normal => { @@ -278,7 +270,7 @@ impl FmtOpts { let count = output.write(&buffer[..len])?; let rpad = self.right_pad(output, len)?; - Ok(lpad + count + rpad) + EResult::Ok(lpad + count + rpad) } } diff --git a/src/header/stdio/printf/mod.rs b/src/header/stdio/printf/mod.rs index 3c5b12c..88a6cfa 100644 --- a/src/header/stdio/printf/mod.rs +++ b/src/header/stdio/printf/mod.rs @@ -3,9 +3,11 @@ use core::{ fmt, }; -use yggdrasil_rt::{io::RawFd, sys as syscall}; - -use crate::{error::EResult, header::errno::Errno, io::Write}; +use crate::{ + error::{CIntCountResult, EResult, TryFromExt}, + file::RawFile, + io::Write, +}; use self::format::{FmtOpts, FmtRadix, FmtSign, FmtSize, FmtSpec}; @@ -21,7 +23,7 @@ struct StringWriter { } struct FdWriter { - fd: RawFd, + file: RawFile, } impl StringWriter { @@ -35,7 +37,7 @@ impl StringWriter { } impl Write for StringWriter { - fn write(&mut self, data: &[u8]) -> Result { + fn write(&mut self, data: &[u8]) -> EResult { let count = core::cmp::min(self.capacity - self.position, data.len()); if count > 0 { let dst = unsafe { @@ -44,41 +46,40 @@ impl Write for StringWriter { dst.copy_from_slice(&data[..count]); self.position += count; } - Ok(count) + EResult::Ok(count) } - fn flush(&mut self) -> Result<(), Errno> { + fn flush(&mut self) -> EResult<()> { todo!() } } impl fmt::Write for StringWriter { fn write_str(&mut self, s: &str) -> fmt::Result { - self.write(s.as_bytes()).map_err(|_| fmt::Error)?; + self.write(s.as_bytes()).into_result(|_| fmt::Error, true)?; Ok(()) } } impl FdWriter { - pub fn new(fd: RawFd) -> Self { - Self { fd } + pub fn new(file: RawFile) -> Self { + Self { file } } } impl Write for FdWriter { - fn write(&mut self, data: &[u8]) -> Result { - let count = EResult::from(unsafe { syscall::write(self.fd, data) })?; - Ok(count) + fn write(&mut self, data: &[u8]) -> EResult { + self.file.write(data) } - fn flush(&mut self) -> Result<(), Errno> { - todo!() + fn flush(&mut self) -> EResult<()> { + self.file.flush() } } impl fmt::Write for FdWriter { fn write_str(&mut self, s: &str) -> fmt::Result { - self.write(s.as_bytes()).map_err(|_| fmt::Error)?; + self.write(s.as_bytes()).into_result(|_| fmt::Error, true)?; Ok(()) } } @@ -87,7 +88,7 @@ fn printf_inner( output: &mut W, format: &[u8], mut ap: VaList, -) -> Result { +) -> EResult { let mut fmt = format.into_iter(); let mut count = 0; @@ -181,41 +182,51 @@ fn printf_inner( } } - Ok(count) + EResult::Ok(count) } #[no_mangle] -unsafe extern "C" fn printf(format: *const c_char, mut args: ...) -> c_int { +unsafe extern "C" fn printf(format: *const c_char, mut args: ...) -> CIntCountResult { vfprintf(stdout, format, args.as_va_list()) } #[no_mangle] -unsafe extern "C" fn fprintf(stream: *mut FILE, format: *const c_char, mut args: ...) -> c_int { +unsafe extern "C" fn fprintf( + stream: *mut FILE, + format: *const c_char, + mut args: ... +) -> CIntCountResult { vfprintf(stream, format, args.as_va_list()) } #[no_mangle] -unsafe extern "C" fn vprintf(format: *const c_char, ap: VaList) -> c_int { +unsafe extern "C" fn vprintf(format: *const c_char, ap: VaList) -> CIntCountResult { vfprintf(stdout, format, ap) } #[no_mangle] -unsafe extern "C" fn vfprintf(stream: *mut FILE, format: *const c_char, ap: VaList) -> c_int { +unsafe extern "C" fn vfprintf( + stream: *mut FILE, + format: *const c_char, + ap: VaList, +) -> CIntCountResult { if format.is_null() { panic!(); } let stream = stream.as_mut().unwrap(); let format = CStr::from_ptr(format); - match printf_inner(stream, format.to_bytes(), ap) { - // TODO handle this - Ok(count) => count as c_int, - Err(_) => -1, - } + let count = printf_inner(stream, format.to_bytes(), ap)?; + + CIntCountResult(count.try_into().unwrap()) } #[no_mangle] -unsafe extern "C" fn sprintf(str: *mut c_char, format: *const c_char, mut args: ...) -> c_int { +unsafe extern "C" fn sprintf( + str: *mut c_char, + format: *const c_char, + mut args: ... +) -> CIntCountResult { vsnprintf(str, usize::MAX, format, args.as_va_list()) } @@ -225,12 +236,16 @@ unsafe extern "C" fn snprintf( len: usize, format: *const c_char, mut args: ... -) -> c_int { +) -> CIntCountResult { vsnprintf(str, len, format, args.as_va_list()) } #[no_mangle] -unsafe extern "C" fn vsprintf(str: *mut c_char, format: *const c_char, ap: VaList) -> c_int { +unsafe extern "C" fn vsprintf( + str: *mut c_char, + format: *const c_char, + ap: VaList, +) -> CIntCountResult { vsnprintf(str, usize::MAX, format, ap) } @@ -240,12 +255,12 @@ unsafe extern "C" fn vsnprintf( len: usize, format: *const c_char, ap: VaList, -) -> c_int { +) -> CIntCountResult { if format.is_null() { panic!(); } if len == 0 { - return 0; + return CIntCountResult(0); } if str.is_null() { // TODO output the length @@ -254,33 +269,26 @@ unsafe extern "C" fn vsnprintf( let mut writer = StringWriter::new(str, len); let format = CStr::from_ptr(format); - match printf_inner(&mut writer, format.to_bytes(), ap) { - // TODO handle this - Ok(count) => count as c_int, - Err(_) => -1, - } + let count = printf_inner(&mut writer, format.to_bytes(), ap)?; + + CIntCountResult(count.try_into().unwrap()) } #[no_mangle] -unsafe extern "C" fn dprintf(fd: c_int, format: *const c_char, mut args: ...) -> c_int { +unsafe extern "C" fn dprintf(fd: c_int, format: *const c_char, mut args: ...) -> CIntCountResult { vdprintf(fd, format, args.as_va_list()) } #[no_mangle] -unsafe extern "C" fn vdprintf(fd: c_int, format: *const c_char, ap: VaList) -> c_int { +unsafe extern "C" fn vdprintf(fd: c_int, format: *const c_char, ap: VaList) -> CIntCountResult { if format.is_null() { panic!(); } - if fd < 0 { - // TODO set errno and return - todo!(); - } - let mut writer = FdWriter::new(RawFd(fd as u32)); + let file = RawFile::e_try_from(fd)?; + let mut writer = FdWriter::new(file); let format = CStr::from_ptr(format); - match printf_inner(&mut writer, format.to_bytes(), ap) { - // TODO handle this - Ok(count) => count as c_int, - Err(_) => -1, - } + let count = printf_inner(&mut writer, format.to_bytes(), ap)?; + + CIntCountResult(count.try_into().unwrap()) } diff --git a/src/header/stdio/scanf/char_set.rs b/src/header/stdio/scanf/char_set.rs index faaba09..9331a64 100644 --- a/src/header/stdio/scanf/char_set.rs +++ b/src/header/stdio/scanf/char_set.rs @@ -1,6 +1,6 @@ use core::ops::RangeInclusive; -use super::ScanError; +use super::FormatError; pub struct ScanCharSet { mask: [u64; 4], @@ -17,7 +17,7 @@ impl ScanCharSet { pub fn from_format_iter<'a, I: Iterator>( mut it: I, - ) -> Result<(I, Self), ScanError> { + ) -> Result<(I, Self), FormatError> { let mut maybe_close_bracket = true; let mut hyphen = false; let mut start: Option = None; @@ -51,7 +51,7 @@ impl ScanCharSet { if ch == b'-' { if hyphen { // "--"? - return Err(ScanError::InvalidFormat); + return Err(FormatError); } hyphen = true; @@ -62,7 +62,7 @@ impl ScanCharSet { if hyphen { let Some(start) = start.take() else { // "-x" without start? - return Err(ScanError::InvalidFormat); + return Err(FormatError); }; let same_category = (start.is_ascii_digit() && ch.is_ascii_digit()) @@ -73,7 +73,7 @@ impl ScanCharSet { hyphen = false; set.insert_range(start..=ch); } else { - return Err(ScanError::InvalidFormat); + return Err(FormatError); } } else { if let Some(start) = start.replace(ch) { diff --git a/src/header/stdio/scanf/mod.rs b/src/header/stdio/scanf/mod.rs index 8b551dd..69c07f4 100644 --- a/src/header/stdio/scanf/mod.rs +++ b/src/header/stdio/scanf/mod.rs @@ -1,6 +1,9 @@ -use core::ffi::{c_char, c_int, CStr, VaList}; +use core::ffi::{c_char, CStr, VaList}; -use crate::header::errno::Errno; +use crate::{ + error::{CEofResult, EResult}, + header::errno::{Errno, ESUCCESS}, +}; use self::{ char_set::ScanCharSet, @@ -14,25 +17,16 @@ mod char_set; mod format; mod reader; -pub enum ScanError { - ReadError(Errno), - InvalidFormat, -} - pub enum ConversionError { - ReadError(Errno), + Error(Errno), ConversionFailed, } -impl From for ScanError { - fn from(value: Errno) -> Self { - Self::ReadError(value) - } -} +pub struct FormatError; impl From for ConversionError { fn from(value: Errno) -> Self { - Self::ReadError(value) + Self::Error(value) } } @@ -40,7 +34,7 @@ fn scanf_inner( stream: &mut ScanReader, format: &[u8], mut ap: VaList, -) -> Result { +) -> EResult { let mut it = format.into_iter(); let mut matched = 0; let mut skip_space = false; @@ -128,7 +122,10 @@ fn scanf_inner( b'o' => ScanSpec::Unsigned(ScanRadix::Oct), b's' => ScanSpec::Word, b'[' => { - let (new_it, set) = ScanCharSet::from_format_iter(it)?; + let (new_it, set) = match ScanCharSet::from_format_iter(it) { + Ok(v) => v, + Err(FormatError) => return EResult::Err(ESUCCESS), + }; it = new_it; ScanSpec::Chars(set) } @@ -138,42 +135,46 @@ fn scanf_inner( b'%' => ScanSpec::Percent, b'f' | b'e' | b'g' | b'E' | b'a' => todo!(), // Unrecognized specifier - _ => return Err(ScanError::InvalidFormat), + _ => return EResult::Err(ESUCCESS), } } else { // No specifier after % - return Err(ScanError::InvalidFormat); + return EResult::Err(ESUCCESS); }; matched += match opts.scan(stream, spec, &mut ap) { Ok(matched) => matched, Err(ConversionError::ConversionFailed) => break, - Err(ConversionError::ReadError(err)) => return Err(ScanError::ReadError(err)), + Err(ConversionError::Error(err)) => return EResult::Err(err), }; } // TODO report end of stream before anything is matched - Ok(matched) + EResult::Ok(matched) } #[no_mangle] -unsafe extern "C" fn fscanf(stream: *mut FILE, format: *const c_char, mut args: ...) -> c_int { +unsafe extern "C" fn fscanf(stream: *mut FILE, format: *const c_char, mut args: ...) -> CEofResult { vfscanf(stream, format, args.as_va_list()) } #[no_mangle] -unsafe extern "C" fn scanf(format: *const c_char, mut args: ...) -> c_int { +unsafe extern "C" fn scanf(format: *const c_char, mut args: ...) -> CEofResult { vfscanf(stdin, format, args.as_va_list()) } #[no_mangle] -unsafe extern "C" fn sscanf(str: *const c_char, format: *const c_char, mut args: ...) -> c_int { +unsafe extern "C" fn sscanf( + str: *const c_char, + format: *const c_char, + mut args: ... +) -> CEofResult { vsscanf(str, format, args.as_va_list()) } #[no_mangle] -unsafe extern "C" fn vfscanf(stream: *mut FILE, format: *const c_char, ap: VaList) -> c_int { +unsafe extern "C" fn vfscanf(stream: *mut FILE, format: *const c_char, ap: VaList) -> CEofResult { if format.is_null() { panic!(); } @@ -183,19 +184,18 @@ unsafe extern "C" fn vfscanf(stream: *mut FILE, format: *const c_char, ap: VaLis let mut reader = ScanReader::new(stream); - match scanf_inner(&mut reader, format.to_bytes(), ap) { - Ok(count) => count.try_into().unwrap(), - Err(_) => -1, - } + let count = scanf_inner(&mut reader, format.to_bytes(), ap)?; + + CEofResult(count.try_into().unwrap()) } #[no_mangle] -unsafe extern "C" fn vscanf(format: *const c_char, ap: VaList) -> c_int { +unsafe extern "C" fn vscanf(format: *const c_char, ap: VaList) -> CEofResult { vfscanf(stdin, format, ap) } #[no_mangle] -unsafe extern "C" fn vsscanf(str: *const c_char, format: *const c_char, ap: VaList) -> c_int { +unsafe extern "C" fn vsscanf(str: *const c_char, format: *const c_char, ap: VaList) -> CEofResult { if str.is_null() || format.is_null() { panic!(); } @@ -206,8 +206,7 @@ unsafe extern "C" fn vsscanf(str: *const c_char, format: *const c_char, ap: VaLi let mut str_it = str.to_bytes().into_iter(); let mut reader = ScanReader::new(&mut str_it); - match scanf_inner(&mut reader, format.to_bytes(), ap) { - Ok(count) => count.try_into().unwrap(), - Err(_) => -1, - } + let count = scanf_inner(&mut reader, format.to_bytes(), ap)?; + + CEofResult(count.try_into().unwrap()) } diff --git a/src/header/stdio/scanf/reader.rs b/src/header/stdio/scanf/reader.rs index 75611bf..2632c51 100644 --- a/src/header/stdio/scanf/reader.rs +++ b/src/header/stdio/scanf/reader.rs @@ -1,10 +1,7 @@ -use crate::{ - header::{errno::Errno, stdio::FILE}, - io::Read, -}; +use crate::{error::EResult, header::stdio::FILE, io::Read}; pub trait GetChar { - fn getc(&mut self) -> Result, Errno>; + fn getc(&mut self) -> EResult>; } pub struct ScanReader<'a, G: GetChar> { @@ -14,19 +11,19 @@ pub struct ScanReader<'a, G: GetChar> { } impl GetChar for FILE { - fn getc(&mut self) -> Result, Errno> { + fn getc(&mut self) -> EResult> { let mut buf = [0]; match self.read(&mut buf) { - Ok(1) => Ok(Some(buf[0])), - Ok(_) => Ok(None), - Err(err) => Err(err), + EResult::Ok(1) => EResult::Ok(Some(buf[0])), + EResult::Ok(_) => EResult::Ok(None), + EResult::Err(err) => EResult::Err(err), } } } impl<'a, I: Iterator> GetChar for I { - fn getc(&mut self) -> Result, Errno> { - Ok(self.next().copied()) + fn getc(&mut self) -> EResult> { + EResult::Ok(self.next().copied()) } } @@ -39,11 +36,11 @@ impl<'a, G: GetChar> ScanReader<'a, G> { } } - fn getc(&mut self) -> Result, Errno> { + fn getc(&mut self) -> EResult> { match self.getter.getc() { - Ok(Some(n)) => { + EResult::Ok(Some(n)) => { self.consumed_count += 1; - Ok(Some(n)) + EResult::Ok(Some(n)) } e => e, } @@ -53,16 +50,16 @@ impl<'a, G: GetChar> ScanReader<'a, G> { self.consumed_count } - pub fn peek(&mut self) -> Result, Errno> { + pub fn peek(&mut self) -> EResult> { if self.buffer.is_none() { self.buffer = self.getc()?; } - Ok(self.buffer) + EResult::Ok(self.buffer) } - pub fn next(&mut self) -> Result, Errno> { + pub fn next(&mut self) -> EResult> { match self.buffer.take() { - Some(v) => Ok(Some(v)), + Some(v) => EResult::Ok(Some(v)), None => self.getc(), } } diff --git a/src/header/stdio/unlocked.rs b/src/header/stdio/unlocked.rs index 4af0bbf..2fe8265 100644 --- a/src/header/stdio/unlocked.rs +++ b/src/header/stdio/unlocked.rs @@ -1,13 +1,11 @@ use core::ffi::{c_char, c_int, c_void, CStr}; -use yggdrasil_rt::io::RawFd; - use crate::{ - error::{self, CSizeResult, CZeroResult}, + error::{CEofResult, CFdResult, CIntZeroResult, CUsizeResult, OptionExt}, header::errno::EBADF, }; -use super::{stdin, stdout, FileFlags, EOF, FILE}; +use super::{stdin, stdout, FileFlags, FILE}; #[no_mangle] pub unsafe extern "C" fn flockfile(stream: *mut FILE) { @@ -16,12 +14,10 @@ pub unsafe extern "C" fn flockfile(stream: *mut FILE) { } #[no_mangle] -pub unsafe extern "C" fn ftrylockfile(stream: *mut FILE) -> c_int { +pub unsafe extern "C" fn ftrylockfile(stream: *mut FILE) -> CIntZeroResult { let stream = stream.as_mut().unwrap(); - match stream.try_lock() { - true => 0, - false => -1, - } + stream.try_lock()?; + CIntZeroResult::OK } #[no_mangle] @@ -49,15 +45,10 @@ pub unsafe extern "C" fn clearerr_unlocked(stream: *mut FILE) { } #[no_mangle] -pub unsafe extern "C" fn fileno_unlocked(stream: *mut FILE) -> c_int { +pub unsafe extern "C" fn fileno_unlocked(stream: *mut FILE) -> CFdResult { let stream = stream.as_mut().unwrap(); - match stream.as_raw_fd_opt_unlocked() { - Some(RawFd(fd)) => fd as _, - None => { - error::set_errno(EBADF); - -1 - } - } + let fd = stream.as_raw_fd_opt_unlocked().e_ok_or(EBADF)?; + CFdResult::success(fd) } #[no_mangle] @@ -66,14 +57,16 @@ pub unsafe extern "C" fn fwrite_unlocked( size: usize, nmemb: usize, stream: *mut FILE, -) -> usize { +) -> CUsizeResult { if ptr.is_null() { panic!(); } let stream = stream.as_mut().unwrap(); let data = core::slice::from_raw_parts(ptr as *const u8, size * nmemb); - stream.write_unlocked(data).into_size_status() / size + let count = stream.write_unlocked(data)?; + + CUsizeResult(count / size) } #[no_mangle] @@ -82,62 +75,64 @@ pub unsafe extern "C" fn fread_unlocked( size: usize, nmemb: usize, stream: *mut FILE, -) -> usize { +) -> CUsizeResult { if ptr.is_null() { panic!(); } let stream = stream.as_mut().unwrap(); let data = core::slice::from_raw_parts_mut(ptr as *mut u8, size * nmemb); - stream.read_unlocked(data).into_size_status() / size + let count = stream.read_unlocked(data)?; + + CUsizeResult(count / size) } #[no_mangle] -pub unsafe extern "C" fn fflush_unlocked(stream: *mut FILE) -> c_int { +pub unsafe extern "C" fn fflush_unlocked(stream: *mut FILE) -> CEofResult { if let Some(stream) = stream.as_mut() { - stream.flush_unlocked().into_eof_status() + stream.flush_unlocked()?; } else { - super::fflush_all_unlocked().into_eof_status() + super::fflush_all_unlocked()?; } + + CEofResult(0) } #[no_mangle] -pub unsafe extern "C" fn fgetc_unlocked(stream: *mut FILE) -> c_int { +pub unsafe extern "C" fn fgetc_unlocked(stream: *mut FILE) -> CEofResult { let stream = stream.as_mut().unwrap(); let mut buf = [0]; - match stream.read_unlocked(&mut buf) { - Ok(1) => buf[0] as c_int, - Ok(_) => EOF, - Err(_) => EOF, + match stream.read_unlocked(&mut buf)? { + 1 => CEofResult(buf[0] as _), + _ => CEofResult::ERR, } } #[no_mangle] -pub unsafe extern "C" fn getc_unlocked(stream: *mut FILE) -> c_int { +pub unsafe extern "C" fn getc_unlocked(stream: *mut FILE) -> CEofResult { fgetc_unlocked(stream) } #[no_mangle] -pub unsafe extern "C" fn getchar_unlocked() -> c_int { +pub unsafe extern "C" fn getchar_unlocked() -> CEofResult { fgetc_unlocked(stdin) } #[no_mangle] -pub unsafe extern "C" fn putchar_unlocked(c: c_int) -> c_int { +pub unsafe extern "C" fn putchar_unlocked(c: c_int) -> CEofResult { fputc_unlocked(c, stdout) } #[no_mangle] -pub unsafe fn fputc_unlocked(c: c_int, stream: *mut FILE) -> c_int { +pub unsafe fn fputc_unlocked(c: c_int, stream: *mut FILE) -> CEofResult { let stream = stream.as_mut().unwrap(); - match stream.write_unlocked(&[c as u8]) { - Ok(_) => c, - Err(_) => EOF, - } + stream.write_unlocked(&[c as u8])?; + + CEofResult(0) } -pub unsafe fn fputs_unlocked(s: *const c_char, stream: *mut FILE) -> c_int { +pub unsafe fn fputs_unlocked(s: *const c_char, stream: *mut FILE) -> CEofResult { if s.is_null() { panic!(); } @@ -145,8 +140,8 @@ pub unsafe fn fputs_unlocked(s: *const c_char, stream: *mut FILE) -> c_int { let s = CStr::from_ptr(s); let stream = stream.as_mut().unwrap(); - match stream.write_unlocked(s.to_bytes()) { - Ok(_) => 0, - Err(_) => EOF, - } + // TODO write_all_unlocked + stream.write_unlocked(s.to_bytes())?; + + CEofResult(0) } diff --git a/src/header/stdlib/malloc.rs b/src/header/stdlib/malloc.rs index 3925a61..e1d8eb2 100644 --- a/src/header/stdlib/malloc.rs +++ b/src/header/stdlib/malloc.rs @@ -1,98 +1,28 @@ -use core::{ - alloc::{GlobalAlloc, Layout}, - ffi::c_void, - intrinsics, - ptr::null_mut, -}; +use core::{ffi::c_void, ptr::NonNull}; -use crate::{allocator::GLOBAL_ALLOCATOR, error, header::errno::ENOMEM}; +use crate::{allocator, error::CPtrResult}; -unsafe fn alloc_inner(size: usize) -> *mut c_void { - let size = (size + 15) & !15; - let layout = Layout::from_size_align(size + 16, 16).unwrap(); - let ptr = GLOBAL_ALLOCATOR.alloc(layout); - - if ptr.is_null() { - error::set_errno(ENOMEM); - return ptr as *mut c_void; - } - - *(ptr as *mut u64) = (size + 16) as u64; - *(ptr as *mut u64).add(1) = 16 as u64; - - ptr.add(16) as *mut c_void -} - -unsafe fn get_allocation(ptr: *mut c_void) -> (*mut u8, Layout) { - assert!(ptr as usize > 0x10); - let base = (ptr as *mut u8).sub(16); - let size = *(base as *mut u64); - let align = *(base as *mut u64).add(1); - let layout = Layout::from_size_align(size as _, align as _).unwrap(); - (base, layout) +#[no_mangle] +pub unsafe extern "C" fn calloc(nmemb: usize, size: usize) -> CPtrResult { + let ptr = allocator::c_allocate_zeroed(nmemb, size)?; + CPtrResult::success(ptr.cast()) } #[no_mangle] -pub unsafe extern "C" fn calloc(nmemb: usize, size: usize) -> *mut c_void { - match nmemb.checked_mul(size) { - Some(size) => { - let ptr = malloc(size); - if !ptr.is_null() { - intrinsics::write_bytes(ptr as *mut u8, 0, size); - } - ptr - } - None => { - error::set_errno(ENOMEM); - null_mut() - } - } +unsafe extern "C" fn malloc(size: usize) -> CPtrResult { + let ptr = allocator::c_allocate(size)?; + CPtrResult::success(ptr.cast()) } #[no_mangle] -pub unsafe extern "C" fn malloc(size: usize) -> *mut c_void { - alloc_inner(size) +unsafe extern "C" fn realloc(ptr: *mut c_void, new_size: usize) -> CPtrResult { + let ptr = allocator::c_reallocate(NonNull::new(ptr).map(NonNull::cast), new_size)?; + CPtrResult::success(ptr.cast()) } #[no_mangle] -pub unsafe extern "C" fn realloc(ptr: *mut c_void, new_size: usize) -> *mut c_void { - if ptr.is_null() { - return malloc(new_size); +unsafe extern "C" fn free(ptr: *mut c_void) { + if let Some(ptr) = NonNull::new(ptr) { + allocator::c_free(ptr.cast()) } - if new_size == 0 { - free(ptr); - return null_mut(); - } - - // TODO: implement realloc in libyalloc? - let (_, old_layout) = get_allocation(ptr); - let new_ptr = malloc(new_size); - - if !new_ptr.is_null() { - yggdrasil_rt::memcpy(new_ptr as _, ptr as _, old_layout.size()); - free(ptr); - } - - new_ptr -} - -#[no_mangle] -pub unsafe extern "C" fn free(ptr: *mut c_void) { - if ptr.is_null() { - return; - } - let (allocation, layout) = get_allocation(ptr); - GLOBAL_ALLOCATOR.dealloc(allocation, layout); -} - -#[no_mangle] -unsafe extern "C" fn ymalloc(size: usize) -> *mut c_void { - let ptr = GLOBAL_ALLOCATOR.alloc(Layout::from_size_align(size, 8).unwrap()); - ptr as _ -} - -#[no_mangle] -unsafe extern "C" fn yfree(ptr: *mut c_void, size: usize) { - assert!(!ptr.is_null()); - GLOBAL_ALLOCATOR.dealloc(ptr as _, Layout::from_size_align(size, 8).unwrap()); } diff --git a/src/header/stdlib/mod.rs b/src/header/stdlib/mod.rs index 7b16327..d28bd18 100644 --- a/src/header/stdlib/mod.rs +++ b/src/header/stdlib/mod.rs @@ -27,8 +27,6 @@ size_t wcstombs(char *restrict, const wchar_t *restrict, size_t); int wctomb(char *, wchar_t); */ -pub use malloc::{calloc, free, malloc, realloc}; - pub const EXIT_SUCCESS: c_int = 0; pub const EXIT_FAILURE: c_int = 1; diff --git a/src/header/stdlib/process.rs b/src/header/stdlib/process.rs index 38e6313..6e440d0 100644 --- a/src/header/stdlib/process.rs +++ b/src/header/stdlib/process.rs @@ -1,16 +1,17 @@ use core::{ ffi::{c_char, c_int, CStr}, - ptr::null_mut, + ptr::NonNull, }; -use crate::process; +use crate::{ + error::{CIntZeroResult, CPtrResult}, + process, +}; #[no_mangle] -pub unsafe extern "C" fn atexit(f: extern "C" fn()) -> c_int { - match process::register_atexit(f) { - Ok(()) => 0, - Err(_) => -1, - } +pub unsafe extern "C" fn atexit(f: extern "C" fn()) -> CIntZeroResult { + process::register_atexit(f)?; + CIntZeroResult::OK } #[no_mangle] @@ -29,15 +30,13 @@ pub unsafe extern "C" fn abort() -> ! { } #[no_mangle] -unsafe extern "C" fn getenv(name: *const c_char) -> *mut c_char { +unsafe extern "C" fn getenv(name: *const c_char) -> CPtrResult { if name.is_null() { panic!(); } let name = CStr::from_ptr(name); - match process::getenv_raw(name.to_bytes()) { - Some(data) => data.as_ptr() as _, - None => null_mut(), - } + let entry = process::getenv_raw(name.to_bytes())?; + CPtrResult::success(NonNull::new_unchecked(entry.as_ptr() as _)) } #[no_mangle] @@ -46,30 +45,32 @@ unsafe extern "C" fn putenv(string: *mut c_char) -> c_int { } #[no_mangle] -unsafe extern "C" fn setenv(name: *const c_char, value: *const c_char, overwrite: c_int) -> c_int { +unsafe extern "C" fn setenv( + name: *const c_char, + value: *const c_char, + overwrite: c_int, +) -> CIntZeroResult { if name.is_null() || value.is_null() { panic!(); } let name = CStr::from_ptr(name); let value = CStr::from_ptr(value); - match process::setenv_raw(name.to_bytes(), Some(value.to_bytes()), overwrite != 0) { - Ok(_) => 0, - Err(_) => -1, - } + process::setenv_raw(name.to_bytes(), Some(value.to_bytes()), overwrite != 0)?; + + CIntZeroResult::OK } #[no_mangle] -unsafe extern "C" fn unsetenv(name: *const c_char) -> c_int { +unsafe extern "C" fn unsetenv(name: *const c_char) -> CIntZeroResult { if name.is_null() { panic!(); } let name = CStr::from_ptr(name); - match process::setenv_raw(name.to_bytes(), None, true) { - Ok(_) => 0, - Err(_) => -1, - } + process::setenv_raw(name.to_bytes(), None, true)?; + + CIntZeroResult::OK } #[no_mangle] diff --git a/src/header/string/str.rs b/src/header/string/str.rs index a19680b..06425b1 100644 --- a/src/header/string/str.rs +++ b/src/header/string/str.rs @@ -7,10 +7,11 @@ use core::{ use yggdrasil_rt::memcpy; use crate::{ + allocator, + error::CPtrResult, header::{ errno::{self, Errno}, locale::locale_t, - stdlib::malloc, string::strlen, }, util::Nullable, @@ -95,12 +96,12 @@ unsafe extern "C" fn strcspn(mut s: *const c_char, reject: *const c_char) -> usi } #[no_mangle] -unsafe extern "C" fn strdup(s: *const c_char) -> *mut c_char { +unsafe extern "C" fn strdup(s: *const c_char) -> CPtrResult { s.ensure(); let len = strlen(s); - let data = malloc(len + 1); - memcpy(data as _, s as _, len + 1); - data as _ + let data = allocator::c_allocate(len + 1)?; + memcpy(data.cast().as_ptr(), s as _, len + 1); + CPtrResult::success(data.cast()) } unsafe fn strerror_inner(e: c_int) -> *const c_char { diff --git a/src/header/sys_stat/mod.rs b/src/header/sys_stat/mod.rs index 3ee3221..2fc92f2 100644 --- a/src/header/sys_stat/mod.rs +++ b/src/header/sys_stat/mod.rs @@ -3,13 +3,12 @@ use core::ffi::{c_char, c_int, CStr}; use yggdrasil_rt::io::{FileAttr, FileMode, FileType, RawFd}; use crate::{ - error::{self, CZeroResult}, + error::{CIntZeroResult, TryFromExt}, io, - util::Nullable, + util::{self, Nullable}, }; use super::{ - errno::EBADF, fcntl::{AT_FDCWD, AT_SYMLINK_NOFOLLOW}, sys_time::__ygg_timespec_t, sys_types::{blkcnt_t, blksize_t, dev_t, gid_t, ino_t, mode_t, nlink_t, off_t, uid_t}, @@ -115,29 +114,20 @@ unsafe extern "C" fn umask(mode: mode_t) -> mode_t { // Create stuff #[no_mangle] -unsafe extern "C" fn mkdir(pathname: *const c_char, mode: mode_t) -> c_int { +unsafe extern "C" fn mkdir(pathname: *const c_char, mode: mode_t) -> CIntZeroResult { mkdirat(AT_FDCWD, pathname, mode) } #[no_mangle] -unsafe extern "C" fn mkdirat(atfd: c_int, pathname: *const c_char, mode: mode_t) -> c_int { +unsafe extern "C" fn mkdirat(atfd: c_int, pathname: *const c_char, mode: mode_t) -> CIntZeroResult { pathname.ensure(); let pathname = CStr::from_ptr(pathname).to_str().unwrap(); - - // TODO move this to a function - let atfd = match atfd { - // Same as stat() - AT_FDCWD => None, - 0.. => Some(RawFd(atfd as _)), - _ => { - error::set_errno(EBADF); - return -1; - } - }; - + let atfd = util::at_fd(atfd)?; let mode = FileMode::new((mode & 0o777) as u32); - io::create_directory(atfd, pathname, mode).into_zero_status() + io::create_directory(atfd, pathname, mode)?; + + CIntZeroResult::OK } #[no_mangle] @@ -168,22 +158,15 @@ unsafe extern "C" fn mknodat( // File status #[no_mangle] -unsafe extern "C" fn fstat(fd: c_int, statbuf: *mut stat) -> c_int { - if fd < 0 { - error::set_errno(EBADF); - return -1; - } - - let attr = match io::get_metadata(Some(RawFd(fd as _)), "", false) { - Ok(attr) => attr, - Err(_) => return -1, - }; +unsafe extern "C" fn fstat(fd: c_int, statbuf: *mut stat) -> CIntZeroResult { + let fd = RawFd::e_try_from(fd)?; + let attr = io::get_metadata(Some(fd), "", false)?; if let Some(statbuf) = statbuf.as_mut() { *statbuf = attr.into(); } - 0 + CIntZeroResult::OK } #[no_mangle] @@ -192,42 +175,28 @@ unsafe extern "C" fn fstatat( pathname: *const c_char, statbuf: *mut stat, opt: c_int, -) -> c_int { +) -> CIntZeroResult { pathname.ensure(); let pathname = CStr::from_ptr(pathname).to_str().unwrap(); - - // TODO move this to a function - let atfd = match atfd { - // Same as stat() - AT_FDCWD => None, - 0.. => Some(RawFd(atfd as _)), - _ => { - error::set_errno(EBADF); - return -1; - } - }; - + let atfd = util::at_fd(atfd)?; let follow = opt & AT_SYMLINK_NOFOLLOW == 0; - let attr = match io::get_metadata(atfd, pathname, follow) { - Ok(attr) => attr, - Err(_) => return -1, - }; + let attr = io::get_metadata(atfd, pathname, follow)?; if let Some(statbuf) = statbuf.as_mut() { *statbuf = attr.into(); } - 0 + CIntZeroResult::OK } #[no_mangle] -unsafe extern "C" fn lstat(pathname: *const c_char, statbuf: *mut stat) -> c_int { +unsafe extern "C" fn lstat(pathname: *const c_char, statbuf: *mut stat) -> CIntZeroResult { fstatat(AT_FDCWD, pathname, statbuf, AT_SYMLINK_NOFOLLOW) } #[no_mangle] -unsafe extern "C" fn stat(pathname: *const c_char, statbuf: *mut stat) -> c_int { +unsafe extern "C" fn stat(pathname: *const c_char, statbuf: *mut stat) -> CIntZeroResult { fstatat(AT_FDCWD, pathname, statbuf, 0) } diff --git a/src/header/sys_wait/mod.rs b/src/header/sys_wait/mod.rs index d5e478f..48765cf 100644 --- a/src/header/sys_wait/mod.rs +++ b/src/header/sys_wait/mod.rs @@ -2,33 +2,31 @@ use core::ffi::c_int; use yggdrasil_rt::{process::ExitCode, sys as syscall}; -use super::{errno::Errno, sys_types::pid_t}; +use crate::error::{CPidResult, EResult}; -fn waitpid_inner(pid: u32) -> Result { +use super::sys_types::pid_t; + +fn waitpid_inner(pid: u32) -> EResult { let mut exit_code = ExitCode::SUCCESS; unsafe { syscall::wait_process(pid, &mut exit_code) }?; - Ok(exit_code) + EResult::Ok(exit_code) } #[no_mangle] -unsafe extern "C" fn waitpid(pid: pid_t, wstatus: *mut c_int, options: c_int) -> pid_t { +unsafe extern "C" fn waitpid(pid: pid_t, wstatus: *mut c_int, options: c_int) -> CPidResult { let _ = options; if pid < 0 { todo!(); } - let pid = pid as u32; + let pid: u32 = pid.try_into().unwrap(); + let code = waitpid_inner(pid)?; - match waitpid_inner(pid) { - Ok(code) => { - if let Some(wstatus) = wstatus.as_mut() { - match code { - ExitCode::Exited(code) => *wstatus = code, - ExitCode::BySignal(_) => todo!(), - } - } - - pid as pid_t + if let Some(wstatus) = wstatus.as_mut() { + match code { + ExitCode::Exited(code) => *wstatus = code, + ExitCode::BySignal(_signal) => todo!(), } - Err(_) => -1, } + + CPidResult::success(pid) } diff --git a/src/header/time/utility.rs b/src/header/time/utility.rs index 44da52a..b6f23c0 100644 --- a/src/header/time/utility.rs +++ b/src/header/time/utility.rs @@ -1,9 +1,7 @@ -use core::{ - ffi::{c_double, c_int}, - time::Duration, -}; +use core::{ffi::c_double, time::Duration}; use crate::{ + error::CIntZeroResult, header::{sys_time::__ygg_timespec_t, sys_types::time_t}, util, }; @@ -12,27 +10,17 @@ use crate::{ unsafe extern "C" fn nanosleep( rqtp: *const __ygg_timespec_t, rmtp: *mut __ygg_timespec_t, -) -> c_int { +) -> CIntZeroResult { let rqtp = rqtp.as_ref().unwrap(); + if let Some(_rmtp) = rmtp.as_mut() { + todo!(); + } let amount = Duration::from(*rqtp); - match util::nanosleep(amount, None) { - Ok(()) => { - if let Some(rmtp) = rmtp.as_mut() { - // Zero - *rmtp = __ygg_timespec_t::default(); - } + util::nanosleep(amount, None)?; - 0 - } - Err(_) => { - if let Some(rmtp) = rmtp.as_mut() { - todo!(); - } - -1 - } - } + CIntZeroResult::OK } #[no_mangle] diff --git a/src/header/unistd/io.rs b/src/header/unistd/io.rs index ef78c4e..ba1e187 100644 --- a/src/header/unistd/io.rs +++ b/src/header/unistd/io.rs @@ -3,7 +3,7 @@ use core::ffi::{c_char, c_int, c_long, c_void}; use yggdrasil_rt::io::SeekFrom; use crate::{ - error, + error::{CFdResult, CIntZeroResult, CIsizeResult, COffsetResult, EResult, TryFromExt}, file::RawFile, header::{ errno::EINVAL, @@ -18,82 +18,69 @@ use crate::{ pub const _PC_NAME_MAX: c_int = 1; pub const _PC_PATH_MAX: c_int = 2; +fn seek_offset(whence: c_int, offset: off_t) -> EResult { + match whence { + SEEK_SET => EResult::Ok(SeekFrom::Start(offset.try_into().unwrap())), + SEEK_END => EResult::Ok(SeekFrom::End(offset.try_into().unwrap())), + SEEK_CUR => EResult::Ok(SeekFrom::Current(offset.try_into().unwrap())), + _ => EResult::Err(EINVAL), + } +} + #[no_mangle] unsafe extern "C" fn getcwd(buf: *mut c_char, size: usize) -> *mut c_char { todo!() } #[no_mangle] -unsafe extern "C" fn close(fd: c_int) -> c_int { - let Ok(mut file) = RawFile::try_from(fd) else { - return -1; - }; - - match file.close() { - Ok(()) => 0, - Err(_) => -1, - } +unsafe extern "C" fn close(fd: c_int) -> CIntZeroResult { + let mut file = RawFile::e_try_from(fd)?; + file.close()?; + CIntZeroResult::OK } #[no_mangle] -unsafe extern "C" fn unlink(pathname: *const c_char) -> c_int { +unsafe extern "C" fn unlink(pathname: *const c_char) -> CIntZeroResult { unlinkat(AT_FDCWD, pathname, AT_SYMLINK_NOFOLLOW) } #[no_mangle] -unsafe extern "C" fn unlinkat(atfd: c_int, pathname: *const c_char, flags: c_int) -> c_int { +unsafe extern "C" fn unlinkat( + atfd: c_int, + pathname: *const c_char, + flags: c_int, +) -> CIntZeroResult { todo!() } #[no_mangle] -unsafe extern "C" fn write(fd: c_int, buf: *const c_void, count: usize) -> isize { +unsafe extern "C" fn write(fd: c_int, buf: *const c_void, count: usize) -> CIsizeResult { buf.ensure(); - let Ok(mut file) = RawFile::try_from(fd) else { - return -1; - }; + let mut file = RawFile::e_try_from(fd)?; let data = core::slice::from_raw_parts(buf as *const u8, count); + let count = file.write(data)?; - match file.write(data) { - Ok(amount) => amount.try_into().unwrap(), - Err(_) => -1, - } + CIsizeResult::success(count) } #[no_mangle] -unsafe extern "C" fn read(fd: c_int, buf: *mut c_void, count: usize) -> isize { +unsafe extern "C" fn read(fd: c_int, buf: *mut c_void, count: usize) -> CIsizeResult { buf.ensure(); - let Ok(mut file) = RawFile::try_from(fd) else { - return -1; - }; + let mut file = RawFile::e_try_from(fd)?; let data = core::slice::from_raw_parts_mut(buf as *mut u8, count); + let count = file.read(data)?; - match file.read(data) { - Ok(amount) => amount.try_into().unwrap(), - Err(_) => -1, - } + CIsizeResult::success(count) } #[no_mangle] -unsafe extern "C" fn lseek(fd: c_int, offset: off_t, whence: c_int) -> off_t { - let Ok(mut file) = RawFile::try_from(fd) else { - return -1; - }; - let offset = match whence { - SEEK_SET => SeekFrom::Start(offset.try_into().unwrap()), - SEEK_CUR => SeekFrom::Current(offset), - SEEK_END => SeekFrom::End(offset), - _ => { - error::set_errno(EINVAL); - return -1; - } - }; - - match file.seek(offset) { - Ok(pos) => pos.try_into().unwrap(), - Err(_) => -1, - } +unsafe extern "C" fn lseek(fd: c_int, offset: off_t, whence: c_int) -> COffsetResult { + let mut file = RawFile::e_try_from(fd)?; + let offset = seek_offset(whence, offset)?; + let pos = file.seek(offset)?; + COffsetResult::success(pos) } #[no_mangle] @@ -102,22 +89,22 @@ unsafe extern "C" fn faccessat( path: *const c_char, amode: c_int, flags: c_int, -) -> c_int { +) -> CIntZeroResult { todo!() } #[no_mangle] -unsafe extern "C" fn access(path: *const c_char, amode: c_int) -> c_int { +unsafe extern "C" fn access(path: *const c_char, amode: c_int) -> CIntZeroResult { faccessat(AT_FDCWD, path, amode, 0) } #[no_mangle] -unsafe extern "C" fn dup(fd: c_int) -> c_int { +unsafe extern "C" fn dup(fd: c_int) -> CFdResult { todo!() } #[no_mangle] -unsafe extern "C" fn dup2(oldfd: c_int, newfd: c_int) -> c_int { +unsafe extern "C" fn dup2(oldfd: c_int, newfd: c_int) -> CFdResult { todo!() } @@ -127,17 +114,17 @@ unsafe extern "C" fn isatty(fd: c_int) -> c_int { } #[no_mangle] -unsafe extern "C" fn rmdir(pathname: *const c_char) -> c_int { +unsafe extern "C" fn rmdir(pathname: *const c_char) -> CIntZeroResult { todo!() } #[no_mangle] -unsafe extern "C" fn chdir(pathname: *const c_char) -> c_int { +unsafe extern "C" fn chdir(pathname: *const c_char) -> CIntZeroResult { todo!() } #[no_mangle] -unsafe extern "C" fn pipe(fds: *mut c_int) -> c_int { +unsafe extern "C" fn pipe(fds: *mut c_int) -> CIntZeroResult { todo!() } diff --git a/src/header/unistd/process.rs b/src/header/unistd/process.rs index 2e0e924..639847e 100644 --- a/src/header/unistd/process.rs +++ b/src/header/unistd/process.rs @@ -7,21 +7,22 @@ use alloc::{vec, vec::Vec}; use yggdrasil_rt::{path::Path, process::ExecveOptions, sys as syscall}; use crate::{ - error::{CZeroResult, EResult}, - header::{errno::Errno, sys_types::pid_t}, + error::{CIntZeroResult, CPidResult, EResult}, + header::sys_types::pid_t, + process, util::{self, NullTerminated}, }; -unsafe fn fork_inner() -> Result { - let result = EResult::from(syscall::fork())?; - Ok(result as _) +unsafe fn fork_inner() -> EResult { + let result = syscall::fork()?; + EResult::Ok(result) } // TODO error reporting unsafe fn collect_execve_args<'a, 'e>( argv: *const *mut c_char, envp: *const *mut c_char, -) -> Result<(Vec<&'a str>, Vec<&'e str>), Errno> { +) -> EResult<(Vec<&'a str>, Vec<&'e str>)> { let mut arg_list = vec![]; let mut env_list = vec![]; @@ -38,34 +39,28 @@ unsafe fn collect_execve_args<'a, 'e>( } } - Ok((arg_list, env_list)) + EResult::Ok((arg_list, env_list)) } -unsafe fn execve_inner>( - pathname: P, - argv: &[&str], - envp: &[&str], -) -> Result<(), Errno> { +unsafe fn execve_inner>(pathname: P, argv: &[&str], envp: &[&str]) -> EResult<()> { let opts = ExecveOptions { program: pathname.as_ref().as_str(), arguments: argv, environment: envp, }; - let result = EResult::from(syscall::execve(&opts))?; - Ok(result as _) + let result = syscall::execve(&opts)?; + EResult::Ok(result) } -unsafe fn execvpe_inner(file: &str, argv: &[&str], envp: &[&str]) -> Result<(), Errno> { +unsafe fn execvpe_inner(file: &str, argv: &[&str], envp: &[&str]) -> EResult<()> { let pathname = util::resolve_binary(file)?; execve_inner(&pathname, argv, envp) } #[no_mangle] -unsafe extern "C" fn fork() -> pid_t { - match fork_inner() { - Ok(pid) => pid, - Err(_) => -1, - } +unsafe extern "C" fn fork() -> CPidResult { + let pid = fork_inner()?; + CPidResult::success(pid) } #[no_mangle] @@ -73,27 +68,26 @@ unsafe extern "C" fn execve( pathname: *const c_char, argv: *const *mut c_char, envp: *const *mut c_char, -) -> c_int { +) -> CIntZeroResult { if pathname.is_null() { panic!(); } let pathname = CStr::from_ptr(pathname); let pathname = pathname.to_str().unwrap(); - let (argv, envp) = match collect_execve_args(argv, envp) { - Ok(r) => r, - Err(_) => return -1, - }; + let (argv, envp) = collect_execve_args(argv, envp)?; - execve_inner(pathname, &argv, &envp).into_zero_status() + execve_inner(pathname, &argv, &envp)?; + + CIntZeroResult::OK } #[no_mangle] -unsafe extern "C" fn execv(pathname: *const c_char, argv: *const *mut c_char) -> c_int { +unsafe extern "C" fn execv(pathname: *const c_char, argv: *const *mut c_char) -> CIntZeroResult { execve(pathname, argv, null()) } #[no_mangle] -unsafe extern "C" fn execvp(file: *const c_char, argv: *const *mut c_char) -> c_int { +unsafe extern "C" fn execvp(file: *const c_char, argv: *const *mut c_char) -> CIntZeroResult { execvpe(file, argv, null()) } @@ -102,18 +96,17 @@ unsafe extern "C" fn execvpe( file: *const c_char, argv: *const *mut c_char, envp: *const *mut c_char, -) -> c_int { +) -> CIntZeroResult { if file.is_null() { panic!(); } let file = CStr::from_ptr(file); let file = file.to_str().unwrap(); - let (argv, envp) = match collect_execve_args(argv, envp) { - Ok(r) => r, - Err(_) => return -1, - }; + let (argv, envp) = collect_execve_args(argv, envp)?; - execvpe_inner(file, &argv, &envp).into_zero_status() + execvpe_inner(file, &argv, &envp)?; + + CIntZeroResult::OK } #[no_mangle] @@ -123,6 +116,6 @@ unsafe extern "C" fn _exit(status: c_int) -> ! { #[no_mangle] unsafe extern "C" fn getpid() -> pid_t { - let pid = syscall::get_pid(); + let pid = process::current_pid(); pid.try_into().unwrap() } diff --git a/src/io/buffered.rs b/src/io/buffered.rs index f70c1ff..7493a6f 100644 --- a/src/io/buffered.rs +++ b/src/io/buffered.rs @@ -6,7 +6,7 @@ use core::{ use alloc::{boxed::Box, vec::Vec}; -use crate::header::errno::Errno; +use crate::error::EResult; use super::{Read, Write}; @@ -65,20 +65,20 @@ impl<'a> ReadBuffer<'a> { self.len = 0; } - pub fn fill_from(&mut self, source: &mut R) -> Result<&[u8], Errno> { + pub fn fill_from(&mut self, source: &mut R) -> EResult<&[u8]> { let buffer = unsafe { self.data.as_slice_mut() }; if self.position == self.len { let amount = match source.read(buffer) { - Ok(0) => return Ok(&buffer[..0]), - Ok(n) => n, - Err(err) => return Err(err), + EResult::Ok(0) => return EResult::Ok(&buffer[..0]), + EResult::Ok(n) => n, + EResult::Err(err) => return EResult::Err(err), }; self.position = 0; self.len = amount; } - Ok(&mut buffer[self.position..self.len]) + EResult::Ok(&mut buffer[self.position..self.len]) } pub fn consume(&mut self, amount: usize) { @@ -137,17 +137,17 @@ impl LineWriter { } impl Write for UnbufferedWriter { - fn write(&mut self, data: &[u8]) -> Result { + fn write(&mut self, data: &[u8]) -> EResult { self.inner.write(data) } - fn flush(&mut self) -> Result<(), Errno> { - Ok(()) + fn flush(&mut self) -> EResult<()> { + EResult::Ok(()) } } impl Write for BufWriter { - fn write(&mut self, mut data: &[u8]) -> Result { + fn write(&mut self, mut data: &[u8]) -> EResult { if data.len() + self.buffer.len() >= self.buffer.capacity() { self.flush()?; } @@ -169,10 +169,10 @@ impl Write for BufWriter { // Store the data in the buffer assert!(data.len() < self.buffer.capacity()); self.buffer.extend_from_slice(data); - Ok(len) + EResult::Ok(len) } - fn flush(&mut self) -> Result<(), Errno> { + fn flush(&mut self) -> EResult<()> { let (amount, result) = self.inner.write_chunked(&self.buffer); if amount != 0 { self.buffer.drain(..amount); @@ -182,7 +182,7 @@ impl Write for BufWriter { } impl Write for LineWriter { - fn write(&mut self, data: &[u8]) -> Result { + fn write(&mut self, data: &[u8]) -> EResult { if self.need_flush { self.flush()?; } @@ -195,20 +195,20 @@ impl Write for LineWriter { let amount = self.inner.write(&data[..nl_pos + 1])?; self.need_flush = true; if self.flush().is_err() || amount != nl_pos + 1 { - return Ok(amount); + return EResult::Ok(amount); } // Write the rest to the buffer match self.inner.write(&data[nl_pos + 1..]) { - Ok(amount_to_buffer) => Ok(amount_to_buffer + amount), - Err(_) => Ok(amount), + EResult::Ok(amount_to_buffer) => EResult::Ok(amount_to_buffer + amount), + EResult::Err(_) => EResult::Ok(amount), } } - fn flush(&mut self) -> Result<(), Errno> { + fn flush(&mut self) -> EResult<()> { self.inner.flush()?; self.need_flush = false; - Ok(()) + EResult::Ok(()) } } diff --git a/src/io/dir.rs b/src/io/dir.rs index 07b5e97..19eadcb 100644 --- a/src/io/dir.rs +++ b/src/io/dir.rs @@ -7,10 +7,9 @@ use yggdrasil_rt::{ sys as syscall, }; -use crate::{ - error::{self, EResult}, - header::errno::{Errno, EBADF}, -}; +use crate::{error::EResult, header::errno::EBADF}; + +use super::FromRawFd; #[derive(Debug)] pub struct DirReader { @@ -25,27 +24,17 @@ pub struct DirReader { impl DirReader { const BUFFER_SIZE: usize = 16; - pub fn open_at>(at: Option, path: P) -> Result { - let fd = EResult::from(unsafe { syscall::open_directory(at, path.as_ref().as_str()) })?; - Ok(unsafe { Self::from_raw_fd(fd) }) + pub fn open_at>(at: Option, path: P) -> EResult { + let fd = unsafe { syscall::open_directory(at, path.as_ref().as_str()) }?; + EResult::Ok(unsafe { Self::from_raw_fd(fd) }) } - pub unsafe fn from_raw_fd(fd: RawFd) -> Self { - Self { - fd: Some(fd), - - buffer: Box::new_uninit_slice(Self::BUFFER_SIZE), - position: 0, - len: 0, - } - } - - pub unsafe fn close(&mut self) -> Result<(), Errno> { + pub unsafe fn close(&mut self) -> EResult<()> { if let Some(fd) = self.fd.take() { - EResult::from(unsafe { syscall::close(fd) })?; - Ok(()) + unsafe { syscall::close(fd) }?; + EResult::Ok(()) } else { - error::set_errno_result(EBADF) + EResult::Err(EBADF) } } @@ -53,34 +42,47 @@ impl DirReader { self.fd.unwrap() } - fn fill_buf(&mut self) -> Result<&[DirectoryEntry], Errno> { + fn fill_buf(&mut self) -> EResult<&[DirectoryEntry]> { let Some(fd) = self.fd else { - return error::set_errno_result(EBADF); + return EResult::Err(EBADF); }; if self.position == self.len { - let count = - EResult::from(unsafe { syscall::read_directory_entries(fd, &mut self.buffer) })?; + let count = unsafe { syscall::read_directory_entries(fd, &mut self.buffer) }?; self.position = 0; self.len = count; } - Ok(unsafe { MaybeUninit::slice_assume_init_ref(&self.buffer[self.position..self.len]) }) + EResult::Ok(unsafe { + MaybeUninit::slice_assume_init_ref(&self.buffer[self.position..self.len]) + }) } fn consume(&mut self, count: usize) { self.position = (self.position + count).min(self.len); } - pub fn read_entry(&mut self) -> Result, Errno> { + pub fn read_entry(&mut self) -> EResult> { let buf = self.fill_buf()?; if let Some(&entry) = buf.get(0) { self.consume(1); - Ok(Some(entry)) + EResult::Ok(Some(entry)) } else { - Ok(None) + EResult::Ok(None) + } + } +} + +impl FromRawFd for DirReader { + unsafe fn from_raw_fd(fd: RawFd) -> Self { + Self { + fd: Some(fd), + + buffer: Box::new_uninit_slice(Self::BUFFER_SIZE), + position: 0, + len: 0, } } } diff --git a/src/io/mod.rs b/src/io/mod.rs index 08d0098..8e16ea0 100644 --- a/src/io/mod.rs +++ b/src/io/mod.rs @@ -8,54 +8,62 @@ use yggdrasil_rt::{ use crate::{ error::EResult, - header::errno::{Errno, EINTR}, + header::errno::{EINTR, ESUCCESS}, }; pub mod buffered; pub mod dir; pub trait Write { - fn write(&mut self, data: &[u8]) -> Result; - fn flush(&mut self) -> Result<(), Errno>; + fn write(&mut self, data: &[u8]) -> EResult; + fn flush(&mut self) -> EResult<()>; - fn write_chunked(&mut self, data: &[u8]) -> (usize, Result<(), Errno>) { + fn write_chunked(&mut self, data: &[u8]) -> (usize, EResult<()>) { let mut pos = 0; let len = data.len(); while pos < len { match self.write(data) { - Ok(0) => todo!(), - Ok(n) => pos += n, - Err(err) if err == EINTR => todo!(), - Err(err) => return (pos, Err(err)), + EResult::Ok(0) => todo!(), + EResult::Ok(n) => pos += n, + EResult::Err(err) if err == EINTR => todo!(), + EResult::Err(err) => return (pos, EResult::Err(err)), } } - (pos, Ok(())) + (pos, EResult::Ok(())) } - fn write_all(&mut self, data: &[u8]) -> Result<(), Errno> { + fn write_all(&mut self, data: &[u8]) -> EResult<()> { match self.write(data) { - Ok(n) if n == data.len() => Ok(()), - Ok(_) => todo!(), // TODO handle partial writes in write_all - Err(err) => Err(err), + EResult::Ok(n) if n == data.len() => EResult::Ok(()), + EResult::Ok(_) => todo!(), // TODO handle partial writes in write_all + EResult::Err(err) => EResult::Err(err), } } } pub trait Read { - fn read(&mut self, data: &mut [u8]) -> Result; + fn read(&mut self, data: &mut [u8]) -> EResult; + + fn read_exact(&mut self, data: &mut [u8]) -> EResult<()> { + if self.read(data)? == data.len() { + EResult::Ok(()) + } else { + EResult::Err(ESUCCESS) + } + } } pub trait BufRead { - fn fill_buf(&mut self) -> Result<&[u8], Errno>; + fn fill_buf(&mut self) -> EResult<&[u8]>; fn consume(&mut self, amount: usize); } pub trait Seek { - fn seek(&mut self, off: SeekFrom) -> Result; + fn seek(&mut self, off: SeekFrom) -> EResult; - fn stream_position(&mut self) -> Result { + fn stream_position(&mut self) -> EResult { self.seek(SeekFrom::Current(0)) } } @@ -76,21 +84,13 @@ pub trait IntoRawFd { fn into_raw_fd(self) -> RawFd; } -pub fn get_metadata>( - at: Option, - path: P, - follow: bool, -) -> Result { +pub fn get_metadata>(at: Option, path: P, follow: bool) -> EResult { let mut attr = MaybeUninit::uninit(); - EResult::from(unsafe { syscall::get_metadata(at, path.as_ref().as_str(), &mut attr, follow) })?; - Ok(unsafe { attr.assume_init() }) + unsafe { syscall::get_metadata(at, path.as_ref().as_str(), &mut attr, follow) }?; + EResult::Ok(unsafe { attr.assume_init() }) } -pub fn create_directory>( - at: Option, - path: P, - mode: FileMode, -) -> Result<(), Errno> { - EResult::from(unsafe { syscall::create_directory(at, path.as_ref().as_str(), mode) })?; - Ok(()) +pub fn create_directory>(at: Option, path: P, mode: FileMode) -> EResult<()> { + unsafe { syscall::create_directory(at, path.as_ref().as_str(), mode) }?; + EResult::Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index 13cf630..3d5d33d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,9 @@ new_uninit, maybe_uninit_slice, inline_const, - vec_into_raw_parts + vec_into_raw_parts, + slice_ptr_get, + strict_provenance )] #![no_std] diff --git a/src/path.rs b/src/path.rs index 4b77be6..eea8326 100644 --- a/src/path.rs +++ b/src/path.rs @@ -3,10 +3,10 @@ use core::{borrow::Borrow, mem::MaybeUninit, ops::Deref}; use alloc::{borrow::ToOwned, string::String}; use yggdrasil_rt::{io::FileAttr, path::Path, sys as syscall}; -use crate::{error::EResult, header::errno::Errno}; +use crate::error::EResult; pub trait PathExt { - fn metadata(&self) -> Result; + fn metadata(&self) -> EResult; fn exists(&self) -> bool { self.metadata().is_ok() @@ -17,11 +17,11 @@ pub trait PathExt { pub struct PathBuf(String); impl PathExt for Path { - fn metadata(&self) -> Result { + fn metadata(&self) -> EResult { let mut metadata = MaybeUninit::uninit(); - EResult::from(unsafe { syscall::get_metadata(None, self.as_str(), &mut metadata, true) })?; + unsafe { syscall::get_metadata(None, self.as_str(), &mut metadata, true) }?; let metadata = unsafe { metadata.assume_init() }; - Ok(metadata) + EResult::Ok(metadata) } } diff --git a/src/process.rs b/src/process.rs index 2e36197..4cd789e 100644 --- a/src/process.rs +++ b/src/process.rs @@ -7,9 +7,9 @@ use yggdrasil_rt::{ }; use crate::{ - error, + error::{EResult, OptionExt}, header::{ - errno::{Errno, EINVAL, ENOMEM, ESUCCESS}, + errno::{EINVAL, ENOMEM, ESUCCESS}, stdio, unistd::environ, }, @@ -40,13 +40,14 @@ const ATEXIT_MAX: usize = 32; static ATEXIT: Mutex<[Option; ATEXIT_MAX]> = Mutex::new([const { None }; ATEXIT_MAX]); -pub unsafe fn register_atexit(f: extern "C" fn()) -> Result<(), Errno> { +pub unsafe fn register_atexit(f: extern "C" fn()) -> EResult<()> { let mut lock = ATEXIT.lock(); let Some(slot) = lock.iter_mut().find(|p| p.is_none()) else { - return error::set_errno_result(ENOMEM); + return EResult::Err(ENOMEM); }; + slot.replace(f); - Ok(()) + EResult::Ok(()) } pub unsafe fn raw_exit(code: T) -> ! { @@ -118,26 +119,28 @@ pub fn getenv(name: &str) -> Option<&'static str> { } // NOTE guaranteed to be null-terminated, as the slice is backed by a CString -pub unsafe fn getenv_raw(key: &[u8]) -> Option<&'static [u8]> { +pub unsafe fn getenv_raw(key: &[u8]) -> EResult<&'static [u8]> { debug_assert_eq!(ENVS.len() + 1, C_ENVS.len()); - ENVS.iter().find_map(|var| { - let var = var.as_bytes(); - let eq_pos = memchr::memchr(b'=', var)?; - let var_key = &var[..eq_pos]; - let var_value = &var[eq_pos + 1..]; + ENVS.iter() + .find_map(|var| { + let var = var.as_bytes(); + let eq_pos = memchr::memchr(b'=', var)?; + let var_key = &var[..eq_pos]; + let var_value = &var[eq_pos + 1..]; - (var_key == key).then_some(var_value) - }) + (var_key == key).then_some(var_value) + }) + .e_ok_or(ESUCCESS) } // TODO test this crap works at all -pub unsafe fn setenv_raw(key: &[u8], value: Option<&[u8]>, overwrite: bool) -> Result<(), Errno> { +pub unsafe fn setenv_raw(key: &[u8], value: Option<&[u8]>, overwrite: bool) -> EResult<()> { // TODO even though char **environ exists, can this still be put under a lock? debug_assert_eq!(ENVS.len() + 1, C_ENVS.len()); if memchr::memchr(b'=', key).is_some() { - return error::set_errno_result(EINVAL); + return EResult::Err(EINVAL); } let index = ENVS.iter().position(|var| { @@ -154,7 +157,7 @@ pub unsafe fn setenv_raw(key: &[u8], value: Option<&[u8]>, overwrite: bool) -> R if let Some(index) = index { if !overwrite { // errno is not set - return error::set_errno_result(ESUCCESS); + return EResult::Err(ESUCCESS); } // Remove the old var @@ -162,7 +165,7 @@ pub unsafe fn setenv_raw(key: &[u8], value: Option<&[u8]>, overwrite: bool) -> R ENVS.remove(index); } else if value.is_none() { // No entry exists and unsetenv was called - return error::set_errno_result(ESUCCESS); + return EResult::Err(ESUCCESS); } if let Some(value) = value { @@ -181,5 +184,5 @@ pub unsafe fn setenv_raw(key: &[u8], value: Option<&[u8]>, overwrite: bool) -> R C_ENVS.push(null_mut()); } - Ok(()) + EResult::Ok(()) } diff --git a/src/signal.rs b/src/signal.rs index 8b6444a..f252c1d 100644 --- a/src/signal.rs +++ b/src/signal.rs @@ -8,10 +8,7 @@ use yggdrasil_rt::{ use crate::{ error::EResult, - header::{ - errno::Errno, - signal::{sig_handler_t, SigNumber}, - }, + header::signal::{sig_handler_t, SigNumber}, process, }; @@ -55,9 +52,9 @@ pub unsafe fn set_handler(signal: Signal, handler: Option) -> sig core::mem::transmute(old_handler_ptr) } -pub unsafe fn send(target: u32, signal: Signal) -> Result<(), Errno> { - EResult::from(syscall::send_signal(target, signal))?; - Ok(()) +pub unsafe fn send(target: u32, signal: Signal) -> EResult<()> { + syscall::send_signal(target, signal)?; + EResult::Ok(()) } pub unsafe fn init() { diff --git a/src/util.rs b/src/util.rs index 37223e9..47dbb49 100644 --- a/src/util.rs +++ b/src/util.rs @@ -1,10 +1,19 @@ -use core::{ffi::c_char, fmt, marker::PhantomData, ptr::NonNull, time::Duration}; +use core::{ + ffi::{c_char, c_int}, + fmt, + marker::PhantomData, + ptr::NonNull, + time::Duration, +}; -use yggdrasil_rt::{path::Path, sys as syscall}; +use yggdrasil_rt::{io::RawFd, path::Path, sys as syscall}; use crate::{ error::{EResult, OptionExt}, - header::errno::Errno, + header::{ + errno::{EBADF, EEXIST}, + fcntl::AT_FDCWD, + }, path::{PathBuf, PathExt}, process::getenv, }; @@ -20,6 +29,12 @@ pub trait Nullable { fn ensure(&self); } +pub trait NonNullExt { + // TODO added in later versions of Rust + unsafe fn add_ext(self, n: usize) -> Self; + unsafe fn sub_ext(self, n: usize) -> Self; +} + pub struct NullTerminated<'a, T: Nullable> { data: *const T, _pd: PhantomData<&'a ()>, @@ -105,12 +120,22 @@ impl fmt::Write for CStringWriter { } } +impl NonNullExt for NonNull { + unsafe fn add_ext(self, n: usize) -> Self { + Self::new_unchecked(self.as_ptr().add(n)) + } + + unsafe fn sub_ext(self, n: usize) -> Self { + Self::new_unchecked(self.as_ptr().sub(n)) + } +} + pub fn resolve_binary>(name: P) -> EResult { let name = name.as_ref(); if name.is_absolute() { return EResult::Ok(PathBuf::from(name)); } - let env_path = getenv("PATH").e_ok_or(yggdrasil_rt::Error::DoesNotExist)?; + let env_path = getenv("PATH").e_ok_or(EEXIST)?; for el in env_path.split(':') { let path = PathBuf::from_str(el).join(name); @@ -119,14 +144,22 @@ pub fn resolve_binary>(name: P) -> EResult { } } - EResult::Err(yggdrasil_rt::Error::DoesNotExist) + EResult::Err(EEXIST) } // TODO EINTR for interrupted sleeps -pub fn nanosleep(amount: Duration, remaining: Option<&mut Duration>) -> Result<(), Errno> { +pub fn nanosleep(amount: Duration, remaining: Option<&mut Duration>) -> EResult<()> { if remaining.is_some() { todo!(); } unsafe { syscall::nanosleep(amount) }; - Ok(()) + EResult::Ok(()) +} + +pub fn at_fd(fd: c_int) -> EResult> { + match fd { + AT_FDCWD => EResult::Ok(None), + 0.. => EResult::Ok(Some(RawFd(fd.try_into().unwrap()))), + _ => EResult::Err(EBADF), + } }