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