#![allow(dead_code)]
use std::{
mem::MaybeUninit,
os::fd::{AsFd, AsRawFd, FromRawFd, OwnedFd, RawFd},
sync::LazyLock,
};
use libseccomp::ScmpSyscall;
use nix::{
errno::Errno,
fcntl::{AtFlags, OFlag, OpenHow},
sys::socket::{bind, connect, Shutdown, SockFlag, SockaddrLike},
unistd::UnlinkatFlags,
NixPath,
};
use crate::{compat::RenameFlags, path::XPath, rng::randint, uts::UtsName};
#[cfg(target_pointer_width = "32")]
pub(crate) type Cookie = u32;
#[cfg(target_pointer_width = "64")]
pub(crate) type Cookie = u64;
pub(crate) fn getcookie() -> Result<Cookie, Errno> {
#[cfg(target_pointer_width = "32")]
{
randint(0u32..=u32::MAX)
}
#[cfg(target_pointer_width = "64")]
{
randint(0u64..=u64::MAX)
}
}
#[expect(clippy::disallowed_methods)]
pub(crate) static OPENAT2_COOKIE_ARG4: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static OPENAT2_COOKIE_ARG5: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub static SOCKET_COOKIE_ARG3: LazyLock<Cookie> = LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub static SOCKET_COOKIE_ARG4: LazyLock<Cookie> = LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub static SOCKET_COOKIE_ARG5: LazyLock<Cookie> = LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub static SOCKETPAIR_COOKIE_ARG4: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub static SOCKETPAIR_COOKIE_ARG5: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub static ACCEPT4_COOKIE_ARG4: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub static ACCEPT4_COOKIE_ARG5: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub static BIND_COOKIE_ARG3: LazyLock<Cookie> = LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub static BIND_COOKIE_ARG4: LazyLock<Cookie> = LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub static BIND_COOKIE_ARG5: LazyLock<Cookie> = LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub static CONNECT_COOKIE_ARG3: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub static CONNECT_COOKIE_ARG4: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub static CONNECT_COOKIE_ARG5: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub static SHUTDOWN_COOKIE_ARG2: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub static SHUTDOWN_COOKIE_ARG3: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub static SHUTDOWN_COOKIE_ARG4: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub static SHUTDOWN_COOKIE_ARG5: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static MEMFD_CREATE_COOKIE_ARG2: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static MEMFD_CREATE_COOKIE_ARG3: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static MEMFD_CREATE_COOKIE_ARG4: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static MEMFD_CREATE_COOKIE_ARG5: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static RENAMEAT2_COOKIE_ARG5: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static TRUNCATE_COOKIE_ARG2: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static TRUNCATE_COOKIE_ARG3: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static TRUNCATE_COOKIE_ARG4: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static TRUNCATE_COOKIE_ARG5: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static TRUNCATE64_COOKIE_ARG3: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static TRUNCATE64_COOKIE_ARG4: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static TRUNCATE64_COOKIE_ARG5: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static FTRUNCATE_COOKIE_ARG2: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static FTRUNCATE_COOKIE_ARG3: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static FTRUNCATE_COOKIE_ARG4: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static FTRUNCATE_COOKIE_ARG5: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static FTRUNCATE64_COOKIE_ARG3: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static FTRUNCATE64_COOKIE_ARG4: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static FTRUNCATE64_COOKIE_ARG5: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static UNAME_COOKIE_ARG1: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static UNAME_COOKIE_ARG2: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static UNAME_COOKIE_ARG3: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static UNAME_COOKIE_ARG4: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static UNAME_COOKIE_ARG5: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static UNLINKAT_COOKIE_ARG3: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static UNLINKAT_COOKIE_ARG4: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static UNLINKAT_COOKIE_ARG5: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static LINKAT_COOKIE_ARG5: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub static PIPE2_COOKIE_ARG2: LazyLock<Cookie> = LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub static PIPE2_COOKIE_ARG3: LazyLock<Cookie> = LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub static PIPE2_COOKIE_ARG4: LazyLock<Cookie> = LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub static PIPE2_COOKIE_ARG5: LazyLock<Cookie> = LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static SECCOMP_IOCTL_NOTIF_ADDFD_COOKIE_ARG3: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static SECCOMP_IOCTL_NOTIF_ADDFD_COOKIE_ARG4: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static SECCOMP_IOCTL_NOTIF_ADDFD_COOKIE_ARG5: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static SECCOMP_IOCTL_NOTIF_SEND_COOKIE_ARG3: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static SECCOMP_IOCTL_NOTIF_SEND_COOKIE_ARG4: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static SECCOMP_IOCTL_NOTIF_SEND_COOKIE_ARG5: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static PROCMAP_QUERY_COOKIE_ARG3: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static PROCMAP_QUERY_COOKIE_ARG4: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[expect(clippy::disallowed_methods)]
pub(crate) static PROCMAP_QUERY_COOKIE_ARG5: LazyLock<Cookie> =
LazyLock::new(|| getcookie().expect("getcookie"));
#[inline(always)]
pub(crate) fn safe_openat2<Fd: AsFd>(
dirfd: Fd,
path: &XPath,
mut how: OpenHow,
) -> Result<OwnedFd, Errno> {
#[expect(clippy::cast_possible_truncation)]
let fd = path.with_nix_path(|cstr| unsafe {
libc::syscall(
libc::SYS_openat2,
dirfd.as_fd().as_raw_fd(),
cstr.as_ptr(),
std::ptr::addr_of_mut!(how),
std::mem::size_of::<libc::open_how>(),
*OPENAT2_COOKIE_ARG4,
*OPENAT2_COOKIE_ARG5,
)
})? as RawFd;
Errno::result(fd)?;
Ok(unsafe { OwnedFd::from_raw_fd(fd) })
}
pub static SYS_SOCKET: LazyLock<Option<libc::c_long>> = LazyLock::new(|| {
match ScmpSyscall::from_name("socket")
.map(i32::from)
.map(libc::c_long::from)
.ok()
{
Some(n) if n < 0 => None,
Some(n) => Some(n),
None => None,
}
});
#[inline(always)]
pub fn safe_socket(
domain: libc::c_int,
stype: libc::c_int,
proto: libc::c_int,
) -> Result<OwnedFd, Errno> {
if let Some(sys_socket) = *SYS_SOCKET {
#[expect(clippy::cast_possible_truncation)]
Errno::result(unsafe {
libc::syscall(
sys_socket,
domain,
stype,
proto,
*SOCKET_COOKIE_ARG3,
*SOCKET_COOKIE_ARG4,
*SOCKET_COOKIE_ARG5,
)
})
.map(|fd| fd as RawFd)
} else {
Errno::result(unsafe { libc::socket(domain, stype, proto) })
}
.map(|fd| {
unsafe { OwnedFd::from_raw_fd(fd) }
})
}
pub static SYS_SOCKETPAIR: LazyLock<Option<libc::c_long>> = LazyLock::new(|| {
match ScmpSyscall::from_name("socketpair")
.map(i32::from)
.map(libc::c_long::from)
.ok()
{
Some(n) if n < 0 => None,
Some(n) => Some(n),
None => None,
}
});
#[inline(always)]
pub fn safe_socketpair(
domain: libc::c_int,
stype: libc::c_int,
proto: libc::c_int,
) -> Result<(OwnedFd, OwnedFd), Errno> {
let mut fds = [-1, -1];
if let Some(sys_socketpair) = *SYS_SOCKETPAIR {
Errno::result(unsafe {
libc::syscall(
sys_socketpair,
domain,
stype,
proto,
fds.as_mut_ptr(),
*SOCKETPAIR_COOKIE_ARG4,
*SOCKETPAIR_COOKIE_ARG5,
)
})?;
} else {
Errno::result(unsafe { libc::socketpair(domain, stype, proto, fds.as_mut_ptr()) })?;
}
unsafe { Ok((OwnedFd::from_raw_fd(fds[0]), OwnedFd::from_raw_fd(fds[1]))) }
}
pub static SYS_ACCEPT4: LazyLock<Option<libc::c_long>> = LazyLock::new(|| {
match ScmpSyscall::from_name("accept4")
.map(i32::from)
.map(libc::c_long::from)
.ok()
{
Some(n) if n < 0 => None,
Some(n) => Some(n),
None => None,
}
});
#[inline(always)]
pub unsafe fn safe_accept4<Fd: AsFd>(
fd: Fd,
addr: *mut libc::sockaddr,
len: *mut libc::socklen_t,
flags: SockFlag,
) -> Result<OwnedFd, Errno> {
if let Some(sys_accept4) = *SYS_ACCEPT4 {
#[expect(clippy::cast_possible_truncation)]
Errno::result(unsafe {
libc::syscall(
sys_accept4,
fd.as_fd().as_raw_fd(),
addr,
len,
flags.bits(),
*ACCEPT4_COOKIE_ARG4,
*ACCEPT4_COOKIE_ARG5,
)
})
.map(|fd| {
unsafe { OwnedFd::from_raw_fd(fd as RawFd) }
})
} else {
Errno::result(unsafe { libc::accept4(fd.as_fd().as_raw_fd(), addr, len, flags.bits()) })
.map(|fd| {
unsafe { OwnedFd::from_raw_fd(fd) }
})
}
}
#[inline(always)]
pub fn safer_accept4<Fd: AsFd>(fd: Fd, flags: SockFlag) -> Result<OwnedFd, Errno> {
unsafe { safe_accept4(fd, std::ptr::null_mut(), std::ptr::null_mut(), flags) }
}
pub(crate) static SYS_BIND: LazyLock<Option<libc::c_long>> = LazyLock::new(|| {
match ScmpSyscall::from_name("bind")
.map(i32::from)
.map(libc::c_long::from)
.ok()
{
Some(n) if n < 0 => None,
Some(n) => Some(n),
None => None,
}
});
#[inline(always)]
pub fn safe_bind<Fd: AsFd>(fd: Fd, addr: &dyn SockaddrLike) -> Result<(), Errno> {
if let Some(sys_bind) = *SYS_BIND {
Errno::result(unsafe {
libc::syscall(
sys_bind,
fd.as_fd().as_raw_fd(),
addr.as_ptr(),
addr.len(),
*BIND_COOKIE_ARG3,
*BIND_COOKIE_ARG4,
*BIND_COOKIE_ARG5,
)
})
.map(drop)
} else {
bind(fd.as_fd().as_raw_fd(), addr)
}
}
pub static SYS_CONNECT: LazyLock<Option<libc::c_long>> = LazyLock::new(|| {
match ScmpSyscall::from_name("connect")
.map(i32::from)
.map(libc::c_long::from)
.ok()
{
Some(n) if n < 0 => None,
Some(n) => Some(n),
None => None,
}
});
#[inline(always)]
pub fn safe_connect<Fd: AsFd>(fd: Fd, addr: &dyn SockaddrLike) -> Result<(), Errno> {
if let Some(sys_connect) = *SYS_CONNECT {
Errno::result(unsafe {
libc::syscall(
sys_connect,
fd.as_fd().as_raw_fd(),
addr.as_ptr(),
addr.len(),
*CONNECT_COOKIE_ARG3,
*CONNECT_COOKIE_ARG4,
*CONNECT_COOKIE_ARG5,
)
})
.map(drop)
} else {
connect(fd.as_fd().as_raw_fd(), addr)
}
}
pub static SYS_SHUTDOWN: LazyLock<Option<libc::c_long>> = LazyLock::new(|| {
match ScmpSyscall::from_name("shutdown")
.map(i32::from)
.map(libc::c_long::from)
.ok()
{
Some(n) if n < 0 => None,
Some(n) => Some(n),
None => None,
}
});
#[inline(always)]
pub fn safe_shutdown<Fd: AsFd>(fd: Fd, how: Shutdown) -> Result<(), Errno> {
let how = match how {
Shutdown::Read => libc::SHUT_RD,
Shutdown::Write => libc::SHUT_WR,
Shutdown::Both => libc::SHUT_RDWR,
};
if let Some(sys_shutdown) = *SYS_SHUTDOWN {
Errno::result(unsafe {
libc::syscall(
sys_shutdown,
fd.as_fd().as_raw_fd(),
how,
*SHUTDOWN_COOKIE_ARG2,
*SHUTDOWN_COOKIE_ARG3,
*SHUTDOWN_COOKIE_ARG4,
*SHUTDOWN_COOKIE_ARG5,
)
})
.map(drop)
} else {
Errno::result(unsafe { libc::shutdown(fd.as_fd().as_raw_fd(), how) }).map(drop)
}
}
#[inline(always)]
pub(crate) fn safe_memfd_create(name: &[u8], flags: libc::c_uint) -> Result<OwnedFd, Errno> {
#[expect(clippy::cast_possible_truncation)]
let fd = Errno::result(unsafe {
libc::syscall(
libc::SYS_memfd_create,
name.as_ptr(),
flags,
*MEMFD_CREATE_COOKIE_ARG2,
*MEMFD_CREATE_COOKIE_ARG3,
*MEMFD_CREATE_COOKIE_ARG4,
*MEMFD_CREATE_COOKIE_ARG5,
)
})? as RawFd;
Ok(unsafe { OwnedFd::from_raw_fd(fd) })
}
#[inline(always)]
pub(crate) fn safe_renameat2<Fd1: AsFd, Fd2: AsFd>(
old_dirfd: Fd1,
old_path: &XPath,
new_dirfd: Fd2,
new_path: &XPath,
flags: RenameFlags,
) -> Result<(), Errno> {
let res = old_path.with_nix_path(|old_cstr| {
new_path.with_nix_path(|new_cstr| unsafe {
libc::syscall(
libc::SYS_renameat2,
old_dirfd.as_fd().as_raw_fd(),
old_cstr.as_ptr(),
new_dirfd.as_fd().as_raw_fd(),
new_cstr.as_ptr(),
flags.bits(),
*RENAMEAT2_COOKIE_ARG5,
)
})
})??;
Errno::result(res).map(drop)
}
static SYS_TRUNCATE: LazyLock<Option<libc::c_long>> =
LazyLock::new(|| {
match ScmpSyscall::from_name("truncate")
.map(i32::from)
.map(libc::c_long::from)
.ok()
{
Some(n) if n < 0 => None,
Some(n) => Some(n),
None => None,
}
});
static SYS_TRUNCATE64: LazyLock<Option<libc::c_long>> = LazyLock::new(|| {
match ScmpSyscall::from_name("truncate64")
.map(i32::from)
.map(libc::c_long::from)
.ok()
{
Some(n) if n < 0 => None,
Some(n) => Some(n),
None => None,
}
});
static SYS_FTRUNCATE: LazyLock<Option<libc::c_long>> = LazyLock::new(|| {
match ScmpSyscall::from_name("ftruncate")
.map(i32::from)
.map(libc::c_long::from)
.ok()
{
Some(n) if n < 0 => None,
Some(n) => Some(n),
None => None,
}
});
static SYS_FTRUNCATE64: LazyLock<Option<libc::c_long>> = LazyLock::new(|| {
match ScmpSyscall::from_name("ftruncate64")
.map(i32::from)
.map(libc::c_long::from)
.ok()
{
Some(n) if n < 0 => None,
Some(n) => Some(n),
None => None,
}
});
pub(crate) fn safe_truncate(path: &XPath, len: libc::off_t) -> Result<(), Errno> {
if size_of::<libc::off_t>() > size_of::<libc::c_long>() {
return safe_truncate64(path, libc::off64_t::from(len));
}
let sys_truncate = SYS_TRUNCATE.ok_or(Errno::ENOSYS)?;
let res = path.with_nix_path(|cstr| unsafe {
libc::syscall(
sys_truncate,
cstr.as_ptr(),
len,
*TRUNCATE_COOKIE_ARG2,
*TRUNCATE_COOKIE_ARG3,
*TRUNCATE_COOKIE_ARG4,
*TRUNCATE_COOKIE_ARG5,
)
})?;
Errno::result(res).map(drop)
}
pub(crate) fn safe_truncate64(path: &XPath, len: libc::off64_t) -> Result<(), Errno> {
#[cfg(not(any(
target_pointer_width = "64",
all(target_arch = "x86_64", target_pointer_width = "32"),
target_arch = "x86",
target_arch = "arm",
target_arch = "powerpc",
target_arch = "m68k",
target_arch = "mips",
target_arch = "mips32r6",
)))]
{
compile_error!("BUG: safe_truncate64 is not implemented for this architecture!");
}
#[cfg(any(
target_pointer_width = "64",
all(target_arch = "x86_64", target_pointer_width = "32"),
))]
{
safe_truncate(path, len)
}
#[cfg(any(target_arch = "m68k", target_arch = "x86",))]
{
let sys_truncate64 = SYS_TRUNCATE64.ok_or(Errno::ENOSYS)?;
let val = len as u64;
let low = (val & 0xFFFF_FFFF) as libc::c_long;
let high = (val >> 32) as libc::c_long;
Errno::result(path.with_nix_path(|cstr| unsafe {
libc::syscall(
sys_truncate64,
cstr.as_ptr(),
low,
high,
*TRUNCATE64_COOKIE_ARG3,
*TRUNCATE64_COOKIE_ARG4,
*TRUNCATE64_COOKIE_ARG5,
)
})?)
.map(drop)
}
#[cfg(any(
target_arch = "arm",
target_arch = "powerpc",
target_arch = "mips",
target_arch = "mips32r6"
))]
{
let sys_truncate64 = SYS_TRUNCATE64.ok_or(Errno::ENOSYS)?;
let val = len as u64;
let low = (val & 0xFFFF_FFFF) as libc::c_long;
let high = (val >> 32) as libc::c_long;
Errno::result(path.with_nix_path(|cstr| unsafe {
libc::syscall(
sys_truncate64,
cstr.as_ptr(),
0 as libc::c_long,
low,
high,
*TRUNCATE64_COOKIE_ARG4,
*TRUNCATE64_COOKIE_ARG5,
)
})?)
.map(drop)
}
}
pub(crate) fn safe_ftruncate<Fd: AsFd>(fd: Fd, len: libc::off_t) -> Result<(), Errno> {
if size_of::<libc::off_t>() > size_of::<libc::c_long>() {
return safe_ftruncate64(fd, libc::off64_t::from(len));
}
let sys_ftruncate = SYS_FTRUNCATE.ok_or(Errno::ENOSYS)?;
Errno::result(unsafe {
libc::syscall(
sys_ftruncate,
fd.as_fd().as_raw_fd(),
len,
*FTRUNCATE_COOKIE_ARG2,
*FTRUNCATE_COOKIE_ARG3,
*FTRUNCATE_COOKIE_ARG4,
*FTRUNCATE_COOKIE_ARG5,
)
})
.map(drop)
}
pub(crate) fn safe_ftruncate64<Fd: AsFd>(fd: Fd, len: libc::off64_t) -> Result<(), Errno> {
#[cfg(not(any(
target_pointer_width = "64",
all(target_arch = "x86_64", target_pointer_width = "32"),
target_arch = "x86",
target_arch = "arm",
target_arch = "powerpc",
target_arch = "m68k",
target_arch = "mips",
target_arch = "mips32r6",
)))]
{
compile_error!("BUG: safe_ftruncate64 is not implemented for this architecture!");
}
#[cfg(any(
target_pointer_width = "64",
all(target_arch = "x86_64", target_pointer_width = "32"),
))]
{
safe_ftruncate(fd, len)
}
#[cfg(any(target_arch = "m68k", target_arch = "x86",))]
{
let sys_ftruncate64 = SYS_FTRUNCATE64.ok_or(Errno::ENOSYS)?;
let val = len as u64;
let low = (val & 0xFFFF_FFFF) as libc::c_long;
let high = (val >> 32) as libc::c_long;
Errno::result(unsafe {
libc::syscall(
sys_ftruncate64,
fd.as_fd().as_raw_fd(),
low,
high,
*FTRUNCATE64_COOKIE_ARG3,
*FTRUNCATE64_COOKIE_ARG4,
*FTRUNCATE64_COOKIE_ARG5,
)
})
.map(drop)
}
#[cfg(any(
target_arch = "arm",
target_arch = "powerpc",
target_arch = "mips",
target_arch = "mips32r6"
))]
{
let sys_ftruncate64 = SYS_FTRUNCATE64.ok_or(Errno::ENOSYS)?;
let val = len as u64;
let low = (val & 0xFFFF_FFFF) as libc::c_long;
let high = (val >> 32) as libc::c_long;
Errno::result(unsafe {
libc::syscall(
sys_ftruncate64,
fd.as_fd().as_raw_fd(),
0 as libc::c_long,
low,
high,
*FTRUNCATE64_COOKIE_ARG4,
*FTRUNCATE64_COOKIE_ARG5,
)
})
.map(drop)
}
}
#[inline(always)]
pub(crate) fn safe_unlinkat<Fd: AsFd>(
dirfd: Fd,
path: &XPath,
flag: UnlinkatFlags,
) -> Result<(), Errno> {
let atflag = match flag {
UnlinkatFlags::RemoveDir => AtFlags::AT_REMOVEDIR,
UnlinkatFlags::NoRemoveDir => AtFlags::empty(),
};
let res = path.with_nix_path(|cstr| unsafe {
libc::syscall(
libc::SYS_unlinkat,
dirfd.as_fd().as_raw_fd(),
cstr.as_ptr(),
atflag.bits(),
*UNLINKAT_COOKIE_ARG3,
*UNLINKAT_COOKIE_ARG4,
*UNLINKAT_COOKIE_ARG5,
)
})?;
Errno::result(res).map(drop)
}
#[inline(always)]
pub(crate) fn safe_linkat<Fd1: AsFd, Fd2: AsFd>(
olddirfd: Fd1,
oldpath: &XPath,
newdirfd: Fd2,
newpath: &XPath,
flag: AtFlags,
) -> Result<(), Errno> {
let res = oldpath.with_nix_path(|oldcstr| {
newpath.with_nix_path(|newcstr| unsafe {
libc::syscall(
libc::SYS_linkat,
olddirfd.as_fd().as_raw_fd(),
oldcstr.as_ptr(),
newdirfd.as_fd().as_raw_fd(),
newcstr.as_ptr(),
flag.bits(),
*LINKAT_COOKIE_ARG5,
)
})
})??;
Errno::result(res).map(drop)
}
#[inline(always)]
pub fn safe_uname() -> Result<UtsName, Errno> {
let mut name = UtsName::default();
Errno::result(unsafe {
libc::syscall(
libc::SYS_uname,
&raw mut name,
*UNAME_COOKIE_ARG1,
*UNAME_COOKIE_ARG2,
*UNAME_COOKIE_ARG3,
*UNAME_COOKIE_ARG4,
*UNAME_COOKIE_ARG5,
)
})?;
Ok(name)
}
#[inline(always)]
pub fn safe_pipe2(flags: OFlag) -> Result<(OwnedFd, OwnedFd), Errno> {
let mut fds = MaybeUninit::<[OwnedFd; 2]>::uninit();
Errno::result(unsafe {
libc::syscall(
libc::SYS_pipe2,
fds.as_mut_ptr(),
flags.bits(),
*PIPE2_COOKIE_ARG2,
*PIPE2_COOKIE_ARG3,
*PIPE2_COOKIE_ARG4,
*PIPE2_COOKIE_ARG5,
)
})?;
let [read, write] = unsafe { fds.assume_init() };
Ok((read, write))
}