Extract common interface from lucet-wasi

This commit is contained in:
Jakub Konka
2019-05-04 14:28:22 +02:00
commit cd39c1dfd8
13 changed files with 4574 additions and 0 deletions

22
Cargo.toml Normal file
View File

@@ -0,0 +1,22 @@
[package]
name = "wasi-common"
version = "0.1.0"
authors = ["Adam C. Foltzer <acfoltzer@fastly.com>", "Jakub Konka <kubkon@jakubkonka.com>"]
edition = "2018"
license = "Apache-2.0 WITH LLVM-exception"
[dependencies]
cast = "0.2"
clap = "2.23"
failure = "0.1"
human-size = "0.4"
libc = "0.2"
nix = "0.13"
rand = "0.6"
[build-dependencies]
bindgen = "0.49.0"
[lib]
name = "wasi_common"
crate-type = ["rlib", "staticlib", "cdylib"]

220
LICENSE Normal file
View File

@@ -0,0 +1,220 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--- LLVM Exceptions to the Apache 2.0 License ----
As an exception, if, as a result of your compiling your source code, portions
of this Software are embedded into an Object form of such source code, you
may redistribute such embedded portions in such Object form without complying
with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
In addition, if you combine or link compiled forms of this Software with
software that is licensed under the GPLv2 ("Combined Software") and if a
court of competent jurisdiction determines that the patent provision (Section
3), the indemnity provision (Section 9) or other Section of the License
conflicts with the conditions of the GPLv2, you may retroactively and
prospectively choose to deem waived or otherwise exclude such Section(s) of
the License, but only in their entirety and only with respect to the Combined
Software.

24
LICENSE.cloudabi-utils Normal file
View File

@@ -0,0 +1,24 @@
All code is distributed under the following license:
Copyright (c) 2015 Nuxi, https://nuxi.nl/
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.

219
LICENSE.wasmtime Normal file
View File

@@ -0,0 +1,219 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--- LLVM Exceptions to the Apache 2.0 License ----
As an exception, if, as a result of your compiling your source code, portions
of this Software are embedded into an Object form of such source code, you
may redistribute such embedded portions in such Object form without complying
with the conditions of Sections 4(a), 4(b) and 4(d) of the License.
In addition, if you combine or link compiled forms of this Software with
software that is licensed under the GPLv2 ("Combined Software") and if a
court of competent jurisdiction determines that the patent provision (Section
3), the indemnity provision (Section 9) or other Section of the License
conflicts with the conditions of the GPLv2, you may retroactively and
prospectively choose to deem waived or otherwise exclude such Section(s) of
the License, but only in their entirety and only with respect to the Combined
Software.

44
README.md Normal file
View File

