Add template for Windows impl

This commit is contained in:
Jakub Konka
2019-05-20 11:04:51 +02:00
committed by Dan Gohman
parent 7605584691
commit c3ff3cf075
20 changed files with 575 additions and 339 deletions

View File

@@ -0,0 +1,89 @@
use crate::host;
use std::fs::File;
use std::os::windows::prelude::{AsRawHandle, FromRawHandle, IntoRawHandle, RawHandle};
use std::path::PathBuf;
use winapi::shared::minwindef::FALSE;
use winapi::um::handleapi::DuplicateHandle;
use winapi::um::processthreadsapi::GetCurrentProcess;
use winapi::um::winnt::DUPLICATE_SAME_ACCESS;
#[derive(Clone, Debug)]
pub struct FdObject {
pub ty: host::__wasi_filetype_t,
pub raw_handle: RawHandle,
pub needs_close: bool,
// TODO: directories
}
#[derive(Clone, Debug)]
pub struct FdEntry {
pub fd_object: FdObject,
pub rights_base: host::__wasi_rights_t,
pub rights_inheriting: host::__wasi_rights_t,
pub preopen_path: Option<PathBuf>,
}
impl Drop for FdObject {
fn drop(&mut self) {
if self.needs_close {
unsafe {
if winapi::um::handleapi::CloseHandle(self.raw_handle) == 0 {
// TODO: use DWORD WINAPI GetLastError(void) to get error
eprintln!("FdObject::drop(): couldn't close raw Handle");
}
}
}
}
}
impl FdEntry {
pub fn from_file(file: File) -> Self {
unsafe { Self::from_raw_handle(file.into_raw_handle()) }
}
pub fn duplicate<F: AsRawHandle>(fd: &F) -> Self {
unsafe {
let source = fd.as_raw_handle();
let mut dest = 0 as RawHandle;
let cur_proc = GetCurrentProcess();
if DuplicateHandle(
cur_proc,
source,
cur_proc,
&mut dest,
0, // dwDesiredAccess; this flag is ignored if DUPLICATE_SAME_ACCESS is specified
FALSE,
DUPLICATE_SAME_ACCESS,
) == FALSE
{
panic!("Couldn't duplicate handle");
}
Self::from_raw_handle(dest)
}
}
}
impl FromRawHandle for FdEntry {
// TODO: implement
unsafe fn from_raw_handle(raw_handle: RawHandle) -> Self {
let (ty, rights_base, rights_inheriting) = (
host::__WASI_FILETYPE_REGULAR_FILE,
host::RIGHTS_REGULAR_FILE_BASE,
host::RIGHTS_REGULAR_FILE_INHERITING,
);
Self {
fd_object: FdObject {
ty,
raw_handle,
needs_close: true,
},
rights_base,
rights_inheriting,
preopen_path: None,
}
}
}

View File

