diff --git a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmFileSuite.java b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmFileSuite.java index 78b1215d7b98..396ff22dbe72 100644 --- a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmFileSuite.java +++ b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/WasmFileSuite.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -291,6 +291,7 @@ private WasmTestStatus runTestCase(WasmCase testCase) { System.out.println("wasm.StoreConstantsPolicy: " + WasmTestOptions.STORE_CONSTANTS_POLICY); } contextBuilder.option("wasm.Builtins", includedExternalModules()); + contextBuilder.option("wasm.WasiConstantRandomGet", "true"); final String commandLineArgs = testCase.options().getProperty("command-line-args"); if (commandLineArgs != null) { // The first argument is the program name. We set it to the empty string in tests. diff --git a/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/wasi/WasiOptionsSuite.java b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/wasi/WasiOptionsSuite.java new file mode 100644 index 000000000000..9454a99e59c9 --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/org/graalvm/wasm/test/suites/wasi/WasiOptionsSuite.java @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.graalvm.wasm.test.suites.wasi; + +import org.graalvm.polyglot.Context; +import org.graalvm.polyglot.Source; +import org.graalvm.polyglot.Value; +import org.graalvm.polyglot.io.ByteSequence; +import org.graalvm.polyglot.io.FileSystem; +import org.graalvm.polyglot.io.IOAccess; +import org.graalvm.wasm.WasmLanguage; +import org.graalvm.wasm.utils.Assert; +import org.graalvm.wasm.utils.WasmBinaryTools; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.io.IOException; +import java.net.URI; +import java.nio.channels.SeekableByteChannel; +import java.nio.file.AccessMode; +import java.nio.file.DirectoryStream; +import java.nio.file.LinkOption; +import java.nio.file.OpenOption; +import java.nio.file.Path; +import java.nio.file.attribute.FileAttribute; +import java.util.Map; +import java.util.Set; + +@RunWith(Parameterized.class) +public class WasiOptionsSuite { + @Parameterized.Parameter() public String dir; + + @Parameterized.Parameter(1) public String absolutePath; + + @Parameterized.Parameters(name = "{0}") + public static String[][] dirs() { + return new String[][]{ + {".", "/test/data/foo"}, + {"/", "/foo"}, + {"/tmp", "/tmp/foo"}, + {"./tmp", "/test/data/tmp/foo"}, + {".::.", "/test/data/foo"}, + {".::/", "/test/data/foo"}, + {".::/tmp", "/test/data/foo"}, + {".::./tmp", "/test/data/foo"}, + {"/::.", "/foo"}, + {"/::/", "/foo"}, + {"/::/tmp", "/foo"}, + {"/::./tmp", "/foo"}, + {"/tmp::.", "/tmp/foo"}, + {"/tmp::/", "/tmp/foo"}, + {"/tmp::/tmp", "/tmp/foo"}, + {"/tmp::./tmp", "/tmp/foo"}, + {"./tmp::.", "/test/data/tmp/foo"}, + {"./tmp::/", "/test/data/tmp/foo"}, + {"./tmp::/tmp", "/test/data/tmp/foo"}, + {"./tmp::./tmp", "/test/data/tmp/foo"} + }; + } + + private static class TestFileSystem implements FileSystem { + + @Override + public Path parsePath(URI uri) { + return Path.of(uri); + } + + @Override + public Path parsePath(String path) { + return Path.of(path); + } + + @Override + public void checkAccess(Path path, Set modes, LinkOption... linkOptions) { + throw new UnsupportedOperationException(); + } + + @Override + public void createDirectory(Path dir, FileAttribute... attrs) { + + } + + @Override + public void delete(Path path) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public SeekableByteChannel newByteChannel(Path path, Set options, FileAttribute... attrs) { + throw new UnsupportedOperationException(); + } + + @Override + public DirectoryStream newDirectoryStream(Path dir, DirectoryStream.Filter filter) { + throw new UnsupportedOperationException(); + } + + @Override + public Path toAbsolutePath(Path path) { + throw new UnsupportedOperationException(); + } + + @Override + public Path toRealPath(Path path, LinkOption... linkOptions) { + return Path.of("/test", "data").resolve(path); + } + + @Override + public Map readAttributes(Path path, String attributes, LinkOption... options) { + throw new UnsupportedOperationException(); + } + } + + @Test + public void test() throws IOException, InterruptedException { + final byte[] source = WasmBinaryTools.compileWat("main", "" + + "(module" + + " (import \"wasi_snapshot_preview1\" \"path_create_directory\" (func $path_create_dir (param i32 i32 i32) (result i32)))" + + " (memory 1)" + + " (data (i32.const 0) \"dir\")" + + " (data (i32.const 3) \"./tmp\")" + + " (data (i32.const 8) \"" + absolutePath + "\")" + + " (export \"memory\" (memory 0))" + + " (func (export \"relative\") (result i32)" + + " (call $path_create_dir" + + " (i32.const 3)" + + " (i32.const 0)" + + " (i32.const 3)" + + " )" + + " )" + + " (func (export \"direct\") (result i32)" + + " (call $path_create_dir" + + " (i32.const 3)" + + " (i32.const 3)" + + " (i32.const 5)" + + " )" + + " )" + + " (func (export \"absolute\") (result i32)" + + " (call $path_create_dir" + + " (i32.const 3)" + + " (i32.const 8)" + + " (i32.const " + absolutePath.length() + ")" + + " )" + + " )" + + ")"); + + final Context.Builder contextBuilder = Context.newBuilder(WasmLanguage.ID); + contextBuilder.allowIO(IOAccess.newBuilder().fileSystem(new TestFileSystem()).build()); + contextBuilder.option("wasm.Builtins", "wasi_snapshot_preview1"); + contextBuilder.option("wasm.WasiMapDirs", dir); + try (Context context = contextBuilder.build()) { + final Source s = Source.newBuilder(WasmLanguage.ID, ByteSequence.create(source), "main").build(); + context.eval(s); + final Value main = context.getBindings(WasmLanguage.ID).getMember("main"); + final Value relative = main.getMember("relative"); + final Value direct = main.getMember("direct"); + final Value absolute = main.getMember("absolute"); + Assert.assertEquals("Expected success result", 0, relative.execute().asInt()); + Assert.assertEquals("Expected success result", 0, direct.execute().asInt()); + Assert.assertEquals("Expected success result", 0, absolute.execute().asInt()); + } + } +} diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_create_directory.opts b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_create_directory.opts new file mode 100644 index 000000000000..7fdb6ea57eab --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_create_directory.opts @@ -0,0 +1,2 @@ +enable-io=true +zero-memory=true diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_create_directory.result b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_create_directory.result new file mode 100644 index 000000000000..b1d422d0987c --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_create_directory.result @@ -0,0 +1 @@ +int 0 diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_create_directory.wat b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_create_directory.wat new file mode 100644 index 000000000000..bb4bf028b220 --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_create_directory.wat @@ -0,0 +1,137 @@ +;; +;; Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +;; DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +;; +;; The Universal Permissive License (UPL), Version 1.0 +;; +;; Subject to the condition set forth below, permission is hereby granted to any +;; person obtaining a copy of this software, associated documentation and/or +;; data (collectively the "Software"), free of charge and under any and all +;; copyright rights in the Software, and any and all patent rights owned or +;; freely licensable by each licensor hereunder covering either (i) the +;; unmodified Software as contributed to or provided by such licensor, or (ii) +;; the Larger Works (as defined below), to deal in both +;; +;; (a) the Software, and +;; +;; (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +;; one is included with the Software each a "Larger Work" to which the Software +;; is contributed by such licensors), +;; +;; without restriction, including without limitation the rights to copy, create +;; derivative works of, display, perform, and distribute the Software and make, +;; use, sell, offer for sale, import, export, have made, and have sold the +;; Software and the Larger Work(s), and to sublicense the foregoing rights on +;; either these or other terms. +;; +;; This license is subject to the following condition: +;; +;; The above copyright notice and either this complete permission notice or at a +;; minimum a reference to the UPL must be included in all copies or substantial +;; portions of the Software. +;; +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +;; SOFTWARE. +;; +(module + (import "wasi_snapshot_preview1" "path_filestat_get" (func $path_filestat_get (param i32 i32 i32 i32 i32) (result i32))) + (import "wasi_snapshot_preview1" "path_create_directory" (func $path_create_dir (param i32 i32 i32) (result i32))) + (import "wasi_snapshot_preview1" "path_remove_directory" (func $path_rem_dir (param i32 i32 i32) (result i32))) + (memory 1) + (data (i32.const 0) "./dir") + (export "memory" (memory 0)) + (func (export "_main") (result i32) (local $ret i32) + + ;; Check that dir does not exist + (call $path_filestat_get + (i32.const 3) ;; pre-opened "test" directory fd + (i32.const 0) ;; lookupflags + (i32.const 0) ;; pointer to path "./dir" + (i32.const 5) ;; path length + (i32.const 5) ;; filestat address + ) + i32.eqz + if + i32.const 1 + return + end + + ;; Create dir + (call $path_create_dir + (i32.const 3) ;; pre-opened "test" directory fd + (i32.const 0) ;; pointer to path "./dir" + (i32.const 5) ;; path length + ) + + local.tee $ret + + i32.const 0 + i32.ne + if + local.get $ret + return + end + + ;; Check that dir was created + (call $path_filestat_get + (i32.const 3) ;; pre-opened "test" directory fd + (i32.const 0) ;; lookup flags + (i32.const 0) ;; pointer to path "./dir" + (i32.const 5) ;; path length + (i32.const 5) ;; filestat address + ) + + local.tee $ret + + i32.const 0 + i32.ne + if + local.get $ret + return + end + + ;; Remove dir + (call $path_rem_dir + (i32.const 3) ;; pre-opened "test" directory fd + (i32.const 0) ;; pointer to path "./dir" + (i32.const 5) ;; path length + ) + + local.tee $ret + + i32.const 0 + i32.ne + if + local.get $ret + return + end + + ;; Check that dir does not exist + (call $path_filestat_get + (i32.const 3) ;; pre-opened "test" directory fd + (i32.const 0) ;; lookupflags + (i32.const 0) ;; pointer to path "./dir" + (i32.const 5) ;; path length + (i32.const 5) ;; filestat address + ) + i32.eqz + if + i32.const 1 + return + end + + ;; Clear filestat entry + (memory.fill + (i32.const 5) ;; start offset + (i32.const 0) ;; value + (i32.const 64) ;; length + ) + + i32.const 0 + ) +) diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_filestat_get-file.opts b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_filestat_get-file.opts new file mode 100644 index 000000000000..7bfd1a84a622 --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_filestat_get-file.opts @@ -0,0 +1 @@ +enable-io=true diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_filestat_get-file.result b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_filestat_get-file.result new file mode 100644 index 000000000000..b1d422d0987c --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_filestat_get-file.result @@ -0,0 +1 @@ +int 0 diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_filestat_get-file.wat b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_filestat_get-file.wat new file mode 100644 index 000000000000..ef74cd272284 --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_filestat_get-file.wat @@ -0,0 +1,86 @@ +;; +;; Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +;; DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +;; +;; The Universal Permissive License (UPL), Version 1.0 +;; +;; Subject to the condition set forth below, permission is hereby granted to any +;; person obtaining a copy of this software, associated documentation and/or +;; data (collectively the "Software"), free of charge and under any and all +;; copyright rights in the Software, and any and all patent rights owned or +;; freely licensable by each licensor hereunder covering either (i) the +;; unmodified Software as contributed to or provided by such licensor, or (ii) +;; the Larger Works (as defined below), to deal in both +;; +;; (a) the Software, and +;; +;; (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +;; one is included with the Software each a "Larger Work" to which the Software +;; is contributed by such licensors), +;; +;; without restriction, including without limitation the rights to copy, create +;; derivative works of, display, perform, and distribute the Software and make, +;; use, sell, offer for sale, import, export, have made, and have sold the +;; Software and the Larger Work(s), and to sublicense the foregoing rights on +;; either these or other terms. +;; +;; This license is subject to the following condition: +;; +;; The above copyright notice and either this complete permission notice or at a +;; minimum a reference to the UPL must be included in all copies or substantial +;; portions of the Software. +;; +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +;; SOFTWARE. +;; +(module + (import "wasi_snapshot_preview1" "path_filestat_get" (func $path_filestat_get (param i32 i32 i32 i32 i32) (result i32))) + (memory 1) + (data (i32.const 0) "file.txt") + (export "memory" (memory 0)) + (func (export "_main") (result i32) (local $ret i32) + (call $path_filestat_get + (i32.const 3) ;; pre-opened "test" directory fd + (i32.const 0) ;; lookupflags + (i32.const 0) ;; pointer to path "file.txt" + (i32.const 8) ;; path length + (i32.const 8) ;; filestat address + ) + local.tee $ret + i32.const 0 + i32.ne + if + local.get $ret + return + end + + ;; Check if filetype is correct + i32.const 24 + i64.load + i64.const 4 + i64.ne + if + i32.const 1 + return + end + + ;; Check if size is correct + i32.const 40 + i64.load + i64.const 17 + i64.ne + if + i32.const 1 + return + end + + ;; Cannot check other file attributes since they are platform specific + + i32.const 0 + ) +) diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_filestat_set_times-file.opts b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_filestat_set_times-file.opts new file mode 100644 index 000000000000..7bfd1a84a622 --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_filestat_set_times-file.opts @@ -0,0 +1 @@ +enable-io=true diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_filestat_set_times-file.result b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_filestat_set_times-file.result new file mode 100644 index 000000000000..b1d422d0987c --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_filestat_set_times-file.result @@ -0,0 +1 @@ +int 0 diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_filestat_set_times-file.wat b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_filestat_set_times-file.wat new file mode 100644 index 000000000000..86ddbacd90c4 --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_filestat_set_times-file.wat @@ -0,0 +1,108 @@ +;; +;; Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +;; DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +;; +;; The Universal Permissive License (UPL), Version 1.0 +;; +;; Subject to the condition set forth below, permission is hereby granted to any +;; person obtaining a copy of this software, associated documentation and/or +;; data (collectively the "Software"), free of charge and under any and all +;; copyright rights in the Software, and any and all patent rights owned or +;; freely licensable by each licensor hereunder covering either (i) the +;; unmodified Software as contributed to or provided by such licensor, or (ii) +;; the Larger Works (as defined below), to deal in both +;; +;; (a) the Software, and +;; +;; (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +;; one is included with the Software each a "Larger Work" to which the Software +;; is contributed by such licensors), +;; +;; without restriction, including without limitation the rights to copy, create +;; derivative works of, display, perform, and distribute the Software and make, +;; use, sell, offer for sale, import, export, have made, and have sold the +;; Software and the Larger Work(s), and to sublicense the foregoing rights on +;; either these or other terms. +;; +;; This license is subject to the following condition: +;; +;; The above copyright notice and either this complete permission notice or at a +;; minimum a reference to the UPL must be included in all copies or substantial +;; portions of the Software. +;; +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +;; SOFTWARE. +;; +(module + (import "wasi_snapshot_preview1" "path_filestat_get" (func $path_filestat_get (param i32 i32 i32 i32 i32) (result i32))) + (import "wasi_snapshot_preview1" "path_filestat_set_times" (func $path_filestat_set_times (param i32 i32 i32 i32 i64 i64 i32) (result i32))) + (memory 1) + (data (i32.const 0) "file.txt") + (export "memory" (memory 0)) + (func (export "_main") (result i32) (local $ret i32) + + ;; set times + (call $path_filestat_set_times + (i32.const 3) ;; pre-opened "test" directory fd + (i32.const 0) ;; lookup flags + (i32.const 0) ;; pointer to file "file.txt" + (i32.const 8) ;; path length + (i64.const 1675928482000000000) ;; Thursday, February 9, 2023 7:41:22 AM + (i64.const 1675928482000000000) ;; Thursday, February 9, 2023 7:41:22 AM + (i32.const 5) ;; fst flags + ) + + local.tee $ret + i32.const 0 + i32.ne + if + local.get $ret + return + end + + ;; Check that times were set correctly + (call $path_filestat_get + (i32.const 3) ;; pre-opened "test" directory fd + (i32.const 0) ;; lookupflags + (i32.const 0) ;; pointer to path "file.txt" + (i32.const 8) ;; path length + (i32.const 8) ;; filestat address + ) + + local.tee $ret + i32.const 0 + i32.ne + + i32.const 8 + i64.load offset=40 + i64.const 1675928482000000000 + i64.ne + + i32.const 8 + i64.load offset=48 + i64.const 1675928482000000000 + i64.ne + + i32.or + i32.or + if + i32.const 1 + return + end + + + ;; Clear filestat entry + (memory.fill + (i32.const 8) ;; start offset + (i32.const 0) ;; value + (i32.const 64) ;; length + ) + + i32.const 0 + ) +) diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_link-file.opts b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_link-file.opts new file mode 100644 index 000000000000..7bfd1a84a622 --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_link-file.opts @@ -0,0 +1 @@ +enable-io=true diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_link-file.result b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_link-file.result new file mode 100644 index 000000000000..b1d422d0987c --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_link-file.result @@ -0,0 +1 @@ +int 0 diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_link-file.wat b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_link-file.wat new file mode 100644 index 000000000000..776b33b9708a --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_link-file.wat @@ -0,0 +1,75 @@ +;; +;; Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +;; DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +;; +;; The Universal Permissive License (UPL), Version 1.0 +;; +;; Subject to the condition set forth below, permission is hereby granted to any +;; person obtaining a copy of this software, associated documentation and/or +;; data (collectively the "Software"), free of charge and under any and all +;; copyright rights in the Software, and any and all patent rights owned or +;; freely licensable by each licensor hereunder covering either (i) the +;; unmodified Software as contributed to or provided by such licensor, or (ii) +;; the Larger Works (as defined below), to deal in both +;; +;; (a) the Software, and +;; +;; (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +;; one is included with the Software each a "Larger Work" to which the Software +;; is contributed by such licensors), +;; +;; without restriction, including without limitation the rights to copy, create +;; derivative works of, display, perform, and distribute the Software and make, +;; use, sell, offer for sale, import, export, have made, and have sold the +;; Software and the Larger Work(s), and to sublicense the foregoing rights on +;; either these or other terms. +;; +;; This license is subject to the following condition: +;; +;; The above copyright notice and either this complete permission notice or at a +;; minimum a reference to the UPL must be included in all copies or substantial +;; portions of the Software. +;; +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +;; SOFTWARE. +;; +(module + (import "wasi_snapshot_preview1" "path_link" (func $path_link (param i32 i32 i32 i32 i32 i32 i32) (result i32))) + (import "wasi_snapshot_preview1" "path_unlink_file" (func $path_unlink_file (param i32 i32 i32) (result i32))) + (memory 1) + (data (i32.const 0) "file.txt") + (data (i32.const 8) "link") + (export "memory" (memory 0)) + (func (export "_main") (result i32) (local $ret i32) + ;; Create a hard link + (call $path_link + (i32.const 3) ;; pre-opeend "test" directory fd + (i32.const 0) ;; lookup flags + (i32.const 0) ;; pointer to "file.txt" + (i32.const 8) ;; pointer length + (i32.const 3) ;; pre-opened "test" directory fd + (i32.const 8) ;; pointer to "link" + (i32.const 4) ;; pointer length + ) + + local.tee $ret + i32.const 0 + i32.ne + if + local.get $ret + return + end + + ;; Remove hard link + (call $path_unlink_file + (i32.const 3) ;; pre-opened "test" directory fd + (i32.const 8) ;; pointer to "link" + (i32.const 4) ;; path length + ) + ) +) diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_open-existing-file.opts b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_open-existing-file.opts index d12b465d953f..7bfd1a84a622 100644 --- a/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_open-existing-file.opts +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_open-existing-file.opts @@ -1 +1 @@ -enable-io=true \ No newline at end of file +enable-io=true diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_open-existing-file.result b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_open-existing-file.result index 8a50673d0631..b1d422d0987c 100644 --- a/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_open-existing-file.result +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_open-existing-file.result @@ -1 +1 @@ -int 0 \ No newline at end of file +int 0 diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_remove_directory.opts b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_remove_directory.opts new file mode 100644 index 000000000000..7fdb6ea57eab --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_remove_directory.opts @@ -0,0 +1,2 @@ +enable-io=true +zero-memory=true diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_remove_directory.result b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_remove_directory.result new file mode 100644 index 000000000000..b1d422d0987c --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_remove_directory.result @@ -0,0 +1 @@ +int 0 diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_remove_directory.wat b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_remove_directory.wat new file mode 100644 index 000000000000..50e5ba4a8150 --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_remove_directory.wat @@ -0,0 +1,89 @@ +;; +;; Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +;; DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +;; +;; The Universal Permissive License (UPL), Version 1.0 +;; +;; Subject to the condition set forth below, permission is hereby granted to any +;; person obtaining a copy of this software, associated documentation and/or +;; data (collectively the "Software"), free of charge and under any and all +;; copyright rights in the Software, and any and all patent rights owned or +;; freely licensable by each licensor hereunder covering either (i) the +;; unmodified Software as contributed to or provided by such licensor, or (ii) +;; the Larger Works (as defined below), to deal in both +;; +;; (a) the Software, and +;; +;; (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +;; one is included with the Software each a "Larger Work" to which the Software +;; is contributed by such licensors), +;; +;; without restriction, including without limitation the rights to copy, create +;; derivative works of, display, perform, and distribute the Software and make, +;; use, sell, offer for sale, import, export, have made, and have sold the +;; Software and the Larger Work(s), and to sublicense the foregoing rights on +;; either these or other terms. +;; +;; This license is subject to the following condition: +;; +;; The above copyright notice and either this complete permission notice or at a +;; minimum a reference to the UPL must be included in all copies or substantial +;; portions of the Software. +;; +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +;; SOFTWARE. +;; +(module + (import "wasi_snapshot_preview1" "path_filestat_get" (func $path_filestat_get (param i32 i32 i32 i32 i32) (result i32))) + (import "wasi_snapshot_preview1" "path_remove_directory" (func $path_rem_dir (param i32 i32 i32) (result i32))) + (memory 1) + (data (i32.const 0) "file.txt") + (export "memory" (memory 0)) + (func (export "_main") (result i32) (local $ret i32) + ;; Remove dir + (call $path_rem_dir + (i32.const 3) ;; pre-opened "test" directory fd + (i32.const 0) ;; pointer to path "file.txt" + (i32.const 8) ;; path length + ) + + local.tee $ret + + i32.eqz + if + i32.const 1 + return + end + + ;; Check that file still exist + (call $path_filestat_get + (i32.const 3) ;; pre-opened "test" directory fd + (i32.const 0) ;; lookupflags + (i32.const 0) ;; pointer to path "file.txt" + (i32.const 8) ;; path length + (i32.const 5) ;; filestat address + ) + local.tee $ret + + i32.const 0 + i32.ne + if + local.get $ret + return + end + + ;; Clear filestat entry + (memory.fill + (i32.const 5) ;; start offset + (i32.const 0) ;; value + (i32.const 64) ;; length + ) + + i32.const 0 + ) +) diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_rename-file.opts b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_rename-file.opts new file mode 100644 index 000000000000..7bfd1a84a622 --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_rename-file.opts @@ -0,0 +1 @@ +enable-io=true diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_rename-file.result b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_rename-file.result new file mode 100644 index 000000000000..b1d422d0987c --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_rename-file.result @@ -0,0 +1 @@ +int 0 diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_rename-file.wat b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_rename-file.wat new file mode 100644 index 000000000000..1125ce5ee467 --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_rename-file.wat @@ -0,0 +1,77 @@ +;; +;; Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +;; DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +;; +;; The Universal Permissive License (UPL), Version 1.0 +;; +;; Subject to the condition set forth below, permission is hereby granted to any +;; person obtaining a copy of this software, associated documentation and/or +;; data (collectively the "Software"), free of charge and under any and all +;; copyright rights in the Software, and any and all patent rights owned or +;; freely licensable by each licensor hereunder covering either (i) the +;; unmodified Software as contributed to or provided by such licensor, or (ii) +;; the Larger Works (as defined below), to deal in both +;; +;; (a) the Software, and +;; +;; (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +;; one is included with the Software each a "Larger Work" to which the Software +;; is contributed by such licensors), +;; +;; without restriction, including without limitation the rights to copy, create +;; derivative works of, display, perform, and distribute the Software and make, +;; use, sell, offer for sale, import, export, have made, and have sold the +;; Software and the Larger Work(s), and to sublicense the foregoing rights on +;; either these or other terms. +;; +;; This license is subject to the following condition: +;; +;; The above copyright notice and either this complete permission notice or at a +;; minimum a reference to the UPL must be included in all copies or substantial +;; portions of the Software. +;; +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +;; SOFTWARE. +;; +(module + (import "wasi_snapshot_preview1" "path_rename" (func $path_rename (param i32 i32 i32 i32 i32 i32) (result i32))) + (import "wasi_snapshot_preview1" "path_unlink_file" (func $path_unlink_file (param i32 i32 i32) (result i32))) + (memory 1) + (data (i32.const 0) "file.txt") + (data (i32.const 8) "rename.txt") + (export "memory" (memory 0)) + (func (export "_main") (result i32) (local $ret i32) + ;; Rename file + (call $path_rename + (i32.const 3) ;; pre-opened "test" directory fd + (i32.const 0) ;; pointer to "file.txt" + (i32.const 8) ;; pointer length + (i32.const 3) ;; pre-opened "test" directory fd + (i32.const 8) ;; pointer to "rename.txt" + (i32.const 10) ;; pointer length + ) + + local.tee $ret + i32.const 0 + i32.ne + if + local.get $ret + return + end + + ;; Rename back + (call $path_rename + (i32.const 3) ;; pre-opened "test" directory fd + (i32.const 8) ;; pointer to "rename.txt" + (i32.const 10) ;; pointer length + (i32.const 3) ;; pre-opened "test" directory fd + (i32.const 0) ;; pointer to "file.txt" + (i32.const 8) ;; pointer length + ) + ) +) \ No newline at end of file diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_symlink-file.opts b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_symlink-file.opts new file mode 100644 index 000000000000..7bfd1a84a622 --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_symlink-file.opts @@ -0,0 +1 @@ +enable-io=true diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_symlink-file.result b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_symlink-file.result new file mode 100644 index 000000000000..b1d422d0987c --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_symlink-file.result @@ -0,0 +1 @@ +int 0 diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_symlink-file.wat b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_symlink-file.wat new file mode 100644 index 000000000000..1186c8121c01 --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/path_symlink-file.wat @@ -0,0 +1,73 @@ +;; +;; Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +;; DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +;; +;; The Universal Permissive License (UPL), Version 1.0 +;; +;; Subject to the condition set forth below, permission is hereby granted to any +;; person obtaining a copy of this software, associated documentation and/or +;; data (collectively the "Software"), free of charge and under any and all +;; copyright rights in the Software, and any and all patent rights owned or +;; freely licensable by each licensor hereunder covering either (i) the +;; unmodified Software as contributed to or provided by such licensor, or (ii) +;; the Larger Works (as defined below), to deal in both +;; +;; (a) the Software, and +;; +;; (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +;; one is included with the Software each a "Larger Work" to which the Software +;; is contributed by such licensors), +;; +;; without restriction, including without limitation the rights to copy, create +;; derivative works of, display, perform, and distribute the Software and make, +;; use, sell, offer for sale, import, export, have made, and have sold the +;; Software and the Larger Work(s), and to sublicense the foregoing rights on +;; either these or other terms. +;; +;; This license is subject to the following condition: +;; +;; The above copyright notice and either this complete permission notice or at a +;; minimum a reference to the UPL must be included in all copies or substantial +;; portions of the Software. +;; +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +;; SOFTWARE. +;; +(module + (import "wasi_snapshot_preview1" "path_symlink" (func $path_symlink (param i32 i32 i32 i32 i32) (result i32))) + (import "wasi_snapshot_preview1" "path_unlink_file" (func $path_unlink_file (param i32 i32 i32) (result i32))) + (memory 1) + (data (i32.const 0) "file.txt") + (data (i32.const 8) "link") + (export "memory" (memory 0)) + (func (export "_main") (result i32) (local $ret i32) + ;; Create a hard link + (call $path_symlink + (i32.const 0) ;; pointer to "file.txt" + (i32.const 8) ;; pointer length + (i32.const 3) ;; pre-opened "test" directory fd + (i32.const 8) ;; pointer to "link" + (i32.const 4) ;; pointer length + ) + + local.tee $ret + i32.const 0 + i32.ne + if + local.get $ret + return + end + + ;; Remove hard link + (call $path_unlink_file + (i32.const 3) ;; pre-opened "test" directory fd + (i32.const 8) ;; pointer to "link" + (i32.const 4) ;; path length + ) + ) +) diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/proc-exit.result b/wasm/src/org.graalvm.wasm.test/src/test/wasi/proc-exit.result index fc0b88b6fc63..08b0c54162cf 100644 --- a/wasm/src/org.graalvm.wasm.test/src/test/wasi/proc-exit.result +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/proc-exit.result @@ -1 +1 @@ -exception Program exited with status code 11. \ No newline at end of file +exception Program exited with status code 11. diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/random_get.result b/wasm/src/org.graalvm.wasm.test/src/test/wasi/random_get.result new file mode 100644 index 000000000000..b1d422d0987c --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/random_get.result @@ -0,0 +1 @@ +int 0 diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/random_get.wat b/wasm/src/org.graalvm.wasm.test/src/test/wasi/random_get.wat new file mode 100644 index 000000000000..26fda47c45ed --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/random_get.wat @@ -0,0 +1,54 @@ +;; +;; Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +;; DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +;; +;; The Universal Permissive License (UPL), Version 1.0 +;; +;; Subject to the condition set forth below, permission is hereby granted to any +;; person obtaining a copy of this software, associated documentation and/or +;; data (collectively the "Software"), free of charge and under any and all +;; copyright rights in the Software, and any and all patent rights owned or +;; freely licensable by each licensor hereunder covering either (i) the +;; unmodified Software as contributed to or provided by such licensor, or (ii) +;; the Larger Works (as defined below), to deal in both +;; +;; (a) the Software, and +;; +;; (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +;; one is included with the Software each a "Larger Work" to which the Software +;; is contributed by such licensors), +;; +;; without restriction, including without limitation the rights to copy, create +;; derivative works of, display, perform, and distribute the Software and make, +;; use, sell, offer for sale, import, export, have made, and have sold the +;; Software and the Larger Work(s), and to sublicense the foregoing rights on +;; either these or other terms. +;; +;; This license is subject to the following condition: +;; +;; The above copyright notice and either this complete permission notice or at a +;; minimum a reference to the UPL must be included in all copies or substantial +;; portions of the Software. +;; +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +;; SOFTWARE. +;; +(module + (type (;0;) (func (param i32 i32) (result i32))) + (type (;1;) (func (result i32))) + (import "wasi_snapshot_preview1" "random_get" (func $__wasi_random_get (type 0))) + (memory (;0;) 4) + (export "memory" (memory 0)) + (func (export "_main") (type 1) + i32.const 0 + i32.const 4 + call $__wasi_random_get + drop + i32.const 0 + ) +) diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/sched_yield.result b/wasm/src/org.graalvm.wasm.test/src/test/wasi/sched_yield.result new file mode 100644 index 000000000000..b1d422d0987c --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/sched_yield.result @@ -0,0 +1 @@ +int 0 diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/sched_yield.wat b/wasm/src/org.graalvm.wasm.test/src/test/wasi/sched_yield.wat new file mode 100644 index 000000000000..634996308311 --- /dev/null +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/sched_yield.wat @@ -0,0 +1,65 @@ +;; +;; Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. +;; DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +;; +;; The Universal Permissive License (UPL), Version 1.0 +;; +;; Subject to the condition set forth below, permission is hereby granted to any +;; person obtaining a copy of this software, associated documentation and/or +;; data (collectively the "Software"), free of charge and under any and all +;; copyright rights in the Software, and any and all patent rights owned or +;; freely licensable by each licensor hereunder covering either (i) the +;; unmodified Software as contributed to or provided by such licensor, or (ii) +;; the Larger Works (as defined below), to deal in both +;; +;; (a) the Software, and +;; +;; (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +;; one is included with the Software each a "Larger Work" to which the Software +;; is contributed by such licensors), +;; +;; without restriction, including without limitation the rights to copy, create +;; derivative works of, display, perform, and distribute the Software and make, +;; use, sell, offer for sale, import, export, have made, and have sold the +;; Software and the Larger Work(s), and to sublicense the foregoing rights on +;; either these or other terms. +;; +;; This license is subject to the following condition: +;; +;; The above copyright notice and either this complete permission notice or at a +;; minimum a reference to the UPL must be included in all copies or substantial +;; portions of the Software. +;; +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +;; SOFTWARE. +;; +(module + (type (;0;) (func (result i32))) + (import "wasi_snapshot_preview1" "sched_yield" (func $__wasi_sched_yield (type 0))) + (memory (;0;) 4) + (export "memory" (memory 0)) + (func (export "_main") (type 0) + (local $i i32) + i32.const 100 + local.set $i + block + loop + local.get $i + i32.const 1 + i32.sub + local.tee $i + call $__wasi_sched_yield + drop + i32.eqz + br_if 1 + br 0 + end + end + i32.const 0 + ) +) diff --git a/wasm/src/org.graalvm.wasm.test/src/test/wasi/wasm_test_index b/wasm/src/org.graalvm.wasm.test/src/test/wasi/wasm_test_index index 10738aa2fd80..c31b05b741bd 100644 --- a/wasm/src/org.graalvm.wasm.test/src/test/wasi/wasm_test_index +++ b/wasm/src/org.graalvm.wasm.test/src/test/wasi/wasm_test_index @@ -10,4 +10,13 @@ fd_seek-file fd_fdstat_get-file fd_filestat_get-file fd_fdstat_set_flags-file -path_open-existing-file \ No newline at end of file +path_create_directory +path_filestat_get-file +path_filestat_set_times-file +path_link-file +path_open-existing-file +path_remove_directory +path_rename-file +path_symlink-file +random_get +sched_yield diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmContextOptions.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmContextOptions.java index 0e3379908f30..f525d1c86274 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmContextOptions.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmContextOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -56,6 +56,8 @@ public class WasmContextOptions { @CompilationFinal private boolean unsafeMemory; @CompilationFinal private boolean memoryOverheadMode; + @CompilationFinal private boolean constantRandomGet; + private final OptionValues optionValues; WasmContextOptions(OptionValues optionValues) { @@ -76,6 +78,7 @@ private void setOptionValues() { this.memory64 = readBooleanOption(WasmOptions.Memory64); this.unsafeMemory = readBooleanOption(WasmOptions.UseUnsafeMemory); this.memoryOverheadMode = readBooleanOption(WasmOptions.MemoryOverheadMode); + this.constantRandomGet = readBooleanOption(WasmOptions.WasiConstantRandomGet); } private void checkOptionDependencies() { @@ -120,6 +123,10 @@ public boolean memoryOverheadMode() { return memoryOverheadMode; } + public boolean constantRandomGet() { + return constantRandomGet; + } + @Override public int hashCode() { int hash = 5; @@ -130,6 +137,7 @@ public int hashCode() { hash = 53 * hash + (this.memory64 ? 1 : 0); hash = 53 * hash + (this.unsafeMemory ? 1 : 0); hash = 53 * hash + (this.memoryOverheadMode ? 1 : 0); + hash = 53 * hash + (this.constantRandomGet ? 1 : 0); return hash; } @@ -166,6 +174,9 @@ public boolean equals(Object obj) { if (this.memoryOverheadMode != other.memoryOverheadMode) { return false; } + if (this.constantRandomGet != other.constantRandomGet) { + return false; + } return true; } } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmOptions.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmOptions.java index 4d49e030fffd..4456da31d2d4 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmOptions.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/WasmOptions.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -57,7 +57,7 @@ public class WasmOptions { @Option(help = "The stack size in kilobytes to use during async parsing, or zero to use defaults.", category = OptionCategory.USER, stability = OptionStability.STABLE, usageSyntax = "[0, inf)")// public static final OptionKey AsyncParsingStackSize = new OptionKey<>(0); - @Option(help = "A comma-separated list of pre-opened Wasi directories.", category = OptionCategory.USER, stability = OptionStability.STABLE, usageSyntax = "[:],[:],...")// + @Option(help = "A comma-separated list of pre-opened Wasi directories.", category = OptionCategory.USER, stability = OptionStability.STABLE, usageSyntax = "[::],[::],...")// public static final OptionKey WasiMapDirs = new OptionKey<>(""); public enum ConstantsStorePolicy { @@ -93,4 +93,7 @@ public enum ConstantsStorePolicy { @Option(help = "In this mode memories and tables are not initialized.", category = OptionCategory.INTERNAL, stability = OptionStability.EXPERIMENTAL, usageSyntax = "false|true") // public static final OptionKey MemoryOverheadMode = new OptionKey<>(false); + + @Option(help = "Make WASI random_get always return the same random numbers. For testing purpose only.", category = OptionCategory.INTERNAL, stability = OptionStability.EXPERIMENTAL, usageSyntax = "false|true") // + public static final OptionKey WasiConstantRandomGet = new OptionKey<>(false); } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/SuppressFBWarnings.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/SuppressFBWarnings.java new file mode 100644 index 000000000000..235fcf933b56 --- /dev/null +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/SuppressFBWarnings.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.graalvm.wasm.predefined.wasi; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * Used to suppress SpotBugs warnings. + */ +@Retention(RetentionPolicy.CLASS) +@interface SuppressFBWarnings { + /** + * @see "https://spotbugs.readthedocs.io/en/latest/bugDescriptions.html" + */ + String[] value(); + + /** + * Reason why the warning is suppressed. Use a SpotBugs issue id where appropriate. + */ + String justification(); +} diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiClockTimeGetNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiClockTimeGetNode.java index d4f9d754952e..3b8c35582c0b 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiClockTimeGetNode.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiClockTimeGetNode.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -85,7 +85,7 @@ private Object clockTimeGet(int clockIdValue, int resultAddress) { } @TruffleBoundary - private static long realtimeNow() { + public static long realtimeNow() { return ChronoUnit.NANOS.between(Instant.EPOCH, Instant.now()); } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiConstantRandomGetNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiConstantRandomGetNode.java new file mode 100644 index 000000000000..e4ef617b04d1 --- /dev/null +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiConstantRandomGetNode.java @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.graalvm.wasm.predefined.wasi; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.frame.VirtualFrame; +import org.graalvm.wasm.WasmContext; +import org.graalvm.wasm.WasmInstance; +import org.graalvm.wasm.WasmLanguage; +import org.graalvm.wasm.predefined.WasmBuiltinRootNode; +import org.graalvm.wasm.predefined.wasi.types.Errno; + +import java.util.Random; + +/** + * WASI random_get for testing purposes. + */ +public class WasiConstantRandomGetNode extends WasmBuiltinRootNode { + private static final int SEED = 12345; + + public WasiConstantRandomGetNode(WasmLanguage language, WasmInstance instance) { + super(language, instance); + } + + @Override + public Object executeWithContext(VirtualFrame frame, WasmContext context) { + final Object[] args = frame.getArguments(); + return randomGet((int) args[0], (int) args[1]); + } + + @SuppressFBWarnings(value = "DMI_RANDOM_USED_ONLY_ONCE", justification = "This is a testing class only") + @CompilerDirectives.TruffleBoundary + private Object randomGet(int buf, int size) { + byte[] randomData = new byte[size]; + new Random(SEED).nextBytes(randomData); + memory().initialize(randomData, 0, buf, size); + return Errno.Success.ordinal(); + } + + @Override + public String builtinNodeName() { + return "__wasi_random_get"; + } +} diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiModule.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiModule.java index 968c4091b4d7..4a9340dc3630 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiModule.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiModule.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -52,7 +52,7 @@ import static org.graalvm.wasm.constants.Sizes.MAX_MEMORY_DECLARATION_SIZE; public final class WasiModule extends BuiltinModule { - private static final int NUMBER_OF_FUNCTIONS = 16; + private static final int NUMBER_OF_FUNCTIONS = 27; @Override protected WasmInstance createInstance(WasmLanguage language, WasmContext context, String name) { @@ -79,6 +79,22 @@ protected WasmInstance createInstance(WasmLanguage language, WasmContext context defineFunction(instance, "fd_filestat_get", types(I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiFdFilestatGetNode(language, instance)); defineFunction(instance, "path_open", types(I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE, I64_TYPE, I64_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiPathOpenNode(language, instance)); + defineFunction(instance, "path_create_directory", types(I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiPathCreateDirectoryNode(language, instance)); + defineFunction(instance, "path_remove_directory", types(I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiPathRemoveDirectoryNode(language, instance)); + defineFunction(instance, "path_filestat_set_times", types(I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE, I64_TYPE, I64_TYPE, I32_TYPE), types(I32_TYPE), + new WasiPathFilestatSetTimesNode(language, instance)); + defineFunction(instance, "path_link", types(I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiPathLinkNode(language, instance)); + defineFunction(instance, "path_rename", types(I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiPathRenameNode(language, instance)); + defineFunction(instance, "path_symlink", types(I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiPathSymlinkNode(language, instance)); + defineFunction(instance, "path_unlink_file", types(I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiPathUnlinkFileNode(language, instance)); + defineFunction(instance, "path_readlink", types(I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiPathReadLinkNode(language, instance)); + defineFunction(instance, "path_filestat_get", types(I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiPathFileStatGetNode(language, instance)); + defineFunction(instance, "sched_yield", types(), types(I32_TYPE), new WasiSchedYieldNode(language, instance)); + if (context.getContextOptions().constantRandomGet()) { + defineFunction(instance, "random_get", types(I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiConstantRandomGetNode(language, instance)); + } else { + defineFunction(instance, "random_get", types(I32_TYPE, I32_TYPE), types(I32_TYPE), new WasiRandomGetNode(language, instance)); + } return instance; } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiPathCreateDirectoryNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiPathCreateDirectoryNode.java new file mode 100644 index 000000000000..736f355f6df7 --- /dev/null +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiPathCreateDirectoryNode.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.graalvm.wasm.predefined.wasi; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.frame.VirtualFrame; +import org.graalvm.wasm.WasmContext; +import org.graalvm.wasm.WasmInstance; +import org.graalvm.wasm.WasmLanguage; +import org.graalvm.wasm.predefined.WasmBuiltinRootNode; +import org.graalvm.wasm.predefined.wasi.fd.Fd; +import org.graalvm.wasm.predefined.wasi.types.Errno; + +public class WasiPathCreateDirectoryNode extends WasmBuiltinRootNode { + + public WasiPathCreateDirectoryNode(WasmLanguage language, WasmInstance instance) { + super(language, instance); + } + + @Override + public Object executeWithContext(VirtualFrame frame, WasmContext context) { + final Object[] args = frame.getArguments(); + return pathCreateDirectory(context, (int) args[0], (int) args[1], (int) args[2]); + } + + @TruffleBoundary + private int pathCreateDirectory(WasmContext context, int fd, int pathAddress, int pathLength) { + final Fd handle = context.fdManager().get(fd); + if (handle == null) { + return Errno.Badf.ordinal(); + } + return handle.pathCreateDirectory(this, memory(), pathAddress, pathLength).ordinal(); + } + + @Override + public String builtinNodeName() { + return "__wasi_path_create_directory"; + } +} diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiPathFileStatGetNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiPathFileStatGetNode.java new file mode 100644 index 000000000000..e2dba508a835 --- /dev/null +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiPathFileStatGetNode.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.graalvm.wasm.predefined.wasi; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.frame.VirtualFrame; +import org.graalvm.wasm.WasmContext; +import org.graalvm.wasm.WasmInstance; +import org.graalvm.wasm.WasmLanguage; +import org.graalvm.wasm.predefined.WasmBuiltinRootNode; +import org.graalvm.wasm.predefined.wasi.fd.Fd; +import org.graalvm.wasm.predefined.wasi.types.Errno; + +public class WasiPathFileStatGetNode extends WasmBuiltinRootNode { + + public WasiPathFileStatGetNode(WasmLanguage language, WasmInstance instance) { + super(language, instance); + } + + @Override + public Object executeWithContext(VirtualFrame frame, WasmContext context) { + final Object[] args = frame.getArguments(); + return pathFilestatGet(context, (int) args[0], (int) args[1], (int) args[2], (int) args[3], (int) args[4]); + } + + @TruffleBoundary + private int pathFilestatGet(WasmContext context, int fd, int flags, int pathAddress, int pathLength, int resultAddress) { + final Fd handle = context.fdManager().get(fd); + if (handle == null) { + return Errno.Badf.ordinal(); + } + return handle.pathFilestatGet(this, memory(), flags, pathAddress, pathLength, resultAddress).ordinal(); + } + + @Override + public String builtinNodeName() { + return "__wasi_path_filestat_get"; + } +} diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiPathFilestatSetTimesNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiPathFilestatSetTimesNode.java new file mode 100644 index 000000000000..4df1453c1462 --- /dev/null +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiPathFilestatSetTimesNode.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.graalvm.wasm.predefined.wasi; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.frame.VirtualFrame; +import org.graalvm.wasm.WasmContext; +import org.graalvm.wasm.WasmInstance; +import org.graalvm.wasm.WasmLanguage; +import org.graalvm.wasm.predefined.WasmBuiltinRootNode; +import org.graalvm.wasm.predefined.wasi.fd.Fd; +import org.graalvm.wasm.predefined.wasi.types.Errno; + +public class WasiPathFilestatSetTimesNode extends WasmBuiltinRootNode { + public WasiPathFilestatSetTimesNode(WasmLanguage language, WasmInstance instance) { + super(language, instance); + } + + @Override + public Object executeWithContext(VirtualFrame frame, WasmContext context) { + final Object[] args = frame.getArguments(); + return pathFilestatSetTimeNode(context, (int) args[0], (int) args[1], (int) args[2], (int) args[3], (long) args[4], (long) args[5], (int) args[6]); + } + + @TruffleBoundary + private int pathFilestatSetTimeNode(WasmContext context, int fd, int flags, int pathAddress, int pathLength, long atim, long mtim, int fstFlags) { + final Fd handle = context.fdManager().get(fd); + if (handle == null) { + return Errno.Badf.ordinal(); + } + return handle.pathFilestatSetTimes(this, memory(), flags, pathAddress, pathLength, atim, mtim, fstFlags).ordinal(); + } + + @Override + public String builtinNodeName() { + return "__wasi_path_filestat_set_times"; + } +} diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiPathLinkNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiPathLinkNode.java new file mode 100644 index 000000000000..0c1484eae9ff --- /dev/null +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiPathLinkNode.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.graalvm.wasm.predefined.wasi; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.frame.VirtualFrame; +import org.graalvm.wasm.WasmContext; +import org.graalvm.wasm.WasmInstance; +import org.graalvm.wasm.WasmLanguage; +import org.graalvm.wasm.predefined.WasmBuiltinRootNode; +import org.graalvm.wasm.predefined.wasi.fd.Fd; +import org.graalvm.wasm.predefined.wasi.types.Errno; + +public class WasiPathLinkNode extends WasmBuiltinRootNode { + + public WasiPathLinkNode(WasmLanguage language, WasmInstance instance) { + super(language, instance); + } + + @Override + public Object executeWithContext(VirtualFrame frame, WasmContext context) { + final Object[] args = frame.getArguments(); + return pathLink(context, (int) args[0], (int) args[1], (int) args[2], (int) args[3], (int) args[4], (int) args[5], (int) args[6]); + } + + @TruffleBoundary + private int pathLink(WasmContext context, int oldFd, int oldFlags, int oldPathAddress, int oldPathLength, int newFd, int newPathAddress, int newPathLength) { + final Fd oldHandle = context.fdManager().get(oldFd); + final Fd newHandle = context.fdManager().get(newFd); + if (oldHandle == null || newHandle == null) { + return Errno.Badf.ordinal(); + } + return oldHandle.pathLink(this, memory(), oldFlags, oldPathAddress, oldPathLength, newHandle, newPathAddress, newPathLength).ordinal(); + } + + @Override + public String builtinNodeName() { + return "__wasi_path_link"; + } +} diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiPathReadLinkNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiPathReadLinkNode.java new file mode 100644 index 000000000000..b8db26a13be1 --- /dev/null +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiPathReadLinkNode.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.graalvm.wasm.predefined.wasi; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.frame.VirtualFrame; +import org.graalvm.wasm.WasmContext; +import org.graalvm.wasm.WasmInstance; +import org.graalvm.wasm.WasmLanguage; +import org.graalvm.wasm.predefined.WasmBuiltinRootNode; +import org.graalvm.wasm.predefined.wasi.fd.Fd; +import org.graalvm.wasm.predefined.wasi.types.Errno; + +public class WasiPathReadLinkNode extends WasmBuiltinRootNode { + public WasiPathReadLinkNode(WasmLanguage language, WasmInstance instance) { + super(language, instance); + } + + @Override + public Object executeWithContext(VirtualFrame frame, WasmContext context) { + final Object[] args = frame.getArguments(); + return pathReadLink(context, (int) args[0], (int) args[1], (int) args[2], (int) args[3], (int) args[4]); + } + + @TruffleBoundary + private int pathReadLink(WasmContext context, int fd, int pathAddress, int pathLength, int buf, int bufLen) { + final Fd handle = context.fdManager().get(fd); + if (handle == null) { + return Errno.Badf.ordinal(); + } + return handle.pathReadLink(this, memory(), pathAddress, pathLength, buf, bufLen); + } + + @Override + public String builtinNodeName() { + return "__wasi_path_readlink"; + } +} diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiPathRemoveDirectoryNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiPathRemoveDirectoryNode.java new file mode 100644 index 000000000000..3c539e3c6462 --- /dev/null +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiPathRemoveDirectoryNode.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.graalvm.wasm.predefined.wasi; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.frame.VirtualFrame; +import org.graalvm.wasm.WasmContext; +import org.graalvm.wasm.WasmInstance; +import org.graalvm.wasm.WasmLanguage; +import org.graalvm.wasm.predefined.WasmBuiltinRootNode; +import org.graalvm.wasm.predefined.wasi.fd.Fd; +import org.graalvm.wasm.predefined.wasi.types.Errno; + +public class WasiPathRemoveDirectoryNode extends WasmBuiltinRootNode { + public WasiPathRemoveDirectoryNode(WasmLanguage language, WasmInstance instance) { + super(language, instance); + } + + @Override + public Object executeWithContext(VirtualFrame frame, WasmContext context) { + final Object[] args = frame.getArguments(); + return pathRemoveDirectory(context, (int) args[0], (int) args[1], (int) args[2]); + } + + @TruffleBoundary + private int pathRemoveDirectory(WasmContext context, int fd, int pathAddress, int pathLength) { + final Fd handle = context.fdManager().get(fd); + if (handle == null) { + return Errno.Badf.ordinal(); + } + return handle.pathRemoveDirectory(this, memory(), pathAddress, pathLength).ordinal(); + } + + @Override + public String builtinNodeName() { + return "__wasi_path_remove_directory"; + } +} diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiPathRenameNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiPathRenameNode.java new file mode 100644 index 000000000000..28a49e409de7 --- /dev/null +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiPathRenameNode.java @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.graalvm.wasm.predefined.wasi; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.frame.VirtualFrame; +import org.graalvm.wasm.WasmContext; +import org.graalvm.wasm.WasmInstance; +import org.graalvm.wasm.WasmLanguage; +import org.graalvm.wasm.predefined.WasmBuiltinRootNode; +import org.graalvm.wasm.predefined.wasi.fd.Fd; +import org.graalvm.wasm.predefined.wasi.types.Errno; + +public class WasiPathRenameNode extends WasmBuiltinRootNode { + + public WasiPathRenameNode(WasmLanguage language, WasmInstance instance) { + super(language, instance); + } + + @Override + public Object executeWithContext(VirtualFrame frame, WasmContext context) { + final Object[] args = frame.getArguments(); + return pathRename(context, (int) args[0], (int) args[1], (int) args[2], (int) args[3], (int) args[4], (int) args[5]); + } + + @TruffleBoundary + private int pathRename(WasmContext context, int oldFd, int oldPathAddress, int oldPathLength, int newFd, int newPathAddress, int newPathLength) { + final Fd oldHandle = context.fdManager().get(oldFd); + final Fd newHandle = context.fdManager().get(newFd); + if (oldHandle == null || newHandle == null) { + return Errno.Badf.ordinal(); + } + return oldHandle.pathRename(this, memory(), oldPathAddress, oldPathLength, newHandle, newPathAddress, newPathLength).ordinal(); + } + + @Override + public String builtinNodeName() { + return "__wasi_path_rename"; + } +} diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiPathSymlinkNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiPathSymlinkNode.java new file mode 100644 index 000000000000..ce3fa5332783 --- /dev/null +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiPathSymlinkNode.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.graalvm.wasm.predefined.wasi; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.frame.VirtualFrame; +import org.graalvm.wasm.WasmContext; +import org.graalvm.wasm.WasmInstance; +import org.graalvm.wasm.WasmLanguage; +import org.graalvm.wasm.predefined.WasmBuiltinRootNode; +import org.graalvm.wasm.predefined.wasi.fd.Fd; +import org.graalvm.wasm.predefined.wasi.types.Errno; + +public class WasiPathSymlinkNode extends WasmBuiltinRootNode { + + public WasiPathSymlinkNode(WasmLanguage language, WasmInstance instance) { + super(language, instance); + } + + @Override + public Object executeWithContext(VirtualFrame frame, WasmContext context) { + final Object[] args = frame.getArguments(); + return pathSymlink(context, (int) args[0], (int) args[1], (int) args[2], (int) args[3], (int) args[4]); + } + + @TruffleBoundary + private int pathSymlink(WasmContext context, int oldPathAddress, int oldPathLength, int fd, int newPathAddress, int newPathLength) { + final Fd handle = context.fdManager().get(fd); + if (handle == null) { + return Errno.Badf.ordinal(); + } + return handle.pathSymlink(this, memory(), oldPathAddress, oldPathLength, newPathAddress, newPathLength).ordinal(); + } + + @Override + public String builtinNodeName() { + return "__wasi_path_symlink"; + } +} diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiPathUnlinkFileNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiPathUnlinkFileNode.java new file mode 100644 index 000000000000..19e126951f26 --- /dev/null +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiPathUnlinkFileNode.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.graalvm.wasm.predefined.wasi; + +import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary; +import com.oracle.truffle.api.frame.VirtualFrame; +import org.graalvm.wasm.WasmContext; +import org.graalvm.wasm.WasmInstance; +import org.graalvm.wasm.WasmLanguage; +import org.graalvm.wasm.predefined.WasmBuiltinRootNode; +import org.graalvm.wasm.predefined.wasi.fd.Fd; +import org.graalvm.wasm.predefined.wasi.types.Errno; + +public class WasiPathUnlinkFileNode extends WasmBuiltinRootNode { + public WasiPathUnlinkFileNode(WasmLanguage language, WasmInstance instance) { + super(language, instance); + } + + @Override + public Object executeWithContext(VirtualFrame frame, WasmContext context) { + final Object[] args = frame.getArguments(); + return pathUnlinkFile(context, (int) args[0], (int) args[1], (int) args[2]); + } + + @TruffleBoundary + private int pathUnlinkFile(WasmContext context, int fd, int pathAddress, int pathLength) { + final Fd handle = context.fdManager().get(fd); + if (handle == null) { + return Errno.Badf.ordinal(); + } + return handle.pathUnlinkFile(this, memory(), pathAddress, pathLength).ordinal(); + } + + @Override + public String builtinNodeName() { + return "__wasi_path_unlink_file"; + } +} diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiRandomGetNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiRandomGetNode.java new file mode 100644 index 000000000000..50160d5f9604 --- /dev/null +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiRandomGetNode.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.graalvm.wasm.predefined.wasi; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.frame.VirtualFrame; +import org.graalvm.wasm.WasmContext; +import org.graalvm.wasm.WasmInstance; +import org.graalvm.wasm.WasmLanguage; +import org.graalvm.wasm.predefined.WasmBuiltinRootNode; +import org.graalvm.wasm.predefined.wasi.types.Errno; + +import java.util.concurrent.ThreadLocalRandom; + +public class WasiRandomGetNode extends WasmBuiltinRootNode { + public WasiRandomGetNode(WasmLanguage language, WasmInstance instance) { + super(language, instance); + } + + @Override + public Object executeWithContext(VirtualFrame frame, WasmContext context) { + final Object[] args = frame.getArguments(); + return randomGet((int) args[0], (int) args[1]); + } + + @CompilerDirectives.TruffleBoundary + private Object randomGet(int buf, int size) { + byte[] randomData = new byte[size]; + ThreadLocalRandom.current().nextBytes(randomData); + memory().initialize(randomData, 0, buf, size); + return Errno.Success.ordinal(); + } + + @Override + public String builtinNodeName() { + return "__wasi_random_get"; + } +} diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiSchedYieldNode.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiSchedYieldNode.java new file mode 100644 index 000000000000..24c30e351c7c --- /dev/null +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/WasiSchedYieldNode.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2023, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * The Universal Permissive License (UPL), Version 1.0 + * + * Subject to the condition set forth below, permission is hereby granted to any + * person obtaining a copy of this software, associated documentation and/or + * data (collectively the "Software"), free of charge and under any and all + * copyright rights in the Software, and any and all patent rights owned or + * freely licensable by each licensor hereunder covering either (i) the + * unmodified Software as contributed to or provided by such licensor, or (ii) + * the Larger Works (as defined below), to deal in both + * + * (a) the Software, and + * + * (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if + * one is included with the Software each a "Larger Work" to which the Software + * is contributed by such licensors), + * + * without restriction, including without limitation the rights to copy, create + * derivative works of, display, perform, and distribute the Software and make, + * use, sell, offer for sale, import, export, have made, and have sold the + * Software and the Larger Work(s), and to sublicense the foregoing rights on + * either these or other terms. + * + * This license is subject to the following condition: + * + * The above copyright notice and either this complete permission notice or at a + * minimum a reference to the UPL must be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +package org.graalvm.wasm.predefined.wasi; + +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.frame.VirtualFrame; +import org.graalvm.wasm.WasmContext; +import org.graalvm.wasm.WasmInstance; +import org.graalvm.wasm.WasmLanguage; +import org.graalvm.wasm.predefined.WasmBuiltinRootNode; +import org.graalvm.wasm.predefined.wasi.types.Errno; + +public class WasiSchedYieldNode extends WasmBuiltinRootNode { + + public WasiSchedYieldNode(WasmLanguage language, WasmInstance instance) { + super(language, instance); + } + + @Override + public Object executeWithContext(VirtualFrame frame, WasmContext context) { + return schedYield(); + } + + @CompilerDirectives.TruffleBoundary + private static Object schedYield() { + Thread.yield(); + return Errno.Success.ordinal(); + } + + @Override + public String builtinNodeName() { + return "__wasi_sched_yield"; + } +} diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/DirectoryFd.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/DirectoryFd.java index a90322639f98..50b58075b15a 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/DirectoryFd.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/DirectoryFd.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -41,21 +41,30 @@ package org.graalvm.wasm.predefined.wasi.fd; -import com.oracle.truffle.api.TruffleFile; -import com.oracle.truffle.api.nodes.Node; +import static org.graalvm.wasm.predefined.wasi.FlagUtils.isSet; +import static org.graalvm.wasm.predefined.wasi.FlagUtils.isSubsetOf; + +import java.io.IOException; +import java.nio.file.DirectoryNotEmptyException; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.NoSuchFileException; +import java.nio.file.NotLinkException; +import java.nio.file.attribute.FileTime; +import java.util.concurrent.TimeUnit; + import org.graalvm.wasm.memory.WasmMemory; +import org.graalvm.wasm.predefined.wasi.WasiClockTimeGetNode; import org.graalvm.wasm.predefined.wasi.types.Errno; import org.graalvm.wasm.predefined.wasi.types.Fdflags; import org.graalvm.wasm.predefined.wasi.types.Filetype; +import org.graalvm.wasm.predefined.wasi.types.Fstflags; import org.graalvm.wasm.predefined.wasi.types.Lookupflags; import org.graalvm.wasm.predefined.wasi.types.Oflags; import org.graalvm.wasm.predefined.wasi.types.Rights; -import java.io.IOException; -import java.nio.file.FileAlreadyExistsException; - -import static org.graalvm.wasm.predefined.wasi.FlagUtils.isSet; -import static org.graalvm.wasm.predefined.wasi.FlagUtils.isSubsetOf; +import com.oracle.truffle.api.CompilerDirectives; +import com.oracle.truffle.api.TruffleFile; +import com.oracle.truffle.api.nodes.Node; /** * File descriptor representing a directory. @@ -73,6 +82,179 @@ protected DirectoryFd(FdManager fdManager, TruffleFile virtualFile, PreopenedDir this.preopenedRoot = preopenedRoot; } + private TruffleFile resolveVirtualFile(Node node, WasmMemory memory, int pathAddress, int pathLength) { + final String path = memory.readString(pathAddress, pathLength, node); + return preopenedRoot.containedVirtualFile(virtualFile.resolve(path)); + } + + private static TruffleFile resolveVirtualFile(Node node, WasmMemory memory, DirectoryFd fd, int pathAddress, int pathLength) { + final String path = memory.readString(pathAddress, pathLength, node); + return fd.preopenedRoot.containedVirtualFile(fd.virtualFile.resolve(path)); + } + + private TruffleFile resolveHostFile(Node node, WasmMemory memory, int pathAddress, int pathLength) { + final TruffleFile virtualChildFile = resolveVirtualFile(node, memory, pathAddress, pathLength); + if (virtualChildFile == null) { + return null; + } + + return preopenedRoot.virtualFileToHostFile(virtualChildFile); + } + + private static TruffleFile resolveHostFile(Node node, WasmMemory memory, DirectoryFd fd, int pathAddress, int pathLength) { + final TruffleFile virtualChildFile = resolveVirtualFile(node, memory, fd, pathAddress, pathLength); + if (virtualChildFile == null) { + return null; + } + return fd.preopenedRoot.virtualFileToHostFile(virtualChildFile); + } + + private TruffleFile resolveHostFile(Node node, WasmMemory memory, int pathAddress, int pathLength, int lookupFlags) throws IOException, SecurityException { + TruffleFile hostFile = resolveHostFile(node, memory, pathAddress, pathLength); + if (hostFile == null) { + return null; + } + + if (isSet(lookupFlags, Lookupflags.SymlinkFollow) && hostFile.exists()) { + // Follow symbolic links, and make sure that the target is still contained in + // preopenedRoot. + hostFile = preopenedRoot.containedHostFile(hostFile.getCanonicalFile()); + } + return hostFile; + } + + private TruffleFile resolveHostFile(TruffleFile virtualChildFile, int lookupFlags) throws IOException, SecurityException { + if (virtualChildFile == null) { + return null; + } + TruffleFile hostFile = preopenedRoot.virtualFileToHostFile(virtualChildFile); + if (hostFile == null) { + return null; + } + if (isSet(lookupFlags, Lookupflags.SymlinkFollow) && hostFile.exists()) { + // Follow symbolic links, and make sure that the target is still contained in + // preopenedRoot. + hostFile = preopenedRoot.containedHostFile(hostFile.getCanonicalFile()); + } + return hostFile; + } + + @Override + public Errno pathCreateDirectory(Node node, WasmMemory memory, int pathAddress, int pathLength) { + if (!isSet(fsRightsBase, Rights.PathCreateDirectory)) { + return Errno.Notcapable; + } + + final TruffleFile hostChildFile = resolveHostFile(node, memory, pathAddress, pathLength); + if (hostChildFile == null) { + return Errno.Noent; + } + try { + hostChildFile.createDirectory(); + } catch (FileAlreadyExistsException e) { + return Errno.Exist; + } catch (IOException | UnsupportedOperationException e) { + return Errno.Io; + } catch (SecurityException e) { + return Errno.Acces; + } + return Errno.Success; + } + + @Override + public Errno pathFilestatGet(Node node, WasmMemory memory, int flags, int pathAddress, int pathLength, int resultAddress) { + if (!isSet(fsRightsBase, Rights.PathFilestatGet)) { + return Errno.Notcapable; + } + + final TruffleFile hostChildFile; + try { + hostChildFile = resolveHostFile(node, memory, pathAddress, pathLength, flags); + } catch (IOException e) { + return Errno.Io; + } catch (SecurityException e) { + return Errno.Acces; + } + if (hostChildFile == null) { + return Errno.Noent; + } + return FdUtils.writeFilestat(node, memory, resultAddress, hostChildFile); + } + + @Override + public Errno pathFilestatSetTimes(Node node, WasmMemory memory, int flags, int pathAddress, int pathLength, long atim, long mtim, int fstFlags) { + if (!isSet(fsRightsBase, Rights.PathFilestatSetTimes)) { + return Errno.Notcapable; + } + final TruffleFile hostChildFile; + try { + hostChildFile = resolveHostFile(node, memory, pathAddress, pathLength, flags); + } catch (IOException e) { + return Errno.Io; + } catch (SecurityException e) { + return Errno.Acces; + } + if (hostChildFile == null) { + return Errno.Noent; + } + try { + if (isSet(fstFlags, Fstflags.Atim)) { + hostChildFile.setLastAccessTime(FileTime.from(atim, TimeUnit.NANOSECONDS)); + } + if (isSet(fstFlags, Fstflags.AtimNow)) { + hostChildFile.setLastAccessTime(FileTime.from(WasiClockTimeGetNode.realtimeNow(), TimeUnit.NANOSECONDS)); + } + if (isSet(fstFlags, Fstflags.Mtim)) { + hostChildFile.setLastModifiedTime(FileTime.from(mtim, TimeUnit.NANOSECONDS)); + } + if (isSet(fstFlags, Fstflags.MtimNow)) { + hostChildFile.setLastModifiedTime(FileTime.from(WasiClockTimeGetNode.realtimeNow(), TimeUnit.NANOSECONDS)); + } + } catch (IOException e) { + return Errno.Io; + } catch (SecurityException e) { + return Errno.Acces; + } + return Errno.Success; + } + + @Override + public Errno pathLink(Node node, WasmMemory memory, int oldFlags, int oldPathAddress, int oldPathLength, Fd newFd, int newPathAddress, int newPathLength) { + if (!isSet(fsRightsBase, Rights.PathLinkSource) || !isSet(newFd.fsRightsBase, Rights.PathLinkTarget)) { + return Errno.Notcapable; + } + + final TruffleFile oldHostChildFile; + try { + oldHostChildFile = resolveHostFile(node, memory, oldPathAddress, oldPathLength, oldFlags); + } catch (IOException e) { + return Errno.Io; + } catch (SecurityException e) { + return Errno.Acces; + } + if (oldHostChildFile == null) { + return Errno.Noent; + } + + if (!(newFd instanceof DirectoryFd)) { + return Errno.Notdir; + } + final TruffleFile newHostChildFile = resolveHostFile(node, memory, (DirectoryFd) newFd, newPathAddress, newPathLength); + if (newHostChildFile == null) { + return Errno.Noent; + } + try { + newHostChildFile.createLink(oldHostChildFile); + } catch (FileAlreadyExistsException e) { + return Errno.Exist; + } catch (IOException | UnsupportedOperationException e) { + return Errno.Io; + } catch (SecurityException e) { + return Errno.Acces; + } + return Errno.Success; + } + @Override public Errno pathOpen(Node node, WasmMemory memory, int dirFlags, int pathAddress, int pathLength, short childOflags, long childFsRightsBase, long childFsRightsInheriting, short childFdFlags, int fdAddress) { @@ -82,30 +264,21 @@ public Errno pathOpen(Node node, WasmMemory memory, int dirFlags, int pathAddres return Errno.Notcapable; } - final String path = memory.readString(pathAddress, pathLength, node); - final TruffleFile virtualChildFile = preopenedRoot.containedVirtualFile(virtualFile.resolve(path)); + final TruffleFile virtualChildFile = resolveVirtualFile(node, memory, pathAddress, pathLength); if (virtualChildFile == null) { - return Errno.Notcapable; + return Errno.Noent; } - TruffleFile hostChildFile = preopenedRoot.virtualFileToHostFile(virtualChildFile); - if (hostChildFile == null) { - return Errno.Notcapable; + final TruffleFile hostChildFile; + try { + hostChildFile = resolveHostFile(virtualChildFile, dirFlags); + } catch (IOException e) { + return Errno.Io; + } catch (SecurityException e) { + return Errno.Acces; } - - if (isSet(dirFlags, Lookupflags.SymlinkFollow) && hostChildFile.exists()) { - try { - // Follow symbolic links, and make sure that the target is still contained in - // preopenedRoot. - hostChildFile = preopenedRoot.containedHostFile(hostChildFile.getCanonicalFile()); - if (hostChildFile == null) { - return Errno.Notcapable; - } - } catch (IOException e) { - return Errno.Io; - } catch (SecurityException e) { - return Errno.Acces; - } + if (hostChildFile == null) { + return Errno.Noent; } // As they are non-null, virtualChildFile and hostChildFile are guaranteed to be @@ -131,10 +304,150 @@ public Errno pathOpen(Node node, WasmMemory memory, int dirFlags, int pathAddres return Errno.Success; } catch (FileAlreadyExistsException e) { return Errno.Exist; - } catch (IOException | UnsupportedOperationException | IllegalArgumentException | SecurityException e) { + } catch (IOException | UnsupportedOperationException e) { return Errno.Io; + } catch (IllegalArgumentException e) { + return Errno.Inval; + } catch (SecurityException e) { + return Errno.Acces; + } + } + } + + @Override + public int pathReadLink(Node node, WasmMemory memory, int pathAddress, int pathLength, int buf, int bufLen) { + if (!isSet(fsRightsBase, Rights.PathReadlink)) { + return Errno.Notcapable.ordinal(); + } + final TruffleFile hostChildFile = resolveHostFile(node, memory, pathAddress, pathLength); + if (hostChildFile == null) { + return Errno.Noent.ordinal(); + } + try { + final TruffleFile link = hostChildFile.readSymbolicLink(); + final TruffleFile virtualLink = preopenedRoot.hostFileToVirtualFile(link); + if (virtualLink == null) { + return Errno.Noent.ordinal(); } + final String content = virtualLink.getPath(); + return memory.writeString(node, content, buf, bufLen); + } catch (NotLinkException e) { + return Errno.Nolink.ordinal(); + } catch (IOException | UnsupportedOperationException e) { + return Errno.Io.ordinal(); + } catch (SecurityException e) { + return Errno.Acces.ordinal(); } } + @Override + public Errno pathRemoveDirectory(Node node, WasmMemory memory, int pathAddress, int pathLength) { + if (!isSet(fsRightsBase, Rights.PathRemoveDirectory)) { + return Errno.Notcapable; + } + final TruffleFile hostChildFile = resolveHostFile(node, memory, pathAddress, pathLength); + if (hostChildFile == null) { + return Errno.Noent; + } + if (!hostChildFile.isDirectory()) { + return Errno.Notdir; + } + try { + hostChildFile.delete(); + } catch (DirectoryNotEmptyException e) { + return Errno.Notempty; + } catch (NoSuchFileException e) { + return Errno.Noent; + } catch (IOException e) { + return Errno.Io; + } catch (SecurityException e) { + return Errno.Acces; + } + return Errno.Success; + } + + @Override + @CompilerDirectives.TruffleBoundary + public Errno pathRename(Node node, WasmMemory memory, int oldPathAddress, int oldPathLength, Fd newFd, int newPathAddress, int newPathLength) { + if (!isSet(fsRightsBase, Rights.PathRenameSource) || !isSet(newFd.fsRightsBase, Rights.PathRenameTarget)) { + return Errno.Notcapable; + } + final TruffleFile oldHostChildFile = resolveHostFile(node, memory, oldPathAddress, oldPathLength); + if (oldHostChildFile == null) { + return Errno.Noent; + } + + if (!(newFd instanceof DirectoryFd)) { + return Errno.Notdir; + } + + final TruffleFile newHostChildFile = resolveHostFile(node, memory, (DirectoryFd) newFd, newPathAddress, newPathLength); + if (newHostChildFile == null) { + return Errno.Noent; + } + + try { + oldHostChildFile.move(newHostChildFile); + } catch (FileAlreadyExistsException e) { + return Errno.Exist; + } catch (IOException | UnsupportedOperationException e) { + return Errno.Io; + } catch (SecurityException e) { + return Errno.Acces; + } + return Errno.Success; + } + + @Override + public Errno pathSymlink(Node node, WasmMemory memory, int oldPathAddress, int oldPathLength, int newPathAddress, int newPathLength) { + if (!isSet(fsRightsBase, Rights.PathSymlink)) { + return Errno.Notcapable; + } + + final TruffleFile oldHostChildFile = resolveHostFile(node, memory, oldPathAddress, oldPathLength); + if (oldHostChildFile == null) { + return Errno.Noent; + } + + final TruffleFile newHostChildFile = resolveHostFile(node, memory, newPathAddress, newPathLength); + if (newHostChildFile == null) { + return Errno.Noent; + } + + try { + newHostChildFile.createSymbolicLink(oldHostChildFile); + } catch (FileAlreadyExistsException e) { + return Errno.Exist; + } catch (IOException | UnsupportedOperationException e) { + return Errno.Io; + } catch (SecurityException e) { + return Errno.Acces; + } + return Errno.Success; + } + + @Override + public Errno pathUnlinkFile(Node node, WasmMemory memory, int pathAddress, int pathLength) { + if (!isSet(fsRightsBase, Rights.PathUnlinkFile)) { + return Errno.Notcapable; + } + + final TruffleFile hostChildFile = resolveHostFile(node, memory, pathAddress, pathLength); + if (hostChildFile == null) { + return Errno.Noent; + } + if (hostChildFile.isDirectory()) { + return Errno.Isdir; + } + try { + hostChildFile.delete(); + } catch (NoSuchFileException e) { + return Errno.Noent; + } catch (IOException e) { + return Errno.Io; + } catch (SecurityException e) { + return Errno.Acces; + } + return Errno.Success; + } } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/Fd.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/Fd.java index 836ce6fe7c98..753eb762d903 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/Fd.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/Fd.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -47,6 +47,7 @@ import org.graalvm.wasm.predefined.wasi.types.Errno; import org.graalvm.wasm.predefined.wasi.types.Fdflags; import org.graalvm.wasm.predefined.wasi.types.Filetype; +import org.graalvm.wasm.predefined.wasi.types.Fstflags; import org.graalvm.wasm.predefined.wasi.types.Lookupflags; import org.graalvm.wasm.predefined.wasi.types.Oflags; import org.graalvm.wasm.predefined.wasi.types.Rights; @@ -353,6 +354,219 @@ public Errno prestatDirName(Node node, WasmMemory memory, int pathAddress, int p return Errno.Acces; } + /** + * Implementation of WASI path_create_directory: + * create a directory. + * + * @param node the calling node, used as location for any thrown {@link WasmException} + * @param memory the {@link WasmMemory} from which to read and write + * @param pathAddress {@code u8*}: start address from which to read the path encoded in UTF-8 + * @param pathLength length of the path to get, in bytes, including the trailing null character + * @return {@link Errno#Success} in case of success, or anthoer {@link Errno} in case of error + * @throws WasmException if an error happens while writing or reading to {@code memory} + * @see Pre-opend directories + */ + public Errno pathCreateDirectory(Node node, WasmMemory memory, int pathAddress, int pathLength) { + if (!isSet(fsRightsBase, Rights.PathCreateDirectory)) { + return Errno.Notcapable; + } + return Errno.Acces; + } + + /** + * Implementation of WASI path_filestat_get: + * return the attributes of a file or directory. + * + * @param node the calling node, used as location for any thrown {@link WasmException} + * @param memory the {@link WasmMemory} from which to read and write + * @param flags bitmap of {@link Lookupflags} + * @param pathAddress {@code u8*}: start address from which to read the path encoded in UTF-8 + * @param pathLength length of the path to get, in bytes, including the trailing null character + * @param resultAddress {@code filestat*}: address at which to write the filestat + * structure + * @return {@link Errno#Success} in case of success, or another {@link Errno} in case of error + * @throws WasmException if an error happens while writing or reading to {@code memory} + * @see Pre-opened directories + */ + public Errno pathFilestatGet(Node node, WasmMemory memory, int flags, int pathAddress, int pathLength, int resultAddress) { + if (!isSet(fsRightsBase, Rights.PathFilestatGet)) { + return Errno.Notcapable; + } + return Errno.Acces; + } + + /** + * Implementation of WASI path_filestat_set_times: + * adjust the timestamps of a file or directory. + * + * @param node the calling node, used as location for any thrown {@link WasmException} + * @param memory the {@link WasmMemory} from which to read and write + * @param flags bitmap of {@link Lookupflags} + * @param pathAddress {@code u8*}: start address from which to read the path encoded in UTF-8 + * @param pathLength length of the path to get, in bytes, including the trailing null character + * @param atim the desired values of the data access timestamp + * @param mtim the desired values of the data modification timestamp + * @param fstFlags bitmap of {@link Fstflags} + * @return {@link Errno#Success} in case of success, or another {@link Errno} in case of error + * @throws WasmException if an error happens while writing or reading to {@code memory} + * @see Pre-opened directories + */ + public Errno pathFilestatSetTimes(Node node, WasmMemory memory, int flags, int pathAddress, int pathLength, long atim, long mtim, int fstFlags) { + if (!isSet(fsRightsBase, Rights.PathFilestatSetTimes)) { + return Errno.Notcapable; + } + return Errno.Acces; + } + + /** + * Implementation of WASI path_link: + * create a hard link. + * + * @param node the calling node, used as location for any thrown {@link WasmException} + * @param memory the {@link WasmMemory} from which to read and write + * @param oldFlags bitmap of {@link Lookupflags} for the source + * @param oldPathAddress {@code u8*}: source start address from which to read the path encoded + * in UTF-8 + * @param oldPathLength length of the source path to get, in bytes, including the trailing null + * character + * @param newFd the {@link Fd} of the target + * @param newPathAddress {@code u8*}: target start address from which to read the path encoded + * in UTF-8 + * @param newPathLength length of the target path to get, in bytes, including the trailing null + * character + * @return {@link Errno#Success} in case of success, or another {@link Errno} in case of error + * @throws WasmException if an error happens while writing or reading to {@code memory} + * @see Pre-opened directories + */ + public Errno pathLink(Node node, WasmMemory memory, int oldFlags, int oldPathAddress, int oldPathLength, Fd newFd, int newPathAddress, int newPathLength) { + if (!isSet(fsRightsBase, Rights.PathLinkSource) || !isSet(newFd.fsRightsBase, Rights.PathLinkTarget)) { + return Errno.Notcapable; + } + return Errno.Acces; + } + + /** + * Implementation of WASI path_readlink: + * read the contents of a symbolic link. + * + * @param node the calling node, used as location for any thrown {@link WasmException} + * @param memory the {@link WasmMemory} from which to read and write + * @param pathAddress {@code u8*}: start address from which to read the path encoded in UTF-8 + * @param pathLength length of the path to get, in bytes, including the trailing null character + * @param buf the buffer to which to write the contents of the symbolic link + * @param bufLen the length of the buffer + * @return {@link Errno#Success} in case of success, or another {@link Errno} in case of error + * @throws WasmException if an error happens while writing or reading to {@code memory} + * @see Pre-opened directories + */ + public int pathReadLink(Node node, WasmMemory memory, int pathAddress, int pathLength, int buf, int bufLen) { + if (!isSet(fsRightsBase, Rights.PathReadlink)) { + return Errno.Notcapable.ordinal(); + } + return Errno.Acces.ordinal(); + } + + /** + * Implementation of WASI path_remove_directory: + * remove a directory. + * + * @param node the calling node, used as location for any thrown {@link WasmException} + * @param memory the {@link WasmMemory} from which to read and write + * @param pathAddress {@code u8*}: start address from which to read the path encoded in UTF-8 + * @param pathLength length of the path to get, in bytes, including the trailing null character + * @return {@link Errno#Success} in case of success, {@link Errno#Notempty} if the directory is + * not empty, or another {@link Errno} in case of error + * @throws WasmException if an error happens while writing or reading to {@code memory} + * @see Pre-opened directories + */ + public Errno pathRemoveDirectory(Node node, WasmMemory memory, int pathAddress, int pathLength) { + if (!isSet(fsRightsBase, Rights.PathRemoveDirectory)) { + return Errno.Notcapable; + } + return Errno.Acces; + } + + /** + * Implementation of WASI path_rename: + * rename a file or directory. + * + * @param node the calling node, used as location for any thrown {@link WasmException} + * @param memory the {@link WasmMemory} from which to read and write + * @param oldPathAddress {@code u8*}: source start address from which to read the path encoded + * in UTF-8 + * @param oldPathLength length of the source path to get, in bytes, including the trailing null + * character + * @param newFd the {@link Fd} of the target + * @param newPathAddress {@code u8*}: target start address from which to read the path encoded + * in UTF-8 + * @param newPathLength length of the target path to get, in bytes, including the trailing null + * character + * @return {@link Errno#Success} in case of success, or another {@link Errno} in case of error + * @throws WasmException if an error happens while writing or reading to {@code memory} + * @see Pre-opened directories + */ + public Errno pathRename(Node node, WasmMemory memory, int oldPathAddress, int oldPathLength, Fd newFd, int newPathAddress, int newPathLength) { + if (!isSet(fsRightsBase, Rights.PathRenameSource) || !isSet(newFd.fsRightsBase, Rights.PathRenameTarget)) { + return Errno.Notcapable; + } + return Errno.Acces; + } + + /** + * Implementation of WASI path_symlink: + * create a symbolic link. + * + * @param node the calling node, used as location for any thrown {@link WasmException} + * @param memory the {@link WasmMemory} from which to read and write + * @param oldPathAddress {@code u8*}: source start address from which to read the path encoded + * in UTF-8 + * @param oldPathLength length of the source path to get, in bytes, including the trailing null + * character + * @param newPathAddress {@code u8*}: target start address from which to read the path encoded + * in UTF-8 + * @param newPathLength length of the target path to get, in bytes, including the trailing null + * character + * @return {@link Errno#Success} in case of success, or another {@link Errno} in case of error + * @throws WasmException if an error happens while writing or reading to {@code memory} + * @see Pre-opened directories + */ + public Errno pathSymlink(Node node, WasmMemory memory, int oldPathAddress, int oldPathLength, int newPathAddress, int newPathLength) { + if (!isSet(fsRightsBase, Rights.PathSymlink)) { + return Errno.Notcapable; + } + return Errno.Acces; + } + + /** + * Implementation of WASI path_unlink_file: + * Unlink a file. + * + * @param node the calling node, used as location for any thrown {@link WasmException} + * @param memory the {@link WasmMemory} from which to read and write + * @param pathAddress {@code u8*}: start address from which to read the path encoded in UTF-8 + * @param pathLength length of the path to get, in bytes, including the trailing null character + * @return {@link Errno#Success} in case of success, {@link Errno#Isdir} in case the specified + * path points to a directory, or another {@link Errno} in case of error + * @throws WasmException if an error happens while writing or reading to {@code memory} + * @see Pre-opened directories + */ + public Errno pathUnlinkFile(Node node, WasmMemory memory, int pathAddress, int pathLength) { + if (!isSet(fsRightsBase, Rights.PathUnlinkFile)) { + return Errno.Notcapable; + } + return Errno.Acces; + } + @Override public void close() throws IOException { } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/FdManager.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/FdManager.java index ae4d1e2add77..97a3dd440285 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/FdManager.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/FdManager.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -43,10 +43,9 @@ import java.io.Closeable; import java.io.IOException; -import java.util.HashMap; -import java.util.Map; import java.util.concurrent.ThreadLocalRandom; +import org.graalvm.collections.EconomicMap; import org.graalvm.wasm.WasmOptions; import org.graalvm.wasm.exception.Failure; import org.graalvm.wasm.exception.WasmException; @@ -57,11 +56,11 @@ public final class FdManager implements Closeable { - private final Map handles; + private final EconomicMap handles; public FdManager(TruffleLanguage.Env env) { CompilerAsserts.neverPartOfCompilation(); - handles = new HashMap<>(); + handles = EconomicMap.create(3); put(0, new InputStreamFd(env.in())); put(1, new OutputStreamFd(env.out())); @@ -82,9 +81,15 @@ public FdManager(TruffleLanguage.Env env) { final String virtualDirPath = parts[0]; final String hostDirPath = parts.length == 2 ? parts[1] : parts[0]; - final TruffleFile virtualDir = env.getPublicTruffleFile(virtualDirPath).normalize(); + final TruffleFile virtualDir; final TruffleFile hostDir; try { + if (virtualDirPath.startsWith(".")) { + // Get canonical name if path is relative. + virtualDir = env.getPublicTruffleFile(virtualDirPath).getCanonicalFile(); + } else { + virtualDir = env.getPublicTruffleFile(virtualDirPath).normalize(); + } // Currently, we follow symbolic links. hostDir = env.getPublicTruffleFile(hostDirPath).getCanonicalFile(); } catch (IOException | SecurityException e) { @@ -122,7 +127,7 @@ private synchronized void put(int fd, Fd handle) { } public synchronized void remove(int fd) { - handles.remove(fd); + handles.removeKey(fd); } /** @@ -134,7 +139,7 @@ public synchronized int size() { @Override public synchronized void close() throws IOException { - for (final Fd handle : handles.values()) { + for (final Fd handle : handles.getValues()) { handle.close(); } handles.clear(); diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/FdUtils.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/FdUtils.java index 6198d347d718..cb53a6728618 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/FdUtils.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/FdUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -138,19 +138,21 @@ static Errno writeFilestat(Node node, WasmMemory memory, int address, TruffleFil try { Filestat.writeFiletype(node, memory, address, getType(file)); Filestat.writeSize(node, memory, address, file.getAttribute(TruffleFile.SIZE)); - Filestat.writeAtim(node, memory, address, file.getAttribute(TruffleFile.LAST_ACCESS_TIME).to(TimeUnit.SECONDS)); - Filestat.writeMtim(node, memory, address, file.getAttribute(TruffleFile.LAST_MODIFIED_TIME).to(TimeUnit.SECONDS)); + Filestat.writeAtim(node, memory, address, file.getAttribute(TruffleFile.LAST_ACCESS_TIME).to(TimeUnit.NANOSECONDS)); + Filestat.writeMtim(node, memory, address, file.getAttribute(TruffleFile.LAST_MODIFIED_TIME).to(TimeUnit.NANOSECONDS)); try { Filestat.writeDev(node, memory, address, file.getAttribute(TruffleFile.UNIX_DEV)); Filestat.writeIno(node, memory, address, file.getAttribute(TruffleFile.UNIX_INODE)); Filestat.writeNlink(node, memory, address, file.getAttribute(TruffleFile.UNIX_NLINK)); - Filestat.writeCtim(node, memory, address, file.getAttribute(TruffleFile.UNIX_CTIME).to(TimeUnit.SECONDS)); + Filestat.writeCtim(node, memory, address, file.getAttribute(TruffleFile.UNIX_CTIME).to(TimeUnit.NANOSECONDS)); } catch (UnsupportedOperationException e) { // GR-29297: these attributes are currently not supported on non-Unix platforms. } } catch (IOException e) { return Errno.Io; + } catch (SecurityException e) { + return Errno.Acces; } return Errno.Success; } diff --git a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/PreopenedDirectory.java b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/PreopenedDirectory.java index 23c4cc12183c..ff87fe1991f7 100644 --- a/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/PreopenedDirectory.java +++ b/wasm/src/org.graalvm.wasm/src/org/graalvm/wasm/predefined/wasi/fd/PreopenedDirectory.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * The Universal Permissive License (UPL), Version 1.0 @@ -41,12 +41,10 @@ package org.graalvm.wasm.predefined.wasi.fd; -import com.oracle.truffle.api.TruffleFile; -import com.oracle.truffle.api.nodes.Node; -import org.graalvm.wasm.memory.WasmMemory; - import java.util.Objects; +import com.oracle.truffle.api.TruffleFile; + /** * Wrapper around a pair (virtual directory, host directory). *

@@ -57,9 +55,8 @@ * ({@link #containedVirtualFile(TruffleFile)} and {@link #containedHostFile(TruffleFile)}). * *

- * These methods are only called from - * {@link DirectoryFd#pathOpen(Node, WasmMemory, int, int, int, short, long, long, short, int)}, - * which is currently the only way to create new {@link Fd} objects. + * These methods are only called from {@link DirectoryFd}, which is currently the only way to + * interact with {@link Fd} objects. */ final class PreopenedDirectory { @@ -68,18 +65,43 @@ final class PreopenedDirectory { */ private final TruffleFile hostPath; + /** + * The length of the host path used for comparisons. + */ + private final int hostPathLength; + /** * Virtual path of this pre-opened directory. */ private final TruffleFile virtualPath; + /** + * The length of the virtual path used for comparisons. + */ + private final int virtualPathLength; + PreopenedDirectory(TruffleFile hostPath, TruffleFile virtualPath) { Objects.requireNonNull(hostPath); Objects.requireNonNull(virtualPath); assert hostPath.isAbsolute() : "hostRoot must be absolute"; this.hostPath = hostPath.normalize(); + this.hostPathLength = this.hostPath.getPath().length(); this.virtualPath = virtualPath.normalize(); + this.virtualPathLength = this.virtualPath.getPath().length(); + } + + private static String getRelativePath(TruffleFile virtualFile, int rootPathLength) { + final int virtualFileLength = virtualFile.getPath().length(); + if (virtualFileLength == rootPathLength) { + return ""; + } + if (rootPathLength == 1) { + // root path, no trailing slash + return virtualFile.getPath().substring(1); + } + // remove trailing slash + return virtualFile.getPath().substring(rootPathLength + 1); } /** @@ -117,10 +139,25 @@ TruffleFile virtualFileToHostFile(TruffleFile virtualTruffleFile) { final TruffleFile resolvedVirtualTruffleFile = containedVirtualFile(virtualTruffleFile); if (resolvedVirtualTruffleFile != null) { - final String relativePathToRoot = resolvedVirtualTruffleFile.getPath().substring(virtualPath.getPath().length() + 1); + final String relativePathToRoot = getRelativePath(resolvedVirtualTruffleFile, virtualPathLength); return containedHostFile(hostPath.resolve(relativePathToRoot)); } return null; } + /** + * Returns the normalized virtual file for the given host file if it is contained in this + * pre-opened directory, or {@code null} otherwise. + */ + TruffleFile hostFileToVirtualFile(TruffleFile hostTruffleFile) { + Objects.requireNonNull(hostTruffleFile); + + final TruffleFile resolvedHostTruffleFile = containedHostFile(hostTruffleFile); + if (resolvedHostTruffleFile != null) { + final String resolvedPathToRoot = getRelativePath(resolvedHostTruffleFile, hostPathLength); + return containedVirtualFile(virtualPath.resolve(resolvedPathToRoot)); + } + return null; + } + }