Add Out<T> wrapper
This commit is contained in:
@@ -13,6 +13,7 @@ use crate::{
|
||||
error::{Errno, ResultExt, ResultExtPtrMut},
|
||||
fs::File,
|
||||
header::{fcntl, stdlib, string},
|
||||
out::Out,
|
||||
platform::{self, types::*, Pal, Sys},
|
||||
};
|
||||
|
||||
@@ -49,7 +50,7 @@ impl DIR {
|
||||
pub fn from_fd(fd: c_int) -> Result<Box<Self>, Errno> {
|
||||
let mut stat = sys_stat::stat::default();
|
||||
unsafe {
|
||||
Sys::fstat(fd, &mut stat)?;
|
||||
Sys::fstat(fd, Out::from_mut(&mut stat))?;
|
||||
}
|
||||
if (stat.st_mode & sys_stat::S_IFMT) != sys_stat::S_IFDIR {
|
||||
return Err(Errno(ENOTDIR));
|
||||
|
||||
@@ -5,7 +5,10 @@ use alloc::{
|
||||
};
|
||||
use core::mem;
|
||||
|
||||
use crate::platform::{types::*, Pal, Sys};
|
||||
use crate::{
|
||||
out::Out,
|
||||
platform::{types::*, Pal, Sys},
|
||||
};
|
||||
|
||||
use crate::header::{
|
||||
errno::*,
|
||||
@@ -50,7 +53,10 @@ pub fn lookup_host(host: &str) -> Result<LookupHost, c_int> {
|
||||
if let Some(dns_addr) = parse_ipv4_string(&dns_string) {
|
||||
let mut timespec = timespec::default();
|
||||
unsafe {
|
||||
Sys::clock_gettime(time::constants::CLOCK_REALTIME, &mut timespec);
|
||||
Sys::clock_gettime(
|
||||
time::constants::CLOCK_REALTIME,
|
||||
Out::from_mut(&mut timespec),
|
||||
);
|
||||
}
|
||||
let tid = (timespec.tv_nsec >> 16) as u16;
|
||||
|
||||
@@ -149,7 +155,12 @@ pub fn lookup_addr(addr: in_addr) -> Result<Vec<Vec<u8>>, c_int> {
|
||||
);
|
||||
|
||||
let mut timespec = timespec::default();
|
||||
unsafe { Sys::clock_gettime(time::constants::CLOCK_REALTIME, &mut timespec) };
|
||||
unsafe {
|
||||
Sys::clock_gettime(
|
||||
time::constants::CLOCK_REALTIME,
|
||||
Out::from_mut(&mut timespec),
|
||||
)
|
||||
};
|
||||
let tid = (timespec.tv_nsec >> 16) as u16;
|
||||
|
||||
let packet = Dns {
|
||||
|
||||
@@ -26,6 +26,7 @@ use crate::{
|
||||
unistd,
|
||||
},
|
||||
io::{self, BufRead, BufWriter, LineWriter, Read, Write},
|
||||
out::Out,
|
||||
platform::{self, types::*, Pal, Sys, WriteByte, ERRNO},
|
||||
sync::Mutex,
|
||||
};
|
||||
@@ -826,6 +827,7 @@ pub unsafe extern "C" fn getw(stream: *mut FILE) -> c_int {
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pclose(stream: *mut FILE) -> c_int {
|
||||
// TODO: rusty error handling?
|
||||
let pid = {
|
||||
let mut stream = (*stream).lock();
|
||||
|
||||
@@ -840,7 +842,7 @@ pub unsafe extern "C" fn pclose(stream: *mut FILE) -> c_int {
|
||||
fclose(stream);
|
||||
|
||||
let mut wstatus = 0;
|
||||
if Sys::waitpid(pid, &mut wstatus, 0).or_minus_one_errno() == -1 {
|
||||
if Sys::waitpid(pid, Some(Out::from_mut(&mut wstatus)), 0).or_minus_one_errno() == -1 {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ use crate::{
|
||||
wchar::*,
|
||||
},
|
||||
ld_so,
|
||||
out::Out,
|
||||
platform::{self, types::*, Pal, Sys},
|
||||
sync::Once,
|
||||
};
|
||||
@@ -760,7 +761,7 @@ where
|
||||
fn get_nstime() -> u64 {
|
||||
unsafe {
|
||||
let mut ts = mem::MaybeUninit::uninit();
|
||||
Sys::clock_gettime(CLOCK_MONOTONIC, ts.as_mut_ptr());
|
||||
Sys::clock_gettime(CLOCK_MONOTONIC, Out::from_uninit_mut(&mut ts));
|
||||
ts.assume_init().tv_nsec as u64
|
||||
}
|
||||
}
|
||||
@@ -1523,6 +1524,7 @@ pub unsafe extern "C" fn strtoull(
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/system.html>.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn system(command: *const c_char) -> c_int {
|
||||
// TODO: rusty error handling?
|
||||
//TODO: share code with popen
|
||||
|
||||
// handle shell detection on command == NULL
|
||||
@@ -1555,7 +1557,8 @@ pub unsafe extern "C" fn system(command: *const c_char) -> c_int {
|
||||
unreachable!();
|
||||
} else if child_pid > 0 {
|
||||
let mut wstatus = 0;
|
||||
if Sys::waitpid(child_pid, &mut wstatus, 0).or_minus_one_errno() == -1 {
|
||||
if Sys::waitpid(child_pid, Some(Out::from_mut(&mut wstatus)), 0).or_minus_one_errno() == -1
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
use crate::{
|
||||
error::ResultExt,
|
||||
header::sys_time::timeval,
|
||||
out::Out,
|
||||
platform::{types::*, Pal, Sys},
|
||||
};
|
||||
|
||||
@@ -84,6 +85,8 @@ pub unsafe extern "C" fn setpriority(which: c_int, who: id_t, nice: c_int) -> c_
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn getrlimit(resource: c_int, rlp: *mut rlimit) -> c_int {
|
||||
let rlp = Out::nonnull(rlp);
|
||||
|
||||
Sys::getrlimit(resource, rlp)
|
||||
.map(|()| 0)
|
||||
.or_minus_one_errno()
|
||||
@@ -98,7 +101,7 @@ pub unsafe extern "C" fn setrlimit(resource: c_int, rlp: *const rlimit) -> c_int
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn getrusage(who: c_int, r_usage: *mut rusage) -> c_int {
|
||||
Sys::getrusage(who, &mut *r_usage)
|
||||
Sys::getrusage(who, Out::nonnull(r_usage))
|
||||
.map(|()| 0)
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ use crate::{
|
||||
fcntl::{O_NOFOLLOW, O_PATH},
|
||||
time::timespec,
|
||||
},
|
||||
out::Out,
|
||||
platform::{types::*, Pal, Sys},
|
||||
};
|
||||
|
||||
@@ -83,6 +84,7 @@ pub extern "C" fn fchmod(fildes: c_int, mode: mode_t) -> c_int {
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn fstat(fildes: c_int, buf: *mut stat) -> c_int {
|
||||
let buf = Out::nonnull(buf);
|
||||
Sys::fstat(fildes, buf).map(|()| 0).or_minus_one_errno()
|
||||
}
|
||||
|
||||
@@ -93,6 +95,8 @@ pub unsafe extern "C" fn fstatat(
|
||||
buf: *mut stat,
|
||||
flags: c_int,
|
||||
) -> c_int {
|
||||
let path = CStr::from_nullable_ptr(path);
|
||||
let buf = Out::nonnull(buf);
|
||||
Sys::fstatat(fildes, path, buf, flags)
|
||||
.map(|()| 0)
|
||||
.or_minus_one_errno()
|
||||
@@ -111,6 +115,8 @@ pub unsafe extern "C" fn futimens(fd: c_int, times: *const timespec) -> c_int {
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn lstat(path: *const c_char, buf: *mut stat) -> c_int {
|
||||
let path = CStr::from_ptr(path);
|
||||
let buf = Out::nonnull(buf);
|
||||
|
||||
// TODO: Rustify
|
||||
let fd = Sys::open(path, O_PATH | O_NOFOLLOW, 0).or_minus_one_errno();
|
||||
if fd < 0 {
|
||||
@@ -159,6 +165,8 @@ pub unsafe extern "C" fn mknodat(
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn stat(file: *const c_char, buf: *mut stat) -> c_int {
|
||||
let file = CStr::from_ptr(file);
|
||||
let buf = Out::nonnull(buf);
|
||||
|
||||
// TODO: Rustify
|
||||
let fd = Sys::open(file, O_PATH, 0).or_minus_one_errno();
|
||||
if fd < 0 {
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::{
|
||||
c_str::CStr,
|
||||
error::ResultExt,
|
||||
header::fcntl::O_PATH,
|
||||
out::Out,
|
||||
platform::{types::*, Pal, Sys},
|
||||
};
|
||||
|
||||
@@ -28,12 +29,14 @@ pub struct statvfs {
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn fstatvfs(fildes: c_int, buf: *mut statvfs) -> c_int {
|
||||
let buf = Out::nonnull(buf);
|
||||
Sys::fstatvfs(fildes, buf).map(|()| 0).or_minus_one_errno()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn statvfs(file: *const c_char, buf: *mut statvfs) -> c_int {
|
||||
let file = CStr::from_ptr(file);
|
||||
let buf = Out::nonnull(buf);
|
||||
// TODO: Rustify
|
||||
let fd = Sys::open(file, O_PATH, 0).or_minus_one_errno();
|
||||
if fd < 0 {
|
||||
|
||||
@@ -6,6 +6,7 @@ use crate::{
|
||||
c_str::CStr,
|
||||
error::ResultExt,
|
||||
header::time::timespec,
|
||||
out::Out,
|
||||
platform::{types::*, Pal, PalSignal, Sys},
|
||||
};
|
||||
use core::ptr::null;
|
||||
@@ -97,7 +98,9 @@ pub unsafe extern "C" fn getitimer(which: c_int, value: *mut itimerval) -> c_int
|
||||
#[deprecated]
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn gettimeofday(tp: *mut timeval, tzp: *mut timezone) -> c_int {
|
||||
Sys::gettimeofday(tp, tzp).map(|()| 0).or_minus_one_errno()
|
||||
Sys::gettimeofday(Out::nonnull(tp), Out::nullable(tzp))
|
||||
.map(|()| 0)
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
// `select()` declared in `sys/select.h`, as specified in modern POSIX
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! sys/wait.h implementation for Redox, following
|
||||
//! http://pubs.opengroup.org/onlinepubs/7908799/xsh/syswait.h.html
|
||||
|
||||
use crate::error::ResultExt;
|
||||
use crate::{error::ResultExt, out::Out};
|
||||
//use header::sys_resource::rusage;
|
||||
use crate::platform::{types::*, Pal, Sys};
|
||||
|
||||
@@ -48,5 +48,5 @@ pub unsafe extern "C" fn wait(stat_loc: *mut c_int) -> pid_t {
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn waitpid(pid: pid_t, stat_loc: *mut c_int, options: c_int) -> pid_t {
|
||||
Sys::waitpid(pid, stat_loc, options).or_minus_one_errno()
|
||||
Sys::waitpid(pid, Out::nullable(stat_loc), options).or_minus_one_errno()
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ use crate::{
|
||||
fs::File,
|
||||
header::{errno::EOVERFLOW, fcntl::O_RDONLY, stdlib::getenv, unistd::readlink},
|
||||
io::Read,
|
||||
out::Out,
|
||||
platform::{self, types::*, Pal, Sys},
|
||||
sync::{Mutex, MutexGuard},
|
||||
};
|
||||
@@ -259,8 +260,8 @@ pub extern "C" fn clock_getcpuclockid(pid: pid_t, clock_id: *mut clockid_t) -> c
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/clock_getres.html>.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn clock_getres(clock_id: clockid_t, tp: *mut timespec) -> c_int {
|
||||
Sys::clock_getres(clock_id, tp)
|
||||
pub unsafe extern "C" fn clock_getres(clock_id: clockid_t, res: *mut timespec) -> c_int {
|
||||
Sys::clock_getres(clock_id, Out::nullable(res))
|
||||
.map(|()| 0)
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
@@ -268,7 +269,7 @@ pub unsafe extern "C" fn clock_getres(clock_id: clockid_t, tp: *mut timespec) ->
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/clock_getres.html>.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn clock_gettime(clock_id: clockid_t, tp: *mut timespec) -> c_int {
|
||||
Sys::clock_gettime(clock_id, tp)
|
||||
Sys::clock_gettime(clock_id, Out::nonnull(tp))
|
||||
.map(|()| 0)
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
@@ -449,7 +450,7 @@ pub unsafe extern "C" fn strftime(
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn time(tloc: *mut time_t) -> time_t {
|
||||
let mut ts = timespec::default();
|
||||
Sys::clock_gettime(CLOCK_REALTIME, &mut ts);
|
||||
Sys::clock_gettime(CLOCK_REALTIME, Out::from_mut(&mut ts));
|
||||
if !tloc.is_null() {
|
||||
*tloc = ts.tv_sec
|
||||
};
|
||||
@@ -646,7 +647,7 @@ fn time_zone() -> Tz {
|
||||
fn now() -> NaiveDateTime {
|
||||
let mut now = timespec::default();
|
||||
unsafe {
|
||||
Sys::clock_gettime(CLOCK_REALTIME, &mut now);
|
||||
Sys::clock_gettime(CLOCK_REALTIME, Out::from_mut(&mut now));
|
||||
}
|
||||
NaiveDateTime::from_timestamp(now.tv_sec, now.tv_nsec as _)
|
||||
}
|
||||
|
||||
+29
-12
@@ -20,6 +20,7 @@ use crate::{
|
||||
sys_ioctl, sys_resource, sys_time, sys_utsname, termios,
|
||||
time::timespec,
|
||||
},
|
||||
out::Out,
|
||||
platform::{self, types::*, Pal, Sys, ERRNO},
|
||||
};
|
||||
|
||||
@@ -35,7 +36,7 @@ pub use crate::header::stdio::{ctermid, cuserid};
|
||||
//pub use crate::header::fcntl::{faccessat, fchownat, fexecve, linkat, readlinkat, symlinkat, unlinkat};
|
||||
|
||||
use super::{
|
||||
errno::{E2BIG, ENOMEM},
|
||||
errno::{E2BIG, EINVAL, ENOMEM},
|
||||
stdio::snprintf,
|
||||
};
|
||||
|
||||
@@ -460,7 +461,7 @@ pub unsafe extern "C" fn getcwd(mut buf: *mut c_char, mut size: size_t) -> *mut
|
||||
size = stack_buf.len();
|
||||
}
|
||||
|
||||
let ret = match Sys::getcwd(buf, size) {
|
||||
let ret = match Sys::getcwd(Out::from_raw_parts(buf.cast(), size)) {
|
||||
Ok(()) => buf,
|
||||
Err(Errno(errno)) => {
|
||||
ERRNO.set(errno);
|
||||
@@ -538,7 +539,17 @@ pub extern "C" fn getgid() -> gid_t {
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getgroups.html>.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn getgroups(size: c_int, list: *mut gid_t) -> c_int {
|
||||
Sys::getgroups(size, list).or_minus_one_errno()
|
||||
(|| {
|
||||
let size = usize::try_from(size)
|
||||
// fails for negative size, but EINVAL required if size != 0 && size < actual size,
|
||||
// where the actual number of entries in the group list is obviously nonnegative
|
||||
.map_err(|_| Errno(EINVAL))?;
|
||||
|
||||
let list = Out::from_raw_parts(list, size);
|
||||
|
||||
Sys::getgroups(list)
|
||||
})()
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/gethostid.html>.
|
||||
@@ -637,19 +648,25 @@ pub extern "C" fn getppid() -> pid_t {
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getresgid.html>.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn getresgid(rgid: *mut gid_t, egid: *mut gid_t, sgid: *mut gid_t) -> c_int {
|
||||
// TODO: Out<T> write-only wrapper?
|
||||
Sys::getresgid(rgid.as_mut(), egid.as_mut(), sgid.as_mut())
|
||||
.map(|()| 0)
|
||||
.or_minus_one_errno()
|
||||
Sys::getresgid(
|
||||
Out::nullable(rgid),
|
||||
Out::nullable(egid),
|
||||
Out::nullable(sgid),
|
||||
)
|
||||
.map(|()| 0)
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getresuid.html>.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn getresuid(ruid: *mut uid_t, euid: *mut uid_t, suid: *mut uid_t) -> c_int {
|
||||
// TODO: Out<T> write-only wrapper?
|
||||
Sys::getresuid(ruid.as_mut(), euid.as_mut(), suid.as_mut())
|
||||
.map(|()| 0)
|
||||
.or_minus_one_errno()
|
||||
Sys::getresuid(
|
||||
Out::nullable(ruid),
|
||||
Out::nullable(euid),
|
||||
Out::nullable(suid),
|
||||
)
|
||||
.map(|()| 0)
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/getsid.html>.
|
||||
@@ -770,7 +787,7 @@ pub unsafe extern "C" fn pipe(fildes: *mut c_int) -> c_int {
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/pipe.html>.
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn pipe2(fildes: *mut c_int, flags: c_int) -> c_int {
|
||||
Sys::pipe2(slice::from_raw_parts_mut(fildes, 2), flags)
|
||||
Sys::pipe2(Out::nonnull(fildes.cast::<[c_int; 2]>()), flags)
|
||||
.map(|()| 0)
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
+2
-3
@@ -25,6 +25,7 @@ use crate::{
|
||||
unistd::F_OK,
|
||||
},
|
||||
ld_so::dso::{resolve_sym, SymbolBinding},
|
||||
out::Out,
|
||||
platform::{
|
||||
types::{c_int, c_uint, c_void},
|
||||
Pal, Sys,
|
||||
@@ -88,9 +89,7 @@ impl MmapFile {
|
||||
fn open(path: CStr, oflag: c_int) -> core::result::Result<Self, Errno> {
|
||||
let fd = Sys::open(path, oflag, 0 /* mode */)?;
|
||||
let mut stat = crate::header::sys_stat::stat::default();
|
||||
unsafe {
|
||||
Sys::fstat(fd, &mut stat)?;
|
||||
}
|
||||
Sys::fstat(fd, Out::from_mut(&mut stat))?;
|
||||
|
||||
let size = stat.st_size as usize;
|
||||
let ptr = unsafe {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#![feature(pointer_is_aligned_to)]
|
||||
#![feature(ptr_as_uninit)]
|
||||
#![feature(slice_as_chunks)]
|
||||
#![feature(slice_ptr_get)]
|
||||
#![feature(stmt_expr_attributes)]
|
||||
#![feature(strict_provenance)]
|
||||
#![feature(sync_unsafe_cell)]
|
||||
@@ -63,6 +64,7 @@ pub mod header;
|
||||
pub mod io;
|
||||
pub mod iter;
|
||||
pub mod ld_so;
|
||||
pub mod out;
|
||||
pub mod platform;
|
||||
pub mod pthread;
|
||||
pub mod start;
|
||||
|
||||
+167
@@ -0,0 +1,167 @@
|
||||
//! Wrapper for the "out pointer" pattern.
|
||||
//!
|
||||
//! This is functionally equivalent to `&Cell<MaybeUninit<T>>` except the only allowed operation is
|
||||
//! to write a `T`. Using `MaybeUninit` directly would not have been equally general; a
|
||||
//! `&mut MaybeUninit<T>` could never then be created from a `&mut T` and passed to safe code,
|
||||
//! which can safely replace it with `MaybeUninit::uninit` and make the existence of `&mut T` UB.
|
||||
//!
|
||||
//! As for the "`&Cell<...>`", this is to be slightly weaker than Rust's normally strict
|
||||
//! requirement that `&mut` references are never aliased, which can typically not be assumed when
|
||||
//! getting pointers from C.
|
||||
|
||||
use core::{cell::UnsafeCell, fmt, marker::PhantomData, mem::MaybeUninit, ptr::NonNull};
|
||||
|
||||
/// Wrapper for write-only "out pointers" that are safe to write to
|
||||
// TODO: We may want to change this to &mut MaybeUninit, or have a generic parameter deciding
|
||||
// whether it should be noalias or not
|
||||
#[derive(Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
pub struct Out<'a, T: ?Sized> {
|
||||
ptr: NonNull<T>,
|
||||
_marker: PhantomData<&'a UnsafeCell<T>>,
|
||||
}
|
||||
impl<'a, T: ?Sized> Out<'a, T> {
|
||||
/// # Safety
|
||||
///
|
||||
/// - pointer must either be NULL, or be valid for the duration of lifetime `'a`
|
||||
#[inline]
|
||||
pub unsafe fn nullable(ptr: *mut T) -> Option<Self> {
|
||||
Some(Self {
|
||||
ptr: NonNull::new(ptr)?,
|
||||
_marker: PhantomData,
|
||||
})
|
||||
}
|
||||
/// # Safety
|
||||
///
|
||||
/// - pointer must be valid for the duration of lifetime `'a`
|
||||
#[inline]
|
||||
pub unsafe fn nonnull(ptr: *mut T) -> Self {
|
||||
if cfg!(debug_assertions) {
|
||||
assert!(!ptr.is_null());
|
||||
}
|
||||
Self {
|
||||
ptr: NonNull::new_unchecked(ptr),
|
||||
_marker: PhantomData,
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
pub fn from_mut(r: &'a mut T) -> Self {
|
||||
// SAFETY:
|
||||
//
|
||||
// - `r` will obviously have the same lifetime as Self
|
||||
// - a Rust reference is obviously valid as a pointer, and the lifetime is tied to that of
|
||||
// this struct
|
||||
unsafe { Self::nonnull(r) }
|
||||
}
|
||||
#[inline]
|
||||
pub fn as_mut_ptr(&mut self) -> *mut T {
|
||||
self.ptr.as_ptr()
|
||||
}
|
||||
}
|
||||
impl<'a, T> Out<'a, T> {
|
||||
#[inline]
|
||||
pub fn from_uninit_mut(r: &'a mut MaybeUninit<T>) -> Self {
|
||||
// SAFETY:
|
||||
//
|
||||
// Same as for from_mut. It's fine if *r is uninitialized, as this wrapper only allows
|
||||
// writes.
|
||||
unsafe { Self::nonnull(r.as_mut_ptr()) }
|
||||
}
|
||||
#[inline]
|
||||
pub fn write(&mut self, t: T) {
|
||||
unsafe {
|
||||
self.ptr.as_ptr().write(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<'a, T> Out<'a, [T]> {
|
||||
/// # Safety
|
||||
///
|
||||
/// If `len > 0`, `ptr` be valid for `len` elements of `T`, during lifetime `'a`.
|
||||
pub unsafe fn from_raw_parts(ptr: *mut T, len: usize) -> Self {
|
||||
// Empty slices must be non-NULL in Rust, but C typically does not force this for
|
||||
// pointer-length pairs.
|
||||
let ptr = if len == 0 {
|
||||
core::ptr::dangling_mut::<T>()
|
||||
} else {
|
||||
ptr
|
||||
};
|
||||
Self::nonnull(core::slice::from_raw_parts_mut(ptr, len))
|
||||
}
|
||||
pub fn len(&self) -> usize {
|
||||
self.ptr.as_ptr().len()
|
||||
}
|
||||
// TODO: Maybe strengthen lifetimes?
|
||||
#[inline]
|
||||
pub fn split_at_checked<'b>(&'b mut self, n: usize) -> Option<[Out<'b, [T]>; 2]> {
|
||||
let l = self.ptr.len();
|
||||
if n > l {
|
||||
return None;
|
||||
}
|
||||
Some([
|
||||
Out {
|
||||
ptr: unsafe {
|
||||
NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(
|
||||
self.ptr.as_mut_ptr(),
|
||||
n,
|
||||
))
|
||||
},
|
||||
_marker: PhantomData,
|
||||
},
|
||||
Out {
|
||||
ptr: unsafe {
|
||||
NonNull::new_unchecked(core::ptr::slice_from_raw_parts_mut(
|
||||
self.ptr.as_mut_ptr().add(n),
|
||||
l - n,
|
||||
))
|
||||
},
|
||||
_marker: PhantomData,
|
||||
},
|
||||
])
|
||||
}
|
||||
#[inline]
|
||||
pub fn copy_from_slice(&mut self, src: &[T])
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
assert_eq!(
|
||||
self.ptr.len(),
|
||||
src.len(),
|
||||
"Out::copy_from_slice size mismatch"
|
||||
);
|
||||
unsafe {
|
||||
// SAFETY:
|
||||
//
|
||||
// - we have already know from the existence of self that the slice is a valid writable
|
||||
// pointer
|
||||
// - src is similarly also a valid readable pointer of the same type
|
||||
// - because of `T: Copy`, it is valid to copy bytes directly
|
||||
// - although self.ptr may alias, src must not alias with any writable pointer, and the
|
||||
// Copy bound ensures T cannot have interior mutability since `UnsafeCell: !Copy`
|
||||
self.ptr
|
||||
.as_mut_ptr()
|
||||
.copy_from_nonoverlapping(src.as_ptr(), src.len());
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO: different trait?
|
||||
impl<T: plain::Plain> Out<'_, [T]> {
|
||||
pub fn zero(&mut self) {
|
||||
let l = self.ptr.len();
|
||||
unsafe {
|
||||
// SAFETY:
|
||||
// - already know the pointer is valid up to its length
|
||||
// - the Plain trait ensures zero is a valid bit pattern
|
||||
self.ptr.as_mut_ptr().write_bytes(0, l)
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T: ?Sized> fmt::Pointer for Out<'_, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{:p}", self.ptr)
|
||||
}
|
||||
}
|
||||
impl<T: ?Sized> fmt::Debug for Out<'_, T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "[Out: {:p}]", self.ptr)
|
||||
}
|
||||
}
|
||||
+109
-57
@@ -1,4 +1,4 @@
|
||||
use crate::{header::errno::EOPNOTSUPP, io::Write};
|
||||
use crate::{header::errno::EOPNOTSUPP, io::Write, out::Out};
|
||||
use core::{arch::asm, ptr};
|
||||
|
||||
use super::{types::*, Pal, ERRNO};
|
||||
@@ -109,12 +109,19 @@ impl Pal for Sys {
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
unsafe fn clock_getres(clk_id: clockid_t, tp: *mut timespec) -> Result<()> {
|
||||
e_raw(syscall!(CLOCK_GETRES, clk_id, tp)).map(|_| ())
|
||||
fn clock_getres(clk_id: clockid_t, res: Option<Out<timespec>>) -> Result<()> {
|
||||
e_raw(unsafe {
|
||||
syscall!(
|
||||
CLOCK_GETRES,
|
||||
clk_id,
|
||||
res.map_or(core::ptr::null_mut(), |mut p| p.as_mut_ptr())
|
||||
)
|
||||
})
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
unsafe fn clock_gettime(clk_id: clockid_t, tp: *mut timespec) -> Result<()> {
|
||||
e_raw(syscall!(CLOCK_GETTIME, clk_id, tp)).map(|_| ())
|
||||
fn clock_gettime(clk_id: clockid_t, mut tp: Out<timespec>) -> Result<()> {
|
||||
e_raw(unsafe { syscall!(CLOCK_GETTIME, clk_id, tp.as_mut_ptr()) }).map(|_| ())
|
||||
}
|
||||
|
||||
unsafe fn clock_settime(clk_id: clockid_t, tp: *const timespec) -> Result<()> {
|
||||
@@ -176,42 +183,59 @@ impl Pal for Sys {
|
||||
e_raw(unsafe { syscall!(FLOCK, fd, operation) }).map(|_| ())
|
||||
}
|
||||
|
||||
unsafe fn fstat(fildes: c_int, buf: *mut stat) -> Result<()> {
|
||||
fn fstat(fildes: c_int, mut buf: Out<stat>) -> Result<()> {
|
||||
let empty = b"\0";
|
||||
let empty_ptr = empty.as_ptr() as *const c_char;
|
||||
e_raw(unsafe { syscall!(NEWFSTATAT, fildes, empty_ptr, buf, AT_EMPTY_PATH) }).map(|_| ())
|
||||
e_raw(unsafe {
|
||||
syscall!(
|
||||
NEWFSTATAT,
|
||||
fildes,
|
||||
empty_ptr,
|
||||
buf.as_mut_ptr(),
|
||||
AT_EMPTY_PATH
|
||||
)
|
||||
})
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
unsafe fn fstatat(
|
||||
fildes: c_int,
|
||||
path: *const c_char,
|
||||
buf: *mut stat,
|
||||
flags: c_int,
|
||||
) -> Result<()> {
|
||||
e_raw(unsafe { syscall!(NEWFSTATAT, fildes, path, buf, flags) }).map(|_| ())
|
||||
fn fstatat(fildes: c_int, path: Option<CStr>, mut buf: Out<stat>, flags: c_int) -> Result<()> {
|
||||
e_raw(unsafe {
|
||||
syscall!(
|
||||
NEWFSTATAT,
|
||||
fildes,
|
||||
path.map_or(core::ptr::null(), |s| s.as_ptr()),
|
||||
buf.as_mut_ptr(),
|
||||
flags
|
||||
)
|
||||
})
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
unsafe fn fstatvfs(fildes: c_int, buf: *mut statvfs) -> Result<()> {
|
||||
fn fstatvfs(fildes: c_int, mut buf: Out<statvfs>) -> Result<()> {
|
||||
let buf = buf.as_mut_ptr();
|
||||
|
||||
let mut kbuf = linux_statfs::default();
|
||||
let kbuf_ptr = &mut kbuf as *mut linux_statfs;
|
||||
e_raw(syscall!(FSTATFS, fildes, kbuf_ptr))?;
|
||||
e_raw(unsafe { syscall!(FSTATFS, fildes, kbuf_ptr) })?;
|
||||
|
||||
if !buf.is_null() {
|
||||
(*buf).f_bsize = kbuf.f_bsize as c_ulong;
|
||||
(*buf).f_frsize = if kbuf.f_frsize != 0 {
|
||||
kbuf.f_frsize
|
||||
} else {
|
||||
kbuf.f_bsize
|
||||
} as c_ulong;
|
||||
(*buf).f_blocks = kbuf.f_blocks;
|
||||
(*buf).f_bfree = kbuf.f_bfree;
|
||||
(*buf).f_bavail = kbuf.f_bavail;
|
||||
(*buf).f_files = kbuf.f_files;
|
||||
(*buf).f_ffree = kbuf.f_ffree;
|
||||
(*buf).f_favail = kbuf.f_ffree;
|
||||
(*buf).f_fsid = kbuf.f_fsid as c_ulong;
|
||||
(*buf).f_flag = kbuf.f_flags as c_ulong;
|
||||
(*buf).f_namemax = kbuf.f_namelen as c_ulong;
|
||||
unsafe {
|
||||
(*buf).f_bsize = kbuf.f_bsize as c_ulong;
|
||||
(*buf).f_frsize = if kbuf.f_frsize != 0 {
|
||||
kbuf.f_frsize
|
||||
} else {
|
||||
kbuf.f_bsize
|
||||
} as c_ulong;
|
||||
(*buf).f_blocks = kbuf.f_blocks;
|
||||
(*buf).f_bfree = kbuf.f_bfree;
|
||||
(*buf).f_bavail = kbuf.f_bavail;
|
||||
(*buf).f_files = kbuf.f_files;
|
||||
(*buf).f_ffree = kbuf.f_ffree;
|
||||
(*buf).f_favail = kbuf.f_ffree;
|
||||
(*buf).f_fsid = kbuf.f_fsid as c_ulong;
|
||||
(*buf).f_flag = kbuf.f_flags as c_ulong;
|
||||
(*buf).f_namemax = kbuf.f_namelen as c_ulong;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@@ -268,8 +292,14 @@ impl Pal for Sys {
|
||||
e_raw(unsafe { syscall!(UTIMENSAT, AT_FDCWD, path.as_ptr(), times, 0) }).map(|_| ())
|
||||
}
|
||||
|
||||
unsafe fn getcwd(buf: *mut c_char, size: size_t) -> Result<()> {
|
||||
e_raw(unsafe { syscall!(GETCWD, buf, size) })?;
|
||||
fn getcwd(mut buf: Out<[u8]>) -> Result<()> {
|
||||
e_raw(unsafe {
|
||||
syscall!(
|
||||
GETCWD,
|
||||
buf.as_mut_ptr().as_mut_ptr(),
|
||||
buf.as_mut_ptr().len()
|
||||
)
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -300,8 +330,14 @@ impl Pal for Sys {
|
||||
unsafe { syscall!(GETGID) as gid_t }
|
||||
}
|
||||
|
||||
unsafe fn getgroups(size: c_int, list: *mut gid_t) -> Result<c_int> {
|
||||
Ok(e_raw(unsafe { syscall!(GETGROUPS, size, list) })? as c_int)
|
||||
fn getgroups(mut list: Out<[gid_t]>) -> Result<c_int> {
|
||||
Ok(e_raw(unsafe {
|
||||
syscall!(
|
||||
GETGROUPS,
|
||||
list.len() as c_int,
|
||||
list.as_mut_ptr().as_mut_ptr()
|
||||
)
|
||||
})? as c_int)
|
||||
}
|
||||
|
||||
fn getpagesize() -> usize {
|
||||
@@ -330,36 +366,36 @@ impl Pal for Sys {
|
||||
e_raw(unsafe { syscall!(GETRANDOM, buf.as_mut_ptr(), buf.len(), flags) })
|
||||
}
|
||||
|
||||
unsafe fn getrlimit(resource: c_int, rlim: *mut rlimit) -> Result<()> {
|
||||
e_raw(syscall!(GETRLIMIT, resource, rlim)).map(|_| ())
|
||||
fn getrlimit(resource: c_int, mut rlim: Out<rlimit>) -> Result<()> {
|
||||
e_raw(unsafe { syscall!(GETRLIMIT, resource, rlim.as_mut_ptr()) }).map(|_| ())
|
||||
}
|
||||
|
||||
fn getresgid(
|
||||
rgid: Option<&mut gid_t>,
|
||||
egid: Option<&mut gid_t>,
|
||||
sgid: Option<&mut gid_t>,
|
||||
rgid: Option<Out<gid_t>>,
|
||||
egid: Option<Out<gid_t>>,
|
||||
sgid: Option<Out<gid_t>>,
|
||||
) -> Result<()> {
|
||||
unsafe {
|
||||
e_raw(syscall!(
|
||||
GETRESGID,
|
||||
rgid.map_or(0, |r| r as *const _ as usize),
|
||||
egid.map_or(0, |r| r as *const _ as usize),
|
||||
sgid.map_or(0, |r| r as *const _ as usize)
|
||||
rgid.map_or(0, |mut r| r.as_mut_ptr() as usize),
|
||||
egid.map_or(0, |mut r| r.as_mut_ptr() as usize),
|
||||
sgid.map_or(0, |mut r| r.as_mut_ptr() as usize)
|
||||
))
|
||||
.map(|_| ())
|
||||
}
|
||||
}
|
||||
fn getresuid(
|
||||
ruid: Option<&mut uid_t>,
|
||||
euid: Option<&mut uid_t>,
|
||||
suid: Option<&mut uid_t>,
|
||||
ruid: Option<Out<uid_t>>,
|
||||
euid: Option<Out<uid_t>>,
|
||||
suid: Option<Out<uid_t>>,
|
||||
) -> Result<()> {
|
||||
unsafe {
|
||||
e_raw(syscall!(
|
||||
GETRESUID,
|
||||
ruid.map_or(0, |r| r as *const _ as usize),
|
||||
euid.map_or(0, |r| r as *const _ as usize),
|
||||
suid.map_or(0, |r| r as *const _ as usize)
|
||||
ruid.map_or(0, |mut r| r.as_mut_ptr() as usize),
|
||||
euid.map_or(0, |mut r| r.as_mut_ptr() as usize),
|
||||
suid.map_or(0, |mut r| r.as_mut_ptr() as usize)
|
||||
))
|
||||
.map(|_| ())
|
||||
}
|
||||
@@ -369,8 +405,8 @@ impl Pal for Sys {
|
||||
e_raw(syscall!(SETRLIMIT, resource, rlimit)).map(|_| ())
|
||||
}
|
||||
|
||||
fn getrusage(who: c_int, r_usage: &mut rusage) -> Result<()> {
|
||||
e_raw(unsafe { syscall!(GETRUSAGE, who, r_usage as *mut rusage) })?;
|
||||
fn getrusage(who: c_int, mut r_usage: Out<rusage>) -> Result<()> {
|
||||
e_raw(unsafe { syscall!(GETRUSAGE, who, r_usage.as_mut_ptr()) })?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -383,8 +419,15 @@ impl Pal for Sys {
|
||||
unsafe { syscall!(GETTID) as pid_t }
|
||||
}
|
||||
|
||||
unsafe fn gettimeofday(tp: *mut timeval, tzp: *mut timezone) -> Result<()> {
|
||||
e_raw(unsafe { syscall!(GETTIMEOFDAY, tp, tzp) }).map(|_| ())
|
||||
fn gettimeofday(mut tp: Out<timeval>, tzp: Option<Out<timezone>>) -> Result<()> {
|
||||
e_raw(unsafe {
|
||||
syscall!(
|
||||
GETTIMEOFDAY,
|
||||
tp.as_mut_ptr(),
|
||||
tzp.map_or(0, |mut p| p.as_mut_ptr() as usize)
|
||||
)
|
||||
})
|
||||
.map(|_| ())
|
||||
}
|
||||
|
||||
fn getuid() -> uid_t {
|
||||
@@ -498,7 +541,7 @@ impl Pal for Sys {
|
||||
.map(|fd| fd as c_int)
|
||||
}
|
||||
|
||||
fn pipe2(fildes: &mut [c_int], flags: c_int) -> Result<()> {
|
||||
fn pipe2(mut fildes: Out<[c_int; 2]>, flags: c_int) -> Result<()> {
|
||||
e_raw(unsafe { syscall!(PIPE2, fildes.as_mut_ptr(), flags) }).map(|_| ())
|
||||
}
|
||||
|
||||
@@ -647,15 +690,24 @@ impl Pal for Sys {
|
||||
}
|
||||
|
||||
unsafe fn uname(utsname: *mut utsname) -> Result<()> {
|
||||
e_raw(syscall!(UNAME, utsname, 0)).map(|_| ())
|
||||
e_raw(unsafe { syscall!(UNAME, utsname, 0) }).map(|_| ())
|
||||
}
|
||||
|
||||
fn unlink(path: CStr) -> Result<()> {
|
||||
e_raw(unsafe { syscall!(UNLINKAT, AT_FDCWD, path.as_ptr(), 0) }).map(|_| ())
|
||||
}
|
||||
|
||||
unsafe fn waitpid(pid: pid_t, stat_loc: *mut c_int, options: c_int) -> Result<pid_t> {
|
||||
e_raw(unsafe { syscall!(WAIT4, pid, stat_loc, options, 0) }).map(|p| p as pid_t)
|
||||
fn waitpid(pid: pid_t, stat_loc: Option<Out<c_int>>, options: c_int) -> Result<pid_t> {
|
||||
e_raw(unsafe {
|
||||
syscall!(
|
||||
WAIT4,
|
||||
pid,
|
||||
stat_loc.map_or(core::ptr::null_mut(), |mut o| o.as_mut_ptr()),
|
||||
options,
|
||||
0
|
||||
)
|
||||
})
|
||||
.map(|p| p as pid_t)
|
||||
}
|
||||
|
||||
fn write(fildes: c_int, buf: &[u8]) -> Result<usize> {
|
||||
|
||||
+20
-23
@@ -10,6 +10,7 @@ use crate::{
|
||||
sys_utsname::utsname,
|
||||
time::timespec,
|
||||
},
|
||||
out::Out,
|
||||
pthread,
|
||||
};
|
||||
|
||||
@@ -39,9 +40,10 @@ pub trait Pal {
|
||||
|
||||
fn chown(path: CStr, owner: uid_t, group: gid_t) -> Result<()>;
|
||||
|
||||
unsafe fn clock_getres(clk_id: clockid_t, tp: *mut timespec) -> Result<()>;
|
||||
fn clock_getres(clk_id: clockid_t, tp: Option<Out<timespec>>) -> Result<()>;
|
||||
|
||||
unsafe fn clock_gettime(clk_id: clockid_t, tp: *mut timespec) -> Result<()>;
|
||||
// TODO: maybe remove tp and change signature to -> Result<timespec>?
|
||||
fn clock_gettime(clk_id: clockid_t, tp: Out<timespec>) -> Result<()>;
|
||||
|
||||
unsafe fn clock_settime(clk_id: clockid_t, tp: *const timespec) -> Result<()>;
|
||||
|
||||
@@ -72,16 +74,11 @@ pub trait Pal {
|
||||
|
||||
fn flock(fd: c_int, operation: c_int) -> Result<()>;
|
||||
|
||||
unsafe fn fstat(fildes: c_int, buf: *mut stat) -> Result<()>;
|
||||
fn fstat(fildes: c_int, buf: Out<stat>) -> Result<()>;
|
||||
|
||||
unsafe fn fstatat(
|
||||
fildes: c_int,
|
||||
path: *const c_char,
|
||||
buf: *mut stat,
|
||||
flags: c_int,
|
||||
) -> Result<()>;
|
||||
fn fstatat(fildes: c_int, path: Option<CStr>, buf: Out<stat>, flags: c_int) -> Result<()>;
|
||||
|
||||
unsafe fn fstatvfs(fildes: c_int, buf: *mut statvfs) -> Result<()>;
|
||||
fn fstatvfs(fildes: c_int, buf: Out<statvfs>) -> Result<()>;
|
||||
|
||||
fn fcntl(fildes: c_int, cmd: c_int, arg: c_ulonglong) -> Result<c_int>;
|
||||
|
||||
@@ -100,7 +97,7 @@ pub trait Pal {
|
||||
|
||||
unsafe fn utimens(path: CStr, times: *const timespec) -> Result<()>;
|
||||
|
||||
unsafe fn getcwd(buf: *mut c_char, size: size_t) -> Result<()>;
|
||||
fn getcwd(buf: Out<[u8]>) -> Result<()>;
|
||||
|
||||
fn getdents(fd: c_int, buf: &mut [u8], opaque_offset: u64) -> Result<usize>;
|
||||
fn dir_seek(fd: c_int, opaque_offset: u64) -> Result<()>;
|
||||
@@ -119,7 +116,7 @@ pub trait Pal {
|
||||
// Always successful
|
||||
fn getgid() -> gid_t;
|
||||
|
||||
unsafe fn getgroups(size: c_int, list: *mut gid_t) -> Result<c_int>;
|
||||
fn getgroups(list: Out<[gid_t]>) -> Result<c_int>;
|
||||
|
||||
/* Note that this is distinct from the legacy POSIX function
|
||||
* getpagesize(), which returns a c_int. On some Linux platforms,
|
||||
@@ -139,29 +136,29 @@ pub trait Pal {
|
||||
fn getrandom(buf: &mut [u8], flags: c_uint) -> Result<usize>;
|
||||
|
||||
fn getresgid(
|
||||
rgid: Option<&mut gid_t>,
|
||||
egid: Option<&mut gid_t>,
|
||||
sgid: Option<&mut gid_t>,
|
||||
rgid: Option<Out<gid_t>>,
|
||||
egid: Option<Out<gid_t>>,
|
||||
sgid: Option<Out<gid_t>>,
|
||||
) -> Result<()>;
|
||||
|
||||
fn getresuid(
|
||||
ruid: Option<&mut uid_t>,
|
||||
euid: Option<&mut uid_t>,
|
||||
suid: Option<&mut uid_t>,
|
||||
ruid: Option<Out<uid_t>>,
|
||||
euid: Option<Out<uid_t>>,
|
||||
suid: Option<Out<uid_t>>,
|
||||
) -> Result<()>;
|
||||
|
||||
unsafe fn getrlimit(resource: c_int, rlim: *mut rlimit) -> Result<()>;
|
||||
fn getrlimit(resource: c_int, rlim: Out<rlimit>) -> Result<()>;
|
||||
|
||||
unsafe fn setrlimit(resource: c_int, rlim: *const rlimit) -> Result<()>;
|
||||
|
||||
fn getrusage(who: c_int, r_usage: &mut rusage) -> Result<()>;
|
||||
fn getrusage(who: c_int, r_usage: Out<rusage>) -> Result<()>;
|
||||
|
||||
fn getsid(pid: pid_t) -> Result<pid_t>;
|
||||
|
||||
// Always successful
|
||||
fn gettid() -> pid_t;
|
||||
|
||||
unsafe fn gettimeofday(tp: *mut timeval, tzp: *mut timezone) -> Result<()>;
|
||||
fn gettimeofday(tp: Out<timeval>, tzp: Option<Out<timezone>>) -> Result<()>;
|
||||
|
||||
fn getuid() -> uid_t;
|
||||
|
||||
@@ -216,7 +213,7 @@ pub trait Pal {
|
||||
|
||||
fn open(path: CStr, oflag: c_int, mode: mode_t) -> Result<c_int>;
|
||||
|
||||
fn pipe2(fildes: &mut [c_int], flags: c_int) -> Result<()>;
|
||||
fn pipe2(fildes: Out<[c_int; 2]>, flags: c_int) -> Result<()>;
|
||||
|
||||
unsafe fn rlct_clone(stack: *mut usize) -> Result<pthread::OsTid, Errno>;
|
||||
unsafe fn rlct_kill(os_tid: pthread::OsTid, signal: usize) -> Result<()>;
|
||||
@@ -259,7 +256,7 @@ pub trait Pal {
|
||||
|
||||
fn unlink(path: CStr) -> Result<()>;
|
||||
|
||||
unsafe fn waitpid(pid: pid_t, stat_loc: *mut c_int, options: c_int) -> Result<pid_t>;
|
||||
fn waitpid(pid: pid_t, stat_loc: Option<Out<c_int>>, options: c_int) -> Result<pid_t>;
|
||||
|
||||
fn write(fildes: c_int, buf: &[u8]) -> Result<usize>;
|
||||
fn pwrite(fildes: c_int, buf: &[u8], offset: off_t) -> Result<usize>;
|
||||
|
||||
@@ -19,16 +19,13 @@ pub unsafe extern "C" fn redox_fpath(fd: c_int, buf: *mut c_void, count: size_t)
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
pub fn pipe2(fds: &mut [c_int], flags: usize) -> syscall::error::Result<()> {
|
||||
let fds =
|
||||
<&mut [c_int; 2]>::try_from(fds).expect("expected Pal pipe2 to have validated pipe2 array");
|
||||
|
||||
pub fn pipe2(flags: usize) -> syscall::error::Result<[c_int; 2]> {
|
||||
let mut read_fd = FdGuard::new(syscall::open("/scheme/pipe", flags)?);
|
||||
let mut write_fd = FdGuard::new(syscall::dup(*read_fd, b"write")?);
|
||||
syscall::fcntl(*write_fd, F_SETFL, flags)?;
|
||||
syscall::fcntl(*write_fd, F_SETFD, flags)?;
|
||||
|
||||
*fds = [
|
||||
let fds = [
|
||||
c_int::try_from(*read_fd).map_err(|_| Error::new(EMFILE))?,
|
||||
c_int::try_from(*write_fd).map_err(|_| Error::new(EMFILE))?,
|
||||
];
|
||||
@@ -36,5 +33,5 @@ pub fn pipe2(fds: &mut [c_int], flags: usize) -> syscall::error::Result<()> {
|
||||
read_fd.take();
|
||||
write_fd.take();
|
||||
|
||||
Ok(())
|
||||
Ok(fds)
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ use crate::{
|
||||
sys_uio::iovec,
|
||||
time::timespec,
|
||||
},
|
||||
out::Out,
|
||||
platform::{types::*, PalSignal},
|
||||
};
|
||||
|
||||
@@ -111,11 +112,13 @@ pub unsafe fn futimens(fd: usize, times: *const timespec) -> syscall::Result<()>
|
||||
syscall::futimens(fd as usize, ×)?;
|
||||
Ok(())
|
||||
}
|
||||
pub unsafe fn clock_gettime(clock: usize, tp: *mut timespec) -> syscall::Result<()> {
|
||||
let mut redox_tp = syscall::TimeSpec::from(&*tp);
|
||||
pub fn clock_gettime(clock: usize, mut tp: Out<timespec>) -> syscall::Result<()> {
|
||||
let mut redox_tp = syscall::TimeSpec::default();
|
||||
syscall::clock_gettime(clock as usize, &mut redox_tp)?;
|
||||
(*tp).tv_sec = redox_tp.tv_sec as time_t;
|
||||
(*tp).tv_nsec = redox_tp.tv_nsec as c_long;
|
||||
tp.write(timespec {
|
||||
tv_sec: redox_tp.tv_sec as time_t,
|
||||
tv_nsec: redox_tp.tv_nsec as c_long,
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -331,7 +334,7 @@ pub unsafe extern "C" fn redox_munmap_v1(addr: *mut (), unaligned_len: usize) ->
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn redox_clock_gettime_v1(clock: usize, ts: *mut timespec) -> RawResult {
|
||||
Error::mux(clock_gettime(clock, ts).map(|()| 0))
|
||||
Error::mux(clock_gettime(clock, Out::nonnull(ts)).map(|()| 0))
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
|
||||
+67
-63
@@ -25,7 +25,8 @@ use crate::{
|
||||
EBADF, EBADFD, EBADR, EINTR, EINVAL, EIO, ENAMETOOLONG, ENOENT, ENOMEM, ENOSYS,
|
||||
EOPNOTSUPP, EPERM, ERANGE,
|
||||
},
|
||||
fcntl, limits,
|
||||
fcntl::{self, AT_FDCWD, O_RDONLY},
|
||||
limits,
|
||||
sys_mman::{MAP_ANONYMOUS, MAP_FAILED, PROT_READ, PROT_WRITE},
|
||||
sys_random,
|
||||
sys_resource::{rlimit, rusage, RLIM_INFINITY},
|
||||
@@ -38,6 +39,7 @@ use crate::{
|
||||
unistd::{F_OK, R_OK, W_OK, X_OK},
|
||||
},
|
||||
io::{self, prelude::*, BufReader},
|
||||
out::Out,
|
||||
sync::rwlock::RwLock,
|
||||
};
|
||||
|
||||
@@ -178,13 +180,16 @@ impl Pal for Sys {
|
||||
Self::fchown(*file, owner, group)
|
||||
}
|
||||
|
||||
unsafe fn clock_getres(clk_id: clockid_t, tp: *mut timespec) -> Result<()> {
|
||||
fn clock_getres(clk_id: clockid_t, res: Option<Out<timespec>>) -> Result<()> {
|
||||
// TODO
|
||||
eprintln!("relibc clock_getres({}, {:p}): not implemented", clk_id, tp);
|
||||
eprintln!(
|
||||
"relibc clock_getres({}, {:?}): not implemented",
|
||||
clk_id, res
|
||||
);
|
||||
Err(Errno(ENOSYS))
|
||||
}
|
||||
|
||||
unsafe fn clock_gettime(clk_id: clockid_t, tp: *mut timespec) -> Result<()> {
|
||||
fn clock_gettime(clk_id: clockid_t, tp: Out<timespec>) -> Result<()> {
|
||||
libredox::clock_gettime(clk_id as usize, tp)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -281,26 +286,25 @@ impl Pal for Sys {
|
||||
Ok(clone::fork_impl(&redox_rt::proc::ForkArgs::Managed)? as pid_t)
|
||||
}
|
||||
|
||||
unsafe fn fstat(fildes: c_int, buf: *mut stat) -> Result<()> {
|
||||
libredox::fstat(fildes as usize, buf)?;
|
||||
fn fstat(fildes: c_int, mut buf: Out<stat>) -> Result<()> {
|
||||
unsafe {
|
||||
libredox::fstat(fildes as usize, buf.as_mut_ptr())?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn fstatat(
|
||||
dirfd: c_int,
|
||||
path: *const c_char,
|
||||
buf: *mut stat,
|
||||
flags: c_int,
|
||||
) -> Result<()> {
|
||||
let path = CStr::from_nullable_ptr(path)
|
||||
fn fstatat(dirfd: c_int, path: Option<CStr>, buf: Out<stat>, flags: c_int) -> Result<()> {
|
||||
let path = path
|
||||
.and_then(|cs| str::from_utf8(cs.to_bytes()).ok())
|
||||
.ok_or(Errno(ENOENT))?;
|
||||
let file = cap_path_at(dirfd, path, flags, 0)?;
|
||||
Sys::fstat(*file, buf)
|
||||
}
|
||||
|
||||
unsafe fn fstatvfs(fildes: c_int, buf: *mut statvfs) -> Result<()> {
|
||||
libredox::fstatvfs(fildes as usize, buf)?;
|
||||
fn fstatvfs(fildes: c_int, mut buf: Out<statvfs>) -> Result<()> {
|
||||
unsafe {
|
||||
libredox::fstatvfs(fildes as usize, buf.as_mut_ptr())?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -338,15 +342,8 @@ impl Pal for Sys {
|
||||
Self::futimens(*file, times)
|
||||
}
|
||||
|
||||
unsafe fn getcwd(buf: *mut c_char, size: size_t) -> Result<()> {
|
||||
// TODO: Not using MaybeUninit seems a little unsafe
|
||||
|
||||
let buf_slice = unsafe { slice::from_raw_parts_mut(buf as *mut u8, size as usize) };
|
||||
if buf_slice.is_empty() {
|
||||
return Err(Errno(EINVAL));
|
||||
}
|
||||
|
||||
path::getcwd(buf_slice).ok_or(Errno(ERANGE))?;
|
||||
fn getcwd(buf: Out<[u8]>) -> Result<()> {
|
||||
path::getcwd(buf).ok_or(Errno(ERANGE))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -438,9 +435,13 @@ impl Pal for Sys {
|
||||
redox_rt::sys::posix_getresugid().rgid as gid_t
|
||||
}
|
||||
|
||||
unsafe fn getgroups(size: c_int, list: *mut gid_t) -> Result<c_int> {
|
||||
fn getgroups(list: Out<[gid_t]>) -> Result<c_int> {
|
||||
// TODO
|
||||
eprintln!("relibc getgroups({}, {:p}): not implemented", size, list);
|
||||
eprintln!(
|
||||
"relibc getgroups({}, {:p}): not implemented",
|
||||
list.len(),
|
||||
list
|
||||
);
|
||||
Err(Errno(ENOSYS))
|
||||
}
|
||||
|
||||
@@ -485,54 +486,54 @@ impl Pal for Sys {
|
||||
}
|
||||
|
||||
fn getresgid(
|
||||
rgid_out: Option<&mut gid_t>,
|
||||
egid_out: Option<&mut gid_t>,
|
||||
sgid_out: Option<&mut gid_t>,
|
||||
rgid_out: Option<Out<gid_t>>,
|
||||
egid_out: Option<Out<gid_t>>,
|
||||
sgid_out: Option<Out<gid_t>>,
|
||||
) -> Result<()> {
|
||||
let Resugid {
|
||||
rgid, egid, sgid, ..
|
||||
} = redox_rt::sys::posix_getresugid();
|
||||
if let Some(rgid_out) = rgid_out {
|
||||
*rgid_out = rgid as _;
|
||||
if let Some(mut rgid_out) = rgid_out {
|
||||
rgid_out.write(rgid as _);
|
||||
}
|
||||
if let Some(egid_out) = egid_out {
|
||||
*egid_out = egid as _;
|
||||
if let Some(mut egid_out) = egid_out {
|
||||
egid_out.write(egid as _);
|
||||
}
|
||||
if let Some(sgid_out) = sgid_out {
|
||||
*sgid_out = sgid as _;
|
||||
if let Some(mut sgid_out) = sgid_out {
|
||||
sgid_out.write(sgid as _);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn getresuid(
|
||||
ruid_out: Option<&mut uid_t>,
|
||||
euid_out: Option<&mut uid_t>,
|
||||
suid_out: Option<&mut uid_t>,
|
||||
ruid_out: Option<Out<uid_t>>,
|
||||
euid_out: Option<Out<uid_t>>,
|
||||
suid_out: Option<Out<uid_t>>,
|
||||
) -> Result<()> {
|
||||
let Resugid {
|
||||
ruid, euid, suid, ..
|
||||
} = redox_rt::sys::posix_getresugid();
|
||||
if let Some(ruid_out) = ruid_out {
|
||||
*ruid_out = ruid as _;
|
||||
if let Some(mut ruid_out) = ruid_out {
|
||||
ruid_out.write(ruid as _);
|
||||
}
|
||||
if let Some(euid_out) = euid_out {
|
||||
*euid_out = euid as _;
|
||||
if let Some(mut euid_out) = euid_out {
|
||||
euid_out.write(euid as _);
|
||||
}
|
||||
if let Some(suid_out) = suid_out {
|
||||
*suid_out = suid as _;
|
||||
if let Some(mut suid_out) = suid_out {
|
||||
suid_out.write(suid as _);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn getrlimit(resource: c_int, rlim: *mut rlimit) -> Result<()> {
|
||||
fn getrlimit(resource: c_int, mut rlim: Out<rlimit>) -> Result<()> {
|
||||
//TODO
|
||||
eprintln!(
|
||||
"relibc getrlimit({}, {:p}): not implemented",
|
||||
resource, rlim
|
||||
);
|
||||
if !rlim.is_null() {
|
||||
(*rlim).rlim_cur = RLIM_INFINITY;
|
||||
(*rlim).rlim_max = RLIM_INFINITY;
|
||||
}
|
||||
rlim.write(rlimit {
|
||||
rlim_cur: RLIM_INFINITY,
|
||||
rlim_max: RLIM_INFINITY,
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -545,7 +546,7 @@ impl Pal for Sys {
|
||||
Err(Errno(EPERM))
|
||||
}
|
||||
|
||||
fn getrusage(who: c_int, r_usage: &mut rusage) -> Result<()> {
|
||||
fn getrusage(who: c_int, r_usage: Out<rusage>) -> Result<()> {
|
||||
//TODO
|
||||
eprintln!("relibc getrusage({}, {:p}): not implemented", who, r_usage);
|
||||
Ok(())
|
||||
@@ -566,16 +567,20 @@ impl Pal for Sys {
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
unsafe fn gettimeofday(tp: *mut timeval, tzp: *mut timezone) -> Result<()> {
|
||||
fn gettimeofday(mut tp: Out<timeval>, tzp: Option<Out<timezone>>) -> Result<()> {
|
||||
let mut redox_tp = redox_timespec::default();
|
||||
syscall::clock_gettime(syscall::CLOCK_REALTIME, &mut redox_tp)?;
|
||||
unsafe {
|
||||
(*tp).tv_sec = redox_tp.tv_sec as time_t;
|
||||
(*tp).tv_usec = (redox_tp.tv_nsec / 1000) as suseconds_t;
|
||||
tp.write(timeval {
|
||||
tv_sec: redox_tp.tv_sec as time_t,
|
||||
tv_usec: (redox_tp.tv_nsec / 1000) as suseconds_t,
|
||||
});
|
||||
|
||||
if !tzp.is_null() {
|
||||
(*tzp).tz_minuteswest = 0;
|
||||
(*tzp).tz_dsttime = 0;
|
||||
if let Some(mut tzp) = tzp {
|
||||
tzp.write(timezone {
|
||||
tz_minuteswest: 0,
|
||||
tz_dsttime: 0,
|
||||
});
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
@@ -791,8 +796,8 @@ impl Pal for Sys {
|
||||
Ok(libredox::open(path, oflag, effective_mode)? as c_int)
|
||||
}
|
||||
|
||||
fn pipe2(fds: &mut [c_int], flags: c_int) -> Result<()> {
|
||||
extra::pipe2(fds, flags as usize)?;
|
||||
fn pipe2(mut fds: Out<[c_int; 2]>, flags: c_int) -> Result<()> {
|
||||
fds.write(extra::pipe2(flags as usize)?);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1048,7 +1053,7 @@ impl Pal for Sys {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn waitpid(mut pid: pid_t, stat_loc: *mut c_int, options: c_int) -> Result<pid_t> {
|
||||
fn waitpid(mut pid: pid_t, stat_loc: Option<Out<'_, c_int>>, options: c_int) -> Result<pid_t> {
|
||||
let mut res = None;
|
||||
let mut status = 0;
|
||||
|
||||
@@ -1102,11 +1107,10 @@ impl Pal for Sys {
|
||||
});
|
||||
|
||||
// If stat_loc is non-null, set that and the return
|
||||
unsafe {
|
||||
if !stat_loc.is_null() {
|
||||
*stat_loc = status as c_int;
|
||||
}
|
||||
if let Some(mut stat_loc) = stat_loc {
|
||||
stat_loc.write(status as c_int);
|
||||
}
|
||||
|
||||
Ok(res? as pid_t)
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ use crate::{
|
||||
error::Errno,
|
||||
fs::File,
|
||||
header::{fcntl, limits},
|
||||
out::Out,
|
||||
sync::Mutex,
|
||||
};
|
||||
|
||||
@@ -44,19 +45,15 @@ pub fn chdir(path: &str) -> Result<()> {
|
||||
}
|
||||
|
||||
// getcwd is similarly both thread-safe and signal-safe.
|
||||
// TODO: MaybeUninit
|
||||
pub fn getcwd(buf: &mut [u8]) -> Option<usize> {
|
||||
pub fn getcwd(mut buf: Out<[u8]>) -> Option<usize> {
|
||||
let _siglock = tmp_disable_signals();
|
||||
let cwd_guard = CWD.lock();
|
||||
let cwd = cwd_guard.as_deref().unwrap_or("").as_bytes();
|
||||
|
||||
// But is already checked not to be empty.
|
||||
if buf.len() - 1 < cwd.len() {
|
||||
return None;
|
||||
}
|
||||
let [mut before, mut after] = buf.split_at_checked(cwd.len())?;
|
||||
|
||||
buf[..cwd.len()].copy_from_slice(&cwd);
|
||||
buf[cwd.len()..].fill(0_u8);
|
||||
before.copy_from_slice(&cwd);
|
||||
after.zero();
|
||||
|
||||
Some(cwd.len())
|
||||
}
|
||||
@@ -238,7 +235,7 @@ pub fn cap_path_at(
|
||||
let path = if dirfd == fcntl::AT_FDCWD {
|
||||
// The special constant AT_FDCWD indicates that we should use the cwd.
|
||||
let mut buf = [0; limits::PATH_MAX];
|
||||
let len = getcwd(&mut buf).ok_or(Errno(ENAMETOOLONG))?;
|
||||
let len = getcwd(Out::from_mut(&mut buf)).ok_or(Errno(ENAMETOOLONG))?;
|
||||
// SAFETY: Redox's cwd is stored as a str.
|
||||
let cwd = unsafe { str::from_utf8_unchecked(&buf[..len]) };
|
||||
|
||||
|
||||
+5
-1
@@ -26,6 +26,7 @@ use crate::{
|
||||
errno::{EAGAIN, ETIMEDOUT},
|
||||
time::timespec,
|
||||
},
|
||||
out::Out,
|
||||
platform::{types::*, Pal, Sys},
|
||||
};
|
||||
use core::{
|
||||
@@ -140,7 +141,10 @@ pub fn rttime() -> timespec {
|
||||
let mut time = MaybeUninit::uninit();
|
||||
|
||||
// TODO: Handle error
|
||||
Sys::clock_gettime(crate::header::time::CLOCK_REALTIME, time.as_mut_ptr());
|
||||
Sys::clock_gettime(
|
||||
crate::header::time::CLOCK_REALTIME,
|
||||
Out::from_uninit_mut(&mut time),
|
||||
);
|
||||
|
||||
time.assume_init()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user