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, 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 { fn include_dir(d: &DirEntry) -> bool {
d.metadata().map(|m| m.is_dir()).unwrap_or(false) d.metadata().map(|m| m.is_dir()).unwrap_or(false)
&& d.path() && d.path()
@ -26,7 +37,12 @@ fn generate_header<P: AsRef<Path>>(config_path: P) {
.with_extension("h"); .with_extension("h");
let mod_path = config_path.with_file_name("mod.rs"); 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() cbindgen::Builder::new()
.with_config(config) .with_config(config)

View File

@ -1,4 +1,81 @@
use core::{
alloc::{GlobalAlloc, Layout},
intrinsics,
ptr::NonNull,
};
use libyalloc::global::GlobalAllocator; use libyalloc::global::GlobalAllocator;
use yggdrasil_rt::memcpy;
use crate::{error::EResult, header::errno::ENOMEM, util::NonNullExt};
#[global_allocator] #[global_allocator]
pub static GLOBAL_ALLOCATOR: GlobalAllocator = GlobalAllocator; 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, convert::Infallible,
ffi::c_int, ffi::c_int,
ops::{ControlFlow, FromResidual, Try}, ops::{ControlFlow, FromResidual, Try},
ptr::{null_mut, NonNull},
}; };
use crate::header::{errno::Errno, stdio::EOF}; use yggdrasil_rt::io::RawFd;
pub trait CZeroResult { use crate::header::{
fn into_zero_status(self) -> c_int; errno::{Errno, EBADF},
fn into_eof_status(self) -> c_int; 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 { impl CIsizeResult {
fn into_size_status(self) -> usize; pub const ERR: Self = Self(-1);
pub fn success(value: usize) -> Self {
Self(value.try_into().unwrap())
}
} }
pub trait TryFromExt<T>: Sized { impl FromResidual<EResult<Infallible>> for CIsizeResult {
fn e_try_from(value: T) -> EResult<Self>; fn from_residual(residual: EResult<Infallible>) -> Self {
let err = residual.unwrap_err();
unsafe {
errno = err;
}
Self(-1)
}
} }
pub trait OptionExt<T> { impl FromResidual<EResult<Infallible>> for CIntCountResult {
fn e_ok_or(self, err: yggdrasil_rt::Error) -> EResult<T>; fn from_residual(residual: EResult<Infallible>) -> Self {
let err = residual.unwrap_err();
unsafe {
errno = err;
}
Self(-1)
}
} }
// TODO thread_local impl CIntZeroResult {
#[no_mangle] pub const ERR: Self = Self(-1);
pub static mut errno: Errno = Errno(0); pub const OK: Self = Self(0);
pub enum EResult<T> {
Ok(T),
Err(yggdrasil_rt::Error),
Errno(Errno),
} }
impl<T> From<Result<T, yggdrasil_rt::Error>> for EResult<T> { impl FromResidual<EResult<Infallible>> for CIntZeroResult {
fn from(value: Result<T, yggdrasil_rt::Error>) -> Self { fn from_residual(residual: EResult<Infallible>) -> Self {
match value { let err = residual.unwrap_err();
Ok(value) => Self::Ok(value), unsafe {
Err(error) => Self::Err(error), 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> { 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 { match self {
Self::Ok(value) => Self::Ok(value), Self::Ok(value) => Some(value),
Self::Errno(e) => Self::Errno(e), 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) => { Self::Err(err) => {
let e = Errno::from(err); if set_errno {
unsafe { unsafe {
errno = e; 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> { impl<T> Try for EResult<T> {
type Output = T; type Output = T;
type Residual = Result<Infallible, Errno>; type Residual = EResult<Infallible>;
fn branch(self) -> ControlFlow<Self::Residual, Self::Output> { fn branch(self) -> ControlFlow<Self::Residual, Self::Output> {
match self.into_set_errno() { match self {
Self::Ok(value) => ControlFlow::Continue(value), Self::Ok(value) => ControlFlow::Continue(value),
Self::Errno(e) => ControlFlow::Break(Err(e)), Self::Err(err) => ControlFlow::Break(EResult::Err(err)),
Self::Err(_error) => unreachable!(),
} }
} }
fn from_output(_output: Self::Output) -> Self { fn from_output(output: Self::Output) -> Self {
todo!() 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> { 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 { match self {
Some(value) => EResult::Ok(value), Some(val) => EResult::Ok(val),
None => EResult::Err(err), 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) { impl TryFromExt<c_int> for RawFd {
unsafe { fn e_try_from(value: c_int) -> EResult<Self> {
errno = e; 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::{ use crate::{
error::{self, EResult}, error::{EResult, TryFromExt},
header::errno::{Errno, EBADF},
io::{AsRawFd, AsRawFdOpt, FromRawFd, IntoRawFd, Read, Seek, Write}, io::{AsRawFd, AsRawFdOpt, FromRawFd, IntoRawFd, Read, Seek, Write},
}; };
@ -36,42 +35,41 @@ impl RawFile {
pathname: P, pathname: P,
opts: OpenOptions, opts: OpenOptions,
mode: FileMode, mode: FileMode,
) -> Result<Self, Errno> { ) -> EResult<Self> {
let fd = let fd = unsafe { syscall::open(at, pathname.as_ref().as_str(), opts, mode) }?;
EResult::from(unsafe { syscall::open(at, pathname.as_ref().as_str(), opts, mode) })?; EResult::Ok(Self { fd })
Ok(Self { fd })
} }
pub unsafe fn close(self: &mut Self) -> Result<(), Errno> { pub unsafe fn close(self: &mut Self) -> EResult<()> {
EResult::from(unsafe { syscall::close(self.fd) })?; unsafe { syscall::close(self.fd) }?;
self.fd = RawFd::NONE; self.fd = RawFd::NONE;
Ok(()) EResult::Ok(())
} }
} }
impl Write for RawFile { impl Write for RawFile {
fn write(&mut self, data: &[u8]) -> Result<usize, Errno> { fn write(&mut self, data: &[u8]) -> EResult<usize> {
let count = EResult::from(unsafe { syscall::write(self.fd, data) })?; let count = unsafe { syscall::write(self.fd, data) }?;
Ok(count) EResult::Ok(count)
} }
fn flush(&mut self) -> Result<(), Errno> { fn flush(&mut self) -> EResult<()> {
// TODO fsync // TODO fsync
Ok(()) EResult::Ok(())
} }
} }
impl Read for RawFile { impl Read for RawFile {
fn read(&mut self, data: &mut [u8]) -> Result<usize, Errno> { fn read(&mut self, data: &mut [u8]) -> EResult<usize> {
let count = EResult::from(unsafe { syscall::read(self.fd, data) })?; let count = unsafe { syscall::read(self.fd, data) }?;
Ok(count) EResult::Ok(count)
} }
} }
impl Seek for RawFile { impl Seek for RawFile {
fn seek(&mut self, off: SeekFrom) -> Result<u64, Errno> { fn seek(&mut self, off: SeekFrom) -> EResult<u64> {
let pos = EResult::from(unsafe { syscall::seek(self.fd, off) })?; let pos = unsafe { syscall::seek(self.fd, off) }?;
Ok(pos) EResult::Ok(pos)
} }
} }
@ -93,17 +91,10 @@ impl IntoRawFd for RawFile {
} }
} }
impl TryFrom<c_int> for RawFile { impl TryFromExt<c_int> for RawFile {
type Error = Errno; fn e_try_from(value: c_int) -> EResult<Self> {
let fd = RawFd::e_try_from(value)?;
fn try_from(value: c_int) -> Result<Self, Self::Error> { EResult::Ok(unsafe { Self::from_raw_fd(fd) })
if value >= 0 {
Ok(Self {
fd: RawFd(value as _),
})
} else {
error::set_errno_result(EBADF)
}
} }
} }
@ -115,15 +106,15 @@ impl ManagedFile {
pathname: P, pathname: P,
opts: OpenOptions, opts: OpenOptions,
mode: FileMode, mode: FileMode,
) -> Result<Self, Errno> { ) -> EResult<Self> {
let inner = RawFile::open_at(at, pathname, opts, mode)?; let inner = RawFile::open_at(at, pathname, opts, mode)?;
Ok(Self { EResult::Ok(Self {
inner, inner,
reference: false, reference: false,
}) })
} }
pub unsafe fn close(self: &mut Self) -> Result<(), Errno> { pub unsafe fn close(self: &mut Self) -> EResult<()> {
if self.reference { if self.reference {
unreachable!("Cannot close a reference ManagedFile"); 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 { match self {
Self::File(file) => ManagedFile::close(file), Self::File(file) => ManagedFile::close(file),
} }
@ -199,13 +190,13 @@ impl AsRawFdOpt for FileBacking {
} }
impl Write 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 { match self {
Self::File(file) => file.write(data), Self::File(file) => file.write(data),
} }
} }
fn flush(&mut self) -> Result<(), Errno> { fn flush(&mut self) -> EResult<()> {
match self { match self {
Self::File(file) => file.flush(), Self::File(file) => file.flush(),
} }
@ -213,7 +204,7 @@ impl Write for FileBacking {
} }
impl Read 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 { match self {
Self::File(file) => file.read(data), Self::File(file) => file.read(data),
} }
@ -221,7 +212,7 @@ impl Read for FileBacking {
} }
impl Seek 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 { match self {
Self::File(file) => file.seek(off), Self::File(file) => file.seek(off),
} }

View File

@ -1,15 +1,19 @@
use core::{ use core::{
ffi::{c_char, c_int, c_long, CStr}, ffi::{c_char, c_int, c_long, CStr},
mem::MaybeUninit, mem::MaybeUninit,
ptr::null_mut, ptr::NonNull,
}; };
use alloc::boxed::Box; use alloc::boxed::Box;
use yggdrasil_rt::io::{DirectoryEntry, RawFd}; 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)] #[derive(Debug)]
#[repr(C)] #[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_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; 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 { impl From<DirectoryEntry> for dirent {
fn from(value: DirectoryEntry) -> Self { fn from(value: DirectoryEntry) -> Self {
let mut d_name = [0; 256]; let mut d_name = [0; 256];
@ -52,49 +76,34 @@ impl From<DirectoryEntry> for dirent {
// Primary stuff // Primary stuff
#[no_mangle] #[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(); pathname.ensure();
let pathname = CStr::from_ptr(pathname).to_str().unwrap(); let pathname = CStr::from_ptr(pathname).to_str().unwrap();
let reader = DirReader::open_at(None, pathname)?;
match DirReader::open_at(None, pathname) { let dir = NonNull::from(Box::leak(Box::new(DIR {
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 {
reader, reader,
buffer: MaybeUninit::uninit(), buffer: MaybeUninit::uninit(),
})) })));
CPtrResult::success(dir)
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn closedir(dir: *mut DIR) -> c_int { unsafe extern "C" fn fdopendir(fd: c_int) -> CPtrResult<DIR> {
let result = { let fd = RawFd::e_try_from(fd)?;
let dir = dir.as_mut().unwrap(); 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() { #[no_mangle]
Ok(_) => 0, unsafe extern "C" fn closedir(dir: *mut DIR) -> CIntZeroResult {
Err(_) => -1, let dir = NonNull::new(dir).unwrap();
} DIR::close(dir)?;
}; CIntZeroResult::OK
drop(Box::from_raw(dir));
result
} }
#[no_mangle] #[no_mangle]
@ -105,16 +114,10 @@ unsafe extern "C" fn dirfd(dir: *mut DIR) -> c_int {
} }
#[no_mangle] #[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(); let dir = dir.as_mut().unwrap();
let dirent = dir.read_entry()?;
match dir.reader.read_entry() { CPtrResult::success(dirent)
Ok(Some(entry)) => {
dir.buffer.write(dirent::from(entry));
dir.buffer.as_mut_ptr()
}
Ok(None) | Err(_) => null_mut(),
}
} }
// Deprecated // 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 yggdrasil_rt::io::{FileMode, OpenOptions};
use crate::{error, file::RawFile, header::errno::EINVAL, io::IntoRawFd, util::Nullable}; use crate::{
error::{CFdResult, CIntCountResult, EResult, TryFromExt},
use super::{ file::RawFile,
errno::Errno, header::errno::EINVAL,
sys_types::{mode_t, off_t, pid_t}, io::IntoRawFd,
util::{self, Nullable},
}; };
use super::sys_types::{mode_t, off_t, pid_t};
/* /*
TODO: TODO:
int posix_fadvise(int, off_t, off_t, int); int posix_fadvise(int, off_t, off_t, int);
@ -75,13 +78,13 @@ enum OpenMode {
Directory, 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 {
if opts & !O_DIRECTORY != 0 { if opts & !O_DIRECTORY != 0 {
todo!(); todo!();
} }
return Ok(OpenMode::Directory); return EResult::Ok(OpenMode::Directory);
} }
let need_mode = opts & O_CREAT != 0; 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_EXEC => todo!(),
O_SEARCH => 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() FileMode::empty()
}; };
Ok(OpenMode::File(res, mode)) EResult::Ok(OpenMode::File(res, mode))
} }
#[no_mangle] #[no_mangle]
@ -133,41 +136,38 @@ unsafe extern "C" fn creat(pathname: *const c_char, mode: mode_t) -> c_int {
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn fcntl(fd: c_int, cmd: c_int, args: ...) -> c_int { unsafe extern "C" fn fcntl(fd: c_int, cmd: c_int, args: ...) -> CIntCountResult {
let Ok(file) = RawFile::try_from(fd) else { let file = RawFile::e_try_from(fd)?;
return -1;
};
match cmd { match cmd {
F_GETFD => 0,
F_SETFD => 0,
_ => todo!("fcntl({}, {}, ...)", fd, cmd), _ => todo!("fcntl({}, {}, ...)", fd, cmd),
} }
} }
#[no_mangle] unsafe fn vopenat(atfd: c_int, pathname: *const c_char, opts: c_int, mut ap: VaList) -> CFdResult {
unsafe extern "C" fn open(pathname: *const c_char, opts: c_int, mut args: ...) -> c_int { let atfd = util::at_fd(atfd)?;
pathname.ensure(); pathname.ensure();
let pathname = CStr::from_ptr(pathname).to_str().unwrap(); let pathname = CStr::from_ptr(pathname).to_str().unwrap();
let mut args = args.as_va_list();
let result = match open_opts(opts, &mut args) { let fd = match open_opts(opts, &mut ap)? {
Ok(OpenMode::File(opts, mode)) => { OpenMode::File(opts, mode) => RawFile::open_at(atfd, pathname, opts, mode)?.into_raw_fd(),
RawFile::open_at(None, pathname, opts, mode).map(RawFile::into_raw_fd) OpenMode::Directory => todo!(),
}
Ok(OpenMode::Directory) => {
todo!();
}
Err(_) => return -1,
}; };
match result { CFdResult::success(fd)
Ok(fd) => fd.0.try_into().unwrap(),
Err(_) => -1,
}
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn openat(atfd: c_int, pathname: *const c_char, opts: c_int, ...) -> c_int { unsafe extern "C" fn open(pathname: *const c_char, opts: c_int, mut args: ...) -> CFdResult {
todo!() 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::{ use core::{
ffi::{c_char, c_int, c_long, c_void, CStr}, ffi::{c_char, c_int, c_long, c_void, CStr},
ptr::null_mut, ptr::{null_mut, NonNull},
}; };
use alloc::boxed::Box; use alloc::boxed::Box;
@ -10,11 +10,11 @@ use yggdrasil_rt::{
}; };
use crate::{ use crate::{
error::{self, CSizeResult, CZeroResult}, error::{
header::{ CEofResult, CFdResult, CIntZeroResult, COffsetResult, CPtrResult, CUsizeResult, EResult,
errno::{Errno, EBADF}, OptionExt,
sys_types::off_t,
}, },
header::{errno::EBADF, sys_types::off_t},
io::{AsRawFdOpt, Read, Seek, Write}, 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, 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 { let opts = match mode_str {
b"r" | b"rb" => OpenOptions::READ, b"r" | b"rb" => OpenOptions::READ,
b"r+" | b"rb+" => OpenOptions::READ | OpenOptions::WRITE, 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!(), _ => todo!(),
}; };
match source.open_with(opts) { let file = source.open_with(opts)?;
Ok(file) => { let file = NonNull::from(Box::leak(Box::new(file)));
let file = Box::into_raw(Box::new(file)); unsafe {
unsafe { super::register_file(file);
super::register_file(file);
}
Ok(file)
}
Err(err) => Err(err),
} }
EResult::Ok(file)
} }
#[no_mangle] #[no_mangle]
@ -58,7 +54,7 @@ pub unsafe extern "C" fn ctermid(buffer: *mut c_char) -> *mut c_char {
} }
#[no_mangle] #[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() { if pathname.is_null() || mode.is_null() {
panic!(); 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 pathname = pathname.to_str().unwrap();
let mode = CStr::from_ptr(mode); let mode = CStr::from_ptr(mode);
let res = open_inner(Path::from_str(pathname), mode.to_bytes()).unwrap_or(null_mut()); let file = open_inner(Path::from_str(pathname), mode.to_bytes())?;
yggdrasil_rt::debug_trace!("fopen({:?}, {:?}) -> {:p}", pathname, mode, res);
res CPtrResult::success(file)
} }
#[no_mangle] #[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() { if fd < 0 || mode.is_null() {
panic!(); panic!();
} }
let mode = CStr::from_ptr(mode); 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] #[no_mangle]
@ -109,28 +107,22 @@ pub unsafe extern "C" fn clearerr(stream: *mut FILE) {
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn fclose(stream: *mut FILE) -> c_int { pub unsafe extern "C" fn fclose(stream: *mut FILE) -> CEofResult {
if stream.is_null() { let stream = NonNull::new(stream).unwrap();
panic!();
}
if !super::deregister_file(stream) { if !super::deregister_file(stream) {
yggdrasil_rt::debug_trace!("fclose() non-registered file: {:p}", stream); yggdrasil_rt::debug_trace!("fclose() non-registered file: {:p}", stream);
} }
stream.close().into_eof_status() FILE::close(stream)?;
CEofResult(0)
} }
#[no_mangle] #[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(); let stream = stream.as_mut().unwrap();
match stream.as_raw_fd_opt() { let fd = stream.as_raw_fd_opt().e_ok_or(EBADF)?;
Some(RawFd(fd)) => fd as _, CFdResult::success(fd)
None => {
error::set_errno(EBADF);
-1
}
}
} }
#[no_mangle] #[no_mangle]
@ -139,14 +131,15 @@ pub unsafe extern "C" fn fwrite(
size: usize, size: usize,
nmemb: usize, nmemb: usize,
stream: *mut FILE, stream: *mut FILE,
) -> usize { ) -> CUsizeResult {
if ptr.is_null() { if ptr.is_null() {
panic!(); panic!();
} }
let stream = stream.as_mut().unwrap(); let stream = stream.as_mut().unwrap();
let data = core::slice::from_raw_parts(ptr as *const u8, size * nmemb); 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] #[no_mangle]
@ -155,32 +148,35 @@ pub unsafe extern "C" fn fread(
size: usize, size: usize,
nmemb: usize, nmemb: usize,
stream: *mut FILE, stream: *mut FILE,
) -> usize { ) -> CUsizeResult {
if ptr.is_null() { if ptr.is_null() {
panic!(); panic!();
} }
let stream = stream.as_mut().unwrap(); let stream = stream.as_mut().unwrap();
let data = core::slice::from_raw_parts_mut(ptr as *mut u8, size * nmemb); 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] #[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() { if let Some(stream) = stream.as_mut() {
stream.flush().into_eof_status() stream.flush()?;
} else { } else {
super::fflush_all().into_eof_status() super::fflush_all()?;
} }
CEofResult(0)
} }
#[no_mangle] #[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) fseeko(stream, offset.try_into().unwrap(), whence)
} }
#[no_mangle] #[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 stream = stream.as_mut().unwrap();
let off = match whence { let off = match whence {
SEEK_SET => SeekFrom::Start(offset.try_into().unwrap()), 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!(), _ => todo!(),
}; };
match stream.seek(off) { stream.seek(off)?;
Ok(_) => 0,
Err(_) => -1, CIntZeroResult::OK
}
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn ftell(stream: *mut FILE) -> c_long { 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] #[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(); let stream = stream.as_mut().unwrap();
match stream.stream_position() { let pos = stream.stream_position()?;
Ok(p) => p.try_into().unwrap(), COffsetResult::success(pos)
Err(_) => -1,
}
} }
#[no_mangle] #[no_mangle]
@ -216,26 +212,20 @@ pub unsafe extern "C" fn rewind(stream: *mut FILE) {
} }
#[no_mangle] #[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 stream = stream.as_mut().unwrap();
let pos = pos.as_mut().unwrap(); let dst = pos.as_mut().unwrap();
match stream.stream_position() { let pos = stream.stream_position()?;
Ok(p) => { *dst = pos;
*pos = p; CIntZeroResult::OK
0
}
Err(_) => -1,
}
} }
#[no_mangle] #[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 stream = stream.as_mut().unwrap();
let pos = pos.as_ref().unwrap(); let pos = pos.as_ref().unwrap();
match stream.seek(SeekFrom::Start(*pos as _)) { stream.seek(SeekFrom::Start(*pos))?;
Ok(_) => 0, CIntZeroResult::OK
Err(_) => -1,
}
} }
#[no_mangle] #[no_mangle]
@ -244,9 +234,10 @@ pub unsafe extern "C" fn setvbuf(
buf: *mut c_char, buf: *mut c_char,
mode: c_int, mode: c_int,
size: usize, size: usize,
) -> c_int { ) -> CIntZeroResult {
let stream = stream.as_mut().unwrap(); let stream = stream.as_mut().unwrap();
stream.setvbuf(mode, buf, size).into_eof_status() stream.setvbuf(mode, buf, size)?;
CIntZeroResult::OK
} }
#[no_mangle] #[no_mangle]
@ -266,17 +257,24 @@ pub unsafe extern "C" fn setlinebuf(stream: *mut FILE) {
} }
#[no_mangle] #[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!() todo!()
} }
#[no_mangle] #[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!() todo!()
} }
#[no_mangle] #[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!() todo!()
} }

View File

@ -1,18 +1,20 @@
use core::{ use core::{
ffi::{c_char, c_int, CStr}, ffi::{c_char, c_int, CStr},
ptr::null_mut, ptr::{null_mut, NonNull},
}; };
use crate::{ use crate::{
error, allocator,
header::stdlib::realloc, error::{self, CEofResult, CIsizeResult, CPtrResult, EResult},
header::errno::ESUCCESS,
io::{Read, Write}, io::{Read, Write},
util::NonNullExt,
}; };
use super::{ use super::{
stderr, stdin, stdout, stderr, stdin, stdout,
unlocked::{flockfile, fputc_unlocked, fputs_unlocked, funlockfile}, unlocked::{flockfile, fputc_unlocked, fputs_unlocked, funlockfile},
EOF, FILE, FILE,
}; };
#[no_mangle] #[no_mangle]
@ -34,101 +36,91 @@ unsafe extern "C" fn perror(msg: *const c_char) {
// Chars // Chars
#[no_mangle] #[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 stream = stream.as_mut().unwrap();
let c = c as u8; let c = c as u8;
match stream.write(&[c]) { stream.write_all(&[c])?;
Ok(_) => c as c_int,
Err(_) => EOF, CEofResult(c as c_int)
}
} }
#[no_mangle] #[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) fputc(c, stream)
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn putchar(c: c_int) -> c_int { unsafe extern "C" fn putchar(c: c_int) -> CEofResult {
fputc(c, stdout) fputc(c, stdout)
} }
// Strings // Strings
#[no_mangle] #[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); let r = fputs(s, stdout);
if r < 0 { if r.0 < 0 {
return r; return r;
} }
fputc(b'\n' as _, stdout) fputc(b'\n' as _, stdout)
} }
#[no_mangle] #[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(); let stream = stream.as_mut().unwrap();
if s.is_null() { if s.is_null() {
panic!(); panic!();
} }
let s = CStr::from_ptr(s); let s = CStr::from_ptr(s);
stream.write_all(s.to_bytes())?;
match stream.write(s.to_bytes()) { CEofResult(0)
Ok(_) => 0,
Err(_) => EOF,
}
} }
#[no_mangle] #[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 stream = stream.as_mut().unwrap();
let mut buf = [0]; let mut buf = [0];
match stream.read(&mut buf) { stream.read_exact(&mut buf)?;
Ok(1) => buf[0] as c_int, CEofResult(buf[0] as _)
Ok(_) => EOF,
Err(_) => EOF,
}
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn getc(stream: *mut FILE) -> c_int { unsafe extern "C" fn getc(stream: *mut FILE) -> CEofResult {
fgetc(stream) fgetc(stream)
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn getchar() -> c_int { unsafe extern "C" fn getchar() -> CEofResult {
fgetc(stdin) fgetc(stdin)
} }
#[no_mangle] #[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 stream = stream.as_mut().unwrap();
let mut s = NonNull::new(s).unwrap();
if size <= 0 { if size <= 0 {
return null_mut(); return CPtrResult::ERR;
} }
// Nothing to read // Nothing to read
if size == 1 { if size == 1 {
*s = 0; *s.as_mut() = 0;
return s; return CPtrResult::success(s);
} }
let size = size as usize; let size = size as usize;
let mut pos = 0; let mut pos = 0;
let mut buf = [0]; let mut buf = [0];
let slice = NonNull::slice_from_raw_parts(s, size).as_mut();
while pos < size - 1 { while pos < size - 1 {
let ch = match stream.read(&mut buf) { let ch = match stream.read(&mut buf)? {
Ok(1) => buf[0], 1 => buf[0],
Ok(_) => { _ => break,
break;
}
Err(err) => {
return null_mut();
}
}; };
*s.add(pos) = ch as _; slice[pos] = ch as _;
pos += 1; pos += 1;
if ch == b'\n' { 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 { if pos == 0 {
null_mut() CPtrResult::ERR
} else { } else {
*s.add(pos) = 0; slice[pos] = 0;
s CPtrResult::success(s)
} }
} }
#[no_mangle] #[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(); let stream = stream.as_mut().unwrap();
if stream.ungetc(c as _) { stream.ungetc(c as _)?;
c CEofResult(c)
} else {
EOF
}
} }
// Line // Line
struct MallocBufferWriter { struct MallocBufferWriter {
buffer: *mut c_char, buffer: Option<NonNull<c_char>>,
position: usize,
capacity: usize, capacity: usize,
position: usize,
} }
impl MallocBufferWriter { 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 { if self.position == self.capacity {
// Extend the buffer
self.capacity = (self.capacity + 64) & !63; self.capacity = (self.capacity + 64) & !63;
self.buffer = unsafe { realloc(self.buffer as _, self.capacity) as _ }; self.buffer = Some(
if self.buffer.is_null() { unsafe { allocator::c_reallocate(self.buffer.map(NonNull::cast), self.capacity) }?
// ENOMEM is set .cast(),
return false; );
}
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 { if ch == delim {
*self.buffer.add(self.position) = ch as _; 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] #[no_mangle]
@ -188,52 +232,32 @@ unsafe extern "C" fn getdelim(
n: *mut usize, n: *mut usize,
delim: c_int, delim: c_int,
stream: *mut FILE, stream: *mut FILE,
) -> isize { ) -> CIsizeResult {
let lineptr = lineptr.as_mut().unwrap(); let lineptr = lineptr.as_mut().unwrap();
let buffer = NonNull::new(*lineptr);
let n = n.as_mut().unwrap(); let n = n.as_mut().unwrap();
let mut capacity = *n; let stream = stream.as_mut().unwrap();
if lineptr.is_null() { let (writer, result) = getdelim_inner(buffer, *n, delim, stream);
capacity = 0;
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; *n = writer.capacity;
// Minus the '\0' result?;
(writer.position - 1).try_into().unwrap() assert_ne!(writer.position, 0);
CIsizeResult::success(writer.position - 1)
} }
#[no_mangle] #[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) getdelim(lineptr, n, b'\n' as _, stream)
} }

View File

@ -1,6 +1,7 @@
use core::{ use core::{
ffi::{c_char, c_int}, ffi::{c_char, c_int},
fmt, ptr, fmt,
ptr::{self, NonNull},
}; };
use alloc::{boxed::Box, collections::BTreeSet, vec::Vec}; use alloc::{boxed::Box, collections::BTreeSet, vec::Vec};
@ -20,7 +21,7 @@ use crate::{
sync::{Mutex, RawMutex}, sync::{Mutex, RawMutex},
}; };
use super::errno::Errno; use super::errno::{EINVAL, ENOMEM, ESUCCESS};
// TODO: // TODO:
// L_ctermid // L_ctermid
@ -42,7 +43,7 @@ mod scanf;
mod unlocked; mod unlocked;
pub trait FileOpenSource { pub trait FileOpenSource {
fn open_with(self, opts: OpenOptions) -> Result<FILE, Errno>; fn open_with(self, opts: OpenOptions) -> EResult<FILE>;
} }
pub enum BufferingMode { pub enum BufferingMode {
@ -126,16 +127,16 @@ impl FILE {
Self::from_backing(inner, flags, buffering) 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? // TODO lock needed?
let r = self.as_mut().unwrap(); let file = ptr.as_mut();
r.flush()?; file.flush()?;
if r.flags.contains(FileFlags::BUILTIN) { if file.flags.contains(FileFlags::BUILTIN) {
todo!() todo!()
} else { } else {
// Drop the file // Drop the file
let mut this = Box::from_raw(self); let mut this = Box::from_raw(file);
let result = FileBacking::close(&mut this.inner); let result = FileBacking::close(&mut this.inner);
drop(this); drop(this);
result result
@ -162,41 +163,36 @@ impl FILE {
self.flags.contains(flag) self.flags.contains(flag)
} }
pub fn setvbuf( pub fn setvbuf(&mut self, mode: c_int, buffer: *mut c_char, capacity: usize) -> EResult<()> {
&mut self,
mode: c_int,
buffer: *mut c_char,
capacity: usize,
) -> Result<(), Errno> {
locked_op!(self, self.setvbuf_unlocked(mode, buffer, capacity)) 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)?; self.set_direction(Direction::Write)?;
match self.output.write(data) { match self.output.write(data) {
Ok(amount) => Ok(amount), EResult::Ok(amount) => EResult::Ok(amount),
Err(err) => { EResult::Err(err) => {
self.flags |= FileFlags::ERROR; 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() { match self.output.flush() {
Ok(()) => { EResult::Ok(()) => {
self.last_operation = None; self.last_operation = None;
Ok(()) EResult::Ok(())
} }
Err(err) => { EResult::Err(err) => {
self.flags |= FileFlags::ERROR; 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)?; self.set_direction(Direction::Read)?;
if !self.ungetc.is_empty() { if !self.ungetc.is_empty() {
@ -204,7 +200,7 @@ impl FILE {
let amount = core::cmp::min(self.ungetc.len(), data.len()); let amount = core::cmp::min(self.ungetc.len(), data.len());
data[..amount].copy_from_slice(&self.ungetc[..amount]); data[..amount].copy_from_slice(&self.ungetc[..amount]);
self.ungetc.drain(..amount); self.ungetc.drain(..amount);
return Ok(amount); return EResult::Ok(amount);
} }
if self.read_buffer.is_some() { if self.read_buffer.is_some() {
@ -212,23 +208,23 @@ impl FILE {
let len = core::cmp::min(data.len(), buf.len()); let len = core::cmp::min(data.len(), buf.len());
data[..len].copy_from_slice(&buf[..len]); data[..len].copy_from_slice(&buf[..len]);
self.consume(len); self.consume(len);
Ok(len) EResult::Ok(len)
} else { } else {
match self.inner.read(data) { match self.inner.read(data) {
Ok(0) => { EResult::Ok(0) => {
self.flags |= FileFlags::EOF; self.flags |= FileFlags::EOF;
Ok(0) EResult::Ok(0)
} }
Ok(n) => Ok(n), EResult::Ok(n) => EResult::Ok(n),
Err(err) => { EResult::Err(err) => {
self.flags |= FileFlags::ERROR; 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)) locked_op!(self, self.ungetc_unlocked(ch))
} }
@ -236,8 +232,11 @@ impl FILE {
self.lock.lock(); self.lock.lock();
} }
pub fn try_lock(&mut self) -> bool { pub fn try_lock(&mut self) -> EResult<()> {
self.lock.try_lock() match self.lock.try_lock() {
true => EResult::Ok(()),
false => EResult::Err(ESUCCESS),
}
} }
pub unsafe fn unlock(&mut self) { pub unsafe fn unlock(&mut self) {
@ -259,7 +258,7 @@ impl FILE {
mode: c_int, mode: c_int,
buffer: *mut c_char, buffer: *mut c_char,
capacity: usize, capacity: usize,
) -> Result<(), Errno> { ) -> EResult<()> {
let mode = BufferingMode::e_try_from(mode)?; let mode = BufferingMode::e_try_from(mode)?;
if self.last_operation.is_some() { 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.flush_unlocked()?;
self.ungetc.clear(); self.ungetc.clear();
match self.inner.seek(off) { match self.inner.seek(off) {
Ok(pos) => { EResult::Ok(pos) => {
self.flags &= !FileFlags::EOF; self.flags &= !FileFlags::EOF;
Ok(pos) EResult::Ok(pos)
} }
Err(err) => { EResult::Err(err) => {
self.flags |= FileFlags::ERROR; 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) { match self.last_operation.replace(direction) {
Some(dir) if dir != direction => { Some(dir) if dir != direction => {
self.flags |= FileFlags::ERROR; self.flags |= FileFlags::ERROR;
todo!() 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 // ungetc() for write doesn't make any sense
if self.set_direction(Direction::Read).is_err() { self.set_direction(Direction::Read)?;
return false;
}
if self.ungetc.len() == UNGETC_MAX { if self.ungetc.len() == UNGETC_MAX {
return false; return EResult::Err(ENOMEM);
} }
self.ungetc.push(ch); self.ungetc.push(ch);
true EResult::Ok(())
} }
} }
impl fmt::Write for FILE { impl fmt::Write for FILE {
fn write_str(&mut self, s: &str) -> fmt::Result { 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 { 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)) locked_op!(self, self.write_unlocked(data))
} }
fn flush(&mut self) -> Result<(), Errno> { fn flush(&mut self) -> EResult<()> {
locked_op!(self, self.flush_unlocked()) locked_op!(self, self.flush_unlocked())
} }
} }
impl Read for FILE { 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)) locked_op!(self, self.read_unlocked(data))
} }
} }
// NOTE assumes file is locked // NOTE assumes file is locked
impl BufRead for FILE { 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(); let buffer = self.read_buffer.as_mut().unwrap();
match buffer.fill_from(&mut self.inner) { match buffer.fill_from(&mut self.inner) {
Ok(slice) => { EResult::Ok(slice) => {
if slice.len() == 0 { if slice.len() == 0 {
self.flags |= FileFlags::EOF; self.flags |= FileFlags::EOF;
} }
Ok(slice) EResult::Ok(slice)
} }
Err(err) => { EResult::Err(err) => {
self.flags |= FileFlags::ERROR; self.flags |= FileFlags::ERROR;
Err(err) EResult::Err(err)
} }
} }
} }
@ -395,7 +393,7 @@ impl BufRead for FILE {
} }
impl Seek 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)) locked_op!(self, self.seek_unlocked(off))
} }
} }
@ -407,7 +405,7 @@ impl AsRawFdOpt for FILE {
} }
impl FileOpenSource for &Path { 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 f = ManagedFile::open_at(None, self, opts, FileMode::default_file())?;
let mut flags = FileFlags::empty(); let mut flags = FileFlags::empty();
if opts.contains(OpenOptions::READ) { if opts.contains(OpenOptions::READ) {
@ -416,12 +414,12 @@ impl FileOpenSource for &Path {
if opts.contains(OpenOptions::WRITE) { if opts.contains(OpenOptions::WRITE) {
flags |= FileFlags::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 { 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 f = unsafe { RawFile::from_raw_fd(self) };
let mut flags = FileFlags::empty(); let mut flags = FileFlags::empty();
if opts.contains(OpenOptions::READ) { if opts.contains(OpenOptions::READ) {
@ -430,7 +428,7 @@ impl FileOpenSource for RawFd {
if opts.contains(OpenOptions::WRITE) { if opts.contains(OpenOptions::WRITE) {
flags |= FileFlags::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), _IOFBF => EResult::Ok(Self::Full),
_IOLBF => EResult::Ok(Self::Line), _IOLBF => EResult::Ok(Self::Line),
_IONBF => EResult::Ok(Self::None), _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; 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); 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) OPEN_FILES.lock().remove(&file)
} }
pub unsafe fn setup_default_files() { 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, RawFd::STDIN,
FileFlags::READ, FileFlags::READ,
BufferingMode::Line, BufferingMode::Line,
))); )));
let stdout_ = Box::into_raw(Box::new(FILE::new_builtin( let stdout_ = Box::leak(Box::new(FILE::new_builtin(
RawFd::STDOUT, RawFd::STDOUT,
FileFlags::WRITE, FileFlags::WRITE,
BufferingMode::Line, BufferingMode::Line,
))); )));
let stderr_ = Box::into_raw(Box::new(FILE::new_builtin( let stderr_ = Box::leak(Box::new(FILE::new_builtin(
RawFd::STDERR, RawFd::STDERR,
FileFlags::WRITE, FileFlags::WRITE,
BufferingMode::None, BufferingMode::None,
@ -502,32 +500,34 @@ pub unsafe fn setup_default_files() {
stderr = stderr_; stderr = stderr_;
let mut open_files = OPEN_FILES.lock(); let mut open_files = OPEN_FILES.lock();
open_files.insert(stdin); open_files.insert(NonNull::from(stdin_));
open_files.insert(stdout); open_files.insert(NonNull::from(stdout_));
open_files.insert(stderr); open_files.insert(NonNull::from(stderr_));
} }
pub fn fflush_all() -> Result<(), Errno> { pub fn fflush_all() -> EResult<()> {
let open_files = OPEN_FILES.lock(); let open_files = OPEN_FILES.lock();
for &file in open_files.iter() { for file in open_files.iter() {
let mut file = *file;
unsafe { 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(); let open_files = OPEN_FILES.lock();
for &file in open_files.iter() { for file in open_files.iter() {
file.as_mut().unwrap().flush_unlocked()?; let mut file = *file;
file.as_mut().flush_unlocked()?;
} }
Ok(()) EResult::Ok(())
} }
pub unsafe fn cleanup() { pub unsafe fn cleanup() {
let mut open_files = OPEN_FILES.lock(); let mut open_files = OPEN_FILES.lock();
while let Some(file) = open_files.pop_first() { 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 alloc::{format, string::String};
use crate::{ use crate::{error::EResult, header::errno::EINVAL, io::Write};
header::errno::{Errno, EINVAL},
io::Write,
};
use super::format::FmtOpts; use super::format::FmtOpts;
@ -37,7 +34,7 @@ fn fmt_float_exp<W: Write + fmt::Write>(
output: &mut W, output: &mut W,
precision: usize, precision: usize,
opts: &FmtOpts, opts: &FmtOpts,
) -> Result<usize, Errno> { ) -> EResult<usize> {
let mut exp2 = exp; let mut exp2 = exp;
let mut exp_len = 1; let mut exp_len = 1;
while exp2 >= 10 { while exp2 >= 10 {
@ -48,12 +45,14 @@ fn fmt_float_exp<W: Write + fmt::Write>(
let string = fmt_float_string(val, precision); let string = fmt_float_string(val, precision);
let f_len = output.write(string.as_bytes())?; let f_len = output.write(string.as_bytes())?;
let e_len = match write!(output, "{}{:+03}", exp_fmt as char, exp) { let e_len = match write!(output, "{}{:+03}", exp_fmt as char, exp) {
Ok(count) => count, 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 { 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, output: &mut W,
precision: usize, precision: usize,
opts: &FmtOpts, opts: &FmtOpts,
) -> Result<usize, Errno> { ) -> EResult<usize> {
let s = fmt_float_string(val, precision); let s = fmt_float_string(val, precision);
let lpad = opts.left_pad(output, s.len())?; let lpad = opts.left_pad(output, s.len())?;
let flen = output.write(s.as_bytes())?; let flen = output.write(s.as_bytes())?;
let rpad = opts.right_pad(output, s.len())?; 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>( fn fmt_float_nonfinite<W: Write + fmt::Write>(
@ -80,7 +79,7 @@ fn fmt_float_nonfinite<W: Write + fmt::Write>(
output: &mut W, output: &mut W,
upper: bool, upper: bool,
opts: &FmtOpts, opts: &FmtOpts,
) -> Result<usize, Errno> { ) -> EResult<usize> {
let mut len = 0; let mut len = 0;
if val.is_sign_negative() { if val.is_sign_negative() {
len += output.write(b"-")?; len += output.write(b"-")?;
@ -102,7 +101,7 @@ fn fmt_float_nonfinite<W: Write + fmt::Write>(
let flen = output.write(nonfinite_str)?; let flen = output.write(nonfinite_str)?;
let rpad = opts.right_pad(output, len + nonfinite_str.len())?; 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>( pub fn fmt_float<W: Write + fmt::Write>(
@ -110,7 +109,7 @@ pub fn fmt_float<W: Write + fmt::Write>(
output: &mut W, output: &mut W,
upper: bool, upper: bool,
opts: &FmtOpts, opts: &FmtOpts,
) -> Result<usize, Errno> { ) -> EResult<usize> {
if val.is_finite() { if val.is_finite() {
fmt_float_finite(val, output, 6, opts) fmt_float_finite(val, output, 6, opts)
} else { } else {
@ -123,7 +122,7 @@ pub fn fmt_float_scientific<W: Write + fmt::Write>(
output: &mut W, output: &mut W,
upper: bool, upper: bool,
opts: &FmtOpts, opts: &FmtOpts,
) -> Result<usize, Errno> { ) -> EResult<usize> {
if val.is_finite() { if val.is_finite() {
let (val, exp) = float_exp(val); let (val, exp) = float_exp(val);
let exp_fmt = match upper { let exp_fmt = match upper {
@ -143,7 +142,7 @@ pub fn fmt_float_any<W: Write + fmt::Write>(
output: &mut W, output: &mut W,
upper: bool, upper: bool,
opts: &FmtOpts, opts: &FmtOpts,
) -> Result<usize, Errno> { ) -> EResult<usize> {
if val.is_finite() { if val.is_finite() {
let (log, exp) = float_exp(val); let (log, exp) = float_exp(val);
let exp_fmt = match upper { let exp_fmt = match upper {

View File

@ -8,7 +8,7 @@ use core::{
use alloc::string::String; 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}; use super::float::{fmt_float, fmt_float_any, fmt_float_scientific};
@ -144,35 +144,27 @@ impl FmtSize {
} }
impl FmtOpts { 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); let pad = self.width - core::cmp::min(self.width, len);
for _ in 0..pad { for _ in 0..pad {
output.write(&[self.pad_char])?; output.write(&[self.pad_char])?;
} }
Ok(pad) EResult::Ok(pad)
} }
pub fn left_pad<W: Write + fmt::Write>( pub fn left_pad<W: Write + fmt::Write>(&self, output: &mut W, len: usize) -> EResult<usize> {
&self,
output: &mut W,
len: usize,
) -> Result<usize, Errno> {
if !self.left_adjust { if !self.left_adjust {
self.pad(output, len) self.pad(output, len)
} else { } else {
Ok(0) EResult::Ok(0)
} }
} }
pub fn right_pad<W: Write + fmt::Write>( pub fn right_pad<W: Write + fmt::Write>(&self, output: &mut W, len: usize) -> EResult<usize> {
&self,
output: &mut W,
len: usize,
) -> Result<usize, Errno> {
if self.left_adjust { if self.left_adjust {
self.pad(output, len) self.pad(output, len)
} else { } else {
Ok(0) EResult::Ok(0)
} }
} }
@ -181,7 +173,7 @@ impl FmtOpts {
spec: FmtSpec, spec: FmtSpec,
output: &mut W, output: &mut W,
ap: &mut VaList, ap: &mut VaList,
) -> Result<usize, Errno> { ) -> EResult<usize> {
let mut buffer = [0; 64]; let mut buffer = [0; 64];
let len = match spec { let len = match spec {
@ -214,7 +206,7 @@ impl FmtOpts {
let lpad = self.left_pad(output, bytes.len())?; let lpad = self.left_pad(output, bytes.len())?;
let len = output.write(bytes)?; let len = output.write(bytes)?;
let rpad = self.right_pad(output, bytes.len())?; 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 => { FmtSpec::String if self.size == FmtSize::Long => {
@ -242,7 +234,7 @@ impl FmtOpts {
let lpad = self.left_pad(output, bytes.len())?; let lpad = self.left_pad(output, bytes.len())?;
let len = output.write(bytes)?; let len = output.write(bytes)?;
let rpad = self.right_pad(output, bytes.len())?; 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 => { FmtSpec::Char if self.size == FmtSize::Normal => {
@ -278,7 +270,7 @@ impl FmtOpts {
let count = output.write(&buffer[..len])?; let count = output.write(&buffer[..len])?;
let rpad = self.right_pad(output, 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, fmt,
}; };
use yggdrasil_rt::{io::RawFd, sys as syscall}; use crate::{
error::{CIntCountResult, EResult, TryFromExt},
use crate::{error::EResult, header::errno::Errno, io::Write}; file::RawFile,
io::Write,
};
use self::format::{FmtOpts, FmtRadix, FmtSign, FmtSize, FmtSpec}; use self::format::{FmtOpts, FmtRadix, FmtSign, FmtSize, FmtSpec};
@ -21,7 +23,7 @@ struct StringWriter {
} }
struct FdWriter { struct FdWriter {
fd: RawFd, file: RawFile,
} }
impl StringWriter { impl StringWriter {
@ -35,7 +37,7 @@ impl StringWriter {
} }
impl Write for 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()); let count = core::cmp::min(self.capacity - self.position, data.len());
if count > 0 { if count > 0 {
let dst = unsafe { let dst = unsafe {
@ -44,41 +46,40 @@ impl Write for StringWriter {
dst.copy_from_slice(&data[..count]); dst.copy_from_slice(&data[..count]);
self.position += count; self.position += count;
} }
Ok(count) EResult::Ok(count)
} }
fn flush(&mut self) -> Result<(), Errno> { fn flush(&mut self) -> EResult<()> {
todo!() todo!()
} }
} }
impl fmt::Write for StringWriter { impl fmt::Write for StringWriter {
fn write_str(&mut self, s: &str) -> fmt::Result { 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(()) Ok(())
} }
} }
impl FdWriter { impl FdWriter {
pub fn new(fd: RawFd) -> Self { pub fn new(file: RawFile) -> Self {
Self { fd } Self { file }
} }
} }
impl Write for FdWriter { impl Write for FdWriter {
fn write(&mut self, data: &[u8]) -> Result<usize, Errno> { fn write(&mut self, data: &[u8]) -> EResult<usize> {
let count = EResult::from(unsafe { syscall::write(self.fd, data) })?; self.file.write(data)
Ok(count)
} }
fn flush(&mut self) -> Result<(), Errno> { fn flush(&mut self) -> EResult<()> {
todo!() self.file.flush()
} }
} }
impl fmt::Write for FdWriter { impl fmt::Write for FdWriter {
fn write_str(&mut self, s: &str) -> fmt::Result { 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(()) Ok(())
} }
} }
@ -87,7 +88,7 @@ fn printf_inner<W: Write + fmt::Write>(
output: &mut W, output: &mut W,
format: &[u8], format: &[u8],
mut ap: VaList, mut ap: VaList,
) -> Result<usize, Errno> { ) -> EResult<usize> {
let mut fmt = format.into_iter(); let mut fmt = format.into_iter();
let mut count = 0; let mut count = 0;
@ -181,41 +182,51 @@ fn printf_inner<W: Write + fmt::Write>(
} }
} }
Ok(count) EResult::Ok(count)
} }
#[no_mangle] #[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()) vfprintf(stdout, format, args.as_va_list())
} }
#[no_mangle] #[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()) vfprintf(stream, format, args.as_va_list())
} }
#[no_mangle] #[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) vfprintf(stdout, format, ap)
} }
#[no_mangle] #[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() { if format.is_null() {
panic!(); panic!();
} }
let stream = stream.as_mut().unwrap(); let stream = stream.as_mut().unwrap();
let format = CStr::from_ptr(format); let format = CStr::from_ptr(format);
match printf_inner(stream, format.to_bytes(), ap) { let count = printf_inner(stream, format.to_bytes(), ap)?;
// TODO handle this
Ok(count) => count as c_int, CIntCountResult(count.try_into().unwrap())
Err(_) => -1,
}
} }
#[no_mangle] #[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()) vsnprintf(str, usize::MAX, format, args.as_va_list())
} }
@ -225,12 +236,16 @@ unsafe extern "C" fn snprintf(
len: usize, len: usize,
format: *const c_char, format: *const c_char,
mut args: ... mut args: ...
) -> c_int { ) -> CIntCountResult {
vsnprintf(str, len, format, args.as_va_list()) vsnprintf(str, len, format, args.as_va_list())
} }
#[no_mangle] #[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) vsnprintf(str, usize::MAX, format, ap)
} }
@ -240,12 +255,12 @@ unsafe extern "C" fn vsnprintf(
len: usize, len: usize,
format: *const c_char, format: *const c_char,
ap: VaList, ap: VaList,
) -> c_int { ) -> CIntCountResult {
if format.is_null() { if format.is_null() {
panic!(); panic!();
} }
if len == 0 { if len == 0 {
return 0; return CIntCountResult(0);
} }
if str.is_null() { if str.is_null() {
// TODO output the length // TODO output the length
@ -254,33 +269,26 @@ unsafe extern "C" fn vsnprintf(
let mut writer = StringWriter::new(str, len); let mut writer = StringWriter::new(str, len);
let format = CStr::from_ptr(format); let format = CStr::from_ptr(format);
match printf_inner(&mut writer, format.to_bytes(), ap) { let count = printf_inner(&mut writer, format.to_bytes(), ap)?;
// TODO handle this
Ok(count) => count as c_int, CIntCountResult(count.try_into().unwrap())
Err(_) => -1,
}
} }
#[no_mangle] #[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()) vdprintf(fd, format, args.as_va_list())
} }
#[no_mangle] #[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() { if format.is_null() {
panic!(); panic!();
} }
if fd < 0 { let file = RawFile::e_try_from(fd)?;
// TODO set errno and return let mut writer = FdWriter::new(file);
todo!();
}
let mut writer = FdWriter::new(RawFd(fd as u32));
let format = CStr::from_ptr(format); let format = CStr::from_ptr(format);
match printf_inner(&mut writer, format.to_bytes(), ap) { let count = printf_inner(&mut writer, format.to_bytes(), ap)?;
// TODO handle this
Ok(count) => count as c_int, CIntCountResult(count.try_into().unwrap())
Err(_) => -1,
}
} }

View File

@ -1,6 +1,6 @@
use core::ops::RangeInclusive; use core::ops::RangeInclusive;
use super::ScanError; use super::FormatError;
pub struct ScanCharSet { pub struct ScanCharSet {
mask: [u64; 4], mask: [u64; 4],
@ -17,7 +17,7 @@ impl ScanCharSet {
pub fn from_format_iter<'a, I: Iterator<Item = &'a u8>>( pub fn from_format_iter<'a, I: Iterator<Item = &'a u8>>(
mut it: I, mut it: I,
) -> Result<(I, Self), ScanError> { ) -> Result<(I, Self), FormatError> {
let mut maybe_close_bracket = true; let mut maybe_close_bracket = true;
let mut hyphen = false; let mut hyphen = false;
let mut start: Option<u8> = None; let mut start: Option<u8> = None;
@ -51,7 +51,7 @@ impl ScanCharSet {
if ch == b'-' { if ch == b'-' {
if hyphen { if hyphen {
// "--"? // "--"?
return Err(ScanError::InvalidFormat); return Err(FormatError);
} }
hyphen = true; hyphen = true;
@ -62,7 +62,7 @@ impl ScanCharSet {
if hyphen { if hyphen {
let Some(start) = start.take() else { let Some(start) = start.take() else {
// "-x" without start? // "-x" without start?
return Err(ScanError::InvalidFormat); return Err(FormatError);
}; };
let same_category = (start.is_ascii_digit() && ch.is_ascii_digit()) let same_category = (start.is_ascii_digit() && ch.is_ascii_digit())
@ -73,7 +73,7 @@ impl ScanCharSet {
hyphen = false; hyphen = false;
set.insert_range(start..=ch); set.insert_range(start..=ch);
} else { } else {
return Err(ScanError::InvalidFormat); return Err(FormatError);
} }
} else { } else {
if let Some(start) = start.replace(ch) { 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::{ use self::{
char_set::ScanCharSet, char_set::ScanCharSet,
@ -14,25 +17,16 @@ mod char_set;
mod format; mod format;
mod reader; mod reader;
pub enum ScanError {
ReadError(Errno),
InvalidFormat,
}
pub enum ConversionError { pub enum ConversionError {
ReadError(Errno), Error(Errno),
ConversionFailed, ConversionFailed,
} }
impl From<Errno> for ScanError { pub struct FormatError;
fn from(value: Errno) -> Self {
Self::ReadError(value)
}
}
impl From<Errno> for ConversionError { impl From<Errno> for ConversionError {
fn from(value: Errno) -> Self { fn from(value: Errno) -> Self {
Self::ReadError(value) Self::Error(value)
} }
} }
@ -40,7 +34,7 @@ fn scanf_inner<G: GetChar>(
stream: &mut ScanReader<G>, stream: &mut ScanReader<G>,
format: &[u8], format: &[u8],
mut ap: VaList, mut ap: VaList,
) -> Result<usize, ScanError> { ) -> EResult<usize> {
let mut it = format.into_iter(); let mut it = format.into_iter();
let mut matched = 0; let mut matched = 0;
let mut skip_space = false; let mut skip_space = false;
@ -128,7 +122,10 @@ fn scanf_inner<G: GetChar>(
b'o' => ScanSpec::Unsigned(ScanRadix::Oct), b'o' => ScanSpec::Unsigned(ScanRadix::Oct),
b's' => ScanSpec::Word, b's' => ScanSpec::Word,
b'[' => { 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; it = new_it;
ScanSpec::Chars(set) ScanSpec::Chars(set)
} }
@ -138,42 +135,46 @@ fn scanf_inner<G: GetChar>(
b'%' => ScanSpec::Percent, b'%' => ScanSpec::Percent,
b'f' | b'e' | b'g' | b'E' | b'a' => todo!(), b'f' | b'e' | b'g' | b'E' | b'a' => todo!(),
// Unrecognized specifier // Unrecognized specifier
_ => return Err(ScanError::InvalidFormat), _ => return EResult::Err(ESUCCESS),
} }
} else { } else {
// No specifier after % // No specifier after %
return Err(ScanError::InvalidFormat); return EResult::Err(ESUCCESS);
}; };
matched += match opts.scan(stream, spec, &mut ap) { matched += match opts.scan(stream, spec, &mut ap) {
Ok(matched) => matched, Ok(matched) => matched,
Err(ConversionError::ConversionFailed) => break, 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 // TODO report end of stream before anything is matched
Ok(matched) EResult::Ok(matched)
} }
#[no_mangle] #[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()) vfscanf(stream, format, args.as_va_list())
} }
#[no_mangle] #[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()) vfscanf(stdin, format, args.as_va_list())
} }
#[no_mangle] #[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()) vsscanf(str, format, args.as_va_list())
} }
#[no_mangle] #[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() { if format.is_null() {
panic!(); 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); let mut reader = ScanReader::new(stream);
match scanf_inner(&mut reader, format.to_bytes(), ap) { let count = scanf_inner(&mut reader, format.to_bytes(), ap)?;
Ok(count) => count.try_into().unwrap(),
Err(_) => -1, CEofResult(count.try_into().unwrap())
}
} }
#[no_mangle] #[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) vfscanf(stdin, format, ap)
} }
#[no_mangle] #[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() { if str.is_null() || format.is_null() {
panic!(); 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 str_it = str.to_bytes().into_iter();
let mut reader = ScanReader::new(&mut str_it); let mut reader = ScanReader::new(&mut str_it);
match scanf_inner(&mut reader, format.to_bytes(), ap) { let count = scanf_inner(&mut reader, format.to_bytes(), ap)?;
Ok(count) => count.try_into().unwrap(),
Err(_) => -1, CEofResult(count.try_into().unwrap())
}
} }

View File

@ -1,10 +1,7 @@
use crate::{ use crate::{error::EResult, header::stdio::FILE, io::Read};
header::{errno::Errno, stdio::FILE},
io::Read,
};
pub trait GetChar { pub trait GetChar {
fn getc(&mut self) -> Result<Option<u8>, Errno>; fn getc(&mut self) -> EResult<Option<u8>>;
} }
pub struct ScanReader<'a, G: GetChar> { pub struct ScanReader<'a, G: GetChar> {
@ -14,19 +11,19 @@ pub struct ScanReader<'a, G: GetChar> {
} }
impl GetChar for FILE { impl GetChar for FILE {
fn getc(&mut self) -> Result<Option<u8>, Errno> { fn getc(&mut self) -> EResult<Option<u8>> {
let mut buf = [0]; let mut buf = [0];
match self.read(&mut buf) { match self.read(&mut buf) {
Ok(1) => Ok(Some(buf[0])), EResult::Ok(1) => EResult::Ok(Some(buf[0])),
Ok(_) => Ok(None), EResult::Ok(_) => EResult::Ok(None),
Err(err) => Err(err), EResult::Err(err) => EResult::Err(err),
} }
} }
} }
impl<'a, I: Iterator<Item = &'a u8>> GetChar for I { impl<'a, I: Iterator<Item = &'a u8>> GetChar for I {
fn getc(&mut self) -> Result<Option<u8>, Errno> { fn getc(&mut self) -> EResult<Option<u8>> {
Ok(self.next().copied()) 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() { match self.getter.getc() {
Ok(Some(n)) => { EResult::Ok(Some(n)) => {
self.consumed_count += 1; self.consumed_count += 1;
Ok(Some(n)) EResult::Ok(Some(n))
} }
e => e, e => e,
} }
@ -53,16 +50,16 @@ impl<'a, G: GetChar> ScanReader<'a, G> {
self.consumed_count 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() { if self.buffer.is_none() {
self.buffer = self.getc()?; 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() { match self.buffer.take() {
Some(v) => Ok(Some(v)), Some(v) => EResult::Ok(Some(v)),
None => self.getc(), None => self.getc(),
} }
} }

View File

@ -1,13 +1,11 @@
use core::ffi::{c_char, c_int, c_void, CStr}; use core::ffi::{c_char, c_int, c_void, CStr};
use yggdrasil_rt::io::RawFd;
use crate::{ use crate::{
error::{self, CSizeResult, CZeroResult}, error::{CEofResult, CFdResult, CIntZeroResult, CUsizeResult, OptionExt},
header::errno::EBADF, header::errno::EBADF,
}; };
use super::{stdin, stdout, FileFlags, EOF, FILE}; use super::{stdin, stdout, FileFlags, FILE};
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn flockfile(stream: *mut FILE) { pub unsafe extern "C" fn flockfile(stream: *mut FILE) {
@ -16,12 +14,10 @@ pub unsafe extern "C" fn flockfile(stream: *mut FILE) {
} }
#[no_mangle] #[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(); let stream = stream.as_mut().unwrap();
match stream.try_lock() { stream.try_lock()?;
true => 0, CIntZeroResult::OK
false => -1,
}
} }
#[no_mangle] #[no_mangle]
@ -49,15 +45,10 @@ pub unsafe extern "C" fn clearerr_unlocked(stream: *mut FILE) {
} }
#[no_mangle] #[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(); let stream = stream.as_mut().unwrap();
match stream.as_raw_fd_opt_unlocked() { let fd = stream.as_raw_fd_opt_unlocked().e_ok_or(EBADF)?;
Some(RawFd(fd)) => fd as _, CFdResult::success(fd)
None => {
error::set_errno(EBADF);
-1
}
}
} }
#[no_mangle] #[no_mangle]
@ -66,14 +57,16 @@ pub unsafe extern "C" fn fwrite_unlocked(
size: usize, size: usize,
nmemb: usize, nmemb: usize,
stream: *mut FILE, stream: *mut FILE,
) -> usize { ) -> CUsizeResult {
if ptr.is_null() { if ptr.is_null() {
panic!(); panic!();
} }
let stream = stream.as_mut().unwrap(); let stream = stream.as_mut().unwrap();
let data = core::slice::from_raw_parts(ptr as *const u8, size * nmemb); 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] #[no_mangle]
@ -82,62 +75,64 @@ pub unsafe extern "C" fn fread_unlocked(
size: usize, size: usize,
nmemb: usize, nmemb: usize,
stream: *mut FILE, stream: *mut FILE,
) -> usize { ) -> CUsizeResult {
if ptr.is_null() { if ptr.is_null() {
panic!(); panic!();
} }
let stream = stream.as_mut().unwrap(); let stream = stream.as_mut().unwrap();
let data = core::slice::from_raw_parts_mut(ptr as *mut u8, size * nmemb); 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] #[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() { if let Some(stream) = stream.as_mut() {
stream.flush_unlocked().into_eof_status() stream.flush_unlocked()?;
} else { } else {
super::fflush_all_unlocked().into_eof_status() super::fflush_all_unlocked()?;
} }
CEofResult(0)
} }
#[no_mangle] #[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 stream = stream.as_mut().unwrap();
let mut buf = [0]; let mut buf = [0];
match stream.read_unlocked(&mut buf) { match stream.read_unlocked(&mut buf)? {
Ok(1) => buf[0] as c_int, 1 => CEofResult(buf[0] as _),
Ok(_) => EOF, _ => CEofResult::ERR,
Err(_) => EOF,
} }
} }
#[no_mangle] #[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) fgetc_unlocked(stream)
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn getchar_unlocked() -> c_int { pub unsafe extern "C" fn getchar_unlocked() -> CEofResult {
fgetc_unlocked(stdin) fgetc_unlocked(stdin)
} }
#[no_mangle] #[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) fputc_unlocked(c, stdout)
} }
#[no_mangle] #[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(); let stream = stream.as_mut().unwrap();
match stream.write_unlocked(&[c as u8]) { stream.write_unlocked(&[c as u8])?;
Ok(_) => c,
Err(_) => EOF, 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() { if s.is_null() {
panic!(); 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 s = CStr::from_ptr(s);
let stream = stream.as_mut().unwrap(); let stream = stream.as_mut().unwrap();
match stream.write_unlocked(s.to_bytes()) { // TODO write_all_unlocked
Ok(_) => 0, stream.write_unlocked(s.to_bytes())?;
Err(_) => EOF,
} CEofResult(0)
} }

View File

@ -1,98 +1,28 @@
use core::{ use core::{ffi::c_void, ptr::NonNull};
alloc::{GlobalAlloc, Layout},
ffi::c_void,
intrinsics,
ptr::null_mut,
};
use crate::{allocator::GLOBAL_ALLOCATOR, error, header::errno::ENOMEM}; use crate::{allocator, error::CPtrResult};
unsafe fn alloc_inner(size: usize) -> *mut c_void { #[no_mangle]
let size = (size + 15) & !15; pub unsafe extern "C" fn calloc(nmemb: usize, size: usize) -> CPtrResult<c_void> {
let layout = Layout::from_size_align(size + 16, 16).unwrap(); let ptr = allocator::c_allocate_zeroed(nmemb, size)?;
let ptr = GLOBAL_ALLOCATOR.alloc(layout); CPtrResult::success(ptr.cast())
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] #[no_mangle]
pub unsafe extern "C" fn calloc(nmemb: usize, size: usize) -> *mut c_void { unsafe extern "C" fn malloc(size: usize) -> CPtrResult<c_void> {
match nmemb.checked_mul(size) { let ptr = allocator::c_allocate(size)?;
Some(size) => { CPtrResult::success(ptr.cast())
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()
}
}
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn malloc(size: usize) -> *mut c_void { unsafe extern "C" fn realloc(ptr: *mut c_void, new_size: usize) -> CPtrResult<c_void> {
alloc_inner(size) let ptr = allocator::c_reallocate(NonNull::new(ptr).map(NonNull::cast), new_size)?;
CPtrResult::success(ptr.cast())
} }
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn realloc(ptr: *mut c_void, new_size: usize) -> *mut c_void { unsafe extern "C" fn free(ptr: *mut c_void) {
if ptr.is_null() { if let Some(ptr) = NonNull::new(ptr) {
return malloc(new_size); 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); int wctomb(char *, wchar_t);
*/ */
pub use malloc::{calloc, free, malloc, realloc};
pub const EXIT_SUCCESS: c_int = 0; pub const EXIT_SUCCESS: c_int = 0;
pub const EXIT_FAILURE: c_int = 1; pub const EXIT_FAILURE: c_int = 1;

View File

@ -1,16 +1,17 @@
use core::{ use core::{
ffi::{c_char, c_int, CStr}, ffi::{c_char, c_int, CStr},
ptr::null_mut, ptr::NonNull,
}; };
use crate::process; use crate::{
error::{CIntZeroResult, CPtrResult},
process,
};
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn atexit(f: extern "C" fn()) -> c_int { pub unsafe extern "C" fn atexit(f: extern "C" fn()) -> CIntZeroResult {
match process::register_atexit(f) { process::register_atexit(f)?;
Ok(()) => 0, CIntZeroResult::OK
Err(_) => -1,
}
} }
#[no_mangle] #[no_mangle]
@ -29,15 +30,13 @@ pub unsafe extern "C" fn abort() -> ! {
} }
#[no_mangle] #[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() { if name.is_null() {
panic!(); panic!();
} }
let name = CStr::from_ptr(name); let name = CStr::from_ptr(name);
match process::getenv_raw(name.to_bytes()) { let entry = process::getenv_raw(name.to_bytes())?;
Some(data) => data.as_ptr() as _, CPtrResult::success(NonNull::new_unchecked(entry.as_ptr() as _))
None => null_mut(),
}
} }
#[no_mangle] #[no_mangle]
@ -46,30 +45,32 @@ unsafe extern "C" fn putenv(string: *mut c_char) -> c_int {
} }
#[no_mangle] #[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() { if name.is_null() || value.is_null() {
panic!(); panic!();
} }
let name = CStr::from_ptr(name); let name = CStr::from_ptr(name);
let value = CStr::from_ptr(value); let value = CStr::from_ptr(value);
match process::setenv_raw(name.to_bytes(), Some(value.to_bytes()), overwrite != 0) { process::setenv_raw(name.to_bytes(), Some(value.to_bytes()), overwrite != 0)?;
Ok(_) => 0,
Err(_) => -1, CIntZeroResult::OK
}
} }
#[no_mangle] #[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() { if name.is_null() {
panic!(); panic!();
} }
let name = CStr::from_ptr(name); let name = CStr::from_ptr(name);
match process::setenv_raw(name.to_bytes(), None, true) { process::setenv_raw(name.to_bytes(), None, true)?;
Ok(_) => 0,
Err(_) => -1, CIntZeroResult::OK
}
} }
#[no_mangle] #[no_mangle]

View File

@ -7,10 +7,11 @@ use core::{
use yggdrasil_rt::memcpy; use yggdrasil_rt::memcpy;
use crate::{ use crate::{
allocator,
error::CPtrResult,
header::{ header::{
errno::{self, Errno}, errno::{self, Errno},
locale::locale_t, locale::locale_t,
stdlib::malloc,
string::strlen, string::strlen,
}, },
util::Nullable, util::Nullable,
@ -95,12 +96,12 @@ unsafe extern "C" fn strcspn(mut s: *const c_char, reject: *const c_char) -> usi
} }
#[no_mangle] #[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(); s.ensure();
let len = strlen(s); let len = strlen(s);
let data = malloc(len + 1); let data = allocator::c_allocate(len + 1)?;
memcpy(data as _, s as _, len + 1); memcpy(data.cast().as_ptr(), s as _, len + 1);
data as _ CPtrResult::success(data.cast())
} }
unsafe fn strerror_inner(e: c_int) -> *const c_char { 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 yggdrasil_rt::io::{FileAttr, FileMode, FileType, RawFd};
use crate::{ use crate::{
error::{self, CZeroResult}, error::{CIntZeroResult, TryFromExt},
io, io,
util::Nullable, util::{self, Nullable},
}; };
use super::{ use super::{
errno::EBADF,
fcntl::{AT_FDCWD, AT_SYMLINK_NOFOLLOW}, fcntl::{AT_FDCWD, AT_SYMLINK_NOFOLLOW},
sys_time::__ygg_timespec_t, 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}, 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 // Create stuff
#[no_mangle] #[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) mkdirat(AT_FDCWD, pathname, mode)
} }
#[no_mangle] #[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(); pathname.ensure();
let pathname = CStr::from_ptr(pathname).to_str().unwrap(); let pathname = CStr::from_ptr(pathname).to_str().unwrap();
let atfd = util::at_fd(atfd)?;
// 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 mode = FileMode::new((mode & 0o777) as u32); 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] #[no_mangle]
@ -168,22 +158,15 @@ unsafe extern "C" fn mknodat(
// File status // File status
#[no_mangle] #[no_mangle]
unsafe extern "C" fn fstat(fd: c_int, statbuf: *mut stat) -> c_int { unsafe extern "C" fn fstat(fd: c_int, statbuf: *mut stat) -> CIntZeroResult {
if fd < 0 { let fd = RawFd::e_try_from(fd)?;
error::set_errno(EBADF); let attr = io::get_metadata(Some(fd), "", false)?;
return -1;
}
let attr = match io::get_metadata(Some(RawFd(fd as _)), "", false) {
Ok(attr) => attr,
Err(_) => return -1,
};
if let Some(statbuf) = statbuf.as_mut() { if let Some(statbuf) = statbuf.as_mut() {
*statbuf = attr.into(); *statbuf = attr.into();
} }
0 CIntZeroResult::OK
} }
#[no_mangle] #[no_mangle]
@ -192,42 +175,28 @@ unsafe extern "C" fn fstatat(
pathname: *const c_char, pathname: *const c_char,
statbuf: *mut stat, statbuf: *mut stat,
opt: c_int, opt: c_int,
) -> c_int { ) -> CIntZeroResult {
pathname.ensure(); pathname.ensure();
let pathname = CStr::from_ptr(pathname).to_str().unwrap(); let pathname = CStr::from_ptr(pathname).to_str().unwrap();
let atfd = util::at_fd(atfd)?;
// 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 follow = opt & AT_SYMLINK_NOFOLLOW == 0; let follow = opt & AT_SYMLINK_NOFOLLOW == 0;
let attr = match io::get_metadata(atfd, pathname, follow) { let attr = io::get_metadata(atfd, pathname, follow)?;
Ok(attr) => attr,
Err(_) => return -1,
};
if let Some(statbuf) = statbuf.as_mut() { if let Some(statbuf) = statbuf.as_mut() {
*statbuf = attr.into(); *statbuf = attr.into();
} }
0 CIntZeroResult::OK
} }
#[no_mangle] #[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) fstatat(AT_FDCWD, pathname, statbuf, AT_SYMLINK_NOFOLLOW)
} }
#[no_mangle] #[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) 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 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; let mut exit_code = ExitCode::SUCCESS;
unsafe { syscall::wait_process(pid, &mut exit_code) }?; unsafe { syscall::wait_process(pid, &mut exit_code) }?;
Ok(exit_code) EResult::Ok(exit_code)
} }
#[no_mangle] #[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; let _ = options;
if pid < 0 { if pid < 0 {
todo!(); todo!();
} }
let pid = pid as u32; let pid: u32 = pid.try_into().unwrap();
let code = waitpid_inner(pid)?;
match waitpid_inner(pid) { if let Some(wstatus) = wstatus.as_mut() {
Ok(code) => { match code {
if let Some(wstatus) = wstatus.as_mut() { ExitCode::Exited(code) => *wstatus = code,
match code { ExitCode::BySignal(_signal) => todo!(),
ExitCode::Exited(code) => *wstatus = code,
ExitCode::BySignal(_) => todo!(),
}
}
pid as pid_t
} }
Err(_) => -1,
} }
CPidResult::success(pid)
} }

