Initial check in
Bug: 137197907
diff --git a/src/libstd/sys/wasi/fd.rs b/src/libstd/sys/wasi/fd.rs
new file mode 100644
index 0000000..0b68b6f
--- /dev/null
+++ b/src/libstd/sys/wasi/fd.rs
@@ -0,0 +1,350 @@
+#![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::<IoVecMut<'_>>(),
+ mem::size_of::<libc::__wasi_iovec_t>()
+ );
+ assert_eq!(
+ mem::align_of::<IoVecMut<'_>>(),
+ mem::align_of::<libc::__wasi_iovec_t>()
+ );
+ (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::<IoVec<'_>>(),
+ mem::size_of::<libc::__wasi_ciovec_t>()
+ );
+ assert_eq!(
+ mem::align_of::<IoVec<'_>>(),
+ mem::align_of::<libc::__wasi_ciovec_t>()
+ );
+ (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<usize> {
+ 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<usize> {
+ 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<usize> {
+ 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<usize> {
+ 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<u64> {
+ 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<u64> {
+ 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<WasiFd> {
+ 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<usize> {
+ 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<usize> {
+ 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<usize> {
+ 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);
+ }
+ }
+}