Merge branch 'faccessat-fchownat' into 'master'
add faccessat(2) and fchownat(2) See merge request redox-os/relibc!1213
This commit is contained in:
+102
-3
@@ -2,14 +2,18 @@
|
||||
//!
|
||||
//! See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/fcntl.h.html>.
|
||||
|
||||
use core::num::NonZeroU64;
|
||||
use core::{num::NonZeroU64, slice};
|
||||
|
||||
use crate::{
|
||||
c_str::CStr,
|
||||
error::ResultExt,
|
||||
error::{Errno, ResultExt},
|
||||
header::errno::ENAMETOOLONG,
|
||||
platform::{
|
||||
Pal, Sys,
|
||||
types::{c_char, c_int, c_short, c_ulonglong, mode_t, off_t, pid_t},
|
||||
types::{
|
||||
c_char, c_int, c_short, c_ulonglong, gid_t, mode_t, off_t, pid_t, size_t, ssize_t,
|
||||
uid_t,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@@ -122,3 +126,98 @@ pub unsafe extern "C" fn posix_fallocate(fd: c_int, offset: off_t, length: off_t
|
||||
.map(|e| e.0)
|
||||
.unwrap_or_default()
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/readlinkat.html>.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn readlinkat(
|
||||
dirfd: c_int,
|
||||
pathname: *const c_char,
|
||||
buf: *mut c_char,
|
||||
len: size_t,
|
||||
) -> ssize_t {
|
||||
let pathname = unsafe { CStr::from_ptr(pathname) };
|
||||
let buf = unsafe { slice::from_raw_parts_mut(buf.cast(), len) };
|
||||
Sys::readlinkat(dirfd, pathname, buf)
|
||||
.map(|read| {
|
||||
read.try_into()
|
||||
.map_err(|_| Errno(ENAMETOOLONG))
|
||||
.or_minus_one_errno()
|
||||
})
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/linkat.html>.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn linkat(
|
||||
fd1: c_int,
|
||||
path1: *const c_char,
|
||||
fd2: c_int,
|
||||
path2: *const c_char,
|
||||
flags: c_int,
|
||||
) -> c_int {
|
||||
let path1 = unsafe { CStr::from_ptr(path1) };
|
||||
let path2 = unsafe { CStr::from_ptr(path2) };
|
||||
Sys::linkat(fd1, path1, fd2, path2, flags)
|
||||
.map(|()| 0)
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/symlinkat.html>.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn symlinkat(path1: *const c_char, fd: c_int, path2: *const c_char) -> c_int {
|
||||
let path1 = unsafe { CStr::from_ptr(path1) };
|
||||
let path2 = unsafe { CStr::from_ptr(path2) };
|
||||
Sys::symlinkat(path1, fd, path2)
|
||||
.map(|()| 0)
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/unlinkat.html>.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn unlinkat(fd: c_int, path: *const c_char, flags: c_int) -> c_int {
|
||||
let path = unsafe { CStr::from_ptr(path) };
|
||||
Sys::unlinkat(fd, path, flags)
|
||||
.map(|()| 0)
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/fexecve.html>.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn fexecve(
|
||||
fd: c_int,
|
||||
argv: *const *mut c_char,
|
||||
envp: *const *mut c_char,
|
||||
) -> c_int {
|
||||
unsafe { Sys::fexecve(fd, argv, envp) }
|
||||
.map(|()| unreachable!())
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/faccessat.html>.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn faccessat(
|
||||
fd: c_int,
|
||||
path: *const c_char,
|
||||
mode: c_int,
|
||||
flags: c_int,
|
||||
) -> c_int {
|
||||
let path = unsafe { CStr::from_ptr(path) };
|
||||
Sys::faccessat(fd, path, mode, flags)
|
||||
.map(|()| 0)
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/faccessat.html>.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn fchownat(
|
||||
fd: c_int,
|
||||
path: *const c_char,
|
||||
owner: uid_t,
|
||||
group: gid_t,
|
||||
flags: c_int,
|
||||
) -> c_int {
|
||||
let path = unsafe { CStr::from_ptr(path) };
|
||||
Sys::fchownat(fd, path, owner, group, flags)
|
||||
.map(|()| 0)
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
@@ -30,7 +30,11 @@ pub const O_NDELAY: c_int = O_NONBLOCK;
|
||||
|
||||
// Flags for capability based "at" functions
|
||||
pub const AT_FDCWD: c_int = -100;
|
||||
pub const AT_SYMLINK_NOFOLLOW: c_int = 0x0200;
|
||||
pub const AT_SYMLINK_FOLLOW: c_int = 0x2000;
|
||||
pub const AT_EMPTY_PATH: c_int = 0x4000;
|
||||
pub const AT_SYMLINK_NOFOLLOW: c_int = 0x200;
|
||||
pub const AT_REMOVEDIR: c_int = 0x200;
|
||||
// Used by linkat()
|
||||
pub const AT_SYMLINK_FOLLOW: c_int = 0x2000;
|
||||
// nonstandard extension, but likely to be in a future standard
|
||||
pub const AT_EMPTY_PATH: c_int = 0x4000;
|
||||
// only used for faccessat()
|
||||
pub const AT_EACCESS: c_int = 0x400;
|
||||
|
||||
@@ -17,8 +17,7 @@ use crate::{
|
||||
header::{
|
||||
bits_timespec::timespec,
|
||||
crypt::{crypt_data, crypt_r},
|
||||
errno::{self, ENAMETOOLONG},
|
||||
fcntl, limits,
|
||||
errno, fcntl, limits,
|
||||
stdlib::getenv,
|
||||
sys_ioctl, sys_resource,
|
||||
sys_select::timeval,
|
||||
@@ -45,13 +44,14 @@ pub use crate::header::stdio::ctermid;
|
||||
#[allow(deprecated)]
|
||||
pub use crate::header::stdio::cuserid;
|
||||
|
||||
// TODO: implement and reexport fcntl functions:
|
||||
//pub use crate::header::fcntl::{faccessat, fchownat, fexecve, linkat, readlinkat, symlinkat, unlinkat};
|
||||
|
||||
use super::{
|
||||
errno::{E2BIG, EINVAL, ENOMEM},
|
||||
stdio::snprintf,
|
||||
};
|
||||
// Export *at functions because unistd.h includes them.
|
||||
pub use crate::header::fcntl::{
|
||||
faccessat, fchownat, fexecve, linkat, readlinkat, symlinkat, unlinkat,
|
||||
};
|
||||
|
||||
use crate::header::signal::{sigprocmask, sigset_t, sigsuspend};
|
||||
|
||||
@@ -337,18 +337,6 @@ pub unsafe extern "C" fn execve(
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/exec.html>.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn fexecve(
|
||||
fd: c_int,
|
||||
argv: *const *mut c_char,
|
||||
envp: *const *mut c_char,
|
||||
) -> c_int {
|
||||
unsafe { Sys::fexecve(fd, argv, envp) }
|
||||
.map(|()| unreachable!())
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
const PATH_SEPARATOR: u8 = b':';
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/exec.html>.
|
||||
@@ -712,22 +700,6 @@ pub unsafe extern "C" fn link(path1: *const c_char, path2: *const c_char) -> c_i
|
||||
Sys::link(path1, path2).map(|()| 0).or_minus_one_errno()
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/linkat.html>.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn linkat(
|
||||
fd1: c_int,
|
||||
path1: *const c_char,
|
||||
fd2: c_int,
|
||||
path2: *const c_char,
|
||||
flags: c_int,
|
||||
) -> c_int {
|
||||
let path1 = unsafe { CStr::from_ptr(path1) };
|
||||
let path2 = unsafe { CStr::from_ptr(path2) };
|
||||
Sys::linkat(fd1, path1, fd2, path2, flags)
|
||||
.map(|()| 0)
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/lockf.html>.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn lockf(fildes: c_int, function: c_int, size: off_t) -> c_int {
|
||||
@@ -876,25 +848,6 @@ pub unsafe extern "C" fn readlink(
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/readlink.html>.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn readlinkat(
|
||||
dirfd: c_int,
|
||||
pathname: *const c_char,
|
||||
buf: *mut c_char,
|
||||
len: size_t,
|
||||
) -> ssize_t {
|
||||
let pathname = unsafe { CStr::from_ptr(pathname) };
|
||||
let buf = unsafe { slice::from_raw_parts_mut(buf.cast(), len) };
|
||||
Sys::readlinkat(dirfd, pathname, buf)
|
||||
.map(|read| {
|
||||
read.try_into()
|
||||
.map_err(|_| Errno(ENAMETOOLONG))
|
||||
.or_minus_one_errno()
|
||||
})
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/rmdir.html>.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn rmdir(path: *const c_char) -> c_int {
|
||||
@@ -1031,16 +984,6 @@ pub unsafe extern "C" fn symlink(path1: *const c_char, path2: *const c_char) ->
|
||||
Sys::symlink(path1, path2).map(|()| 0).or_minus_one_errno()
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/symlinkat.html>.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn symlinkat(path1: *const c_char, fd: c_int, path2: *const c_char) -> c_int {
|
||||
let path1 = unsafe { CStr::from_ptr(path1) };
|
||||
let path2 = unsafe { CStr::from_ptr(path2) };
|
||||
Sys::symlinkat(path1, fd, path2)
|
||||
.map(|()| 0)
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sync.html>.
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn sync() {
|
||||
@@ -1155,15 +1098,6 @@ pub unsafe extern "C" fn unlink(path: *const c_char) -> c_int {
|
||||
Sys::unlink(path).map(|()| 0).or_minus_one_errno()
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/unlinkat.html>.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn unlinkat(fd: c_int, path: *const c_char, flags: c_int) -> c_int {
|
||||
let path = unsafe { CStr::from_ptr(path) };
|
||||
Sys::unlinkat(fd, path, flags)
|
||||
.map(|()| 0)
|
||||
.or_minus_one_errno()
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/009695399/functions/usleep.html>.
|
||||
///
|
||||
/// # Deprecation
|
||||
|
||||
@@ -81,14 +81,12 @@ impl Sys {
|
||||
}
|
||||
|
||||
impl Pal for Sys {
|
||||
#[cfg(any(target_arch = "x86_64", target_arch = "x86"))]
|
||||
fn access(path: CStr, mode: c_int) -> Result<()> {
|
||||
e_raw(unsafe { syscall!(ACCESS, path.as_ptr(), mode) }).map(|_| ())
|
||||
Sys::faccessat(AT_FDCWD, path, mode, 0)
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
fn access(path: CStr, mode: c_int) -> Result<()> {
|
||||
e_raw(unsafe { syscall!(FACCESSAT, AT_FDCWD, path.as_ptr(), mode, 0) }).map(|_| ())
|
||||
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(|_| ())
|
||||
}
|
||||
|
||||
unsafe fn brk(addr: *mut c_void) -> Result<*mut c_void> {
|
||||
@@ -104,11 +102,14 @@ impl Pal for Sys {
|
||||
}
|
||||
|
||||
fn chown(path: CStr, owner: uid_t, group: gid_t) -> Result<()> {
|
||||
let flags: c_int = 0;
|
||||
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!(
|
||||
FCHOWNAT,
|
||||
AT_FDCWD,
|
||||
fildes,
|
||||
path.as_ptr(),
|
||||
owner as u32,
|
||||
group as u32,
|
||||
|
||||
@@ -37,6 +37,9 @@ 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<()>;
|
||||
|
||||
/// 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<()>;
|
||||
|
||||
/// Platform implementation of [`brk()`](crate::header::unistd::brk) from [`unistd.h`](crate::header::unistd).
|
||||
unsafe fn brk(addr: *mut c_void) -> Result<*mut c_void>;
|
||||
|
||||
@@ -95,6 +98,9 @@ pub trait Pal {
|
||||
/// 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<()>;
|
||||
|
||||
/// 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<()>;
|
||||
|
||||
/// Platform implementation of [`fdatasync()`](crate::header::unistd::fdatasync) from [`unistd.h`](crate::header::unistd).
|
||||
fn fdatasync(fildes: c_int) -> Result<()>;
|
||||
|
||||
|
||||
@@ -32,8 +32,9 @@ use crate::{
|
||||
ENOSYS, EOPNOTSUPP, EPERM,
|
||||
},
|
||||
fcntl::{
|
||||
self, 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,
|
||||
AT_SYMLINK_NOFOLLOW, 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},
|
||||
@@ -107,7 +108,15 @@ pub struct Sys;
|
||||
|
||||
impl Pal for Sys {
|
||||
fn access(path: CStr, mode: c_int) -> Result<()> {
|
||||
let fd = FdGuard::new(Sys::open(path, fcntl::O_PATH | fcntl::O_CLOEXEC, 0)? as usize);
|
||||
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);
|
||||
|
||||
if (flags & !(AT_EACCESS)) != 0 {
|
||||
return Err(Errno(EINVAL));
|
||||
}
|
||||
|
||||
if mode == F_OK {
|
||||
return Ok(());
|
||||
@@ -117,11 +126,22 @@ impl Pal for Sys {
|
||||
|
||||
fd.fstat(&mut stat)?;
|
||||
|
||||
let Resugid { ruid, rgid, .. } = redox_rt::sys::posix_getresugid();
|
||||
let Resugid {
|
||||
ruid,
|
||||
rgid,
|
||||
euid,
|
||||
egid,
|
||||
..
|
||||
} = redox_rt::sys::posix_getresugid();
|
||||
let (uid, gid) = if (flags & AT_EACCESS) == AT_EACCESS {
|
||||
(euid, egid)
|
||||
} else {
|
||||
(ruid, rgid)
|
||||
};
|
||||
|
||||
let perms = (if stat.st_uid == ruid {
|
||||
let perms = (if stat.st_uid == uid {
|
||||
stat.st_mode >> (3 * 2)
|
||||
} else if stat.st_gid == rgid {
|
||||
} else if stat.st_gid == gid {
|
||||
stat.st_mode >> (3 * 1)
|
||||
} else {
|
||||
stat.st_mode
|
||||
@@ -277,7 +297,7 @@ impl Pal for Sys {
|
||||
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 {
|
||||
return Err(Errno(EOPNOTSUPP));
|
||||
return Err(Errno(EINVAL));
|
||||
}
|
||||
let mut path = path
|
||||
.and_then(|cs| str::from_utf8(cs.to_bytes()).ok())
|
||||
@@ -306,6 +326,21 @@ impl Pal for Sys {
|
||||
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 file = openat2(fildes, path, flags, 0)?;
|
||||
libredox::fchown(
|
||||
*file as usize,
|
||||
owner.try_into().map_err(|_| Errno(EINVAL))?,
|
||||
group.try_into().map_err(|_| Errno(EINVAL))?,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fcntl(fd: c_int, cmd: c_int, args: c_ulonglong) -> Result<c_int> {
|
||||
match cmd {
|
||||
F_SETLK | F_OFD_SETLK => {
|
||||
|
||||
Reference in New Issue
Block a user