View File

@ -1,9 +1,7 @@
use core::{ use core::{ffi::c_double, time::Duration};
ffi::{c_double, c_int},
time::Duration,
};
use crate::{ use crate::{
error::CIntZeroResult,
header::{sys_time::__ygg_timespec_t, sys_types::time_t}, header::{sys_time::__ygg_timespec_t, sys_types::time_t},
util, util,
}; };
@ -12,27 +10,17 @@ use crate::{
unsafe extern "C" fn nanosleep( unsafe extern "C" fn nanosleep(
rqtp: *const __ygg_timespec_t, rqtp: *const __ygg_timespec_t,
rmtp: *mut __ygg_timespec_t, rmtp: *mut __ygg_timespec_t,
) -> c_int { ) -> CIntZeroResult {
let rqtp = rqtp.as_ref().unwrap(); let rqtp = rqtp.as_ref().unwrap();
if let Some(_rmtp) = rmtp.as_mut() {
todo!();
}
let amount = Duration::from(*rqtp); let amount = Duration::from(*rqtp);
match util::nanosleep(amount, None) { util::nanosleep(amount, None)?;
Ok(()) => {
if let Some(rmtp) = rmtp.as_mut() {
// Zero
*rmtp = __ygg_timespec_t::default();
}
0 CIntZeroResult::OK
}
Err(_) => {
if let Some(rmtp) = rmtp.as_mut() {
todo!();
}
-1
}
}
} }
#[no_mangle] #[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 yggdrasil_rt::io::SeekFrom;
use crate::{ use crate::{
error, error::{CFdResult, CIntZeroResult, CIsizeResult, COffsetResult, EResult, TryFromExt},
file::RawFile, file::RawFile,
header::{ header::{
errno::EINVAL, errno::EINVAL,
@ -18,82 +18,69 @@ use crate::{
pub const _PC_NAME_MAX: c_int = 1; pub const _PC_NAME_MAX: c_int = 1;
pub const _PC_PATH_MAX: c_int = 2; 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] #[no_mangle]
unsafe extern "C" fn getcwd(buf: *mut c_char, size: usize) -> *mut c_char { unsafe extern "C" fn getcwd(buf: *mut c_char, size: usize) -> *mut c_char {
todo!() todo!()
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn close(fd: c_int) -> c_int { unsafe extern "C" fn close(fd: c_int) -> CIntZeroResult {
let Ok(mut file) = RawFile::try_from(fd) else { let mut file = RawFile::e_try_from(fd)?;
return -1; file.close()?;
}; CIntZeroResult::OK
match file.close() {
Ok(()) => 0,
Err(_) => -1,
}
} }
#[no_mangle] #[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) unlinkat(AT_FDCWD, pathname, AT_SYMLINK_NOFOLLOW)
} }
#[no_mangle] #[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!() todo!()
} }
#[no_mangle] #[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(); buf.ensure();
let Ok(mut file) = RawFile::try_from(fd) else { let mut file = RawFile::e_try_from(fd)?;
return -1;
};
let data = core::slice::from_raw_parts(buf as *const u8, count); let data = core::slice::from_raw_parts(buf as *const u8, count);
let count = file.write(data)?;
match file.write(data) { CIsizeResult::success(count)
Ok(amount) => amount.try_into().unwrap(),
Err(_) => -1,
}
} }
#[no_mangle] #[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(); buf.ensure();
let Ok(mut file) = RawFile::try_from(fd) else { let mut file = RawFile::e_try_from(fd)?;
return -1;
};
let data = core::slice::from_raw_parts_mut(buf as *mut u8, count); let data = core::slice::from_raw_parts_mut(buf as *mut u8, count);
let count = file.read(data)?;
match file.read(data) { CIsizeResult::success(count)
Ok(amount) => amount.try_into().unwrap(),
Err(_) => -1,
}
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn lseek(fd: c_int, offset: off_t, whence: c_int) -> off_t { unsafe extern "C" fn lseek(fd: c_int, offset: off_t, whence: c_int) -> COffsetResult {
let Ok(mut file) = RawFile::try_from(fd) else { let mut file = RawFile::e_try_from(fd)?;
return -1; let offset = seek_offset(whence, offset)?;
}; let pos = file.seek(offset)?;
let offset = match whence { COffsetResult::success(pos)
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,
}
} }
#[no_mangle] #[no_mangle]
@ -102,22 +89,22 @@ unsafe extern "C" fn faccessat(
path: *const c_char, path: *const c_char,
amode: c_int, amode: c_int,
flags: c_int, flags: c_int,
) -> c_int { ) -> CIntZeroResult {
todo!() todo!()
} }
#[no_mangle] #[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) faccessat(AT_FDCWD, path, amode, 0)
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn dup(fd: c_int) -> c_int { unsafe extern "C" fn dup(fd: c_int) -> CFdResult {
todo!() todo!()
} }
#[no_mangle] #[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!() todo!()
} }
@ -127,17 +114,17 @@ unsafe extern "C" fn isatty(fd: c_int) -> c_int {
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn rmdir(pathname: *const c_char) -> c_int { unsafe extern "C" fn rmdir(pathname: *const c_char) -> CIntZeroResult {
todo!() todo!()
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn chdir(pathname: *const c_char) -> c_int { unsafe extern "C" fn chdir(pathname: *const c_char) -> CIntZeroResult {
todo!() todo!()
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn pipe(fds: *mut c_int) -> c_int { unsafe extern "C" fn pipe(fds: *mut c_int) -> CIntZeroResult {
todo!() todo!()
} }

View File

@ -7,21 +7,22 @@ use alloc::{vec, vec::Vec};
use yggdrasil_rt::{path::Path, process::ExecveOptions, sys as syscall}; use yggdrasil_rt::{path::Path, process::ExecveOptions, sys as syscall};
use crate::{ use crate::{
error::{CZeroResult, EResult}, error::{CIntZeroResult, CPidResult, EResult},
header::{errno::Errno, sys_types::pid_t}, header::sys_types::pid_t,
process,
util::{self, NullTerminated}, util::{self, NullTerminated},
}; };
unsafe fn fork_inner() -> Result<pid_t, Errno> { unsafe fn fork_inner() -> EResult<u32> {
let result = EResult::from(syscall::fork())?; let result = syscall::fork()?;
Ok(result as _) EResult::Ok(result)
} }
// TODO error reporting // TODO error reporting
unsafe fn collect_execve_args<'a, 'e>( unsafe fn collect_execve_args<'a, 'e>(
argv: *const *mut c_char, argv: *const *mut c_char,
envp: *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 arg_list = vec![];
let mut env_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>>( unsafe fn execve_inner<P: AsRef<Path>>(pathname: P, argv: &[&str], envp: &[&str]) -> EResult<()> {
pathname: P,
argv: &[&str],
envp: &[&str],
) -> Result<(), Errno> {
let opts = ExecveOptions { let opts = ExecveOptions {
program: pathname.as_ref().as_str(), program: pathname.as_ref().as_str(),
arguments: argv, arguments: argv,
environment: envp, environment: envp,
}; };
let result = EResult::from(syscall::execve(&opts))?; let result = syscall::execve(&opts)?;
Ok(result as _) 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)?; let pathname = util::resolve_binary(file)?;
execve_inner(&pathname, argv, envp) execve_inner(&pathname, argv, envp)
} }
#[no_mangle] #[no_mangle]
unsafe extern "C" fn fork() -> pid_t { unsafe extern "C" fn fork() -> CPidResult {
match fork_inner() { let pid = fork_inner()?;
Ok(pid) => pid, CPidResult::success(pid)
Err(_) => -1,
}
} }
#[no_mangle] #[no_mangle]
@ -73,27 +68,26 @@ unsafe extern "C" fn execve(
pathname: *const c_char, pathname: *const c_char,
argv: *const *mut c_char, argv: *const *mut c_char,
envp: *const *mut c_char, envp: *const *mut c_char,
) -> c_int { ) -> CIntZeroResult {
if pathname.is_null() { if pathname.is_null() {
panic!(); panic!();
} }
let pathname = CStr::from_ptr(pathname); let pathname = CStr::from_ptr(pathname);
let pathname = pathname.to_str().unwrap(); let pathname = pathname.to_str().unwrap();
let (argv, envp) = match collect_execve_args(argv, envp) { let (argv, envp) = collect_execve_args(argv, envp)?;
Ok(r) => r,
Err(_) => return -1,
};
execve_inner(pathname, &argv, &envp).into_zero_status() execve_inner(pathname, &argv, &envp)?;
CIntZeroResult::OK
} }
#[no_mangle] #[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()) execve(pathname, argv, null())
} }
#[no_mangle] #[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()) execvpe(file, argv, null())
} }
@ -102,18 +96,17 @@ unsafe extern "C" fn execvpe(
file: *const c_char, file: *const c_char,
argv: *const *mut c_char, argv: *const *mut c_char,
envp: *const *mut c_char, envp: *const *mut c_char,
) -> c_int { ) -> CIntZeroResult {
if file.is_null() { if file.is_null() {
panic!(); panic!();
} }
let file = CStr::from_ptr(file); let file = CStr::from_ptr(file);
let file = file.to_str().unwrap(); let file = file.to_str().unwrap();
let (argv, envp) = match collect_execve_args(argv, envp) { let (argv, envp) = collect_execve_args(argv, envp)?;
Ok(r) => r,
Err(_) => return -1,
};
execvpe_inner(file, &argv, &envp).into_zero_status() execvpe_inner(file, &argv, &envp)?;
CIntZeroResult::OK
} }
#[no_mangle] #[no_mangle]
@ -123,6 +116,6 @@ unsafe extern "C" fn _exit(status: c_int) -> ! {
#[no_mangle] #[no_mangle]
unsafe extern "C" fn getpid() -> pid_t { unsafe extern "C" fn getpid() -> pid_t {
let pid = syscall::get_pid(); let pid = process::current_pid();
pid.try_into().unwrap() pid.try_into().unwrap()
} }

View File

@ -6,7 +6,7 @@ use core::{
use alloc::{boxed::Box, vec::Vec}; use alloc::{boxed::Box, vec::Vec};
use crate::header::errno::Errno; use crate::error::EResult;
use super::{Read, Write}; use super::{Read, Write};
@ -65,20 +65,20 @@ impl<'a> ReadBuffer<'a> {
self.len = 0; 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() }; let buffer = unsafe { self.data.as_slice_mut() };
if self.position == self.len { if self.position == self.len {
let amount = match source.read(buffer) { let amount = match source.read(buffer) {
Ok(0) => return Ok(&buffer[..0]), EResult::Ok(0) => return EResult::Ok(&buffer[..0]),
Ok(n) => n, EResult::Ok(n) => n,
Err(err) => return Err(err), EResult::Err(err) => return EResult::Err(err),
}; };
self.position = 0; self.position = 0;
self.len = amount; 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) { pub fn consume(&mut self, amount: usize) {
@ -137,17 +137,17 @@ impl<W: Write> LineWriter<W> {
} }
impl<W: Write> Write for UnbufferedWriter<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) self.inner.write(data)
} }
fn flush(&mut self) -> Result<(), Errno> { fn flush(&mut self) -> EResult<()> {
Ok(()) EResult::Ok(())
} }
} }
impl<W: Write> Write for BufWriter<W> { 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() { if data.len() + self.buffer.len() >= self.buffer.capacity() {
self.flush()?; self.flush()?;
} }
@ -169,10 +169,10 @@ impl<W: Write> Write for BufWriter<W> {
// Store the data in the buffer // Store the data in the buffer
assert!(data.len() < self.buffer.capacity()); assert!(data.len() < self.buffer.capacity());
self.buffer.extend_from_slice(data); 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); let (amount, result) = self.inner.write_chunked(&self.buffer);
if amount != 0 { if amount != 0 {
self.buffer.drain(..amount); self.buffer.drain(..amount);
@ -182,7 +182,7 @@ impl<W: Write> Write for BufWriter<W> {
} }
impl<W: Write> Write for LineWriter<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 { if self.need_flush {
self.flush()?; self.flush()?;
} }
@ -195,20 +195,20 @@ impl<W: Write> Write for LineWriter<W> {
let amount = self.inner.write(&data[..nl_pos + 1])?; let amount = self.inner.write(&data[..nl_pos + 1])?;
self.need_flush = true; self.need_flush = true;
if self.flush().is_err() || amount != nl_pos + 1 { if self.flush().is_err() || amount != nl_pos + 1 {
return Ok(amount); return EResult::Ok(amount);
} }
// Write the rest to the buffer // Write the rest to the buffer
match self.inner.write(&data[nl_pos + 1..]) { match self.inner.write(&data[nl_pos + 1..]) {
Ok(amount_to_buffer) => Ok(amount_to_buffer + amount), EResult::Ok(amount_to_buffer) => EResult::Ok(amount_to_buffer + amount),
Err(_) => Ok(amount), EResult::Err(_) => EResult::Ok(amount),
} }
} }
fn flush(&mut self) -> Result<(), Errno> { fn flush(&mut self) -> EResult<()> {
self.inner.flush()?; self.inner.flush()?;
self.need_flush = false; self.need_flush = false;
Ok(()) EResult::Ok(())
} }
} }

