refactor: Migrate fstat*/fchmod/getdents/ftruncate/futimens to stdfscall

This commit is contained in:
Ibuki.O
2026-03-14 13:35:39 +09:00
parent df97789fb9
commit ac88c8f670
5 changed files with 68 additions and 205 deletions
+2 -2
View File
@@ -5,7 +5,7 @@ use crate::{
arch::*,
auxv_defs::*,
read_proc_meta,
sys::{open, proc_call, thread_call},
sys::{fstat, open, proc_call, thread_call},
};
use redox_protocols::protocol::{ProcCall, ThreadCall};
@@ -798,7 +798,7 @@ impl<const UPPER: bool> FdGuard<UPPER> {
#[inline]
pub fn fstat(&self, stat: &mut syscall::Stat) -> Result<usize> {
syscall::fstat(self.fd, stat)
fstat(self.fd, stat)
}
#[inline]
+4 -1
View File
@@ -6,7 +6,7 @@ use core::{
use ioslice::IoSlice;
use syscall::{
CallFlags, EINVAL, ERESTART, TimeSpec,
CallFlags, EINVAL, ERESTART, StdFsCallKind, TimeSpec,
data::StdFsCallMeta,
error::{self, EINTR, ENODEV, ESRCH, Error, Result},
};
@@ -527,3 +527,6 @@ pub fn std_fs_call_wo(fd: usize, payload: &[u8], metadata: &StdFsCallMeta) -> Re
pub fn std_fs_call_rw(fd: usize, payload: &mut [u8], metadata: &StdFsCallMeta) -> Result<usize> {
sys_call_rw(fd, payload, CallFlags::STD_FS, metadata)
}
pub fn fstat(fd: usize, stat: &mut syscall::Stat) -> Result<usize> {
std_fs_call_ro(fd, stat, &StdFsCallMeta::new(StdFsCallKind::Fstat, 0, 0))
}
+1 -1
View File
@@ -94,7 +94,7 @@ pub fn execve(
// executable memory.
let mut stat = Stat::default();
syscall::fstat(*image_file as usize, &mut stat)?;
redox_rt::sys::fstat(*image_file as usize, &mut stat)?;
let Resugid { ruid, rgid, .. } = redox_rt::sys::posix_getresugid();
let mode = if ruid == stat.st_uid {
+48 -133
View File
@@ -1,10 +1,14 @@
use core::{slice, str};
use core::{mem, slice, str};
use alloc::vec::Vec;
use ioslice::IoSlice;
use redox_protocols::protocol::{ProcKillTarget, SocketCall, WaitFlags};
use redox_rt::sys::{WaitpidTarget, posix_read, posix_write};
use syscall::{EMFILE, Error, Result};
use redox_rt::sys::{WaitpidTarget, posix_read, posix_write, std_fs_call_ro, std_fs_call_wo};
use syscall::{
EMFILE, ENAMETOOLONG, ENOSYS, EOPNOTSUPP, Error, Result, StdFsCallKind,
data::StdFsCallMeta,
dirent::{DirentHeader, DirentKind},
};
use crate::{
header::{
@@ -46,84 +50,30 @@ pub fn openat(dirfd: c_int, path: &str, oflag: c_int, mode: mode_t) -> Result<us
})
.map(|f| f as usize)
}
pub unsafe fn fstat(fd: usize, buf: *mut crate::header::sys_stat::stat) -> Result<()> {
let mut redox_buf: syscall::Stat = Default::default();
syscall::fstat(fd, &mut redox_buf)?;
if let Some(buf) = unsafe { buf.as_mut() } {
buf.st_dev = redox_buf.st_dev as dev_t;
buf.st_ino = redox_buf.st_ino as ino_t;
buf.st_nlink = redox_buf.st_nlink as nlink_t;
buf.st_mode = redox_buf.st_mode as mode_t;
buf.st_uid = redox_buf.st_uid as uid_t;
buf.st_gid = redox_buf.st_gid as gid_t;
// TODO st_rdev
buf.st_rdev = 0;
buf.st_size = redox_buf.st_size as off_t;
buf.st_blksize = redox_buf.st_blksize as blksize_t;
buf.st_blocks = redox_buf.st_blocks as blkcnt_t;
buf.st_atim = timespec {
tv_sec: redox_buf.st_atime as time_t,
tv_nsec: redox_buf.st_atime_nsec as c_long,
};
buf.st_mtim = timespec {
tv_sec: redox_buf.st_mtime as time_t,
tv_nsec: redox_buf.st_mtime_nsec as c_long,
};
buf.st_ctim = timespec {
tv_sec: redox_buf.st_ctime as time_t,
tv_nsec: redox_buf.st_ctime_nsec as c_long,
};
}
pub fn fchmod(fd: usize, new_mode: u16) -> Result<()> {
std_fs_call_wo(
fd,
&[],
&StdFsCallMeta::new(StdFsCallKind::Fchmod, new_mode as u64, 0),
)?;
Ok(())
}
pub unsafe fn fstatvfs(
fd: usize,
buf: *mut crate::header::sys_statvfs::statvfs,
) -> syscall::Result<()> {
let mut kbuf: syscall::StatVfs = Default::default();
syscall::fstatvfs(fd, &mut kbuf)?;
if !buf.is_null() {
unsafe {
(*buf).f_bsize = kbuf.f_bsize as c_ulong;
(*buf).f_frsize = kbuf.f_bsize as c_ulong;
(*buf).f_blocks = kbuf.f_blocks as c_ulong;
(*buf).f_bfree = kbuf.f_bfree as c_ulong;
(*buf).f_bavail = kbuf.f_bavail as c_ulong;
//TODO
(*buf).f_files = 0;
(*buf).f_ffree = 0;
(*buf).f_favail = 0;
(*buf).f_fsid = 0;
(*buf).f_flag = 0;
(*buf).f_namemax = 0;
}
}
pub fn fchown(fd: usize, new_uid: u32, new_gid: u32) -> Result<()> {
/* std_fs_call
Error::mux(std_fs_call_wo(
fd,
&[],
&StdFsCallMeta::new(
StdFsCallKind::Fchmod,
(new_uid as u64) | ((new_gid as u64) << 32),
0,
),
))
*/
syscall::fchown(fd, new_uid, new_gid)?;
Ok(())
}
pub unsafe fn futimens(fd: usize, times: *const timespec) -> syscall::Result<()> {
let times = if times.is_null() {
// null means set to current time using special UTIME_NOW value (tv_sec is ignored in that case)
[
syscall::TimeSpec {
tv_sec: 0,
tv_nsec: UTIME_NOW as c_int,
},
syscall::TimeSpec {
tv_sec: 0,
tv_nsec: UTIME_NOW as c_int,
},
]
} else {
unsafe { times.cast::<[timespec; 2]>().read() }.map(|ts| syscall::TimeSpec::from(&ts))
};
syscall::futimens(fd as usize, &times)?;
Ok(())
}
/* std_fs_call
pub fn std_fs_call_getdents(fd: usize, buf: &mut [u8], opaque: u64) -> Result<usize> {
pub fn getdents(fd: usize, buf: &mut [u8], opaque: u64) -> Result<usize> {
//println!("GETDENTS {} into ({:p}+{})", fd, buf.as_ptr(), buf.len());
const HEADER_SIZE: usize = mem::size_of::<DirentHeader>();
@@ -177,13 +127,9 @@ pub fn std_fs_call_getdents(fd: usize, buf: &mut [u8], opaque: u64) -> Result<us
Ok(record_len.into())
}
pub unsafe fn std_fs_call_fstat(fd: usize, buf: *mut crate::header::sys_stat::stat) -> Result<()> {
pub unsafe fn fstat(fd: usize, buf: *mut crate::header::sys_stat::stat) -> Result<()> {
let mut redox_buf: syscall::Stat = Default::default();
std_fs_call_ro(
fd,
&mut redox_buf,
&StdFsCallMeta::new(StdFsCallKind::Fstat, 0, 0),
)?;
redox_rt::sys::fstat(fd, &mut redox_buf)?;
if let Some(buf) = unsafe { buf.as_mut() } {
buf.st_dev = redox_buf.st_dev as dev_t;
@@ -212,10 +158,7 @@ pub unsafe fn std_fs_call_fstat(fd: usize, buf: *mut crate::header::sys_stat::st
}
Ok(())
}
pub unsafe fn std_fs_call_fstatvfs(
fd: usize,
buf: *mut crate::header::sys_statvfs::statvfs,
) -> Result<()> {
pub unsafe fn fstatvfs(fd: usize, buf: *mut crate::header::sys_statvfs::statvfs) -> Result<()> {
let mut kbuf: syscall::StatVfs = Default::default();
std_fs_call_ro(
fd,
@@ -241,7 +184,19 @@ pub unsafe fn std_fs_call_fstatvfs(
}
Ok(())
}
pub unsafe fn std_fs_call_futimens(fd: usize, times: *const timespec) -> Result<()> {
pub fn fsync(fd: usize) -> Result<()> {
std_fs_call_wo(fd, &[], &StdFsCallMeta::new(StdFsCallKind::Fsync, 0, 0))?;
Ok(())
}
pub fn ftruncate(fd: usize, len: usize) -> Result<()> {
std_fs_call_wo(
fd,
&[],
&StdFsCallMeta::new(StdFsCallKind::Ftruncate, len as u64, 0),
)?;
Ok(())
}
pub unsafe fn futimens(fd: usize, times: *const timespec) -> Result<()> {
let times = if times.is_null() {
// null means set to current time using special UTIME_NOW value (tv_sec is ignored in that case)
[
@@ -270,7 +225,6 @@ pub unsafe fn std_fs_call_futimens(fd: usize, times: *const timespec) -> Result<
)?;
Ok(())
}
*/
pub fn clock_gettime(clock: usize, mut tp: Out<timespec>) -> Result<()> {
let mut redox_tp = syscall::TimeSpec::default();
syscall::clock_gettime(clock as usize, &mut redox_tp)?;
@@ -344,29 +298,11 @@ pub unsafe extern "C" fn redox_write_v1(
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn redox_fchmod_v1(fd: usize, new_mode: u16) -> RawResult {
/* std_fs_call
Error::mux(std_fs_call_wo(
fd,
&[],
&StdFsCallMeta::new(StdFsCallKind::Fchmod, new_mode as u64, 0),
))
*/
Error::mux(syscall::fchmod(fd, new_mode))
Error::mux(fchmod(fd, new_mode).map(|()| 0))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn redox_fchown_v1(fd: usize, new_uid: u32, new_gid: u32) -> RawResult {
/* std_fs_call
Error::mux(std_fs_call_wo(
fd,
&[],
&StdFsCallMeta::new(
StdFsCallKind::Fchmod,
(new_uid as u64) | ((new_gid as u64) << 32),
0,
),
))
*/
Error::mux(syscall::fchown(fd, new_uid, new_gid))
Error::mux(fchown(fd, new_uid, new_gid).map(|()| 0))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn redox_getdents_v0(
@@ -400,37 +336,16 @@ pub unsafe extern "C" fn redox_fstatvfs_v1(
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn redox_fsync_v1(fd: usize) -> RawResult {
/* std_fs_call
Error::mux(std_fs_call_wo(
fd,
&[],
&StdFsCallMeta::new(StdFsCallKind::Fsync, 0, 0),
))
*/
Error::mux(syscall::fsync(fd))
Error::mux(fsync(fd).map(|()| 0))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn redox_fdatasync_v1(fd: usize) -> RawResult {
/* std_fs_call
Error::mux(std_fs_call_wo(
fd,
&[],
&StdFsCallMeta::new(StdFsCallKind::Fsync, 0, 0),
))
*/
// TODO
Error::mux(syscall::fsync(fd))
Error::mux(fsync(fd).map(|()| 0))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn redox_ftruncate_v0(fd: usize, len: usize) -> RawResult {
/* std_fs_call
Error::mux(std_fs_call_wo(
fd,
&[],
&StdFsCallMeta::new(StdFsCallKind::Ftruncate, len as u64, 0),
))
*/
Error::mux(syscall::ftruncate(fd as usize, len as usize))
Error::mux(ftruncate(fd, len).map(|()| 0))
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn redox_futimens_v1(fd: usize, times: *const timespec) -> RawResult {
+13 -68
View File
@@ -13,7 +13,7 @@ use redox_rt::{
use syscall::{
self, EILSEQ, ESRCH, Error, MODE_PERM, StdFsCallKind, StdFsCallMeta,
data::{Map, TimeSpec as redox_timespec},
dirent::{DirentHeader, DirentKind},
dirent::DirentHeader,
};
use self::{
@@ -270,7 +270,7 @@ impl Pal for Sys {
}
fn fchmod(fd: c_int, mode: mode_t) -> Result<()> {
syscall::fchmod(fd as usize, mode as u16)?;
libredox::fchmod(fd as usize, mode as u16)?;
Ok(())
}
@@ -283,12 +283,12 @@ impl Pal for Sys {
.and_then(|cs| str::from_utf8(cs.to_bytes()).ok())
.ok_or(Errno(ENOENT))?;
let file = openat2(dirfd, path, flags, 0)?;
syscall::fchmod(*file as usize, mode as u16)?;
libredox::fchmod(*file as usize, mode as u16)?;
Ok(())
}
fn fchown(fd: c_int, owner: uid_t, group: gid_t) -> Result<()> {
syscall::fchown(fd as usize, owner as u32, group as u32)?;
libredox::fchown(fd as usize, owner as u32, group as u32)?;
Ok(())
}
@@ -484,12 +484,12 @@ impl Pal for Sys {
}
fn fsync(fd: c_int) -> Result<()> {
syscall::fsync(fd as usize)?;
libredox::fsync(fd as usize)?;
Ok(())
}
fn ftruncate(fd: c_int, len: off_t) -> Result<()> {
syscall::ftruncate(fd as usize, len as usize)?;
libredox::ftruncate(fd as usize, len as usize)?;
Ok(())
}
@@ -523,63 +523,7 @@ impl Pal for Sys {
}
fn getdents(fd: c_int, buf: &mut [u8], opaque: u64) -> Result<usize> {
//println!("GETDENTS {} into ({:p}+{})", fd, buf.as_ptr(), buf.len());
const HEADER_SIZE: usize = size_of::<DirentHeader>();
// Use syscall if it exists.
match unsafe {
syscall::syscall5(
syscall::SYS_GETDENTS,
fd as usize,
buf.as_mut_ptr() as usize,
buf.len(),
HEADER_SIZE,
opaque as usize,
)
} {
Err(Error {
errno: EOPNOTSUPP | ENOSYS,
}) => (),
other => {
//println!("REAL GETDENTS {:?}", other);
return Ok(other?);
}
}
// Otherwise, for legacy schemes, assume the buffer is pre-arranged (all schemes do this in
// practice), and just read the name. If multiple names appear, pretend it didn't happen
// and just use the first entry.
let (header, name) = buf.split_at_mut(size_of::<DirentHeader>());
let bytes_read = Sys::pread(fd, name, opaque as i64)? as usize;
if bytes_read == 0 {
return Ok(0);
}
let (name_len, advance) = match name[..bytes_read].iter().position(|c| *c == b'\n') {
Some(idx) => (idx, idx + 1),
// Insufficient space for NUL byte, or entire entry was not read. Indicate we need a
// larger buffer.
None if bytes_read == name.len() => return Err(Errno(EINVAL)),
None => (bytes_read, name.len()),
};
name[name_len] = b'\0';
let record_len = u16::try_from(size_of::<DirentHeader>() + name_len + 1)
.map_err(|_| Error::new(ENAMETOOLONG))?;
header.copy_from_slice(&DirentHeader {
inode: 0,
next_opaque_id: opaque + advance as u64,
record_len,
kind: DirentKind::Unspecified as u8,
});
//println!("EMULATED GETDENTS");
Ok(record_len.into())
Ok(libredox::getdents(fd as usize, buf, opaque)?)
}
fn dir_seek(_fd: c_int, _off: u64) -> Result<()> {
@@ -1041,17 +985,18 @@ impl Pal for Sys {
let length = length.get();
let total_offset = offset.checked_add(length).ok_or(Errno(EFBIG))?;
let mut stat = syscall::Stat::default();
syscall::fstat(fd as usize, &mut stat)?;
let mut stat: stat = unsafe { mem::zeroed() };
unsafe { libredox::fstat(fd as usize, &mut stat)? };
let st_size = stat.st_size as u64;
// The difference between total_offset and the file size is the number of bytes to
// allocate. So, if it's negative then the file is already large enough and we don't
// need to do any extra work.
if let Some(total_len) = total_offset
.checked_sub(stat.st_size)
.and_then(|diff| stat.st_size.checked_add(diff))
.checked_sub(st_size)
.and_then(|diff| st_size.checked_add(diff))
{
let total_len: usize = total_len.try_into().map_err(|_| Errno(EFBIG))?;
syscall::ftruncate(fd as usize, total_len)?;
libredox::ftruncate(fd as usize, total_len)?;
}
Ok(())