@@ -0,0 +1,84 @@
//! WASI host types specific to Windows host.
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
#![allow(unused)]
use crate::host;
use std::marker::PhantomData;
use std::slice;
use winapi::shared::{ntdef, ws2def};
// these will be obsolete once https://github.com/rust-lang/rust/pull/60334
// lands in stable
pub struct IoVec<'a> {
vec: ws2def::WSABUF,
_p: PhantomData<&'a [u8]>,
}
pub struct IoVecMut<'a> {
vec: ws2def::WSABUF,
_p: PhantomData<&'a mut [u8]>,
}
impl<'a> IoVec<'a> {
#[inline]
pub fn new(buf: &'a [u8]) -> Self {
assert!(buf.len() <= ntdef::ULONG::max_value() as usize);
Self {
vec: ws2def::WSABUF {
len: buf.len() as ntdef::ULONG,
buf: buf.as_ptr() as *mut u8 as *mut ntdef::CHAR,
},
_p: PhantomData,
}
}
#[inline]
pub fn as_slice(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.vec.buf as *mut u8, self.vec.len as usize) }
}
}
impl<'a> IoVecMut<'a> {
#[inline]
pub fn new(buf: &'a mut [u8]) -> Self {
assert!(buf.len() <= ntdef::ULONG::max_value() as usize);
Self {
vec: ws2def::WSABUF {
len: buf.len() as ntdef::ULONG,
buf: buf.as_mut_ptr() as *mut u8 as *mut ntdef::CHAR,
},
_p: PhantomData,
}
}
#[inline]
pub fn as_slice(&self) -> &[u8] {
unsafe { slice::from_raw_parts(self.vec.buf as *mut u8, self.vec.len as usize) }
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [u8] {
unsafe { slice::from_raw_parts_mut(self.vec.buf as *mut u8, self.vec.len as usize) }
}
}
pub unsafe fn ciovec_to_win<'a>(ciovec: &'a host::__wasi_ciovec_t) -> IoVec<'a> {
let slice = slice::from_raw_parts(ciovec.buf as *const u8, ciovec.buf_len);
IoVec::new(slice)
}
pub unsafe fn ciovec_to_win_mut<'a>(ciovec: &'a mut host::__wasi_ciovec_t) -> IoVecMut<'a> {
let slice = slice::from_raw_parts_mut(ciovec.buf as *mut u8, ciovec.buf_len);
IoVecMut::new(slice)
}
pub unsafe fn iovec_to_win<'a>(iovec: &'a host::__wasi_iovec_t) -> IoVec<'a> {
let slice = slice::from_raw_parts(iovec.buf as *const u8, iovec.buf_len);
IoVec::new(slice)
}
pub unsafe fn iovec_to_win_mut<'a>(iovec: &'a mut host::__wasi_iovec_t) -> IoVecMut<'a> {
let slice = slice::from_raw_parts_mut(iovec.buf as *mut u8, iovec.buf_len);
IoVecMut::new(slice)
}

View File

