75ca2cf29e
Linux's variant uses the syscall as intended. Redox's variant uses fpath to build a path to pass to mkdir from the file descriptor plus the file name, which isn't atomic due to the fpath lookup being subject to TOCTOU when paired with mkdir.
232 lines
6.7 KiB
Rust
232 lines
6.7 KiB
Rust
//! `sys/stat.h` implementation.
|
|
//!
|
|
//! See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_stat.h.html>.
|
|
|
|
use crate::{
|
|
c_str::CStr,
|
|
error::ResultExt,
|
|
header::{
|
|
fcntl::{O_NOFOLLOW, O_PATH},
|
|
time::timespec,
|
|
},
|
|
out::Out,
|
|
platform::{
|
|
Pal, Sys,
|
|
types::{
|
|
blkcnt_t, blksize_t, c_char, c_int, dev_t, gid_t, ino_t, mode_t, nlink_t, off_t, uid_t,
|
|
useconds_t,
|
|
},
|
|
},
|
|
};
|
|
|
|
pub const S_IFMT: c_int = 0o0_170_000;
|
|
|
|
pub const S_IFDIR: c_int = 0o040_000;
|
|
pub const S_IFCHR: c_int = 0o020_000;
|
|
pub const S_IFBLK: c_int = 0o060_000;
|
|
pub const S_IFREG: c_int = 0o100_000;
|
|
pub const S_IFIFO: c_int = 0o010_000;
|
|
pub const S_IFLNK: c_int = 0o120_000;
|
|
pub const S_IFSOCK: c_int = 0o140_000;
|
|
|
|
pub const S_IRWXU: c_int = 0o0_700;
|
|
pub const S_IRUSR: c_int = 0o0_400;
|
|
pub const S_IWUSR: c_int = 0o0_200;
|
|
pub const S_IXUSR: c_int = 0o0_100;
|
|
|
|
// Defined for compatibility
|
|
pub const S_IREAD: c_int = S_IRUSR;
|
|
pub const S_IWRITE: c_int = S_IWUSR;
|
|
pub const S_IEXEC: c_int = S_IXUSR;
|
|
|
|
pub const S_IRWXG: c_int = 0o0_070;
|
|
pub const S_IRGRP: c_int = 0o0_040;
|
|
pub const S_IWGRP: c_int = 0o0_020;
|
|
pub const S_IXGRP: c_int = 0o0_010;
|
|
|
|
pub const S_IRWXO: c_int = 0o0_007;
|
|
pub const S_IROTH: c_int = 0o0_004;
|
|
pub const S_IWOTH: c_int = 0o0_002;
|
|
pub const S_IXOTH: c_int = 0o0_001;
|
|
pub const S_ISUID: c_int = 0o4_000;
|
|
pub const S_ISGID: c_int = 0o2_000;
|
|
pub const S_ISVTX: c_int = 0o1_000;
|
|
|
|
pub const UTIME_NOW: useconds_t = (1 << 30) - 1;
|
|
pub const UTIME_OMIT: useconds_t = (1 << 30) - 2;
|
|
|
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/sys_stat.h.html>.
|
|
#[repr(C)]
|
|
#[derive(Default)]
|
|
pub struct stat {
|
|
pub st_dev: dev_t,
|
|
pub st_ino: ino_t,
|
|
pub st_nlink: nlink_t,
|
|
pub st_mode: mode_t,
|
|
pub st_uid: uid_t,
|
|
pub st_gid: gid_t,
|
|
pub st_rdev: dev_t,
|
|
pub st_size: off_t,
|
|
pub st_blksize: blksize_t,
|
|
pub st_blocks: blkcnt_t,
|
|
|
|
pub st_atim: timespec,
|
|
pub st_mtim: timespec,
|
|
pub st_ctim: timespec,
|
|
|
|
// Compared to glibc, our struct is for some reason 24 bytes too small.
|
|
// Accessing atime works, so clearly the struct isn't incorrect...
|
|
// This works.
|
|
pub _pad: [c_char; 24],
|
|
}
|
|
|
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/chmod.html>.
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn chmod(path: *const c_char, mode: mode_t) -> c_int {
|
|
let path = CStr::from_ptr(path);
|
|
Sys::chmod(path, mode).map(|()| 0).or_minus_one_errno()
|
|
}
|
|
|
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/fchmod.html>.
|
|
#[unsafe(no_mangle)]
|
|
pub extern "C" fn fchmod(fildes: c_int, mode: mode_t) -> c_int {
|
|
Sys::fchmod(fildes, mode).map(|()| 0).or_minus_one_errno()
|
|
}
|
|
|
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/fchmodat.html>.
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn fchmodat(
|
|
dirfd: c_int,
|
|
path: *const c_char,
|
|
mode: mode_t,
|
|
flags: c_int,
|
|
) -> c_int {
|
|
let path = CStr::from_nullable_ptr(path);
|
|
Sys::fchmodat(dirfd, path, mode, flags)
|
|
.map(|()| 0)
|
|
.or_minus_one_errno()
|
|
}
|
|
|
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/fstat.html>.
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn fstat(fildes: c_int, buf: *mut stat) -> c_int {
|
|
let buf = Out::nonnull(buf);
|
|
Sys::fstat(fildes, buf).map(|()| 0).or_minus_one_errno()
|
|
}
|
|
|
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/fstatat.html>.
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn fstatat(
|
|
fildes: c_int,
|
|
path: *const c_char,
|
|
buf: *mut stat,
|
|
flags: c_int,
|
|
) -> c_int {
|
|
let path = CStr::from_nullable_ptr(path);
|
|
let buf = Out::nonnull(buf);
|
|
Sys::fstatat(fildes, path, buf, flags)
|
|
.map(|()| 0)
|
|
.or_minus_one_errno()
|
|
}
|
|
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn __fxstat(_ver: c_int, fildes: c_int, buf: *mut stat) -> c_int {
|
|
fstat(fildes, buf)
|
|
}
|
|
|
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/futimens.html>.
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn futimens(fd: c_int, times: *const timespec) -> c_int {
|
|
Sys::futimens(fd, times).map(|()| 0).or_minus_one_errno()
|
|
}
|
|
|
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/lstat.html>.
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn lstat(path: *const c_char, buf: *mut stat) -> c_int {
|
|
let path = CStr::from_ptr(path);
|
|
let buf = 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();
|
|
|
|
Sys::close(fd);
|
|
|
|
res
|
|
}
|
|
|
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/mkdirat.html>.
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn mkdirat(dirfd: c_int, path: *const c_char, mode: mode_t) -> c_int {
|
|
let path = CStr::from_ptr(path);
|
|
Sys::mkdirat(dirfd, path, mode)
|
|
.map(|()| 0)
|
|
.or_minus_one_errno()
|
|
}
|
|
|
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/mkdir.html>.
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn mkdir(path: *const c_char, mode: mode_t) -> c_int {
|
|
let path = CStr::from_ptr(path);
|
|
Sys::mkdir(path, mode).map(|()| 0).or_minus_one_errno()
|
|
}
|
|
|
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/mkfifo.html>.
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn mkfifo(path: *const c_char, mode: mode_t) -> c_int {
|
|
let path = CStr::from_ptr(path);
|
|
Sys::mkfifo(path, mode).map(|()| 0).or_minus_one_errno()
|
|
}
|
|
|
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/mknod.html>.
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn mknod(path: *const c_char, mode: mode_t, dev: dev_t) -> c_int {
|
|
let path = CStr::from_ptr(path);
|
|
Sys::mknod(path, mode, dev).map(|()| 0).or_minus_one_errno()
|
|
}
|
|
|
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/mknodat.html>.
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn mknodat(
|
|
dirfd: c_int,
|
|
path: *const c_char,
|
|
mode: mode_t,
|
|
dev: dev_t,
|
|
) -> c_int {
|
|
let path = CStr::from_ptr(path);
|
|
Sys::mknodat(dirfd, path, mode, dev)
|
|
.map(|()| 0)
|
|
.or_minus_one_errno()
|
|
}
|
|
|
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/stat.html>.
|
|
#[unsafe(no_mangle)]
|
|
pub unsafe extern "C" fn stat(file: *const c_char, buf: *mut stat) -> c_int {
|
|
let file = CStr::from_ptr(file);
|
|
let buf = 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();
|
|
|
|
Sys::close(fd);
|
|
|
|
res
|
|
}
|
|
|
|
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/umask.html>.
|
|
#[unsafe(no_mangle)]
|
|
pub extern "C" fn umask(mask: mode_t) -> mode_t {
|
|
Sys::umask(mask)
|
|
}
|