#![allow(dead_code)] use crate::io::{self, IoVec, IoVecMut, SeekFrom}; use crate::mem; use crate::net::Shutdown; use crate::sys::cvt_wasi; use libc::{self, c_char, c_void}; #[derive(Debug)] pub struct WasiFd { fd: libc::__wasi_fd_t, } // FIXME: these should probably all be fancier structs, builders, enums, etc pub type LookupFlags = u32; pub type FdFlags = u16; pub type Advice = u8; pub type Rights = u64; pub type Oflags = u16; pub type DirCookie = u64; pub type Timestamp = u64; pub type FstFlags = u16; pub type RiFlags = u16; pub type RoFlags = u16; pub type SiFlags = u16; fn iovec(a: &mut [IoVecMut<'_>]) -> (*const libc::__wasi_iovec_t, usize) { assert_eq!( mem::size_of::>(), mem::size_of::() ); assert_eq!( mem::align_of::>(), mem::align_of::() ); (a.as_ptr() as *const libc::__wasi_iovec_t, a.len()) } fn ciovec(a: &[IoVec<'_>]) -> (*const libc::__wasi_ciovec_t, usize) { assert_eq!( mem::size_of::>(), mem::size_of::() ); assert_eq!( mem::align_of::>(), mem::align_of::() ); (a.as_ptr() as *const libc::__wasi_ciovec_t, a.len()) } impl WasiFd { pub unsafe fn from_raw(fd: libc::__wasi_fd_t) -> WasiFd { WasiFd { fd } } pub fn into_raw(self) -> libc::__wasi_fd_t { let ret = self.fd; mem::forget(self); ret } pub fn as_raw(&self) -> libc::__wasi_fd_t { self.fd } pub fn datasync(&self) -> io::Result<()> { cvt_wasi(unsafe { libc::__wasi_fd_datasync(self.fd) }) } pub fn pread(&self, bufs: &mut [IoVecMut<'_>], offset: u64) -> io::Result { let mut read = 0; let (ptr, len) = iovec(bufs); cvt_wasi(unsafe { libc::__wasi_fd_pread(self.fd, ptr, len, offset, &mut read) })?; Ok(read) } pub fn pwrite(&self, bufs: &[IoVec<'_>], offset: u64) -> io::Result { let mut read = 0; let (ptr, len) = ciovec(bufs); cvt_wasi(unsafe { libc::__wasi_fd_pwrite(self.fd, ptr, len, offset, &mut read) })?; Ok(read) } pub fn read(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result { let mut read = 0; let (ptr, len) = iovec(bufs); cvt_wasi(unsafe { libc::__wasi_fd_read(self.fd, ptr, len, &mut read) })?; Ok(read) } pub fn write(&self, bufs: &[IoVec<'_>]) -> io::Result { let mut read = 0; let (ptr, len) = ciovec(bufs); cvt_wasi(unsafe { libc::__wasi_fd_write(self.fd, ptr, len, &mut read) })?; Ok(read) } pub fn seek(&self, pos: SeekFrom) -> io::Result { let (whence, offset) = match pos { SeekFrom::Start(pos) => (libc::__WASI_WHENCE_SET, pos as i64), SeekFrom::End(pos) => (libc::__WASI_WHENCE_END, pos), SeekFrom::Current(pos) => (libc::__WASI_WHENCE_CUR, pos), }; let mut pos = 0; cvt_wasi(unsafe { libc::__wasi_fd_seek(self.fd, offset, whence, &mut pos) })?; Ok(pos) } pub fn tell(&self) -> io::Result { let mut pos = 0; cvt_wasi(unsafe { libc::__wasi_fd_tell(self.fd, &mut pos) })?; Ok(pos) } // FIXME: __wasi_fd_fdstat_get pub fn set_flags(&self, flags: FdFlags) -> io::Result<()> { cvt_wasi(unsafe { libc::__wasi_fd_fdstat_set_flags(self.fd, flags) }) } pub fn set_rights(&self, base: Rights, inheriting: Rights) -> io::Result<()> { cvt_wasi(unsafe { libc::__wasi_fd_fdstat_set_rights(self.fd, base, inheriting) }) } pub fn sync(&self) -> io::Result<()> { cvt_wasi(unsafe { libc::__wasi_fd_sync(self.fd) }) } pub fn advise(&self, offset: u64, len: u64, advice: Advice) -> io::Result<()> { cvt_wasi(unsafe { libc::__wasi_fd_advise(self.fd, offset, len, advice as u8) }) } pub fn allocate(&self, offset: u64, len: u64) -> io::Result<()> { cvt_wasi(unsafe { libc::__wasi_fd_allocate(self.fd, offset, len) }) } pub fn create_directory(&self, path: &[u8]) -> io::Result<()> { cvt_wasi(unsafe { libc::__wasi_path_create_directory(self.fd, path.as_ptr() as *const c_char, path.len()) }) } pub fn link( &self, old_flags: LookupFlags, old_path: &[u8], new_fd: &WasiFd, new_path: &[u8], ) -> io::Result<()> { cvt_wasi(unsafe { libc::__wasi_path_link( self.fd, old_flags, old_path.as_ptr() as *const c_char, old_path.len(), new_fd.fd, new_path.as_ptr() as *const c_char, new_path.len(), ) }) } pub fn open( &self, dirflags: LookupFlags, path: &[u8], oflags: Oflags, fs_rights_base: Rights, fs_rights_inheriting: Rights, fs_flags: FdFlags, ) -> io::Result { unsafe { let mut fd = 0; cvt_wasi(libc::__wasi_path_open( self.fd, dirflags, path.as_ptr() as *const c_char, path.len(), oflags, fs_rights_base, fs_rights_inheriting, fs_flags, &mut fd, ))?; Ok(WasiFd::from_raw(fd)) } } pub fn readdir(&self, buf: &mut [u8], cookie: DirCookie) -> io::Result { let mut used = 0; cvt_wasi(unsafe { libc::__wasi_fd_readdir( self.fd, buf.as_mut_ptr() as *mut c_void, buf.len(), cookie, &mut used, ) })?; Ok(used) } pub fn readlink(&self, path: &[u8], buf: &mut [u8]) -> io::Result { let mut used = 0; cvt_wasi(unsafe { libc::__wasi_path_readlink( self.fd, path.as_ptr() as *const c_char, path.len(), buf.as_mut_ptr() as *mut c_char, buf.len(), &mut used, ) })?; Ok(used) } pub fn rename(&self, old_path: &[u8], new_fd: &WasiFd, new_path: &[u8]) -> io::Result<()> { cvt_wasi(unsafe { libc::__wasi_path_rename( self.fd, old_path.as_ptr() as *const c_char, old_path.len(), new_fd.fd, new_path.as_ptr() as *const c_char, new_path.len(), ) }) } pub fn filestat_get(&self, buf: *mut libc::__wasi_filestat_t) -> io::Result<()> { cvt_wasi(unsafe { libc::__wasi_fd_filestat_get(self.fd, buf) }) } pub fn filestat_set_times( &self, atim: Timestamp, mtim: Timestamp, fstflags: FstFlags, ) -> io::Result<()> { cvt_wasi(unsafe { libc::__wasi_fd_filestat_set_times(self.fd, atim, mtim, fstflags) }) } pub fn filestat_set_size(&self, size: u64) -> io::Result<()> { cvt_wasi(unsafe { libc::__wasi_fd_filestat_set_size(self.fd, size) }) } pub fn path_filestat_get( &self, flags: LookupFlags, path: &[u8], buf: *mut libc::__wasi_filestat_t, ) -> io::Result<()> { cvt_wasi(unsafe { libc::__wasi_path_filestat_get( self.fd, flags, path.as_ptr() as *const c_char, path.len(), buf, ) }) } pub fn path_filestat_set_times( &self, flags: LookupFlags, path: &[u8], atim: Timestamp, mtim: Timestamp, fstflags: FstFlags, ) -> io::Result<()> { cvt_wasi(unsafe { libc::__wasi_path_filestat_set_times( self.fd, flags, path.as_ptr() as *const c_char, path.len(), atim, mtim, fstflags, ) }) } pub fn symlink(&self, old_path: &[u8], new_path: &[u8]) -> io::Result<()> { cvt_wasi(unsafe { libc::__wasi_path_symlink( old_path.as_ptr() as *const c_char, old_path.len(), self.fd, new_path.as_ptr() as *const c_char, new_path.len(), ) }) } pub fn unlink_file(&self, path: &[u8]) -> io::Result<()> { cvt_wasi(unsafe { libc::__wasi_path_unlink_file(self.fd, path.as_ptr() as *const c_char, path.len()) }) } pub fn remove_directory(&self, path: &[u8]) -> io::Result<()> { cvt_wasi(unsafe { libc::__wasi_path_remove_directory(self.fd, path.as_ptr() as *const c_char, path.len()) }) } pub fn sock_recv( &self, ri_data: &mut [IoVecMut<'_>], ri_flags: RiFlags, ) -> io::Result<(usize, RoFlags)> { let mut ro_datalen = 0; let mut ro_flags = 0; let (ptr, len) = iovec(ri_data); cvt_wasi(unsafe { libc::__wasi_sock_recv(self.fd, ptr, len, ri_flags, &mut ro_datalen, &mut ro_flags) })?; Ok((ro_datalen, ro_flags)) } pub fn sock_send(&self, si_data: &[IoVec<'_>], si_flags: SiFlags) -> io::Result { let mut so_datalen = 0; let (ptr, len) = ciovec(si_data); cvt_wasi(unsafe { libc::__wasi_sock_send(self.fd, ptr, len, si_flags, &mut so_datalen) })?; Ok(so_datalen) } pub fn sock_shutdown(&self, how: Shutdown) -> io::Result<()> { let how = match how { Shutdown::Read => libc::__WASI_SHUT_RD, Shutdown::Write => libc::__WASI_SHUT_WR, Shutdown::Both => libc::__WASI_SHUT_WR | libc::__WASI_SHUT_RD, }; cvt_wasi(unsafe { libc::__wasi_sock_shutdown(self.fd, how) })?; Ok(()) } } impl Drop for WasiFd { fn drop(&mut self) { unsafe { // FIXME: can we handle the return code here even though we can't on // unix? libc::__wasi_fd_close(self.fd); } } }