@@ -0,0 +1,452 @@
#![allow(non_camel_case_types)]
#![allow(unused_unsafe)]
#![allow(unused)]
use super::host_impl;
use super::host_impl::IoVec;
use crate::ctx::WasiCtx;
use crate::memory::*;
use crate::{host, wasm32};
use std::cmp;
use std::os::windows::prelude::OsStrExt;
use wasi_common_cbindgen::wasi_common_cbindgen;
#[wasi_common_cbindgen]
pub fn fd_close(wasi_ctx: &mut WasiCtx, fd: wasm32::__wasi_fd_t) -> wasm32::__wasi_errno_t {
unimplemented!("fd_close")
}
#[wasi_common_cbindgen]
pub fn fd_datasync(wasi_ctx: &WasiCtx, fd: wasm32::__wasi_fd_t) -> wasm32::__wasi_errno_t {
unimplemented!("fd_datasync")
}
#[wasi_common_cbindgen]
pub fn fd_pread(
wasi_ctx: &WasiCtx,
memory: &mut [u8],
fd: wasm32::__wasi_fd_t,
iovs_ptr: wasm32::uintptr_t,
iovs_len: wasm32::size_t,
offset: wasm32::__wasi_filesize_t,
nread: wasm32::uintptr_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("fd_pread")
}
#[wasi_common_cbindgen]
pub fn fd_pwrite(
wasi_ctx: &WasiCtx,
memory: &mut [u8],
fd: wasm32::__wasi_fd_t,
iovs_ptr: wasm32::uintptr_t,
iovs_len: wasm32::size_t,
offset: wasm32::__wasi_filesize_t,
nwritten: wasm32::uintptr_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("fd_pwrite")
}
#[wasi_common_cbindgen]
pub fn fd_read(
wasi_ctx: &mut WasiCtx,
memory: &mut [u8],
fd: wasm32::__wasi_fd_t,
iovs_ptr: wasm32::uintptr_t,
iovs_len: wasm32::size_t,
nread: wasm32::uintptr_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("fd_read")
}
#[wasi_common_cbindgen]
pub fn fd_renumber(
wasi_ctx: &mut WasiCtx,
from: wasm32::__wasi_fd_t,
to: wasm32::__wasi_fd_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("fd_renumber")
}
#[wasi_common_cbindgen]
pub fn fd_seek(
wasi_ctx: &WasiCtx,
memory: &mut [u8],
fd: wasm32::__wasi_fd_t,
offset: wasm32::__wasi_filedelta_t,
whence: wasm32::__wasi_whence_t,
newoffset: wasm32::uintptr_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("fd_seek")
}
#[wasi_common_cbindgen]
pub fn fd_tell(
wasi_ctx: &WasiCtx,
memory: &mut [u8],
fd: wasm32::__wasi_fd_t,
newoffset: wasm32::uintptr_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("fd_tell")
}
#[wasi_common_cbindgen]
pub fn fd_fdstat_get(
wasi_ctx: &WasiCtx,
memory: &mut [u8],
fd: wasm32::__wasi_fd_t,
fdstat_ptr: wasm32::uintptr_t, // *mut wasm32::__wasi_fdstat_t
) -> wasm32::__wasi_errno_t {
unimplemented!("fd_fdstat_get")
}
#[wasi_common_cbindgen]
pub fn fd_fdstat_set_flags(
wasi_ctx: &WasiCtx,
fd: wasm32::__wasi_fd_t,
fdflags: wasm32::__wasi_fdflags_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("fd_fdstat_set_flags")
}
#[wasi_common_cbindgen]
pub fn fd_fdstat_set_rights(
wasi_ctx: &mut WasiCtx,
fd: wasm32::__wasi_fd_t,
fs_rights_base: wasm32::__wasi_rights_t,
fs_rights_inheriting: wasm32::__wasi_rights_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("fd_fdstat_set_rights")
}
#[wasi_common_cbindgen]
pub fn fd_sync(wasi_ctx: &WasiCtx, fd: wasm32::__wasi_fd_t) -> wasm32::__wasi_errno_t {
unimplemented!("fd_sync")
}
#[wasi_common_cbindgen]
pub fn fd_write(
wasi_ctx: &WasiCtx,
memory: &mut [u8],
fd: wasm32::__wasi_fd_t,
iovs_ptr: wasm32::uintptr_t,
iovs_len: wasm32::size_t,
nwritten: wasm32::uintptr_t,
) -> wasm32::__wasi_errno_t {
use winapi::shared::minwindef::{DWORD, LPVOID};
use winapi::shared::ws2def::WSABUF;
use winapi::um::fileapi::WriteFile;
let fd = dec_fd(fd);
let mut iovs = match dec_iovec_slice(memory, iovs_ptr, iovs_len) {
Ok(iovs) => iovs,
Err(e) => return enc_errno(e),
};
let fe = match wasi_ctx.get_fd_entry(fd, host::__WASI_RIGHT_FD_WRITE.into(), 0) {
Ok(fe) => fe,
Err(e) => return enc_errno(e),
};
let iovs: Vec<IoVec> = iovs
.iter()
.map(|iov| unsafe { host_impl::iovec_to_win(iov) })
.collect();
let buf = iovs
.iter()
.find(|b| !b.as_slice().is_empty())
.map_or(&[][..], |b| b.as_slice());
let mut host_nwritten = 0;
let len = cmp::min(buf.len(), <DWORD>::max_value() as usize) as DWORD;
unsafe {
WriteFile(
fe.fd_object.raw_handle,
buf.as_ptr() as LPVOID,
len,
&mut host_nwritten,
std::ptr::null_mut(),
)
};
enc_usize_byref(memory, nwritten, host_nwritten as usize)
.map(|_| wasm32::__WASI_ESUCCESS)
.unwrap_or_else(|e| e)
}
#[wasi_common_cbindgen]
pub fn fd_advise(
wasi_ctx: &WasiCtx,
fd: wasm32::__wasi_fd_t,
offset: wasm32::__wasi_filesize_t,
len: wasm32::__wasi_filesize_t,
advice: wasm32::__wasi_advice_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("fd_advise")
}
#[wasi_common_cbindgen]
pub fn fd_allocate(
wasi_ctx: &WasiCtx,
fd: wasm32::__wasi_fd_t,
offset: wasm32::__wasi_filesize_t,
len: wasm32::__wasi_filesize_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("fd_allocate")
}
#[wasi_common_cbindgen]
pub fn path_create_directory(
wasi_ctx: &WasiCtx,
memory: &mut [u8],
dirfd: wasm32::__wasi_fd_t,
path_ptr: wasm32::uintptr_t,
path_len: wasm32::size_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("path_create_directory")
}
#[wasi_common_cbindgen]
pub fn path_link(
wasi_ctx: &WasiCtx,
memory: &mut [u8],
old_dirfd: wasm32::__wasi_fd_t,
_old_flags: wasm32::__wasi_lookupflags_t,
old_path_ptr: wasm32::uintptr_t,
old_path_len: wasm32::size_t,
new_dirfd: wasm32::__wasi_fd_t,
new_path_ptr: wasm32::uintptr_t,
new_path_len: wasm32::size_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("path_link")
}
#[wasi_common_cbindgen]
pub fn path_open(
wasi_ctx: &mut WasiCtx,
memory: &mut [u8],
dirfd: wasm32::__wasi_fd_t,
dirflags: wasm32::__wasi_lookupflags_t,
path_ptr: wasm32::uintptr_t,
path_len: wasm32::size_t,
oflags: wasm32::__wasi_oflags_t,
fs_rights_base: wasm32::__wasi_rights_t,
fs_rights_inheriting: wasm32::__wasi_rights_t,
fs_flags: wasm32::__wasi_fdflags_t,
fd_out_ptr: wasm32::uintptr_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("path_open")
}
#[wasi_common_cbindgen]
pub fn fd_readdir(
wasi_ctx: &WasiCtx,
memory: &mut [u8],
fd: wasm32::__wasi_fd_t,
buf: wasm32::uintptr_t,
buf_len: wasm32::size_t,
cookie: wasm32::__wasi_dircookie_t,
buf_used: wasm32::uintptr_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("fd_readdir")
}
#[wasi_common_cbindgen]
pub fn path_readlink(
wasi_ctx: &WasiCtx,
memory: &mut [u8],
dirfd: wasm32::__wasi_fd_t,
path_ptr: wasm32::uintptr_t,
path_len: wasm32::size_t,
buf_ptr: wasm32::uintptr_t,
buf_len: wasm32::size_t,
buf_used: wasm32::uintptr_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("path_readlink")
}
#[wasi_common_cbindgen]
pub fn path_rename(
wasi_ctx: &WasiCtx,
memory: &mut [u8],
old_dirfd: wasm32::__wasi_fd_t,
old_path_ptr: wasm32::uintptr_t,
old_path_len: wasm32::size_t,
new_dirfd: wasm32::__wasi_fd_t,
new_path_ptr: wasm32::uintptr_t,
new_path_len: wasm32::size_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("path_rename")
}
#[wasi_common_cbindgen]
pub fn fd_filestat_get(
wasi_ctx: &WasiCtx,
memory: &mut [u8],
fd: wasm32::__wasi_fd_t,
filestat_ptr: wasm32::uintptr_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("fd_filestat_get")
}
#[wasi_common_cbindgen]
pub fn fd_filestat_set_times(
wasi_ctx: &WasiCtx,
fd: wasm32::__wasi_fd_t,
st_atim: wasm32::__wasi_timestamp_t,
st_mtim: wasm32::__wasi_timestamp_t,
fst_flags: wasm32::__wasi_fstflags_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("fd_filestat_set_times")
}
#[wasi_common_cbindgen]
pub fn fd_filestat_set_size(
wasi_ctx: &WasiCtx,
fd: wasm32::__wasi_fd_t,
st_size: wasm32::__wasi_filesize_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("fd_filestat_set_size")
}
#[wasi_common_cbindgen]
pub fn path_filestat_get(
wasi_ctx: &WasiCtx,
memory: &mut [u8],
dirfd: wasm32::__wasi_fd_t,
dirflags: wasm32::__wasi_lookupflags_t,
path_ptr: wasm32::uintptr_t,
path_len: wasm32::size_t,
filestat_ptr: wasm32::uintptr_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("path_filestat_get")
}
#[wasi_common_cbindgen]
pub fn path_filestat_set_times(
wasi_ctx: &WasiCtx,
memory: &mut [u8],
dirfd: wasm32::__wasi_fd_t,
dirflags: wasm32::__wasi_lookupflags_t,
path_ptr: wasm32::uintptr_t,
path_len: wasm32::size_t,
st_atim: wasm32::__wasi_timestamp_t,
st_mtim: wasm32::__wasi_timestamp_t,
fst_flags: wasm32::__wasi_fstflags_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("path_filestat_set_times")
}
#[wasi_common_cbindgen]
pub fn path_symlink(
wasi_ctx: &WasiCtx,
memory: &mut [u8],
old_path_ptr: wasm32::uintptr_t,
old_path_len: wasm32::size_t,
dirfd: wasm32::__wasi_fd_t,
new_path_ptr: wasm32::uintptr_t,
new_path_len: wasm32::size_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("path_symlink")
}
#[wasi_common_cbindgen]
pub fn path_unlink_file(
wasi_ctx: &WasiCtx,
memory: &mut [u8],
dirfd: wasm32::__wasi_fd_t,
path_ptr: wasm32::uintptr_t,
path_len: wasm32::size_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("path_unlink_file")
}
#[wasi_common_cbindgen]
pub fn path_remove_directory(
wasi_ctx: &WasiCtx,
memory: &mut [u8],
dirfd: wasm32::__wasi_fd_t,
path_ptr: wasm32::uintptr_t,
path_len: wasm32::size_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("path_remove_directory")
}
#[wasi_common_cbindgen]
pub fn fd_prestat_get(
wasi_ctx: &WasiCtx,
memory: &mut [u8],
fd: wasm32::__wasi_fd_t,
prestat_ptr: wasm32::uintptr_t,
) -> wasm32::__wasi_errno_t {
let fd = dec_fd(fd);
// TODO: is this the correct right for this?
match wasi_ctx.get_fd_entry(fd, host::__WASI_RIGHT_PATH_OPEN.into(), 0) {
Ok(fe) => {
if let Some(po_path) = &fe.preopen_path {
if fe.fd_object.ty != host::__WASI_FILETYPE_DIRECTORY {
return wasm32::__WASI_ENOTDIR;
}
enc_prestat_byref(
memory,
prestat_ptr,
host::__wasi_prestat_t {
pr_type: host::__WASI_PREOPENTYPE_DIR,
u: host::__wasi_prestat_t___wasi_prestat_u {
dir: host::__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t {
// TODO: clean up
pr_name_len: po_path.as_os_str().encode_wide().count() * 2,
},
},
},
)
.map(|_| wasm32::__WASI_ESUCCESS)
.unwrap_or_else(|e| e)
} else {
wasm32::__WASI_ENOTSUP
}
}
Err(e) => enc_errno(e),
}
}
#[wasi_common_cbindgen]
pub fn fd_prestat_dir_name(
wasi_ctx: &WasiCtx,
memory: &mut [u8],
fd: wasm32::__wasi_fd_t,
path_ptr: wasm32::uintptr_t,
path_len: wasm32::size_t,
) -> wasm32::__wasi_errno_t {
let fd = dec_fd(fd);
match wasi_ctx.get_fd_entry(fd, host::__WASI_RIGHT_PATH_OPEN.into(), 0) {
Ok(fe) => {
if let Some(po_path) = &fe.preopen_path {
if fe.fd_object.ty != host::__WASI_FILETYPE_DIRECTORY {
return wasm32::__WASI_ENOTDIR;
}
// TODO: clean up
let path_bytes = &po_path
.as_os_str()
.encode_wide()
.map(u16::to_le_bytes)
.fold(Vec::new(), |mut acc, bytes| {
acc.extend_from_slice(&bytes);
acc
});
if path_bytes.len() > dec_usize(path_len) {
return wasm32::__WASI_ENAMETOOLONG;
}
enc_slice_of(memory, path_bytes, path_ptr)
.map(|_| wasm32::__WASI_ESUCCESS)
.unwrap_or_else(|e| e)
} else {
wasm32::__WASI_ENOTSUP
}
}
Err(e) => enc_errno(e),
}
}

