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