| #![unstable(reason = "not public", issue = "none", feature = "fd")] |
| |
| use crate::cmp; |
| use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, Read, SeekFrom}; |
| use crate::os::hermit::hermit_abi; |
| use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; |
| use crate::sys::{cvt, unsupported}; |
| use crate::sys_common::{AsInner, FromInner, IntoInner}; |
| |
| const fn max_iov() -> usize { |
| hermit_abi::IOV_MAX |
| } |
| |
| #[derive(Debug)] |
| pub struct FileDesc { |
| fd: OwnedFd, |
| } |
| |
| impl FileDesc { |
| pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { |
| let result = |
| cvt(unsafe { hermit_abi::read(self.fd.as_raw_fd(), buf.as_mut_ptr(), buf.len()) })?; |
| Ok(result as usize) |
| } |
| |
| pub fn read_buf(&self, mut buf: BorrowedCursor<'_>) -> io::Result<()> { |
| // SAFETY: The `read` syscall does not read from the buffer, so it is |
| // safe to use `&mut [MaybeUninit<u8>]`. |
| let result = cvt(unsafe { |
| hermit_abi::read( |
| self.fd.as_raw_fd(), |
| buf.as_mut().as_mut_ptr() as *mut u8, |
| buf.capacity(), |
| ) |
| })?; |
| // SAFETY: Exactly `result` bytes have been filled. |
| unsafe { buf.advance_unchecked(result as usize) }; |
| Ok(()) |
| } |
| |
| pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { |
| let ret = cvt(unsafe { |
| hermit_abi::readv( |
| self.as_raw_fd(), |
| bufs.as_mut_ptr() as *mut hermit_abi::iovec as *const hermit_abi::iovec, |
| cmp::min(bufs.len(), max_iov()), |
| ) |
| })?; |
| Ok(ret as usize) |
| } |
| |
| #[inline] |
| pub fn is_read_vectored(&self) -> bool { |
| true |
| } |
| |
| pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { |
| let mut me = self; |
| (&mut me).read_to_end(buf) |
| } |
| |
| pub fn write(&self, buf: &[u8]) -> io::Result<usize> { |
| let result = |
| cvt(unsafe { hermit_abi::write(self.fd.as_raw_fd(), buf.as_ptr(), buf.len()) })?; |
| Ok(result as usize) |
| } |
| |
| pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { |
| let ret = cvt(unsafe { |
| hermit_abi::writev( |
| self.as_raw_fd(), |
| bufs.as_ptr() as *const hermit_abi::iovec, |
| cmp::min(bufs.len(), max_iov()), |
| ) |
| })?; |
| Ok(ret as usize) |
| } |
| |
| #[inline] |
| pub fn is_write_vectored(&self) -> bool { |
| true |
| } |
| |
| pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> { |
| let (whence, pos) = match pos { |
| // Casting to `i64` is fine, too large values will end up as |
| // negative which will cause an error in `lseek`. |
| SeekFrom::Start(off) => (hermit_abi::SEEK_SET, off as i64), |
| SeekFrom::End(off) => (hermit_abi::SEEK_END, off), |
| SeekFrom::Current(off) => (hermit_abi::SEEK_CUR, off), |
| }; |
| let n = cvt(unsafe { hermit_abi::lseek(self.as_raw_fd(), pos as isize, whence) })?; |
| Ok(n as u64) |
| } |
| |
| pub fn tell(&self) -> io::Result<u64> { |
| self.seek(SeekFrom::Current(0)) |
| } |
| |
| pub fn duplicate(&self) -> io::Result<FileDesc> { |
| self.duplicate_path(&[]) |
| } |
| |
| pub fn duplicate_path(&self, _path: &[u8]) -> io::Result<FileDesc> { |
| unsupported() |
| } |
| |
| pub fn nonblocking(&self) -> io::Result<bool> { |
| Ok(false) |
| } |
| |
| pub fn set_cloexec(&self) -> io::Result<()> { |
| unsupported() |
| } |
| |
| pub fn set_nonblocking(&self, _nonblocking: bool) -> io::Result<()> { |
| unsupported() |
| } |
| |
| pub fn fstat(&self, stat: *mut hermit_abi::stat) -> io::Result<()> { |
| cvt(unsafe { hermit_abi::fstat(self.fd.as_raw_fd(), stat) })?; |
| Ok(()) |
| } |
| } |
| |
| impl<'a> Read for &'a FileDesc { |
| fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { |
| (**self).read(buf) |
| } |
| } |
| |
| impl IntoInner<OwnedFd> for FileDesc { |
| fn into_inner(self) -> OwnedFd { |
| self.fd |
| } |
| } |
| |
| impl FromInner<OwnedFd> for FileDesc { |
| fn from_inner(owned_fd: OwnedFd) -> Self { |
| Self { fd: owned_fd } |
| } |
| } |
| |
| impl FromRawFd for FileDesc { |
| unsafe fn from_raw_fd(raw_fd: RawFd) -> Self { |
| let fd = unsafe { OwnedFd::from_raw_fd(raw_fd) }; |
| Self { fd } |
| } |
| } |
| |
| impl AsInner<OwnedFd> for FileDesc { |
| #[inline] |
| fn as_inner(&self) -> &OwnedFd { |
| &self.fd |
| } |
| } |
| |
| impl AsFd for FileDesc { |
| fn as_fd(&self) -> BorrowedFd<'_> { |
| self.fd.as_fd() |
| } |
| } |
| |
| impl AsRawFd for FileDesc { |
| #[inline] |
| fn as_raw_fd(&self) -> RawFd { |
| self.fd.as_raw_fd() |
| } |
| } |
| |
| impl IntoRawFd for FileDesc { |
| fn into_raw_fd(self) -> RawFd { |
| self.fd.into_raw_fd() |
| } |
| } |