Add Out<T> wrapper

This commit is contained in:
Jacob Lorentzon
2025-09-21 14:36:12 +02:00
parent 3ad1ba516e
commit 9c5f11fbc8
21 changed files with 469 additions and 195 deletions
+2 -1
View File
@@ -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));
+14 -3
View File
@@ -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 {
+3 -1
View File
@@ -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;
}
+5 -2
View File
@@ -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 -1
View File
@@ -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()
}
+8
View File
@@ -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 {
+3
View File
@@ -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 {
+4 -1
View File
@@ -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
+2 -2
View File
@@ -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()
}
+6 -5
View File
@@ -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
View File
@@ -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
View File
@@ -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 {
+2
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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>;
+3 -6
View File
@@ -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)
}
+8 -5
View File
@@ -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, &times)?;
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
View File
@@ -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)
}
+6 -9
View File
@@ -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
View File
@@ -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()
}