View File

@ -7,10 +7,9 @@ use yggdrasil_rt::{
sys as syscall, sys as syscall,
}; };
use crate::{ use crate::{error::EResult, header::errno::EBADF};
error::{self, EResult},
header::errno::{Errno, EBADF}, use super::FromRawFd;
};
#[derive(Debug)] #[derive(Debug)]
pub struct DirReader { pub struct DirReader {
@ -25,27 +24,17 @@ pub struct DirReader {
impl DirReader { impl DirReader {
const BUFFER_SIZE: usize = 16; const BUFFER_SIZE: usize = 16;
pub fn open_at<P: AsRef<Path>>(at: Option<RawFd>, path: P) -> Result<Self, Errno> { pub fn open_at<P: AsRef<Path>>(at: Option<RawFd>, path: P) -> EResult<Self> {
let fd = EResult::from(unsafe { syscall::open_directory(at, path.as_ref().as_str()) })?; let fd = unsafe { syscall::open_directory(at, path.as_ref().as_str()) }?;
Ok(unsafe { Self::from_raw_fd(fd) }) EResult::Ok(unsafe { Self::from_raw_fd(fd) })
} }
pub unsafe fn from_raw_fd(fd: RawFd) -> Self { pub unsafe fn close(&mut self) -> EResult<()> {
Self {
fd: Some(fd),
buffer: Box::new_uninit_slice(Self::BUFFER_SIZE),
position: 0,
len: 0,
}
}
pub unsafe fn close(&mut self) -> Result<(), Errno> {
if let Some(fd) = self.fd.take() { if let Some(fd) = self.fd.take() {
EResult::from(unsafe { syscall::close(fd) })?; unsafe { syscall::close(fd) }?;
Ok(()) EResult::Ok(())
} else { } else {
error::set_errno_result(EBADF) EResult::Err(EBADF)
} }
} }
@ -53,34 +42,47 @@ impl DirReader {
self.fd.unwrap() self.fd.unwrap()
} }
fn fill_buf(&mut self) -> Result<&[DirectoryEntry], Errno> { fn fill_buf(&mut self) -> EResult<&[DirectoryEntry]> {
let Some(fd) = self.fd else { let Some(fd) = self.fd else {
return error::set_errno_result(EBADF); return EResult::Err(EBADF);
}; };
if self.position == self.len { if self.position == self.len {
let count = let count = unsafe { syscall::read_directory_entries(fd, &mut self.buffer) }?;
EResult::from(unsafe { syscall::read_directory_entries(fd, &mut self.buffer) })?;
self.position = 0; self.position = 0;
self.len = count; 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) { fn consume(&mut self, count: usize) {
self.position = (self.position + count).min(self.len); 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()?; let buf = self.fill_buf()?;
if let Some(&entry) = buf.get(0) { if let Some(&entry) = buf.get(0) {
self.consume(1); self.consume(1);
Ok(Some(entry)) EResult::Ok(Some(entry))
} else { } 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::{ use crate::{
error::EResult, error::EResult,
header::errno::{Errno, EINTR}, header::errno::{EINTR, ESUCCESS},
}; };
pub mod buffered; pub mod buffered;
pub mod dir; pub mod dir;
pub trait Write { pub trait Write {
fn write(&mut self, data: &[u8]) -> Result<usize, Errno>; fn write(&mut self, data: &[u8]) -> EResult<usize>;
fn flush(&mut self) -> Result<(), Errno>; 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 mut pos = 0;
let len = data.len(); let len = data.len();
while pos < len { while pos < len {
match self.write(data) { match self.write(data) {
Ok(0) => todo!(), EResult::Ok(0) => todo!(),
Ok(n) => pos += n, EResult::Ok(n) => pos += n,
Err(err) if err == EINTR => todo!(), EResult::Err(err) if err == EINTR => todo!(),
Err(err) => return (pos, Err(err)), 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) { match self.write(data) {
Ok(n) if n == data.len() => Ok(()), EResult::Ok(n) if n == data.len() => EResult::Ok(()),
Ok(_) => todo!(), // TODO handle partial writes in write_all EResult::Ok(_) => todo!(), // TODO handle partial writes in write_all
Err(err) => Err(err), EResult::Err(err) => EResult::Err(err),
} }
} }
} }
pub trait Read { 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 { pub trait BufRead {
fn fill_buf(&mut self) -> Result<&[u8], Errno>; fn fill_buf(&mut self) -> EResult<&[u8]>;
fn consume(&mut self, amount: usize); fn consume(&mut self, amount: usize);
} }
pub trait Seek { 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)) self.seek(SeekFrom::Current(0))
} }
} }
@ -76,21 +84,13 @@ pub trait IntoRawFd {
fn into_raw_fd(self) -> RawFd; fn into_raw_fd(self) -> RawFd;
} }
pub fn get_metadata<P: AsRef<Path>>( pub fn get_metadata<P: AsRef<Path>>(at: Option<RawFd>, path: P, follow: bool) -> EResult<FileAttr> {
at: Option<RawFd>,
path: P,
follow: bool,
) -> Result<FileAttr, Errno> {
let mut attr = MaybeUninit::uninit(); let mut attr = MaybeUninit::uninit();
EResult::from(unsafe { syscall::get_metadata(at, path.as_ref().as_str(), &mut attr, follow) })?; unsafe { syscall::get_metadata(at, path.as_ref().as_str(), &mut attr, follow) }?;
Ok(unsafe { attr.assume_init() }) EResult::Ok(unsafe { attr.assume_init() })
} }
pub fn create_directory<P: AsRef<Path>>( pub fn create_directory<P: AsRef<Path>>(at: Option<RawFd>, path: P, mode: FileMode) -> EResult<()> {
at: Option<RawFd>, unsafe { syscall::create_directory(at, path.as_ref().as_str(), mode) }?;
path: P, EResult::Ok(())
mode: FileMode,
) -> Result<(), Errno> {
EResult::from(unsafe { syscall::create_directory(at, path.as_ref().as_str(), mode) })?;
Ok(())
} }

View File

@ -8,7 +8,9 @@
new_uninit, new_uninit,
maybe_uninit_slice, maybe_uninit_slice,
inline_const, inline_const,
vec_into_raw_parts vec_into_raw_parts,
slice_ptr_get,
strict_provenance
)] )]
#![no_std] #![no_std]

View File

@ -3,10 +3,10 @@ use core::{borrow::Borrow, mem::MaybeUninit, ops::Deref};
use alloc::{borrow::ToOwned, string::String}; use alloc::{borrow::ToOwned, string::String};
use yggdrasil_rt::{io::FileAttr, path::Path, sys as syscall}; use yggdrasil_rt::{io::FileAttr, path::Path, sys as syscall};
use crate::{error::EResult, header::errno::Errno}; use crate::error::EResult;
pub trait PathExt { pub trait PathExt {
fn metadata(&self) -> Result<FileAttr, Errno>; fn metadata(&self) -> EResult<FileAttr>;
fn exists(&self) -> bool { fn exists(&self) -> bool {
self.metadata().is_ok() self.metadata().is_ok()
@ -17,11 +17,11 @@ pub trait PathExt {
pub struct PathBuf(String); pub struct PathBuf(String);
impl PathExt for Path { impl PathExt for Path {
fn metadata(&self) -> Result<FileAttr, Errno> { fn metadata(&self) -> EResult<FileAttr> {
let mut metadata = MaybeUninit::uninit(); 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() }; let metadata = unsafe { metadata.assume_init() };
Ok(metadata) EResult::Ok(metadata)
} }
} }

View File

@ -7,9 +7,9 @@ use yggdrasil_rt::{
}; };
use crate::{ use crate::{
error, error::{EResult, OptionExt},
header::{ header::{
errno::{Errno, EINVAL, ENOMEM, ESUCCESS}, errno::{EINVAL, ENOMEM, ESUCCESS},
stdio, stdio,
unistd::environ, unistd::environ,
}, },
@ -40,13 +40,14 @@ const ATEXIT_MAX: usize = 32;
static ATEXIT: Mutex<[Option<extern "C" fn()>; ATEXIT_MAX]> = static ATEXIT: Mutex<[Option<extern "C" fn()>; ATEXIT_MAX]> =
Mutex::new([const { None }; 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 mut lock = ATEXIT.lock();
let Some(slot) = lock.iter_mut().find(|p| p.is_none()) else { 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); slot.replace(f);
Ok(()) EResult::Ok(())
} }
pub unsafe fn raw_exit<T: ToExitCode>(code: T) -> ! { 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 // 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()); debug_assert_eq!(ENVS.len() + 1, C_ENVS.len());
ENVS.iter().find_map(|var| { ENVS.iter()
let var = var.as_bytes(); .find_map(|var| {
let eq_pos = memchr::memchr(b'=', var)?; let var = var.as_bytes();
let var_key = &var[..eq_pos]; let eq_pos = memchr::memchr(b'=', var)?;
let var_value = &var[eq_pos + 1..]; 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 // 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? // TODO even though char **environ exists, can this still be put under a lock?
debug_assert_eq!(ENVS.len() + 1, C_ENVS.len()); debug_assert_eq!(ENVS.len() + 1, C_ENVS.len());
if memchr::memchr(b'=', key).is_some() { if memchr::memchr(b'=', key).is_some() {
return error::set_errno_result(EINVAL); return EResult::Err(EINVAL);
} }
let index = ENVS.iter().position(|var| { 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 let Some(index) = index {
if !overwrite { if !overwrite {
// errno is not set // errno is not set
return error::set_errno_result(ESUCCESS); return EResult::Err(ESUCCESS);
} }
// Remove the old var // Remove the old var
@ -162,7 +165,7 @@ pub unsafe fn setenv_raw(key: &[u8], value: Option<&[u8]>, overwrite: bool) -> R
ENVS.remove(index); ENVS.remove(index);
} else if value.is_none() { } else if value.is_none() {
// No entry exists and unsetenv was called // No entry exists and unsetenv was called
return error::set_errno_result(ESUCCESS); return EResult::Err(ESUCCESS);
} }
if let Some(value) = value { 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()); C_ENVS.push(null_mut());
} }
Ok(()) EResult::Ok(())
} }

View File

@ -8,10 +8,7 @@ use yggdrasil_rt::{
use crate::{ use crate::{
error::EResult, error::EResult,
header::{ header::signal::{sig_handler_t, SigNumber},
errno::Errno,
signal::{sig_handler_t, SigNumber},
},
process, process,
}; };
@ -55,9 +52,9 @@ pub unsafe fn set_handler(signal: Signal, handler: Option<sig_handler_t>) -> sig
core::mem::transmute(old_handler_ptr) core::mem::transmute(old_handler_ptr)
} }
pub unsafe fn send(target: u32, signal: Signal) -> Result<(), Errno> { pub unsafe fn send(target: u32, signal: Signal) -> EResult<()> {
EResult::from(syscall::send_signal(target, signal))?; syscall::send_signal(target, signal)?;
Ok(()) EResult::Ok(())
} }
pub unsafe fn init() { 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::{ use crate::{
error::{EResult, OptionExt}, error::{EResult, OptionExt},
header::errno::Errno, header::{
errno::{EBADF, EEXIST},
fcntl::AT_FDCWD,
},
path::{PathBuf, PathExt}, path::{PathBuf, PathExt},
process::getenv, process::getenv,
}; };
@ -20,6 +29,12 @@ pub trait Nullable {
fn ensure(&self); 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> { pub struct NullTerminated<'a, T: Nullable> {
data: *const T, data: *const T,
_pd: PhantomData<&'a ()>, _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> { pub fn resolve_binary<P: AsRef<Path>>(name: P) -> EResult<PathBuf> {
let name = name.as_ref(); let name = name.as_ref();
if name.is_absolute() { if name.is_absolute() {
return EResult::Ok(PathBuf::from(name)); 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(':') { for el in env_path.split(':') {
let path = PathBuf::from_str(el).join(name); 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 // 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() { if remaining.is_some() {
todo!(); todo!();
} }
unsafe { syscall::nanosleep(amount) }; 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),
}
} }