summaryrefslogtreecommitdiffstats
path: root/third_party/rust/lucet-wasi-wasmsbx
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/lucet-wasi-wasmsbx
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/lucet-wasi-wasmsbx')
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/.cargo-checksum.json1
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/Cargo.toml67
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/LICENSE220
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/LICENSE.cloudabi-utils24
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/LICENSE.wasmtime219
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/bindings.json88
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/build.rs114
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/examples/.gitignore1
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/examples/Makefile54
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/examples/README.md69
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/examples/hello.c16
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/examples/pseudoquine.c18
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/include/lucet_wasi.h23
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/src/bindings.rs11
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/src/c_api.rs98
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/src/ctx.rs260
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/src/fdentry.rs169
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/src/host.rs346
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/fs.rs1358
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/fs_helpers.rs306
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/misc.rs457
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/mod.rs448
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/timers.rs113
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/src/lib.rs16
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/src/memory.rs620
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/src/wasi_host.rs1035
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/src/wasm32.rs1367
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/cant_dotdot.c12
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/clock_getres.c13
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/duplicate_import.wat38
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/exitcode.c4
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/follow_symlink.c14
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/fs.c158
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/getentropy.c17
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/getrusage.c30
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/gettimeofday.c26
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/notdir.c12
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/poll.c32
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/preopen_populates.c4
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/read_file.c14
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/read_file_twice.c16
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/stat.c54
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/stdin.c10
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/symlink_escape.c10
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/symlink_loop.c10
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/guests/write_file.c16
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/test_helpers/mod.rs127
-rw-r--r--third_party/rust/lucet-wasi-wasmsbx/tests/tests.rs405
48 files changed, 8540 insertions, 0 deletions
diff --git a/third_party/rust/lucet-wasi-wasmsbx/.cargo-checksum.json b/third_party/rust/lucet-wasi-wasmsbx/.cargo-checksum.json
new file mode 100644
index 0000000000..122611acfb
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/.cargo-checksum.json
@@ -0,0 +1 @@
+{"files":{"Cargo.toml":"42e73da184367cdd609f7fb5574de225ee53ae58c0a88fec1f1d091b1e0e72b8","LICENSE":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","LICENSE.cloudabi-utils":"86a34251f0aab76b7dc3daf8d252afbdf481ea94aa5b46d020205178b7e2eac1","LICENSE.wasmtime":"a6c48161a09acc75a0e25503bab66a731eb5fba5392ed4bb4743e4ba5085327a","bindings.json":"08df8aaa3e5610f1e2f2d2c0a6399d80a7c0842ae871367e932a2b3ec741a289","build.rs":"593173ad03963afcbef43f1843be6f04cde1df3eae0298ca20bf881019dd350a","examples/.gitignore":"44575cf5b28512d75644bf54a517dcef304ff809fd511747621b4d64f19aac66","examples/Makefile":"d2d2ceeb1bc4435189ea9a2710b6f5f5331ce6aa73ae8a4f4edcca215058a9b4","examples/README.md":"f2a5be6cc88d511c9f4d3bfefdd42dcb2ace813bc23f6a4430b6b543f7373341","examples/hello.c":"9cbc0d3173e02309e15372835fa849d196b2a202d81806fea60378e1878d0c53","examples/pseudoquine.c":"8fd696f8e1b8fb86188564a05f4776875ead31d785a12e3aa4af9d9c1b46d5b5","include/lucet_wasi.h":"497f712c64f753ebdf73ab05b0b340d50094f9c59bb8637ccbf99d895cd20966","src/bindings.rs":"edbeb51d1a93fd31039ee1f1dc7c1b6c0bded2cf5dad10039e8b7da81a4d4a12","src/c_api.rs":"a9c73070a88a461882a28e3e2adfd773f569b964c7ffabde39a3cef907782f71","src/ctx.rs":"1c40b0c2dd8afa61090470a11c09ace24f25bca448b95bb1275e37cf8061f109","src/fdentry.rs":"94a8480fa587e5586327dfd6b66d8a6a3ef1f8091ba8deb335bf45642f4f98e6","src/host.rs":"6f05f8fea2afed827abfc3c008a5854a8023d91d066580ecfb49e5c8036ef3a3","src/hostcalls/fs.rs":"4726e6f695f7d1d4e371ec52c57f4e36b0ba0d2302fc008b21a301f5fd7a5c97","src/hostcalls/fs_helpers.rs":"474bce0a1f15fa23b0b0b8aa83143d993dd2cbd7cdfc38c118d452d04e80caea","src/hostcalls/misc.rs":"83d087891d92af08cfa2d2e0c5f41cc47cb8219460f6dbcc8666b418dfef206e","src/hostcalls/mod.rs":"4c5d3f65c69503e11e647770879026c37c0e5e01a99b7116c8fb9411b4797187","src/hostcalls/timers.rs":"e65d6a491256b5d6051b6816f6c5049ba3cdc6142651bac81f34d659c1c2a104","src/lib.rs":"1e8f0e325385d53393ff2495da0ece4e6b1f955290a8cfdbea368d4a3350fbf2","src/memory.rs":"0a09026b15d27f99d74e560cd94795f645cba414a8491bc961987fab9d9da69b","src/wasi_host.rs":"cacbdac28304a837b11e5ad400ae9de3ee79c0284be335e64606ecdfe426ad6e","src/wasm32.rs":"13a5dc6e59784662f1e55eccb457cbbae241a96f70cfa72c41d55858ca05b980","tests/guests/cant_dotdot.c":"609b8cece9443e375a0b38a7e43651b179f66ee9c686edba6696fe1bcd45b111","tests/guests/clock_getres.c":"f5e41c0a2b05a8d7cdb5b4da6c8b6778b858004c1e9d115503c45a1d976be33b","tests/guests/duplicate_import.wat":"4bd8d7a5c1d1597dbe7648300e94e3fab84d7ab068d56cfb656aa1a208026cee","tests/guests/exitcode.c":"b7c5cec3ead0ed82326c568287a1f3398e71ae7e447ce49a3c4c7114c82495af","tests/guests/follow_symlink.c":"de3143ad2bbbfe834c0c32b54c9fcf144ca4eba5cdcf7588929e5f47225ab616","tests/guests/fs.c":"0dca5232ff5da1b7745e3b44bca39333c01a20ba4eae1a6a0a1c492c71ca1efa","tests/guests/getentropy.c":"5d80bcc68dcf3ba91576969055099d61635ae713c057b3cb36afb122a5f26347","tests/guests/getrusage.c":"8114c103b85eb564d9ab43684958bc1939de3794d314b7c121762f3a2f0434a6","tests/guests/gettimeofday.c":"4a57f376b06f4228017b82695448a0bd213fb91455f5301d689cd87fcff01f06","tests/guests/notdir.c":"bd8f8b24360b7cf8d5dced9d9ba4c15843fcbbae89fecc13e3a457c33a275e28","tests/guests/poll.c":"aefaa9b58ce9906dc379e0bd25fa68dfbf8cdffb48cd5ecde1d67708b83b366d","tests/guests/preopen_populates.c":"f186e4eb4aab6a1d9ec7bc5c49eaea6d9d162e0159dfe8f953bb48ade9b58d43","tests/guests/read_file.c":"1aab9393f005f05b69592826d7c4d384a115d5bca42c66f10a901811b4b1dcac","tests/guests/read_file_twice.c":"04a3dad7a43b93e36efd4e2c822c11b3f129429ec799af304d82b358686c578a","tests/guests/stat.c":"02756933ea7d4337b4fa04344b32968851b02f9d0bd5ea1cb0e2f022e8c65ab0","tests/guests/stdin.c":"66efc4b54f68d1138046f1afefae15f7d4555b2904b4a988818e61e67fe8fefb","tests/guests/symlink_escape.c":"686e047b5c986e29c854bcd93996d027dcdc8721219fa9fa532efc98d2798f5c","tests/guests/symlink_loop.c":"2bbddf3a5edfc6e5f3c0fa82cee4ac92b18804810509e263abd17f5240cd37e5","tests/guests/write_file.c":"9e9b14552c2445cfa6d0aa26b334081a59e6e3428dbb17ceca005a9ba59d3220","tests/test_helpers/mod.rs":"bc18194317611fe1be5c439a7a9e0de75399555c3b6de4275af149fb180456c8","tests/tests.rs":"173a7e0f086f6ed46474686cc3413ee68bbd2ff67004f7790e963a1392c7c46e"},"package":null} \ No newline at end of file
diff --git a/third_party/rust/lucet-wasi-wasmsbx/Cargo.toml b/third_party/rust/lucet-wasi-wasmsbx/Cargo.toml
new file mode 100644
index 0000000000..54d41f6e49
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/Cargo.toml
@@ -0,0 +1,67 @@
+[package]
+name = "lucet-wasi-wasmsbx"
+version = "0.1.1"
+description = "Fastly's runtime for the WebAssembly System Interface (WASI)"
+homepage = "https://github.com/fastly/lucet"
+repository = "https://github.com/fastly/lucet"
+license = "Apache-2.0 WITH LLVM-exception"
+categories = ["wasm"]
+authors = ["Lucet team <lucet@fastly.com>"]
+edition = "2018"
+
+# `src/wasi_host.rs` is automatically generated using clang and
+# wasi-libc headers. This requires these to be present, and installed
+# at specific paths, which is not something we can rely on outside
+# of our environment.
+# So, we follow what most other tools using `bindgen` do, and provide
+# a pre-generated version of the file, along with a way to update it.
+# This is what the `update-bindings` feature do. It requires the WASI SDK
+# to be either installed in `/opt/wasi-sdk`, or at a location defined by
+# a `WASI_SDK` environment variable, as well as `clang` headers either
+# being part of `WASI_SDK`, or found in a path defined by a
+# `CLANG_ROOT` environment variable.
+[features]
+update-bindings = ["bindgen"]
+
+[dependencies]
+cast = "0.2"
+failure = "0.1"
+libc = "0.2.65"
+lucet-runtime = { path = "../lucet-runtime", version = "0.1.1", package = "lucet-runtime-wasmsbx" }
+lucet-runtime-internals = { path = "../lucet-runtime/lucet-runtime-internals", version = "0.1.1", package = "lucet-runtime-internals-wasmsbx" }
+lucet-module = { path = "../lucet-module", version = "0.1.1", package="lucet-module-wasmsbx" }
+nix = "0.13"
+rand = "0.7"
+lazy_static = ">=1.4.0"
+
+[target.'cfg(target_os = "macos")'.dependencies]
+mach = "0.3.2"
+
+[dev-dependencies]
+lucet-wasi-sdk = { path = "../lucet-wasi-sdk", version = "0.1.1" }
+lucetc = { path = "../lucetc", version = "0.1.1" }
+tempfile = "3.0"
+
+[build-dependencies.bindgen]
+version = "0.47"
+optional = true
+
+[lib]
+name = "lucet_wasi"
+crate-type = ["rlib", "staticlib"]
+
+[package.metadata.deb]
+name = "fst-lucet-wasi"
+maintainer = "Adam C. Foltzer <acfoltzer@fastly.com>"
+depends = "$auto"
+priority = "optional"
+assets = [
+ ["target/release/liblucet_wasi.a", "/opt/fst-lucet-wasi/lib/", "644"],
+ ["target/release/liblucet_wasi.rlib", "/opt/fst-lucet-wasi/lib/", "644"],
+ ["target/release/liblucet_wasi.so", "/opt/fst-lucet-wasi/lib/", "755"],
+ ["include/*.h", "/opt/fst-lucet-wasi/include/", "644"],
+ ["LICENSE", "/opt/fst-lucet-wasi/share/doc/lucet-wasi/", "644"],
+ ["LICENSE.wasmtime", "/opt/fst-lucet-wasi/share/doc/lucet-wasi/", "644"],
+ ["LICENSE.cloudabi-utils", "/opt/fst-lucet-wasi/share/doc/lucet-wasi/", "644"],
+ ["bindings.json", "/opt/fst-lucet-wasi/share/", "644"],
+]
diff --git a/third_party/rust/lucet-wasi-wasmsbx/LICENSE b/third_party/rust/lucet-wasi-wasmsbx/LICENSE
new file mode 100644
index 0000000000..f9d81955f4
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/LICENSE
@@ -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.
+
diff --git a/third_party/rust/lucet-wasi-wasmsbx/LICENSE.cloudabi-utils b/third_party/rust/lucet-wasi-wasmsbx/LICENSE.cloudabi-utils
new file mode 100644
index 0000000000..fef83ffb83
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/LICENSE.cloudabi-utils
@@ -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. \ No newline at end of file
diff --git a/third_party/rust/lucet-wasi-wasmsbx/LICENSE.wasmtime b/third_party/rust/lucet-wasi-wasmsbx/LICENSE.wasmtime
new file mode 100644
index 0000000000..be1d7c438a
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/LICENSE.wasmtime
@@ -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.
diff --git a/third_party/rust/lucet-wasi-wasmsbx/bindings.json b/third_party/rust/lucet-wasi-wasmsbx/bindings.json
new file mode 100644
index 0000000000..90d3e7c6b9
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/bindings.json
@@ -0,0 +1,88 @@
+{
+ "wasi_unstable": {
+ "args_get": "__wasi_args_get",
+ "args_sizes_get": "__wasi_args_sizes_get",
+ "clock_res_get": "__wasi_clock_res_get",
+ "clock_time_get": "__wasi_clock_time_get",
+ "environ_get": "__wasi_environ_get",
+ "environ_sizes_get": "__wasi_environ_sizes_get",
+ "fd_advise": "__wasi_fd_advise",
+ "fd_allocate": "__wasi_fd_allocate",
+ "fd_close": "__wasi_fd_close",
+ "fd_datasync": "__wasi_fd_datasync",
+ "fd_fdstat_get": "__wasi_fd_fdstat_get",
+ "fd_fdstat_set_flags": "__wasi_fd_fdstat_set_flags",
+ "fd_fdstat_set_rights": "__wasi_fd_fdstat_set_rights",
+ "fd_filestat_get": "__wasi_fd_filestat_get",
+ "fd_filestat_set_size": "__wasi_fd_filestat_set_size",
+ "fd_filestat_set_times": "__wasi_fd_filestat_set_times",
+ "fd_pread": "__wasi_fd_pread",
+ "fd_prestat_dir_name": "__wasi_fd_prestat_dir_name",
+ "fd_prestat_get": "__wasi_fd_prestat_get",
+ "fd_pwrite": "__wasi_fd_pwrite",
+ "fd_read": "__wasi_fd_read",
+ "fd_readdir": "__wasi_fd_readdir",
+ "fd_renumber": "__wasi_fd_renumber",
+ "fd_seek": "__wasi_fd_seek",
+ "fd_sync": "__wasi_fd_sync",
+ "fd_tell": "__wasi_fd_tell",
+ "fd_write": "__wasi_fd_write",
+ "path_create_directory": "__wasi_path_create_directory",
+ "path_filestat_get": "__wasi_path_filestat_get",
+ "path_filestat_set_times": "__wasi_path_filestat_set_times",
+ "path_link": "__wasi_path_link",
+ "path_open": "__wasi_path_open",
+ "path_readlink": "__wasi_path_readlink",
+ "path_remove_directory": "__wasi_path_remove_directory",
+ "path_rename": "__wasi_path_rename",
+ "path_symlink": "__wasi_path_symlink",
+ "path_unlink_file": "__wasi_path_unlink_file",
+ "poll_oneoff": "__wasi_poll_oneoff",
+ "proc_exit": "__wasi_proc_exit",
+ "random_get": "__wasi_random_get",
+ "sched_yield": "__wasi_sched_yield"
+ },
+ "wasi_snapshot_preview1": {
+ "args_get": "__wasi_args_get",
+ "args_sizes_get": "__wasi_args_sizes_get",
+ "clock_res_get": "__wasi_clock_res_get",
+ "clock_time_get": "__wasi_clock_time_get",
+ "environ_get": "__wasi_environ_get",
+ "environ_sizes_get": "__wasi_environ_sizes_get",
+ "fd_advise": "__wasi_fd_advise",
+ "fd_allocate": "__wasi_fd_allocate",
+ "fd_close": "__wasi_fd_close",
+ "fd_datasync": "__wasi_fd_datasync",
+ "fd_fdstat_get": "__wasi_fd_fdstat_get",
+ "fd_fdstat_set_flags": "__wasi_fd_fdstat_set_flags",
+ "fd_fdstat_set_rights": "__wasi_fd_fdstat_set_rights",
+ "fd_filestat_get": "__wasi_fd_filestat_get",
+ "fd_filestat_set_size": "__wasi_fd_filestat_set_size",
+ "fd_filestat_set_times": "__wasi_fd_filestat_set_times",
+ "fd_pread": "__wasi_fd_pread",
+ "fd_prestat_dir_name": "__wasi_fd_prestat_dir_name",
+ "fd_prestat_get": "__wasi_fd_prestat_get",
+ "fd_pwrite": "__wasi_fd_pwrite",
+ "fd_read": "__wasi_fd_read",
+ "fd_readdir": "__wasi_fd_readdir",
+ "fd_renumber": "__wasi_fd_renumber",
+ "fd_seek": "__wasi_fd_seek",
+ "fd_sync": "__wasi_fd_sync",
+ "fd_tell": "__wasi_fd_tell",
+ "fd_write": "__wasi_fd_write",
+ "path_create_directory": "__wasi_path_create_directory",
+ "path_filestat_get": "__wasi_path_filestat_get",
+ "path_filestat_set_times": "__wasi_path_filestat_set_times",
+ "path_link": "__wasi_path_link",
+ "path_open": "__wasi_path_open",
+ "path_readlink": "__wasi_path_readlink",
+ "path_remove_directory": "__wasi_path_remove_directory",
+ "path_rename": "__wasi_path_rename",
+ "path_symlink": "__wasi_path_symlink",
+ "path_unlink_file": "__wasi_path_unlink_file",
+ "poll_oneoff": "__wasi_poll_oneoff",
+ "proc_exit": "__wasi_proc_exit",
+ "random_get": "__wasi_random_get",
+ "sched_yield": "__wasi_sched_yield"
+ }
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/build.rs b/third_party/rust/lucet-wasi-wasmsbx/build.rs
new file mode 100644
index 0000000000..068e214fae
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/build.rs
@@ -0,0 +1,114 @@
+#![allow(unused)]
+
+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("wasi-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.1");
+ path
+ }
+ }
+}
+
+// `src/wasi_host.rs` is automatically generated using clang and
+// wasi-libc headers. This requires these to be present, and installed
+// at specific paths, which is not something we can rely on outside
+// of our environment.
+// So, we follow what most other tools using `bindgen` do, and provide
+// a pre-generated version of the file, along with a way to update it.
+// This is what the `update-bindings` feature do. It requires the WASI SDK
+// to be either installed in `/opt/wasi-sdk`, or at a location defined by
+// a `WASI_SDK` environment variable, as well as `clang` headers either
+// being part of `WASI_SDK`, or found in a path defined by a
+// `CLANG_ROOT` environment variable.
+#[cfg(not(feature = "update-bindings"))]
+fn main() {}
+
+#[cfg(feature = "update-bindings")]
+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_.*");
+
+ let src_path = Path::new("src");
+ host_builder
+ .generate()
+ .expect("can generate host bindings")
+ .write_to_file(src_path.join("wasi_host.rs"))
+ .expect("can write host bindings");
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/examples/.gitignore b/third_party/rust/lucet-wasi-wasmsbx/examples/.gitignore
new file mode 100644
index 0000000000..c795b054e5
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/examples/.gitignore
@@ -0,0 +1 @@
+build \ No newline at end of file
diff --git a/third_party/rust/lucet-wasi-wasmsbx/examples/Makefile b/third_party/rust/lucet-wasi-wasmsbx/examples/Makefile
new file mode 100644
index 0000000000..bbca5518ab
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/examples/Makefile
@@ -0,0 +1,54 @@
+WASI_CC ?= /opt/wasi-sdk/bin/clang
+WASI_LD ?= /opt/wasi-sdk/bin/wasm-ld
+
+default: run-hello
+
+.PHONY: run-hello
+run-hello: build/hello.so
+ cargo run -p lucet-wasi -- ./build/hello.so
+
+.PHONY: run-hello-all
+run-hello-all: run-hello
+ cargo run -p lucet-wasi -- ./build/hello.so -- "makefile user"
+ GREETING="goodbye" cargo run -p lucet-wasi -- ./build/hello.so -- "makefile user"
+
+build/hello.so: build/hello.wasm ../bindings.json
+ cargo run -p lucetc -- $< --bindings ../bindings.json -o $@
+
+build/hello.wasm: hello.c
+ mkdir -p build
+ $(WASI_CC) $< -o $@
+
+build/hello.wat: build/hello.wasm
+ wasm2wat -f $< > $@
+
+.PHONY: run-pseudoquine
+run-pseudoquine: build/pseudoquine.so
+ cargo run -p lucet-wasi -- ./build/pseudoquine.so --dir "$(CURDIR):/examples"
+
+build/pseudoquine.so: build/pseudoquine.wasm ../bindings.json
+ cargo run -p lucetc -- $< --bindings ../bindings.json -o $@
+
+build/pseudoquine.wasm: pseudoquine.c
+ mkdir -p build
+ $(WASI_CC) $< -o $@
+
+build/pseudoquine.wat: build/pseudoquine.wasm
+ wasm2wat -f $< > $@
+
+.PHONY: run-kgt
+run-kgt: build/kgt.so
+ cargo run -p lucet-wasi -- ./build/kgt.so -- -l bnf -e rrutf8 < build/kgt/examples/expr.bnf
+
+build/kgt.so: build/kgt/build/bin/kgt ../bindings.json
+ cargo run -p lucetc -- $< --bindings ../bindings.json -o $@
+
+build/kgt/build/bin/kgt: build/kgt
+ NOSTRIP=1 CC=$(WASI_CC) LD=$(WASI_LD) pmake -C build/kgt -r all
+
+build/kgt:
+ git clone --recursive https://github.com/katef/kgt.git build/kgt
+
+.PHONY: clean
+clean:
+ @rm -rf build
diff --git a/third_party/rust/lucet-wasi-wasmsbx/examples/README.md b/third_party/rust/lucet-wasi-wasmsbx/examples/README.md
new file mode 100644
index 0000000000..e4b958203d
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/examples/README.md
@@ -0,0 +1,69 @@
+# WASI Examples
+
+These are some examples showing how to build and run WASI programs with the Lucet runtime. By
+default, the Makefile in this directory builds and runs a Hello World program, but see below for
+other examples.
+
+By default, these examples look for the WASI SDK to be installed in `/opt/wasi-sdk`, which is
+present in the Lucet `devenv` environment. If you want to use your own SDK, you can override the
+environment variables `WASI_CC` and `WASI_LD` with paths to your own `clang` and `wasm-ld`.
+
+## Hello World
+
+In addition to the standard Hello World behavior, this program also shows the use of command-line
+arguments and environment variables:
+
+```
+cargo run -p lucet-wasi -- ./build/hello.so
+ Compiling lucet-wasi v0.1.0 (/lucet/lucet-wasi)
+ Finished dev [unoptimized + debuginfo] target(s) in 1.91s
+ Running `/lucet/target/debug/lucet-wasi ./build/hello.so`
+hello, wasi!
+```
+
+```
+cargo run -p lucet-wasi -- ./build/hello.so -- "readme reader"
+ Finished dev [unoptimized + debuginfo] target(s) in 0.10s
+ Running `/lucet/target/debug/lucet-wasi ./build/hello.so -- 'readme reader'`
+hello, readme reader!
+```
+
+```
+GREETING="goodbye" cargo run -p lucet-wasi -- ./build/hello.so -- "readme reader"
+ Finished dev [unoptimized + debuginfo] target(s) in 0.11s
+ Running `/lucet/target/debug/lucet-wasi ./build/hello.so -- 'readme reader'`
+goodbye, readme reader!
+```
+
+Use the `make run-hello` or `make run-hello-all` targets to run these variations.
+
+## KGT
+
+This example shows that a realistically-sized program, using standard IO and command-line arguments,
+can be compiled against WASI with no modifications to its source. In addition to the WASI SDK
+requirements mentioned above, the `kgt` example requires `pmake` to be installed:
+
+```
+# make run-kgt
+cargo run -p lucet-wasi -- ./build/kgt.so -- -l bnf -e rrutf8 < build/kgt/examples/expr.bnf
+ Finished dev [unoptimized + debuginfo] target(s) in 0.12s
+ Running `/lucet/target/debug/lucet-wasi ./build/kgt.so -- -l bnf -e rrutf8`
+expr:
+ │├──╮── term ── "+" ── expr ──╭──┤│
+ │ │
+ ╰───────── term ──────────╯
+
+term:
+ │├──╮── factor ── "*" ── term ──╭──┤│
+ │ │
+ ╰───────── factor ──────────╯
+
+factor:
+ │├──╮── "(" ── expr ── ")" ──╭──┤│
+ │ │
+ ╰──────── const ─────────╯
+
+const:
+ │├── integer ──┤│
+
+```
diff --git a/third_party/rust/lucet-wasi-wasmsbx/examples/hello.c b/third_party/rust/lucet-wasi-wasmsbx/examples/hello.c
new file mode 100644
index 0000000000..4b5ff49ec9
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/examples/hello.c
@@ -0,0 +1,16 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+int main(int argc, char **argv)
+{
+ char *greeting = getenv("GREETING");
+ if (greeting == NULL) {
+ greeting = "hello";
+ }
+
+ if (argc < 2) {
+ printf("%s, wasi!\n", greeting);
+ } else {
+ printf("%s, %s!\n", greeting, argv[1]);
+ }
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/examples/pseudoquine.c b/third_party/rust/lucet-wasi-wasmsbx/examples/pseudoquine.c
new file mode 100644
index 0000000000..9111caf25d
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/examples/pseudoquine.c
@@ -0,0 +1,18 @@
+#include <stdio.h>
+#include <stdlib.h>
+
+int main()
+{
+ FILE *self = fopen("/examples/pseudoquine.c", "r");
+ if (self == NULL) {
+ return 1;
+ }
+
+ char c = fgetc(self);
+ while (c != EOF) {
+ if (fputc(c, stdout) == EOF) {
+ return 1;
+ }
+ c = fgetc(self);
+ }
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/include/lucet_wasi.h b/third_party/rust/lucet-wasi-wasmsbx/include/lucet_wasi.h
new file mode 100644
index 0000000000..b0c5d6edc0
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/include/lucet_wasi.h
@@ -0,0 +1,23 @@
+#ifndef LUCET_WASI_H
+#define LUCET_WASI_H
+
+#include "lucet.h"
+
+struct lucet_wasi_ctx;
+
+struct lucet_wasi_ctx *lucet_wasi_ctx_create(void);
+
+enum lucet_error lucet_wasi_ctx_args(struct lucet_wasi_ctx *wasi_ctx, size_t argc, char **argv);
+
+enum lucet_error lucet_wasi_ctx_inherit_env(struct lucet_wasi_ctx *wasi_ctx);
+
+enum lucet_error lucet_wasi_ctx_inherit_stdio(struct lucet_wasi_ctx *wasi_ctx);
+
+void lucet_wasi_ctx_destroy(struct lucet_wasi_ctx *wasi_ctx);
+
+enum lucet_error lucet_region_new_instance_with_wasi_ctx(const struct lucet_region * region,
+ const struct lucet_dl_module *module,
+ struct lucet_wasi_ctx * wasi_ctx,
+ struct lucet_instance ** inst_out);
+
+#endif /* LUCET_WASI_H */
diff --git a/third_party/rust/lucet-wasi-wasmsbx/src/bindings.rs b/third_party/rust/lucet-wasi-wasmsbx/src/bindings.rs
new file mode 100644
index 0000000000..0d454a1f04
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/src/bindings.rs
@@ -0,0 +1,11 @@
+use lucet_module::bindings::Bindings;
+
+pub fn bindings() -> Bindings {
+ Bindings::from_str(include_str!("../bindings.json")).expect("lucet-wasi bindings.json is valid")
+}
+
+#[cfg(test)]
+#[test]
+fn test_bindings_parses() {
+ let _ = bindings();
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/src/c_api.rs b/third_party/rust/lucet-wasi-wasmsbx/src/c_api.rs
new file mode 100644
index 0000000000..be8dc94169
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/src/c_api.rs
@@ -0,0 +1,98 @@
+use crate::ctx::WasiCtxBuilder;
+use lucet_runtime::{DlModule, Module, Region};
+use lucet_runtime_internals::c_api::{lucet_dl_module, lucet_error, lucet_instance, lucet_region};
+use lucet_runtime_internals::instance::instance_handle_to_raw;
+use lucet_runtime_internals::{assert_nonnull, with_ffi_arcs};
+use std::ffi::CStr;
+use std::sync::Arc;
+
+#[repr(C)]
+pub struct lucet_wasi_ctx {
+ _unused: [u8; 0],
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn lucet_wasi_ctx_create() -> *mut lucet_wasi_ctx {
+ let b = WasiCtxBuilder::new();
+ Box::into_raw(Box::new(b)) as _
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn lucet_wasi_ctx_args(
+ wasi_ctx: *mut lucet_wasi_ctx,
+ argc: usize,
+ argv: *const *const libc::c_char,
+) -> lucet_error {
+ assert_nonnull!(wasi_ctx);
+ let mut b = Box::from_raw(wasi_ctx as *mut WasiCtxBuilder);
+ let args_raw = std::slice::from_raw_parts(argv, argc);
+ // TODO: error handling
+ let args = args_raw
+ .into_iter()
+ .map(|arg| CStr::from_ptr(*arg))
+ .collect::<Vec<&CStr>>();
+ *b = b.c_args(&args);
+ Box::into_raw(b);
+ lucet_error::Ok
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn lucet_wasi_ctx_inherit_env(wasi_ctx: *mut lucet_wasi_ctx) -> lucet_error {
+ assert_nonnull!(wasi_ctx);
+ let mut b = Box::from_raw(wasi_ctx as *mut WasiCtxBuilder);
+ *b = b.inherit_env();
+ Box::into_raw(b);
+ lucet_error::Ok
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn lucet_wasi_ctx_inherit_stdio(
+ wasi_ctx: *mut lucet_wasi_ctx,
+) -> lucet_error {
+ assert_nonnull!(wasi_ctx);
+ let mut b = Box::from_raw(wasi_ctx as *mut WasiCtxBuilder);
+ *b = b.inherit_stdio();
+ Box::into_raw(b);
+ lucet_error::Ok
+}
+
+#[no_mangle]
+pub unsafe extern "C" fn lucet_wasi_ctx_destroy(wasi_ctx: *mut lucet_wasi_ctx) {
+ Box::from_raw(wasi_ctx as *mut WasiCtxBuilder);
+}
+
+/// Create a Lucet instance with the given WASI context.
+///
+/// After this call, the `wasi_ctx` pointer is no longer valid.
+#[no_mangle]
+pub unsafe extern "C" fn lucet_region_new_instance_with_wasi_ctx(
+ region: *const lucet_region,
+ module: *const lucet_dl_module,
+ wasi_ctx: *mut lucet_wasi_ctx,
+ inst_out: *mut *mut lucet_instance,
+) -> lucet_error {
+ assert_nonnull!(wasi_ctx);
+ assert_nonnull!(inst_out);
+ with_ffi_arcs!([region: dyn Region, module: DlModule], {
+ let wasi_ctx = *Box::from_raw(wasi_ctx as *mut WasiCtxBuilder);
+ region
+ .new_instance_builder(module.clone() as Arc<dyn Module>)
+ .with_embed_ctx(wasi_ctx.build())
+ .build()
+ .map(|i| {
+ inst_out.write(instance_handle_to_raw(i) as _);
+ lucet_error::Ok
+ })
+ .unwrap_or_else(|e| e.into())
+ })
+}
+
+/// Call this if you're having trouble with `__wasi_*` symbols not being exported.
+///
+/// This is pretty hackish; we will hopefully be able to avoid this altogether once [this
+/// issue](https://github.com/rust-lang/rust/issues/58037) is addressed.
+#[no_mangle]
+#[doc(hidden)]
+pub extern "C" fn lucet_wasi_internal_ensure_linked() {
+ crate::hostcalls::ensure_linked();
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/src/ctx.rs b/third_party/rust/lucet-wasi-wasmsbx/src/ctx.rs
new file mode 100644
index 0000000000..49e96145b5
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/src/ctx.rs
@@ -0,0 +1,260 @@
+use crate::fdentry::FdEntry;
+use crate::host;
+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 struct WasiCtxBuilder {
+ fds: HashMap<host::__wasi_fd_t, FdEntry>,
+ preopens: HashMap<PathBuf, File>,
+ args: Vec<CString>,
+ env: HashMap<CString, CString>,
+}
+
+lazy_static! {
+ static ref DEV_NULL_FILE: File = dev_null();
+}
+
+impl WasiCtxBuilder {
+ /// Builder for a new `WasiCtx`.
+ pub fn new() -> Self {
+ WasiCtxBuilder {
+ fds: HashMap::new(),
+ preopens: HashMap::new(),
+ args: vec![],
+ env: HashMap::new(),
+ }
+ }
+
+ 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_stdio_no_syscall(self) -> Self {
+ self.fd_dup_for_io_desc(0, &stdin(), false /* writeable */)
+ .fd_dup_for_io_desc(1, &stdout(), true /* writeable */)
+ .fd_dup_for_io_desc(2, &stderr(), true /* writeable */)
+ }
+
+ 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()) }
+ }
+
+ pub fn fd_dup_for_io_desc<F: AsRawFd>(self, wasm_fd: host::__wasi_fd_t, fd: &F, writable : bool) -> Self {
+ // safe because we're getting a valid RawFd from the F directly
+ unsafe { self.raw_fd_for_io_desc(wasm_fd, dup(fd.as_raw_fd()).unwrap(), writable) }
+ }
+
+ /// 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
+ }
+
+ pub unsafe fn raw_fd_for_io_desc(mut self, wasm_fd: host::__wasi_fd_t, fd: RawFd, writable : bool) -> Self {
+ self.fds.insert(wasm_fd, FdEntry::from_raw_fd_for_io_desc(fd, writable));
+ 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")
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/src/fdentry.rs b/third_party/rust/lucet-wasi-wasmsbx/src/fdentry.rs
new file mode 100644
index 0000000000..7c65a64705
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/src/fdentry.rs
@@ -0,0 +1,169 @@
+use crate::host;
+use std::fs::File;
+use std::os::unix::prelude::{FileTypeExt, FromRawFd, IntoRawFd, RawFd};
+use std::path::PathBuf;
+
+#[derive(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()) }
+ }
+ pub unsafe fn from_raw_fd_for_io_desc(rawfd: RawFd, writable : bool) -> FdEntry {
+ let (ty, mut rights_base, rights_inheriting) =
+ (
+ host::__WASI_FILETYPE_CHARACTER_DEVICE,
+ host::RIGHTS_TTY_BASE,
+ host::RIGHTS_TTY_BASE,
+ );
+
+ if !writable {
+ rights_base &= !host::__WASI_RIGHT_FD_WRITE as host::__wasi_rights_t;
+ } else {
+ 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,
+ }
+ }
+
+}
+
+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(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));
+ }
+ }
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/src/host.rs b/third_party/rust/lucet-wasi-wasmsbx/src/host.rs
new file mode 100644
index 0000000000..e1a6027d0c
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/src/host.rs
@@ -0,0 +1,346 @@
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+
+include!("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 unsafe fn iovec_to_nix<'a>(iovec: &'a __wasi_iovec_t) -> nix::sys::uio::IoVec<&'a [u8]> {
+ let slice = std::slice::from_raw_parts(iovec.buf as *const u8, iovec.buf_len);
+ nix::sys::uio::IoVec::from_slice(slice)
+}
+
+pub unsafe fn iovec_to_nix_mut<'a>(
+ iovec: &'a mut __wasi_iovec_t,
+) -> nix::sys::uio::IoVec<&'a mut [u8]> {
+ let slice = std::slice::from_raw_parts_mut(iovec.buf as *mut u8, iovec.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 * 1_000_000_000,
+ st_ctim: filestat.st_ctime as __wasi_timestamp_t * 1_000_000_000,
+ st_mtim: filestat.st_mtime as __wasi_timestamp_t * 1_000_000_000,
+ 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_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;
diff --git a/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/fs.rs b/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/fs.rs
new file mode 100644
index 0000000000..db1a0c5d2d
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/fs.rs
@@ -0,0 +1,1358 @@
+#![allow(non_camel_case_types)]
+#![allow(unused_unsafe)]
+
+use crate::ctx::WasiCtx;
+use crate::fdentry::{determine_type_rights, FdEntry};
+use crate::memory::*;
+use crate::{host, wasm32};
+
+use super::fs_helpers::*;
+use super::timers;
+use lucet_runtime::vmctx::Vmctx;
+
+use nix::libc::{self, c_long, c_void, off_t};
+use std::ffi::OsStr;
+use std::mem::MaybeUninit;
+use std::os::unix::prelude::{FromRawFd, OsStrExt};
+
+pub fn wasi_fd_close(vmctx: &mut Vmctx, fd: wasm32::__wasi_fd_t) -> wasm32::__wasi_errno_t {
+ let mut ctx = vmctx.get_embed_ctx_mut::<WasiCtx>();
+ let fd = dec_fd(fd);
+ if let Some(fdent) = ctx.fds.get(&fd) {
+ // can't close preopened files
+ if fdent.preopen_path.is_some() {
+ return wasm32::__WASI_ENOTSUP;
+ }
+ }
+ if let Some(mut fdent) = ctx.fds.remove(&fd) {
+ fdent.fd_object.needs_close = false;
+ match nix::unistd::close(fdent.fd_object.rawfd) {
+ Ok(_) => wasm32::__WASI_ESUCCESS,
+ Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()),
+ }
+ } else {
+ wasm32::__WASI_EBADF
+ }
+}
+
+pub fn wasi_fd_fdstat_get(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ fdstat_ptr: wasm32::uintptr_t, // *mut wasm32::__wasi_fdstat_t
+) -> wasm32::__wasi_errno_t {
+ let host_fd = dec_fd(fd);
+ let mut host_fdstat = match dec_fdstat_byref(vmctx, fdstat_ptr) {
+ Ok(host_fdstat) => host_fdstat,
+ Err(e) => return enc_errno(e),
+ };
+
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let errno = if let Some(fe) = ctx.fds.get(&host_fd) {
+ host_fdstat.fs_filetype = fe.fd_object.ty;
+ host_fdstat.fs_rights_base = fe.rights_base;
+ host_fdstat.fs_rights_inheriting = fe.rights_inheriting;
+ use nix::fcntl::{fcntl, OFlag, F_GETFL};
+ match fcntl(fe.fd_object.rawfd, F_GETFL).map(OFlag::from_bits_truncate) {
+ Ok(flags) => {
+ host_fdstat.fs_flags = host::fdflags_from_nix(flags);
+ wasm32::__WASI_ESUCCESS
+ }
+ Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()),
+ }
+ } else {
+ wasm32::__WASI_EBADF
+ };
+ enc_fdstat_byref(vmctx, fdstat_ptr, host_fdstat)
+ .expect("can write back into the pointer we read from");
+ errno
+}
+
+pub fn wasi_fd_fdstat_set_flags(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ fdflags: wasm32::__wasi_fdflags_t,
+) -> wasm32::__wasi_errno_t {
+ let host_fd = dec_fd(fd);
+ let host_fdflags = dec_fdflags(fdflags);
+ let nix_flags = host::nix_from_fdflags(host_fdflags);
+
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ if let Some(fe) = ctx.fds.get(&host_fd) {
+ match nix::fcntl::fcntl(fe.fd_object.rawfd, nix::fcntl::F_SETFL(nix_flags)) {
+ Ok(_) => wasm32::__WASI_ESUCCESS,
+ Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()),
+ }
+ } else {
+ wasm32::__WASI_EBADF
+ }
+}
+
+pub fn wasi_fd_tell(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ offset: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let fd = dec_fd(fd);
+
+ let host_offset = {
+ use nix::unistd::{lseek, Whence};
+
+ let rights = host::__WASI_RIGHT_FD_TELL;
+ match ctx.get_fd_entry(fd, rights.into(), 0) {
+ Ok(fe) => match lseek(fe.fd_object.rawfd, 0, Whence::SeekCur) {
+ Ok(newoffset) => newoffset,
+ Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()),
+ },
+ Err(e) => return enc_errno(e),
+ }
+ };
+ enc_filesize_byref(vmctx, offset, host_offset as u64)
+ .map(|_| wasm32::__WASI_ESUCCESS)
+ .unwrap_or_else(|e| e)
+}
+
+pub fn wasi_fd_seek(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ offset: wasm32::__wasi_filedelta_t,
+ whence: wasm32::__wasi_whence_t,
+ newoffset: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let fd = dec_fd(fd);
+ let offset = dec_filedelta(offset);
+ let whence = dec_whence(whence);
+
+ let host_newoffset = {
+ use nix::unistd::{lseek, Whence};
+ let nwhence = match u32::from(whence) {
+ host::__WASI_WHENCE_CUR => Whence::SeekCur,
+ host::__WASI_WHENCE_END => Whence::SeekEnd,
+ host::__WASI_WHENCE_SET => Whence::SeekSet,
+ _ => return wasm32::__WASI_EINVAL,
+ };
+
+ let rights = if offset == 0 && whence as u32 == host::__WASI_WHENCE_CUR {
+ host::__WASI_RIGHT_FD_TELL
+ } else {
+ host::__WASI_RIGHT_FD_SEEK | host::__WASI_RIGHT_FD_TELL
+ };
+ match ctx.get_fd_entry(fd, rights.into(), 0) {
+ Ok(fe) => match lseek(fe.fd_object.rawfd, offset, nwhence) {
+ Ok(newoffset) => newoffset,
+ Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()),
+ },
+ Err(e) => return enc_errno(e),
+ }
+ };
+ enc_filesize_byref(vmctx, newoffset, host_newoffset as u64)
+ .map(|_| wasm32::__WASI_ESUCCESS)
+ .unwrap_or_else(|e| e)
+}
+
+pub fn wasi_fd_prestat_get(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ prestat_ptr: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let fd = dec_fd(fd);
+
+ let rights = host::__WASI_RIGHT_PATH_OPEN;
+ match ctx.get_fd_entry(fd, rights.into(), 0) {
+ Ok(fe) => {
+ if let Some(po_path) = &fe.preopen_path {
+ if fe.fd_object.ty != host::__WASI_FILETYPE_DIRECTORY as host::__wasi_filetype_t {
+ return wasm32::__WASI_ENOTDIR;
+ }
+ enc_prestat_byref(
+ vmctx,
+ prestat_ptr,
+ host::__wasi_prestat_t {
+ pr_type: host::__WASI_PREOPENTYPE_DIR as host::__wasi_preopentype_t,
+ u: host::__wasi_prestat_t___wasi_prestat_u {
+ dir: host::__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t {
+ pr_name_len: po_path.as_os_str().as_bytes().len(),
+ },
+ },
+ },
+ )
+ .map(|_| wasm32::__WASI_ESUCCESS)
+ .unwrap_or_else(|e| e)
+ } else {
+ wasm32::__WASI_ENOTSUP
+ }
+ }
+ Err(e) => enc_errno(e),
+ }
+}
+
+pub fn wasi_fd_prestat_dir_name(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+) -> wasm32::__wasi_errno_t {
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let fd = dec_fd(fd);
+ let rights = host::__WASI_RIGHT_PATH_OPEN;
+ match ctx.get_fd_entry(fd, rights.into(), 0) {
+ Ok(fe) => {
+ if let Some(po_path) = &fe.preopen_path {
+ if fe.fd_object.ty != host::__WASI_FILETYPE_DIRECTORY as host::__wasi_filetype_t {
+ return wasm32::__WASI_ENOTDIR;
+ }
+ let path_bytes = po_path.as_os_str().as_bytes();
+ if path_bytes.len() > dec_usize(path_len) {
+ return wasm32::__WASI_ENAMETOOLONG;
+ }
+ enc_slice_of(vmctx, path_bytes, path_ptr)
+ .map(|_| wasm32::__WASI_ESUCCESS)
+ .unwrap_or_else(|e| e)
+ } else {
+ wasm32::__WASI_ENOTSUP
+ }
+ }
+ Err(e) => enc_errno(e),
+ }
+}
+
+pub fn wasi_fd_read(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ iovs_ptr: wasm32::uintptr_t,
+ iovs_len: wasm32::size_t,
+ nread: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::sys::uio::{readv, IoVec};
+
+ let fd = dec_fd(fd);
+ let mut iovs = match dec_iovec_slice(vmctx, iovs_ptr, iovs_len) {
+ Ok(iovs) => iovs,
+ Err(e) => return enc_errno(e),
+ };
+
+ let mut ctx = vmctx.get_embed_ctx_mut::<WasiCtx>();
+ let rights = host::__WASI_RIGHT_FD_READ;
+ let fe = match ctx.get_fd_entry(fd, rights.into(), 0) {
+ Ok(fe) => fe,
+ Err(e) => return enc_errno(e),
+ };
+
+ let mut iovs: Vec<IoVec<&mut [u8]>> = iovs
+ .iter_mut()
+ .map(|iov| unsafe { host::iovec_to_nix_mut(iov) })
+ .collect();
+
+ let host_nread = match readv(fe.fd_object.rawfd, &mut iovs) {
+ Ok(len) => len,
+ Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()),
+ };
+
+ if host_nread == 0 {
+ // we hit eof, so remove the fdentry from the context
+ let mut fe = ctx.fds.remove(&fd).expect("file entry is still there");
+ fe.fd_object.needs_close = false;
+ }
+ enc_usize_byref(vmctx, nread, host_nread)
+ .map(|_| wasm32::__WASI_ESUCCESS)
+ .unwrap_or_else(|e| e)
+}
+
+pub fn wasi_fd_write(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ iovs_ptr: wasm32::uintptr_t,
+ iovs_len: wasm32::size_t,
+ nwritten: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::sys::uio::{writev, IoVec};
+
+ let fd = dec_fd(fd);
+ let iovs = match dec_ciovec_slice(vmctx, iovs_ptr, iovs_len) {
+ Ok(iovs) => iovs,
+ Err(e) => return enc_errno(e),
+ };
+
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let rights = host::__WASI_RIGHT_FD_WRITE;
+ let fe = match ctx.get_fd_entry(fd, rights.into(), 0) {
+ Ok(fe) => fe,
+ Err(e) => return enc_errno(e),
+ };
+
+ let iovs: Vec<IoVec<&[u8]>> = iovs
+ .iter()
+ .map(|iov| unsafe { host::ciovec_to_nix(iov) })
+ .collect();
+
+ let host_nwritten = match writev(fe.fd_object.rawfd, &iovs) {
+ Ok(len) => len,
+ Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()),
+ };
+ enc_usize_byref(vmctx, nwritten, host_nwritten)
+ .map(|_| wasm32::__WASI_ESUCCESS)
+ .unwrap_or_else(|e| e)
+}
+
+pub fn wasi_path_open(
+ vmctx: &mut Vmctx,
+ dirfd: wasm32::__wasi_fd_t,
+ dirflags: wasm32::__wasi_lookupflags_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+ oflags: wasm32::__wasi_oflags_t,
+ fs_rights_base: wasm32::__wasi_rights_t,
+ fs_rights_inheriting: wasm32::__wasi_rights_t,
+ fs_flags: wasm32::__wasi_fdflags_t,
+ fd_out_ptr: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::errno::Errno;
+ use nix::fcntl::{openat, AtFlags, OFlag};
+ use nix::sys::stat::{fstatat, Mode, SFlag};
+
+ let dirfd = dec_fd(dirfd);
+ let dirflags = dec_lookupflags(dirflags);
+ let oflags = dec_oflags(oflags);
+ let fs_rights_base = dec_rights(fs_rights_base);
+ let fs_rights_inheriting = dec_rights(fs_rights_inheriting);
+ let fs_flags = dec_fdflags(fs_flags);
+
+ // which open mode do we need?
+ let read = fs_rights_base
+ & ((host::__WASI_RIGHT_FD_READ | host::__WASI_RIGHT_FD_READDIR) as host::__wasi_rights_t)
+ != 0;
+ let write = fs_rights_base
+ & ((host::__WASI_RIGHT_FD_DATASYNC
+ | host::__WASI_RIGHT_FD_WRITE
+ | host::__WASI_RIGHT_FD_ALLOCATE
+ | host::__WASI_RIGHT_FD_FILESTAT_SET_SIZE) as host::__wasi_rights_t)
+ != 0;
+
+ let mut nix_all_oflags = if read && write {
+ OFlag::O_RDWR
+ } else if read {
+ OFlag::O_RDONLY
+ } else {
+ OFlag::O_WRONLY
+ };
+
+ // on non-Capsicum systems, we always want nofollow
+ nix_all_oflags.insert(OFlag::O_NOFOLLOW);
+
+ // which rights are needed on the dirfd?
+ let mut needed_base = host::__WASI_RIGHT_PATH_OPEN as host::__wasi_rights_t;
+ let mut needed_inheriting = fs_rights_base | fs_rights_inheriting;
+
+ // convert open flags
+ let nix_oflags = host::nix_from_oflags(oflags);
+ nix_all_oflags.insert(nix_oflags);
+ if nix_all_oflags.contains(OFlag::O_CREAT) {
+ needed_base |= host::__WASI_RIGHT_PATH_CREATE_FILE as host::__wasi_rights_t;
+ }
+ if nix_all_oflags.contains(OFlag::O_TRUNC) {
+ needed_base |= host::__WASI_RIGHT_PATH_FILESTAT_SET_SIZE as host::__wasi_rights_t;
+ }
+
+ // convert file descriptor flags
+ nix_all_oflags.insert(host::nix_from_fdflags(fs_flags));
+ if nix_all_oflags.contains(OFlag::O_DSYNC) {
+ needed_inheriting |= host::__WASI_RIGHT_FD_DATASYNC as host::__wasi_rights_t;
+ }
+ if nix_all_oflags.intersects(O_RSYNC | OFlag::O_SYNC) {
+ needed_inheriting |= host::__WASI_RIGHT_FD_SYNC as host::__wasi_rights_t;
+ }
+ if nix_all_oflags.contains(OFlag::O_DIRECTORY) {
+ nix_all_oflags.remove(OFlag::O_RDWR);
+ nix_all_oflags.remove(OFlag::O_WRONLY);
+ nix_all_oflags.insert(OFlag::O_RDONLY);
+ }
+ let path = match dec_slice_of::<u8>(vmctx, path_ptr, path_len) {
+ Ok(path_bytes) => OsStr::from_bytes(path_bytes),
+ Err(e) => return enc_errno(e),
+ };
+
+ let (dir, path) = match path_get(
+ &vmctx,
+ dirfd,
+ dirflags,
+ path,
+ needed_base,
+ needed_inheriting,
+ nix_oflags.contains(OFlag::O_CREAT),
+ ) {
+ Ok((dir, path)) => (dir, path),
+ Err(e) => return enc_errno(e),
+ };
+
+ // Call openat. Use mode 0o666 so that we follow whatever the user's
+ // umask is, but don't set the executable flag, because it isn't yet
+ // meaningful for WASI programs to create executable files.
+ let new_fd = match openat(
+ dir,
+ path.as_os_str(),
+ nix_all_oflags,
+ Mode::from_bits_truncate(0o666),
+ ) {
+ Ok(fd) => fd,
+ Err(e) => {
+ match e.as_errno() {
+ // Linux returns ENXIO instead of EOPNOTSUPP when opening a socket
+ Some(Errno::ENXIO) => {
+ if let Ok(stat) = fstatat(dir, path.as_os_str(), AtFlags::AT_SYMLINK_NOFOLLOW) {
+ if SFlag::from_bits_truncate(stat.st_mode).contains(SFlag::S_IFSOCK) {
+ return wasm32::__WASI_ENOTSUP;
+ } else {
+ return wasm32::__WASI_ENXIO;
+ }
+ } else {
+ return wasm32::__WASI_ENXIO;
+ }
+ }
+ // Linux returns ENOTDIR instead of ELOOP when using O_NOFOLLOW|O_DIRECTORY
+ // on a symlink.
+ Some(Errno::ENOTDIR)
+ if !(nix_all_oflags & (OFlag::O_NOFOLLOW | OFlag::O_DIRECTORY)).is_empty() =>
+ {
+ if let Ok(stat) = fstatat(dir, path.as_os_str(), AtFlags::AT_SYMLINK_NOFOLLOW) {
+ if SFlag::from_bits_truncate(stat.st_mode).contains(SFlag::S_IFLNK) {
+ return wasm32::__WASI_ELOOP;
+ }
+ }
+ return wasm32::__WASI_ENOTDIR;
+ }
+ // FreeBSD returns EMLINK instead of ELOOP when using O_NOFOLLOW on
+ // a symlink.
+ Some(Errno::EMLINK) if !(nix_all_oflags & OFlag::O_NOFOLLOW).is_empty() => {
+ return wasm32::__WASI_ELOOP;
+ }
+ Some(e) => return wasm32::errno_from_nix(e),
+ None => return wasm32::__WASI_ENOSYS,
+ }
+ }
+ };
+
+ // Determine the type of the new file descriptor and which rights contradict with this type
+ let guest_fd = match unsafe { determine_type_rights(new_fd) } {
+ Err(e) => {
+ // if `close` fails, note it but do not override the underlying errno
+ nix::unistd::close(new_fd).unwrap_or_else(|e| {
+ dbg!(e);
+ });
+ if let Err(e) = enc_fd_byref(vmctx, fd_out_ptr, wasm32::__wasi_fd_t::max_value()) {
+ return enc_errno(e);
+ }
+ return enc_errno(e);
+ }
+ Ok((_ty, max_base, max_inheriting)) => {
+ let mut fe = unsafe { FdEntry::from_raw_fd(new_fd) };
+ fe.rights_base &= max_base;
+ fe.rights_inheriting &= max_inheriting;
+ match vmctx.get_embed_ctx_mut::<WasiCtx>().insert_fd_entry(fe) {
+ Ok(fd) => fd,
+ Err(e) => return enc_errno(e),
+ }
+ }
+ };
+ enc_fd_byref(vmctx, fd_out_ptr, guest_fd)
+ .map(|_| wasm32::__WASI_ESUCCESS)
+ .unwrap_or_else(|e| e)
+}
+
+pub fn wasi_fd_filestat_get(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ filestat_ptr: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::sys::stat::fstat;
+
+ let host_fd = dec_fd(fd);
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+
+ let rights = host::__WASI_RIGHT_FD_FILESTAT_GET;
+ match ctx.get_fd_entry(host_fd, rights.into(), 0) {
+ Ok(fe) => match fstat(fe.fd_object.rawfd) {
+ Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()),
+ Ok(filestat) => {
+ let host_filestat = host::filestat_from_nix(filestat);
+ enc_filestat_byref(vmctx, filestat_ptr, host_filestat)
+ .expect("can write into the pointer");
+ }
+ },
+ Err(e) => return enc_errno(e),
+ }
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_path_filestat_get(
+ vmctx: &mut Vmctx,
+ dirfd: wasm32::__wasi_fd_t,
+ dirflags: wasm32::__wasi_lookupflags_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+ filestat_ptr: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::fcntl::AtFlags;
+ use nix::sys::stat::fstatat;
+
+ let dirfd = dec_fd(dirfd);
+ let dirflags = dec_lookupflags(dirflags);
+ let path = match dec_slice_of::<u8>(vmctx, path_ptr, path_len) {
+ Ok(path_bytes) => OsStr::from_bytes(path_bytes),
+ Err(e) => return enc_errno(e),
+ };
+ let rights = host::__WASI_RIGHT_PATH_FILESTAT_GET;
+ let (dir, path) = match path_get(&vmctx, dirfd, dirflags, path, rights.into(), 0, false) {
+ Ok((dir, path)) => (dir, path),
+ Err(e) => return enc_errno(e),
+ };
+ let atflags = match dirflags {
+ wasm32::__WASI_LOOKUP_SYMLINK_FOLLOW => AtFlags::empty(),
+ _ => AtFlags::AT_SYMLINK_NOFOLLOW,
+ };
+ match fstatat(dir, path.as_os_str(), atflags) {
+ Err(e) => wasm32::errno_from_nix(e.as_errno().unwrap()),
+ Ok(filestat) => {
+ let host_filestat = host::filestat_from_nix(filestat);
+ enc_filestat_byref(vmctx, filestat_ptr, host_filestat)
+ .expect("can write into the pointer");
+ wasm32::__WASI_ESUCCESS
+ }
+ }
+}
+
+pub fn wasi_path_create_directory(
+ vmctx: &mut Vmctx,
+ dirfd: wasm32::__wasi_fd_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::errno;
+ use nix::libc::mkdirat;
+
+ let dirfd = dec_fd(dirfd);
+ let path = match dec_slice_of::<u8>(vmctx, path_ptr, path_len) {
+ Ok(path_bytes) => OsStr::from_bytes(path_bytes),
+ Err(e) => return enc_errno(e),
+ };
+ let rights = host::__WASI_RIGHT_PATH_CREATE_DIRECTORY;
+ let (dir, path) = match path_get(&vmctx, dirfd, 0, path, rights.into(), 0, false) {
+ Ok((dir, path)) => (dir, path),
+ Err(e) => return enc_errno(e),
+ };
+ let path_cstr = match std::ffi::CString::new(path.as_os_str().as_bytes()) {
+ Ok(path_cstr) => path_cstr,
+ Err(_) => return wasm32::__WASI_EINVAL,
+ };
+ // nix doesn't expose mkdirat() yet
+ match unsafe { mkdirat(dir, path_cstr.as_ptr(), 0o777) } {
+ 0 => wasm32::__WASI_ESUCCESS,
+ _ => wasm32::errno_from_nix(errno::Errno::last()),
+ }
+}
+
+pub fn wasi_path_unlink_file(
+ vmctx: &mut Vmctx,
+ dirfd: wasm32::__wasi_fd_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::errno;
+ use nix::libc::unlinkat;
+
+ let dirfd = dec_fd(dirfd);
+ let path = match dec_slice_of::<u8>(vmctx, path_ptr, path_len) {
+ Ok(path_bytes) => OsStr::from_bytes(path_bytes),
+ Err(e) => return enc_errno(e),
+ };
+ let rights = host::__WASI_RIGHT_PATH_UNLINK_FILE;
+ let (dir, path) = match path_get(&vmctx, dirfd, 0, path, rights.into(), 0, false) {
+ Ok((dir, path)) => (dir, path),
+ Err(e) => return enc_errno(e),
+ };
+ let path_cstr = match std::ffi::CString::new(path.as_os_str().as_bytes()) {
+ Ok(path_cstr) => path_cstr,
+ Err(_) => return wasm32::__WASI_EINVAL,
+ };
+ // nix doesn't expose unlinkat() yet
+ match unsafe { unlinkat(dir, path_cstr.as_ptr(), 0) } {
+ 0 => wasm32::__WASI_ESUCCESS,
+ _ => {
+ let mut e = errno::Errno::last();
+ // Non-Linux implementations may return EPERM when attempting to remove a
+ // directory without `REMOVEDIR`. For WASI, adjust this to `EISDIR`.
+ #[cfg(not(linux))]
+ {
+ use nix::fcntl::AtFlags;
+ use nix::sys::stat::{fstatat, SFlag};
+ if e == errno::Errno::EPERM {
+ if let Ok(stat) = fstatat(dir, path.as_os_str(), AtFlags::AT_SYMLINK_NOFOLLOW) {
+ if SFlag::from_bits_truncate(stat.st_mode).contains(SFlag::S_IFDIR) {
+ e = errno::Errno::EISDIR;
+ }
+ } else {
+ e = errno::Errno::last();
+ }
+ }
+ }
+ wasm32::errno_from_nix(e)
+ }
+ }
+}
+
+pub fn wasi_fd_allocate(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ offset: wasm32::__wasi_filesize_t,
+ len: wasm32::__wasi_filesize_t,
+) -> wasm32::__wasi_errno_t {
+ let host_fd = dec_fd(fd);
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let rights = host::__WASI_RIGHT_FD_ALLOCATE;
+ let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) {
+ Ok(fe) => fe,
+ Err(e) => return enc_errno(e),
+ };
+ let offset = dec_filesize(offset);
+ let len = dec_filesize(len);
+
+ #[cfg(target_os = "linux")]
+ {
+ let res =
+ unsafe { libc::posix_fallocate(fe.fd_object.rawfd, offset as off_t, len as off_t) };
+ if res != 0 {
+ return wasm32::errno_from_nix(nix::errno::Errno::last());
+ }
+ }
+
+ #[cfg(not(target_os = "linux"))]
+ {
+ use nix::sys::stat::fstat;
+ use nix::unistd::ftruncate;
+
+ match fstat(fe.fd_object.rawfd) {
+ Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()),
+ Ok(st) => {
+ let current_size = st.st_size as u64;
+ let wanted_size = match offset.checked_add(len) {
+ Some(wanted_size) => wanted_size,
+ None => return wasm32::__WASI_E2BIG,
+ };
+ if wanted_size > i64::max_value() as u64 {
+ return wasm32::__WASI_E2BIG;
+ }
+ if wanted_size > current_size {
+ if let Err(e) = ftruncate(fe.fd_object.rawfd, wanted_size as off_t) {
+ return wasm32::errno_from_nix(e.as_errno().unwrap());
+ }
+ }
+ }
+ }
+ }
+
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_fd_advise(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ offset: wasm32::__wasi_filesize_t,
+ len: wasm32::__wasi_filesize_t,
+ advice: wasm32::__wasi_advice_t,
+) -> wasm32::__wasi_errno_t {
+ let host_fd = dec_fd(fd);
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let rights = host::__WASI_RIGHT_FD_ADVISE;
+ let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) {
+ Ok(fe) => fe,
+ Err(e) => return enc_errno(e),
+ };
+ let advice = dec_advice(advice);
+
+ #[cfg(target_os = "linux")]
+ {
+ let host_advice = match advice as u32 {
+ host::__WASI_ADVICE_DONTNEED => libc::POSIX_FADV_DONTNEED,
+ host::__WASI_ADVICE_SEQUENTIAL => libc::POSIX_FADV_SEQUENTIAL,
+ host::__WASI_ADVICE_WILLNEED => libc::POSIX_FADV_DONTNEED,
+ host::__WASI_ADVICE_NOREUSE => libc::POSIX_FADV_NOREUSE,
+ host::__WASI_ADVICE_RANDOM => libc::POSIX_FADV_RANDOM,
+ host::__WASI_ADVICE_NORMAL => libc::POSIX_FADV_NORMAL,
+ _ => return wasm32::__WASI_EINVAL,
+ };
+ let offset = dec_filesize(offset);
+ let len = dec_filesize(len);
+ let res = unsafe {
+ libc::posix_fadvise(
+ fe.fd_object.rawfd,
+ offset as off_t,
+ len as off_t,
+ host_advice,
+ )
+ };
+ if res != 0 {
+ return wasm32::errno_from_nix(nix::errno::Errno::last());
+ }
+ }
+
+ #[cfg(not(target_os = "linux"))]
+ {
+ let _ = (fe, offset, len);
+ match advice as u32 {
+ host::__WASI_ADVICE_DONTNEED
+ | host::__WASI_ADVICE_SEQUENTIAL
+ | host::__WASI_ADVICE_WILLNEED
+ | host::__WASI_ADVICE_NOREUSE
+ | host::__WASI_ADVICE_RANDOM
+ | host::__WASI_ADVICE_NORMAL => {}
+ _ => return wasm32::__WASI_EINVAL,
+ }
+ }
+
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_fd_datasync(vmctx: &mut Vmctx, fd: wasm32::__wasi_fd_t) -> wasm32::__wasi_errno_t {
+ let host_fd = dec_fd(fd);
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let rights = host::__WASI_RIGHT_FD_DATASYNC;
+ let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) {
+ Ok(fe) => fe,
+ Err(e) => return enc_errno(e),
+ };
+ let res;
+
+ #[cfg(target_os = "linux")]
+ {
+ res = nix::unistd::fdatasync(fe.fd_object.rawfd);
+ }
+
+ #[cfg(not(target_os = "linux"))]
+ {
+ res = nix::unistd::fsync(fe.fd_object.rawfd);
+ }
+
+ if let Err(e) = res {
+ return wasm32::errno_from_nix(e.as_errno().unwrap());
+ }
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_fd_sync(vmctx: &mut Vmctx, fd: wasm32::__wasi_fd_t) -> wasm32::__wasi_errno_t {
+ let host_fd = dec_fd(fd);
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let rights = host::__WASI_RIGHT_FD_SYNC;
+ let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) {
+ Ok(fe) => fe,
+ Err(e) => return enc_errno(e),
+ };
+ let res = nix::unistd::fsync(fe.fd_object.rawfd);
+ if let Err(e) = res {
+ return wasm32::errno_from_nix(e.as_errno().unwrap());
+ }
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_fd_fdstat_set_rights(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ fs_rights_base: wasm32::__wasi_rights_t,
+ fs_rights_inheriting: wasm32::__wasi_rights_t,
+) -> wasm32::__wasi_errno_t {
+ let host_fd = dec_fd(fd);
+ let mut ctx = vmctx.get_embed_ctx_mut::<WasiCtx>();
+ let fe = match ctx.fds.get_mut(&host_fd) {
+ Some(fe) => fe,
+ None => return wasm32::__WASI_EBADF,
+ };
+ if fe.rights_base & fs_rights_base != fs_rights_base
+ || fe.rights_inheriting & fs_rights_inheriting != fs_rights_inheriting
+ {
+ return wasm32::__WASI_ENOTCAPABLE;
+ }
+ fe.rights_base = fs_rights_base;
+ fe.rights_inheriting = fs_rights_inheriting;
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_fd_filestat_set_size(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ st_size: wasm32::__wasi_filesize_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::unistd::ftruncate;
+
+ let host_fd = dec_fd(fd);
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let rights = host::__WASI_RIGHT_FD_FILESTAT_SET_SIZE;
+ let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) {
+ Ok(fe) => fe,
+ Err(e) => return enc_errno(e),
+ };
+ let st_size = dec_filesize(st_size);
+ if st_size > i64::max_value() as u64 {
+ return wasm32::__WASI_E2BIG;
+ }
+ if let Err(e) = ftruncate(fe.fd_object.rawfd, st_size as off_t) {
+ return wasm32::errno_from_nix(e.as_errno().unwrap());
+ }
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_fd_filestat_set_times(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ st_atim: wasm32::__wasi_timestamp_t,
+ st_mtim: wasm32::__wasi_timestamp_t,
+ fst_flags: wasm32::__wasi_fstflags_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::sys::time::{TimeSpec, TimeValLike};
+
+ let host_fd = dec_fd(fd);
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let rights = host::__WASI_RIGHT_FD_FILESTAT_SET_TIMES;
+ let fe = match ctx.get_fd_entry(host_fd, rights.into(), 0) {
+ Ok(fe) => fe,
+ Err(e) => return enc_errno(e),
+ };
+ let st_atim = dec_timestamp(st_atim);
+ let mut st_mtim = dec_timestamp(st_mtim);
+ let fst_flags = dec_fstflags(fst_flags);
+ if fst_flags & (host::__WASI_FILESTAT_SET_MTIM_NOW as host::__wasi_fstflags_t) != 0 {
+ let clock_id = libc::CLOCK_REALTIME;
+ let mut timespec = MaybeUninit::<libc::timespec>::uninit();
+ let res = unsafe { timers::clock_gettime_helper(clock_id, timespec.as_mut_ptr()) };
+ if res != 0 {
+ return wasm32::errno_from_nix(nix::errno::Errno::last());
+ }
+ let timespec = unsafe { timespec.assume_init() };
+ let time_ns = match (timespec.tv_sec as host::__wasi_timestamp_t)
+ .checked_mul(1_000_000_000)
+ .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as host::__wasi_timestamp_t))
+ {
+ Some(time_ns) => time_ns,
+ None => return wasm32::__WASI_EOVERFLOW,
+ };
+ st_mtim = time_ns;
+ }
+ let ts_atime = match fst_flags as u32 {
+ f if f & host::__WASI_FILESTAT_SET_ATIM_NOW != 0 => libc::timespec {
+ tv_sec: 0,
+ tv_nsec: utime_now(),
+ },
+ f if f & host::__WASI_FILESTAT_SET_ATIM != 0 => {
+ *TimeSpec::nanoseconds(st_atim as i64).as_ref()
+ }
+ _ => libc::timespec {
+ tv_sec: 0,
+ tv_nsec: utime_omit(),
+ },
+ };
+ let ts_mtime = *TimeSpec::nanoseconds(st_mtim as i64).as_ref();
+ let times = [ts_atime, ts_mtime];
+ let res = unsafe { timers::futimens_helper(fe.fd_object.rawfd, times.as_ptr()) };
+ if res != 0 {
+ return wasm32::errno_from_nix(nix::errno::Errno::last());
+ }
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_path_filestat_set_times(
+ vmctx: &mut Vmctx,
+ dirfd: wasm32::__wasi_fd_t,
+ dirflags: wasm32::__wasi_lookupflags_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+ st_atim: wasm32::__wasi_timestamp_t,
+ st_mtim: wasm32::__wasi_timestamp_t,
+ fst_flags: wasm32::__wasi_fstflags_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::sys::time::{TimeSpec, TimeValLike};
+
+ let dirfd = dec_fd(dirfd);
+ let dirflags = dec_lookupflags(dirflags);
+ let path = match dec_slice_of::<u8>(vmctx, path_ptr, path_len) {
+ Ok(path_bytes) => OsStr::from_bytes(path_bytes),
+ Err(e) => return enc_errno(e),
+ };
+ let rights = host::__WASI_RIGHT_PATH_FILESTAT_SET_TIMES;
+ let (dir, path) = match path_get(&vmctx, dirfd, dirflags, path, rights.into(), 0, false) {
+ Ok((dir, path)) => (dir, path),
+ Err(e) => return enc_errno(e),
+ };
+ let atflags = match dirflags {
+ wasm32::__WASI_LOOKUP_SYMLINK_FOLLOW => 0,
+ _ => libc::AT_SYMLINK_NOFOLLOW,
+ };
+ let st_atim = dec_timestamp(st_atim);
+ let mut st_mtim = dec_timestamp(st_mtim);
+ let fst_flags = dec_fstflags(fst_flags);
+ if fst_flags & (host::__WASI_FILESTAT_SET_MTIM_NOW as host::__wasi_fstflags_t) != 0 {
+ let clock_id = libc::CLOCK_REALTIME;
+ let mut timespec = MaybeUninit::<libc::timespec>::uninit();
+ let res = unsafe { timers::clock_gettime_helper(clock_id, timespec.as_mut_ptr()) };
+ if res != 0 {
+ return wasm32::errno_from_nix(nix::errno::Errno::last());
+ }
+ let timespec = unsafe { timespec.assume_init() };
+ let time_ns = match (timespec.tv_sec as host::__wasi_timestamp_t)
+ .checked_mul(1_000_000_000)
+ .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as host::__wasi_timestamp_t))
+ {
+ Some(time_ns) => time_ns,
+ None => return wasm32::__WASI_EOVERFLOW,
+ };
+ st_mtim = time_ns;
+ }
+ let ts_atime = match fst_flags as u32 {
+ f if f & host::__WASI_FILESTAT_SET_ATIM_NOW != 0 => libc::timespec {
+ tv_sec: 0,
+ tv_nsec: utime_now(),
+ },
+ f if f & host::__WASI_FILESTAT_SET_ATIM != 0 => {
+ *TimeSpec::nanoseconds(st_atim as i64).as_ref()
+ }
+ _ => libc::timespec {
+ tv_sec: 0,
+ tv_nsec: utime_omit(),
+ },
+ };
+ let ts_mtime = *TimeSpec::nanoseconds(st_mtim as i64).as_ref();
+ let times = [ts_atime, ts_mtime];
+ let path_cstr = match std::ffi::CString::new(path.as_os_str().as_bytes()) {
+ Ok(path_cstr) => path_cstr,
+ Err(_) => return wasm32::__WASI_EINVAL,
+ };
+ let res = unsafe { timers::utimensat_helper(dir, path_cstr.as_ptr(), times.as_ptr(), atflags) };
+ if res != 0 {
+ return wasm32::errno_from_nix(nix::errno::Errno::last());
+ }
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_fd_pread(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ iovs_ptr: wasm32::uintptr_t,
+ iovs_len: wasm32::size_t,
+ offset: wasm32::__wasi_filesize_t,
+ nread: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::sys::uio::pread;
+ use std::cmp;
+
+ let fd = dec_fd(fd);
+ let iovs = match dec_iovec_slice(vmctx, iovs_ptr, iovs_len) {
+ Ok(iovs) => iovs,
+ Err(e) => return enc_errno(e),
+ };
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let rights = host::__WASI_RIGHT_FD_READ;
+ let fe = match ctx.get_fd_entry(fd, rights.into(), 0) {
+ Ok(fe) => fe,
+ Err(e) => return enc_errno(e),
+ };
+ let offset = dec_filesize(offset);
+ if offset > i64::max_value() as u64 {
+ return wasm32::__WASI_EIO;
+ }
+ let buf_size = iovs.iter().map(|v| v.buf_len).sum();
+ let mut buf = vec![0; buf_size];
+ let host_nread = match pread(fe.fd_object.rawfd, &mut buf, offset as off_t) {
+ Ok(len) => len,
+ Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()),
+ };
+ let mut buf_offset = 0;
+ let mut left = host_nread;
+ for iov in &iovs {
+ if left == 0 {
+ break;
+ }
+ let vec_len = cmp::min(iov.buf_len, left);
+ unsafe { std::slice::from_raw_parts_mut(iov.buf as *mut u8, vec_len) }
+ .copy_from_slice(&buf[buf_offset..buf_offset + vec_len]);
+ buf_offset += vec_len;
+ left -= vec_len;
+ }
+ enc_usize_byref(vmctx, nread, host_nread)
+ .map(|_| wasm32::__WASI_ESUCCESS)
+ .unwrap_or_else(|e| e)
+}
+
+pub fn wasi_fd_pwrite(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ iovs_ptr: wasm32::uintptr_t,
+ iovs_len: wasm32::size_t,
+ offset: wasm32::__wasi_filesize_t,
+ nwritten: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::sys::uio::pwrite;
+
+ let fd = dec_fd(fd);
+ let iovs = match dec_iovec_slice(vmctx, iovs_ptr, iovs_len) {
+ Ok(iovs) => iovs,
+ Err(e) => return enc_errno(e),
+ };
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let rights = host::__WASI_RIGHT_FD_READ;
+ let fe = match ctx.get_fd_entry(fd, rights.into(), 0) {
+ Ok(fe) => fe,
+ Err(e) => return enc_errno(e),
+ };
+ let offset = dec_filesize(offset);
+ if offset > i64::max_value() as u64 {
+ return wasm32::__WASI_EIO;
+ }
+ let buf_size = iovs.iter().map(|v| v.buf_len).sum();
+ let mut buf = Vec::with_capacity(buf_size);
+ for iov in &iovs {
+ buf.extend_from_slice(unsafe {
+ std::slice::from_raw_parts(iov.buf as *const u8, iov.buf_len)
+ });
+ }
+ let host_nwritten = match pwrite(fe.fd_object.rawfd, &buf, offset as off_t) {
+ Ok(len) => len,
+ Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()),
+ };
+ enc_usize_byref(vmctx, nwritten, host_nwritten)
+ .map(|_| wasm32::__WASI_ESUCCESS)
+ .unwrap_or_else(|e| e)
+}
+
+pub fn wasi_fd_readdir(
+ vmctx: &mut Vmctx,
+ fd: wasm32::__wasi_fd_t,
+ buf: wasm32::uintptr_t,
+ buf_len: wasm32::size_t,
+ cookie: wasm32::__wasi_dircookie_t,
+ bufused: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ use libc::{dirent, fdopendir, readdir_r, seekdir};
+
+ match enc_usize_byref(vmctx, bufused, 0) {
+ Ok(_) => {}
+ Err(e) => return enc_errno(e),
+ };
+ let fd = dec_fd(fd);
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+ let rights = host::__WASI_RIGHT_FD_READDIR;
+ let fe = match ctx.get_fd_entry(fd, rights.into(), 0) {
+ Ok(fe) => fe,
+ Err(e) => return enc_errno(e),
+ };
+ let host_buf = match dec_slice_of::<u8>(vmctx, buf, buf_len) {
+ Ok(host_buf) => host_buf,
+ Err(e) => return enc_errno(e),
+ };
+ let host_buf_ptr = host_buf.as_ptr();
+ let host_buf_len = host_buf.len();
+ let dir = unsafe { fdopendir(fe.fd_object.rawfd) };
+ if dir.is_null() {
+ return wasm32::errno_from_nix(nix::errno::Errno::last());
+ }
+ let cookie = dec_dircookie(cookie);
+ if cookie != wasm32::__WASI_DIRCOOKIE_START {
+ unsafe { seekdir(dir, cookie as c_long) };
+ }
+ let mut entry_buf = MaybeUninit::<dirent>::uninit();
+ let mut left = host_buf_len;
+ let mut host_buf_offset: usize = 0;
+ while left > 0 {
+ let mut host_entry: *mut dirent = std::ptr::null_mut();
+ let res = unsafe { readdir_r(dir, entry_buf.as_mut_ptr(), &mut host_entry) };
+ if res == -1 {
+ return wasm32::errno_from_nix(nix::errno::Errno::last());
+ }
+ if host_entry.is_null() {
+ break;
+ }
+ unsafe { entry_buf.assume_init() };
+ let entry: wasm32::__wasi_dirent_t = match dirent_from_host(&unsafe { *host_entry }) {
+ Ok(entry) => entry,
+ Err(e) => return enc_errno(e),
+ };
+ let name_len = entry.d_namlen as usize;
+ let required_space = std::mem::size_of_val(&entry) + name_len;
+ if required_space > left {
+ break;
+ }
+ unsafe {
+ let ptr = host_buf_ptr.offset(host_buf_offset as isize) as *mut c_void
+ as *mut wasm32::__wasi_dirent_t;
+ *ptr = entry;
+ }
+ host_buf_offset += std::mem::size_of_val(&entry);
+ let name_ptr = unsafe { *host_entry }.d_name.as_ptr();
+ unsafe {
+ std::ptr::copy_nonoverlapping(
+ name_ptr as *const _,
+ host_buf_ptr.offset(host_buf_offset as isize) as *mut _,
+ name_len,
+ )
+ };
+ host_buf_offset += name_len;
+ left -= required_space;
+ }
+ let host_bufused = host_buf_len - left;
+ enc_usize_byref(vmctx, bufused, host_bufused)
+ .map(|_| wasm32::__WASI_ESUCCESS)
+ .unwrap_or_else(|e| e)
+}
+
+pub fn wasi_fd_renumber(
+ vmctx: &mut Vmctx,
+ from: wasm32::__wasi_fd_t,
+ to: wasm32::__wasi_fd_t,
+) -> wasm32::__wasi_errno_t {
+ let from = dec_fd(from);
+ let to = dec_fd(to);
+ let mut ctx = vmctx.get_embed_ctx_mut::<WasiCtx>();
+ let fe_from = match ctx.fds.get(&from) {
+ Some(fe_from) => fe_from,
+ None => return wasm32::__WASI_EBADF,
+ };
+ let fe_to = match ctx.fds.get(&to) {
+ Some(fe_to) => fe_to,
+ None => return wasm32::__WASI_EBADF,
+ };
+ if let Err(e) = nix::unistd::dup2(fe_from.fd_object.rawfd, fe_to.fd_object.rawfd) {
+ return wasm32::errno_from_nix(e.as_errno().unwrap());
+ }
+ let fe_from_rawfd = fe_from.fd_object.rawfd;
+ ctx.fds.remove(&(fe_from_rawfd as host::__wasi_fd_t));
+
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_path_link(
+ vmctx: &mut Vmctx,
+ old_dirfd: wasm32::__wasi_fd_t,
+ _old_flags: wasm32::__wasi_lookupflags_t,
+ old_path_ptr: wasm32::uintptr_t,
+ old_path_len: wasm32::size_t,
+ new_dirfd: wasm32::__wasi_fd_t,
+ new_path_ptr: wasm32::uintptr_t,
+ new_path_len: wasm32::size_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::libc::linkat;
+
+ let old_dirfd = dec_fd(old_dirfd);
+ let new_dirfd = dec_fd(new_dirfd);
+ let old_path = match dec_slice_of::<u8>(vmctx, old_path_ptr, old_path_len) {
+ Ok(old_path_bytes) => OsStr::from_bytes(old_path_bytes),
+ Err(e) => return enc_errno(e),
+ };
+ let new_path = match dec_slice_of::<u8>(vmctx, new_path_ptr, new_path_len) {
+ Ok(new_path_bytes) => OsStr::from_bytes(new_path_bytes),
+ Err(e) => return enc_errno(e),
+ };
+ let rights = host::__WASI_RIGHT_PATH_LINK_SOURCE;
+ let (old_dir, old_path) =
+ match path_get(&vmctx, old_dirfd, 0, old_path, rights.into(), 0, false) {
+ Ok((dir, path)) => (dir, path),
+ Err(e) => return enc_errno(e),
+ };
+ let rights = host::__WASI_RIGHT_PATH_LINK_TARGET;
+ let (new_dir, new_path) =
+ match path_get(&vmctx, new_dirfd, 0, new_path, rights.into(), 0, false) {
+ Ok((dir, path)) => (dir, path),
+ Err(e) => return enc_errno(e),
+ };
+ let old_path_cstr = match std::ffi::CString::new(old_path.as_bytes()) {
+ Ok(old_path_cstr) => old_path_cstr,
+ Err(_) => return wasm32::__WASI_EINVAL,
+ };
+ let new_path_cstr = match std::ffi::CString::new(new_path.as_bytes()) {
+ Ok(new_path_cstr) => new_path_cstr,
+ Err(_) => return wasm32::__WASI_EINVAL,
+ };
+
+ // Not setting AT_SYMLINK_FOLLOW fails on most filesystems
+ let atflags = libc::AT_SYMLINK_FOLLOW;
+ let res = unsafe {
+ linkat(
+ old_dir,
+ old_path_cstr.as_ptr(),
+ new_dir,
+ new_path_cstr.as_ptr(),
+ atflags,
+ )
+ };
+ if res != 0 {
+ return wasm32::errno_from_nix(nix::errno::Errno::last());
+ }
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_path_readlink(
+ vmctx: &mut Vmctx,
+ dirfd: wasm32::__wasi_fd_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+ buf_ptr: wasm32::uintptr_t,
+ buf_len: wasm32::size_t,
+ bufused: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::fcntl::readlinkat;
+ use std::cmp;
+
+ match enc_usize_byref(vmctx, bufused, 0) {
+ Ok(_) => {}
+ Err(e) => return enc_errno(e),
+ };
+ let dirfd = dec_fd(dirfd);
+ let path = match dec_slice_of::<u8>(vmctx, path_ptr, path_len) {
+ Ok(path_bytes) => OsStr::from_bytes(path_bytes),
+ Err(e) => return enc_errno(e),
+ };
+ let rights = host::__WASI_RIGHT_PATH_READLINK;
+ let (dir, path) = match path_get(&vmctx, dirfd, 0, path, rights.into(), 0, false) {
+ Ok((dir, path)) => (dir, path),
+ Err(e) => return enc_errno(e),
+ };
+ let dummy_buf = &mut [0u8];
+ let mut buf = if buf_len > 0 {
+ match dec_slice_of_mut::<u8>(vmctx, buf_ptr, buf_len) {
+ Ok(buf) => buf,
+ Err(e) => return enc_errno(e),
+ }
+ } else {
+ dummy_buf
+ };
+ let target_path = match readlinkat(dir, path.as_os_str(), &mut buf) {
+ Err(e) => return wasm32::errno_from_nix(e.as_errno().unwrap()),
+ Ok(target_path) => target_path,
+ };
+ let host_bufused = cmp::min(buf_len as usize, target_path.len());
+ match enc_usize_byref(vmctx, bufused, host_bufused) {
+ Ok(_) => {}
+ Err(e) => return enc_errno(e),
+ };
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_path_remove_directory(
+ vmctx: &mut Vmctx,
+ dirfd: wasm32::__wasi_fd_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::errno;
+ use nix::libc::{unlinkat, AT_REMOVEDIR};
+
+ let dirfd = dec_fd(dirfd);
+ let path = match dec_slice_of::<u8>(vmctx, path_ptr, path_len) {
+ Ok(path_bytes) => OsStr::from_bytes(path_bytes),
+ Err(e) => return enc_errno(e),
+ };
+ let rights = host::__WASI_RIGHT_PATH_REMOVE_DIRECTORY;
+ let (dir, path) = match path_get(&vmctx, dirfd, 0, path, rights.into(), 0, false) {
+ Ok((dir, path)) => (dir, path),
+ Err(e) => return enc_errno(e),
+ };
+ let path_cstr = match std::ffi::CString::new(path.as_os_str().as_bytes()) {
+ Ok(path_cstr) => path_cstr,
+ Err(_) => return wasm32::__WASI_EINVAL,
+ };
+ // nix doesn't expose unlinkat() yet
+ match unsafe { unlinkat(dir, path_cstr.as_ptr(), AT_REMOVEDIR) } {
+ 0 => wasm32::__WASI_ESUCCESS,
+ _ => wasm32::errno_from_nix(errno::Errno::last()),
+ }
+}
+
+pub fn wasi_path_rename(
+ vmctx: &mut Vmctx,
+ old_dirfd: wasm32::__wasi_fd_t,
+ old_path_ptr: wasm32::uintptr_t,
+ old_path_len: wasm32::size_t,
+ new_dirfd: wasm32::__wasi_fd_t,
+ new_path_ptr: wasm32::uintptr_t,
+ new_path_len: wasm32::size_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::libc::renameat;
+
+ let old_dirfd = dec_fd(old_dirfd);
+ let new_dirfd = dec_fd(new_dirfd);
+ let old_path = match dec_slice_of::<u8>(vmctx, old_path_ptr, old_path_len) {
+ Ok(old_path_bytes) => OsStr::from_bytes(old_path_bytes),
+ Err(e) => return enc_errno(e),
+ };
+ let new_path = match dec_slice_of::<u8>(vmctx, new_path_ptr, new_path_len) {
+ Ok(new_path_bytes) => OsStr::from_bytes(new_path_bytes),
+ Err(e) => return enc_errno(e),
+ };
+ let rights = host::__WASI_RIGHT_PATH_RENAME_SOURCE;
+ let (old_dir, old_path) =
+ match path_get(&vmctx, old_dirfd, 0, old_path, rights.into(), 0, false) {
+ Ok((dir, path)) => (dir, path),
+ Err(e) => return enc_errno(e),
+ };
+ let rights = host::__WASI_RIGHT_PATH_RENAME_TARGET;
+ let (new_dir, new_path) =
+ match path_get(&vmctx, new_dirfd, 0, new_path, rights.into(), 0, false) {
+ Ok((dir, path)) => (dir, path),
+ Err(e) => return enc_errno(e),
+ };
+ let old_path_cstr = match std::ffi::CString::new(old_path.as_bytes()) {
+ Ok(old_path_cstr) => old_path_cstr,
+ Err(_) => return wasm32::__WASI_EINVAL,
+ };
+ let new_path_cstr = match std::ffi::CString::new(new_path.as_bytes()) {
+ Ok(new_path_cstr) => new_path_cstr,
+ Err(_) => return wasm32::__WASI_EINVAL,
+ };
+ let res = unsafe {
+ renameat(
+ old_dir,
+ old_path_cstr.as_ptr(),
+ new_dir,
+ new_path_cstr.as_ptr(),
+ )
+ };
+ if res != 0 {
+ return wasm32::errno_from_nix(nix::errno::Errno::last());
+ }
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_path_symlink(
+ vmctx: &mut Vmctx,
+ old_path_ptr: wasm32::uintptr_t,
+ old_path_len: wasm32::size_t,
+ dirfd: wasm32::__wasi_fd_t,
+ new_path_ptr: wasm32::uintptr_t,
+ new_path_len: wasm32::size_t,
+) -> wasm32::__wasi_errno_t {
+ use nix::libc::symlinkat;
+
+ let dirfd = dec_fd(dirfd);
+ let old_path = match dec_slice_of::<u8>(vmctx, old_path_ptr, old_path_len) {
+ Ok(old_path_bytes) => OsStr::from_bytes(old_path_bytes),
+ Err(e) => return enc_errno(e),
+ };
+ let new_path = match dec_slice_of::<u8>(vmctx, new_path_ptr, new_path_len) {
+ Ok(new_path_bytes) => OsStr::from_bytes(new_path_bytes),
+ Err(e) => return enc_errno(e),
+ };
+ let rights = host::__WASI_RIGHT_PATH_SYMLINK;
+ let (dir, new_path) = match path_get(&vmctx, dirfd, 0, new_path, rights.into(), 0, false) {
+ Ok((dir, path)) => (dir, path),
+ Err(e) => return enc_errno(e),
+ };
+ let old_path_cstr = match std::ffi::CString::new(old_path.as_bytes()) {
+ Ok(old_path_cstr) => old_path_cstr,
+ Err(_) => return wasm32::__WASI_EINVAL,
+ };
+ let new_path_cstr = match std::ffi::CString::new(new_path.as_bytes()) {
+ Ok(new_path_cstr) => new_path_cstr,
+ Err(_) => return wasm32::__WASI_EINVAL,
+ };
+ let res = unsafe { symlinkat(old_path_cstr.as_ptr(), dir, new_path_cstr.as_ptr()) };
+ if res != 0 {
+ return wasm32::errno_from_nix(nix::errno::Errno::last());
+ }
+ wasm32::__WASI_ESUCCESS
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/fs_helpers.rs b/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/fs_helpers.rs
new file mode 100644
index 0000000000..a82924e481
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/fs_helpers.rs
@@ -0,0 +1,306 @@
+#![allow(non_camel_case_types)]
+#![allow(unused_unsafe)]
+use crate::ctx::WasiCtx;
+use crate::host;
+
+use lucet_runtime::vmctx::Vmctx;
+
+use nix::libc::{self, c_long};
+use std::ffi::{OsStr, OsString};
+use std::os::unix::prelude::{OsStrExt, OsStringExt, RawFd};
+
+#[cfg(target_os = "linux")]
+pub const O_RSYNC: nix::fcntl::OFlag = nix::fcntl::OFlag::O_RSYNC;
+
+#[cfg(not(target_os = "linux"))]
+pub const O_RSYNC: nix::fcntl::OFlag = nix::fcntl::OFlag::O_SYNC;
+
+/// Normalizes a path to ensure that the target path is located under the directory provided.
+///
+/// This is a workaround for not having Capsicum support in the OS.
+pub fn path_get<P: AsRef<OsStr>>(
+ vmctx: &Vmctx,
+ dirfd: host::__wasi_fd_t,
+ dirflags: host::__wasi_lookupflags_t,
+ path: P,
+ needed_base: host::__wasi_rights_t,
+ needed_inheriting: host::__wasi_rights_t,
+ needs_final_component: bool,
+) -> Result<(RawFd, OsString), host::__wasi_errno_t> {
+ use nix::errno::Errno;
+ use nix::fcntl::{openat, readlinkat, OFlag};
+ use nix::sys::stat::Mode;
+
+ const MAX_SYMLINK_EXPANSIONS: usize = 128;
+
+ /// close all the intermediate file descriptors, but make sure not to drop either the original
+ /// dirfd or the one we return (which may be the same dirfd)
+ fn ret_dir_success(dir_stack: &mut Vec<RawFd>) -> RawFd {
+ let ret_dir = dir_stack.pop().expect("there is always a dirfd to return");
+ if let Some(dirfds) = dir_stack.get(1..) {
+ for dirfd in dirfds {
+ nix::unistd::close(*dirfd).unwrap_or_else(|e| {
+ dbg!(e);
+ });
+ }
+ }
+ ret_dir
+ }
+
+ /// close all file descriptors other than the base directory, and return the errno for
+ /// convenience with `return`
+ fn ret_error(
+ dir_stack: &mut Vec<RawFd>,
+ errno: host::__wasi_errno_t,
+ ) -> Result<(RawFd, OsString), host::__wasi_errno_t> {
+ if let Some(dirfds) = dir_stack.get(1..) {
+ for dirfd in dirfds {
+ nix::unistd::close(*dirfd).unwrap_or_else(|e| {
+ dbg!(e);
+ });
+ }
+ }
+ Err(errno)
+ }
+
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+
+ let dirfe = ctx.get_fd_entry(dirfd, needed_base, needed_inheriting)?;
+
+ // Stack of directory file descriptors. Index 0 always corresponds with the directory provided
+ // to this function. Entering a directory causes a file descriptor to be pushed, while handling
+ // ".." entries causes an entry to be popped. Index 0 cannot be popped, as this would imply
+ // escaping the base directory.
+ let mut dir_stack = vec![dirfe.fd_object.rawfd];
+
+ // Stack of paths left to process. This is initially the `path` argument to this function, but
+ // any symlinks we encounter are processed by pushing them on the stack.
+ let mut path_stack = vec![path.as_ref().to_owned().into_vec()];
+
+ // Track the number of symlinks we've expanded, so we can return `ELOOP` after too many.
+ let mut symlink_expansions = 0;
+
+ // Buffer to read links into; defined outside of the loop so we don't reallocate it constantly.
+ let mut readlink_buf = vec![0u8; libc::PATH_MAX as usize + 1];
+
+ // TODO: rewrite this using a custom posix path type, with a component iterator that respects
+ // trailing slashes. This version does way too much allocation, and is way too fiddly.
+ loop {
+ let component = if let Some(cur_path) = path_stack.pop() {
+ // eprintln!(
+ // "cur_path = {:?}",
+ // std::str::from_utf8(cur_path.as_slice()).unwrap()
+ // );
+ let mut split = cur_path.splitn(2, |&c| c == b'/');
+ let head = split.next();
+ let tail = split.next();
+ match (head, tail) {
+ (None, _) => {
+ // split always returns at least a singleton iterator with an empty slice
+ panic!("unreachable");
+ }
+ // path is empty
+ (Some([]), None) => {
+ return ret_error(&mut dir_stack, host::__WASI_ENOENT as host::__wasi_errno_t);
+ }
+ // path starts with `/`, is absolute
+ (Some([]), Some(_)) => {
+ return ret_error(
+ &mut dir_stack,
+ host::__WASI_ENOTCAPABLE as host::__wasi_errno_t,
+ );
+ }
+ // the final component of the path with no trailing slash
+ (Some(component), None) => component.to_vec(),
+ (Some(component), Some(rest)) => {
+ if rest.iter().all(|&c| c == b'/') {
+ // the final component of the path with trailing slashes; put one trailing
+ // slash back on
+ let mut component = component.to_vec();
+ component.push('/' as u8);
+ component
+ } else {
+ // non-final component; push the rest back on the stack
+ path_stack.push(rest.to_vec());
+ component.to_vec()
+ }
+ }
+ }
+ } else {
+ // if the path stack is ever empty, we return rather than going through the loop again
+ panic!("unreachable");
+ };
+
+ // eprintln!(
+ // "component = {:?}",
+ // std::str::from_utf8(component.as_slice()).unwrap()
+ // );
+
+ match component.as_slice() {
+ b"." => {
+ // skip component
+ }
+ b".." => {
+ // pop a directory
+ let dirfd = dir_stack.pop().expect("dir_stack is never empty");
+
+ // we're not allowed to pop past the original directory
+ if dir_stack.is_empty() {
+ return ret_error(
+ &mut dir_stack,
+ host::__WASI_ENOTCAPABLE as host::__wasi_errno_t,
+ );
+ } else {
+ nix::unistd::close(dirfd).unwrap_or_else(|e| {
+ dbg!(e);
+ });
+ }
+ }
+ // should the component be a directory? it should if there is more path left to process, or
+ // if it has a trailing slash and `needs_final_component` is not set
+ component
+ if !path_stack.is_empty()
+ || (component.ends_with(b"/") && !needs_final_component) =>
+ {
+ match openat(
+ *dir_stack.last().expect("dir_stack is never empty"),
+ component,
+ OFlag::O_RDONLY | OFlag::O_DIRECTORY | OFlag::O_NOFOLLOW,
+ Mode::empty(),
+ ) {
+ Ok(new_dir) => {
+ dir_stack.push(new_dir);
+ continue;
+ }
+ Err(e)
+ // Check to see if it was a symlink. Linux indicates
+ // this with ENOTDIR because of the O_DIRECTORY flag.
+ if e.as_errno() == Some(Errno::ELOOP)
+ || e.as_errno() == Some(Errno::EMLINK)
+ || e.as_errno() == Some(Errno::ENOTDIR) =>
+ {
+ // attempt symlink expansion
+ match readlinkat(
+ *dir_stack.last().expect("dir_stack is never empty"),
+ component,
+ readlink_buf.as_mut_slice(),
+ ) {
+ Ok(link_path) => {
+ symlink_expansions += 1;
+ if symlink_expansions > MAX_SYMLINK_EXPANSIONS {
+ return ret_error(
+ &mut dir_stack,
+ host::__WASI_ELOOP as host::__wasi_errno_t,
+ );
+ }
+
+ let mut link_path = link_path.as_bytes().to_vec();
+
+ // append a trailing slash if the component leading to it has one, so
+ // that we preserve any ENOTDIR that might come from trying to open a
+ // non-directory
+ if component.ends_with(b"/") {
+ link_path.push(b'/');
+ }
+
+ path_stack.push(link_path);
+ continue;
+ }
+ Err(e) => {
+ return ret_error(
+ &mut dir_stack,
+ host::errno_from_nix(e.as_errno().unwrap()),
+ );
+ }
+ }
+ }
+ Err(e) => {
+ return ret_error(
+ &mut dir_stack,
+ host::errno_from_nix(e.as_errno().unwrap()),
+ );
+ }
+ }
+ }
+ // the final component
+ component => {
+ // if there's a trailing slash, or if `LOOKUP_SYMLINK_FOLLOW` is set, attempt
+ // symlink expansion
+ if component.ends_with(b"/") || (dirflags & host::__WASI_LOOKUP_SYMLINK_FOLLOW) != 0
+ {
+ match readlinkat(
+ *dir_stack.last().expect("dir_stack is never empty"),
+ component,
+ readlink_buf.as_mut_slice(),
+ ) {
+ Ok(link_path) => {
+ symlink_expansions += 1;
+ if symlink_expansions > MAX_SYMLINK_EXPANSIONS {
+ return ret_error(
+ &mut dir_stack,
+ host::__WASI_ELOOP as host::__wasi_errno_t,
+ );
+ }
+
+ let mut link_path = link_path.as_bytes().to_vec();
+
+ // append a trailing slash if the component leading to it has one, so
+ // that we preserve any ENOTDIR that might come from trying to open a
+ // non-directory
+ if component.ends_with(b"/") {
+ link_path.push(b'/');
+ }
+
+ path_stack.push(link_path);
+ continue;
+ }
+ Err(e) => {
+ let errno = e.as_errno().unwrap();
+ if errno != Errno::EINVAL && errno != Errno::ENOENT {
+ // only return an error if this path is not actually a symlink
+ return ret_error(&mut dir_stack, host::errno_from_nix(errno));
+ }
+ }
+ }
+ }
+
+ // not a symlink, so we're done;
+ return Ok((
+ ret_dir_success(&mut dir_stack),
+ OsStr::from_bytes(component).to_os_string(),
+ ));
+ }
+ }
+
+ if path_stack.is_empty() {
+ // no further components to process. means we've hit a case like "." or "a/..", or if the
+ // input path has trailing slashes and `needs_final_component` is not set
+ return Ok((
+ ret_dir_success(&mut dir_stack),
+ OsStr::new(".").to_os_string(),
+ ));
+ } else {
+ continue;
+ }
+ }
+}
+
+#[cfg(not(target_os = "macos"))]
+pub fn utime_now() -> c_long {
+ libc::UTIME_NOW
+}
+
+#[cfg(target_os = "macos")]
+pub fn utime_now() -> c_long {
+ -1
+}
+
+#[cfg(not(target_os = "macos"))]
+pub fn utime_omit() -> c_long {
+ libc::UTIME_OMIT
+}
+
+#[cfg(target_os = "macos")]
+pub fn utime_omit() -> c_long {
+ -2
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/misc.rs b/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/misc.rs
new file mode 100644
index 0000000000..39ab5109c1
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/misc.rs
@@ -0,0 +1,457 @@
+#![allow(non_camel_case_types)]
+#![allow(unused_unsafe)]
+
+use crate::ctx::WasiCtx;
+use crate::memory::*;
+use crate::{host, wasm32};
+
+use super::timers;
+
+use cast::From as _0;
+use lucet_runtime::lucet_hostcall_terminate;
+use lucet_runtime::vmctx::Vmctx;
+
+use nix::convert_ioctl_res;
+use nix::libc::{self, c_int};
+use std::cmp;
+use std::mem::MaybeUninit;
+use std::time::SystemTime;
+
+// define the `fionread()` function, equivalent to `ioctl(fd, FIONREAD, *bytes)`
+nix::ioctl_read_bad!(fionread, nix::libc::FIONREAD, c_int);
+
+fn wasi_clock_to_relative_ns_delay(
+ wasi_clock: host::__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t,
+) -> u128 {
+ if wasi_clock.flags != wasm32::__WASI_SUBSCRIPTION_CLOCK_ABSTIME {
+ return wasi_clock.timeout as u128;
+ }
+ let now: u128 = SystemTime::now()
+ .duration_since(SystemTime::UNIX_EPOCH)
+ .expect("Current date is before the epoch")
+ .as_nanos();
+ let deadline = wasi_clock.timeout as u128;
+ deadline.saturating_sub(now)
+}
+
+#[derive(Debug, Copy, Clone)]
+struct ClockEventData {
+ delay: u128,
+ userdata: host::__wasi_userdata_t,
+}
+#[derive(Debug, Copy, Clone)]
+struct FdEventData {
+ fd: c_int,
+ type_: host::__wasi_eventtype_t,
+ userdata: host::__wasi_userdata_t,
+}
+
+pub fn wasi_proc_exit(_vmctx: &mut Vmctx, rval: wasm32::__wasi_exitcode_t) -> ! {
+ lucet_hostcall_terminate!(dec_exitcode(rval));
+}
+
+pub fn wasi_args_get(
+ vmctx: &mut Vmctx,
+ argv_ptr: wasm32::uintptr_t,
+ argv_buf: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+
+ let mut argv_buf_offset = 0;
+ let mut argv = vec![];
+
+ for arg in ctx.args.iter() {
+ let arg_bytes = arg.as_bytes_with_nul();
+ let arg_ptr = argv_buf + argv_buf_offset;
+
+ if let Err(e) = enc_slice_of(vmctx, arg_bytes, arg_ptr) {
+ return enc_errno(e);
+ }
+
+ argv.push(arg_ptr);
+
+ argv_buf_offset = if let Some(new_offset) = argv_buf_offset.checked_add(
+ wasm32::uintptr_t::cast(arg_bytes.len())
+ .expect("cast overflow would have been caught by `enc_slice_of` above"),
+ ) {
+ new_offset
+ } else {
+ return wasm32::__WASI_EOVERFLOW;
+ }
+ }
+ enc_slice_of(vmctx, argv.as_slice(), argv_ptr)
+ .map(|_| wasm32::__WASI_ESUCCESS)
+ .unwrap_or_else(|e| e)
+}
+
+pub fn wasi_args_sizes_get(
+ vmctx: &mut Vmctx,
+ argc_ptr: wasm32::uintptr_t,
+ argv_buf_size_ptr: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+
+ let argc = ctx.args.len();
+ let argv_size = ctx
+ .args
+ .iter()
+ .map(|arg| arg.as_bytes_with_nul().len())
+ .sum();
+ if let Err(e) = enc_usize_byref(vmctx, argc_ptr, argc) {
+ return enc_errno(e);
+ }
+ if let Err(e) = enc_usize_byref(vmctx, argv_buf_size_ptr, argv_size) {
+ return enc_errno(e);
+ }
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_sched_yield(_vmctx: &mut Vmctx) -> wasm32::__wasi_errno_t {
+ unsafe { libc::sched_yield() };
+ wasm32::__WASI_ESUCCESS
+}
+
+pub fn wasi_clock_res_get(
+ vmctx: &mut Vmctx,
+ clock_id: wasm32::__wasi_clockid_t,
+ resolution_ptr: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ // convert the supported clocks to the libc types, or return EINVAL
+ let clock_id = match dec_clockid(clock_id) {
+ host::__WASI_CLOCK_REALTIME => libc::CLOCK_REALTIME,
+ host::__WASI_CLOCK_MONOTONIC => libc::CLOCK_MONOTONIC,
+ host::__WASI_CLOCK_PROCESS_CPUTIME_ID => libc::CLOCK_PROCESS_CPUTIME_ID,
+ host::__WASI_CLOCK_THREAD_CPUTIME_ID => libc::CLOCK_THREAD_CPUTIME_ID,
+ _ => return wasm32::__WASI_EINVAL,
+ };
+
+ // no `nix` wrapper for clock_getres, so we do it ourselves
+ let mut timespec = MaybeUninit::<libc::timespec>::uninit();
+ let res = unsafe { timers::clock_getres_helper(clock_id, timespec.as_mut_ptr()) };
+ if res != 0 {
+ return wasm32::errno_from_nix(nix::errno::Errno::last());
+ }
+ let timespec = unsafe { timespec.assume_init() };
+
+ // convert to nanoseconds, returning EOVERFLOW in case of overflow; this is freelancing a bit
+ // from the spec but seems like it'll be an unusual situation to hit
+ (timespec.tv_sec as host::__wasi_timestamp_t)
+ .checked_mul(1_000_000_000)
+ .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as host::__wasi_timestamp_t))
+ .map(|resolution| {
+ // a supported clock can never return zero; this case will probably never get hit, but
+ // make sure we follow the spec
+ if resolution == 0 {
+ wasm32::__WASI_EINVAL
+ } else {
+ enc_timestamp_byref(vmctx, resolution_ptr, resolution)
+ .map(|_| wasm32::__WASI_ESUCCESS)
+ .unwrap_or_else(|e| e)
+ }
+ })
+ .unwrap_or(wasm32::__WASI_EOVERFLOW)
+}
+
+pub fn wasi_clock_time_get(
+ vmctx: &mut Vmctx,
+ clock_id: wasm32::__wasi_clockid_t,
+ // ignored for now, but will be useful once we put optional limits on precision to reduce side
+ // channels
+ _precision: wasm32::__wasi_timestamp_t,
+ time_ptr: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ // convert the supported clocks to the libc types, or return EINVAL
+ let clock_id = match dec_clockid(clock_id) {
+ host::__WASI_CLOCK_REALTIME => libc::CLOCK_REALTIME,
+ host::__WASI_CLOCK_MONOTONIC => libc::CLOCK_MONOTONIC,
+ host::__WASI_CLOCK_PROCESS_CPUTIME_ID => libc::CLOCK_PROCESS_CPUTIME_ID,
+ host::__WASI_CLOCK_THREAD_CPUTIME_ID => libc::CLOCK_THREAD_CPUTIME_ID,
+ _ => return wasm32::__WASI_EINVAL,
+ };
+
+ // no `nix` wrapper for clock_getres, so we do it ourselves
+ let mut timespec = MaybeUninit::<libc::timespec>::uninit();
+ let res = unsafe { timers::clock_gettime_helper(clock_id, timespec.as_mut_ptr()) };
+ if res != 0 {
+ return wasm32::errno_from_nix(nix::errno::Errno::last());
+ }
+ let timespec = unsafe { timespec.assume_init() };
+ // convert to nanoseconds, returning EOVERFLOW in case of overflow; this is freelancing a bit
+ // from the spec but seems like it'll be an unusual situation to hit
+ (timespec.tv_sec as host::__wasi_timestamp_t)
+ .checked_mul(1_000_000_000)
+ .and_then(|sec_ns| sec_ns.checked_add(timespec.tv_nsec as host::__wasi_timestamp_t))
+ .map(|time| {
+ enc_timestamp_byref(vmctx, time_ptr, time)
+ .map(|_| wasm32::__WASI_ESUCCESS)
+ .unwrap_or_else(|e| e)
+ })
+ .unwrap_or(wasm32::__WASI_EOVERFLOW)
+}
+
+pub fn wasi_environ_get(
+ vmctx: &mut Vmctx,
+ environ_ptr: wasm32::uintptr_t,
+ environ_buf: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+
+ let mut environ_buf_offset = 0;
+ let mut environ = vec![];
+
+ for pair in ctx.env.iter() {
+ let env_bytes = pair.as_bytes_with_nul();
+ let env_ptr = environ_buf + environ_buf_offset;
+
+ if let Err(e) = enc_slice_of(vmctx, env_bytes, env_ptr) {
+ return enc_errno(e);
+ }
+
+ environ.push(env_ptr);
+
+ environ_buf_offset = if let Some(new_offset) = environ_buf_offset.checked_add(
+ wasm32::uintptr_t::cast(env_bytes.len())
+ .expect("cast overflow would have been caught by `enc_slice_of` above"),
+ ) {
+ new_offset
+ } else {
+ return wasm32::__WASI_EOVERFLOW;
+ }
+ }
+ enc_slice_of(vmctx, environ.as_slice(), environ_ptr)
+ .map(|_| wasm32::__WASI_ESUCCESS)
+ .unwrap_or_else(|e| e)
+}
+
+pub fn wasi_environ_sizes_get(
+ vmctx: &mut Vmctx,
+ environ_count_ptr: wasm32::uintptr_t,
+ environ_size_ptr: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ let ctx = vmctx.get_embed_ctx::<WasiCtx>();
+
+ let environ_count = ctx.env.len();
+ if let Some(environ_size) = ctx.env.iter().try_fold(0, |acc: u32, pair| {
+ acc.checked_add(pair.as_bytes_with_nul().len() as u32)
+ }) {
+ if let Err(e) = enc_usize_byref(vmctx, environ_count_ptr, environ_count) {
+ return enc_errno(e);
+ }
+ if let Err(e) = enc_usize_byref(vmctx, environ_size_ptr, environ_size as usize) {
+ return enc_errno(e);
+ }
+ wasm32::__WASI_ESUCCESS
+ } else {
+ wasm32::__WASI_EOVERFLOW
+ }
+}
+
+pub fn wasi_random_get(
+ vmctx: &mut Vmctx,
+ buf_ptr: wasm32::uintptr_t,
+ buf_len: wasm32::size_t,
+) -> wasm32::__wasi_errno_t {
+ use rand::{thread_rng, RngCore};
+
+ let buf = match dec_slice_of_mut::<u8>(vmctx, buf_ptr, buf_len) {
+ Ok(buf) => buf,
+ Err(e) => return enc_errno(e),
+ };
+ thread_rng().fill_bytes(buf);
+
+ return wasm32::__WASI_ESUCCESS;
+}
+
+fn _wasi_poll_oneoff_handle_timeout_event(
+ output_slice: &mut [wasm32::__wasi_event_t],
+ timeout: Option<ClockEventData>,
+) -> wasm32::size_t {
+ if let Some(ClockEventData { userdata, .. }) = timeout {
+ let output_event = host::__wasi_event_t {
+ userdata,
+ type_: wasm32::__WASI_EVENTTYPE_CLOCK,
+ error: wasm32::__WASI_ESUCCESS,
+ u: host::__wasi_event_t___wasi_event_u {
+ fd_readwrite: host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t {
+ nbytes: 0,
+ flags: 0,
+ },
+ },
+ };
+ output_slice[0] = enc_event(output_event);
+ 1
+ } else {
+ // shouldn't happen
+ 0
+ }
+}
+
+fn _wasi_poll_oneoff_handle_fd_event<'t>(
+ output_slice: &mut [wasm32::__wasi_event_t],
+ events: impl Iterator<Item = (&'t FdEventData, &'t nix::poll::PollFd)>,
+) -> wasm32::size_t {
+ let mut output_slice_cur = output_slice.iter_mut();
+ let mut revents_count = 0;
+ for (fd_event, poll_fd) in events {
+ let revents = match poll_fd.revents() {
+ Some(revents) => revents,
+ None => continue,
+ };
+ let mut nbytes = 0;
+ if fd_event.type_ == wasm32::__WASI_EVENTTYPE_FD_READ {
+ let _ = unsafe { fionread(fd_event.fd, &mut nbytes) };
+ }
+ let output_event = if revents.contains(nix::poll::EventFlags::POLLNVAL) {
+ host::__wasi_event_t {
+ userdata: fd_event.userdata,
+ type_: fd_event.type_,
+ error: wasm32::__WASI_EBADF,
+ u: host::__wasi_event_t___wasi_event_u {
+ fd_readwrite:
+ host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t {
+ nbytes: 0,
+ flags: wasm32::__WASI_EVENT_FD_READWRITE_HANGUP,
+ },
+ },
+ }
+ } else if revents.contains(nix::poll::EventFlags::POLLERR) {
+ host::__wasi_event_t {
+ userdata: fd_event.userdata,
+ type_: fd_event.type_,
+ error: wasm32::__WASI_EIO,
+ u: host::__wasi_event_t___wasi_event_u {
+ fd_readwrite:
+ host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t {
+ nbytes: 0,
+ flags: wasm32::__WASI_EVENT_FD_READWRITE_HANGUP,
+ },
+ },
+ }
+ } else if revents.contains(nix::poll::EventFlags::POLLHUP) {
+ host::__wasi_event_t {
+ userdata: fd_event.userdata,
+ type_: fd_event.type_,
+ error: wasm32::__WASI_ESUCCESS,
+ u: host::__wasi_event_t___wasi_event_u {
+ fd_readwrite:
+ host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t {
+ nbytes: 0,
+ flags: wasm32::__WASI_EVENT_FD_READWRITE_HANGUP,
+ },
+ },
+ }
+ } else if revents.contains(nix::poll::EventFlags::POLLIN)
+ | revents.contains(nix::poll::EventFlags::POLLOUT)
+ {
+ host::__wasi_event_t {
+ userdata: fd_event.userdata,
+ type_: fd_event.type_,
+ error: wasm32::__WASI_ESUCCESS,
+ u: host::__wasi_event_t___wasi_event_u {
+ fd_readwrite:
+ host::__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t {
+ nbytes: nbytes as host::__wasi_filesize_t,
+ flags: 0,
+ },
+ },
+ }
+ } else {
+ continue;
+ };
+ *output_slice_cur.next().unwrap() = enc_event(output_event);
+ revents_count += 1;
+ }
+ revents_count
+}
+
+pub fn wasi_poll_oneoff(
+ vmctx: &mut Vmctx,
+ input: wasm32::uintptr_t,
+ output: wasm32::uintptr_t,
+ nsubscriptions: wasm32::size_t,
+ nevents: wasm32::uintptr_t,
+) -> wasm32::__wasi_errno_t {
+ if nsubscriptions as u64 > wasm32::__wasi_filesize_t::max_value() {
+ return wasm32::__WASI_EINVAL;
+ }
+ enc_pointee(vmctx, nevents, 0).unwrap();
+
+ let input_slice =
+ dec_slice_of::<wasm32::__wasi_subscription_t>(vmctx, input, nsubscriptions).unwrap();
+
+ let output_slice =
+ dec_slice_of_mut::<wasm32::__wasi_event_t>(vmctx, output, nsubscriptions).unwrap();
+
+ let input: Vec<_> = input_slice.iter().map(|x| dec_subscription(x)).collect();
+
+ let timeout = input
+ .iter()
+ .filter_map(|event| match event {
+ Ok(event) if event.type_ == wasm32::__WASI_EVENTTYPE_CLOCK => Some(ClockEventData {
+ delay: wasi_clock_to_relative_ns_delay(unsafe { event.u.clock }) / 1_000_000,
+ userdata: event.userdata,
+ }),
+ _ => None,
+ })
+ .min_by_key(|event| event.delay);
+ let fd_events: Vec<_> = input
+ .iter()
+ .filter_map(|event| match event {
+ Ok(event)
+ if event.type_ == wasm32::__WASI_EVENTTYPE_FD_READ
+ || event.type_ == wasm32::__WASI_EVENTTYPE_FD_WRITE =>
+ {
+ Some(FdEventData {
+ fd: unsafe { event.u.fd_readwrite.fd } as c_int,
+ type_: event.type_,
+ userdata: event.userdata,
+ })
+ }
+ _ => None,
+ })
+ .collect();
+ if fd_events.is_empty() && timeout.is_none() {
+ return wasm32::__WASI_ESUCCESS;
+ }
+ let mut poll_fds: Vec<_> = fd_events
+ .iter()
+ .map(|event| {
+ let mut flags = nix::poll::EventFlags::empty();
+ match event.type_ {
+ wasm32::__WASI_EVENTTYPE_FD_READ => flags.insert(nix::poll::EventFlags::POLLIN),
+ wasm32::__WASI_EVENTTYPE_FD_WRITE => flags.insert(nix::poll::EventFlags::POLLOUT),
+ // An event on a file descriptor can currently only be of type FD_READ or FD_WRITE
+ // Nothing else has been defined in the specification, and these are also the only two
+ // events we filtered before. If we get something else here, the code has a serious bug.
+ _ => unreachable!(),
+ };
+ nix::poll::PollFd::new(event.fd, flags)
+ })
+ .collect();
+ let timeout = timeout.map(|ClockEventData { delay, userdata }| ClockEventData {
+ delay: cmp::min(delay, c_int::max_value() as u128),
+ userdata,
+ });
+ let poll_timeout = timeout.map(|timeout| timeout.delay as c_int).unwrap_or(-1);
+ let ready = loop {
+ match nix::poll::poll(&mut poll_fds, poll_timeout) {
+ Err(_) => {
+ if nix::errno::Errno::last() == nix::errno::Errno::EINTR {
+ continue;
+ }
+ return wasm32::errno_from_nix(nix::errno::Errno::last());
+ }
+ Ok(ready) => break ready as usize,
+ }
+ };
+ let events_count = if ready == 0 {
+ _wasi_poll_oneoff_handle_timeout_event(output_slice, timeout)
+ } else {
+ let events = fd_events.iter().zip(poll_fds.iter()).take(ready);
+ _wasi_poll_oneoff_handle_fd_event(output_slice, events)
+ };
+ if let Err(e) = enc_pointee(vmctx, nevents, events_count) {
+ return enc_errno(e);
+ }
+ wasm32::__WASI_ESUCCESS
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/mod.rs b/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/mod.rs
new file mode 100644
index 0000000000..ed9b5e038d
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/mod.rs
@@ -0,0 +1,448 @@
+//! Hostcalls that implement
+//! [WASI](https://github.com/CraneStation/wasmtime-wasi/blob/wasi/docs/WASI-overview.md).
+//!
+//! This code borrows heavily from [wasmtime-wasi](https://github.com/CraneStation/wasmtime-wasi),
+//! which in turn borrows from cloudabi-utils. See `LICENSE.wasmtime-wasi` for license information.
+
+#![allow(non_camel_case_types)]
+#![allow(unused_unsafe)]
+
+mod fs;
+mod fs_helpers;
+mod misc;
+mod timers;
+
+use crate::wasm32;
+
+use fs::*;
+use lucet_runtime::lucet_hostcalls;
+use misc::*;
+
+lucet_hostcalls! {
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_proc_exit(&mut vmctx, rval: wasm32::__wasi_exitcode_t,) -> ! {
+ wasi_proc_exit(vmctx, rval)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_args_get(
+ &mut vmctx,
+ argv_ptr: wasm32::uintptr_t,
+ argv_buf: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_args_get(vmctx, argv_ptr, argv_buf)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_args_sizes_get(&mut vmctx,
+ argc_ptr: wasm32::uintptr_t,
+ argv_buf_size_ptr: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_args_sizes_get(vmctx, argc_ptr, argv_buf_size_ptr)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_sched_yield(&mut vmctx,) -> wasm32::__wasi_errno_t {
+ wasi_sched_yield(vmctx)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_clock_res_get(
+ &mut vmctx,
+ clock_id: wasm32::__wasi_clockid_t,
+ resolution_ptr: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_clock_res_get(vmctx, clock_id, resolution_ptr)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_clock_time_get(
+ &mut vmctx,
+ clock_id: wasm32::__wasi_clockid_t,
+ precision: wasm32::__wasi_timestamp_t,
+ time_ptr: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_clock_time_get(vmctx, clock_id, precision, time_ptr)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_environ_get(
+ &mut vmctx,
+ environ_ptr: wasm32::uintptr_t,
+ environ_buf: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_environ_get(vmctx, environ_ptr, environ_buf)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_environ_sizes_get(
+ &mut vmctx,
+ environ_count_ptr: wasm32::uintptr_t,
+ environ_size_ptr: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_environ_sizes_get(vmctx, environ_count_ptr, environ_size_ptr)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_close(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_close(vmctx, fd)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_fdstat_get(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ fdstat_ptr: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_fdstat_get(vmctx, fd, fdstat_ptr)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_fdstat_set_flags(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ fdflags: wasm32::__wasi_fdflags_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_fdstat_set_flags(vmctx, fd, fdflags)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_tell(&mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ offset: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_tell(vmctx, fd, offset)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_seek(&mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ offset: wasm32::__wasi_filedelta_t,
+ whence: wasm32::__wasi_whence_t,
+ newoffset: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_seek(vmctx, fd, offset, whence, newoffset)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_prestat_get(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ prestat_ptr: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_prestat_get(vmctx, fd, prestat_ptr)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_prestat_dir_name(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_prestat_dir_name(vmctx, fd, path_ptr, path_len)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_read(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ iovs_ptr: wasm32::uintptr_t,
+ iovs_len: wasm32::size_t,
+ nread: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_read(vmctx, fd, iovs_ptr, iovs_len, nread)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_write(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ iovs_ptr: wasm32::uintptr_t,
+ iovs_len: wasm32::size_t,
+ nwritten: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_write(vmctx, fd, iovs_ptr, iovs_len, nwritten)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_path_open(
+ &mut vmctx,
+ dirfd: wasm32::__wasi_fd_t,
+ dirflags: wasm32::__wasi_lookupflags_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+ oflags: wasm32::__wasi_oflags_t,
+ fs_rights_base: wasm32::__wasi_rights_t,
+ fs_rights_inheriting: wasm32::__wasi_rights_t,
+ fs_flags: wasm32::__wasi_fdflags_t,
+ fd_out_ptr: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_path_open(vmctx, dirfd, dirflags, path_ptr, path_len,
+ oflags, fs_rights_base, fs_rights_inheriting, fs_flags,
+ fd_out_ptr)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_random_get(
+ &mut vmctx,
+ buf_ptr: wasm32::uintptr_t,
+ buf_len: wasm32::size_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_random_get(vmctx, buf_ptr, buf_len)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_poll_oneoff(
+ &mut vmctx,
+ input: wasm32::uintptr_t,
+ output: wasm32::uintptr_t,
+ nsubscriptions: wasm32::size_t,
+ nevents: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_poll_oneoff(vmctx, input, output, nsubscriptions, nevents)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_filestat_get(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ filestat_ptr: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_filestat_get(vmctx, fd, filestat_ptr)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_path_filestat_get(
+ &mut vmctx,
+ dirfd: wasm32::__wasi_fd_t,
+ dirflags: wasm32::__wasi_lookupflags_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+ filestat_ptr: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_path_filestat_get(vmctx, dirfd, dirflags, path_ptr,
+ path_len, filestat_ptr)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_path_create_directory(
+ &mut vmctx,
+ dirfd: wasm32::__wasi_fd_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_path_create_directory(vmctx, dirfd, path_ptr, path_len)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_path_unlink_file(
+ &mut vmctx,
+ dirfd: wasm32::__wasi_fd_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_path_unlink_file(vmctx, dirfd, path_ptr, path_len)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_allocate(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ offset: wasm32::__wasi_filesize_t,
+ len: wasm32::__wasi_filesize_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_allocate(vmctx, fd, offset, len)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_advise(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ offset: wasm32::__wasi_filesize_t,
+ len: wasm32::__wasi_filesize_t,
+ advice: wasm32::__wasi_advice_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_advise(vmctx, fd, offset, len, advice)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_datasync(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_datasync(vmctx, fd)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_sync(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_sync(vmctx, fd)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_fdstat_set_rights(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ fs_rights_base: wasm32::__wasi_rights_t,
+ fs_rights_inheriting: wasm32::__wasi_rights_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_fdstat_set_rights(vmctx, fd, fs_rights_base, fs_rights_inheriting)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_filestat_set_size(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ st_size: wasm32::__wasi_filesize_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_filestat_set_size(vmctx, fd, st_size)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_filestat_set_times(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ st_atim: wasm32::__wasi_timestamp_t,
+ st_mtim: wasm32::__wasi_timestamp_t,
+ fst_flags: wasm32::__wasi_fstflags_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_filestat_set_times(vmctx, fd, st_atim, st_mtim, fst_flags)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_pread(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ iovs_ptr: wasm32::uintptr_t,
+ iovs_len: wasm32::size_t,
+ offset: wasm32::__wasi_filesize_t,
+ nread: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_pread(vmctx, fd, iovs_ptr, iovs_len, offset, nread)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_pwrite(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ iovs_ptr: wasm32::uintptr_t,
+ iovs_len: wasm32::size_t,
+ offset: wasm32::__wasi_filesize_t,
+ nwritten: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_pwrite(vmctx, fd, iovs_ptr, iovs_len, offset, nwritten)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_readdir(
+ &mut vmctx,
+ fd: wasm32::__wasi_fd_t,
+ buf: wasm32::uintptr_t,
+ buf_len: wasm32::size_t,
+ cookie: wasm32::__wasi_dircookie_t,
+ bufused: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_readdir(vmctx, fd, buf, buf_len, cookie, bufused)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_fd_renumber(
+ &mut vmctx,
+ from: wasm32::__wasi_fd_t,
+ to: wasm32::__wasi_fd_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_fd_renumber(vmctx, from, to)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_path_filestat_set_times(
+ &mut vmctx,
+ dirfd: wasm32::__wasi_fd_t,
+ dirflags: wasm32::__wasi_lookupflags_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+ st_atim: wasm32::__wasi_timestamp_t,
+ st_mtim: wasm32::__wasi_timestamp_t,
+ fst_flags: wasm32::__wasi_fstflags_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_path_filestat_set_times(vmctx, dirfd, dirflags, path_ptr, path_len, st_atim, st_mtim, fst_flags)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_path_link(
+ &mut vmctx,
+ old_fd: wasm32::__wasi_fd_t,
+ old_flags: wasm32::__wasi_lookupflags_t,
+ old_path_ptr: wasm32::uintptr_t,
+ old_path_len: wasm32::size_t,
+ new_fd: wasm32::__wasi_fd_t,
+ new_path_ptr: wasm32::uintptr_t,
+ new_path_len: wasm32::size_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_path_link(vmctx, old_fd, old_flags, old_path_ptr, old_path_len,
+ new_fd, new_path_ptr, new_path_len)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_path_readlink(
+ &mut vmctx,
+ dirfd: wasm32::__wasi_fd_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+ buf_ptr: wasm32::uintptr_t,
+ buf_len: wasm32::size_t,
+ bufused: wasm32::uintptr_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_path_readlink(vmctx, dirfd, path_ptr, path_len, buf_ptr, buf_len, bufused)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_path_remove_directory(
+ &mut vmctx,
+ dirfd: wasm32::__wasi_fd_t,
+ path_ptr: wasm32::uintptr_t,
+ path_len: wasm32::size_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_path_remove_directory(vmctx, dirfd, path_ptr, path_len)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_path_rename(
+ &mut vmctx,
+ old_dirfd: wasm32::__wasi_fd_t,
+ old_path_ptr: wasm32::uintptr_t,
+ old_path_len: wasm32::size_t,
+ new_dirfd: wasm32::__wasi_fd_t,
+ new_path_ptr: wasm32::uintptr_t,
+ new_path_len: wasm32::size_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_path_rename(vmctx, old_dirfd, old_path_ptr, old_path_len,
+ new_dirfd, new_path_ptr, new_path_len)
+ }
+
+ #[no_mangle] pub unsafe extern "C"
+ fn __wasi_path_symlink(
+ &mut vmctx,
+ old_path_ptr: wasm32::uintptr_t,
+ old_path_len: wasm32::size_t,
+ dir_fd: wasm32::__wasi_fd_t,
+ new_path_ptr: wasm32::uintptr_t,
+ new_path_len: wasm32::size_t,
+ ) -> wasm32::__wasi_errno_t {
+ wasi_path_symlink(vmctx, old_path_ptr, old_path_len,
+ dir_fd, new_path_ptr, new_path_len)
+ }
+}
+
+#[doc(hidden)]
+pub fn ensure_linked() {
+ unsafe {
+ std::ptr::read_volatile(__wasi_proc_exit as *const extern "C" fn());
+ }
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/timers.rs b/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/timers.rs
new file mode 100644
index 0000000000..926a998445
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/src/hostcalls/timers.rs
@@ -0,0 +1,113 @@
+use nix::libc::{self, c_int, c_char};
+
+#[cfg(not(target_os = "macos"))]
+mod notmac
+{
+ use super::*;
+
+ pub unsafe fn clock_gettime_helper(clock_id: libc::clockid_t, tp: *mut libc::timespec) -> c_int {
+ libc::clock_gettime(clock_id, tp)
+ }
+
+ pub unsafe fn clock_getres_helper(clock_id: libc::clockid_t, res: *mut libc::timespec) -> c_int {
+ libc::clock_getres(clock_id, res)
+ }
+
+ pub unsafe fn futimens_helper(fd: c_int, times: *const libc::timespec) -> c_int {
+ libc::futimens(fd, times)
+ }
+
+ pub unsafe fn utimensat_helper(dirfd: c_int, path: *const c_char, times: *const libc::timespec, flag: c_int) -> c_int {
+ libc::utimensat(dirfd, path, times, flag)
+ }
+}
+
+#[cfg(target_os = "macos")]
+mod mac
+{
+ use super::*;
+ use std::mem::MaybeUninit;
+ use std::sync::Once;
+
+ use mach::mach_time::*;
+
+ // Referring these 3 sources
+ //https://stackoverflow.com/questions/5167269/clock-gettime-alternative-in-mac-os-x
+ //https://stackoverflow.com/questions/11680461/monotonic-clock-on-osx
+ //https://gist.github.com/lifthrasiir/393ffb3e9900709fa2e3ae2a540b635f
+
+ static mut CONVERSION_FACTOR : f64 = 0.0;
+ static INIT : Once = Once::new();
+
+ unsafe fn get_cached_conversion_factor() -> f64 {
+ unsafe {
+ INIT.call_once(|| {
+ let mut timebase = MaybeUninit::<mach_timebase_info_data_t>::uninit();
+ mach_timebase_info(timebase.as_mut_ptr());
+ let timebase = unsafe { timebase.assume_init() };
+
+ let numer_d : f64 = timebase.numer as f64;
+ let denom_d : f64 = timebase.denom as f64;
+
+ CONVERSION_FACTOR = numer_d / denom_d;
+ });
+ }
+ CONVERSION_FACTOR
+ }
+
+ pub unsafe fn clock_gettime_helper(clock_id: libc::clockid_t, tp: *mut libc::timespec) -> c_int {
+ if !(clock_id == libc::CLOCK_REALTIME || clock_id == libc::CLOCK_MONOTONIC) {
+ (*libc::__error()) = libc::EINVAL;
+ return -1;
+ }
+
+ if clock_id == libc::CLOCK_REALTIME {
+ let mut micro = MaybeUninit::<libc::timeval>::uninit();
+ libc::gettimeofday(micro.as_mut_ptr(), core::ptr::null_mut());
+ let micro = unsafe { micro.assume_init() };
+
+ (*tp).tv_sec = micro.tv_sec;
+ (*tp).tv_nsec = i64::from(micro.tv_usec) * 1000;
+ return 0;
+ } else {
+ let time : u64 = mach_absolute_time();
+ let time_d : f64 = time as f64;
+ let conv : f64 = get_cached_conversion_factor();
+ let nseconds : f64 = time_d * conv;
+ let seconds : f64 = nseconds / 1e9;
+ (*tp).tv_sec = seconds as i64;
+ (*tp).tv_nsec = nseconds as i64;
+ return 0;
+ }
+ }
+
+ pub unsafe fn clock_getres_helper(clock_id: libc::clockid_t, res: *mut libc::timespec) -> c_int {
+ if !(clock_id == libc::CLOCK_REALTIME || clock_id == libc::CLOCK_MONOTONIC) {
+ (*libc::__error()) = libc::EINVAL;
+ return -1;
+ }
+
+ (*res).tv_sec = 0 as i64;
+ (*res).tv_nsec =
+ if clock_id == libc::CLOCK_REALTIME {
+ 1000 as i64
+ } else {
+ 1 as i64
+ };
+ return 0;
+ }
+
+ pub unsafe fn futimens_helper(_fd: c_int, _times: *const libc::timespec) -> c_int {
+ panic!("futimens not implemented");
+ }
+
+ pub unsafe fn utimensat_helper(_dirfd: c_int, _path: *const c_char, _times: *const libc::timespec, _flag: c_int) -> c_int {
+ panic!("utimensat not implemented");
+ }
+}
+
+#[cfg(not(target_os = "macos"))]
+pub use notmac::*;
+
+#[cfg(target_os = "macos")]
+pub use mac::*; \ No newline at end of file
diff --git a/third_party/rust/lucet-wasi-wasmsbx/src/lib.rs b/third_party/rust/lucet-wasi-wasmsbx/src/lib.rs
new file mode 100644
index 0000000000..2c3a5f0675
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/src/lib.rs
@@ -0,0 +1,16 @@
+#![deny(bare_trait_objects)]
+
+mod bindings;
+pub mod c_api;
+pub mod ctx;
+pub mod fdentry;
+pub mod host;
+pub mod hostcalls;
+pub mod memory;
+pub mod wasm32;
+
+pub use bindings::bindings;
+pub use ctx::{WasiCtx, WasiCtxBuilder};
+
+#[macro_use]
+extern crate lazy_static; \ No newline at end of file
diff --git a/third_party/rust/lucet-wasi-wasmsbx/src/memory.rs b/third_party/rust/lucet-wasi-wasmsbx/src/memory.rs
new file mode 100644
index 0000000000..3ecfd51b11
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/src/memory.rs
@@ -0,0 +1,620 @@
+//! 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::{host, wasm32};
+use cast;
+use cast::From as _0;
+use lucet_runtime::vmctx::Vmctx;
+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 fn dec_ptr(
+ vmctx: &Vmctx,
+ ptr: wasm32::uintptr_t,
+ len: usize,
+) -> Result<*const u8, host::__wasi_errno_t> {
+ let heap = vmctx.heap();
+
+ // check for overflow
+ let checked_len = (ptr as usize)
+ .checked_add(len)
+ .ok_or(host::__WASI_EFAULT as host::__wasi_errno_t)?;
+ if checked_len > heap.len() {
+ bail_errno!(__WASI_EFAULT);
+ }
+ // translate the pointer
+ Ok(unsafe { heap.as_ptr().offset(ptr as isize) })
+}
+
+pub fn dec_ptr_mut(
+ vmctx: &Vmctx,
+ ptr: wasm32::uintptr_t,
+ len: usize,
+) -> Result<*mut u8, host::__wasi_errno_t> {
+ let mut heap = vmctx.heap_mut();
+
+ // check for overflow
+ let checked_len = (ptr as usize)
+ .checked_add(len)
+ .ok_or(host::__WASI_EFAULT as host::__wasi_errno_t)?;
+ if checked_len > heap.len() {
+ bail_errno!(__WASI_EFAULT);
+ }
+ // translate the pointer
+ Ok(unsafe { heap.as_mut_ptr().offset(ptr as isize) })
+}
+
+pub fn dec_ptr_to<T>(
+ vmctx: &Vmctx,
+ ptr: wasm32::uintptr_t,
+) -> Result<*const T, host::__wasi_errno_t> {
+ // check that the ptr is aligned
+ if ptr as usize % align_of::<T>() != 0 {
+ bail_errno!(__WASI_EINVAL);
+ }
+ dec_ptr(vmctx, ptr, size_of::<T>()).map(|p| p as *const T)
+}
+
+pub fn dec_ptr_to_mut<T>(
+ vmctx: &Vmctx,
+ 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);
+ }
+ dec_ptr_mut(vmctx, ptr, size_of::<T>()).map(|p| p as *mut T)
+}
+
+pub fn dec_pointee<T>(vmctx: &Vmctx, ptr: wasm32::uintptr_t) -> Result<T, host::__wasi_errno_t> {
+ dec_ptr_to::<T>(vmctx, ptr).map(|p| unsafe { p.read() })
+}
+
+pub fn enc_pointee<T>(
+ vmctx: &Vmctx,
+ ptr: wasm32::uintptr_t,
+ t: T,
+) -> Result<(), host::__wasi_errno_t> {
+ dec_ptr_to_mut::<T>(vmctx, ptr).map(|p| unsafe { p.write(t) })
+}
+
+fn check_slice_of<T>(
+ ptr: wasm32::uintptr_t,
+ len: wasm32::size_t,
+) -> Result<(usize, usize), host::__wasi_errno_t> {
+ // check alignment, and that length doesn't overflow
+ if ptr as usize % align_of::<T>() != 0 {
+ bail_errno!(__WASI_EINVAL);
+ }
+ let len = dec_usize(len);
+ let len_bytes = if let Some(len) = size_of::<T>().checked_mul(len) {
+ len
+ } else {
+ bail_errno!(__WASI_EOVERFLOW);
+ };
+ Ok((len, len_bytes))
+}
+
+pub fn dec_slice_of<'vmctx, T>(
+ vmctx: &'vmctx Vmctx,
+ ptr: wasm32::uintptr_t,
+ len: wasm32::size_t,
+) -> Result<&'vmctx [T], host::__wasi_errno_t> {
+ let (len, len_bytes) = check_slice_of::<T>(ptr, len)?;
+ let ptr = dec_ptr(vmctx, ptr, len_bytes)? as *const T;
+ Ok(unsafe { slice::from_raw_parts(ptr, len) })
+}
+
+pub fn dec_slice_of_mut<'vmctx, T>(
+ vmctx: &'vmctx Vmctx,
+ ptr: wasm32::uintptr_t,
+ len: wasm32::size_t,
+) -> Result<&'vmctx mut [T], host::__wasi_errno_t> {
+ let (len, len_bytes) = check_slice_of::<T>(ptr, len)?;
+ let ptr = dec_ptr_mut(vmctx, ptr, len_bytes)? as *mut T;
+ Ok(unsafe { slice::from_raw_parts_mut(ptr, len) })
+}
+
+pub fn enc_slice_of<T>(
+ vmctx: &Vmctx,
+ 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 = dec_ptr(vmctx, ptr, len_bytes)? as *mut libc::c_void;
+ unsafe { std::ptr::copy_nonoverlapping(slice.as_ptr() as *const libc::c_void, ptr, 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 fn $dec_byref(
+ vmctx: &Vmctx,
+ 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 fn $enc_byref(
+ vmctx: &Vmctx,
+ ptr: wasm32::uintptr_t,
+ x: host::$ty,
+ ) -> Result<(), host::__wasi_errno_t> {
+ enc_pointee::<wasm32::$ty>(vmctx, ptr, $enc(x))
+ }
+ };
+}
+
+pub fn dec_ciovec(
+ vmctx: &Vmctx,
+ 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: dec_ptr(vmctx, ciovec.buf, len)? as *const host::void,
+ buf_len: len,
+ })
+}
+
+pub fn dec_ciovec_slice(
+ vmctx: &Vmctx,
+ 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)?;
+ slice.iter().map(|iov| dec_ciovec(vmctx, iov)).collect()
+}
+
+pub fn dec_iovec(
+ vmctx: &Vmctx,
+ iovec: &wasm32::__wasi_iovec_t,
+) -> Result<host::__wasi_iovec_t, host::__wasi_errno_t> {
+ let len = dec_usize(iovec.buf_len);
+ Ok(host::__wasi_iovec_t {
+ buf: dec_ptr(vmctx, iovec.buf, len)? as *mut host::void,
+ buf_len: len,
+ })
+}
+
+pub fn dec_iovec_slice(
+ vmctx: &Vmctx,
+ ptr: wasm32::uintptr_t,
+ len: wasm32::size_t,
+) -> Result<Vec<host::__wasi_iovec_t>, host::__wasi_errno_t> {
+ let slice = dec_slice_of::<wasm32::__wasi_iovec_t>(vmctx, ptr, len)?;
+ slice.iter().map(|iov| dec_iovec(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 fn dec_filestat_byref(
+ vmctx: &Vmctx,
+ 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 fn enc_filestat_byref(
+ vmctx: &Vmctx,
+ 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 fn dec_fdstat_byref(
+ vmctx: &Vmctx,
+ 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 fn enc_fdstat_byref(
+ vmctx: &Vmctx,
+ 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 fn dec_prestat_byref(
+ vmctx: &Vmctx,
+ 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 u32::from(prestat.pr_type) {
+ 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 fn enc_prestat_byref(
+ vmctx: &Vmctx,
+ 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_u32(x: u32) -> u32 {
+ u32::from_le(x)
+}
+
+pub fn enc_u32(x: u32) -> u32 {
+ x.to_le()
+}
+
+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 fn enc_usize_byref(
+ vmctx: &Vmctx,
+ 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,
+ }
+}
+
+dec_enc_scalar!(
+ __wasi_advice_t,
+ dec_advice,
+ dec_advice_byref,
+ enc_advice,
+ enc_advice_byref
+);
+
+dec_enc_scalar!(
+ __wasi_fstflags_t,
+ dec_fstflags,
+ dec_fstflags_byref,
+ enc_fstflags,
+ enc_fstflags_byref
+);
+
+dec_enc_scalar!(
+ __wasi_dircookie_t,
+ dec_dircookie,
+ dec_dircookie_byref,
+ enc_dircookie,
+ enc_dircookie_byref
+);
+
+#[cfg(target_os = "linux")]
+pub fn dirent_from_host(
+ host_entry: &nix::libc::dirent,
+) -> Result<wasm32::__wasi_dirent_t, host::__wasi_errno_t> {
+ let mut entry = unsafe { std::mem::zeroed::<wasm32::__wasi_dirent_t>() };
+ let d_namlen = unsafe { std::ffi::CStr::from_ptr(host_entry.d_name.as_ptr()) }
+ .to_bytes()
+ .len();
+ if d_namlen > u32::max_value() as usize {
+ return Err(host::__WASI_EIO as host::__wasi_errno_t);
+ }
+ entry.d_ino = enc_inode(host_entry.d_ino);
+ entry.d_next = enc_dircookie(host_entry.d_off as u64);
+ entry.d_namlen = enc_u32(d_namlen as u32);
+ entry.d_type = enc_filetype(host_entry.d_type);
+ Ok(entry)
+}
+
+#[cfg(not(target_os = "linux"))]
+pub fn dirent_from_host(
+ host_entry: &nix::libc::dirent,
+) -> Result<wasm32::__wasi_dirent_t, host::__wasi_errno_t> {
+ let mut entry = unsafe { std::mem::zeroed::<wasm32::__wasi_dirent_t>() };
+ entry.d_ino = enc_inode(host_entry.d_ino);
+ entry.d_next = enc_dircookie(host_entry.d_seekoff);
+ entry.d_namlen = enc_u32(u32::from(host_entry.d_namlen));
+ entry.d_type = enc_filetype(host_entry.d_type);
+ Ok(entry)
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/src/wasi_host.rs b/third_party/rust/lucet-wasi-wasmsbx/src/wasi_host.rs
new file mode 100644
index 0000000000..08ae163634
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/src/wasi_host.rs
@@ -0,0 +1,1035 @@
+/* automatically generated by rust-bindgen */
+
+pub const __WASI_ADVICE_NORMAL: u32 = 0;
+pub const __WASI_ADVICE_SEQUENTIAL: u32 = 1;
+pub const __WASI_ADVICE_RANDOM: u32 = 2;
+pub const __WASI_ADVICE_WILLNEED: u32 = 3;
+pub const __WASI_ADVICE_DONTNEED: u32 = 4;
+pub const __WASI_ADVICE_NOREUSE: u32 = 5;
+pub const __WASI_CLOCK_REALTIME: u32 = 0;
+pub const __WASI_CLOCK_MONOTONIC: u32 = 1;
+pub const __WASI_CLOCK_PROCESS_CPUTIME_ID: u32 = 2;
+pub const __WASI_CLOCK_THREAD_CPUTIME_ID: u32 = 3;
+pub const __WASI_DIRCOOKIE_START: u32 = 0;
+pub const __WASI_ESUCCESS: u32 = 0;
+pub const __WASI_E2BIG: u32 = 1;
+pub const __WASI_EACCES: u32 = 2;
+pub const __WASI_EADDRINUSE: u32 = 3;
+pub const __WASI_EADDRNOTAVAIL: u32 = 4;
+pub const __WASI_EAFNOSUPPORT: u32 = 5;
+pub const __WASI_EAGAIN: u32 = 6;
+pub const __WASI_EALREADY: u32 = 7;
+pub const __WASI_EBADF: u32 = 8;
+pub const __WASI_EBADMSG: u32 = 9;
+pub const __WASI_EBUSY: u32 = 10;
+pub const __WASI_ECANCELED: u32 = 11;
+pub const __WASI_ECHILD: u32 = 12;
+pub const __WASI_ECONNABORTED: u32 = 13;
+pub const __WASI_ECONNREFUSED: u32 = 14;
+pub const __WASI_ECONNRESET: u32 = 15;
+pub const __WASI_EDEADLK: u32 = 16;
+pub const __WASI_EDESTADDRREQ: u32 = 17;
+pub const __WASI_EDOM: u32 = 18;
+pub const __WASI_EDQUOT: u32 = 19;
+pub const __WASI_EEXIST: u32 = 20;
+pub const __WASI_EFAULT: u32 = 21;
+pub const __WASI_EFBIG: u32 = 22;
+pub const __WASI_EHOSTUNREACH: u32 = 23;
+pub const __WASI_EIDRM: u32 = 24;
+pub const __WASI_EILSEQ: u32 = 25;
+pub const __WASI_EINPROGRESS: u32 = 26;
+pub const __WASI_EINTR: u32 = 27;
+pub const __WASI_EINVAL: u32 = 28;
+pub const __WASI_EIO: u32 = 29;
+pub const __WASI_EISCONN: u32 = 30;
+pub const __WASI_EISDIR: u32 = 31;
+pub const __WASI_ELOOP: u32 = 32;
+pub const __WASI_EMFILE: u32 = 33;
+pub const __WASI_EMLINK: u32 = 34;
+pub const __WASI_EMSGSIZE: u32 = 35;
+pub const __WASI_EMULTIHOP: u32 = 36;
+pub const __WASI_ENAMETOOLONG: u32 = 37;
+pub const __WASI_ENETDOWN: u32 = 38;
+pub const __WASI_ENETRESET: u32 = 39;
+pub const __WASI_ENETUNREACH: u32 = 40;
+pub const __WASI_ENFILE: u32 = 41;
+pub const __WASI_ENOBUFS: u32 = 42;
+pub const __WASI_ENODEV: u32 = 43;
+pub const __WASI_ENOENT: u32 = 44;
+pub const __WASI_ENOEXEC: u32 = 45;
+pub const __WASI_ENOLCK: u32 = 46;
+pub const __WASI_ENOLINK: u32 = 47;
+pub const __WASI_ENOMEM: u32 = 48;
+pub const __WASI_ENOMSG: u32 = 49;
+pub const __WASI_ENOPROTOOPT: u32 = 50;
+pub const __WASI_ENOSPC: u32 = 51;
+pub const __WASI_ENOSYS: u32 = 52;
+pub const __WASI_ENOTCONN: u32 = 53;
+pub const __WASI_ENOTDIR: u32 = 54;
+pub const __WASI_ENOTEMPTY: u32 = 55;
+pub const __WASI_ENOTRECOVERABLE: u32 = 56;
+pub const __WASI_ENOTSOCK: u32 = 57;
+pub const __WASI_ENOTSUP: u32 = 58;
+pub const __WASI_ENOTTY: u32 = 59;
+pub const __WASI_ENXIO: u32 = 60;
+pub const __WASI_EOVERFLOW: u32 = 61;
+pub const __WASI_EOWNERDEAD: u32 = 62;
+pub const __WASI_EPERM: u32 = 63;
+pub const __WASI_EPIPE: u32 = 64;
+pub const __WASI_EPROTO: u32 = 65;
+pub const __WASI_EPROTONOSUPPORT: u32 = 66;
+pub const __WASI_EPROTOTYPE: u32 = 67;
+pub const __WASI_ERANGE: u32 = 68;
+pub const __WASI_EROFS: u32 = 69;
+pub const __WASI_ESPIPE: u32 = 70;
+pub const __WASI_ESRCH: u32 = 71;
+pub const __WASI_ESTALE: u32 = 72;
+pub const __WASI_ETIMEDOUT: u32 = 73;
+pub const __WASI_ETXTBSY: u32 = 74;
+pub const __WASI_EXDEV: u32 = 75;
+pub const __WASI_ENOTCAPABLE: u32 = 76;
+pub const __WASI_EVENT_FD_READWRITE_HANGUP: u32 = 1;
+pub const __WASI_EVENTTYPE_CLOCK: u32 = 0;
+pub const __WASI_EVENTTYPE_FD_READ: u32 = 1;
+pub const __WASI_EVENTTYPE_FD_WRITE: u32 = 2;
+pub const __WASI_FDFLAG_APPEND: u32 = 1;
+pub const __WASI_FDFLAG_DSYNC: u32 = 2;
+pub const __WASI_FDFLAG_NONBLOCK: u32 = 4;
+pub const __WASI_FDFLAG_RSYNC: u32 = 8;
+pub const __WASI_FDFLAG_SYNC: u32 = 16;
+pub const __WASI_FILETYPE_UNKNOWN: u32 = 0;
+pub const __WASI_FILETYPE_BLOCK_DEVICE: u32 = 1;
+pub const __WASI_FILETYPE_CHARACTER_DEVICE: u32 = 2;
+pub const __WASI_FILETYPE_DIRECTORY: u32 = 3;
+pub const __WASI_FILETYPE_REGULAR_FILE: u32 = 4;
+pub const __WASI_FILETYPE_SOCKET_DGRAM: u32 = 5;
+pub const __WASI_FILETYPE_SOCKET_STREAM: u32 = 6;
+pub const __WASI_FILETYPE_SYMBOLIC_LINK: u32 = 7;
+pub const __WASI_FILESTAT_SET_ATIM: u32 = 1;
+pub const __WASI_FILESTAT_SET_ATIM_NOW: u32 = 2;
+pub const __WASI_FILESTAT_SET_MTIM: u32 = 4;
+pub const __WASI_FILESTAT_SET_MTIM_NOW: u32 = 8;
+pub const __WASI_LOOKUP_SYMLINK_FOLLOW: u32 = 1;
+pub const __WASI_O_CREAT: u32 = 1;
+pub const __WASI_O_DIRECTORY: u32 = 2;
+pub const __WASI_O_EXCL: u32 = 4;
+pub const __WASI_O_TRUNC: u32 = 8;
+pub const __WASI_SOCK_RECV_PEEK: u32 = 1;
+pub const __WASI_SOCK_RECV_WAITALL: u32 = 2;
+pub const __WASI_RIGHT_FD_DATASYNC: u32 = 1;
+pub const __WASI_RIGHT_FD_READ: u32 = 2;
+pub const __WASI_RIGHT_FD_SEEK: u32 = 4;
+pub const __WASI_RIGHT_FD_FDSTAT_SET_FLAGS: u32 = 8;
+pub const __WASI_RIGHT_FD_SYNC: u32 = 16;
+pub const __WASI_RIGHT_FD_TELL: u32 = 32;
+pub const __WASI_RIGHT_FD_WRITE: u32 = 64;
+pub const __WASI_RIGHT_FD_ADVISE: u32 = 128;
+pub const __WASI_RIGHT_FD_ALLOCATE: u32 = 256;
+pub const __WASI_RIGHT_PATH_CREATE_DIRECTORY: u32 = 512;
+pub const __WASI_RIGHT_PATH_CREATE_FILE: u32 = 1024;
+pub const __WASI_RIGHT_PATH_LINK_SOURCE: u32 = 2048;
+pub const __WASI_RIGHT_PATH_LINK_TARGET: u32 = 4096;
+pub const __WASI_RIGHT_PATH_OPEN: u32 = 8192;
+pub const __WASI_RIGHT_FD_READDIR: u32 = 16384;
+pub const __WASI_RIGHT_PATH_READLINK: u32 = 32768;
+pub const __WASI_RIGHT_PATH_RENAME_SOURCE: u32 = 65536;
+pub const __WASI_RIGHT_PATH_RENAME_TARGET: u32 = 131072;
+pub const __WASI_RIGHT_PATH_FILESTAT_GET: u32 = 262144;
+pub const __WASI_RIGHT_PATH_FILESTAT_SET_SIZE: u32 = 524288;
+pub const __WASI_RIGHT_PATH_FILESTAT_SET_TIMES: u32 = 1048576;
+pub const __WASI_RIGHT_FD_FILESTAT_GET: u32 = 2097152;
+pub const __WASI_RIGHT_FD_FILESTAT_SET_SIZE: u32 = 4194304;
+pub const __WASI_RIGHT_FD_FILESTAT_SET_TIMES: u32 = 8388608;
+pub const __WASI_RIGHT_PATH_SYMLINK: u32 = 16777216;
+pub const __WASI_RIGHT_PATH_REMOVE_DIRECTORY: u32 = 33554432;
+pub const __WASI_RIGHT_PATH_UNLINK_FILE: u32 = 67108864;
+pub const __WASI_RIGHT_POLL_FD_READWRITE: u32 = 134217728;
+pub const __WASI_RIGHT_SOCK_SHUTDOWN: u32 = 268435456;
+pub const __WASI_SOCK_RECV_DATA_TRUNCATED: u32 = 1;
+pub const __WASI_SHUT_RD: u32 = 1;
+pub const __WASI_SHUT_WR: u32 = 2;
+pub const __WASI_SIGHUP: u32 = 1;
+pub const __WASI_SIGINT: u32 = 2;
+pub const __WASI_SIGQUIT: u32 = 3;
+pub const __WASI_SIGILL: u32 = 4;
+pub const __WASI_SIGTRAP: u32 = 5;
+pub const __WASI_SIGABRT: u32 = 6;
+pub const __WASI_SIGBUS: u32 = 7;
+pub const __WASI_SIGFPE: u32 = 8;
+pub const __WASI_SIGKILL: u32 = 9;
+pub const __WASI_SIGUSR1: u32 = 10;
+pub const __WASI_SIGSEGV: u32 = 11;
+pub const __WASI_SIGUSR2: u32 = 12;
+pub const __WASI_SIGPIPE: u32 = 13;
+pub const __WASI_SIGALRM: u32 = 14;
+pub const __WASI_SIGTERM: u32 = 15;
+pub const __WASI_SIGCHLD: u32 = 16;
+pub const __WASI_SIGCONT: u32 = 17;
+pub const __WASI_SIGSTOP: u32 = 18;
+pub const __WASI_SIGTSTP: u32 = 19;
+pub const __WASI_SIGTTIN: u32 = 20;
+pub const __WASI_SIGTTOU: u32 = 21;
+pub const __WASI_SIGURG: u32 = 22;
+pub const __WASI_SIGXCPU: u32 = 23;
+pub const __WASI_SIGXFSZ: u32 = 24;
+pub const __WASI_SIGVTALRM: u32 = 25;
+pub const __WASI_SIGPROF: u32 = 26;
+pub const __WASI_SIGWINCH: u32 = 27;
+pub const __WASI_SIGPOLL: u32 = 28;
+pub const __WASI_SIGPWR: u32 = 29;
+pub const __WASI_SIGSYS: u32 = 30;
+pub const __WASI_SUBSCRIPTION_CLOCK_ABSTIME: u32 = 1;
+pub const __WASI_WHENCE_CUR: u32 = 0;
+pub const __WASI_WHENCE_END: u32 = 1;
+pub const __WASI_WHENCE_SET: u32 = 2;
+pub const __WASI_PREOPENTYPE_DIR: u32 = 0;
+pub type __wasi_advice_t = u8;
+pub type __wasi_clockid_t = u32;
+pub type __wasi_device_t = u64;
+pub type __wasi_dircookie_t = u64;
+pub type __wasi_errno_t = u16;
+pub type __wasi_eventrwflags_t = u16;
+pub type __wasi_eventtype_t = u8;
+pub type __wasi_exitcode_t = u32;
+pub type __wasi_fd_t = u32;
+pub type __wasi_fdflags_t = u16;
+pub type __wasi_filedelta_t = i64;
+pub type __wasi_filesize_t = u64;
+pub type __wasi_filetype_t = u8;
+pub type __wasi_fstflags_t = u16;
+pub type __wasi_inode_t = u64;
+pub type __wasi_linkcount_t = u32;
+pub type __wasi_lookupflags_t = u32;
+pub type __wasi_oflags_t = u16;
+pub type __wasi_riflags_t = u16;
+pub type __wasi_rights_t = u64;
+pub type __wasi_roflags_t = u16;
+pub type __wasi_sdflags_t = u8;
+pub type __wasi_siflags_t = u16;
+pub type __wasi_signal_t = u8;
+pub type __wasi_subclockflags_t = u16;
+pub type __wasi_timestamp_t = u64;
+pub type __wasi_userdata_t = u64;
+pub type __wasi_whence_t = u8;
+pub type __wasi_preopentype_t = u8;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_dirent_t {
+ pub d_next: __wasi_dircookie_t,
+ pub d_ino: __wasi_inode_t,
+ pub d_namlen: u32,
+ pub d_type: __wasi_filetype_t,
+}
+#[test]
+fn bindgen_test_layout___wasi_dirent_t() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_dirent_t>(),
+ 24usize,
+ concat!("Size of: ", stringify!(__wasi_dirent_t))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_dirent_t>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(__wasi_dirent_t))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_next as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_dirent_t),
+ "::",
+ stringify!(d_next)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_ino as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_dirent_t),
+ "::",
+ stringify!(d_ino)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_namlen as *const _ as usize },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_dirent_t),
+ "::",
+ stringify!(d_namlen)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_type as *const _ as usize },
+ 20usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_dirent_t),
+ "::",
+ stringify!(d_type)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct __wasi_event_t {
+ pub userdata: __wasi_userdata_t,
+ pub error: __wasi_errno_t,
+ pub type_: __wasi_eventtype_t,
+ pub u: __wasi_event_t___wasi_event_u,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union __wasi_event_t___wasi_event_u {
+ pub fd_readwrite: __wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t,
+ _bindgen_union_align: [u64; 2usize],
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t {
+ pub nbytes: __wasi_filesize_t,
+ pub flags: __wasi_eventrwflags_t,
+}
+#[test]
+fn bindgen_test_layout___wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t>(),
+ 16usize,
+ concat!(
+ "Size of: ",
+ stringify!(__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t)
+ )
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t>(),
+ 8usize,
+ concat!(
+ "Alignment of ",
+ stringify!(__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t>()))
+ .nbytes as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t),
+ "::",
+ stringify!(nbytes)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t>()))
+ .flags as *const _ as usize
+ },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_event_t___wasi_event_u___wasi_event_u_fd_readwrite_t),
+ "::",
+ stringify!(flags)
+ )
+ );
+}
+#[test]
+fn bindgen_test_layout___wasi_event_t___wasi_event_u() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_event_t___wasi_event_u>(),
+ 16usize,
+ concat!("Size of: ", stringify!(__wasi_event_t___wasi_event_u))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_event_t___wasi_event_u>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(__wasi_event_t___wasi_event_u))
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_event_t___wasi_event_u>())).fd_readwrite as *const _
+ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_event_t___wasi_event_u),
+ "::",
+ stringify!(fd_readwrite)
+ )
+ );
+}
+#[test]
+fn bindgen_test_layout___wasi_event_t() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_event_t>(),
+ 32usize,
+ concat!("Size of: ", stringify!(__wasi_event_t))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_event_t>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(__wasi_event_t))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_event_t>())).userdata as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_event_t),
+ "::",
+ stringify!(userdata)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_event_t>())).error as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_event_t),
+ "::",
+ stringify!(error)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_event_t>())).type_ as *const _ as usize },
+ 10usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_event_t),
+ "::",
+ stringify!(type_)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_event_t>())).u as *const _ as usize },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_event_t),
+ "::",
+ stringify!(u)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct __wasi_prestat_t {
+ pub pr_type: __wasi_preopentype_t,
+ pub u: __wasi_prestat_t___wasi_prestat_u,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union __wasi_prestat_t___wasi_prestat_u {
+ pub dir: __wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t,
+ _bindgen_union_align: u64,
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t {
+ pub pr_name_len: usize,
+}
+#[test]
+fn bindgen_test_layout___wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t>(),
+ 8usize,
+ concat!(
+ "Size of: ",
+ stringify!(__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t)
+ )
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t>(),
+ 8usize,
+ concat!(
+ "Alignment of ",
+ stringify!(__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t>()))
+ .pr_name_len as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t),
+ "::",
+ stringify!(pr_name_len)
+ )
+ );
+}
+#[test]
+fn bindgen_test_layout___wasi_prestat_t___wasi_prestat_u() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_prestat_t___wasi_prestat_u>(),
+ 8usize,
+ concat!("Size of: ", stringify!(__wasi_prestat_t___wasi_prestat_u))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_prestat_t___wasi_prestat_u>(),
+ 8usize,
+ concat!(
+ "Alignment of ",
+ stringify!(__wasi_prestat_t___wasi_prestat_u)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_prestat_t___wasi_prestat_u>())).dir as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_prestat_t___wasi_prestat_u),
+ "::",
+ stringify!(dir)
+ )
+ );
+}
+#[test]
+fn bindgen_test_layout___wasi_prestat_t() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_prestat_t>(),
+ 16usize,
+ concat!("Size of: ", stringify!(__wasi_prestat_t))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_prestat_t>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(__wasi_prestat_t))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_prestat_t>())).pr_type as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_prestat_t),
+ "::",
+ stringify!(pr_type)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_prestat_t>())).u as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_prestat_t),
+ "::",
+ stringify!(u)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_fdstat_t {
+ pub fs_filetype: __wasi_filetype_t,
+ pub fs_flags: __wasi_fdflags_t,
+ pub fs_rights_base: __wasi_rights_t,
+ pub fs_rights_inheriting: __wasi_rights_t,
+}
+#[test]
+fn bindgen_test_layout___wasi_fdstat_t() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_fdstat_t>(),
+ 24usize,
+ concat!("Size of: ", stringify!(__wasi_fdstat_t))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_fdstat_t>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(__wasi_fdstat_t))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_filetype as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_fdstat_t),
+ "::",
+ stringify!(fs_filetype)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_flags as *const _ as usize },
+ 2usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_fdstat_t),
+ "::",
+ stringify!(fs_flags)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_rights_base as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_fdstat_t),
+ "::",
+ stringify!(fs_rights_base)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_rights_inheriting as *const _ as usize
+ },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_fdstat_t),
+ "::",
+ stringify!(fs_rights_inheriting)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_filestat_t {
+ pub st_dev: __wasi_device_t,
+ pub st_ino: __wasi_inode_t,
+ pub st_filetype: __wasi_filetype_t,
+ pub st_nlink: __wasi_linkcount_t,
+ pub st_size: __wasi_filesize_t,
+ pub st_atim: __wasi_timestamp_t,
+ pub st_mtim: __wasi_timestamp_t,
+ pub st_ctim: __wasi_timestamp_t,
+}
+#[test]
+fn bindgen_test_layout___wasi_filestat_t() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_filestat_t>(),
+ 56usize,
+ concat!("Size of: ", stringify!(__wasi_filestat_t))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_filestat_t>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(__wasi_filestat_t))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_dev as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_filestat_t),
+ "::",
+ stringify!(st_dev)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_ino as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_filestat_t),
+ "::",
+ stringify!(st_ino)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_filetype as *const _ as usize },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_filestat_t),
+ "::",
+ stringify!(st_filetype)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_nlink as *const _ as usize },
+ 20usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_filestat_t),
+ "::",
+ stringify!(st_nlink)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_size as *const _ as usize },
+ 24usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_filestat_t),
+ "::",
+ stringify!(st_size)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_atim as *const _ as usize },
+ 32usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_filestat_t),
+ "::",
+ stringify!(st_atim)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_mtim as *const _ as usize },
+ 40usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_filestat_t),
+ "::",
+ stringify!(st_mtim)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_ctim as *const _ as usize },
+ 48usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_filestat_t),
+ "::",
+ stringify!(st_ctim)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_ciovec_t {
+ pub buf: *const ::std::os::raw::c_void,
+ pub buf_len: usize,
+}
+#[test]
+fn bindgen_test_layout___wasi_ciovec_t() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_ciovec_t>(),
+ 16usize,
+ concat!("Size of: ", stringify!(__wasi_ciovec_t))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_ciovec_t>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(__wasi_ciovec_t))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_ciovec_t>())).buf as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_ciovec_t),
+ "::",
+ stringify!(buf)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_ciovec_t>())).buf_len as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_ciovec_t),
+ "::",
+ stringify!(buf_len)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_iovec_t {
+ pub buf: *mut ::std::os::raw::c_void,
+ pub buf_len: usize,
+}
+#[test]
+fn bindgen_test_layout___wasi_iovec_t() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_iovec_t>(),
+ 16usize,
+ concat!("Size of: ", stringify!(__wasi_iovec_t))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_iovec_t>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(__wasi_iovec_t))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_iovec_t>())).buf as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_iovec_t),
+ "::",
+ stringify!(buf)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_iovec_t>())).buf_len as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_iovec_t),
+ "::",
+ stringify!(buf_len)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct __wasi_subscription_t {
+ pub userdata: __wasi_userdata_t,
+ pub type_: __wasi_eventtype_t,
+ pub u: __wasi_subscription_t___wasi_subscription_u,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union __wasi_subscription_t___wasi_subscription_u {
+ pub clock: __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t,
+ pub fd_readwrite:
+ __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t,
+ _bindgen_union_align: [u64; 5usize],
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t {
+ pub identifier: __wasi_userdata_t,
+ pub clock_id: __wasi_clockid_t,
+ pub timeout: __wasi_timestamp_t,
+ pub precision: __wasi_timestamp_t,
+ pub flags: __wasi_subclockflags_t,
+}
+#[test]
+fn bindgen_test_layout___wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t() {
+ assert_eq!(
+ ::std::mem::size_of::<
+ __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t,
+ >(),
+ 40usize,
+ concat!(
+ "Size of: ",
+ stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t)
+ )
+ );
+ assert_eq!(
+ ::std::mem::align_of::<
+ __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t,
+ >(),
+ 8usize,
+ concat!(
+ "Alignment of ",
+ stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<
+ __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t,
+ >()))
+ .identifier as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t),
+ "::",
+ stringify!(identifier)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<
+ __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t,
+ >()))
+ .clock_id as *const _ as usize
+ },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t),
+ "::",
+ stringify!(clock_id)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<
+ __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t,
+ >()))
+ .timeout as *const _ as usize
+ },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t),
+ "::",
+ stringify!(timeout)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<
+ __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t,
+ >()))
+ .precision as *const _ as usize
+ },
+ 24usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t),
+ "::",
+ stringify!(precision)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<
+ __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t,
+ >()))
+ .flags as *const _ as usize
+ },
+ 32usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_clock_t),
+ "::",
+ stringify!(flags)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t {
+ pub fd: __wasi_fd_t,
+}
+#[test]
+fn bindgen_test_layout___wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t(
+) {
+ assert_eq!(
+ ::std::mem::size_of::<
+ __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t,
+ >(),
+ 4usize,
+ concat!(
+ "Size of: ",
+ stringify!(
+ __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t
+ )
+ )
+ );
+ assert_eq!(
+ ::std::mem::align_of::<
+ __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t,
+ >(),
+ 4usize,
+ concat!(
+ "Alignment of ",
+ stringify!(
+ __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t
+ )
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<
+ __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t,
+ >()))
+ .fd as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(
+ __wasi_subscription_t___wasi_subscription_u___wasi_subscription_u_fd_readwrite_t
+ ),
+ "::",
+ stringify!(fd)
+ )
+ );
+}
+#[test]
+fn bindgen_test_layout___wasi_subscription_t___wasi_subscription_u() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_subscription_t___wasi_subscription_u>(),
+ 40usize,
+ concat!(
+ "Size of: ",
+ stringify!(__wasi_subscription_t___wasi_subscription_u)
+ )
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_subscription_t___wasi_subscription_u>(),
+ 8usize,
+ concat!(
+ "Alignment of ",
+ stringify!(__wasi_subscription_t___wasi_subscription_u)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_subscription_t___wasi_subscription_u>())).clock
+ as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t___wasi_subscription_u),
+ "::",
+ stringify!(clock)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_subscription_t___wasi_subscription_u>())).fd_readwrite
+ as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t___wasi_subscription_u),
+ "::",
+ stringify!(fd_readwrite)
+ )
+ );
+}
+#[test]
+fn bindgen_test_layout___wasi_subscription_t() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_subscription_t>(),
+ 56usize,
+ concat!("Size of: ", stringify!(__wasi_subscription_t))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_subscription_t>(),
+ 8usize,
+ concat!("Alignment of ", stringify!(__wasi_subscription_t))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_subscription_t>())).userdata as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t),
+ "::",
+ stringify!(userdata)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_subscription_t>())).type_ as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t),
+ "::",
+ stringify!(type_)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_subscription_t>())).u as *const _ as usize },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t),
+ "::",
+ stringify!(u)
+ )
+ );
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/src/wasm32.rs b/third_party/rust/lucet-wasi-wasmsbx/src/wasm32.rs
new file mode 100644
index 0000000000..9983b37907
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/src/wasm32.rs
@@ -0,0 +1,1367 @@
+//! WASI types as defined in wasm32. This file was originally generated
+//! by running bindgen over wasi/core.h with a wasm32 target, and the content
+//! still largely reflects that, however it's been heavily modified, to
+//! be host-independent, to avoid exposing libc implementation details,
+//! to clean up cases where the headers use complex preprocessor macros,
+//! and to
+
+#![allow(non_camel_case_types)]
+#![allow(non_snake_case)]
+#![allow(dead_code)]
+
+// C types
+pub type char = i8;
+pub type schar = i8;
+pub type uchar = u8;
+pub type short = i16;
+pub type ushort = u16;
+pub type int = i32;
+pub type uint = u32;
+pub type long = i32;
+pub type ulong = u32;
+pub type longlong = i64;
+pub type ulonglong = u64;
+
+// libc stdint types
+pub type int8_t = i8;
+pub type uint8_t = u8;
+pub type int16_t = i16;
+pub type uint16_t = u16;
+pub type int32_t = i32;
+pub type uint32_t = u32;
+pub type int64_t = i64;
+pub type uint64_t = u64;
+pub type intmax_t = i64;
+pub type uintmax_t = u64;
+pub type int_least8_t = i8;
+pub type int_least16_t = i16;
+pub type int_least32_t = i32;
+pub type int_least64_t = i64;
+pub type uint_least8_t = u8;
+pub type uint_least16_t = u16;
+pub type uint_least32_t = u32;
+pub type uint_least64_t = u64;
+pub type int_fast8_t = i8;
+pub type int_fast16_t = i32;
+pub type int_fast32_t = i32;
+pub type int_fast64_t = i64;
+pub type uint_fast8_t = u8;
+pub type uint_fast16_t = u32;
+pub type uint_fast32_t = u32;
+pub type uint_fast64_t = u64;
+pub type size_t = ulong;
+pub type intptr_t = long;
+pub type uintptr_t = ulong;
+pub type wchar_t = i32;
+
+// libc types
+pub type dev_t = u64;
+pub type uid_t = u32;
+pub type gid_t = u32;
+pub type ino_t = u64;
+pub type ino64_t = u64;
+pub type mode_t = u32;
+pub type nlink_t = u64;
+pub type off_t = i64;
+pub type off64_t = i64;
+pub type pid_t = i32;
+pub type clock_t = i64;
+pub type rlim_t = u64;
+pub type rlim64_t = u64;
+pub type id_t = u32;
+pub type time_t = i64;
+pub type useconds_t = u32;
+pub type suseconds_t = i64;
+pub type daddr_t = i32;
+pub type key_t = i32;
+pub type clockid_t = i32;
+pub type timer_t = uintptr_t; // *mut ::std::os::raw::c_void
+pub type blksize_t = i64;
+pub type blkcnt_t = i64;
+pub type blkcnt64_t = i64;
+pub type fsblkcnt_t = u64;
+pub type fsblkcnt64_t = u64;
+pub type fsfilcnt_t = u64;
+pub type fsfilcnt64_t = u64;
+pub type fsword_t = i64;
+pub type ssize_t = i32;
+pub type loff_t = off64_t;
+pub type caddr_t = uintptr_t; // *mut i8
+pub type socklen_t = u32;
+pub type sig_atomic_t = i32;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct fsid_t {
+ pub __val: [i32; 2usize],
+}
+#[allow(non_snake_case)]
+#[test]
+fn bindgen_test_layout_fsid_t() {
+ assert_eq!(
+ ::std::mem::size_of::<fsid_t>(),
+ 8usize,
+ concat!("Size of: ", stringify!(fsid_t))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<fsid_t>(),
+ 4usize,
+ concat!("Alignment of ", stringify!(fsid_t))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<fsid_t>())).__val as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(fsid_t),
+ "::",
+ stringify!(__val)
+ )
+ );
+}
+
+// WASI types
+pub type __wasi_advice_t = u8;
+pub type __wasi_clockid_t = u32;
+pub type __wasi_device_t = u64;
+pub type __wasi_dircookie_t = u64;
+pub type __wasi_errno_t = u16;
+pub type __wasi_eventrwflags_t = u16;
+pub type __wasi_eventtype_t = u8;
+pub type __wasi_exitcode_t = u32;
+pub type __wasi_fd_t = u32;
+pub type __wasi_fdflags_t = u16;
+pub type __wasi_fdsflags_t = u16;
+pub type __wasi_filedelta_t = i64;
+pub type __wasi_filesize_t = u64;
+pub type __wasi_filetype_t = u8;
+pub type __wasi_preopentype_t = u8;
+pub type __wasi_fstflags_t = u16;
+pub type __wasi_inode_t = u64;
+pub type __wasi_linkcount_t = u32;
+pub type __wasi_lookupflags_t = u32;
+pub type __wasi_oflags_t = u16;
+pub type __wasi_riflags_t = u16;
+pub type __wasi_rights_t = u64;
+pub type __wasi_roflags_t = u16;
+pub type __wasi_sdflags_t = u8;
+pub type __wasi_siflags_t = u16;
+pub type __wasi_signal_t = u8;
+pub type __wasi_subclockflags_t = u16;
+pub type __wasi_timestamp_t = u64;
+pub type __wasi_userdata_t = u64;
+pub type __wasi_whence_t = u8;
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_dirent_t {
+ pub d_next: __wasi_dircookie_t,
+ pub d_ino: __wasi_inode_t,
+ pub d_namlen: u32,
+ pub d_type: __wasi_filetype_t,
+ pub __bindgen_padding_0: [u8; 3usize],
+}
+#[test]
+fn bindgen_test_layout_wasi_dirent_t() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_dirent_t>(),
+ 24usize,
+ concat!("Size of: ", stringify!(__wasi_dirent_t))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_next as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_dirent_t),
+ "::",
+ stringify!(d_next)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_ino as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_dirent_t),
+ "::",
+ stringify!(d_ino)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_namlen as *const _ as usize },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_dirent_t),
+ "::",
+ stringify!(d_namlen)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_dirent_t>())).d_type as *const _ as usize },
+ 20usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_dirent_t),
+ "::",
+ stringify!(d_type)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct __wasi_event_t {
+ pub userdata: __wasi_userdata_t,
+ pub error: __wasi_errno_t,
+ pub type_: __wasi_eventtype_t,
+ pub __bindgen_padding_0: u32,
+ pub __bindgen_anon_1: __wasi_event_t__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct __wasi_prestat_t {
+ pub pr_type: __wasi_preopentype_t,
+ pub u: __wasi_prestat_t___wasi_prestat_u,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union __wasi_prestat_t___wasi_prestat_u {
+ pub dir: __wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t,
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t {
+ pub pr_name_len: size_t,
+}
+#[test]
+fn bindgen_test_layout___wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t>(),
+ 4usize,
+ concat!(
+ "Size of: ",
+ stringify!(__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t)
+ )
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t>(),
+ 4usize,
+ concat!(
+ "Alignment of ",
+ stringify!(__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t>()))
+ .pr_name_len as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_prestat_t___wasi_prestat_u___wasi_prestat_u_dir_t),
+ "::",
+ stringify!(pr_name_len)
+ )
+ );
+}
+#[test]
+fn bindgen_test_layout___wasi_prestat_t___wasi_prestat_u() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_prestat_t___wasi_prestat_u>(),
+ 4usize,
+ concat!("Size of: ", stringify!(__wasi_prestat_t___wasi_prestat_u))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_prestat_t___wasi_prestat_u>(),
+ 4usize,
+ concat!(
+ "Alignment of ",
+ stringify!(__wasi_prestat_t___wasi_prestat_u)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_prestat_t___wasi_prestat_u>())).dir as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_prestat_t___wasi_prestat_u),
+ "::",
+ stringify!(dir)
+ )
+ );
+}
+#[test]
+fn bindgen_test_layout___wasi_prestat_t() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_prestat_t>(),
+ 8usize,
+ concat!("Size of: ", stringify!(__wasi_prestat_t))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_prestat_t>(),
+ 4usize,
+ concat!("Alignment of ", stringify!(__wasi_prestat_t))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_prestat_t>())).pr_type as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_prestat_t),
+ "::",
+ stringify!(pr_type)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_prestat_t>())).u as *const _ as usize },
+ 4usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_prestat_t),
+ "::",
+ stringify!(u)
+ )
+ );
+}
+#[allow(non_snake_case)]
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union __wasi_event_t__bindgen_ty_1 {
+ pub fd_readwrite: __wasi_event_t__bindgen_ty_1__bindgen_ty_1,
+ _bindgen_union_align: [u64; 2usize],
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_event_t__bindgen_ty_1__bindgen_ty_1 {
+ pub nbytes: __wasi_filesize_t,
+ pub flags: __wasi_eventrwflags_t,
+ pub __bindgen_padding_0: [u16; 3usize],
+}
+#[allow(non_snake_case)]
+#[test]
+fn bindgen_test_layout_wasi_event_t__bindgen_ty_1__bindgen_ty_1() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_event_t__bindgen_ty_1__bindgen_ty_1>(),
+ 16usize,
+ concat!(
+ "Size of: ",
+ stringify!(__wasi_event_t__bindgen_ty_1__bindgen_ty_1)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_event_t__bindgen_ty_1__bindgen_ty_1>())).nbytes
+ as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_event_t__bindgen_ty_1__bindgen_ty_1),
+ "::",
+ stringify!(nbytes)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_event_t__bindgen_ty_1__bindgen_ty_1>())).flags as *const _
+ as usize
+ },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_event_t__bindgen_ty_1__bindgen_ty_1),
+ "::",
+ stringify!(flags)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_event_t__bindgen_ty_1__bindgen_ty_2 {
+ pub signal: __wasi_signal_t,
+ pub exitcode: __wasi_exitcode_t,
+}
+#[allow(non_snake_case)]
+#[test]
+fn bindgen_test_layout_wasi_event_t__bindgen_ty_1__bindgen_ty_2() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_event_t__bindgen_ty_1__bindgen_ty_2>(),
+ 8usize,
+ concat!(
+ "Size of: ",
+ stringify!(__wasi_event_t__bindgen_ty_1__bindgen_ty_2)
+ )
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_event_t__bindgen_ty_1__bindgen_ty_2>(),
+ 4usize,
+ concat!(
+ "Alignment of ",
+ stringify!(__wasi_event_t__bindgen_ty_1__bindgen_ty_2)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_event_t__bindgen_ty_1__bindgen_ty_2>())).signal
+ as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_event_t__bindgen_ty_1__bindgen_ty_2),
+ "::",
+ stringify!(signal)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_event_t__bindgen_ty_1__bindgen_ty_2>())).exitcode
+ as *const _ as usize
+ },
+ 4usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_event_t__bindgen_ty_1__bindgen_ty_2),
+ "::",
+ stringify!(exitcode)
+ )
+ );
+}
+#[allow(non_snake_case)]
+#[test]
+fn bindgen_test_layout_wasi_event_t__bindgen_ty_1() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_event_t__bindgen_ty_1>(),
+ 16usize,
+ concat!("Size of: ", stringify!(__wasi_event_t__bindgen_ty_1))
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_event_t__bindgen_ty_1>())).fd_readwrite as *const _
+ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_event_t__bindgen_ty_1),
+ "::",
+ stringify!(fd_readwrite)
+ )
+ );
+}
+#[test]
+fn bindgen_test_layout_wasi_event_t() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_event_t>(),
+ 32usize,
+ concat!("Size of: ", stringify!(__wasi_event_t))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_event_t>())).userdata as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_event_t),
+ "::",
+ stringify!(userdata)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_event_t>())).error as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_event_t),
+ "::",
+ stringify!(error)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_event_t>())).type_ as *const _ as usize },
+ 10usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_event_t),
+ "::",
+ stringify!(type_)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_fdstat_t {
+ pub fs_filetype: __wasi_filetype_t,
+ pub fs_flags: __wasi_fdflags_t,
+ pub __bindgen_padding_0: u32,
+ pub fs_rights_base: __wasi_rights_t,
+ pub fs_rights_inheriting: __wasi_rights_t,
+}
+#[test]
+fn bindgen_test_layout_wasi_fdstat_t() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_fdstat_t>(),
+ 24usize,
+ concat!("Size of: ", stringify!(__wasi_fdstat_t))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_filetype as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_fdstat_t),
+ "::",
+ stringify!(fs_filetype)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_flags as *const _ as usize },
+ 2usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_fdstat_t),
+ "::",
+ stringify!(fs_flags)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_rights_base as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_fdstat_t),
+ "::",
+ stringify!(fs_rights_base)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_fdstat_t>())).fs_rights_inheriting as *const _ as usize
+ },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_fdstat_t),
+ "::",
+ stringify!(fs_rights_inheriting)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_filestat_t {
+ pub st_dev: __wasi_device_t,
+ pub st_ino: __wasi_inode_t,
+ pub st_filetype: __wasi_filetype_t,
+ pub st_nlink: __wasi_linkcount_t,
+ pub st_size: __wasi_filesize_t,
+ pub st_atim: __wasi_timestamp_t,
+ pub st_mtim: __wasi_timestamp_t,
+ pub st_ctim: __wasi_timestamp_t,
+}
+#[test]
+fn bindgen_test_layout_wasi_filestat_t() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_filestat_t>(),
+ 56usize,
+ concat!("Size of: ", stringify!(__wasi_filestat_t))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_dev as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_filestat_t),
+ "::",
+ stringify!(st_dev)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_ino as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_filestat_t),
+ "::",
+ stringify!(st_ino)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_filetype as *const _ as usize },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_filestat_t),
+ "::",
+ stringify!(st_filetype)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_nlink as *const _ as usize },
+ 20usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_filestat_t),
+ "::",
+ stringify!(st_nlink)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_size as *const _ as usize },
+ 24usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_filestat_t),
+ "::",
+ stringify!(st_size)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_atim as *const _ as usize },
+ 32usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_filestat_t),
+ "::",
+ stringify!(st_atim)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_mtim as *const _ as usize },
+ 40usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_filestat_t),
+ "::",
+ stringify!(st_mtim)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_filestat_t>())).st_ctim as *const _ as usize },
+ 48usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_filestat_t),
+ "::",
+ stringify!(st_ctim)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_ciovec_t {
+ pub buf: uintptr_t, // *const ::std::os::raw::c_void
+ pub buf_len: size_t,
+}
+#[test]
+fn bindgen_test_layout_wasi_ciovec_t() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_ciovec_t>(),
+ 8usize,
+ concat!("Size of: ", stringify!(__wasi_ciovec_t))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_ciovec_t>(),
+ 4usize,
+ concat!("Alignment of ", stringify!(__wasi_ciovec_t))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_ciovec_t>())).buf as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_ciovec_t),
+ "::",
+ stringify!(buf)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_ciovec_t>())).buf_len as *const _ as usize },
+ 4usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_ciovec_t),
+ "::",
+ stringify!(buf_len)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_iovec_t {
+ pub buf: uintptr_t, // *mut ::std::os::raw::c_void
+ pub buf_len: size_t,
+}
+#[test]
+fn bindgen_test_layout_wasi_iovec_t() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_iovec_t>(),
+ 8usize,
+ concat!("Size of: ", stringify!(__wasi_iovec_t))
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_iovec_t>(),
+ 4usize,
+ concat!("Alignment of ", stringify!(__wasi_iovec_t))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_iovec_t>())).buf as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_iovec_t),
+ "::",
+ stringify!(buf)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_iovec_t>())).buf_len as *const _ as usize },
+ 4usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_iovec_t),
+ "::",
+ stringify!(buf_len)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub struct __wasi_subscription_t {
+ pub userdata: __wasi_userdata_t,
+ pub type_: __wasi_eventtype_t,
+ pub __bindgen_padding_0: u32,
+ pub __bindgen_anon_1: __wasi_subscription_t__bindgen_ty_1,
+}
+#[repr(C)]
+#[derive(Copy, Clone)]
+pub union __wasi_subscription_t__bindgen_ty_1 {
+ pub clock: __wasi_subscription_t__bindgen_ty_1__bindgen_ty_1,
+ pub fd_readwrite: __wasi_subscription_t__bindgen_ty_1__bindgen_ty_3,
+ _bindgen_union_align: [u64; 5usize],
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_subscription_t__bindgen_ty_1__bindgen_ty_1 {
+ pub identifier: __wasi_userdata_t,
+ pub clock_id: __wasi_clockid_t,
+ pub __bindgen_padding_0: u32,
+ pub timeout: __wasi_timestamp_t,
+ pub precision: __wasi_timestamp_t,
+ pub flags: __wasi_subclockflags_t,
+ pub __bindgen_padding_1: [u16; 3usize],
+}
+#[allow(non_snake_case)]
+#[test]
+fn bindgen_test_layout_wasi_subscription_t__bindgen_ty_1__bindgen_ty_1() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1>(),
+ 40usize,
+ concat!(
+ "Size of: ",
+ stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1>())).identifier
+ as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1),
+ "::",
+ stringify!(identifier)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1>())).clock_id
+ as *const _ as usize
+ },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1),
+ "::",
+ stringify!(clock_id)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1>())).timeout
+ as *const _ as usize
+ },
+ 16usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1),
+ "::",
+ stringify!(timeout)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1>())).precision
+ as *const _ as usize
+ },
+ 24usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1),
+ "::",
+ stringify!(precision)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1>())).flags
+ as *const _ as usize
+ },
+ 32usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_1),
+ "::",
+ stringify!(flags)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_subscription_t__bindgen_ty_1__bindgen_ty_3 {
+ pub fd: __wasi_fd_t,
+}
+#[allow(non_snake_case)]
+#[test]
+fn bindgen_test_layout_wasi_subscription_t__bindgen_ty_1__bindgen_ty_3() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_3>(),
+ 4usize,
+ concat!(
+ "Size of: ",
+ stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_3)
+ )
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_3>(),
+ 4usize,
+ concat!(
+ "Alignment of ",
+ stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_3)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_3>())).fd
+ as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_3),
+ "::",
+ stringify!(fd)
+ )
+ );
+}
+#[repr(C)]
+#[derive(Debug, Copy, Clone)]
+pub struct __wasi_subscription_t__bindgen_ty_1__bindgen_ty_5 {
+ pub fd: __wasi_fd_t,
+}
+#[allow(non_snake_case)]
+#[test]
+fn bindgen_test_layout_wasi_subscription_t__bindgen_ty_1__bindgen_ty_5() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_5>(),
+ 4usize,
+ concat!(
+ "Size of: ",
+ stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_5)
+ )
+ );
+ assert_eq!(
+ ::std::mem::align_of::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_5>(),
+ 4usize,
+ concat!(
+ "Alignment of ",
+ stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_5)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_subscription_t__bindgen_ty_1__bindgen_ty_5>())).fd
+ as *const _ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t__bindgen_ty_1__bindgen_ty_5),
+ "::",
+ stringify!(fd)
+ )
+ );
+}
+#[allow(non_snake_case)]
+#[test]
+fn bindgen_test_layout_wasi_subscription_t__bindgen_ty_1() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_subscription_t__bindgen_ty_1>(),
+ 40usize,
+ concat!("Size of: ", stringify!(__wasi_subscription_t__bindgen_ty_1))
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_subscription_t__bindgen_ty_1>())).clock as *const _
+ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t__bindgen_ty_1),
+ "::",
+ stringify!(clock)
+ )
+ );
+ assert_eq!(
+ unsafe {
+ &(*(::std::ptr::null::<__wasi_subscription_t__bindgen_ty_1>())).fd_readwrite as *const _
+ as usize
+ },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t__bindgen_ty_1),
+ "::",
+ stringify!(fd_readwrite)
+ )
+ );
+}
+#[allow(non_snake_case)]
+#[test]
+fn bindgen_test_layout_wasi_subscription_t() {
+ assert_eq!(
+ ::std::mem::size_of::<__wasi_subscription_t>(),
+ 56usize,
+ concat!("Size of: ", stringify!(__wasi_subscription_t))
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_subscription_t>())).userdata as *const _ as usize },
+ 0usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t),
+ "::",
+ stringify!(userdata)
+ )
+ );
+ assert_eq!(
+ unsafe { &(*(::std::ptr::null::<__wasi_subscription_t>())).type_ as *const _ as usize },
+ 8usize,
+ concat!(
+ "Offset of field: ",
+ stringify!(__wasi_subscription_t),
+ "::",
+ stringify!(type_)
+ )
+ );
+}
+
+pub fn strerror(errno: __wasi_errno_t) -> &'static str {
+ match errno {
+ __WASI_ESUCCESS => "__WASI_ESUCCESS",
+ __WASI_E2BIG => "__WASI_E2BIG",
+ __WASI_EACCES => "__WASI_EACCES",
+ __WASI_EADDRINUSE => "__WASI_EADDRINUSE",
+ __WASI_EADDRNOTAVAIL => "__WASI_EADDRNOTAVAIL",
+ __WASI_EAFNOSUPPORT => "__WASI_EAFNOSUPPORT",
+ __WASI_EAGAIN => "__WASI_EAGAIN",
+ __WASI_EALREADY => "__WASI_EALREADY",
+ __WASI_EBADF => "__WASI_EBADF",
+ __WASI_EBADMSG => "__WASI_EBADMSG",
+ __WASI_EBUSY => "__WASI_EBUSY",
+ __WASI_ECANCELED => "__WASI_ECANCELED",
+ __WASI_ECHILD => "__WASI_ECHILD",
+ __WASI_ECONNABORTED => "__WASI_ECONNABORTED",
+ __WASI_ECONNREFUSED => "__WASI_ECONNREFUSED",
+ __WASI_ECONNRESET => "__WASI_ECONNRESET",
+ __WASI_EDEADLK => "__WASI_EDEADLK",
+ __WASI_EDESTADDRREQ => "__WASI_EDESTADDRREQ",
+ __WASI_EDOM => "__WASI_EDOM",
+ __WASI_EDQUOT => "__WASI_EDQUOT",
+ __WASI_EEXIST => "__WASI_EEXIST",
+ __WASI_EFAULT => "__WASI_EFAULT",
+ __WASI_EFBIG => "__WASI_EFBIG",
+ __WASI_EHOSTUNREACH => "__WASI_EHOSTUNREACH",
+ __WASI_EIDRM => "__WASI_EIDRM",
+ __WASI_EILSEQ => "__WASI_EILSEQ",
+ __WASI_EINPROGRESS => "__WASI_EINPROGRESS",
+ __WASI_EINTR => "__WASI_EINTR",
+ __WASI_EINVAL => "__WASI_EINVAL",
+ __WASI_EIO => "__WASI_EIO",
+ __WASI_EISCONN => "__WASI_EISCONN",
+ __WASI_EISDIR => "__WASI_EISDIR",
+ __WASI_ELOOP => "__WASI_ELOOP",
+ __WASI_EMFILE => "__WASI_EMFILE",
+ __WASI_EMLINK => "__WASI_EMLINK",
+ __WASI_EMSGSIZE => "__WASI_EMSGSIZE",
+ __WASI_EMULTIHOP => "__WASI_EMULTIHOP",
+ __WASI_ENAMETOOLONG => "__WASI_ENAMETOOLONG",
+ __WASI_ENETDOWN => "__WASI_ENETDOWN",
+ __WASI_ENETRESET => "__WASI_ENETRESET",
+ __WASI_ENETUNREACH => "__WASI_ENETUNREACH",
+ __WASI_ENFILE => "__WASI_ENFILE",
+ __WASI_ENOBUFS => "__WASI_ENOBUFS",
+ __WASI_ENODEV => "__WASI_ENODEV",
+ __WASI_ENOENT => "__WASI_ENOENT",
+ __WASI_ENOEXEC => "__WASI_ENOEXEC",
+ __WASI_ENOLCK => "__WASI_ENOLCK",
+ __WASI_ENOLINK => "__WASI_ENOLINK",
+ __WASI_ENOMEM => "__WASI_ENOMEM",
+ __WASI_ENOMSG => "__WASI_ENOMSG",
+ __WASI_ENOPROTOOPT => "__WASI_ENOPROTOOPT",
+ __WASI_ENOSPC => "__WASI_ENOSPC",
+ __WASI_ENOSYS => "__WASI_ENOSYS",
+ __WASI_ENOTCONN => "__WASI_ENOTCONN",
+ __WASI_ENOTDIR => "__WASI_ENOTDIR",
+ __WASI_ENOTEMPTY => "__WASI_ENOTEMPTY",
+ __WASI_ENOTRECOVERABLE => "__WASI_ENOTRECOVERABLE",
+ __WASI_ENOTSOCK => "__WASI_ENOTSOCK",
+ __WASI_ENOTSUP => "__WASI_ENOTSUP",
+ __WASI_ENOTTY => "__WASI_ENOTTY",
+ __WASI_ENXIO => "__WASI_ENXIO",
+ __WASI_EOVERFLOW => "__WASI_EOVERFLOW",
+ __WASI_EOWNERDEAD => "__WASI_EOWNERDEAD",
+ __WASI_EPERM => "__WASI_EPERM",
+ __WASI_EPIPE => "__WASI_EPIPE",
+ __WASI_EPROTO => "__WASI_EPROTO",
+ __WASI_EPROTONOSUPPORT => "__WASI_EPROTONOSUPPORT",
+ __WASI_EPROTOTYPE => "__WASI_EPROTOTYPE",
+ __WASI_ERANGE => "__WASI_ERANGE",
+ __WASI_EROFS => "__WASI_EROFS",
+ __WASI_ESPIPE => "__WASI_ESPIPE",
+ __WASI_ESRCH => "__WASI_ESRCH",
+ __WASI_ESTALE => "__WASI_ESTALE",
+ __WASI_ETIMEDOUT => "__WASI_ETIMEDOUT",
+ __WASI_ETXTBSY => "__WASI_ETXTBSY",
+ __WASI_EXDEV => "__WASI_EXDEV",
+ __WASI_ENOTCAPABLE => "__WASI_ENOTCAPABLE",
+ other => panic!("Undefined errno value {:?}", other),
+ }
+}
+
+pub fn whence_to_str(whence: __wasi_whence_t) -> &'static str {
+ match whence {
+ __WASI_WHENCE_CUR => "__WASI_WHENCE_CUR",
+ __WASI_WHENCE_END => "__WASI_WHENCE_END",
+ __WASI_WHENCE_SET => "__WASI_WHENCE_SET",
+ other => panic!("Undefined whence value {:?}", other),
+ }
+}
+
+// libc constants
+pub const INT8_MIN: i32 = -128;
+pub const INT16_MIN: i32 = -32768;
+pub const INT32_MIN: i32 = -2147483648;
+pub const INT8_MAX: u32 = 127;
+pub const INT16_MAX: u32 = 32767;
+pub const INT32_MAX: u32 = 2147483647;
+pub const UINT8_MAX: u32 = 255;
+pub const UINT16_MAX: u32 = 65535;
+pub const UINT32_MAX: u32 = 4294967295;
+pub const INT_LEAST8_MIN: i32 = -128;
+pub const INT_LEAST16_MIN: i32 = -32768;
+pub const INT_LEAST32_MIN: i32 = -2147483648;
+pub const INT_LEAST8_MAX: u32 = 127;
+pub const INT_LEAST16_MAX: u32 = 32767;
+pub const INT_LEAST32_MAX: u32 = 2147483647;
+pub const UINT_LEAST8_MAX: u32 = 255;
+pub const UINT_LEAST16_MAX: u32 = 65535;
+pub const UINT_LEAST32_MAX: u32 = 4294967295;
+pub const INT_FAST8_MIN: i32 = -128;
+pub const INT_FAST16_MIN: i32 = -2147483648;
+pub const INT_FAST32_MIN: i32 = -2147483648;
+pub const INT_FAST8_MAX: u32 = 127;
+pub const INT_FAST16_MAX: u32 = 2147483647;
+pub const INT_FAST32_MAX: u32 = 2147483647;
+pub const UINT_FAST8_MAX: u32 = 255;
+pub const UINT_FAST16_MAX: u32 = 4294967295;
+pub const UINT_FAST32_MAX: u32 = 4294967295;
+pub const INTPTR_MIN: i32 = -2147483648;
+pub const INTPTR_MAX: u32 = 2147483647;
+pub const UINTPTR_MAX: u32 = 4294967295;
+pub const PTRDIFF_MIN: i32 = -2147483648;
+pub const PTRDIFF_MAX: u32 = 2147483647;
+pub const SIG_ATOMIC_MIN: i32 = -2147483648;
+pub const SIG_ATOMIC_MAX: u32 = 2147483647;
+pub const SIZE_MAX: u32 = 4294967295;
+pub const WINT_MIN: i32 = -2147483648;
+pub const WINT_MAX: i32 = 2147483647;
+
+// WASI constants
+pub const __WASI_ADVICE_NORMAL: __wasi_advice_t = 0;
+pub const __WASI_ADVICE_SEQUENTIAL: __wasi_advice_t = 1;
+pub const __WASI_ADVICE_RANDOM: __wasi_advice_t = 2;
+pub const __WASI_ADVICE_WILLNEED: __wasi_advice_t = 3;
+pub const __WASI_ADVICE_DONTNEED: __wasi_advice_t = 4;
+pub const __WASI_ADVICE_NOREUSE: __wasi_advice_t = 5;
+pub const __WASI_CLOCK_REALTIME: __wasi_clockid_t = 0;
+pub const __WASI_CLOCK_MONOTONIC: __wasi_clockid_t = 1;
+pub const __WASI_CLOCK_PROCESS_CPUTIME_ID: __wasi_clockid_t = 2;
+pub const __WASI_CLOCK_THREAD_CPUTIME_ID: __wasi_clockid_t = 3;
+pub const __WASI_DIRCOOKIE_START: __wasi_dircookie_t = 0;
+pub const __WASI_ESUCCESS: __wasi_errno_t = 0;
+pub const __WASI_E2BIG: __wasi_errno_t = 1;
+pub const __WASI_EACCES: __wasi_errno_t = 2;
+pub const __WASI_EADDRINUSE: __wasi_errno_t = 3;
+pub const __WASI_EADDRNOTAVAIL: __wasi_errno_t = 4;
+pub const __WASI_EAFNOSUPPORT: __wasi_errno_t = 5;
+pub const __WASI_EAGAIN: __wasi_errno_t = 6;
+pub const __WASI_EALREADY: __wasi_errno_t = 7;
+pub const __WASI_EBADF: __wasi_errno_t = 8;
+pub const __WASI_EBADMSG: __wasi_errno_t = 9;
+pub const __WASI_EBUSY: __wasi_errno_t = 10;
+pub const __WASI_ECANCELED: __wasi_errno_t = 11;
+pub const __WASI_ECHILD: __wasi_errno_t = 12;
+pub const __WASI_ECONNABORTED: __wasi_errno_t = 13;
+pub const __WASI_ECONNREFUSED: __wasi_errno_t = 14;
+pub const __WASI_ECONNRESET: __wasi_errno_t = 15;
+pub const __WASI_EDEADLK: __wasi_errno_t = 16;
+pub const __WASI_EDESTADDRREQ: __wasi_errno_t = 17;
+pub const __WASI_EDOM: __wasi_errno_t = 18;
+pub const __WASI_EDQUOT: __wasi_errno_t = 19;
+pub const __WASI_EEXIST: __wasi_errno_t = 20;
+pub const __WASI_EFAULT: __wasi_errno_t = 21;
+pub const __WASI_EFBIG: __wasi_errno_t = 22;
+pub const __WASI_EHOSTUNREACH: __wasi_errno_t = 23;
+pub const __WASI_EIDRM: __wasi_errno_t = 24;
+pub const __WASI_EILSEQ: __wasi_errno_t = 25;
+pub const __WASI_EINPROGRESS: __wasi_errno_t = 26;
+pub const __WASI_EINTR: __wasi_errno_t = 27;
+pub const __WASI_EINVAL: __wasi_errno_t = 28;
+pub const __WASI_EIO: __wasi_errno_t = 29;
+pub const __WASI_EISCONN: __wasi_errno_t = 30;
+pub const __WASI_EISDIR: __wasi_errno_t = 31;
+pub const __WASI_ELOOP: __wasi_errno_t = 32;
+pub const __WASI_EMFILE: __wasi_errno_t = 33;
+pub const __WASI_EMLINK: __wasi_errno_t = 34;
+pub const __WASI_EMSGSIZE: __wasi_errno_t = 35;
+pub const __WASI_EMULTIHOP: __wasi_errno_t = 36;
+pub const __WASI_ENAMETOOLONG: __wasi_errno_t = 37;
+pub const __WASI_ENETDOWN: __wasi_errno_t = 38;
+pub const __WASI_ENETRESET: __wasi_errno_t = 39;
+pub const __WASI_ENETUNREACH: __wasi_errno_t = 40;
+pub const __WASI_ENFILE: __wasi_errno_t = 41;
+pub const __WASI_ENOBUFS: __wasi_errno_t = 42;
+pub const __WASI_ENODEV: __wasi_errno_t = 43;
+pub const __WASI_ENOENT: __wasi_errno_t = 44;
+pub const __WASI_ENOEXEC: __wasi_errno_t = 45;
+pub const __WASI_ENOLCK: __wasi_errno_t = 46;
+pub const __WASI_ENOLINK: __wasi_errno_t = 47;
+pub const __WASI_ENOMEM: __wasi_errno_t = 48;
+pub const __WASI_ENOMSG: __wasi_errno_t = 49;
+pub const __WASI_ENOPROTOOPT: __wasi_errno_t = 50;
+pub const __WASI_ENOSPC: __wasi_errno_t = 51;
+pub const __WASI_ENOSYS: __wasi_errno_t = 52;
+pub const __WASI_ENOTCONN: __wasi_errno_t = 53;
+pub const __WASI_ENOTDIR: __wasi_errno_t = 54;
+pub const __WASI_ENOTEMPTY: __wasi_errno_t = 55;
+pub const __WASI_ENOTRECOVERABLE: __wasi_errno_t = 56;
+pub const __WASI_ENOTSOCK: __wasi_errno_t = 57;
+pub const __WASI_ENOTSUP: __wasi_errno_t = 58;
+pub const __WASI_ENOTTY: __wasi_errno_t = 59;
+pub const __WASI_ENXIO: __wasi_errno_t = 60;
+pub const __WASI_EOVERFLOW: __wasi_errno_t = 61;
+pub const __WASI_EOWNERDEAD: __wasi_errno_t = 62;
+pub const __WASI_EPERM: __wasi_errno_t = 63;
+pub const __WASI_EPIPE: __wasi_errno_t = 64;
+pub const __WASI_EPROTO: __wasi_errno_t = 65;
+pub const __WASI_EPROTONOSUPPORT: __wasi_errno_t = 66;
+pub const __WASI_EPROTOTYPE: __wasi_errno_t = 67;
+pub const __WASI_ERANGE: __wasi_errno_t = 68;
+pub const __WASI_EROFS: __wasi_errno_t = 69;
+pub const __WASI_ESPIPE: __wasi_errno_t = 70;
+pub const __WASI_ESRCH: __wasi_errno_t = 71;
+pub const __WASI_ESTALE: __wasi_errno_t = 72;
+pub const __WASI_ETIMEDOUT: __wasi_errno_t = 73;
+pub const __WASI_ETXTBSY: __wasi_errno_t = 74;
+pub const __WASI_EXDEV: __wasi_errno_t = 75;
+pub const __WASI_ENOTCAPABLE: __wasi_errno_t = 76;
+pub const __WASI_EVENT_FD_READWRITE_HANGUP: __wasi_eventrwflags_t = 1;
+pub const __WASI_EVENTTYPE_CLOCK: __wasi_eventtype_t = 0;
+pub const __WASI_EVENTTYPE_FD_READ: __wasi_eventtype_t = 1;
+pub const __WASI_EVENTTYPE_FD_WRITE: __wasi_eventtype_t = 2;
+pub const __WASI_FDFLAG_APPEND: __wasi_fdflags_t = 1;
+pub const __WASI_FDFLAG_DSYNC: __wasi_fdflags_t = 2;
+pub const __WASI_FDFLAG_NONBLOCK: __wasi_fdflags_t = 4;
+pub const __WASI_FDFLAG_RSYNC: __wasi_fdflags_t = 8;
+pub const __WASI_FDFLAG_SYNC: __wasi_fdflags_t = 16;
+pub const __WASI_PREOPENTYPE_DIR: __wasi_preopentype_t = 0;
+pub const __WASI_FILETYPE_UNKNOWN: __wasi_filetype_t = 0;
+pub const __WASI_FILETYPE_BLOCK_DEVICE: __wasi_filetype_t = 1;
+pub const __WASI_FILETYPE_CHARACTER_DEVICE: __wasi_filetype_t = 2;
+pub const __WASI_FILETYPE_DIRECTORY: __wasi_filetype_t = 3;
+pub const __WASI_FILETYPE_REGULAR_FILE: __wasi_filetype_t = 4;
+pub const __WASI_FILETYPE_SOCKET_DGRAM: __wasi_filetype_t = 5;
+pub const __WASI_FILETYPE_SOCKET_STREAM: __wasi_filetype_t = 6;
+pub const __WASI_FILETYPE_SYMBOLIC_LINK: __wasi_filetype_t = 7;
+pub const __WASI_FILESTAT_SET_ATIM: __wasi_fstflags_t = 1;
+pub const __WASI_FILESTAT_SET_ATIM_NOW: __wasi_fstflags_t = 2;
+pub const __WASI_FILESTAT_SET_MTIM: __wasi_fstflags_t = 4;
+pub const __WASI_FILESTAT_SET_MTIM_NOW: __wasi_fstflags_t = 8;
+pub const __WASI_LOOKUP_SYMLINK_FOLLOW: __wasi_lookupflags_t = 1;
+pub const __WASI_O_CREAT: __wasi_oflags_t = 1;
+pub const __WASI_O_DIRECTORY: __wasi_oflags_t = 2;
+pub const __WASI_O_EXCL: __wasi_oflags_t = 4;
+pub const __WASI_O_TRUNC: __wasi_oflags_t = 8;
+pub const __WASI_SOCK_RECV_PEEK: __wasi_riflags_t = 1;
+pub const __WASI_SOCK_RECV_WAITALL: __wasi_riflags_t = 2;
+pub const __WASI_RIGHT_FD_DATASYNC: __wasi_rights_t = 1;
+pub const __WASI_RIGHT_FD_READ: __wasi_rights_t = 2;
+pub const __WASI_RIGHT_FD_SEEK: __wasi_rights_t = 4;
+pub const __WASI_RIGHT_FD_FDSTAT_SET_FLAGS: __wasi_rights_t = 8;
+pub const __WASI_RIGHT_FD_SYNC: __wasi_rights_t = 16;
+pub const __WASI_RIGHT_FD_TELL: __wasi_rights_t = 32;
+pub const __WASI_RIGHT_FD_WRITE: __wasi_rights_t = 64;
+pub const __WASI_RIGHT_FD_ADVISE: __wasi_rights_t = 128;
+pub const __WASI_RIGHT_FD_ALLOCATE: __wasi_rights_t = 256;
+pub const __WASI_RIGHT_PATH_CREATE_DIRECTORY: __wasi_rights_t = 512;
+pub const __WASI_RIGHT_PATH_CREATE_FILE: __wasi_rights_t = 1024;
+pub const __WASI_RIGHT_PATH_LINK_SOURCE: __wasi_rights_t = 2048;
+pub const __WASI_RIGHT_PATH_LINK_TARGET: __wasi_rights_t = 4096;
+pub const __WASI_RIGHT_PATH_OPEN: __wasi_rights_t = 8192;
+pub const __WASI_RIGHT_FD_READDIR: __wasi_rights_t = 16384;
+pub const __WASI_RIGHT_PATH_READLINK: __wasi_rights_t = 32768;
+pub const __WASI_RIGHT_PATH_RENAME_SOURCE: __wasi_rights_t = 65536;
+pub const __WASI_RIGHT_PATH_RENAME_TARGET: __wasi_rights_t = 131072;
+pub const __WASI_RIGHT_PATH_FILESTAT_GET: __wasi_rights_t = 262144;
+pub const __WASI_RIGHT_PATH_FILESTAT_SET_SIZE: __wasi_rights_t = 524288;
+pub const __WASI_RIGHT_PATH_FILESTAT_SET_TIMES: __wasi_rights_t = 1048576;
+pub const __WASI_RIGHT_FD_FILESTAT_GET: __wasi_rights_t = 2097152;
+pub const __WASI_RIGHT_FD_FILESTAT_SET_SIZE: __wasi_rights_t = 4194304;
+pub const __WASI_RIGHT_FD_FILESTAT_SET_TIMES: __wasi_rights_t = 8388608;
+pub const __WASI_RIGHT_PATH_SYMLINK: __wasi_rights_t = 16777216;
+pub const __WASI_RIGHT_PATH_REMOVE_DIRECTORY: __wasi_rights_t = 33554432;
+pub const __WASI_RIGHT_PATH_UNLINK_FILE: __wasi_rights_t = 67108864;
+pub const __WASI_RIGHT_POLL_FD_READWRITE: __wasi_rights_t = 134217728;
+pub const __WASI_RIGHT_SOCK_SHUTDOWN: __wasi_rights_t = 268435456;
+pub const __WASI_SOCK_RECV_DATA_TRUNCATED: __wasi_roflags_t = 1;
+pub const __WASI_SHUT_RD: __wasi_sdflags_t = 1;
+pub const __WASI_SHUT_WR: __wasi_sdflags_t = 2;
+pub const __WASI_SIGHUP: __wasi_signal_t = 1;
+pub const __WASI_SIGINT: __wasi_signal_t = 2;
+pub const __WASI_SIGQUIT: __wasi_signal_t = 3;
+pub const __WASI_SIGILL: __wasi_signal_t = 4;
+pub const __WASI_SIGTRAP: __wasi_signal_t = 5;
+pub const __WASI_SIGABRT: __wasi_signal_t = 6;
+pub const __WASI_SIGBUS: __wasi_signal_t = 7;
+pub const __WASI_SIGFPE: __wasi_signal_t = 8;
+pub const __WASI_SIGKILL: __wasi_signal_t = 9;
+pub const __WASI_SIGUSR1: __wasi_signal_t = 10;
+pub const __WASI_SIGSEGV: __wasi_signal_t = 11;
+pub const __WASI_SIGUSR2: __wasi_signal_t = 12;
+pub const __WASI_SIGPIPE: __wasi_signal_t = 13;
+pub const __WASI_SIGALRM: __wasi_signal_t = 14;
+pub const __WASI_SIGTERM: __wasi_signal_t = 15;
+pub const __WASI_SIGCHLD: __wasi_signal_t = 16;
+pub const __WASI_SIGCONT: __wasi_signal_t = 17;
+pub const __WASI_SIGSTOP: __wasi_signal_t = 18;
+pub const __WASI_SIGTSTP: __wasi_signal_t = 19;
+pub const __WASI_SIGTTIN: __wasi_signal_t = 20;
+pub const __WASI_SIGTTOU: __wasi_signal_t = 21;
+pub const __WASI_SIGURG: __wasi_signal_t = 22;
+pub const __WASI_SIGXCPU: __wasi_signal_t = 23;
+pub const __WASI_SIGXFSZ: __wasi_signal_t = 24;
+pub const __WASI_SIGVTALRM: __wasi_signal_t = 25;
+pub const __WASI_SIGPROF: __wasi_signal_t = 26;
+pub const __WASI_SIGWINCH: __wasi_signal_t = 27;
+pub const __WASI_SIGPOLL: __wasi_signal_t = 28;
+pub const __WASI_SIGPWR: __wasi_signal_t = 29;
+pub const __WASI_SIGSYS: __wasi_signal_t = 30;
+pub const __WASI_SUBSCRIPTION_CLOCK_ABSTIME: __wasi_subclockflags_t = 1;
+pub const __WASI_WHENCE_CUR: __wasi_whence_t = 0;
+pub const __WASI_WHENCE_END: __wasi_whence_t = 1;
+pub const __WASI_WHENCE_SET: __wasi_whence_t = 2;
+
+pub fn errno_from_nix(errno: nix::errno::Errno) -> __wasi_errno_t {
+ 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,
+ }
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/cant_dotdot.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/cant_dotdot.c
new file mode 100644
index 0000000000..12b6ce78c9
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/cant_dotdot.c
@@ -0,0 +1,12 @@
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+
+int main()
+{
+ FILE *file = fopen("/sandbox/../outside.txt", "r");
+ assert(file == NULL);
+ assert(errno == ENOTCAPABLE);
+
+ return 0;
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/clock_getres.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/clock_getres.c
new file mode 100644
index 0000000000..27a9f46472
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/clock_getres.c
@@ -0,0 +1,13 @@
+#include <assert.h>
+#include <time.h>
+
+int main()
+{
+ struct timespec ts;
+
+ // supported clocks
+ assert(clock_getres(CLOCK_REALTIME, &ts) == 0);
+ assert(clock_getres(CLOCK_MONOTONIC, &ts) == 0);
+ assert(clock_getres(CLOCK_PROCESS_CPUTIME_ID, &ts) == 0);
+ assert(clock_getres(CLOCK_THREAD_CPUTIME_ID, &ts) == 0);
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/duplicate_import.wat b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/duplicate_import.wat
new file mode 100644
index 0000000000..6bd7c1eeca
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/duplicate_import.wat
@@ -0,0 +1,38 @@
+(module
+ (type (func (param i32 i32 i32 i32) (result i32)))
+ (type (func (result i32)))
+
+ ;; import fd_read, this is fine.
+ (func $read (import "wasi_unstable" "fd_read") (type 0))
+
+ ;; import fd_write, this is also fine.
+ (func $write (import "wasi_unstable" "fd_write") (type 0))
+
+ ;; import fd_read, again, under a different name!
+ ;; this is to test that we join together the imports.
+ ;; the .wat would be invalid if their types disagree, so there
+ ;; is no observable difference between $read and $read_2
+ (func $read_2 (import "wasi_unstable" "fd_read") (type 0))
+
+ ;; import fd_write again for grins.
+ (import "wasi_unstable" "fd_write" (func (type 0)))
+ (memory 1)
+ (data (i32.const 0) "duplicate import works!\0a")
+ (data (i32.const 64) "\00\00\00\00\18\00\00\00")
+
+ (func $_setup (type 1)
+ (call $write (i32.const 1) (i32.const 64) (i32.const 1) (i32.const 0)))
+
+ ;; declare that, actually, one of the imported functions is exported
+ (export "read_2" (func $read_2))
+ ;; and delcare that the *other* read function is also exported, by a
+ ;; different name. This lets us check that when we merge the functions,
+ ;; we also merge their export names properly.
+ (export "read" (func $read))
+
+ ;; and check that other exported functions still work, and are not affected
+ (export "write" (func $write))
+
+ ;; and that we can export local functions without issue
+ (export "_start" (func $_setup))
+)
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/exitcode.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/exitcode.c
new file mode 100644
index 0000000000..500d440ad0
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/exitcode.c
@@ -0,0 +1,4 @@
+int main()
+{
+ return 120;
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/follow_symlink.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/follow_symlink.c
new file mode 100644
index 0000000000..e8db730df4
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/follow_symlink.c
@@ -0,0 +1,14 @@
+#include <assert.h>
+#include <stdio.h>
+
+int main()
+{
+ FILE *file = fopen("/sandbox/subdir2/input_link.txt", "r");
+ assert(file != NULL);
+
+ char c = fgetc(file);
+ while (c != EOF) {
+ assert(fputc(c, stdout) != EOF);
+ c = fgetc(file);
+ }
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/fs.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/fs.c
new file mode 100644
index 0000000000..6f4bfa78e5
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/fs.c
@@ -0,0 +1,158 @@
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sched.h>
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+#include <utime.h>
+
+int main(void)
+{
+ struct timespec times[2];
+ struct dirent * entry;
+ char buf[4];
+ DIR * dir;
+ FILE * fp;
+ struct stat st;
+ off_t offset;
+ int fd;
+ int res;
+
+ fd = open("/sandbox/testfile", O_CREAT | O_RDWR, 0644);
+ assert(fd != -1);
+
+ res = posix_fallocate(fd, 0, 10000);
+ assert(res == 0);
+
+ res = fstat(fd, &st);
+ assert(res == 0);
+ assert(st.st_size == 10000);
+
+ res = ftruncate(fd, 1000);
+ res = fstat(fd, &st);
+ assert(res == 0);
+ assert(st.st_size == 1000);
+ assert(st.st_nlink == 1);
+ res = posix_fadvise(fd, 0, 1000, POSIX_FADV_RANDOM);
+ assert(res == 0);
+
+ res = (int) write(fd, "test", 4);
+ assert(res == 4);
+
+ offset = lseek(fd, 0, SEEK_CUR);
+ assert(offset == 4);
+ offset = lseek(fd, 0, SEEK_END);
+ assert(offset == 1000);
+ offset = lseek(fd, 0, SEEK_SET);
+ assert(offset == 0);
+
+ res = fdatasync(fd);
+ assert(res == 0);
+
+ res = fsync(fd);
+ assert(res == 0);
+
+ times[0] = (struct timespec){ .tv_sec = 1557403800, .tv_nsec = 0 };
+ times[1] = (struct timespec){ .tv_sec = 1557403800, .tv_nsec = 0 };
+
+ res = futimens(fd, times);
+ assert(res == 0);
+
+ res = pread(fd, buf, sizeof buf, 2);
+ assert(res == 4);
+ assert(buf[1] == 't');
+
+ res = pwrite(fd, "T", 1, 3);
+ assert(res == 1);
+
+ res = pread(fd, buf, sizeof buf, 2);
+ assert(res == 4);
+ assert(buf[1] == 'T');
+
+ res = close(fd);
+ assert(res == 0);
+
+ dir = opendir("/nonexistent");
+ assert(dir == NULL);
+
+ res = mkdir("/sandbox/test", 0755);
+ assert(res == 0);
+
+ res = mkdir("/sandbox/test", 0755);
+ assert(res == -1);
+ assert(errno == EEXIST);
+
+ res = rmdir("/sandbox/test");
+ assert(res == 0);
+
+ res = rmdir("/sandbox/test");
+ assert(res == -1);
+
+ res = rename("/sandbox/testfile", "/sandbox/testfile2");
+ assert(res == 0);
+
+ res = unlink("/sandbox/testfile");
+ assert(res == -1);
+
+ res = access("/sandbox/testfile2", R_OK);
+ assert(res == 0);
+
+ res = link("/sandbox/testfile2", "/sandbox/testfile-link");
+ assert(res == 0);
+
+ res = access("/sandbox/testfile-link", R_OK);
+ assert(res == 0);
+
+ res = symlink("/sandbox/testfile-link", "/sandbox/testfile-symlink");
+ assert(res == 0);
+
+ res = symlink("/sandbox/testfile2", "/sandbox/testfile-symlink");
+ assert(res == -1);
+
+ res = sched_yield();
+ assert(res == 0);
+
+ fd = open("/sandbox/testfile2", O_RDONLY);
+ assert(fd != -1);
+
+ fp = fdopen(fd, "r");
+ assert(fp != NULL);
+
+ res = fgetc(fp);
+ assert(res == 't');
+
+ res = fclose(fp);
+ assert(res == 0);
+
+ dir = opendir("/sandbox");
+ assert(dir != NULL);
+
+ res = 0;
+ while ((entry = readdir(dir)) != NULL) {
+ if (entry->d_name[0] == '.') {
+ res += 1000;
+ } else {
+ res++;
+ }
+ }
+ assert(res == 2003);
+
+ res = closedir(dir);
+ assert(res == 0);
+
+ res = mkdir("/sandbox/a", 0755);
+ assert(res == 0);
+ res = mkdir("/sandbox/a/b", 0755);
+ assert(res == 0);
+ res = mkdir("/sandbox/a/b/c", 0755);
+ assert(res == 0);
+ res = access("/sandbox/a/b/c", R_OK);
+ assert(res == 0);
+
+ return 0;
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/getentropy.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/getentropy.c
new file mode 100644
index 0000000000..439512df10
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/getentropy.c
@@ -0,0 +1,17 @@
+#include <assert.h>
+#include <unistd.h>
+
+int main()
+{
+ char buf[256] = { 0 };
+ assert(getentropy(buf, 256) == 0);
+
+ for (int i = 0; i < 256; i++) {
+ if (buf[i] != 0) {
+ return 0;
+ }
+ }
+
+ // if this ever is reached, we either have a bug or should buy a lottery ticket
+ return 1;
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/getrusage.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/getrusage.c
new file mode 100644
index 0000000000..7ff12fe12a
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/getrusage.c
@@ -0,0 +1,30 @@
+#include <assert.h>
+#include <sys/resource.h>
+
+// Temporary fix until
+// https://github.com/CraneStation/wasi-sysroot/pull/24/
+// is available in wasi-sdk package
+extern int getrusage(int who, struct rusage *usage);
+
+int main()
+{
+ struct rusage ru1;
+ getrusage(RUSAGE_SELF, &ru1);
+
+ for (int i = 0; i < 1000; i++) {
+ }
+
+ struct rusage ru2;
+ getrusage(RUSAGE_SELF, &ru2);
+
+ // assert that some time has passed
+ long long s1 = ru1.ru_utime.tv_sec;
+ long long us1 = ru1.ru_utime.tv_usec;
+ long long s2 = ru2.ru_utime.tv_sec;
+ long long us2 = ru2.ru_utime.tv_usec;
+ assert(s1 <= s2);
+ if (s1 == s2) {
+ // strictly less than, so the timestamps can't be equal
+ assert(us1 < us2);
+ }
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/gettimeofday.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/gettimeofday.c
new file mode 100644
index 0000000000..f9e8d5a811
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/gettimeofday.c
@@ -0,0 +1,26 @@
+#include <assert.h>
+#include <stdlib.h>
+#include <sys/time.h>
+
+int main()
+{
+ struct timeval tv1;
+ gettimeofday(&tv1, NULL);
+
+ for (int i = 0; i < 1000; i++) {
+ }
+
+ struct timeval tv2;
+ gettimeofday(&tv2, NULL);
+
+ // assert that some time has passed
+ long long s1 = tv1.tv_sec;
+ long long us1 = tv1.tv_usec;
+ long long s2 = tv2.tv_sec;
+ long long us2 = tv2.tv_usec;
+ assert(s1 <= s2);
+ if (s1 == s2) {
+ // strictly less than, so the timestamps can't be equal
+ assert(us1 < us2);
+ }
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/notdir.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/notdir.c
new file mode 100644
index 0000000000..fcd47a69db
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/notdir.c
@@ -0,0 +1,12 @@
+#include <assert.h>
+#include <errno.h>
+#include <dirent.h>
+
+int main()
+{
+ DIR *dir = opendir("/sandbox/notadir");
+ assert(dir == NULL);
+ assert(errno == ENOTDIR);
+
+ return 0;
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/poll.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/poll.c
new file mode 100644
index 0000000000..d8f9a8c1de
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/poll.c
@@ -0,0 +1,32 @@
+#include <assert.h>
+#include <poll.h>
+#include <time.h>
+#include <unistd.h>
+
+int main(void)
+{
+ struct pollfd fds[2];
+ time_t before, now;
+ int ret;
+
+ fds[0] = (struct pollfd){ .fd = 1, .events = POLLOUT, .revents = 0 };
+ fds[1] = (struct pollfd){ .fd = 2, .events = POLLOUT, .revents = 0 };
+
+ ret = poll(fds, 2, -1);
+ assert(ret == 2);
+ assert(fds[0].revents == POLLOUT);
+ assert(fds[1].revents == POLLOUT);
+
+ fds[0] = (struct pollfd){ .fd = 0, .events = POLLIN, .revents = 0 };
+ time(&before);
+ ret = poll(fds, 1, 2000);
+ time(&now);
+ assert(ret == 0);
+ assert(now - before >= 2);
+
+ sleep(1);
+ time(&now);
+ assert(now - before >= 3);
+
+ return 0;
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/preopen_populates.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/preopen_populates.c
new file mode 100644
index 0000000000..58fe69254d
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/preopen_populates.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/read_file.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/read_file.c
new file mode 100644
index 0000000000..cdd758158e
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/read_file.c
@@ -0,0 +1,14 @@
+#include <assert.h>
+#include <stdio.h>
+
+int main()
+{
+ FILE *file = fopen("/sandbox/input.txt", "r");
+ assert(file != NULL);
+
+ char c = fgetc(file);
+ while (c != EOF) {
+ assert(fputc(c, stdout) != EOF);
+ c = fgetc(file);
+ }
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/read_file_twice.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/read_file_twice.c
new file mode 100644
index 0000000000..c2504fb40e
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/read_file_twice.c
@@ -0,0 +1,16 @@
+#include <assert.h>
+#include <stdio.h>
+
+int main()
+{
+ for (int i = 0; i < 2; i++) {
+ FILE *file = fopen("/sandbox/input.txt", "r");
+ assert(file != NULL);
+
+ char c = fgetc(file);
+ while (c != EOF) {
+ assert(fputc(c, stdout) != EOF);
+ c = fgetc(file);
+ }
+ }
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/stat.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/stat.c
new file mode 100644
index 0000000000..7974c31d84
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/stat.c
@@ -0,0 +1,54 @@
+#include <sys/stat.h>
+
+#include <assert.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+
+#define BASE_DIR "/sandbox"
+#define OUTPUT_DIR BASE_DIR "/testdir"
+#define PATH OUTPUT_DIR "/output.txt"
+#define SIZE 500
+
+int main(void)
+{
+ struct stat st;
+ int fd;
+ int ret;
+ off_t pos;
+
+ (void) st;
+ ret = mkdir(OUTPUT_DIR, 0755);
+ assert(ret == 0);
+
+ fd = open(PATH, O_CREAT | O_WRONLY, 0666);
+ assert(fd != -1);
+
+ pos = lseek(fd, SIZE - 1, SEEK_SET);
+ assert(pos == SIZE - 1);
+
+ ret = (int) write(fd, "", 1);
+ assert(ret == 1);
+
+ ret = fstat(fd, &st);
+ assert(ret == 0);
+ assert(st.st_size == SIZE);
+
+ ret = close(fd);
+ assert(ret == 0);
+
+ ret = access(PATH, R_OK);
+ assert(ret == 0);
+
+ ret = stat(PATH, &st);
+ assert(ret == 0);
+ assert(st.st_size == SIZE);
+
+ ret = unlink(PATH);
+ assert(ret == 0);
+
+ ret = stat(PATH, &st);
+ assert(ret == -1);
+
+ return 0;
+} \ No newline at end of file
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/stdin.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/stdin.c
new file mode 100644
index 0000000000..137a447602
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/stdin.c
@@ -0,0 +1,10 @@
+#include <stdio.h>
+
+int main(void)
+{
+ char x[32];
+
+ fgets(x, sizeof x, stdin);
+ fputs(x, stdout);
+ return 0;
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/symlink_escape.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/symlink_escape.c
new file mode 100644
index 0000000000..20929d5193
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/symlink_escape.c
@@ -0,0 +1,10 @@
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+
+int main()
+{
+ FILE *file = fopen("/sandbox/subdir/outside.txt", "r");
+ assert(file == NULL);
+ assert(errno == ENOTCAPABLE);
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/symlink_loop.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/symlink_loop.c
new file mode 100644
index 0000000000..7256121c3b
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/symlink_loop.c
@@ -0,0 +1,10 @@
+#include <assert.h>
+#include <errno.h>
+#include <stdio.h>
+
+int main()
+{
+ FILE *file = fopen("/sandbox/subdir1/loop1", "r");
+ assert(file == NULL);
+ assert(errno == ELOOP);
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/guests/write_file.c b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/write_file.c
new file mode 100644
index 0000000000..5922c02763
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/guests/write_file.c
@@ -0,0 +1,16 @@
+#include <assert.h>
+#include <stdio.h>
+#include <string.h>
+
+static char *message = "hello, file!";
+
+int main()
+{
+ FILE *file = fopen("/sandbox/output.txt", "w");
+ assert(file != NULL);
+
+ int nwritten = fprintf(file, "%s", message);
+ assert(nwritten == strlen(message));
+
+ assert(fclose(file) == 0);
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/test_helpers/mod.rs b/third_party/rust/lucet-wasi-wasmsbx/tests/test_helpers/mod.rs
new file mode 100644
index 0000000000..455928a92b
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/test_helpers/mod.rs
@@ -0,0 +1,127 @@
+use failure::{bail, Error};
+use lucet_runtime::{DlModule, Limits, MmapRegion, Module, Region};
+use lucet_wasi::host::__wasi_exitcode_t;
+use lucet_wasi::{self, WasiCtx, WasiCtxBuilder};
+use lucet_wasi_sdk::{CompileOpts, Link};
+use lucetc::{Lucetc, LucetcOpts};
+use std::fs::File;
+use std::io::Read;
+use std::os::unix::io::{FromRawFd, IntoRawFd};
+use std::path::{Path, PathBuf};
+use std::sync::Arc;
+use tempfile::TempDir;
+
+pub const LUCET_WASI_ROOT: &'static str = env!("CARGO_MANIFEST_DIR");
+
+pub fn test_module_wasi<P: AsRef<Path>>(cfile: P) -> Result<Arc<dyn Module>, Error> {
+ let c_path = guest_file(&cfile);
+ wasi_test(c_path)
+}
+
+pub fn guest_file<P: AsRef<Path>>(path: P) -> PathBuf {
+ let p = if path.as_ref().is_absolute() {
+ path.as_ref().to_owned()
+ } else {
+ Path::new(LUCET_WASI_ROOT)
+ .join("tests")
+ .join("guests")
+ .join(path)
+ };
+ assert!(p.exists(), "test case source file {} exists", p.display());
+ p
+}
+
+pub fn wasi_test<P: AsRef<Path>>(file: P) -> Result<Arc<dyn Module>, Error> {
+ let workdir = TempDir::new().expect("create working directory");
+
+ let wasm_path = match file.as_ref().extension().and_then(|x| x.to_str()) {
+ Some("c") => {
+ // some tests are .c, and must be compiled/linked to .wasm we can run
+ let wasm_build = Link::new(&[file])
+ .with_cflag("-Wall")
+ .with_cflag("-Werror")
+ .with_print_output(true);
+
+ let wasm_file = workdir.path().join("out.wasm");
+ wasm_build.link(wasm_file.clone())?;
+
+ wasm_file
+ }
+ Some("wasm") | Some("wat") => {
+ // others are just wasm we can run directly
+ file.as_ref().to_owned()
+ }
+ Some(ext) => {
+ panic!("unknown test file extension: .{}", ext);
+ }
+ None => {
+ panic!("unknown test file, has no extension");
+ }
+ };
+
+ wasi_load(&workdir, wasm_path)
+}
+
+pub fn wasi_load<P: AsRef<Path>>(
+ workdir: &TempDir,
+ wasm_file: P,
+) -> Result<Arc<dyn Module>, Error> {
+ let native_build = Lucetc::new(wasm_file).with_bindings(lucet_wasi::bindings());
+
+ let so_file = workdir.path().join("out.so");
+
+ native_build.shared_object_file(so_file.clone())?;
+
+ let dlmodule = DlModule::load(so_file)?;
+
+ Ok(dlmodule as Arc<dyn Module>)
+}
+
+pub fn run<P: AsRef<Path>>(path: P, ctx: WasiCtx) -> Result<__wasi_exitcode_t, Error> {
+ let region = MmapRegion::create(1, &Limits::default())?;
+ let module = test_module_wasi(path)?;
+
+ let mut inst = region
+ .new_instance_builder(module)
+ .with_embed_ctx(ctx)
+ .build()?;
+
+ match inst.run("_start", &[]) {
+ // normal termination implies 0 exit code
+ Ok(_) => Ok(0),
+ Err(lucet_runtime::Error::RuntimeTerminated(
+ lucet_runtime::TerminationDetails::Provided(any),
+ )) => Ok(*any
+ .downcast_ref::<__wasi_exitcode_t>()
+ .expect("termination yields an exitcode")),
+ Err(e) => bail!("runtime error: {}", e),
+ }
+}
+
+pub fn run_with_stdout<P: AsRef<Path>>(
+ path: P,
+ ctx: WasiCtxBuilder,
+) -> Result<(__wasi_exitcode_t, String), Error> {
+ let (pipe_out, pipe_in) = nix::unistd::pipe()?;
+
+ let ctx = unsafe { ctx.raw_fd(1, pipe_in) }.build()?;
+
+ let exitcode = run(path, ctx)?;
+
+ let mut stdout_file = unsafe { File::from_raw_fd(pipe_out) };
+ let mut stdout = String::new();
+ stdout_file.read_to_string(&mut stdout)?;
+ nix::unistd::close(stdout_file.into_raw_fd())?;
+
+ Ok((exitcode, stdout))
+}
+
+/// Call this if you're having trouble with `__wasi_*` symbols not being exported.
+///
+/// This is pretty hackish; we will hopefully be able to avoid this altogether once [this
+/// issue](https://github.com/rust-lang/rust/issues/58037) is addressed.
+#[no_mangle]
+#[doc(hidden)]
+pub extern "C" fn lucet_wasi_tests_internal_ensure_linked() {
+ lucet_wasi::hostcalls::ensure_linked();
+}
diff --git a/third_party/rust/lucet-wasi-wasmsbx/tests/tests.rs b/third_party/rust/lucet-wasi-wasmsbx/tests/tests.rs
new file mode 100644
index 0000000000..18cdf386d2
--- /dev/null
+++ b/third_party/rust/lucet-wasi-wasmsbx/tests/tests.rs
@@ -0,0 +1,405 @@
+mod test_helpers;
+
+use crate::test_helpers::{run, run_with_stdout, LUCET_WASI_ROOT};
+use lucet_wasi::{WasiCtx, WasiCtxBuilder};
+use std::fs::File;
+use std::path::Path;
+use tempfile::TempDir;
+
+#[test]
+fn double_import() {
+ let ctx = WasiCtxBuilder::new();
+
+ let (exitcode, stdout) = run_with_stdout("duplicate_import.wat", ctx).unwrap();
+
+ assert_eq!(stdout, "duplicate import works!\n");
+ assert_eq!(exitcode, 0);
+}
+
+#[test]
+fn hello() {
+ let ctx = WasiCtxBuilder::new().args(&["hello"]);
+
+ let (exitcode, stdout) = run_with_stdout(
+ Path::new(LUCET_WASI_ROOT).join("examples").join("hello.c"),
+ ctx,
+ )
+ .unwrap();
+
+ assert_eq!(exitcode, 0);
+ assert_eq!(&stdout, "hello, wasi!\n");
+}
+
+#[test]
+fn hello_args() {
+ let ctx = WasiCtxBuilder::new().args(&["hello", "test suite"]);
+
+ let (exitcode, stdout) = run_with_stdout(
+ Path::new(LUCET_WASI_ROOT).join("examples").join("hello.c"),
+ ctx,
+ )
+ .unwrap();
+
+ assert_eq!(exitcode, 0);
+ assert_eq!(&stdout, "hello, test suite!\n");
+}
+
+#[test]
+fn hello_env() {
+ let ctx = WasiCtxBuilder::new()
+ .args(&["hello", "test suite"])
+ .env("GREETING", "goodbye");
+
+ let (exitcode, stdout) = run_with_stdout(
+ Path::new(LUCET_WASI_ROOT).join("examples").join("hello.c"),
+ ctx,
+ )
+ .unwrap();
+
+ assert_eq!(exitcode, 0);
+ assert_eq!(&stdout, "goodbye, test suite!\n");
+}
+
+#[test]
+fn exitcode() {
+ let ctx = WasiCtx::new(&["exitcode"]);
+
+ let exitcode = run("exitcode.c", ctx).unwrap();
+
+ assert_eq!(exitcode, 120);
+}
+
+#[test]
+fn clock_getres() {
+ let ctx = WasiCtx::new(&["clock_getres"]);
+
+ let exitcode = run("clock_getres.c", ctx).unwrap();
+
+ assert_eq!(exitcode, 0);
+}
+
+#[test]
+fn getrusage() {
+ let ctx = WasiCtx::new(&["getrusage"]);
+
+ let exitcode = run("getrusage.c", ctx).unwrap();
+
+ assert_eq!(exitcode, 0);
+}
+
+#[test]
+fn gettimeofday() {
+ let ctx = WasiCtx::new(&["gettimeofday"]);
+
+ let exitcode = run("gettimeofday.c", ctx).unwrap();
+
+ assert_eq!(exitcode, 0);
+}
+
+#[test]
+fn getentropy() {
+ let ctx = WasiCtx::new(&["getentropy"]);
+
+ let exitcode = run("getentropy.c", ctx).unwrap();
+
+ assert_eq!(exitcode, 0);
+}
+
+#[test]
+fn stdin() {
+ use std::io::Write;
+ use std::os::unix::io::FromRawFd;
+
+ let (pipe_out, pipe_in) = nix::unistd::pipe().expect("can create pipe");
+
+ let mut stdin_file = unsafe { File::from_raw_fd(pipe_in) };
+ write!(stdin_file, "hello from stdin!").expect("pipe write succeeds");
+ drop(stdin_file);
+
+ let ctx = unsafe { WasiCtxBuilder::new().args(&["stdin"]).raw_fd(0, pipe_out) };
+
+ let (exitcode, stdout) = run_with_stdout("stdin.c", ctx).unwrap();
+
+ assert_eq!(exitcode, 0);
+ assert_eq!(&stdout, "hello from stdin!");
+}
+
+#[test]
+fn preopen_populates() {
+ let tmpdir = TempDir::new().unwrap();
+ let preopen_host_path = tmpdir.path().join("preopen");
+ std::fs::create_dir(&preopen_host_path).unwrap();
+ let preopen_dir = File::open(preopen_host_path).unwrap();
+
+ let ctx = WasiCtxBuilder::new()
+ .args(&["preopen_populates"])
+ .preopened_dir(preopen_dir, "/preopen")
+ .build()
+ .expect("can build WasiCtx");
+
+ let exitcode = run("preopen_populates.c", ctx).unwrap();
+
+ drop(tmpdir);
+
+ assert_eq!(exitcode, 0);
+}
+
+#[test]
+fn write_file() {
+ let tmpdir = TempDir::new().unwrap();
+ let preopen_host_path = tmpdir.path().join("preopen");
+ std::fs::create_dir(&preopen_host_path).unwrap();
+ let preopen_dir = File::open(&preopen_host_path).unwrap();
+
+ let ctx = WasiCtxBuilder::new()
+ .args(&["write_file"])
+ .preopened_dir(preopen_dir, "/sandbox")
+ .build()
+ .expect("can build WasiCtx");
+
+ let exitcode = run("write_file.c", ctx).unwrap();
+ assert_eq!(exitcode, 0);
+
+ let output = std::fs::read(preopen_host_path.join("output.txt")).unwrap();
+
+ assert_eq!(output.as_slice(), b"hello, file!");
+
+ drop(tmpdir);
+}
+
+#[test]
+fn read_file() {
+ const MESSAGE: &'static str = "hello from file!";
+ let tmpdir = TempDir::new().unwrap();
+ let preopen_host_path = tmpdir.path().join("preopen");
+ std::fs::create_dir(&preopen_host_path).unwrap();
+
+ std::fs::write(preopen_host_path.join("input.txt"), MESSAGE).unwrap();
+
+ let preopen_dir = File::open(&preopen_host_path).unwrap();
+
+ let ctx = WasiCtxBuilder::new()
+ .args(&["read_file"])
+ .preopened_dir(preopen_dir, "/sandbox");
+
+ let (exitcode, stdout) = run_with_stdout("read_file.c", ctx).unwrap();
+ assert_eq!(exitcode, 0);
+
+ assert_eq!(&stdout, MESSAGE);
+
+ drop(tmpdir);
+}
+
+#[test]
+fn read_file_twice() {
+ const MESSAGE: &'static str = "hello from file!";
+ let tmpdir = TempDir::new().unwrap();
+ let preopen_host_path = tmpdir.path().join("preopen");
+ std::fs::create_dir(&preopen_host_path).unwrap();
+
+ std::fs::write(preopen_host_path.join("input.txt"), MESSAGE).unwrap();
+
+ let preopen_dir = File::open(&preopen_host_path).unwrap();
+
+ let ctx = WasiCtxBuilder::new()
+ .args(&["read_file_twice"])
+ .preopened_dir(preopen_dir, "/sandbox");
+
+ let (exitcode, stdout) = run_with_stdout("read_file_twice.c", ctx).unwrap();
+ assert_eq!(exitcode, 0);
+
+ let double_message = format!("{}{}", MESSAGE, MESSAGE);
+ assert_eq!(stdout, double_message);
+
+ drop(tmpdir);
+}
+
+#[test]
+fn cant_dotdot() {
+ const MESSAGE: &'static str = "hello from file!";
+ let tmpdir = TempDir::new().unwrap();
+ let preopen_host_path = tmpdir.path().join("preopen");
+ std::fs::create_dir(&preopen_host_path).unwrap();
+
+ std::fs::write(
+ preopen_host_path.parent().unwrap().join("outside.txt"),
+ MESSAGE,
+ )
+ .unwrap();
+
+ let preopen_dir = File::open(&preopen_host_path).unwrap();
+
+ let ctx = WasiCtxBuilder::new()
+ .args(&["cant_dotdot"])
+ .preopened_dir(preopen_dir, "/sandbox")
+ .build()
+ .unwrap();
+
+ let exitcode = run("cant_dotdot.c", ctx).unwrap();
+ assert_eq!(exitcode, 0);
+
+ drop(tmpdir);
+}
+
+#[ignore] // needs fd_readdir
+#[test]
+fn notdir() {
+ const MESSAGE: &'static str = "hello from file!";
+ let tmpdir = TempDir::new().unwrap();
+ let preopen_host_path = tmpdir.path().join("preopen");
+ std::fs::create_dir(&preopen_host_path).unwrap();
+
+ std::fs::write(preopen_host_path.join("notadir"), MESSAGE).unwrap();
+
+ let preopen_dir = File::open(&preopen_host_path).unwrap();
+
+ let ctx = WasiCtxBuilder::new()
+ .args(&["notdir"])
+ .preopened_dir(preopen_dir, "/sandbox")
+ .build()
+ .unwrap();
+
+ let exitcode = run("notdir.c", ctx).unwrap();
+ assert_eq!(exitcode, 0);
+
+ drop(tmpdir);
+}
+
+#[test]
+fn follow_symlink() {
+ const MESSAGE: &'static str = "hello from file!";
+
+ let tmpdir = TempDir::new().unwrap();
+ let preopen_host_path = tmpdir.path().join("preopen");
+ let subdir1 = preopen_host_path.join("subdir1");
+ let subdir2 = preopen_host_path.join("subdir2");
+ std::fs::create_dir_all(&subdir1).unwrap();
+ std::fs::create_dir_all(&subdir2).unwrap();
+
+ std::fs::write(subdir1.join("input.txt"), MESSAGE).unwrap();
+
+ std::os::unix::fs::symlink("../subdir1/input.txt", subdir2.join("input_link.txt")).unwrap();
+
+ let preopen_dir = File::open(&preopen_host_path).unwrap();
+
+ let ctx = WasiCtxBuilder::new()
+ .args(&["follow_symlink"])
+ .preopened_dir(preopen_dir, "/sandbox");
+
+ let (exitcode, stdout) = run_with_stdout("follow_symlink.c", ctx).unwrap();
+ assert_eq!(exitcode, 0);
+ assert_eq!(&stdout, MESSAGE);
+
+ drop(tmpdir);
+}
+
+#[test]
+fn symlink_loop() {
+ let tmpdir = TempDir::new().unwrap();
+ let preopen_host_path = tmpdir.path().join("preopen");
+ let subdir1 = preopen_host_path.join("subdir1");
+ let subdir2 = preopen_host_path.join("subdir2");
+ std::fs::create_dir_all(&subdir1).unwrap();
+ std::fs::create_dir_all(&subdir2).unwrap();
+
+ std::os::unix::fs::symlink("../subdir1/loop1", subdir2.join("loop2")).unwrap();
+ std::os::unix::fs::symlink("../subdir2/loop2", subdir1.join("loop1")).unwrap();
+
+ let preopen_dir = File::open(&preopen_host_path).unwrap();
+
+ let ctx = WasiCtxBuilder::new()
+ .args(&["symlink_loop"])
+ .preopened_dir(preopen_dir, "/sandbox")
+ .build()
+ .unwrap();
+
+ let exitcode = run("symlink_loop.c", ctx).unwrap();
+ assert_eq!(exitcode, 0);
+
+ drop(tmpdir);
+}
+
+#[test]
+fn symlink_escape() {
+ const MESSAGE: &'static str = "hello from file!";
+
+ let tmpdir = TempDir::new().unwrap();
+ let preopen_host_path = tmpdir.path().join("preopen");
+ let subdir = preopen_host_path.join("subdir");
+ std::fs::create_dir_all(&subdir).unwrap();
+
+ std::fs::write(
+ preopen_host_path.parent().unwrap().join("outside.txt"),
+ MESSAGE,
+ )
+ .unwrap();
+ std::os::unix::fs::symlink("../../outside.txt", subdir.join("outside.txt")).unwrap();
+
+ let preopen_dir = File::open(&preopen_host_path).unwrap();
+
+ let ctx = WasiCtxBuilder::new()
+ .args(&["symlink_escape"])
+ .preopened_dir(preopen_dir, "/sandbox")
+ .build()
+ .unwrap();
+
+ let exitcode = run("symlink_escape.c", ctx).unwrap();
+ assert_eq!(exitcode, 0);
+
+ drop(tmpdir);
+}
+
+#[test]
+fn pseudoquine() {
+ let examples_dir = Path::new(LUCET_WASI_ROOT).join("examples");
+ let pseudoquine_c = examples_dir.join("pseudoquine.c");
+
+ let ctx = WasiCtxBuilder::new()
+ .args(&["pseudoquine"])
+ .preopened_dir(File::open(examples_dir).unwrap(), "/examples");
+
+ let (exitcode, stdout) = run_with_stdout(&pseudoquine_c, ctx).unwrap();
+
+ assert_eq!(exitcode, 0);
+
+ let expected = std::fs::read_to_string(&pseudoquine_c).unwrap();
+
+ assert_eq!(stdout, expected);
+}
+
+#[test]
+fn poll() {
+ let ctx = WasiCtxBuilder::new().args(&["poll"]).build().unwrap();
+ let exitcode = run("poll.c", ctx).unwrap();
+ assert_eq!(exitcode, 0);
+}
+
+#[test]
+fn stat() {
+ let tmpdir = TempDir::new().unwrap();
+ let preopen_host_path = tmpdir.path().join("preopen");
+ std::fs::create_dir(&preopen_host_path).unwrap();
+ let preopen_dir = File::open(&preopen_host_path).unwrap();
+ let ctx = WasiCtxBuilder::new()
+ .args(&["stat"])
+ .preopened_dir(preopen_dir, "/sandbox")
+ .build()
+ .expect("can build WasiCtx");
+ let exitcode = run("stat.c", ctx).unwrap();
+ assert_eq!(exitcode, 0);
+}
+
+#[test]
+fn fs() {
+ let tmpdir = TempDir::new().unwrap();
+ let preopen_host_path = tmpdir.path().join("preopen");
+ std::fs::create_dir(&preopen_host_path).unwrap();
+ let preopen_dir = File::open(&preopen_host_path).unwrap();
+ let ctx = WasiCtxBuilder::new()
+ .args(&["stat"])
+ .preopened_dir(preopen_dir, "/sandbox")
+ .build()
+ .expect("can build WasiCtx");
+ let exitcode = run("fs.c", ctx).unwrap();
+ assert_eq!(exitcode, 0);
+}