From 313f2be0f8f44985178a9053c4f8a9000faebdb6 Mon Sep 17 00:00:00 2001 From: Connor-GH Date: Thu, 23 Apr 2026 14:18:04 -0500 Subject: [PATCH] Pal: Add default method impls and remove duplicated code I noticed that the Linux and Redox PALs both do very similar things for a given FS function and its *at variant. For example, `mkdir()` is just a call to `mkdirat()`. POSIX requires these to be equivalent. Additionally, we use AT_EMPTY_PATH in some places but note that this is not POSIX and is instead an extension that Linux (and Redox) implement. That doesn't really matter though, since this is an implementation detail. Implementations can choose to implement these functions anyway and ignore the default impl. Such a case is `fstat`, because the current Redox impl of `fstatat` relies on `fstat`, and this would cause infinite recursion. Future work: POSIX says that `fcntl(fd, F_DUPFD, 0);` shall be equivalent to `dup(fd);`. `dup2` might have cases where it can be implemented using `dup3`. `dup` seemingly cannot be implemented in terms of `dup2`, so the `fcntl` default implementation is sufficient. `pipe(fds)` is equivalent to `pipe2(fds, 0);`. --- src/platform/linux/mod.rs | 49 ------------------------------- src/platform/pal/mod.rs | 61 +++++++++++++++++++++++++++++---------- src/platform/redox/mod.rs | 41 ++++---------------------- 3 files changed, 52 insertions(+), 99 deletions(-) diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index 350818f02f..995df1b2d3 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -81,10 +81,6 @@ impl 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, amode: c_int, flags: c_int) -> Result<()> { e_raw(unsafe { syscall!(FACCESSAT, fd, path.as_ptr(), amode, flags) }).map(|_| ()) } @@ -97,14 +93,6 @@ impl Pal for Sys { e_raw(unsafe { syscall!(CHDIR, path.as_ptr()) }).map(|_| ()) } - fn chmod(path: CStr, mode: mode_t) -> Result<()> { - e_raw(unsafe { syscall!(FCHMODAT, AT_FDCWD, path.as_ptr(), mode, 0) }).map(|_| ()) - } - - fn chown(path: CStr, owner: uid_t, group: gid_t) -> Result<()> { - Sys::fchownat(AT_FDCWD, path, owner, group, 0) - } - fn fchownat(fildes: c_int, path: CStr, owner: uid_t, group: gid_t, flags: c_int) -> Result<()> { e_raw(unsafe { syscall!( @@ -487,10 +475,6 @@ impl Pal for Sys { .map(|_| ()) } - fn link(path1: CStr, path2: CStr) -> Result<()> { - Sys::linkat(AT_FDCWD, path1, AT_FDCWD, path2, 0) - } - fn linkat(fd1: c_int, path1: CStr, fd2: c_int, path2: CStr, flags: c_int) -> Result<()> { e_raw(unsafe { syscall!(LINKAT, fd1, path1.as_ptr(), fd2, path2.as_ptr(), flags) }) .map(|_| ()) @@ -504,10 +488,6 @@ impl Pal for Sys { e_raw(unsafe { syscall!(MKDIRAT, dir_fildes, path.as_ptr(), mode) }).map(|_| ()) } - fn mkdir(path: CStr, mode: mode_t) -> Result<()> { - Sys::mkdirat(AT_FDCWD, path, mode) - } - fn mknodat(dir_fildes: c_int, path: CStr, mode: mode_t, dev: dev_t) -> Result<()> { // Note: dev_t is c_long (i64) and __kernel_dev_t is u32; So we need to cast it // and check for overflow @@ -519,10 +499,6 @@ impl Pal for Sys { e_raw(unsafe { syscall!(MKNODAT, dir_fildes, path.as_ptr(), mode, k_dev) }).map(|_| ()) } - fn mknod(path: CStr, mode: mode_t, dev: dev_t) -> Result<()> { - Sys::mknodat(AT_FDCWD, path, mode, dev) - } - fn mkfifoat(dir_fd: c_int, path: CStr, mode: mode_t) -> Result<()> { Sys::mknodat(dir_fd, path, mode | S_IFIFO, 0) } @@ -718,18 +694,6 @@ impl Pal for Sys { e_raw(unsafe { syscall!(PREAD64, fildes, buf.as_mut_ptr(), buf.len(), off) }) } - fn readlink(pathname: CStr, out: &mut [u8]) -> Result { - e_raw(unsafe { - syscall!( - READLINKAT, - AT_FDCWD, - pathname.as_ptr(), - out.as_mut_ptr(), - out.len() - ) - }) - } - fn readlinkat(dirfd: c_int, pathname: CStr, out: &mut [u8]) -> Result { e_raw(unsafe { syscall!( @@ -742,11 +706,6 @@ impl Pal for Sys { }) } - fn rename(old: CStr, new: CStr) -> Result<()> { - e_raw(unsafe { syscall!(RENAMEAT, AT_FDCWD, old.as_ptr(), AT_FDCWD, new.as_ptr()) }) - .map(|_| ()) - } - fn renameat(old_dir: c_int, old_path: CStr, new_dir: c_int, new_path: CStr) -> Result<()> { e_raw(unsafe { syscall!( @@ -812,10 +771,6 @@ impl Pal for Sys { e_raw(unsafe { syscall!(SETSID) }).map(|s| s as c_int) } - fn symlink(path1: CStr, path2: CStr) -> Result<()> { - Sys::symlinkat(path1, AT_FDCWD, path2) - } - fn symlinkat(path1: CStr, fd: c_int, path2: CStr) -> Result<()> { e_raw(unsafe { syscall!(SYMLINKAT, path1.as_ptr(), fd, path2.as_ptr()) }).map(|_| ()) } @@ -873,10 +828,6 @@ impl Pal for Sys { e_raw(unsafe { syscall!(UNAME, utsname.as_mut_ptr(), 0) }).map(|_| ()) } - fn unlink(path: CStr) -> Result<()> { - Sys::unlinkat(AT_FDCWD, path, 0) - } - fn unlinkat(fd: c_int, path: CStr, flags: c_int) -> Result<()> { e_raw(unsafe { syscall!(UNLINKAT, fd, path.as_ptr(), flags) }).map(|_| ()) } diff --git a/src/platform/pal/mod.rs b/src/platform/pal/mod.rs index 677b3924b4..ad31680e0b 100644 --- a/src/platform/pal/mod.rs +++ b/src/platform/pal/mod.rs @@ -6,6 +6,7 @@ use crate::{ error::{Errno, Result}, header::{ bits_timespec::timespec, + fcntl::{AT_EMPTY_PATH, AT_FDCWD}, signal::sigevent, sys_resource::{rlimit, rusage}, sys_select::timeval, @@ -35,7 +36,9 @@ mod socket; /// Platform abstraction layer, a platform-agnostic abstraction over syscalls. pub trait Pal { /// Platform implementation of [`access()`](crate::header::unistd::access) from [`unistd.h`](crate::header::unistd). - fn access(path: CStr, mode: c_int) -> Result<()>; + fn access(path: CStr, mode: c_int) -> Result<()> { + Self::faccessat(AT_FDCWD, path, mode, 0) + } /// Platform implementation of [`faccessat()`](crate::header::unistd::faccessat) from [`unistd.h`](crate::header::unistd). fn faccessat(fd: c_int, path: CStr, amode: c_int, flags: c_int) -> Result<()>; @@ -47,10 +50,14 @@ pub trait Pal { fn chdir(path: CStr) -> Result<()>; /// Platform implementation of [`chmod()`](crate::header::sys_stat::chmod) from [`sys/stat.h`](crate::header::sys_stat). - fn chmod(path: CStr, mode: mode_t) -> Result<()>; + fn chmod(path: CStr, mode: mode_t) -> Result<()> { + Self::fchmodat(AT_FDCWD, Some(path), mode, 0) + } /// Platform implementation of [`chown()`](crate::header::unistd::chown) from [`unistd.h`](crate::header::unistd). - fn chown(path: CStr, owner: uid_t, group: gid_t) -> Result<()>; + fn chown(path: CStr, owner: uid_t, group: gid_t) -> Result<()> { + Self::fchownat(AT_FDCWD, path, owner, group, 0) + } /// Platform implementation of [`clock_getres()`](crate::header::time::clock_getres) from [`time.h`](crate::header::time). fn clock_getres(clk_id: clockid_t, tp: Option>) -> Result<()>; @@ -90,13 +97,17 @@ pub trait Pal { fn fchdir(fildes: c_int) -> Result<()>; /// Platform implementation of [`fchmod()`](crate::header::sys_stat::fchmod) from [`sys/stat.h`](crate::header::sys_stat). - fn fchmod(fildes: c_int, mode: mode_t) -> Result<()>; + fn fchmod(fildes: c_int, mode: mode_t) -> Result<()> { + Self::fchmodat(fildes, Some(c"".into()), mode, AT_EMPTY_PATH) + } /// Platform implementation of [`fchmodat()`](crate::header::sys_stat::fchmodat) from [`sys/stat.h`](crate::header::sys_stat). fn fchmodat(dirfd: c_int, path: Option, mode: mode_t, flags: c_int) -> Result<()>; /// Platform implementation of [`fchown()`](crate::header::unistd::fchown) from [`unistd.h`](crate::header::unistd). - fn fchown(fildes: c_int, owner: uid_t, group: gid_t) -> Result<()>; + fn fchown(fildes: c_int, owner: uid_t, group: gid_t) -> Result<()> { + Self::fchownat(fildes, c"".into(), owner, group, AT_EMPTY_PATH) + } /// Platform implementation of [`fchownat()`](crate::header::unistd::fchownat) from [`unistd.h`](crate::header::unistd). fn fchownat(fildes: c_int, path: CStr, owner: uid_t, group: gid_t, flags: c_int) -> Result<()>; @@ -108,7 +119,9 @@ pub trait Pal { fn flock(fd: c_int, operation: c_int) -> Result<()>; /// Platform implementation of [`fstat()`](crate::header::sys_stat::fstat) from [`sys/stat.h`](crate::header::sys_stat). - fn fstat(fildes: c_int, buf: Out) -> Result<()>; + fn fstat(fildes: c_int, buf: Out) -> Result<()> { + Self::fstatat(fildes, Some(c"".into()), buf, 0) + } /// Platform implementation of [`fstatat()`](crate::header::sys_stat::fstatat) from [`sys/stat.h`](crate::header::sys_stat). fn fstatat(fildes: c_int, path: Option, buf: Out, flags: c_int) -> Result<()>; @@ -229,7 +242,9 @@ pub trait Pal { fn lchown(path: CStr, owner: uid_t, group: gid_t) -> Result<()>; /// Platform implementation of [`link()`](crate::header::unistd::link) from [`unistd.h`](crate::header::unistd). - fn link(path1: CStr, path2: CStr) -> Result<()>; + fn link(path1: CStr, path2: CStr) -> Result<()> { + Self::linkat(AT_FDCWD, path1, AT_FDCWD, path2, 0) + } /// Platform implementation of [`linkat()`](crate::header::unistd::linkat) from [`unistd.h`](crate::header::unistd). fn linkat(fd1: c_int, oldpath: CStr, fd2: c_int, newpath: CStr, flags: c_int) -> Result<()>; @@ -241,19 +256,25 @@ pub trait Pal { fn mkdirat(fildes: c_int, path: CStr, mode: mode_t) -> Result<()>; /// Platform implementation of [`mkdir()`](crate::header::sys_stat::mkdir) from [`sys/stat.h`](crate::header::sys_stat). - fn mkdir(path: CStr, mode: mode_t) -> Result<()>; + fn mkdir(path: CStr, mode: mode_t) -> Result<()> { + Self::mkdirat(AT_FDCWD, path, mode) + } /// Platform implementation of [`mkfifoat()`](crate::header::sys_stat::mkfifoat) from [`sys/stat.h`](crate::header::sys_stat). fn mkfifoat(dir_fd: c_int, path: CStr, mode: mode_t) -> Result<()>; /// Platform implementation of [`mkfifo()`](crate::header::sys_stat::mkfifo) from [`sys/stat.h`](crate::header::sys_stat). - fn mkfifo(path: CStr, mode: mode_t) -> Result<()>; + fn mkfifo(path: CStr, mode: mode_t) -> Result<()> { + Self::mkfifoat(AT_FDCWD, path, mode) + } /// Platform implementation of [`mknodat()`](crate::header::sys_stat::mknodat) from [`sys/stat.h`](crate::header::sys_stat). fn mknodat(fildes: c_int, path: CStr, mode: mode_t, dev: dev_t) -> Result<()>; /// Platform implementation of [`mknod()`](crate::header::sys_stat::mknod) from [`sys/stat.h`](crate::header::sys_stat). - fn mknod(path: CStr, mode: mode_t, dev: dev_t) -> Result<()>; + fn mknod(path: CStr, mode: mode_t, dev: dev_t) -> Result<()> { + Self::mknodat(AT_FDCWD, path, mode, dev) + } /// Platform implementation of [`mlock()`](crate::header::sys_mman::mlock) from [`sys/mman.h`](crate::header::sys_mman). unsafe fn mlock(addr: *const c_void, len: usize) -> Result<()>; @@ -332,16 +353,22 @@ pub trait Pal { fn pread(fildes: c_int, buf: &mut [u8], offset: off_t) -> Result; /// Platform implementation of [`readlink()`](crate::header::unistd::readlink) from [`unistd.h`](crate::header::unistd). - fn readlink(pathname: CStr, out: &mut [u8]) -> Result; + fn readlink(pathname: CStr, out: &mut [u8]) -> Result { + Self::readlinkat(AT_FDCWD, pathname, out) + } /// Platform implementation of [`readlinkat()`](crate::header::unistd::readlinkat) from [`unistd.h`](crate::header::unistd). fn readlinkat(dirfd: c_int, pathname: CStr, out: &mut [u8]) -> Result; /// Platform implementation of [`rename()`](crate::header::stdio::rename) from [`stdio.h`](crate::header::stdio). - fn rename(old: CStr, new: CStr) -> Result<()>; + fn rename(old: CStr, new: CStr) -> Result<()> { + Self::renameat(AT_FDCWD, old, AT_FDCWD, new) + } /// Platform implementation of [`renameat()`](crate::header::stdio::renameat) from [`stdio.h`](crate::header::stdio). - fn renameat(old_dir: c_int, old_path: CStr, new_dir: c_int, new_path: CStr) -> Result<()>; + fn renameat(old_dir: c_int, old_path: CStr, new_dir: c_int, new_path: CStr) -> Result<()> { + Self::renameat2(old_dir, old_path, new_dir, new_path, 0) + } /// Platform implementation of [`renameat2()`](crate::header::stdio::renameat2) from [`stdio.h`](crate::header::stdio). fn renameat2( @@ -377,7 +404,9 @@ pub trait Pal { fn setsid() -> Result; /// Platform implementation of [`symlink()`](crate::header::unistd::symlink) from [`unistd.h`](crate::header::unistd). - fn symlink(path1: CStr, path2: CStr) -> Result<()>; + fn symlink(path1: CStr, path2: CStr) -> Result<()> { + Self::symlinkat(path1, AT_FDCWD, path2) + } /// Platform implementation of [`symlinkat()`](crate::header::unistd::symlinkat) from [`unistd.h`](crate::header::unistd). fn symlinkat(path1: CStr, fd: c_int, path2: CStr) -> Result<()>; @@ -410,7 +439,9 @@ pub trait Pal { fn uname(utsname: Out) -> Result<()>; /// Platform implementation of [`unlink()`](crate::header::unistd::unlink) from [`unistd.h`](crate::header::unistd). - fn unlink(path: CStr) -> Result<()>; + fn unlink(path: CStr) -> Result<()> { + Self::unlinkat(AT_FDCWD, path, 0) + } /// Platform implementation of [`unlinkat()`](crate::header::unistd::unlinkat) from [`unistd.h`](crate::header::unistd). fn unlinkat(fd: c_int, path: CStr, flags: c_int) -> Result<()>; diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index ea1281a11a..752339a711 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -799,14 +799,6 @@ impl Pal for Sys { Self::fchown(*file, owner, group) } - fn link(oldpath: CStr, newpath: CStr) -> Result<()> { - let newpath = newpath.to_str().map_err(|_| Errno(EINVAL))?; - - let file = File::open(oldpath, fcntl::O_PATH | fcntl::O_CLOEXEC)?; - syscall::flink(*file as usize, newpath)?; - Ok(()) - } - fn linkat(fd1: c_int, oldpath: CStr, fd2: c_int, newpath: CStr, flags: c_int) -> Result<()> { // make sure the flags passed are valid. // valid states: AT_SYMLINK_FOLLOW, or 0. @@ -844,15 +836,6 @@ impl Pal for Sys { Ok(()) } - fn mkdir(path: CStr, mode: mode_t) -> Result<()> { - File::create( - path, - fcntl::O_DIRECTORY | fcntl::O_EXCL | fcntl::O_CLOEXEC, - 0o777, - )?; - Ok(()) - } - fn mkfifoat(dir_fd: c_int, path_name: CStr, mode: mode_t) -> Result<()> { Sys::mknodat( dir_fd, @@ -862,20 +845,11 @@ impl Pal for Sys { ) } - fn mkfifo(path: CStr, mode: mode_t) -> Result<()> { - Sys::mknod(path, syscall::MODE_FIFO as mode_t | (mode & 0o777), 0) - } - fn mknodat(dir_fd: c_int, path_name: CStr, mode: mode_t, dev: dev_t) -> Result<()> { File::createat(dir_fd, path_name, fcntl::O_CREAT | fcntl::O_CLOEXEC, mode)?; Ok(()) } - fn mknod(path: CStr, mode: mode_t, dev: dev_t) -> Result<(), Errno> { - File::create(path, fcntl::O_CREAT | fcntl::O_CLOEXEC, mode)?; - Ok(()) - } - unsafe fn mlock(addr: *const c_void, len: usize) -> Result<()> { // Redox never swaps Ok(()) @@ -1173,17 +1147,14 @@ impl Pal for Sys { } } - fn readlink(pathname: CStr, out: &mut [u8]) -> Result { - let file = File::open( - pathname, - fcntl::O_RDONLY | fcntl::O_SYMLINK | fcntl::O_CLOEXEC, - )?; - Self::read(*file, out) - } - fn readlinkat(dirfd: c_int, path: CStr, out: &mut [u8]) -> Result { let path = str::from_utf8(path.to_bytes()).map_err(|_| Errno(ENOENT))?; - let file = openat2(dirfd, path, 0, fcntl::O_RDONLY | fcntl::O_SYMLINK)?; + let file = openat2( + dirfd, + path, + 0, + fcntl::O_RDONLY | fcntl::O_SYMLINK | fcntl::O_CLOEXEC, + )?; Sys::read(*file, out) }