diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /third_party/rust/lucet-wasi-wasmsbx | |
parent | Initial commit. (diff) | |
download | firefox-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')
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); +} |