use crate::errors::ShmapError;
use memmap2::{MmapAsRawDesc, MmapRawDescriptor};
use std::os::unix::io::RawFd;
pub const SHM_DIR: &str = "/dev/shm";
#[derive(Debug)]
pub struct Fd(RawFd);
impl From<RawFd> for Fd {
fn from(value: RawFd) -> Self {
Self(value)
}
}
impl MmapAsRawDesc for Fd {
fn as_raw_desc(&self) -> MmapRawDescriptor {
self.0.as_raw_desc()
}
}
impl Drop for Fd {
fn drop(&mut self) {
unsafe {
libc::close(self.0);
}
}
}
pub fn open_read(name: &str) -> Result<Fd, ShmapError> {
let fd = shm_open(name, libc::O_RDONLY)?;
if fd < 0 {
let err = std::io::Error::last_os_error();
if err.kind() == std::io::ErrorKind::NotFound {
Err(ShmapError::ShmFileNotFound)
} else {
Err(ShmapError::IOError(err))
}
} else {
Ok(fd.into())
}
}
pub fn open_write(name: &str, length: usize) -> Result<Fd, ShmapError> {
let fd = shm_open(name, libc::O_RDWR | libc::O_CREAT | libc::O_TRUNC)?;
if fd < 0 {
let err = std::io::Error::last_os_error();
return Err(ShmapError::IOError(err));
}
#[allow(clippy::cast_possible_wrap)]
let ret = unsafe { libc::ftruncate(fd, length as libc::off_t) };
if ret != 0 {
let err = std::io::Error::last_os_error();
Err(ShmapError::IOError(err))
} else {
Ok(fd.into())
}
}
fn shm_open(name: &str, flags: i32) -> Result<RawFd, ShmapError> {
let name = std::ffi::CString::new(name)?;
let fd = unsafe { libc::shm_open(name.as_ptr(), flags, 0o600) };
Ok(fd)
}
pub fn unlink(name: &str) -> Result<(), ShmapError> {
let c_name = std::ffi::CString::new(name)?;
let ret = unsafe { libc::shm_unlink(c_name.as_ptr()) };
if ret != 0 {
let err = std::io::Error::last_os_error();
if err.kind() == std::io::ErrorKind::NotFound {
Ok(())
} else {
Err(ShmapError::IOError(err))
}
} else {
Ok(())
}
}