diff --git a/crates/wasi-common/src/sys/unix/hostcalls_impl/misc.rs b/crates/wasi-common/src/sys/unix/hostcalls_impl/misc.rs index 6094395a22..3e6748fbc5 100644 --- a/crates/wasi-common/src/sys/unix/hostcalls_impl/misc.rs +++ b/crates/wasi-common/src/sys/unix/hostcalls_impl/misc.rs @@ -124,9 +124,24 @@ fn poll_oneoff_handle_fd_event<'a>( ready_events: impl Iterator, yanix::poll::PollFd)>, events: &mut Vec, ) -> Result<()> { + use crate::fdentry::Descriptor; use std::{convert::TryInto, os::unix::prelude::AsRawFd}; use yanix::{file::fionread, poll::PollFlags}; + fn query_nbytes(fd: &Descriptor) -> Result { + // fionread may overflow for large files, so use another way for regular files. + if let Descriptor::OsHandle(os_handle) = fd { + let meta = os_handle.metadata()?; + if meta.file_type().is_file() { + use yanix::file::tell; + let len = meta.len(); + let host_offset = unsafe { tell(os_handle.as_raw_fd())? }; + return Ok(len - host_offset); + } + } + unsafe { Ok(fionread(fd.as_raw_fd())?.into()) } + } + for (fd_event, poll_fd) in ready_events { log::debug!("poll_oneoff_handle_fd_event fd_event = {:?}", fd_event); log::debug!("poll_oneoff_handle_fd_event poll_fd = {:?}", poll_fd); @@ -139,7 +154,7 @@ fn poll_oneoff_handle_fd_event<'a>( log::debug!("poll_oneoff_handle_fd_event revents = {:?}", revents); let nbytes = if fd_event.r#type == wasi::__WASI_EVENTTYPE_FD_READ { - unsafe { fionread(fd_event.descriptor.as_raw_fd())? } + query_nbytes(fd_event.descriptor)? } else { 0 }; diff --git a/crates/wasi-common/yanix/src/file.rs b/crates/wasi-common/yanix/src/file.rs index 54524bc234..1124dcd95e 100644 --- a/crates/wasi-common/yanix/src/file.rs +++ b/crates/wasi-common/yanix/src/file.rs @@ -235,8 +235,15 @@ pub unsafe fn fstat(fd: RawFd) -> Result { } /// `fionread()` function, equivalent to `ioctl(fd, FIONREAD, *bytes)`. -pub unsafe fn fionread(fd: RawFd) -> Result { +pub unsafe fn fionread(fd: RawFd) -> Result { let mut nread: libc::c_int = 0; Errno::from_result(libc::ioctl(fd, libc::FIONREAD, &mut nread as *mut _))?; Ok(nread.try_into()?) } + +/// This function is unsafe because it operates on a raw file descriptor. +/// It's provided, because std::io::Seek requires a mutable borrow. +pub unsafe fn tell(fd: RawFd) -> Result { + let offset: i64 = Errno::from_result(libc::lseek(fd, 0, libc::SEEK_CUR))?; + Ok(offset.try_into()?) +}