View File

@@ -0,0 +1,46 @@
#![allow(non_camel_case_types)]
#![allow(unused_unsafe)]
#![allow(unused)]
use super::host_impl;
use crate::memory::*;
use crate::{host, wasm32};
use std::cmp;
use std::time::SystemTime;
use wasi_common_cbindgen::wasi_common_cbindgen;
#[wasi_common_cbindgen]
pub fn clock_res_get(
memory: &mut [u8],
clock_id: wasm32::__wasi_clockid_t,
resolution_ptr: wasm32::uintptr_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("clock_res_get")
}
#[wasi_common_cbindgen]
pub fn clock_time_get(
memory: &mut [u8],
clock_id: wasm32::__wasi_clockid_t,
precision: wasm32::__wasi_timestamp_t,
time_ptr: wasm32::uintptr_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("clock_time_get")
}
#[wasi_common_cbindgen]
pub fn poll_oneoff(
memory: &mut [u8],
input: wasm32::uintptr_t,
output: wasm32::uintptr_t,
nsubscriptions: wasm32::size_t,
nevents: wasm32::uintptr_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("poll_oneoff")
}
#[wasi_common_cbindgen]
pub fn sched_yield() -> wasm32::__wasi_errno_t {
unimplemented!("sched_yield")
}

View File

