diff --git a/Cargo.toml b/Cargo.toml index 8ea9d3f..7817ba1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,10 +15,13 @@ documentation = "https://docs.rs/wasi" # When built as part of libstd compiler_builtins = { version = "0.1", optional = true } core = { version = "1.0", optional = true, package = "rustc-std-workspace-core" } +rustc-std-workspace-alloc = { version = "1.0", optional = true } [features] +default = ["alloc"] +alloc = [] # Unstable feature to support being a libstd dependency -rustc-dep-of-std = ["compiler_builtins", "core"] +rustc-dep-of-std = ["compiler_builtins", "core", "rustc-std-workspace-alloc"] [badges] maintenance = { status = "experimental" } diff --git a/src/lib.rs b/src/lib.rs index 42e13ea..64321e8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,5 +12,9 @@ ) )] #![no_std] +#[cfg(all(feature = "alloc", not(feature = "rustc-std-workspace-alloc")))] +extern crate alloc; +#[cfg(all(feature = "alloc", feature = "rustc-std-workspace-alloc"))] +extern crate rustc_std_workspace_alloc as alloc; pub mod wasi_unstable; diff --git a/src/wasi_unstable/mod.rs b/src/wasi_unstable/mod.rs index 37bec24..2ae35a1 100644 --- a/src/wasi_unstable/mod.rs +++ b/src/wasi_unstable/mod.rs @@ -12,6 +12,7 @@ pub mod raw; use core::ffi::c_void; use core::mem::MaybeUninit; +use core::num::NonZeroU16; use raw::*; pub type Advice = __wasi_advice_t; @@ -19,6 +20,7 @@ pub type ClockId = __wasi_clockid_t; pub type Device = __wasi_device_t; pub type DirCookie = __wasi_dircookie_t; pub type Errno = __wasi_errno_t; +pub type Error = NonZeroU16; pub type EventRwFlags = __wasi_eventrwflags_t; pub type EventType = __wasi_eventtype_t; pub type ExitCode = __wasi_exitcode_t; @@ -52,6 +54,9 @@ pub type Subscription = __wasi_subscription_t; pub type Event = __wasi_event_t; pub type Prestat = __wasi_prestat_t; +// Assert that `__WASI_ESUCCESS` equals to 0 +const _ASSERT1: [(); 0] = [(); __WASI_ESUCCESS as usize]; + pub const ADVICE_NORMAL: Advice = __WASI_ADVICE_NORMAL; pub const ADVICE_SEQUENTIAL: Advice = __WASI_ADVICE_SEQUENTIAL; pub const ADVICE_RANDOM: Advice = __WASI_ADVICE_RANDOM; @@ -63,83 +68,100 @@ pub const CLOCK_MONOTONIC: ClockId = __WASI_CLOCK_MONOTONIC; pub const CLOCK_PROCESS_CPUTIME_ID: ClockId = __WASI_CLOCK_PROCESS_CPUTIME_ID; pub const CLOCK_THREAD_CPUTIME_ID: ClockId = __WASI_CLOCK_THREAD_CPUTIME_ID; pub const DIRCOOKIE_START: DirCookie = __WASI_DIRCOOKIE_START; -pub const ESUCCESS: Errno = __WASI_ESUCCESS; -pub const E2BIG: Errno = __WASI_E2BIG; -pub const EACCES: Errno = __WASI_EACCES; -pub const EADDRINUSE: Errno = __WASI_EADDRINUSE; -pub const EADDRNOTAVAIL: Errno = __WASI_EADDRNOTAVAIL; -pub const EAFNOSUPPORT: Errno = __WASI_EAFNOSUPPORT; -pub const EAGAIN: Errno = __WASI_EAGAIN; -pub const EALREADY: Errno = __WASI_EALREADY; -pub const EBADF: Errno = __WASI_EBADF; -pub const EBADMSG: Errno = __WASI_EBADMSG; -pub const EBUSY: Errno = __WASI_EBUSY; -pub const ECANCELED: Errno = __WASI_ECANCELED; -pub const ECHILD: Errno = __WASI_ECHILD; -pub const ECONNABORTED: Errno = __WASI_ECONNABORTED; -pub const ECONNREFUSED: Errno = __WASI_ECONNREFUSED; -pub const ECONNRESET: Errno = __WASI_ECONNRESET; -pub const EDEADLK: Errno = __WASI_EDEADLK; -pub const EDESTADDRREQ: Errno = __WASI_EDESTADDRREQ; -pub const EDOM: Errno = __WASI_EDOM; -pub const EDQUOT: Errno = __WASI_EDQUOT; -pub const EEXIST: Errno = __WASI_EEXIST; -pub const EFAULT: Errno = __WASI_EFAULT; -pub const EFBIG: Errno = __WASI_EFBIG; -pub const EHOSTUNREACH: Errno = __WASI_EHOSTUNREACH; -pub const EIDRM: Errno = __WASI_EIDRM; -pub const EILSEQ: Errno = __WASI_EILSEQ; -pub const EINPROGRESS: Errno = __WASI_EINPROGRESS; -pub const EINTR: Errno = __WASI_EINTR; -pub const EINVAL: Errno = __WASI_EINVAL; -pub const EIO: Errno = __WASI_EIO; -pub const EISCONN: Errno = __WASI_EISCONN; -pub const EISDIR: Errno = __WASI_EISDIR; -pub const ELOOP: Errno = __WASI_ELOOP; -pub const EMFILE: Errno = __WASI_EMFILE; -pub const EMLINK: Errno = __WASI_EMLINK; -pub const EMSGSIZE: Errno = __WASI_EMSGSIZE; -pub const EMULTIHOP: Errno = __WASI_EMULTIHOP; -pub const ENAMETOOLONG: Errno = __WASI_ENAMETOOLONG; -pub const ENETDOWN: Errno = __WASI_ENETDOWN; -pub const ENETRESET: Errno = __WASI_ENETRESET; -pub const ENETUNREACH: Errno = __WASI_ENETUNREACH; -pub const ENFILE: Errno = __WASI_ENFILE; -pub const ENOBUFS: Errno = __WASI_ENOBUFS; -pub const ENODEV: Errno = __WASI_ENODEV; -pub const ENOENT: Errno = __WASI_ENOENT; -pub const ENOEXEC: Errno = __WASI_ENOEXEC; -pub const ENOLCK: Errno = __WASI_ENOLCK; -pub const ENOLINK: Errno = __WASI_ENOLINK; -pub const ENOMEM: Errno = __WASI_ENOMEM; -pub const ENOMSG: Errno = __WASI_ENOMSG; -pub const ENOPROTOOPT: Errno = __WASI_ENOPROTOOPT; -pub const ENOSPC: Errno = __WASI_ENOSPC; -pub const ENOSYS: Errno = __WASI_ENOSYS; -pub const ENOTCONN: Errno = __WASI_ENOTCONN; -pub const ENOTDIR: Errno = __WASI_ENOTDIR; -pub const ENOTEMPTY: Errno = __WASI_ENOTEMPTY; -pub const ENOTRECOVERABLE: Errno = __WASI_ENOTRECOVERABLE; -pub const ENOTSOCK: Errno = __WASI_ENOTSOCK; -pub const ENOTSUP: Errno = __WASI_ENOTSUP; -pub const ENOTTY: Errno = __WASI_ENOTTY; -pub const ENXIO: Errno = __WASI_ENXIO; -pub const EOVERFLOW: Errno = __WASI_EOVERFLOW; -pub const EOWNERDEAD: Errno = __WASI_EOWNERDEAD; -pub const EPERM: Errno = __WASI_EPERM; -pub const EPIPE: Errno = __WASI_EPIPE; -pub const EPROTO: Errno = __WASI_EPROTO; -pub const EPROTONOSUPPORT: Errno = __WASI_EPROTONOSUPPORT; -pub const EPROTOTYPE: Errno = __WASI_EPROTOTYPE; -pub const ERANGE: Errno = __WASI_ERANGE; -pub const EROFS: Errno = __WASI_EROFS; -pub const ESPIPE: Errno = __WASI_ESPIPE; -pub const ESRCH: Errno = __WASI_ESRCH; -pub const ESTALE: Errno = __WASI_ESTALE; -pub const ETIMEDOUT: Errno = __WASI_ETIMEDOUT; -pub const ETXTBSY: Errno = __WASI_ETXTBSY; -pub const EXDEV: Errno = __WASI_EXDEV; -pub const ENOTCAPABLE: Errno = __WASI_ENOTCAPABLE; + +pub const STDIN_FD: Fd = __WASI_STDIN_FD; +pub const STDOUT_FD: Fd = __WASI_STDOUT_FD; +pub const STDERR_FD: Fd = __WASI_STDERR_FD; + +macro_rules! errno_set { + {$($safe_const:ident = $raw_const:ident;)*} => { + $( + pub const $safe_const: Error = unsafe { + NonZeroU16::new_unchecked($raw_const) + }; + )* + }; +} + +errno_set!{ + E2BIG = __WASI_E2BIG; + EACCES = __WASI_EACCES; + EADDRINUSE = __WASI_EADDRINUSE; + EADDRNOTAVAIL = __WASI_EADDRNOTAVAIL; + EAFNOSUPPORT = __WASI_EAFNOSUPPORT; + EAGAIN = __WASI_EAGAIN; + EALREADY = __WASI_EALREADY; + EBADF = __WASI_EBADF; + EBADMSG = __WASI_EBADMSG; + EBUSY = __WASI_EBUSY; + ECANCELED = __WASI_ECANCELED; + ECHILD = __WASI_ECHILD; + ECONNABORTED = __WASI_ECONNABORTED; + ECONNREFUSED = __WASI_ECONNREFUSED; + ECONNRESET = __WASI_ECONNRESET; + EDEADLK = __WASI_EDEADLK; + EDESTADDRREQ = __WASI_EDESTADDRREQ; + EDOM = __WASI_EDOM; + EDQUOT = __WASI_EDQUOT; + EEXIST = __WASI_EEXIST; + EFAULT = __WASI_EFAULT; + EFBIG = __WASI_EFBIG; + EHOSTUNREACH = __WASI_EHOSTUNREACH; + EIDRM = __WASI_EIDRM; + EILSEQ = __WASI_EILSEQ; + EINPROGRESS = __WASI_EINPROGRESS; + EINTR = __WASI_EINTR; + EINVAL = __WASI_EINVAL; + EIO = __WASI_EIO; + EISCONN = __WASI_EISCONN; + EISDIR = __WASI_EISDIR; + ELOOP = __WASI_ELOOP; + EMFILE = __WASI_EMFILE; + EMLINK = __WASI_EMLINK; + EMSGSIZE = __WASI_EMSGSIZE; + EMULTIHOP = __WASI_EMULTIHOP; + ENAMETOOLONG = __WASI_ENAMETOOLONG; + ENETDOWN = __WASI_ENETDOWN; + ENETRESET = __WASI_ENETRESET; + ENETUNREACH = __WASI_ENETUNREACH; + ENFILE = __WASI_ENFILE; + ENOBUFS = __WASI_ENOBUFS; + ENODEV = __WASI_ENODEV; + ENOENT = __WASI_ENOENT; + ENOEXEC = __WASI_ENOEXEC; + ENOLCK = __WASI_ENOLCK; + ENOLINK = __WASI_ENOLINK; + ENOMEM = __WASI_ENOMEM; + ENOMSG = __WASI_ENOMSG; + ENOPROTOOPT = __WASI_ENOPROTOOPT; + ENOSPC = __WASI_ENOSPC; + ENOSYS = __WASI_ENOSYS; + ENOTCONN = __WASI_ENOTCONN; + ENOTDIR = __WASI_ENOTDIR; + ENOTEMPTY = __WASI_ENOTEMPTY; + ENOTRECOVERABLE = __WASI_ENOTRECOVERABLE; + ENOTSOCK = __WASI_ENOTSOCK; + ENOTSUP = __WASI_ENOTSUP; + ENOTTY = __WASI_ENOTTY; + ENXIO = __WASI_ENXIO; + EOVERFLOW = __WASI_EOVERFLOW; + EOWNERDEAD = __WASI_EOWNERDEAD; + EPERM = __WASI_EPERM; + EPIPE = __WASI_EPIPE; + EPROTO = __WASI_EPROTO; + EPROTONOSUPPORT = __WASI_EPROTONOSUPPORT; + EPROTOTYPE = __WASI_EPROTOTYPE; + ERANGE = __WASI_ERANGE; + EROFS = __WASI_EROFS; + ESPIPE = __WASI_ESPIPE; + ESRCH = __WASI_ESRCH; + ESTALE = __WASI_ESTALE; + ETIMEDOUT = __WASI_ETIMEDOUT; + ETXTBSY = __WASI_ETXTBSY; + EXDEV = __WASI_EXDEV; + ENOTCAPABLE = __WASI_ENOTCAPABLE; +} + pub const EVENT_FD_READWRITE_HANGUP: EventRwFlags = __WASI_EVENT_FD_READWRITE_HANGUP; pub const EVENTTYPE_CLOCK: EventType = __WASI_EVENTTYPE_CLOCK; pub const EVENTTYPE_FD_READ: EventType = __WASI_EVENTTYPE_FD_READ; @@ -236,144 +258,134 @@ pub const WHENCE_CUR: Whence = __WASI_WHENCE_CUR; pub const WHENCE_END: Whence = __WASI_WHENCE_END; pub const WHENCE_SET: Whence = __WASI_WHENCE_SET; -pub fn clock_res_get(clock_id: ClockId) -> (Errno, Timestamp) { - let mut resolution = MaybeUninit::::uninit(); - unsafe { - ( - __wasi_clock_res_get(clock_id, resolution.as_mut_ptr()), - resolution.assume_init(), - ) - } -} - -pub fn clock_time_get(clock_id: ClockId, precision: Timestamp) -> (Errno, Timestamp) { - let mut time = MaybeUninit::::uninit(); - unsafe { - ( - __wasi_clock_time_get(clock_id, precision, time.as_mut_ptr()), - time.assume_init(), - ) - } +macro_rules! wrap0 { + {$f:expr} => { + if let Some(code) = NonZeroU16::new($f) { + Err(code) + } else { + Ok(()) + } + }; } -pub fn fd_pread(fd: Fd, iovs: &[IoVec], offset: FileSize) -> (Errno, usize) { - let mut nread = MaybeUninit::::uninit(); - unsafe { - ( - __wasi_fd_pread(fd, iovs.as_ptr(), iovs.len(), offset, nread.as_mut_ptr()), - nread.assume_init(), - ) - } +macro_rules! wrap { + {$f:ident($($args:expr),* $(,)?)} => { + let mut t = MaybeUninit::uninit(); + let r = $f($($args,)* t.as_mut_ptr()); + if let Some(code) = NonZeroU16::new(r) { + Err(code) + } else { + Ok(t.assume_init()) + } + }; } -pub fn fd_pwrite(fd: Fd, iovs: &[CIoVec], offset: FileSize) -> (Errno, usize) { - let mut nwritten = MaybeUninit::::uninit(); - unsafe { - ( - __wasi_fd_pwrite(fd, iovs.as_ptr(), iovs.len(), offset, nwritten.as_mut_ptr()), - nwritten.assume_init(), - ) - } +#[inline] +pub fn clock_res_get(clock_id: ClockId) -> Result { + unsafe { wrap!{ __wasi_clock_res_get(clock_id) } } } -pub fn random_get(buf: &mut [u8]) -> Errno { - unsafe { __wasi_random_get(buf.as_mut_ptr() as *mut c_void, buf.len()) } +#[inline] +pub fn clock_time_get(clock_id: ClockId, precision: Timestamp) -> Result { + unsafe { wrap!{ __wasi_clock_time_get(clock_id, precision) } } } -pub fn fd_close(fd: Fd) -> Errno { - unsafe { __wasi_fd_close(fd) } +#[inline] +pub unsafe fn fd_pread(fd: Fd, iovs: &[IoVec], offset: FileSize) -> Result { + wrap!{ __wasi_fd_pread(fd, iovs.as_ptr(), iovs.len(), offset) } } -pub fn fd_datasync(fd: Fd) -> Errno { - unsafe { __wasi_fd_datasync(fd) } +#[inline] +pub unsafe fn fd_pwrite(fd: Fd, iovs: &[CIoVec], offset: FileSize) -> Result { + wrap!{ __wasi_fd_pwrite(fd, iovs.as_ptr(), iovs.len(), offset) } } -pub fn fd_read(fd: Fd, iovs: &[IoVec]) -> (Errno, usize) { - let mut nread = MaybeUninit::::uninit(); +#[inline] +pub fn random_get(buf: &mut [u8]) -> Result<(), Error> { unsafe { - ( - __wasi_fd_read(fd, iovs.as_ptr(), iovs.len(), nread.as_mut_ptr()), - nread.assume_init(), - ) + wrap0!{ __wasi_random_get(buf.as_mut_ptr() as *mut c_void, buf.len()) } } } -pub fn fd_renumber(from: Fd, to: Fd) -> Errno { - unsafe { __wasi_fd_renumber(from, to) } +#[inline] +pub unsafe fn fd_close(fd: Fd) -> Result<(), Error> { + wrap0!{ __wasi_fd_close(fd) } } -pub fn fd_seek(fd: Fd, offset: FileDelta, whence: Whence) -> (Errno, FileSize) { - let mut newoffset = MaybeUninit::::uninit(); - unsafe { - ( - __wasi_fd_seek(fd, offset, whence, newoffset.as_mut_ptr()), - newoffset.assume_init(), - ) - } +#[inline] +pub unsafe fn fd_datasync(fd: Fd) -> Result<(), Error> { + wrap0!{ __wasi_fd_datasync(fd) } } -pub fn fd_tell(fd: Fd) -> (Errno, FileSize) { - let mut newoffset = MaybeUninit::::uninit(); - unsafe { - ( - __wasi_fd_tell(fd, newoffset.as_mut_ptr()), - newoffset.assume_init(), - ) - } +#[inline] +pub unsafe fn fd_read(fd: Fd, iovs: &[IoVec]) -> Result { + wrap!{ __wasi_fd_read(fd, iovs.as_ptr(), iovs.len()) } } -pub fn fd_fdstat_get(fd: Fd) -> (Errno, FdStat) { - let mut buf = MaybeUninit::::uninit(); - unsafe { - ( - __wasi_fd_fdstat_get(fd, buf.as_mut_ptr()), - buf.assume_init(), - ) - } +#[inline] +pub unsafe fn fd_renumber(from: Fd, to: Fd) -> Result<(), Error> { + wrap0!{ __wasi_fd_renumber(from, to) } } -pub fn fd_fdstat_set_flags(fd: Fd, flags: FdFlags) -> Errno { - unsafe { __wasi_fd_fdstat_set_flags(fd, flags) } +#[inline] +pub unsafe fn fd_seek(fd: Fd, offset: FileDelta, whence: Whence) -> Result { + wrap!{ __wasi_fd_seek(fd, offset, whence) } } -pub fn fd_fdstat_set_rights(fd: Fd, fs_rights_base: Rights, fs_rights_inheriting: Rights) -> Errno { - unsafe { __wasi_fd_fdstat_set_rights(fd, fs_rights_base, fs_rights_inheriting) } +#[inline] +pub unsafe fn fd_tell(fd: Fd) -> Result { + wrap!{ __wasi_fd_tell(fd) } } -pub fn fd_sync(fd: Fd) -> Errno { - unsafe { __wasi_fd_sync(fd) } +#[inline] +pub unsafe fn fd_fdstat_get(fd: Fd) -> Result { + wrap!{ __wasi_fd_fdstat_get(fd) } } -pub fn fd_write(fd: Fd, iovs: &[CIoVec]) -> (Errno, usize) { - let mut nwritten = MaybeUninit::::uninit(); - unsafe { - ( - __wasi_fd_write(fd, iovs.as_ptr(), iovs.len(), nwritten.as_mut_ptr()), - nwritten.assume_init(), - ) - } +#[inline] +pub unsafe fn fd_fdstat_set_flags(fd: Fd, flags: FdFlags) -> Result<(), Error> { + wrap0!{ __wasi_fd_fdstat_set_flags(fd, flags) } +} + +#[inline] +pub unsafe fn fd_fdstat_set_rights(fd: Fd, fs_rights_base: Rights, fs_rights_inheriting: Rights) -> Result<(), Error> { + wrap0!{ __wasi_fd_fdstat_set_rights(fd, fs_rights_base, fs_rights_inheriting) } +} + +#[inline] +pub unsafe fn fd_sync(fd: Fd) -> Result<(), Error> { + wrap0!{ __wasi_fd_sync(fd) } } -pub fn fd_advise(fd: Fd, offset: FileSize, len: FileSize, advice: Advice) -> Errno { - unsafe { __wasi_fd_advise(fd, offset, len, advice) } +#[inline] +pub unsafe fn fd_write(fd: Fd, iovs: &[CIoVec]) -> Result { + wrap!{ __wasi_fd_write(fd, iovs.as_ptr(), iovs.len()) } } -pub fn fd_allocate(fd: Fd, offset: FileSize, len: FileSize) -> Errno { - unsafe { __wasi_fd_allocate(fd, offset, len) } +#[inline] +pub unsafe fn fd_advise(fd: Fd, offset: FileSize, len: FileSize, advice: Advice) -> Result<(), Error> { + wrap0!{ __wasi_fd_advise(fd, offset, len, advice) } } -pub fn path_create_directory(fd: Fd, path: &[u8]) -> Errno { - unsafe { __wasi_path_create_directory(fd, path.as_ptr(), path.len()) } +#[inline] +pub unsafe fn fd_allocate(fd: Fd, offset: FileSize, len: FileSize) -> Result<(), Error> { + wrap0!{ __wasi_fd_allocate(fd, offset, len) } } -pub fn path_link( +#[inline] +pub unsafe fn path_create_directory(fd: Fd, path: &[u8]) -> Result<(), Error> { + wrap0!{ __wasi_path_create_directory(fd, path.as_ptr(), path.len()) } +} + +#[inline] +pub unsafe fn path_link( old_fd: Fd, old_flags: LookupFlags, old_path: &[u8], new_fd: Fd, new_path: &[u8], -) -> Errno { - unsafe { +) -> Result<(), Error> { + wrap0!{ __wasi_path_link( old_fd, old_flags, @@ -386,7 +398,8 @@ pub fn path_link( } } -pub fn path_open( +#[inline] +pub unsafe fn path_open( dirfd: Fd, dirflags: LookupFlags, path: &[u8], @@ -394,61 +407,38 @@ pub fn path_open( fs_rights_base: Rights, fs_rights_inheriting: Rights, fs_flags: FdFlags, -) -> (Errno, Fd) { - let mut fd = MaybeUninit::::uninit(); - unsafe { - ( - __wasi_path_open( - dirfd, - dirflags, - path.as_ptr(), - path.len(), - oflags, - fs_rights_base, - fs_rights_inheriting, - fs_flags, - fd.as_mut_ptr(), - ), - fd.assume_init(), +) -> Result { + wrap!{ + __wasi_path_open( + dirfd, + dirflags, + path.as_ptr(), + path.len(), + oflags, + fs_rights_base, + fs_rights_inheriting, + fs_flags, ) } } -pub fn fd_readdir(fd: Fd, buf: &mut [u8], cookie: DirCookie) -> (Errno, usize) { - let mut bufused = MaybeUninit::::uninit(); - unsafe { - ( - __wasi_fd_readdir( - fd, - buf.as_mut_ptr() as *mut c_void, - buf.len(), - cookie, - bufused.as_mut_ptr(), - ), - bufused.assume_init(), - ) - } +#[inline] +pub unsafe fn fd_readdir(fd: Fd, buf: &mut [u8], cookie: DirCookie) -> Result { + let ptr = buf.as_mut_ptr() as *mut c_void; + wrap!{ __wasi_fd_readdir(fd, ptr, buf.len(), cookie) } } -pub fn path_readlink(fd: Fd, path: &[u8], buf: &mut [u8]) -> (Errno, usize) { - let mut bufused = MaybeUninit::::uninit(); - unsafe { - ( - __wasi_path_readlink( - fd, - path.as_ptr(), - path.len(), - buf.as_mut_ptr(), - buf.len(), - bufused.as_mut_ptr(), - ), - bufused.assume_init(), - ) +#[inline] +pub unsafe fn path_readlink(fd: Fd, path: &[u8], buf: &mut [u8]) -> Result { + let ptr = buf.as_mut_ptr(); + wrap!{ + __wasi_path_readlink(fd, path.as_ptr(), path.len(), ptr, buf.len()) } } -pub fn path_rename(old_fd: Fd, old_path: &[u8], new_fd: Fd, new_path: &[u8]) -> Errno { - unsafe { +#[inline] +pub unsafe fn path_rename(old_fd: Fd, old_path: &[u8], new_fd: Fd, new_path: &[u8]) -> Result<(), Error> { + wrap0!{ __wasi_path_rename( old_fd, old_path.as_ptr(), @@ -460,48 +450,43 @@ pub fn path_rename(old_fd: Fd, old_path: &[u8], new_fd: Fd, new_path: &[u8]) -> } } -pub fn fd_filestat_get(fd: Fd) -> (Errno, FileStat) { - let mut buf = MaybeUninit::::uninit(); - unsafe { - ( - __wasi_fd_filestat_get(fd, buf.as_mut_ptr()), - buf.assume_init(), - ) - } +#[inline] +pub unsafe fn fd_filestat_get(fd: Fd) -> Result { + wrap!{ __wasi_fd_filestat_get(fd) } } -pub fn fd_filestat_set_times( +#[inline] +pub unsafe fn fd_filestat_set_times( fd: Fd, st_atim: Timestamp, st_mtim: Timestamp, fstflags: FstFlags, -) -> Errno { - unsafe { __wasi_fd_filestat_set_times(fd, st_atim, st_mtim, fstflags) } +) -> Result<(), Error> { + wrap0!{ __wasi_fd_filestat_set_times(fd, st_atim, st_mtim, fstflags) } } -pub fn fd_filestat_set_size(fd: Fd, st_size: FileSize) -> Errno { - unsafe { __wasi_fd_filestat_set_size(fd, st_size) } +#[inline] +pub unsafe fn fd_filestat_set_size(fd: Fd, st_size: FileSize) -> Result<(), Error> { + wrap0!{ __wasi_fd_filestat_set_size(fd, st_size) } } -pub fn path_filestat_get(fd: Fd, flags: LookupFlags, path: &[u8]) -> (Errno, FileStat) { - let mut buf = MaybeUninit::::uninit(); - unsafe { - ( - __wasi_path_filestat_get(fd, flags, path.as_ptr(), path.len(), buf.as_mut_ptr()), - buf.assume_init(), - ) +#[inline] +pub unsafe fn path_filestat_get(fd: Fd, flags: LookupFlags, path: &[u8]) -> Result { + wrap!{ + __wasi_path_filestat_get(fd, flags, path.as_ptr(), path.len()) } } -pub fn path_filestat_set_times( +#[inline] +pub unsafe fn path_filestat_set_times( fd: Fd, flags: LookupFlags, path: &[u8], st_atim: Timestamp, st_mtim: Timestamp, fstflags: FstFlags, -) -> Errno { - unsafe { +) -> Result<(), Error> { + wrap0!{ __wasi_path_filestat_set_times( fd, flags, @@ -514,8 +499,9 @@ pub fn path_filestat_set_times( } } -pub fn path_symlink(old_path: &[u8], fd: Fd, new_path: &[u8]) -> Errno { - unsafe { +#[inline] +pub unsafe fn path_symlink(old_path: &[u8], fd: Fd, new_path: &[u8]) -> Result<(), Error> { + wrap0!{ __wasi_path_symlink( old_path.as_ptr(), old_path.len(), @@ -526,99 +512,272 @@ pub fn path_symlink(old_path: &[u8], fd: Fd, new_path: &[u8]) -> Errno { } } -pub fn path_unlink_file(fd: Fd, path: &[u8]) -> Errno { - unsafe { __wasi_path_unlink_file(fd, path.as_ptr(), path.len()) } +#[inline] +pub unsafe fn path_unlink_file(fd: Fd, path: &[u8]) -> Result<(), Error> { + wrap0!{ __wasi_path_unlink_file(fd, path.as_ptr(), path.len()) } } -pub fn path_remove_directory(fd: Fd, path: &[u8]) -> Errno { - unsafe { __wasi_path_remove_directory(fd, path.as_ptr(), path.len()) } +#[inline] +pub unsafe fn path_remove_directory(fd: Fd, path: &[u8]) -> Result<(), Error> { + wrap0!{ __wasi_path_remove_directory(fd, path.as_ptr(), path.len()) } } -pub fn poll_oneoff(in_: &[Subscription], out: &mut [Event]) -> (Errno, usize) { +#[inline] +pub unsafe fn poll_oneoff(in_: &[Subscription], out: &mut [Event]) -> Result { assert!(out.len() >= in_.len()); - let mut nevents = MaybeUninit::::uninit(); - unsafe { - ( - __wasi_poll_oneoff( - in_.as_ptr(), - out.as_mut_ptr(), - in_.len(), - nevents.as_mut_ptr(), - ), - nevents.assume_init(), + let ptr = out.as_mut_ptr() as *mut __wasi_event_t; + wrap!{ + __wasi_poll_oneoff( + in_.as_ptr(), + ptr, + in_.len(), ) } } -pub fn proc_exit(rval: ExitCode) { +#[inline] +pub fn proc_exit(rval: ExitCode) -> ! { unsafe { __wasi_proc_exit(rval) } } -pub fn proc_raise(sig: Signal) -> Errno { - unsafe { __wasi_proc_raise(sig) } -} - -pub fn sock_recv(sock: Fd, ri_data: &[IoVec], ri_flags: RiFlags) -> (Errno, usize, RoFlags) { +#[inline] +pub unsafe fn sock_recv(sock: Fd, ri_data: &[IoVec], ri_flags: RiFlags) -> Result<(usize, RoFlags), Error> { let mut ro_datalen = MaybeUninit::::uninit(); let mut ro_flags = MaybeUninit::::uninit(); - unsafe { - ( - __wasi_sock_recv( - sock, - ri_data.as_ptr(), - ri_data.len(), - ri_flags, - ro_datalen.as_mut_ptr(), - ro_flags.as_mut_ptr(), - ), - ro_datalen.assume_init(), - ro_flags.assume_init(), - ) + let r = __wasi_sock_recv( + sock, + ri_data.as_ptr(), + ri_data.len(), + ri_flags, + ro_datalen.as_mut_ptr(), + ro_flags.as_mut_ptr(), + ); + if let Some(code) = NonZeroU16::new(r) { + Err(code) + } else { + Ok((ro_datalen.assume_init(), ro_flags.assume_init())) } } -pub fn sock_send(sock: Fd, si_data: &[CIoVec], si_flags: SiFlags) -> (Errno, usize) { - let mut so_datalen = MaybeUninit::::uninit(); - unsafe { - ( - __wasi_sock_send( - sock, - si_data.as_ptr(), - si_data.len(), - si_flags, - so_datalen.as_mut_ptr(), - ), - so_datalen.assume_init(), - ) - } +#[inline] +pub unsafe fn sock_send(sock: Fd, si_data: &[CIoVec], si_flags: SiFlags) -> Result { + wrap!{ __wasi_sock_send(sock, si_data.as_ptr(), si_data.len(), si_flags) } } -pub fn sock_shutdown(sock: Fd, how: SdFlags) -> Errno { - unsafe { __wasi_sock_shutdown(sock, how) } +#[inline] +pub unsafe fn sock_shutdown(sock: Fd, how: SdFlags) -> Result<(), Error> { + wrap0!{ __wasi_sock_shutdown(sock, how) } } -pub fn sched_yield() -> Errno { - unsafe { __wasi_sched_yield() } +#[inline] +pub fn sched_yield() -> Result<(), Error> { + unsafe { wrap0!{ __wasi_sched_yield() } } } -pub fn fd_prestat_get(fd: Fd) -> (Errno, Prestat) { - let mut buf = MaybeUninit::::uninit(); - unsafe { - ( - __wasi_fd_prestat_get(fd, buf.as_mut_ptr()), - buf.assume_init(), - ) - } +#[inline] +pub unsafe fn fd_prestat_get(fd: Fd) -> Result { + wrap!{ __wasi_fd_prestat_get(fd) } +} + +#[inline] +pub unsafe fn fd_prestat_dir_name(fd: Fd, path: &mut [u8]) -> Result<(), Error> { + wrap0!{ __wasi_fd_prestat_dir_name(fd, path.as_mut_ptr(), path.len()) } +} + +#[derive(Copy, Clone)] +pub struct ArgsSizes { + count: usize, + buf_len: usize, } -pub fn fd_prestat_dir_name(fd: Fd, path: &mut [u8]) -> Errno { - unsafe { __wasi_fd_prestat_dir_name(fd, path.as_mut_ptr(), path.len()) } +impl ArgsSizes { + #[inline] + pub fn get_count(&self) -> usize { self.count } + #[inline] + pub fn get_buf_len(&self) -> usize { self.buf_len } } -// TODO: Safe interfaces to the args and environ functions -/* -pub fn args_get(argv: *mut *mut u8, argv_buf: *mut u8) -> Errno {} -pub fn args_sizes_get(argc: *mut usize, argv_buf_size: *mut usize) -> Errno {} -pub fn environ_get(environ: *mut *mut u8, environ_buf: *mut u8) -> Errno {} -pub fn environ_sizes_get(environ_count: *mut usize, environ_buf_size: *mut usize) -> Errno {} -*/ +#[inline] +pub fn args_sizes_get() -> Result { + let mut res = ArgsSizes { count: 0, buf_len: 0 }; + let code = unsafe { + __wasi_args_sizes_get(&mut res.count, &mut res.buf_len) + }; + if let Some(err) = NonZeroU16::new(code) { return Err(err); } + Ok(res) +} + +#[cfg(feature = "alloc")] +#[inline] +pub fn args_get( + ars: ArgsSizes, mut process_arg: impl FnMut(&[u8]), +) -> Result<(), Error> { + use alloc::vec; + + // TODO: remove allocations after stabilization of unsized rvalues, see: + // https://github.com/rust-lang/rust/issues/48055 + let mut arg_ptrs = vec![core::ptr::null_mut::(); ars.count]; + let mut arg_buf = vec![0u8; ars.buf_len]; + let ret = unsafe { + __wasi_args_get(arg_ptrs.as_mut_ptr(), arg_buf.as_mut_ptr()) + }; + if let Some(err) = NonZeroU16::new(ret) { return Err(err); } + + for ptr in arg_ptrs { + for n in 0.. { + unsafe { + if *ptr.offset(n as isize) == 0 { + let slice = core::slice::from_raw_parts(ptr, n); + process_arg(slice); + break + } + } + } + } + + Ok(()) +} + +#[derive(Copy, Clone)] +pub struct EnvironSizes { + count: usize, + buf_len: usize, +} + +impl EnvironSizes { + #[inline] + pub fn get_count(&self) -> usize { self.count } + #[inline] + pub fn get_buf_len(&self) -> usize { self.buf_len } +} + +#[inline] +pub fn environ_sizes_get() -> Result { + let mut res = EnvironSizes { count: 0, buf_len: 0 }; + let code = unsafe { + __wasi_environ_sizes_get(&mut res.count, &mut res.buf_len) + }; + if let Some(err) = NonZeroU16::new(code) { return Err(err); } + Ok(res) +} + +#[cfg(feature = "alloc")] +#[inline] +pub fn environ_get( + es: EnvironSizes, mut process_env: impl FnMut(&[u8], &[u8]), +) -> Result<(), Error> { + use alloc::vec; + + // TODO: remove allocations after stabilization of unsized rvalues, see: + // https://github.com/rust-lang/rust/issues/48055 + let mut env_ptrs = vec![core::ptr::null_mut::(); es.count]; + let mut env_buf = vec![0u8; es.buf_len]; + let ret = unsafe { + __wasi_environ_get(env_ptrs.as_mut_ptr(), env_buf.as_mut_ptr()) + }; + if let Some(err) = NonZeroU16::new(ret) { return Err(err); } + + for ptr in env_ptrs { + let mut key: &[u8] = &[]; + for n in 0.. { + unsafe { + match *ptr.offset(n as isize) { + 0 => { + let val = core::slice::from_raw_parts(ptr, n); + process_env(key, val); + break + } + b'=' if key.is_empty() => { + key = core::slice::from_raw_parts(ptr, n); + } + _ => {} + } + } + } + } + + Ok(()) +} + +pub fn error_str(err: Error) -> Option<&'static str> { + let desc = match err { + E2BIG => "Argument list too long", + EACCES => "Permission denied", + EADDRINUSE => "Address in use", + EADDRNOTAVAIL => "Address not available", + EAFNOSUPPORT => "Address family not supported by protocol", + EAGAIN => "Resource temporarily unavailable", + EALREADY => "Operation already in progress", + EBADF => "Bad file descriptor", + EBADMSG => "Bad message", + EBUSY => "Resource busy", + ECANCELED => "Operation canceled", + ECHILD => "No child process", + ECONNABORTED => "Connection aborted", + ECONNREFUSED => "Connection refused", + ECONNRESET => "Connection reset by peer", + EDEADLK => "Resource deadlock would occur", + EDESTADDRREQ => "Destination address required", + EDOM => "Domain error", + EDQUOT => "Quota exceeded", + EEXIST => "File exists", + EFAULT => "Bad address", + EFBIG => "File too large", + EHOSTUNREACH => "Host is unreachable", + EIDRM => "Identifier removed", + EILSEQ => "Illegal byte sequence", + EINPROGRESS => "Operation in progress", + EINTR => "Interrupted system call", + EINVAL => "Invalid argument", + EIO => "Remote I/O error", + EISCONN => "Socket is connected", + EISDIR => "Is a directory", + ELOOP => "Symbolic link loop", + EMFILE => "No file descriptors available", + EMLINK => "Too many links", + EMSGSIZE => "Message too large", + EMULTIHOP => "Multihop attempted", + ENAMETOOLONG => "Filename too long", + ENETDOWN => "Network is down", + ENETRESET => "Connection reset by network", + ENETUNREACH => "Network unreachable", + ENFILE => "Too many open files in system", + ENOBUFS => "No buffer space available", + ENODEV => "No such device", + ENOENT => "No such file or directory", + ENOEXEC => "Exec format error", + ENOLCK => "No locks available", + ENOLINK => "Link has been severed", + ENOMEM => "Out of memory", + ENOMSG => "No message of desired type", + ENOPROTOOPT => "Protocol not available", + ENOSPC => "No space left on device", + ENOSYS => "Function not implemented", + ENOTCONN => "Socket not connected", + ENOTDIR => "Not a directory", + ENOTEMPTY => "Directory not empty", + ENOTRECOVERABLE => "State not recoverable", + ENOTSOCK => "Not a socket", + ENOTSUP => "Not supported", + ENOTTY => "Not a tty", + ENXIO => "No such device or address", + EOVERFLOW => "Value too large for data type", + EOWNERDEAD => "Previous owner died", + EPERM => "Operation not permitted", + EPIPE => "Broken pipe", + EPROTO => "Protocol error", + EPROTONOSUPPORT => "Protocol not supported", + EPROTOTYPE => "Protocol wrong type for socket", + ERANGE => "Result not representable", + EROFS => "Read-only file system", + ESPIPE => "Invalid seek", + ESRCH => "No such process", + ESTALE => "Stale file handle", + ETIMEDOUT => "Operation timed out", + ETXTBSY => "Text file busy", + EXDEV => "Cross-device link", + ENOTCAPABLE => "Capabilities insufficient", + _ => return None, + }; + Some(desc) +} diff --git a/src/wasi_unstable/raw.rs b/src/wasi_unstable/raw.rs index 1bccc76..962aef2 100644 --- a/src/wasi_unstable/raw.rs +++ b/src/wasi_unstable/raw.rs @@ -342,6 +342,9 @@ pub const __WASI_SUBSCRIPTION_CLOCK_ABSTIME: u16 = 0x0001; pub const __WASI_WHENCE_CUR: u8 = 0; pub const __WASI_WHENCE_END: u8 = 1; pub const __WASI_WHENCE_SET: u8 = 2; +pub const __WASI_STDIN_FD: u32 = 0; +pub const __WASI_STDOUT_FD: u32 = 1; +pub const __WASI_STDERR_FD: u32 = 2; #[link(wasm_import_module = "wasi_unstable")] extern "C" { @@ -572,10 +575,7 @@ extern "C" { ) -> __wasi_errno_t; #[link_name = "proc_exit"] - pub fn __wasi_proc_exit(rval: __wasi_exitcode_t); - - #[link_name = "proc_raise"] - pub fn __wasi_proc_raise(sig: __wasi_signal_t) -> __wasi_errno_t; + pub fn __wasi_proc_exit(rval: __wasi_exitcode_t) -> !; #[link_name = "random_get"] pub fn __wasi_random_get(buf: *mut c_void, buf_len: usize) -> __wasi_errno_t;