#![deny(unsafe_op_in_unsafe_fn)]
use std::os::raw::c_int;
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use std::os::unix::io::{AsFd, BorrowedFd, OwnedFd};
#[derive(Debug)]
pub struct FileDesc {
fd: OwnedFd,
}
impl FileDesc {
pub fn new(fd: OwnedFd) -> Self {
Self { fd }
}
pub unsafe fn from_raw_fd(fd: RawFd) -> Self {
unsafe {
Self::new(OwnedFd::from_raw_fd(fd))
}
}
pub fn duplicate_from<T: AsFd>(other: T) -> std::io::Result<Self> {
Ok(Self::new(other.as_fd().try_clone_to_owned()?))
}
pub unsafe fn duplicate_raw_fd(fd: RawFd) -> std::io::Result<Self> {
unsafe {
Self::duplicate_from(BorrowedFd::borrow_raw(fd))
}
}
pub fn as_fd(&self) -> BorrowedFd {
self.fd.as_fd()
}
pub fn into_fd(self) -> OwnedFd {
self.fd
}
pub fn as_raw_fd(&self) -> RawFd {
self.fd.as_raw_fd()
}
pub fn into_raw_fd(self) -> RawFd {
self.fd.into_raw_fd()
}
pub fn duplicate(&self) -> std::io::Result<Self> {
Self::duplicate_from(self)
}
pub fn set_close_on_exec(&self, close_on_exec: bool) -> std::io::Result<()> {
unsafe {
let arg = if close_on_exec { libc::FD_CLOEXEC } else { 0 };
check_ret(libc::fcntl(self.fd.as_raw_fd(), libc::F_SETFD, arg))?;
Ok(())
}
}
pub fn get_close_on_exec(&self) -> std::io::Result<bool> {
unsafe {
let ret = check_ret(libc::fcntl(self.fd.as_raw_fd(), libc::F_GETFD, 0))?;
Ok(ret & libc::FD_CLOEXEC != 0)
}
}
}
impl AsFd for FileDesc {
fn as_fd(&self) -> BorrowedFd<'_> {
self.fd.as_fd()
}
}
impl From<OwnedFd> for FileDesc {
fn from(value: OwnedFd) -> Self {
Self::new(value)
}
}
impl From<FileDesc> for OwnedFd {
fn from(value: FileDesc) -> Self {
value.fd
}
}
impl FromRawFd for FileDesc {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
unsafe {
Self::from_raw_fd(fd)
}
}
}
impl AsRawFd for FileDesc {
fn as_raw_fd(&self) -> RawFd {
self.as_raw_fd()
}
}
impl AsRawFd for &'_ FileDesc {
fn as_raw_fd(&self) -> RawFd {
(*self).as_raw_fd()
}
}
impl IntoRawFd for FileDesc {
fn into_raw_fd(self) -> RawFd {
self.into_raw_fd()
}
}
fn check_ret(ret: c_int) -> std::io::Result<c_int> {
if ret == -1 {
Err(std::io::Error::last_os_error())
} else {
Ok(ret)
}
}