@@ -0,0 +1,11 @@
//! Windows-specific hostcalls that implement
//! [WASI](https://github.com/CraneStation/wasmtime-wasi/blob/wasi/docs/WASI-overview.md).
mod fs;
mod misc;
mod sock;
use super::host_impl;
pub use self::fs::*;
pub use self::misc::*;
pub use self::sock::*;

View File

@@ -0,0 +1,44 @@
#![allow(non_camel_case_types)]
#![allow(unused_unsafe)]
#![allow(unused)]
use crate::ctx::WasiCtx;
use crate::wasm32;
use wasi_common_cbindgen::wasi_common_cbindgen;
#[wasi_common_cbindgen]
pub fn sock_recv(
wasi_ctx: &WasiCtx,
memory: &mut [u8],
sock: wasm32::__wasi_fd_t,
ri_data: wasm32::uintptr_t,
ri_data_len: wasm32::size_t,
ri_flags: wasm32::__wasi_riflags_t,
ro_datalen: wasm32::uintptr_t,
ro_flags: wasm32::uintptr_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("sock_recv")
}
#[wasi_common_cbindgen]
pub fn sock_send(
wasi_ctx: &WasiCtx,
memory: &mut [u8],
sock: wasm32::__wasi_fd_t,
si_data: wasm32::uintptr_t,
si_data_len: wasm32::size_t,
si_flags: wasm32::__wasi_siflags_t,
so_datalen: wasm32::uintptr_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("sock_send")
}
#[wasi_common_cbindgen]
pub fn sock_shutdown(
wasi_ctx: &WasiCtx,
memory: &mut [u8],
sock: wasm32::__wasi_fd_t,
how: wasm32::__wasi_sdflags_t,
) -> wasm32::__wasi_errno_t {
unimplemented!("sock_shutdown")
}

View File

@@ -0,0 +1,9 @@
pub mod fdentry;
mod host_impl;
pub mod hostcalls;
use std::fs::File;
pub fn dev_null() -> File {
File::open("NUL").expect("failed to open NUL")
}