Better error handling

This commit is contained in:
Mark Poliakov 2024-01-16 14:38:57 +02:00
parent af1b621042
commit 4a4e4d8d13
33 changed files with 1283 additions and 1042 deletions

View File

@ -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<P: AsRef<Path>>(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)

View File

@ -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<u8>) -> (NonNull<u8>, Layout) {
assert!(usize::from(ptr.addr()) > 0x10);
let real_ptr = ptr.sub_ext(OFFSET);
let size = *real_ptr.cast::<u64>().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<NonNull<u8>> {
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::<u64>().as_mut() = layout.size().try_into().unwrap();
}
unsafe { EResult::Ok(ptr.add_ext(OFFSET)) }
}
pub fn c_allocate_zeroed(nmemb: usize, size: usize) -> EResult<NonNull<u8>> {
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<NonNull<u8>>, size: usize) -> EResult<NonNull<u8>> {
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<u8>) {
let (real_ptr, layout) = get_allocation(ptr);
GlobalAllocator.dealloc(real_ptr.as_ptr(), layout);
}

View File

@ -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<T>(*mut T);
impl FromResidual<EResult<Infallible>> for CUsizeResult {
fn from_residual(residual: EResult<Infallible>) -> 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<T>: Sized {
fn e_try_from(value: T) -> EResult<Self>;
impl FromResidual<EResult<Infallible>> for CIsizeResult {
fn from_residual(residual: EResult<Infallible>) -> Self {
let err = residual.unwrap_err();
unsafe {
errno = err;
}
Self(-1)
}
}
pub trait OptionExt<T> {
fn e_ok_or(self, err: yggdrasil_rt::Error) -> EResult<T>;
impl FromResidual<EResult<Infallible>> for CIntCountResult {
fn from_residual(residual: EResult<Infallible>) -> 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<T> {
Ok(T),
Err(yggdrasil_rt::Error),
Errno(Errno),
impl CIntZeroResult {
pub const ERR: Self = Self(-1);
pub const OK: Self = Self(0);
}
impl<T> From<Result<T, yggdrasil_rt::Error>> for EResult<T> {
fn from(value: Result<T, yggdrasil_rt::Error>) -> Self {
match value {
Ok(value) => Self::Ok(value),
Err(error) => Self::Err(error),
impl FromResidual<EResult<Infallible>> for CIntZeroResult {
fn from_residual(residual: EResult<Infallible>) -> 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<EResult<Infallible>> for CFdResult {
fn from_residual(residual: EResult<Infallible>) -> Self {
let err = residual.unwrap_err();
unsafe {
errno = err;
}
Self::ERR
}
}
impl CEofResult {
pub const ERR: Self = Self(EOF);
pub fn ok(&self) -> Option<c_int> {
match self.0 {
EOF => None,
v => Some(v),
}
}
}
impl FromResidual<EResult<Infallible>> for CEofResult {
fn from_residual(residual: EResult<Infallible>) -> Self {
let err = residual.unwrap_err();
unsafe {
errno = err;
}
Self::ERR
}
}
impl COffsetResult {
pub const ERR: Self = Self(-1);
pub fn ok(self) -> Option<i64> {
if self.0 >= 0 {
Some(self.0)
} else {
None
}
}
pub fn success(value: u64) -> Self {
Self(value.try_into().unwrap())
}
}
impl FromResidual<EResult<Infallible>> for COffsetResult {
fn from_residual(residual: EResult<Infallible>) -> 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<EResult<Infallible>> for CPidResult {
fn from_residual(residual: EResult<Infallible>) -> Self {
let err = residual.unwrap_err();
unsafe {
errno = err;
}
Self::ERR
}
}
impl<T> CPtrResult<T> {
pub const ERR: Self = Self(null_mut());
pub const fn success(value: NonNull<T>) -> Self {
Self(value.as_ptr())
}
}
impl<T> FromResidual<EResult<Infallible>> for CPtrResult<T> {
fn from_residual(residual: EResult<Infallible>) -> Self {
let err = residual.unwrap_err();
unsafe {
errno = err;
}
Self::ERR
}
}
/////////////////
#[must_use = "ErrnoResult<T> must be converted into its output type with proper errno set"]
pub enum EResult<T> {
Ok(T),
Err(Errno),
}
impl<T> EResult<T> {
pub fn into_set_errno(self) -> EResult<T> {
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<T> {
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, F: Fn(Errno) -> E>(self, map_err: F, set_errno: bool) -> Result<T, E> {
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<usize, Errno> {
fn into_size_status(self) -> usize {
match self {
Self::Ok(value) => value,
Self::Err(_) => 0,
}
}
}
impl<T> FromResidual<Errno> for EResult<T> {
fn from_residual(residual: Errno) -> Self {
Self::Errno(residual)
}
}
impl<T> FromResidual<yggdrasil_rt::Error> for EResult<T> {
fn from_residual(residual: yggdrasil_rt::Error) -> Self {
Self::Err(residual)
}
}
impl<T> FromResidual<Result<Infallible, Errno>> for EResult<T> {
fn from_residual(_residual: Result<Infallible, Errno>) -> Self {
todo!()
}
}
impl<T> Try for EResult<T> {
type Output = T;
type Residual = Result<Infallible, Errno>;
type Residual = EResult<Infallible>;
fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
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<T> FromResidual<EResult<Infallible>> for EResult<T> {
fn from_residual(residual: EResult<Infallible>) -> Self {
let err = residual.unwrap_err();
Self::Err(err)
}
}
impl<T> FromResidual<Result<Infallible, yggdrasil_rt::Error>> for EResult<T> {
fn from_residual(residual: Result<Infallible, yggdrasil_rt::Error>) -> Self {
let err = residual.unwrap_err();
Self::Err(err.into())
}
}
impl<T, E: From<Errno>> FromResidual<EResult<Infallible>> for Result<T, E> {
fn from_residual(residual: EResult<Infallible>) -> Self {
let err = residual.unwrap_err();
Err(err.into())
}
}
///////////////////////////////////////////////
pub trait OptionExt<T> {
fn e_ok_or(self, err: Errno) -> EResult<T>;
}
impl<T> OptionExt<T> for Option<T> {
fn e_ok_or(self, err: yggdrasil_rt::Error) -> EResult<T> {
fn e_ok_or(self, err: Errno) -> EResult<T> {
match self {
Some(value) => EResult::Ok(value),
Some(val) => EResult::Ok(val),
None => EResult::Err(err),
}
}
}
pub fn set_errno_result<T>(e: Errno) -> Result<T, Errno> {
set_errno(e);
Err(e)
///////////////////////////////////////////////
pub trait TryFromExt<T>: Sized {
fn e_try_from(value: T) -> EResult<Self>;
}
pub fn set_errno(e: Errno) {
unsafe {
errno = e;
impl TryFromExt<c_int> for RawFd {
fn e_try_from(value: c_int) -> EResult<Self> {
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);

View File

@ -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<Self, Errno> {
let fd =
EResult::from(unsafe { syscall::open(at, pathname.as_ref().as_str(), opts, mode) })?;
Ok(Self { fd })
) -> EResult<Self> {
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<usize, Errno> {
let count = EResult::from(unsafe { syscall::write(self.fd, data) })?;
Ok(count)
fn write(&mut self, data: &[u8]) -> EResult<usize> {
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<usize, Errno> {
let count = EResult::from(unsafe { syscall::read(self.fd, data) })?;
Ok(count)
fn read(&mut self, data: &mut [u8]) -> EResult<usize> {
let count = unsafe { syscall::read(self.fd, data) }?;
EResult::Ok(count)
}
}
impl Seek for RawFile {
fn seek(&mut self, off: SeekFrom) -> Result<u64, Errno> {
let pos = EResult::from(unsafe { syscall::seek(self.fd, off) })?;
Ok(pos)
fn seek(&mut self, off: SeekFrom) -> EResult<u64> {
let pos = unsafe { syscall::seek(self.fd, off) }?;
EResult::Ok(pos)
}
}
@ -93,17 +91,10 @@ impl IntoRawFd for RawFile {
}
}
impl TryFrom<c_int> for RawFile {
type Error = Errno;
fn try_from(value: c_int) -> Result<Self, Self::Error> {
if value >= 0 {
Ok(Self {
fd: RawFd(value as _),
})
} else {
error::set_errno_result(EBADF)
}
impl TryFromExt<c_int> for RawFile {
fn e_try_from(value: c_int) -> EResult<Self> {
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<Self, Errno> {
) -> EResult<Self> {
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<usize, Errno> {
fn write(&mut self, data: &[u8]) -> EResult<usize> {
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<usize, Errno> {
fn read(&mut self, data: &mut [u8]) -> EResult<usize> {
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<u64, Errno> {
fn seek(&mut self, off: SeekFrom) -> EResult<u64> {
match self {
Self::File(file) => file.seek(off),
}

View File

@ -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<Self>) -> 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<NonNull<dirent>> {
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<DirectoryEntry> for dirent {
fn from(value: DirectoryEntry) -> Self {
let mut d_name = [0; 256];
@ -52,49 +76,34 @@ impl From<DirectoryEntry> 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<DIR> {
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<DIR> {
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<dirent> {
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

View File

@ -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<OpenMode, Errno> {
fn open_opts(opts: c_int, ap: &mut VaList) -> EResult<OpenMode> {
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<OpenMode, Errno> {
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<OpenMode, Errno> {
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())
}

View File

@ -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<O: FileOpenSource>(source: O, mode_str: &[u8]) -> Result<*mut FILE, Errno> {
fn open_inner<O: FileOpenSource>(source: O, mode_str: &[u8]) -> EResult<NonNull<FILE>> {
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<O: FileOpenSource>(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<FILE> {
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<FILE> {
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<FILE> {
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<FILE> {
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<FILE> {
todo!()
}

View File

@ -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<c_char> {
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<NonNull<c_char>>,
capacity: usize,
position: usize,
}
impl MallocBufferWriter {
fn putc(&mut self, ch: c_int) -> bool {
unsafe fn new(buffer: Option<NonNull<c_char>>, 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<NonNull<c_char>>,
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)
}

View File

@ -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<FILE, Errno>;
fn open_with(self, opts: OpenOptions) -> EResult<FILE>;
}
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<Self>) -> 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<usize, Errno> {
pub unsafe fn write_unlocked(&mut self, data: &[u8]) -> EResult<usize> {
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<usize, Errno> {
pub unsafe fn read_unlocked(&mut self, data: &mut [u8]) -> EResult<usize> {
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<u64, Errno> {
unsafe fn seek_unlocked(&mut self, off: SeekFrom) -> EResult<u64> {
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<usize, Errno> {
fn write(&mut self, data: &[u8]) -> EResult<usize> {
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<usize, Errno> {
fn read(&mut self, data: &mut [u8]) -> EResult<usize> {
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<u64, Errno> {
fn seek(&mut self, off: SeekFrom) -> EResult<u64> {
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<FILE, Errno> {
fn open_with(self, opts: OpenOptions) -> EResult<FILE> {
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<FILE, Errno> {
fn open_with(self, opts: OpenOptions) -> EResult<FILE> {
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<c_int> 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<BTreeSet<*mut FILE>> = Mutex::new(BTreeSet::new());
pub static OPEN_FILES: Mutex<BTreeSet<NonNull<FILE>>> = Mutex::new(BTreeSet::new());
pub unsafe fn register_file(file: *mut FILE) {
pub unsafe fn register_file(file: NonNull<FILE>) {
OPEN_FILES.lock().insert(file);
}
pub unsafe fn deregister_file(file: *mut FILE) -> bool {
pub unsafe fn deregister_file(file: NonNull<FILE>) -> 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();
}
}

View File

@ -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<W: Write + fmt::Write>(
output: &mut W,
precision: usize,
opts: &FmtOpts,
) -> Result<usize, Errno> {
) -> EResult<usize> {
let mut exp2 = exp;
let mut exp_len = 1;
while exp2 >= 10 {
@ -48,12 +45,14 @@ fn fmt_float_exp<W: Write + fmt::Write>(
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<W: Write + fmt::Write>(
output: &mut W,
precision: usize,
opts: &FmtOpts,
) -> Result<usize, Errno> {
) -> EResult<usize> {
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<W: Write + fmt::Write>(
@ -80,7 +79,7 @@ fn fmt_float_nonfinite<W: Write + fmt::Write>(
output: &mut W,
upper: bool,
opts: &FmtOpts,
) -> Result<usize, Errno> {
) -> EResult<usize> {
let mut len = 0;
if val.is_sign_negative() {
len += output.write(b"-")?;
@ -102,7 +101,7 @@ fn fmt_float_nonfinite<W: Write + fmt::Write>(
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<W: Write + fmt::Write>(
@ -110,7 +109,7 @@ pub fn fmt_float<W: Write + fmt::Write>(
output: &mut W,
upper: bool,
opts: &FmtOpts,
) -> Result<usize, Errno> {
) -> EResult<usize> {
if val.is_finite() {
fmt_float_finite(val, output, 6, opts)
} else {
@ -123,7 +122,7 @@ pub fn fmt_float_scientific<W: Write + fmt::Write>(
output: &mut W,
upper: bool,
opts: &FmtOpts,
) -> Result<usize, Errno> {
) -> EResult<usize> {
if val.is_finite() {
let (val, exp) = float_exp(val);
let exp_fmt = match upper {
@ -143,7 +142,7 @@ pub fn fmt_float_any<W: Write + fmt::Write>(
output: &mut W,
upper: bool,
opts: &FmtOpts,
) -> Result<usize, Errno> {
) -> EResult<usize> {
if val.is_finite() {
let (log, exp) = float_exp(val);
let exp_fmt = match upper {

View File

@ -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<W: Write + fmt::Write>(&self, output: &mut W, len: usize) -> Result<usize, Errno> {
fn pad<W: Write + fmt::Write>(&self, output: &mut W, len: usize) -> EResult<usize> {
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<W: Write + fmt::Write>(
&self,
output: &mut W,
len: usize,
) -> Result<usize, Errno> {
pub fn left_pad<W: Write + fmt::Write>(&self, output: &mut W, len: usize) -> EResult<usize> {
if !self.left_adjust {
self.pad(output, len)
} else {
Ok(0)
EResult::Ok(0)
}
}
pub fn right_pad<W: Write + fmt::Write>(
&self,
output: &mut W,
len: usize,
) -> Result<usize, Errno> {
pub fn right_pad<W: Write + fmt::Write>(&self, output: &mut W, len: usize) -> EResult<usize> {
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<usize, Errno> {
) -> EResult<usize> {
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)
}
}

View File

@ -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<usize, Errno> {
fn write(&mut self, data: &[u8]) -> EResult<usize> {
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<usize, Errno> {
let count = EResult::from(unsafe { syscall::write(self.fd, data) })?;
Ok(count)
fn write(&mut self, data: &[u8]) -> EResult<usize> {
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<W: Write + fmt::Write>(
output: &mut W,
format: &[u8],
mut ap: VaList,
) -> Result<usize, Errno> {
) -> EResult<usize> {
let mut fmt = format.into_iter();
let mut count = 0;
@ -181,41 +182,51 @@ fn printf_inner<W: Write + fmt::Write>(
}
}
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())
}

View File

@ -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<Item = &'a u8>>(
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<u8> = 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) {

View File

@ -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<Errno> for ScanError {
fn from(value: Errno) -> Self {
Self::ReadError(value)
}
}
pub struct FormatError;
impl From<Errno> for ConversionError {
fn from(value: Errno) -> Self {
Self::ReadError(value)
Self::Error(value)
}
}
@ -40,7 +34,7 @@ fn scanf_inner<G: GetChar>(
stream: &mut ScanReader<G>,
format: &[u8],
mut ap: VaList,
) -> Result<usize, ScanError> {
) -> EResult<usize> {
let mut it = format.into_iter();
let mut matched = 0;
let mut skip_space = false;
@ -128,7 +122,10 @@ fn scanf_inner<G: GetChar>(
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<G: GetChar>(
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())
}

View File

@ -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<Option<u8>, Errno>;
fn getc(&mut self) -> EResult<Option<u8>>;
}
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<Option<u8>, Errno> {
fn getc(&mut self) -> EResult<Option<u8>> {
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<Item = &'a u8>> GetChar for I {
fn getc(&mut self) -> Result<Option<u8>, Errno> {
Ok(self.next().copied())
fn getc(&mut self) -> EResult<Option<u8>> {
EResult::Ok(self.next().copied())
}
}
@ -39,11 +36,11 @@ impl<'a, G: GetChar> ScanReader<'a, G> {
}
}
fn getc(&mut self) -> Result<Option<u8>, Errno> {
fn getc(&mut self) -> EResult<Option<u8>> {
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<Option<u8>, Errno> {
pub fn peek(&mut self) -> EResult<Option<u8>> {
if self.buffer.is_none() {
self.buffer = self.getc()?;
}
Ok(self.buffer)
EResult::Ok(self.buffer)
}
pub fn next(&mut self) -> Result<Option<u8>, Errno> {
pub fn next(&mut self) -> EResult<Option<u8>> {
match self.buffer.take() {
Some(v) => Ok(Some(v)),
Some(v) => EResult::Ok(Some(v)),
None => self.getc(),
}
}

View File

@ -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)
}

View File

@ -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<c_void> {
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<c_void> {
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<c_void> {
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());
}

View File

@ -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;

View File

@ -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<c_char> {
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]

View File

@ -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<c_char> {
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 {

View File

@ -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)
}

View File

@ -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<ExitCode, Errno> {
use super::sys_types::pid_t;
fn waitpid_inner(pid: u32) -> EResult<ExitCode> {
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)
}

View File

@ -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]

View File

@ -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<SeekFrom> {
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!()
}

View File

@ -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<pid_t, Errno> {
let result = EResult::from(syscall::fork())?;
Ok(result as _)
unsafe fn fork_inner() -> EResult<u32> {
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<P: AsRef<Path>>(
pathname: P,
argv: &[&str],
envp: &[&str],
) -> Result<(), Errno> {
unsafe fn execve_inner<P: AsRef<Path>>(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()
}

View File

@ -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<R: Read + ?Sized>(&mut self, source: &mut R) -> Result<&[u8], Errno> {
pub fn fill_from<R: Read + ?Sized>(&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<W: Write> LineWriter<W> {
}
impl<W: Write> Write for UnbufferedWriter<W> {
fn write(&mut self, data: &[u8]) -> Result<usize, Errno> {
fn write(&mut self, data: &[u8]) -> EResult<usize> {
self.inner.write(data)
}
fn flush(&mut self) -> Result<(), Errno> {
Ok(())
fn flush(&mut self) -> EResult<()> {
EResult::Ok(())
}
}
impl<W: Write> Write for BufWriter<W> {
fn write(&mut self, mut data: &[u8]) -> Result<usize, Errno> {
fn write(&mut self, mut data: &[u8]) -> EResult<usize> {
if data.len() + self.buffer.len() >= self.buffer.capacity() {
self.flush()?;
}
@ -169,10 +169,10 @@ impl<W: Write> Write for BufWriter<W> {
// 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<W: Write> Write for BufWriter<W> {
}
impl<W: Write> Write for LineWriter<W> {
fn write(&mut self, data: &[u8]) -> Result<usize, Errno> {
fn write(&mut self, data: &[u8]) -> EResult<usize> {
if self.need_flush {
self.flush()?;
}
@ -195,20 +195,20 @@ impl<W: Write> Write for LineWriter<W> {
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(())
}
}

View File

@ -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<P: AsRef<Path>>(at: Option<RawFd>, path: P) -> Result<Self, Errno> {
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<P: AsRef<Path>>(at: Option<RawFd>, path: P) -> EResult<Self> {
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<Option<DirectoryEntry>, Errno> {
pub fn read_entry(&mut self) -> EResult<Option<DirectoryEntry>> {
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,
}
}
}

View File

@ -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<usize, Errno>;
fn flush(&mut self) -> Result<(), Errno>;
fn write(&mut self, data: &[u8]) -> EResult<usize>;
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<usize, Errno>;
fn read(&mut self, data: &mut [u8]) -> EResult<usize>;
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<u64, Errno>;
fn seek(&mut self, off: SeekFrom) -> EResult<u64>;
fn stream_position(&mut self) -> Result<u64, Errno> {
fn stream_position(&mut self) -> EResult<u64> {
self.seek(SeekFrom::Current(0))
}
}
@ -76,21 +84,13 @@ pub trait IntoRawFd {
fn into_raw_fd(self) -> RawFd;
}
pub fn get_metadata<P: AsRef<Path>>(
at: Option<RawFd>,
path: P,
follow: bool,
) -> Result<FileAttr, Errno> {
pub fn get_metadata<P: AsRef<Path>>(at: Option<RawFd>, path: P, follow: bool) -> EResult<FileAttr> {
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<P: AsRef<Path>>(
at: Option<RawFd>,
path: P,
mode: FileMode,
) -> Result<(), Errno> {
EResult::from(unsafe { syscall::create_directory(at, path.as_ref().as_str(), mode) })?;
Ok(())
pub fn create_directory<P: AsRef<Path>>(at: Option<RawFd>, path: P, mode: FileMode) -> EResult<()> {
unsafe { syscall::create_directory(at, path.as_ref().as_str(), mode) }?;
EResult::Ok(())
}

View File

@ -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]

View File

@ -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<FileAttr, Errno>;
fn metadata(&self) -> EResult<FileAttr>;
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<FileAttr, Errno> {
fn metadata(&self) -> EResult<FileAttr> {
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)
}
}

View File

@ -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<extern "C" fn()>; 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<T: ToExitCode>(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(())
}

View File

@ -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_handler_t>) -> 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() {

View File

@ -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<T> NonNullExt for NonNull<T> {
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<P: AsRef<Path>>(name: P) -> EResult<PathBuf> {
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<P: AsRef<Path>>(name: P) -> EResult<PathBuf> {
}
}
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<Option<RawFd>> {
match fd {
AT_FDCWD => EResult::Ok(None),
0.. => EResult::Ok(Some(RawFd(fd.try_into().unwrap()))),
_ => EResult::Err(EBADF),
}
}