@@ -0,0 +1,44 @@
# wasi-common
This repo strips away those bits of [lucet-wasi](https://github.com/fastly/lucet/tree/master/lucet-wasi)
which can potentially be encapsulated in a separated crate with potential plug'n'play use in both
[Lucet](https://github.com/fastly/lucet)
and [Wasmtime](https://github.com/CraneStation/wasmtime) projects.
This repo is strictly experimental.
## Supported syscalls
We support a subset of the [WASI
API](https://github.com/CraneStation/wasmtime/blob/master/docs/WASI-api.md), though we are adding
new syscalls on a regular basis. We currently implement:
- `__wasi_args_get`
- `__wasi_args_sizes_get`
- `__wasi_clock_res_get`
- `__wasi_clock_time_get`
- `__wasi_environ_get`
- `__wasi_environ_sizes_get`
- `__wasi_fd_close`
- `__wasi_fd_fdstat_get`
- `__wasi_fd_fdstat_set_flags`
- `__wasi_fd_prestat_dir_name`
- `__wasi_fd_prestat_get`
- `__wasi_fd_read`
- `__wasi_fd_seek`
- `__wasi_fd_write`
- `__wasi_path_open`
- `__wasi_proc_exit`
- `__wasi_random_get`
This is enough to run basic C and Rust programs, including those that use command-line arguments,
environment variables, stdio, and basic file operations.
## Third-Party Code
`src/wasm32.rs` is copied from
[wasmtime](https://github.com/CraneStation/wasmtime/blob/master/wasmtime-wasi/src/wasm32.rs), along
with the associated `LICENSE.wasmtime` file.
Significant parts of our syscall implementations are derived from the C implementations in
`cloudabi-utils`. See `LICENSE.cloudabi-utils` for license information.

96
build.rs Normal file
View File

@@ -0,0 +1,96 @@
use std::env;
use std::fs::File;
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
fn wasi_sdk() -> PathBuf {
Path::new(&env::var("WASI_SDK").unwrap_or("/opt/wasi-sdk".to_owned())).to_path_buf()
}
fn wasi_sysroot() -> PathBuf {
match env::var("WASI_SYSROOT") {
Ok(wasi_sysroot) => Path::new(&wasi_sysroot).to_path_buf(),
Err(_) => {
let mut path = wasi_sdk();
path.push("share");
path.push("sysroot");
path
}
}
}
fn wasm_clang_root() -> PathBuf {
match env::var("CLANG_ROOT") {
Ok(clang) => Path::new(&clang).to_path_buf(),
Err(_) => {
let mut path = wasi_sdk();
path.push("lib");
path.push("clang");
path.push("8.0.0");
path
}
}
}
fn main() {
let wasi_sysroot = wasi_sysroot();
let wasm_clang_root = wasm_clang_root();
assert!(
wasi_sysroot.exists(),
"wasi-sysroot not present at {:?}",
wasi_sysroot
);
assert!(
wasm_clang_root.exists(),
"clang-root not present at {:?}",
wasm_clang_root
);
let wasi_sysroot_core_h = wasi_sysroot.join("include/wasi/core.h");
assert!(
wasi_sysroot_core_h.exists(),
"wasi-sysroot core.h not present at {:?}",
wasi_sysroot_core_h
);
println!("cargo:rerun-if-changed={}", wasi_sysroot_core_h.display());
let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
let core_h_path = out_path.join("core.h");
let core_h = File::create(&core_h_path).unwrap();
// `bindgen` doesn't understand typed constant macros like `UINT8_C(123)`, so this fun regex
// strips them off to yield a copy of `wasi/core.h` with bare constants.
let sed_result = Command::new("sed")
.arg("-E")
.arg(r#"s/U?INT[0-9]+_C\(((0x)?[0-9]+)\)/\1/g"#)
.arg(wasi_sysroot_core_h)
.stdout(Stdio::from(core_h))
.status()
.expect("can execute sed");
if !sed_result.success() {
// something failed, but how?
match sed_result.code() {
Some(code) => panic!("sed failed with code {}", code),
None => panic!("sed exited abnormally"),
}
}
let host_builder = bindgen::Builder::default()
.clang_arg("-nostdinc")
.clang_arg("-D__wasi__")
.clang_arg(format!("-isystem={}/include/", wasi_sysroot.display()))
.clang_arg(format!("-I{}/include/", wasm_clang_root.display()))
.header(core_h_path.to_str().unwrap())
.whitelist_type("__wasi_.*")
.whitelist_var("__WASI_.*");
host_builder
.generate()
.expect("can generate host bindings")
.write_to_file(out_path.join("wasi_host.rs"))
.expect("can write host bindings");
}

257
src/ctx.rs Normal file
View File

@@ -0,0 +1,257 @@
use crate::fdentry::FdEntry;
use crate::host;
use crate::wasm32;
use failure::{bail, format_err, Error};
use nix::unistd::dup;
use std::collections::HashMap;
use std::ffi::{CStr, CString};
use std::fs::File;
use std::io::{stderr, stdin, stdout};
use std::os::unix::prelude::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
use std::path::{Path, PathBuf};
pub trait VmContext {
fn as_wasi_ctx(&self) -> &WasiCtx;
fn as_wasi_ctx_mut(&mut self) -> &mut WasiCtx;
unsafe fn dec_ptr(
&mut self,
ptr: wasm32::uintptr_t,
len: usize,
) -> Result<*mut u8, host::__wasi_errno_t>;
}
pub struct WasiCtxBuilder {
fds: HashMap<host::__wasi_fd_t, FdEntry>,
preopens: HashMap<PathBuf, File>,
args: Vec<CString>,
env: HashMap<CString, CString>,
}
impl WasiCtxBuilder {
/// Builder for a new `WasiCtx`.
pub fn new() -> Self {
let null = dev_null();
WasiCtxBuilder {
fds: HashMap::new(),
preopens: HashMap::new(),
args: vec![],
env: HashMap::new(),
}
.fd_dup(0, &null)
.fd_dup(1, &null)
.fd_dup(2, &null)
}
pub fn args(mut self, args: &[&str]) -> Self {
self.args = args
.into_iter()
.map(|arg| CString::new(*arg).expect("argument can be converted to a CString"))
.collect();
self
}
pub fn arg(mut self, arg: &str) -> Self {
self.args
.push(CString::new(arg).expect("argument can be converted to a CString"));
self
}
pub fn c_args<S: AsRef<CStr>>(mut self, args: &[S]) -> Self {
self.args = args
.into_iter()
.map(|arg| arg.as_ref().to_owned())
.collect();
self
}
pub fn c_arg<S: AsRef<CStr>>(mut self, arg: S) -> Self {
self.args.push(arg.as_ref().to_owned());
self
}
pub fn inherit_stdio(self) -> Self {
self.fd_dup(0, &stdin())
.fd_dup(1, &stdout())
.fd_dup(2, &stderr())
}
pub fn inherit_env(mut self) -> Self {
self.env = std::env::vars()
.map(|(k, v)| {
// TODO: handle errors, and possibly assert that the key is valid per POSIX
(
CString::new(k).expect("environment key can be converted to a CString"),
CString::new(v).expect("environment value can be converted to a CString"),
)
})
.collect();
self
}
pub fn env(mut self, k: &str, v: &str) -> Self {
self.env.insert(
// TODO: handle errors, and possibly assert that the key is valid per POSIX
CString::new(k).expect("environment key can be converted to a CString"),
CString::new(v).expect("environment value can be converted to a CString"),
);
self
}
pub fn c_env<S, T>(mut self, k: S, v: T) -> Self
where
S: AsRef<CStr>,
T: AsRef<CStr>,
{
self.env
.insert(k.as_ref().to_owned(), v.as_ref().to_owned());
self
}
/// Add an existing file-like object as a file descriptor in the context.
///
/// When the `WasiCtx` is dropped, all of its associated file descriptors are `close`d. If you
/// do not want this to close the existing object, use `WasiCtxBuilder::fd_dup()`.
pub fn fd<F: IntoRawFd>(self, wasm_fd: host::__wasi_fd_t, fd: F) -> Self {
// safe because we're getting a valid RawFd from the F directly
unsafe { self.raw_fd(wasm_fd, fd.into_raw_fd()) }
}
/// Add an existing file-like object as a duplicate file descriptor in the context.
///
/// The underlying file descriptor of this object will be duplicated before being added to the
/// context, so it will not be closed when the `WasiCtx` is dropped.
///
/// TODO: handle `dup` errors
pub fn fd_dup<F: AsRawFd>(self, wasm_fd: host::__wasi_fd_t, fd: &F) -> Self {
// safe because we're getting a valid RawFd from the F directly
unsafe { self.raw_fd(wasm_fd, dup(fd.as_raw_fd()).unwrap()) }
}
/// Add an existing file descriptor to the context.
///
/// When the `WasiCtx` is dropped, this file descriptor will be `close`d. If you do not want to
/// close the existing descriptor, use `WasiCtxBuilder::raw_fd_dup()`.
pub unsafe fn raw_fd(mut self, wasm_fd: host::__wasi_fd_t, fd: RawFd) -> Self {
self.fds.insert(wasm_fd, FdEntry::from_raw_fd(fd));
self
}
/// Add a duplicate of an existing file descriptor to the context.
///
/// The file descriptor will be duplicated before being added to the context, so it will not be
/// closed when the `WasiCtx` is dropped.
///
/// TODO: handle `dup` errors
pub unsafe fn raw_fd_dup(self, wasm_fd: host::__wasi_fd_t, fd: RawFd) -> Self {
self.raw_fd(wasm_fd, dup(fd).unwrap())
}
pub fn preopened_dir<P: AsRef<Path>>(mut self, dir: File, guest_path: P) -> Self {
self.preopens.insert(guest_path.as_ref().to_owned(), dir);
self
}
pub fn build(mut self) -> Result<WasiCtx, Error> {
// startup code starts looking at fd 3 for preopens
let mut preopen_fd = 3;
for (guest_path, dir) in self.preopens {
if !dir.metadata()?.is_dir() {
bail!("preopened file is not a directory");
}
while self.fds.contains_key(&preopen_fd) {
preopen_fd = preopen_fd
.checked_add(1)
.ok_or(format_err!("not enough file handles"))?;
}
let mut fe = FdEntry::from_file(dir);
fe.preopen_path = Some(guest_path);
self.fds.insert(preopen_fd, fe);
preopen_fd += 1;
}
let env = self
.env
.into_iter()
.map(|(k, v)| {
let mut pair = k.into_bytes();
pair.extend_from_slice(b"=");
pair.extend_from_slice(v.to_bytes_with_nul());
// constructing a new CString from existing CStrings is safe
unsafe { CString::from_vec_unchecked(pair) }
})
.collect();
Ok(WasiCtx {
fds: self.fds,
args: self.args,
env,
})
}
}
#[derive(Debug)]
pub struct WasiCtx {
pub fds: HashMap<host::__wasi_fd_t, FdEntry>,
pub args: Vec<CString>,
pub env: Vec<CString>,
}
impl WasiCtx {
/// Make a new `WasiCtx` with some default settings.
///
/// - File descriptors 0, 1, and 2 inherit stdin, stdout, and stderr from the host process.
///
/// - Environment variables are inherited from the host process.
///
/// To override these behaviors, use `WasiCtxBuilder`.
pub fn new(args: &[&str]) -> WasiCtx {
WasiCtxBuilder::new()
.args(args)
.inherit_stdio()
.inherit_env()
.build()
.expect("default options don't fail")
}
pub fn get_fd_entry(
&self,
fd: host::__wasi_fd_t,
rights_base: host::__wasi_rights_t,
rights_inheriting: host::__wasi_rights_t,
) -> Result<&FdEntry, host::__wasi_errno_t> {
if let Some(fe) = self.fds.get(&fd) {
// validate rights
if !fe.rights_base & rights_base != 0 || !fe.rights_inheriting & rights_inheriting != 0
{
Err(host::__WASI_ENOTCAPABLE as host::__wasi_errno_t)
} else {
Ok(fe)
}
} else {
Err(host::__WASI_EBADF as host::__wasi_errno_t)
}
}
pub fn insert_fd_entry(
&mut self,
fe: FdEntry,
) -> Result<host::__wasi_fd_t, host::__wasi_errno_t> {
// never insert where stdio handles usually are
let mut fd = 3;
while self.fds.contains_key(&fd) {
if let Some(next_fd) = fd.checked_add(1) {
fd = next_fd;
} else {
return Err(host::__WASI_EMFILE as host::__wasi_errno_t);
}
}
self.fds.insert(fd, fe);
Ok(fd)
}
}
fn dev_null() -> File {
File::open("/dev/null").expect("failed to open /dev/null")
}

143
src/fdentry.rs Normal file
View File

@@ -0,0 +1,143 @@
use crate::host;
use std::fs::File;
use std::os::unix::prelude::{FileTypeExt, FromRawFd, IntoRawFd, RawFd};
use std::path::PathBuf;
#[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 FdEntry {
pub fn from_file(file: File) -> FdEntry {
unsafe { FdEntry::from_raw_fd(file.into_raw_fd()) }
}
}
impl FromRawFd for FdEntry {
// TODO: make this a different function with error handling, rather than using the trait method
unsafe fn from_raw_fd(rawfd: RawFd) -> FdEntry {
let (ty, mut rights_base, rights_inheriting) =
determine_type_rights(rawfd).expect("can determine file rights");
use nix::fcntl::{fcntl, OFlag, F_GETFL};
let flags_bits = fcntl(rawfd, F_GETFL).expect("fcntl succeeds");
let flags = OFlag::from_bits_truncate(flags_bits);
let accmode = flags & OFlag::O_ACCMODE;
if accmode == OFlag::O_RDONLY {
rights_base &= !host::__WASI_RIGHT_FD_WRITE as host::__wasi_rights_t;
} else if accmode == OFlag::O_WRONLY {
rights_base &= !host::__WASI_RIGHT_FD_READ as host::__wasi_rights_t;
}
FdEntry {
fd_object: FdObject {
ty: ty as u8,
rawfd,
needs_close: true,
},
rights_base,
rights_inheriting,
preopen_path: None,
}
}
}
// TODO: can probably make this safe by using fcntl directly rather than going through `File`
pub unsafe fn determine_type_rights(
rawfd: RawFd,
) -> Result<
(
host::__wasi_filetype_t,
host::__wasi_rights_t,
host::__wasi_rights_t,
),
host::__wasi_errno_t,
> {
let (ty, rights_base, rights_inheriting) = {
let file = File::from_raw_fd(rawfd);
let ft = file.metadata().unwrap().file_type();
// we just make a `File` here for convenience; we don't want it to close when it drops
std::mem::forget(file);
if ft.is_block_device() {
(
host::__WASI_FILETYPE_BLOCK_DEVICE,
host::RIGHTS_BLOCK_DEVICE_BASE,
host::RIGHTS_BLOCK_DEVICE_INHERITING,
)
} else if ft.is_char_device() {
if nix::unistd::isatty(rawfd).unwrap() {
(
host::__WASI_FILETYPE_CHARACTER_DEVICE,
host::RIGHTS_TTY_BASE,
host::RIGHTS_TTY_BASE,
)
} else {
(
host::__WASI_FILETYPE_CHARACTER_DEVICE,
host::RIGHTS_CHARACTER_DEVICE_BASE,
host::RIGHTS_CHARACTER_DEVICE_INHERITING,
)
}
} else if ft.is_dir() {
(
host::__WASI_FILETYPE_DIRECTORY,
host::RIGHTS_DIRECTORY_BASE,
host::RIGHTS_DIRECTORY_INHERITING,
)
} else if ft.is_file() {
(
host::__WASI_FILETYPE_REGULAR_FILE,
host::RIGHTS_REGULAR_FILE_BASE,
host::RIGHTS_REGULAR_FILE_INHERITING,
)
} else if ft.is_socket() {
use nix::sys::socket;
match socket::getsockopt(rawfd, socket::sockopt::SockType).unwrap() {
socket::SockType::Datagram => (
host::__WASI_FILETYPE_SOCKET_DGRAM,
host::RIGHTS_SOCKET_BASE,
host::RIGHTS_SOCKET_INHERITING,
),
socket::SockType::Stream => (
host::__WASI_FILETYPE_SOCKET_STREAM,
host::RIGHTS_SOCKET_BASE,
host::RIGHTS_SOCKET_INHERITING,
),
_ => return Err(host::__WASI_EINVAL as host::__wasi_errno_t),
}
} else if ft.is_fifo() {
(
host::__WASI_FILETYPE_SOCKET_STREAM,
host::RIGHTS_SOCKET_BASE,
host::RIGHTS_SOCKET_INHERITING,
)
} else {
return Err(host::__WASI_EINVAL as host::__wasi_errno_t);
}
};
Ok((
ty as host::__wasi_filetype_t,
rights_base,
rights_inheriting,
))
}
#[derive(Clone, Debug)]
pub struct FdObject {
pub ty: host::__wasi_filetype_t,
pub rawfd: RawFd,
pub needs_close: bool,
// TODO: directories
}
impl Drop for FdObject {
fn drop(&mut self) {
if self.needs_close {
nix::unistd::close(self.rawfd).unwrap_or_else(|e| eprintln!("FdObject::drop(): {}", e));
}
}
}

335
src/host.rs Normal file
View File

@@ -0,0 +1,335 @@
#![allow(non_camel_case_types)]
#![allow(non_snake_case)]
include!(concat!(env!("OUT_DIR"), "/wasi_host.rs"));
pub type void = ::std::os::raw::c_void;
pub unsafe fn ciovec_to_nix<'a>(ciovec: &'a __wasi_ciovec_t) -> nix::sys::uio::IoVec<&'a [u8]> {
let slice = std::slice::from_raw_parts(ciovec.buf as *const u8, ciovec.buf_len);
nix::sys::uio::IoVec::from_slice(slice)
}
pub unsafe fn ciovec_to_nix_mut<'a>(
ciovec: &'a mut __wasi_ciovec_t,
) -> nix::sys::uio::IoVec<&'a mut [u8]> {
let slice = std::slice::from_raw_parts_mut(ciovec.buf as *mut u8, ciovec.buf_len);
nix::sys::uio::IoVec::from_mut_slice(slice)
}
pub fn errno_from_nix(errno: nix::errno::Errno) -> __wasi_errno_t {
let e = match errno {
nix::errno::Errno::EPERM => __WASI_EPERM,
nix::errno::Errno::ENOENT => __WASI_ENOENT,
nix::errno::Errno::ESRCH => __WASI_ESRCH,
nix::errno::Errno::EINTR => __WASI_EINTR,
nix::errno::Errno::EIO => __WASI_EIO,
nix::errno::Errno::ENXIO => __WASI_ENXIO,
nix::errno::Errno::E2BIG => __WASI_E2BIG,
nix::errno::Errno::ENOEXEC => __WASI_ENOEXEC,
nix::errno::Errno::EBADF => __WASI_EBADF,
nix::errno::Errno::ECHILD => __WASI_ECHILD,
nix::errno::Errno::EAGAIN => __WASI_EAGAIN,
nix::errno::Errno::ENOMEM => __WASI_ENOMEM,
nix::errno::Errno::EACCES => __WASI_EACCES,
nix::errno::Errno::EFAULT => __WASI_EFAULT,
nix::errno::Errno::EBUSY => __WASI_EBUSY,
nix::errno::Errno::EEXIST => __WASI_EEXIST,
nix::errno::Errno::EXDEV => __WASI_EXDEV,
nix::errno::Errno::ENODEV => __WASI_ENODEV,
nix::errno::Errno::ENOTDIR => __WASI_ENOTDIR,
nix::errno::Errno::EISDIR => __WASI_EISDIR,
nix::errno::Errno::EINVAL => __WASI_EINVAL,
nix::errno::Errno::ENFILE => __WASI_ENFILE,
nix::errno::Errno::EMFILE => __WASI_EMFILE,
nix::errno::Errno::ENOTTY => __WASI_ENOTTY,
nix::errno::Errno::ETXTBSY => __WASI_ETXTBSY,
nix::errno::Errno::EFBIG => __WASI_EFBIG,
nix::errno::Errno::ENOSPC => __WASI_ENOSPC,
nix::errno::Errno::ESPIPE => __WASI_ESPIPE,
nix::errno::Errno::EROFS => __WASI_EROFS,
nix::errno::Errno::EMLINK => __WASI_EMLINK,
nix::errno::Errno::EPIPE => __WASI_EPIPE,
nix::errno::Errno::EDOM => __WASI_EDOM,
nix::errno::Errno::ERANGE => __WASI_ERANGE,
nix::errno::Errno::EDEADLK => __WASI_EDEADLK,
nix::errno::Errno::ENAMETOOLONG => __WASI_ENAMETOOLONG,
nix::errno::Errno::ENOLCK => __WASI_ENOLCK,
nix::errno::Errno::ENOSYS => __WASI_ENOSYS,
nix::errno::Errno::ENOTEMPTY => __WASI_ENOTEMPTY,
nix::errno::Errno::ELOOP => __WASI_ELOOP,
nix::errno::Errno::ENOMSG => __WASI_ENOMSG,
nix::errno::Errno::EIDRM => __WASI_EIDRM,
nix::errno::Errno::ENOLINK => __WASI_ENOLINK,
nix::errno::Errno::EPROTO => __WASI_EPROTO,
nix::errno::Errno::EMULTIHOP => __WASI_EMULTIHOP,
nix::errno::Errno::EBADMSG => __WASI_EBADMSG,
nix::errno::Errno::EOVERFLOW => __WASI_EOVERFLOW,
nix::errno::Errno::EILSEQ => __WASI_EILSEQ,
nix::errno::Errno::ENOTSOCK => __WASI_ENOTSOCK,
nix::errno::Errno::EDESTADDRREQ => __WASI_EDESTADDRREQ,
nix::errno::Errno::EMSGSIZE => __WASI_EMSGSIZE,
nix::errno::Errno::EPROTOTYPE => __WASI_EPROTOTYPE,
nix::errno::Errno::ENOPROTOOPT => __WASI_ENOPROTOOPT,
nix::errno::Errno::EPROTONOSUPPORT => __WASI_EPROTONOSUPPORT,
nix::errno::Errno::EAFNOSUPPORT => __WASI_EAFNOSUPPORT,
nix::errno::Errno::EADDRINUSE => __WASI_EADDRINUSE,
nix::errno::Errno::EADDRNOTAVAIL => __WASI_EADDRNOTAVAIL,
nix::errno::Errno::ENETDOWN => __WASI_ENETDOWN,
nix::errno::Errno::ENETUNREACH => __WASI_ENETUNREACH,
nix::errno::Errno::ENETRESET => __WASI_ENETRESET,
nix::errno::Errno::ECONNABORTED => __WASI_ECONNABORTED,
nix::errno::Errno::ECONNRESET => __WASI_ECONNRESET,
nix::errno::Errno::ENOBUFS => __WASI_ENOBUFS,
nix::errno::Errno::EISCONN => __WASI_EISCONN,
nix::errno::Errno::ENOTCONN => __WASI_ENOTCONN,
nix::errno::Errno::ETIMEDOUT => __WASI_ETIMEDOUT,
nix::errno::Errno::ECONNREFUSED => __WASI_ECONNREFUSED,
nix::errno::Errno::EHOSTUNREACH => __WASI_EHOSTUNREACH,
nix::errno::Errno::EALREADY => __WASI_EALREADY,
nix::errno::Errno::EINPROGRESS => __WASI_EINPROGRESS,
nix::errno::Errno::ESTALE => __WASI_ESTALE,
nix::errno::Errno::EDQUOT => __WASI_EDQUOT,
nix::errno::Errno::ECANCELED => __WASI_ECANCELED,
nix::errno::Errno::EOWNERDEAD => __WASI_EOWNERDEAD,
nix::errno::Errno::ENOTRECOVERABLE => __WASI_ENOTRECOVERABLE,
_ => __WASI_ENOSYS,
};
e as __wasi_errno_t
}
#[cfg(target_os = "linux")]
const O_RSYNC: nix::fcntl::OFlag = nix::fcntl::OFlag::O_RSYNC;
#[cfg(not(target_os = "linux"))]
const O_RSYNC: nix::fcntl::OFlag = nix::fcntl::OFlag::O_SYNC;
pub fn nix_from_fdflags(fdflags: __wasi_fdflags_t) -> nix::fcntl::OFlag {
use nix::fcntl::OFlag;
let mut nix_flags = OFlag::empty();
if fdflags & (__WASI_FDFLAG_APPEND as __wasi_fdflags_t) != 0 {
nix_flags.insert(OFlag::O_APPEND);
}
if fdflags & (__WASI_FDFLAG_DSYNC as __wasi_fdflags_t) != 0 {
nix_flags.insert(OFlag::O_DSYNC);
}
if fdflags & (__WASI_FDFLAG_NONBLOCK as __wasi_fdflags_t) != 0 {
nix_flags.insert(OFlag::O_NONBLOCK);
}
if fdflags & (__WASI_FDFLAG_RSYNC as __wasi_fdflags_t) != 0 {
nix_flags.insert(O_RSYNC);
}
if fdflags & (__WASI_FDFLAG_SYNC as __wasi_fdflags_t) != 0 {
nix_flags.insert(OFlag::O_SYNC);
}
nix_flags
}
pub fn fdflags_from_nix(oflags: nix::fcntl::OFlag) -> __wasi_fdflags_t {
use nix::fcntl::OFlag;
let mut fdflags = 0;
if oflags.contains(OFlag::O_APPEND) {
fdflags |= __WASI_FDFLAG_APPEND;
}
if oflags.contains(OFlag::O_DSYNC) {
fdflags |= __WASI_FDFLAG_DSYNC;
}
if oflags.contains(OFlag::O_NONBLOCK) {
fdflags |= __WASI_FDFLAG_NONBLOCK;
}
if oflags.contains(O_RSYNC) {
fdflags |= __WASI_FDFLAG_RSYNC;
}
if oflags.contains(OFlag::O_SYNC) {
fdflags |= __WASI_FDFLAG_SYNC;
}
fdflags as __wasi_fdflags_t
}
pub fn nix_from_oflags(oflags: __wasi_oflags_t) -> nix::fcntl::OFlag {
use nix::fcntl::OFlag;
let mut nix_flags = OFlag::empty();
if oflags & (__WASI_O_CREAT as __wasi_oflags_t) != 0 {
nix_flags.insert(OFlag::O_CREAT);
}
if oflags & (__WASI_O_DIRECTORY as __wasi_oflags_t) != 0 {
nix_flags.insert(OFlag::O_DIRECTORY);
}
if oflags & (__WASI_O_EXCL as __wasi_oflags_t) != 0 {
nix_flags.insert(OFlag::O_EXCL);
}
if oflags & (__WASI_O_TRUNC as __wasi_oflags_t) != 0 {
nix_flags.insert(OFlag::O_TRUNC);
}
nix_flags
}
pub fn filetype_from_nix(sflags: nix::sys::stat::SFlag) -> __wasi_filetype_t {
use nix::sys::stat::SFlag;
if sflags.contains(SFlag::S_IFCHR) {
__WASI_FILETYPE_CHARACTER_DEVICE as __wasi_filetype_t
} else if sflags.contains(SFlag::S_IFBLK) {
__WASI_FILETYPE_BLOCK_DEVICE as __wasi_filetype_t
} else if sflags.contains(SFlag::S_IFIFO) | sflags.contains(SFlag::S_IFSOCK) {
__WASI_FILETYPE_SOCKET_STREAM as __wasi_filetype_t
} else if sflags.contains(SFlag::S_IFDIR) {
__WASI_FILETYPE_DIRECTORY as __wasi_filetype_t
} else if sflags.contains(SFlag::S_IFREG) {
__WASI_FILETYPE_REGULAR_FILE as __wasi_filetype_t
} else if sflags.contains(SFlag::S_IFLNK) {
__WASI_FILETYPE_SYMBOLIC_LINK as __wasi_filetype_t
} else {
__WASI_FILETYPE_UNKNOWN as __wasi_filetype_t
}
}
pub fn nix_from_filetype(sflags: __wasi_filetype_t) -> nix::sys::stat::SFlag {
use nix::sys::stat::SFlag;
let mut nix_sflags = SFlag::empty();
if sflags & (__WASI_FILETYPE_CHARACTER_DEVICE as __wasi_filetype_t) != 0 {
nix_sflags.insert(SFlag::S_IFCHR);
}
if sflags & (__WASI_FILETYPE_BLOCK_DEVICE as __wasi_filetype_t) != 0 {
nix_sflags.insert(SFlag::S_IFBLK);
}
if sflags & (__WASI_FILETYPE_SOCKET_STREAM as __wasi_filetype_t) != 0 {
nix_sflags.insert(SFlag::S_IFIFO);
nix_sflags.insert(SFlag::S_IFSOCK);
}
if sflags & (__WASI_FILETYPE_DIRECTORY as __wasi_filetype_t) != 0 {
nix_sflags.insert(SFlag::S_IFDIR);
}
if sflags & (__WASI_FILETYPE_REGULAR_FILE as __wasi_filetype_t) != 0 {
nix_sflags.insert(SFlag::S_IFREG);
}
if sflags & (__WASI_FILETYPE_SYMBOLIC_LINK as __wasi_filetype_t) != 0 {
nix_sflags.insert(SFlag::S_IFLNK);
}
nix_sflags
}
pub fn filestat_from_nix(filestat: nix::sys::stat::FileStat) -> __wasi_filestat_t {
let filetype = nix::sys::stat::SFlag::from_bits_truncate(filestat.st_mode);
__wasi_filestat_t {
st_dev: filestat.st_dev as __wasi_device_t,
st_ino: filestat.st_ino as __wasi_inode_t,
st_nlink: filestat.st_nlink as __wasi_linkcount_t,
st_size: filestat.st_size as __wasi_filesize_t,
st_atim: filestat.st_atime as __wasi_timestamp_t,
st_ctim: filestat.st_ctime as __wasi_timestamp_t,
st_mtim: filestat.st_mtime as __wasi_timestamp_t,
st_filetype: filetype_from_nix(filetype),
}
}
// Rights sets from wasmtime-wasi sandboxed system primitives. Transcribed because bindgen can't
// parse the #defines.
pub const RIGHTS_ALL: __wasi_rights_t = (__WASI_RIGHT_FD_DATASYNC
| __WASI_RIGHT_FD_READ
| __WASI_RIGHT_FD_SEEK
| __WASI_RIGHT_FD_FDSTAT_SET_FLAGS
| __WASI_RIGHT_FD_SYNC
| __WASI_RIGHT_FD_TELL
| __WASI_RIGHT_FD_WRITE
| __WASI_RIGHT_FD_ADVISE
| __WASI_RIGHT_FD_ALLOCATE
| __WASI_RIGHT_PATH_CREATE_DIRECTORY
| __WASI_RIGHT_PATH_CREATE_FILE
| __WASI_RIGHT_PATH_LINK_SOURCE
| __WASI_RIGHT_PATH_LINK_TARGET
| __WASI_RIGHT_PATH_OPEN
| __WASI_RIGHT_FD_READDIR
| __WASI_RIGHT_PATH_READLINK
| __WASI_RIGHT_PATH_RENAME_SOURCE
| __WASI_RIGHT_PATH_RENAME_TARGET
| __WASI_RIGHT_PATH_FILESTAT_GET
| __WASI_RIGHT_PATH_FILESTAT_SET_SIZE
| __WASI_RIGHT_PATH_FILESTAT_SET_TIMES
| __WASI_RIGHT_FD_FILESTAT_GET
| __WASI_RIGHT_FD_FILESTAT_SET_SIZE
| __WASI_RIGHT_FD_FILESTAT_SET_TIMES
| __WASI_RIGHT_PATH_SYMLINK
| __WASI_RIGHT_PATH_UNLINK_FILE
| __WASI_RIGHT_PATH_REMOVE_DIRECTORY
| __WASI_RIGHT_POLL_FD_READWRITE
| __WASI_RIGHT_SOCK_SHUTDOWN) as __wasi_rights_t;
// Block and character device interaction is outside the scope of
// CloudABI. Simply allow everything.
pub const RIGHTS_BLOCK_DEVICE_BASE: __wasi_rights_t = RIGHTS_ALL;
pub const RIGHTS_BLOCK_DEVICE_INHERITING: __wasi_rights_t = RIGHTS_ALL;
pub const RIGHTS_CHARACTER_DEVICE_BASE: __wasi_rights_t = RIGHTS_ALL;
pub const RIGHTS_CHARACTER_DEVICE_INHERITING: __wasi_rights_t = RIGHTS_ALL;
// Only allow directory operations on directories. Directories can only
// yield file descriptors to other directories and files.
pub const RIGHTS_DIRECTORY_BASE: __wasi_rights_t = (__WASI_RIGHT_FD_FDSTAT_SET_FLAGS
| __WASI_RIGHT_FD_SYNC
| __WASI_RIGHT_FD_ADVISE
| __WASI_RIGHT_PATH_CREATE_DIRECTORY
| __WASI_RIGHT_PATH_CREATE_FILE
| __WASI_RIGHT_PATH_LINK_SOURCE
| __WASI_RIGHT_PATH_LINK_TARGET
| __WASI_RIGHT_PATH_OPEN
| __WASI_RIGHT_FD_READDIR
| __WASI_RIGHT_PATH_READLINK
| __WASI_RIGHT_PATH_RENAME_SOURCE
| __WASI_RIGHT_PATH_RENAME_TARGET
| __WASI_RIGHT_PATH_FILESTAT_GET
| __WASI_RIGHT_PATH_FILESTAT_SET_SIZE
| __WASI_RIGHT_PATH_FILESTAT_SET_TIMES
| __WASI_RIGHT_FD_FILESTAT_GET
| __WASI_RIGHT_FD_FILESTAT_SET_SIZE
| __WASI_RIGHT_FD_FILESTAT_SET_TIMES
| __WASI_RIGHT_PATH_SYMLINK
| __WASI_RIGHT_PATH_UNLINK_FILE
| __WASI_RIGHT_PATH_REMOVE_DIRECTORY
| __WASI_RIGHT_POLL_FD_READWRITE)
as __wasi_rights_t;
pub const RIGHTS_DIRECTORY_INHERITING: __wasi_rights_t =
(RIGHTS_DIRECTORY_BASE | RIGHTS_REGULAR_FILE_BASE);
// Operations that apply to regular files.
pub const RIGHTS_REGULAR_FILE_BASE: __wasi_rights_t = (__WASI_RIGHT_FD_DATASYNC
| __WASI_RIGHT_FD_READ
| __WASI_RIGHT_FD_SEEK
| __WASI_RIGHT_FD_FDSTAT_SET_FLAGS
| __WASI_RIGHT_FD_SYNC
| __WASI_RIGHT_FD_TELL
| __WASI_RIGHT_FD_WRITE
| __WASI_RIGHT_FD_ADVISE
| __WASI_RIGHT_FD_ALLOCATE
| __WASI_RIGHT_FD_FILESTAT_GET
| __WASI_RIGHT_FD_FILESTAT_SET_SIZE
| __WASI_RIGHT_FD_FILESTAT_SET_TIMES
| __WASI_RIGHT_POLL_FD_READWRITE)
as __wasi_rights_t;
pub const RIGHTS_REGULAR_FILE_INHERITING: __wasi_rights_t = 0;
// Operations that apply to shared memory objects.
pub const RIGHTS_SHARED_MEMORY_BASE: __wasi_rights_t = (__WASI_RIGHT_FD_READ
| __WASI_RIGHT_FD_WRITE
| __WASI_RIGHT_FD_FILESTAT_GET
| __WASI_RIGHT_FD_FILESTAT_SET_SIZE)
as __wasi_rights_t;
pub const RIGHTS_SHARED_MEMORY_INHERITING: __wasi_rights_t = 0;
// Operations that apply to sockets and socket pairs.
pub const RIGHTS_SOCKET_BASE: __wasi_rights_t = (__WASI_RIGHT_FD_READ
| __WASI_RIGHT_FD_FDSTAT_SET_FLAGS
| __WASI_RIGHT_FD_WRITE
| __WASI_RIGHT_FD_FILESTAT_GET
| __WASI_RIGHT_POLL_FD_READWRITE
| __WASI_RIGHT_SOCK_SHUTDOWN)
as __wasi_rights_t;
pub const RIGHTS_SOCKET_INHERITING: __wasi_rights_t = RIGHTS_ALL;
// Operations that apply to TTYs.
pub const RIGHTS_TTY_BASE: __wasi_rights_t = (__WASI_RIGHT_FD_READ
| __WASI_RIGHT_FD_FDSTAT_SET_FLAGS
| __WASI_RIGHT_FD_WRITE
| __WASI_RIGHT_FD_FILESTAT_GET
| __WASI_RIGHT_POLL_FD_READWRITE)
as __wasi_rights_t;
pub const RIGHTS_TTY_INHERITING: __wasi_rights_t = 0;

1360
src/hostcalls.rs Normal file

File diff suppressed because it is too large Load Diff

8
src/lib.rs Normal file
View File

@@ -0,0 +1,8 @@
pub mod ctx;
pub mod fdentry;
pub mod host;
pub mod hostcalls;
pub mod memory;
pub mod wasm32;
pub use ctx::{WasiCtx, WasiCtxBuilder};

479
src/memory.rs Normal file
View File

@@ -0,0 +1,479 @@
//! Functions to go back and forth between WASI types in host and wasm32 representations.
//!
//! This module is an adaptation of the `wasmtime-wasi` module
//! [`translate.rs`](https://github.com/CraneStation/wasmtime-wasi/blob/1a6ecf3a0378d71f3fc1ba25ce76a2b43e4166b8/lib/wasi/src/translate.rs);
//! its license file `LICENSE.wasmtime-wasi` is included in this project.
//!
//! Any of these functions that take a `Vmctx` argument are only meant to be called from within a
//! hostcall.
//!
//! This sort of manual encoding will hopefully be obsolete once the IDL is developed.
use crate::ctx::VmContext;
use crate::{host, wasm32};
use cast;
use cast::From as _0;
use std::mem::{align_of, size_of};
use std::slice;
macro_rules! bail_errno {
( $errno:ident ) => {
return Err(host::$errno as host::__wasi_errno_t);
};
}
pub unsafe fn dec_ptr_to<T>(
vmctx: *mut VmContext,
ptr: wasm32::uintptr_t,
) -> Result<*mut T, host::__wasi_errno_t> {
// check that the ptr is aligned
if ptr as usize % align_of::<T>() != 0 {
bail_errno!(__WASI_EINVAL);
}
(*vmctx).dec_ptr(ptr, size_of::<T>()).map(|p| p as *mut T)
}
pub unsafe fn dec_pointee<T>(
vmctx: *mut VmContext,
ptr: wasm32::uintptr_t,
) -> Result<T, host::__wasi_errno_t> {
dec_ptr_to::<T>(vmctx, ptr).map(|p| p.read())
}
pub unsafe fn enc_pointee<T>(
vmctx: *mut VmContext,
ptr: wasm32::uintptr_t,
t: T,
) -> Result<(), host::__wasi_errno_t> {
dec_ptr_to::<T>(vmctx, ptr).map(|p| p.write(t))
}
pub unsafe fn dec_slice_of<T>(
vmctx: *mut VmContext,
ptr: wasm32::uintptr_t,
len: wasm32::size_t,
) -> Result<(*mut T, usize), host::__wasi_errno_t> {
// check alignment, and that length doesn't overflow
if ptr as usize % align_of::<T>() != 0 {
return Err(host::__WASI_EINVAL as host::__wasi_errno_t);
}
let len = dec_usize(len);
let len_bytes = if let Some(len) = size_of::<T>().checked_mul(len) {
len
} else {
return Err(host::__WASI_EOVERFLOW as host::__wasi_errno_t);
};
let ptr = (*vmctx).dec_ptr(ptr, len_bytes)? as *mut T;
Ok((ptr, len))
}
pub unsafe fn enc_slice_of<T>(
vmctx: *mut VmContext,
slice: &[T],
ptr: wasm32::uintptr_t,
) -> Result<(), host::__wasi_errno_t> {
// check alignment
if ptr as usize % align_of::<T>() != 0 {
return Err(host::__WASI_EINVAL as host::__wasi_errno_t);
}
// check that length doesn't overflow
let len_bytes = if let Some(len) = size_of::<T>().checked_mul(slice.len()) {
len
} else {
return Err(host::__WASI_EOVERFLOW as host::__wasi_errno_t);
};
// get the pointer into guest memory, and copy the bytes
let ptr = (*vmctx).dec_ptr(ptr, len_bytes)? as *mut libc::c_void;
libc::memcpy(ptr, slice.as_ptr() as *const libc::c_void, len_bytes);
Ok(())
}
macro_rules! dec_enc_scalar {
( $ty:ident, $dec:ident, $dec_byref:ident, $enc:ident, $enc_byref:ident) => {
pub fn $dec(x: wasm32::$ty) -> host::$ty {
host::$ty::from_le(x)
}
pub unsafe fn $dec_byref(
vmctx: *mut VmContext,
ptr: wasm32::uintptr_t,
) -> Result<host::$ty, host::__wasi_errno_t> {
dec_pointee::<wasm32::$ty>(vmctx, ptr).map($dec)
}
pub fn $enc(x: host::$ty) -> wasm32::$ty {
x.to_le()
}
pub unsafe fn $enc_byref(
vmctx: *mut VmContext,
ptr: wasm32::uintptr_t,
x: host::$ty,
) -> Result<(), host::__wasi_errno_t> {
enc_pointee::<wasm32::$ty>(vmctx, ptr, $enc(x))
}
};
}
pub unsafe fn dec_ciovec(
vmctx: *mut VmContext,
ciovec: &wasm32::__wasi_ciovec_t,
) -> Result<host::__wasi_ciovec_t, host::__wasi_errno_t> {
let len = dec_usize(ciovec.buf_len);
Ok(host::__wasi_ciovec_t {
buf: (*vmctx).dec_ptr(ciovec.buf, len)? as *const host::void,
buf_len: len,
})
}
pub unsafe fn dec_ciovec_slice(
vmctx: *mut VmContext,
ptr: wasm32::uintptr_t,
len: wasm32::size_t,
) -> Result<Vec<host::__wasi_ciovec_t>, host::__wasi_errno_t> {
let slice = dec_slice_of::<wasm32::__wasi_ciovec_t>(vmctx, ptr, len)?;
let slice = slice::from_raw_parts(slice.0, slice.1);
slice.iter().map(|iov| dec_ciovec(vmctx, iov)).collect()
}
dec_enc_scalar!(
__wasi_clockid_t,
dec_clockid,
dec_clockid_byref,
enc_clockid,
enc_clockid_byref
);
dec_enc_scalar!(
__wasi_errno_t,
dec_errno,
dec_errno_byref,
enc_errno,
enc_errno_byref
);
dec_enc_scalar!(
__wasi_exitcode_t,
dec_exitcode,
dec_exitcode_byref,
enc_exitcode,
enc_exitcode_byref
);
dec_enc_scalar!(__wasi_fd_t, dec_fd, dec_fd_byref, enc_fd, enc_fd_byref);
dec_enc_scalar!(
__wasi_fdflags_t,
dec_fdflags,
dec_fdflags_byref,
enc_fdflags,
enc_fdflags_byref
);
dec_enc_scalar!(
__wasi_device_t,
dec_device,
dev_device_byref,
enc_device,
enc_device_byref
);
dec_enc_scalar!(
__wasi_inode_t,
dec_inode,
dev_inode_byref,
enc_inode,
enc_inode_byref
);
dec_enc_scalar!(
__wasi_linkcount_t,
dec_linkcount,
dev_linkcount_byref,
enc_linkcount,
enc_linkcount_byref
);
pub fn dec_filestat(filestat: wasm32::__wasi_filestat_t) -> host::__wasi_filestat_t {
host::__wasi_filestat_t {
st_dev: dec_device(filestat.st_dev),
st_ino: dec_inode(filestat.st_ino),
st_filetype: dec_filetype(filestat.st_filetype),
st_nlink: dec_linkcount(filestat.st_nlink),
st_size: dec_filesize(filestat.st_size),
st_atim: dec_timestamp(filestat.st_atim),
st_mtim: dec_timestamp(filestat.st_mtim),
st_ctim: dec_timestamp(filestat.st_ctim),
}
}
pub unsafe fn dec_filestat_byref(
vmctx: *mut VmContext,
filestat_ptr: wasm32::uintptr_t,
) -> Result<host::__wasi_filestat_t, host::__wasi_errno_t> {
dec_pointee::<wasm32::__wasi_filestat_t>(vmctx, filestat_ptr).map(dec_filestat)
}
pub fn enc_filestat(filestat: host::__wasi_filestat_t) -> wasm32::__wasi_filestat_t {
wasm32::__wasi_filestat_t {
st_dev: enc_device(filestat.st_dev),
st_ino: enc_inode(filestat.st_ino),
st_filetype: enc_filetype(filestat.st_filetype),
st_nlink: enc_linkcount(filestat.st_nlink),
st_size: enc_filesize(filestat.st_size),
st_atim: enc_timestamp(filestat.st_atim),
st_mtim: enc_timestamp(filestat.st_mtim),
st_ctim: enc_timestamp(filestat.st_ctim),
}
}
pub unsafe fn enc_filestat_byref(
vmctx: *mut VmContext,
filestat_ptr: wasm32::uintptr_t,
host_filestat: host::__wasi_filestat_t,
) -> Result<(), host::__wasi_errno_t> {
let filestat = enc_filestat(host_filestat);
enc_pointee::<wasm32::__wasi_filestat_t>(vmctx, filestat_ptr, filestat)
}
pub fn dec_fdstat(fdstat: wasm32::__wasi_fdstat_t) -> host::__wasi_fdstat_t {
host::__wasi_fdstat_t {
fs_filetype: dec_filetype(fdstat.fs_filetype),
fs_flags: dec_fdflags(fdstat.fs_flags),
fs_rights_base: dec_rights(fdstat.fs_rights_base),
fs_rights_inheriting: dec_rights(fdstat.fs_rights_inheriting),
}
}
pub unsafe fn dec_fdstat_byref(
vmctx: *mut VmContext,
fdstat_ptr: wasm32::uintptr_t,
) -> Result<host::__wasi_fdstat_t, host::__wasi_errno_t> {
dec_pointee::<wasm32::__wasi_fdstat_t>(vmctx, fdstat_ptr).map(dec_fdstat)
}
pub fn enc_fdstat(fdstat: host::__wasi_fdstat_t) -> wasm32::__wasi_fdstat_t {
wasm32::__wasi_fdstat_t {
fs_filetype: enc_filetype(fdstat.fs_filetype),
fs_flags: enc_fdflags(fdstat.fs_flags),
__bindgen_padding_0: 0,
fs_rights_base: enc_rights(fdstat.fs_rights_base),
fs_rights_inheriting: enc_rights(fdstat.fs_rights_inheriting),
}
}
pub unsafe fn enc_fdstat_byref(
vmctx: *mut VmContext,
fdstat_ptr: wasm32::uintptr_t,
host_fdstat: host::__wasi_fdstat_t,
) -> Result<(), host::__wasi_errno_t> {
let fdstat = enc_fdstat(host_fdstat);
enc_pointee::<wasm32::__wasi_fdstat_t>(vmctx, fdstat_ptr, fdstat)
}
dec_enc_scalar!(
__wasi_filedelta_t,
dec_filedelta,
dec_filedelta_byref,
enc_filedelta,
enc_filedelta_byref
);
dec_enc_scalar!(
__wasi_filesize_t,
dec_filesize,
dec_filesize_byref,
enc_filesize,
enc_filesize_byref
);
dec_enc_scalar!(
__wasi_filetype_t,
dec_filetype,
dec_filetype_byref,
enc_filetype,
enc_filetype_byref
);
dec_enc_scalar!(
__wasi_lookupflags_t,
dec_lookupflags,
dec_lookupflags_byref,
enc_lookupflags,
enc_lookupflags_byref
);
dec_enc_scalar!(
__wasi_oflags_t,
dec_oflags,
dec_oflags_byref,
enc_oflags,
enc_oflags_byref
);
pub fn dec_prestat(
prestat: wasm32::__wasi_prestat_t,
) -> Result<host::__wasi_prestat_t, host::__wasi_errno_t> {
match prestat.pr_type {
wasm32::__WASI_PREOPENTYPE_DIR => {
let u = host::__wasi_prestat_t___wasi_prestat_u {
dir: host::__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t {
pr_name_len: dec_usize(unsafe { prestat.u.dir.pr_name_len }),
},
};
Ok(host::__wasi_prestat_t {
pr_type: host::__WASI_PREOPENTYPE_DIR as host::__wasi_preopentype_t,
u,
})
}
_ => Err(host::__WASI_EINVAL as host::__wasi_errno_t),
}
}
pub unsafe fn dec_prestat_byref(
vmctx: *mut VmContext,
prestat_ptr: wasm32::uintptr_t,
) -> Result<host::__wasi_prestat_t, host::__wasi_errno_t> {
dec_pointee::<wasm32::__wasi_prestat_t>(vmctx, prestat_ptr).and_then(dec_prestat)
}
pub fn enc_prestat(
prestat: host::__wasi_prestat_t,
) -> Result<wasm32::__wasi_prestat_t, host::__wasi_errno_t> {
match prestat.pr_type as u32 {
host::__WASI_PREOPENTYPE_DIR => {
let u = wasm32::__wasi_prestat_t___wasi_prestat_u {
dir: wasm32::__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t {
pr_name_len: enc_usize(unsafe { prestat.u.dir.pr_name_len }),
},
};
Ok(wasm32::__wasi_prestat_t {
pr_type: wasm32::__WASI_PREOPENTYPE_DIR as wasm32::__wasi_preopentype_t,
u,
})
}
_ => Err(host::__WASI_EINVAL as host::__wasi_errno_t),
}
}
pub unsafe fn enc_prestat_byref(
vmctx: *mut VmContext,
prestat_ptr: wasm32::uintptr_t,
host_prestat: host::__wasi_prestat_t,
) -> Result<(), host::__wasi_errno_t> {
let prestat = enc_prestat(host_prestat)?;
enc_pointee::<wasm32::__wasi_prestat_t>(vmctx, prestat_ptr, prestat)
}
dec_enc_scalar!(
__wasi_rights_t,
dec_rights,
dec_rights_byref,
enc_rights,
enc_rights_byref
);
dec_enc_scalar!(
__wasi_timestamp_t,
dec_timestamp,
dec_timestamp_byref,
enc_timestamp,
enc_timestamp_byref
);
pub fn dec_usize(size: wasm32::size_t) -> usize {
cast::usize(u32::from_le(size))
}
pub fn enc_usize(size: usize) -> wasm32::size_t {
wasm32::size_t::cast(size).unwrap()
}
pub unsafe fn enc_usize_byref(
vmctx: *mut VmContext,
usize_ptr: wasm32::uintptr_t,
host_usize: usize,
) -> Result<(), host::__wasi_errno_t> {
enc_pointee::<wasm32::size_t>(vmctx, usize_ptr, enc_usize(host_usize))
}
dec_enc_scalar!(
__wasi_whence_t,
dec_whence,
dec_whence_byref,
enc_whence,
enc_whence_byref
);
dec_enc_scalar!(
__wasi_subclockflags_t,
dec_subclockflags,
dec_subclockflags_byref,
enc_subclockflags,
enc_subclockflags_byref
);
dec_enc_scalar!(
__wasi_eventrwflags_t,
dec_eventrwflags,
dec_eventrwflags_byref,
enc_eventrwflags,
enc_eventrwflags_byref
);
dec_enc_scalar!(
__wasi_eventtype_t,
dec_eventtype,
dec_eventtype_byref,
enc_eventtype,
enc_eventtype_byref
);
dec_enc_scalar!(
__wasi_userdata_t,
dec_userdata,
dec_userdata_byref,
enc_userdata,
enc_userdata_byref
);
pub fn dec_subscription(
subscription: &wasm32::__wasi_subscription_t,
) -> Result<host::__wasi_subscription_t, host::__wasi_errno_t> {
let userdata = dec_userdata(subscription.userdata);
let type_ = dec_eventtype(subscription.type_);
let u_orig = subscription.__bindgen_anon_1;
let u = match type_ {
wasm32::__WASI_EVENTTYPE_CLOCK => host::__wasi_subscription_t___wasi_subscription_u {
clock: unsafe {
host::__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t {
identifier: dec_userdata(u_orig.clock.identifier),
clock_id: dec_clockid(u_orig.clock.clock_id),
timeout: dec_timestamp(u_orig.clock.timeout),
precision: dec_timestamp(u_orig.clock.precision),
flags: dec_subclockflags(u_orig.clock.flags),
}
},
},
wasm32::__WASI_EVENTTYPE_FD_READ | wasm32::__WASI_EVENTTYPE_FD_WRITE => host::__wasi_subscription_t___wasi_subscription_u {
fd_readwrite: host::__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t {
fd: dec_fd(unsafe{u_orig.fd_readwrite.fd})
}
},
_ => return Err(wasm32::__WASI_EINVAL)
};
Ok(host::__wasi_subscription_t { userdata, type_, u })
}
pub fn enc_event(event: host::__wasi_event_t) -> wasm32::__wasi_event_t {
let fd_readwrite = unsafe { event.u.fd_readwrite };
wasm32::__wasi_event_t {
userdata: enc_userdata(event.userdata),
type_: enc_eventtype(event.type_),
error: enc_errno(event.error),
__bindgen_anon_1: wasm32::__wasi_event_t__bindgen_ty_1 {
fd_readwrite: wasm32::__wasi_event_t__bindgen_ty_1__bindgen_ty_1 {
nbytes: enc_filesize(fd_readwrite.nbytes),
flags: enc_eventrwflags(fd_readwrite.flags),
__bindgen_padding_0: [0; 3],
},
},
__bindgen_padding_0: 0,
}
}

1367
src/wasm32.rs Normal file

File diff suppressed because it is too large Load Diff