diff --git a/src/header/sys_stat/mod.rs b/src/header/sys_stat/mod.rs index 542208feb3..10e656d2a5 100644 --- a/src/header/sys_stat/mod.rs +++ b/src/header/sys_stat/mod.rs @@ -5,10 +5,7 @@ use crate::{ c_str::CStr, error::ResultExt, - header::{ - fcntl::{AT_SYMLINK_NOFOLLOW, O_NOFOLLOW, O_PATH}, - time::timespec, - }, + header::{fcntl::AT_SYMLINK_NOFOLLOW, time::timespec}, out::Out, platform::{ Pal, Sys, @@ -147,19 +144,7 @@ pub unsafe extern "C" fn futimens(fd: c_int, times: *const timespec) -> c_int { pub unsafe extern "C" fn lstat(path: *const c_char, buf: *mut stat) -> c_int { let path = unsafe { CStr::from_ptr(path) }; let buf = unsafe { Out::nonnull(buf) }; - - // TODO: Rustify - let fd = Sys::open(path, O_PATH | O_NOFOLLOW, 0).or_minus_one_errno(); - if fd < 0 { - return -1; - } - - // TODO: Rustify - let res = Sys::fstat(fd, buf).map(|()| 0).or_minus_one_errno(); - - if let Ok(()) = Sys::close(fd) {}; // TODO handle error - - res + Sys::lstat(path, buf).map(|()| 0).or_minus_one_errno() } /// See . @@ -220,19 +205,7 @@ pub unsafe extern "C" fn mknodat( pub unsafe extern "C" fn stat(file: *const c_char, buf: *mut stat) -> c_int { let file = unsafe { CStr::from_ptr(file) }; let buf = unsafe { Out::nonnull(buf) }; - - // TODO: Rustify - let fd = Sys::open(file, O_PATH, 0).or_minus_one_errno(); - if fd < 0 { - return -1; - } - - // TODO: Rustify - let res = Sys::fstat(fd, buf).map(|()| 0).or_minus_one_errno(); - - if let Ok(()) = Sys::close(fd) {}; // TODO handle error - - res + Sys::stat(file, buf).map(|()| 0).or_minus_one_errno() } /// See . diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index 25a0478cbc..fe127a213b 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -8,7 +8,7 @@ use crate::{ header::{ dirent::dirent, errno::{EINVAL, EIO}, - fcntl::{AT_EMPTY_PATH, AT_FDCWD, AT_REMOVEDIR}, + fcntl::AT_EMPTY_PATH, signal::{SIGCHLD, sigevent}, sys_resource::{rlimit, rusage}, sys_select::timeval, @@ -174,6 +174,8 @@ impl Pal for Sys { e_raw(unsafe { syscall!(FCHDIR, fildes) }).map(|_| ()) } + // Override the default impl in Sys because `fchmodat(fildes, "", mode, AT_EMPTY_PATH)` doesn't + // seem to be equivalent to `fchmod(fildes, mode)` on Linux. fn fchmod(fildes: c_int, mode: mode_t) -> Result<()> { e_raw(unsafe { syscall!(FCHMOD, fildes, mode) }).map(|_| ()) } @@ -191,10 +193,6 @@ impl Pal for Sys { .map(|_| ()) } - fn fchown(fildes: c_int, owner: uid_t, group: gid_t) -> Result<()> { - e_raw(unsafe { syscall!(FCHOWN, fildes, owner, group) }).map(|_| ()) - } - fn fdatasync(fildes: c_int) -> Result<()> { e_raw(unsafe { syscall!(FDATASYNC, fildes) }).map(|_| ()) } @@ -203,21 +201,6 @@ impl Pal for Sys { e_raw(unsafe { syscall!(FLOCK, fd, operation) }).map(|_| ()) } - fn fstat(fildes: c_int, mut buf: Out) -> Result<()> { - let empty = b"\0"; - let empty_ptr = empty.as_ptr().cast::(); - e_raw(unsafe { - syscall!( - NEWFSTATAT, - fildes, - empty_ptr, - buf.as_mut_ptr(), - AT_EMPTY_PATH - ) - }) - .map(|_| ()) - } - fn fstatat(fildes: c_int, path: Option, mut buf: Out, flags: c_int) -> Result<()> { e_raw(unsafe { syscall!( @@ -455,26 +438,6 @@ impl Pal for Sys { unsafe { syscall!(GETUID) as uid_t } } - #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] - fn lchown(path: CStr, owner: uid_t, group: gid_t) -> Result<()> { - e_raw(unsafe { syscall!(LCHOWN, path.as_ptr(), owner, group) }).map(|_| ()) - } - - #[cfg(target_arch = "aarch64")] - fn lchown(path: CStr, owner: uid_t, group: gid_t) -> Result<()> { - e_raw(unsafe { - syscall!( - FCHOWNAT, - AT_FDCWD, - path.as_ptr(), - owner as u32, - group as u32, - crate::header::fcntl::AT_SYMLINK_NOFOLLOW - ) - }) - .map(|_| ()) - } - 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(|_| ()) @@ -503,10 +466,6 @@ impl Pal for Sys { Sys::mknodat(dir_fd, path, mode | S_IFIFO, 0) } - fn mkfifo(path: CStr, mode: mode_t) -> Result<()> { - Sys::mknod(path, mode | S_IFIFO, 0) - } - unsafe fn mlock(addr: *const c_void, len: usize) -> Result<()> { e_raw(unsafe { syscall!(MLOCK, addr, len) }).map(|_| ()) } @@ -564,11 +523,6 @@ impl Pal for Sys { e_raw(unsafe { syscall!(NANOSLEEP, rqtp, rmtp) }).map(|_| ()) } - fn open(path: CStr, oflag: c_int, mode: mode_t) -> Result { - e_raw(unsafe { syscall!(OPENAT, AT_FDCWD, path.as_ptr(), oflag, mode) }) - .map(|fd| fd as c_int) - } - fn openat(dirfd: c_int, path: CStr, oflag: c_int, mode: mode_t) -> Result { e_raw(unsafe { syscall!(OPENAT, dirfd, path.as_ptr(), oflag, mode) }).map(|fd| fd as c_int) } @@ -706,19 +660,6 @@ impl Pal for Sys { }) } - fn renameat(old_dir: c_int, old_path: CStr, new_dir: c_int, new_path: CStr) -> Result<()> { - e_raw(unsafe { - syscall!( - RENAMEAT, - old_dir, - old_path.as_ptr(), - new_dir, - new_path.as_ptr() - ) - }) - .map(|_| ()) - } - fn renameat2( old_dir: c_int, old_path: CStr, @@ -739,10 +680,6 @@ impl Pal for Sys { .map(|_| ()) } - fn rmdir(path: CStr) -> Result<()> { - e_raw(unsafe { syscall!(UNLINKAT, AT_FDCWD, path.as_ptr(), AT_REMOVEDIR) }).map(|_| ()) - } - fn sched_yield() -> Result<()> { e_raw(unsafe { syscall!(SCHED_YIELD) }).map(|_| ()) } diff --git a/src/platform/pal/mod.rs b/src/platform/pal/mod.rs index c3cabc08b1..f3ed9595b3 100644 --- a/src/platform/pal/mod.rs +++ b/src/platform/pal/mod.rs @@ -5,7 +5,7 @@ use crate::{ c_str::CStr, error::{Errno, Result}, header::{ - fcntl::{AT_EMPTY_PATH, AT_FDCWD, F_DUPFD}, + fcntl::{AT_EMPTY_PATH, AT_FDCWD, AT_REMOVEDIR, AT_SYMLINK_NOFOLLOW, F_DUPFD}, signal::sigevent, sys_resource::{rlimit, rusage}, sys_select::timeval, @@ -121,7 +121,17 @@ pub trait Pal { /// 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<()> { - Self::fstatat(fildes, Some(c"".into()), buf, 0) + Self::fstatat(fildes, Some(c"".into()), buf, AT_EMPTY_PATH) + } + + /// Platform implementation of [`lstat()`](crate::header::sys_stat::lstat) from [`sys/stat.h`](crate::header::sys_stat). + fn lstat(path: CStr, buf: Out) -> Result<()> { + Self::fstatat(AT_FDCWD, Some(path), buf, AT_SYMLINK_NOFOLLOW) + } + + /// Platform implementation of [`stat()`](crate::header::sys_stat::stat) from [`sys/stat.h`](crate::header::sys_stat). + fn stat(path: CStr, buf: Out) -> Result<()> { + Self::fstatat(AT_FDCWD, Some(path), buf, 0) } /// Platform implementation of [`fstatat()`](crate::header::sys_stat::fstatat) from [`sys/stat.h`](crate::header::sys_stat). @@ -253,7 +263,9 @@ pub trait Pal { fn getuid() -> uid_t; /// Platform implementation of [`lchown()`](crate::header::unistd::lchown) from [`unistd.h`](crate::header::unistd). - fn lchown(path: CStr, owner: uid_t, group: gid_t) -> Result<()>; + fn lchown(path: CStr, owner: uid_t, group: gid_t) -> Result<()> { + Self::fchownat(AT_FDCWD, path, owner, group, AT_SYMLINK_NOFOLLOW) + } /// Platform implementation of [`link()`](crate::header::unistd::link) from [`unistd.h`](crate::header::unistd). fn link(path1: CStr, path2: CStr) -> Result<()> { @@ -396,7 +408,9 @@ pub trait Pal { ) -> Result<()>; /// Platform implementation of [`rmdir()`](crate::header::unistd::rmdir) from [`unistd.h`](crate::header::unistd). - fn rmdir(path: CStr) -> Result<()>; + fn rmdir(path: CStr) -> Result<()> { + Self::unlinkat(AT_FDCWD, path, AT_REMOVEDIR) + } /// Platform implementation of [`sched_yield()`](crate::header::sched::sched_yield) from [`sched.h`](crate::header::sched). fn sched_yield() -> Result<()>; diff --git a/src/platform/redox/mod.rs b/src/platform/redox/mod.rs index ca136144d2..a1cc231e3b 100644 --- a/src/platform/redox/mod.rs +++ b/src/platform/redox/mod.rs @@ -32,9 +32,8 @@ use crate::{ ENOSYS, EOPNOTSUPP, EPERM, }, fcntl::{ - self, AT_EACCESS, AT_EMPTY_PATH, AT_FDCWD, AT_REMOVEDIR, AT_SYMLINK_FOLLOW, - AT_SYMLINK_NOFOLLOW, F_GETLK, F_OFD_GETLK, F_OFD_SETLK, F_RDLCK, F_SETLK, F_SETLKW, - F_UNLCK, F_WRLCK, flock, + self, AT_EACCESS, AT_EMPTY_PATH, AT_FDCWD, AT_REMOVEDIR, AT_SYMLINK_FOLLOW, F_GETLK, + F_OFD_GETLK, F_OFD_SETLK, F_RDLCK, F_SETLK, F_SETLKW, F_UNLCK, F_WRLCK, flock, }, limits, pthread::{pthread_cancel, pthread_create}, @@ -463,14 +462,7 @@ impl Pal for Sys { Ok(redox_rt::proc::fork_impl(&redox_rt::proc::ForkArgs::Managed)? as pid_t) } - fn fstat(fildes: c_int, mut buf: Out) -> Result<()> { - unsafe { - libredox::fstat(fildes as usize, buf.as_mut_ptr())?; - } - Ok(()) - } - - fn fstatat(dirfd: c_int, path: Option, buf: Out, flags: c_int) -> Result<()> { + fn fstatat(dirfd: c_int, path: Option, mut buf: Out, flags: c_int) -> Result<()> { // `path` should be non-null. let path = path.ok_or(Errno(EFAULT))?; let mut path = str::from_utf8(path.to_bytes()).ok().ok_or(Errno(EILSEQ))?; @@ -480,7 +472,7 @@ impl Pal for Sys { if dirfd == AT_FDCWD { path = "."; } else { - return Ok(Sys::fstat(dirfd, buf)?); + return Ok(unsafe { libredox::fstat(dirfd as usize, buf.as_mut_ptr()) }?); } } else { // If the path is empty but `AT_EMPTY_PATH` is **not** set, bail out. @@ -488,31 +480,15 @@ impl Pal for Sys { } } - // Use `O_PATH` to obtain a file descriptor without actually *opening* the file. This - // bypasses permission checks and avoids cases where opening a file is blocking operation - // (e.g., FIFOs). This gives a file descriptor where fstat(2) can be performed (and some - // other meta operations) but nothing else (e.g. read/write). - // - // `O_CLOEXEC` is used to avoid leaking file descriptors to child processes on exec(2). - // - // FIXME: Ideally we would want the file descriptor to not leak on fork(2) too because - // fstatat(2) should not have side effects. However, Redox does not currently support that, - // so we use `CLOEXEC` as a compromise. - // FIXME: Should we handle AT_* flags here or in openat2? - let mut open_flags = fcntl::O_PATH | fcntl::O_CLOEXEC; - if flags & AT_SYMLINK_NOFOLLOW == AT_SYMLINK_NOFOLLOW { - open_flags |= fcntl::O_SYMLINK | fcntl::O_NOFOLLOW; - } - - let file = openat2(dirfd, path, 0, open_flags)?; + let file = openat2(dirfd, path, flags, 0)?; // Close the file descriptor after fstat(2) regardless of success or failure. - let fstat_res = Sys::fstat(*file, buf); + let fstat_res = unsafe { libredox::fstat(*file as usize, buf.as_mut_ptr()) }; let close_res = syscall::close(*file as usize); if let Err(err) = fstat_res { - return Err(err); + return Err(err.into()); } close_res?; - fstat_res + Ok(fstat_res?) } fn fstatvfs(fildes: c_int, mut buf: Out) -> Result<()> { @@ -791,15 +767,6 @@ impl Pal for Sys { redox_rt::sys::posix_getresugid().ruid as uid_t } - fn lchown(path: CStr, owner: uid_t, group: gid_t) -> Result<()> { - // TODO: Is it correct for regular chown to use O_PATH? On Linux the meaning of that flag - // is to forbid file operations, including fchown. - - // unlike chown, never follow symbolic links - let file = File::open(path, fcntl::O_CLOEXEC | fcntl::O_NOFOLLOW)?; - Self::fchown(*file, owner, group) - } - 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. @@ -1141,22 +1108,6 @@ impl Pal for Sys { Sys::read(*file, out) } - fn rename(oldpath: CStr, newpath: CStr) -> Result<()> { - let newpath = newpath.to_str().map_err(|_| Errno(EINVAL))?; - let newpath = canonicalize(newpath).map_err(|_| Errno(EINVAL))?; - - let file = File::open( - oldpath, - fcntl::O_NOFOLLOW | fcntl::O_PATH | fcntl::O_CLOEXEC, - )?; - syscall::frename(*file as usize, newpath)?; - Ok(()) - } - - fn renameat(old_dir: c_int, old_path: CStr, new_dir: c_int, new_path: CStr) -> Result<()> { - Sys::renameat2(old_dir, old_path, new_dir, new_path, 0) - } - fn renameat2( old_dir: c_int, old_path: CStr, @@ -1190,13 +1141,6 @@ impl Pal for Sys { .map_err(Into::into) } - fn rmdir(path: CStr) -> Result<()> { - let path = path.to_str().map_err(|_| Errno(EINVAL))?; - let canon = canonicalize(path)?; - redox_rt::sys::unlink(&canon, fcntl::AT_REMOVEDIR as usize)?; - Ok(()) - } - fn sched_yield() -> Result<()> { syscall::sched_yield()?; Ok(()) @@ -1251,10 +1195,6 @@ impl Pal for Sys { Ok(()) } - fn symlink(path1: CStr, path2: CStr) -> Result<()> { - Sys::symlinkat(path1, AT_FDCWD, path2) - } - fn symlinkat(path1: CStr, fd: c_int, path2: CStr) -> Result<()> { let mut file = File::createat( fd, @@ -1524,13 +1464,6 @@ impl Pal for Sys { Ok(()) } - fn unlink(path: CStr) -> Result<()> { - let path = path.to_str().map_err(|_| Errno(EINVAL))?; - let canon = canonicalize(path)?; - redox_rt::sys::unlink(&canon, 0)?; - Ok(()) - } - fn unlinkat(fd: c_int, path: CStr, flags: c_int) -> Result<()> { if (flags & !AT_REMOVEDIR) != 0 { return Err(Errno(EINVAL));