use std::fmt;
use std::fs::File;
use std::io;
use std::os::fd::{AsRawFd as _, RawFd};
use std::ptr;
use std::ptr::NonNull;
#[cfg(target_os = "linux")]
const NORESERVE: libc::c_int = libc::MAP_NORESERVE;
#[cfg(not(target_os = "linux"))]
const NORESERVE: libc::c_int = 0;
pub(crate) fn granularity() -> usize {
page()
}
pub(crate) fn page() -> usize {
let size = unsafe { libc::sysconf(libc::_SC_PAGESIZE) };
usize::try_from(size).unwrap_or(4096)
}
pub(crate) struct Backing {
fd: RawFd,
}
impl Backing {
#[expect(
clippy::unnecessary_wraps,
reason = "the signature is shared with the Windows version"
)]
pub(crate) fn new(file: &File) -> io::Result<Self> {
Ok(Self {
fd: file.as_raw_fd(),
})
}
}
impl fmt::Debug for Backing {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Backing").field("fd", &self.fd).finish()
}
}
pub(crate) struct Reservation {
base: NonNull<u8>,
span: usize,
mapped: usize,
}
impl Reservation {
pub(crate) fn new(span: usize) -> io::Result<Self> {
let base = unsafe {
libc::mmap(
ptr::null_mut(),
span,
libc::PROT_NONE,
libc::MAP_PRIVATE | libc::MAP_ANONYMOUS | NORESERVE,
-1,
0,
)
};
if base == libc::MAP_FAILED {
return Err(io::Error::last_os_error());
}
let base = NonNull::new(base.cast::<u8>())
.ok_or_else(|| io::Error::other("mmap succeeded and returned a null address"))?;
Ok(Self {
base,
span,
mapped: 0,
})
}
pub(crate) fn base(&self) -> NonNull<u8> {
self.base
}
pub(crate) fn span(&self) -> usize {
self.span
}
pub(crate) fn map(&mut self, backing: &Backing, offset: u64, len: usize) -> io::Result<()> {
debug_assert!(
len <= self.span,
"the caller clamps a view to the reservation"
);
let offset = libc::off_t::try_from(offset).map_err(|_| {
io::Error::other("the mapping offset is past what this platform can express")
})?;
let got = unsafe {
libc::mmap(
self.base.as_ptr().cast(),
len,
libc::PROT_READ,
libc::MAP_PRIVATE | libc::MAP_FIXED,
backing.fd,
offset,
)
};
if got == libc::MAP_FAILED {
return Err(io::Error::last_os_error());
}
self.mapped = len;
Ok(())
}
pub(crate) fn unmap(&mut self) -> io::Result<()> {
if self.mapped == 0 {
return Ok(());
}
let got = unsafe {
libc::mmap(
self.base.as_ptr().cast(),
self.mapped,
libc::PROT_NONE,
libc::MAP_PRIVATE | libc::MAP_ANONYMOUS | libc::MAP_FIXED | NORESERVE,
-1,
0,
)
};
if got == libc::MAP_FAILED {
return Err(io::Error::last_os_error());
}
self.mapped = 0;
Ok(())
}
}
impl Drop for Reservation {
fn drop(&mut self) {
unsafe {
libc::munmap(self.base.as_ptr().cast(), self.span);
}
}
}
impl fmt::Debug for Reservation {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Reservation")
.field("base", &self.base)
.field("span", &self.span)
.field("mapped", &self.mapped)
.finish()
}
}
unsafe impl Send for Reservation {}
unsafe impl Sync for Reservation {}
#[cfg(feature = "probe")]
pub(crate) fn readable(ptr: *const u8, len: usize) -> bool {
if len == 0 {
return true;
}
let last = unsafe { ptr.add(len - 1) };
probe_one(ptr) && probe_one(last)
}
#[cfg(feature = "probe")]
pub(crate) fn handles() -> Option<u32> {
for directory in ["/proc/self/fd", "/dev/fd"] {
if let Ok(entries) = std::fs::read_dir(directory) {
return u32::try_from(entries.count()).ok();
}
}
None
}
#[cfg(feature = "probe")]
fn probe_one(ptr: *const u8) -> bool {
let mut ends = [0 as libc::c_int; 2];
if unsafe { libc::pipe(ends.as_mut_ptr()) } != 0 {
return false;
}
let written = unsafe { libc::write(ends[1], ptr.cast(), 1) };
let error = io::Error::last_os_error();
unsafe {
libc::close(ends[0]);
libc::close(ends[1]);
}
written >= 0 || error.raw_os_error() != Some(libc::EFAULT)
}