platform/redox: migrate more functions to use their *at variants

Additionally, this adds the `SYMLOOP_MAX` constant in `limits.h` to
replace the `MAX_LEVEL` magic number used during symlink resolution.

`fstat` was kept because it is more difficult than the others to do a
drop-in replacement in terms of `fstatat` for since a naive approach
would cause mutual recursion.
This commit is contained in:
Connor-GH
2026-05-04 10:10:20 -05:00
parent 4bff41fe78
commit cf65eedbaf
5 changed files with 35 additions and 58 deletions
+1
View File
@@ -129,3 +129,4 @@ pub const PTHREAD_DESTRUCTOR_ITERATIONS: c_long = _POSIX_THREAD_DESTRUCTOR_ITERA
// TODO: What should this limit be? Both glibc and musl have it as 1024
pub const PTHREAD_KEYS_MAX: c_long = 4096 * 32;
pub const PTHREAD_STACK_MIN: c_long = 65536;
pub const SYMLOOP_MAX: c_long = 64;
+7 -3
View File
@@ -5,7 +5,7 @@ use crate::{
c_str::CStr,
error::{Errno, Result},
header::{
fcntl::{AT_EMPTY_PATH, AT_FDCWD},
fcntl::{AT_EMPTY_PATH, AT_FDCWD, F_DUPFD},
signal::sigevent,
sys_resource::{rlimit, rusage},
sys_select::timeval,
@@ -72,7 +72,9 @@ pub trait Pal {
fn close(fildes: c_int) -> Result<()>;
/// Platform implementation of [`dup()`](crate::header::unistd::dup) from [`unistd.h`](crate::header::unistd).
fn dup(fildes: c_int) -> Result<c_int>;
fn dup(fildes: c_int) -> Result<c_int> {
Self::fcntl(fildes, F_DUPFD, 0)
}
/// Platform implementation of [`dup2()`](crate::header::unistd::dup2) from [`unistd.h`](crate::header::unistd).
fn dup2(fildes: c_int, fildes2: c_int) -> Result<c_int>;
@@ -322,7 +324,9 @@ pub trait Pal {
unsafe fn nanosleep(rqtp: *const timespec, rmtp: *mut timespec) -> Result<()>;
/// Platform implementation of [`open()`](crate::header::fcntl::open) from [`fcntl.h`](crate::header::fcntl).
fn open(path: CStr, oflag: c_int, mode: mode_t) -> Result<c_int>;
fn open(path: CStr, oflag: c_int, mode: mode_t) -> Result<c_int> {
Self::openat(AT_FDCWD, path, oflag, mode)
}
/// Platform implementation of `openat()` (TODO) from [`fcntl.h`](crate::header::fcntl).
fn openat(dirfd: c_int, path: CStr, oflag: c_int, mode: mode_t) -> Result<c_int>;
+7 -2
View File
@@ -2,7 +2,7 @@ use core::mem::size_of;
use crate::header::{
bits_sigset_t::sigset_t,
fcntl::{O_CLOEXEC, O_CREAT, O_RDWR},
fcntl::{AT_FDCWD, O_CLOEXEC, O_CREAT, O_RDWR},
time::timespec,
};
@@ -16,7 +16,12 @@ pub unsafe extern "C" fn redox_event_queue_create_v1(flags: u32) -> RawResult {
if flags != 0 {
return Err(Error::new(EINVAL));
}
Ok(super::libredox::open("/scheme/event", O_CLOEXEC | O_CREAT | O_RDWR, 0o700)? as usize)
Ok(super::libredox::openat(
AT_FDCWD,
"/scheme/event",
O_CLOEXEC | O_CREAT | O_RDWR,
0o700,
)? as usize)
})())
}
#[unsafe(no_mangle)]
+4 -16
View File
@@ -12,7 +12,8 @@ use syscall::{
use crate::{
header::{
bits_iovec::iovec, errno::EINVAL, signal::sigaction, sys_stat::UTIME_NOW, time::timespec,
bits_iovec::iovec, errno::EINVAL, fcntl::AT_FDCWD, signal::sigaction, sys_stat::UTIME_NOW,
time::timespec,
},
out::Out,
platform::{PalSignal, pal::Pal, types::*},
@@ -22,20 +23,6 @@ use super::Sys;
pub type RawResult = usize;
pub fn open(path: &str, oflag: c_int, mode: mode_t) -> Result<usize> {
let usize_fd = super::path::open(
path,
((oflag as usize) & 0xFFFF_0000) | ((mode as usize) & 0xFFFF),
)?;
c_int::try_from(usize_fd)
.map_err(|_| {
let _ = syscall::close(usize_fd);
Error::new(EMFILE)
})
.map(|f| f as usize)
}
pub fn openat(dirfd: c_int, path: &str, oflag: c_int, mode: mode_t) -> Result<usize> {
let usize_fd = super::path::openat(
dirfd,
@@ -239,7 +226,8 @@ pub unsafe extern "C" fn redox_open_v1(
flags: u32,
mode: u16,
) -> RawResult {
Error::mux(open(
Error::mux(openat(
AT_FDCWD,
unsafe { str::from_utf8_unchecked(slice::from_raw_parts(path_base, path_len)) },
flags as c_int,
mode as mode_t,
+16 -37
View File
@@ -107,10 +107,6 @@ static CLONE_LOCK: RwLock<()> = RwLock::new(());
pub struct Sys;
impl Pal for Sys {
fn access(path: CStr, mode: c_int) -> Result<()> {
Sys::faccessat(AT_FDCWD, path, mode, 0)
}
fn faccessat(fd: c_int, path: CStr, mode: c_int, flags: c_int) -> Result<()> {
let fd = FdGuard::new(Sys::openat(fd, path, fcntl::O_PATH | fcntl::O_CLOEXEC, 0)? as usize);
@@ -247,10 +243,6 @@ impl Pal for Sys {
Ok(())
}
fn dup(fd: c_int) -> Result<c_int> {
Ok(syscall::dup(fd as usize, &[])? as c_int)
}
fn dup2(fd1: c_int, fd2: c_int) -> Result<c_int> {
Ok(syscall::dup2(fd1 as usize, fd2 as usize, &[])? as c_int)
}
@@ -289,11 +281,6 @@ impl Pal for Sys {
Ok(())
}
fn fchmod(fd: c_int, mode: mode_t) -> Result<()> {
libredox::fchmod(fd as usize, mode as u16)?;
Ok(())
}
fn fchmodat(dirfd: c_int, path: Option<CStr>, mode: mode_t, flags: c_int) -> Result<()> {
const MASK: c_int = !(fcntl::AT_SYMLINK_NOFOLLOW | fcntl::AT_EMPTY_PATH);
if MASK & flags != 0 {
@@ -308,7 +295,7 @@ impl Pal for Sys {
if dirfd == AT_FDCWD {
path = ".";
} else {
return Sys::fchmod(dirfd, mode);
return Ok(libredox::fchmod(dirfd as usize, mode as u16)?);
}
} else {
// If the path is empty but `AT_EMPTY_PATH` is **not** set, bail out.
@@ -321,17 +308,24 @@ impl Pal for Sys {
Ok(())
}
fn fchown(fd: c_int, owner: uid_t, group: gid_t) -> Result<()> {
libredox::fchown(fd as usize, owner as u32, group as u32)?;
Ok(())
}
fn fchownat(fildes: c_int, path: CStr, owner: uid_t, group: gid_t, flags: c_int) -> Result<()> {
const MASK: c_int = !(fcntl::AT_SYMLINK_NOFOLLOW | fcntl::AT_EMPTY_PATH);
if MASK & flags != 0 {
return Err(Errno(EINVAL));
}
let path = path.to_str().map_err(|_| Errno(EINVAL))?;
let mut path = path.to_str().map_err(|_| Errno(ENOENT))?;
if path.is_empty() {
if flags & AT_EMPTY_PATH == AT_EMPTY_PATH {
if fildes == AT_FDCWD {
path = ".";
} else {
return Ok(libredox::fchown(fildes as usize, owner as _, group as _)?);
}
} else {
// If the path is empty but `AT_EMPTY_PATH` is **not** set, bail out.
return Err(Errno(ENOENT));
}
}
let file = openat2(fildes, path, flags, 0)?;
libredox::fchown(*file as usize, owner as _, group as _)?;
Ok(())
@@ -486,7 +480,7 @@ impl Pal for Sys {
if dirfd == AT_FDCWD {
path = ".";
} else {
return Sys::fstat(dirfd, buf);
return Ok(Sys::fstat(dirfd, buf)?);
}
} else {
// If the path is empty but `AT_EMPTY_PATH` is **not** set, bail out.
@@ -513,7 +507,7 @@ impl Pal for Sys {
let file = openat2(dirfd, path, 0, open_flags)?;
// Close the file descriptor after fstat(2) regardless of success or failure.
let fstat_res = Sys::fstat(*file, buf);
let close_res = syscall::close(file.fd as usize);
let close_res = syscall::close(*file as usize);
if let Err(err) = fstat_res {
return Err(err);
}
@@ -977,21 +971,6 @@ impl Pal for Sys {
}
}
fn open(path: CStr, oflag: c_int, mode: mode_t) -> Result<c_int> {
let path = path.to_str().map_err(|_| Errno(EINVAL))?;
// POSIX states that umask should affect the following:
//
// open, openat, creat, mkdir, mkdirat,
// mkfifo, mkfifoat, mknod, mknodat,
// mq_open, and sem_open,
//
// all of which (the ones that exist thus far) currently call this function.
let effective_mode = mode & !(redox_rt::sys::get_umask() as mode_t);
Ok(libredox::open(path, oflag, effective_mode)? as c_int)
}
fn openat(dirfd: c_int, path: CStr, oflag: c_int, mode: mode_t) -> Result<c_int> {
let path = path.to_str().map_err(|_| Errno(EINVAL))?;