mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -08:00
Wasm: implement file IO in WASI
This commit is contained in:
parent
3eb4b742ea
commit
e428e2ac7a
|
@ -15,7 +15,9 @@
|
||||||
*/
|
*/
|
||||||
package org.teavm.backend.c.intrinsic;
|
package org.teavm.backend.c.intrinsic;
|
||||||
|
|
||||||
|
import org.teavm.ast.Expr;
|
||||||
import org.teavm.ast.InvocationExpr;
|
import org.teavm.ast.InvocationExpr;
|
||||||
|
import org.teavm.ast.VariableExpr;
|
||||||
import org.teavm.backend.c.generate.CodeGeneratorUtil;
|
import org.teavm.backend.c.generate.CodeGeneratorUtil;
|
||||||
import org.teavm.backend.c.util.ConstantUtil;
|
import org.teavm.backend.c.util.ConstantUtil;
|
||||||
import org.teavm.interop.Address;
|
import org.teavm.interop.Address;
|
||||||
|
@ -62,6 +64,8 @@ public class AddressIntrinsic implements Intrinsic {
|
||||||
case "sizeOf":
|
case "sizeOf":
|
||||||
|
|
||||||
case "ofData":
|
case "ofData":
|
||||||
|
|
||||||
|
case "pin":
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
@ -214,6 +218,16 @@ public class AddressIntrinsic implements Intrinsic {
|
||||||
+ sizeOf(type.getItemType()) + "))");
|
+ sizeOf(type.getItemType()) + "))");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "pin": {
|
||||||
|
context.writer().print("/* PIN ");
|
||||||
|
Expr arg = invocation.getArguments().get(0);
|
||||||
|
if (arg instanceof VariableExpr) {
|
||||||
|
context.writer().print(((VariableExpr) arg).getIndex() + " ");
|
||||||
|
}
|
||||||
|
context.writer().print("*/");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ import org.teavm.backend.wasm.generate.WasmClassGenerator;
|
||||||
import org.teavm.backend.wasm.model.WasmType;
|
import org.teavm.backend.wasm.model.WasmType;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmCall;
|
import org.teavm.backend.wasm.model.expression.WasmCall;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmConversion;
|
import org.teavm.backend.wasm.model.expression.WasmConversion;
|
||||||
|
import org.teavm.backend.wasm.model.expression.WasmDrop;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
import org.teavm.backend.wasm.model.expression.WasmExpression;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
|
import org.teavm.backend.wasm.model.expression.WasmInt32Constant;
|
||||||
import org.teavm.backend.wasm.model.expression.WasmInt32Subtype;
|
import org.teavm.backend.wasm.model.expression.WasmInt32Subtype;
|
||||||
|
@ -172,6 +173,8 @@ public class AddressIntrinsic implements WasmIntrinsic {
|
||||||
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD,
|
return new WasmIntBinary(WasmIntType.INT32, WasmIntBinaryOperation.ADD,
|
||||||
manager.generate(invocation.getArguments().get(0)), new WasmInt32Constant(start));
|
manager.generate(invocation.getArguments().get(0)), new WasmInt32Constant(start));
|
||||||
}
|
}
|
||||||
|
case "pin":
|
||||||
|
return new WasmDrop(new WasmInt32Constant(0));
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException(invocation.getMethod().toString());
|
throw new IllegalArgumentException(invocation.getMethod().toString());
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,159 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2022 TeaVM Contributors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.backend.wasm.runtime.fs;
|
||||||
|
|
||||||
|
import static org.teavm.backend.wasm.wasi.Wasi.ERRNO_BADF;
|
||||||
|
import static org.teavm.backend.wasm.wasi.Wasi.ERRNO_SUCCESS;
|
||||||
|
import static org.teavm.backend.wasm.wasi.Wasi.PRESTAT_DIR;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import org.teavm.backend.wasm.wasi.Prestat;
|
||||||
|
import org.teavm.backend.wasm.wasi.PrestatDir;
|
||||||
|
import org.teavm.backend.wasm.wasi.Wasi;
|
||||||
|
import org.teavm.interop.Address;
|
||||||
|
import org.teavm.runtime.fs.VirtualFile;
|
||||||
|
import org.teavm.runtime.fs.VirtualFileSystem;
|
||||||
|
|
||||||
|
public class WasiFileSystem implements VirtualFileSystem {
|
||||||
|
private List<Preopened> preopenedList;
|
||||||
|
final byte[] buffer = new byte[256];
|
||||||
|
short errno;
|
||||||
|
String bestPreopenedPath;
|
||||||
|
int bestPreopenedId;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getUserDir() {
|
||||||
|
return "/";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VirtualFile getFile(String path) {
|
||||||
|
return new WasiVirtualFile(this, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
void findBestPreopened(String path) {
|
||||||
|
if (path.startsWith("/")) {
|
||||||
|
path = path.substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path.endsWith("/")) {
|
||||||
|
path = path.substring(0, path.length() - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Preopened> list = getPreopenedList();
|
||||||
|
int bestFd = -1;
|
||||||
|
int bestNameLength = -1;
|
||||||
|
for (Preopened preopened : list) {
|
||||||
|
if (path.equals(preopened.name)) {
|
||||||
|
bestFd = preopened.fd;
|
||||||
|
path = null;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preopened.name.length() > bestNameLength) {
|
||||||
|
int prefixLen = getPrefixLength(path, preopened.name);
|
||||||
|
if (prefixLen >= 0) {
|
||||||
|
bestFd = preopened.fd;
|
||||||
|
bestNameLength = prefixLen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bestFd == -1) {
|
||||||
|
path = null;
|
||||||
|
} else if (path != null) {
|
||||||
|
path = path.substring(bestNameLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
bestPreopenedPath = path;
|
||||||
|
bestPreopenedId = bestFd;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int getPrefixLength(String name, String dir) {
|
||||||
|
if (dir.equals("/")) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return name.startsWith(dir) && name.length() > dir.length() && name.charAt(dir.length()) == '/'
|
||||||
|
? dir.length() + 1 : -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isWindows() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String canonicalize(String path) {
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Preopened> getPreopenedList() {
|
||||||
|
if (preopenedList == null) {
|
||||||
|
preopenedList = createPreopenedList();
|
||||||
|
}
|
||||||
|
return preopenedList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Preopened> createPreopenedList() {
|
||||||
|
byte[] buffer = this.buffer;
|
||||||
|
Prestat prestat = Address.align(Address.ofData(buffer), 4).toStructure();
|
||||||
|
List<Preopened> list = new ArrayList<>();
|
||||||
|
int fd = 3; // skip stdin, stdout, and stderr
|
||||||
|
while (true) {
|
||||||
|
short errno = Wasi.fdPrestatGet(fd, prestat);
|
||||||
|
if (errno == ERRNO_BADF) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (errno != ERRNO_BADF) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (prestat.kind == PRESTAT_DIR) {
|
||||||
|
PrestatDir prestatDir = (PrestatDir) prestat;
|
||||||
|
int length = prestatDir.nameLength;
|
||||||
|
byte[] bytes = length <= buffer.length ? buffer : new byte[length];
|
||||||
|
errno = Wasi.fdPrestatDirName(fd, Address.ofData(bytes), length);
|
||||||
|
|
||||||
|
if (errno == ERRNO_SUCCESS && length > 0) {
|
||||||
|
if (bytes[length - 1] == 0) {
|
||||||
|
length -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
list.add(new Preopened(fd, new String(bytes, 0, length, StandardCharsets.UTF_8)));
|
||||||
|
} else {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fd += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Preopened {
|
||||||
|
final int fd;
|
||||||
|
final String name;
|
||||||
|
|
||||||
|
Preopened(int fd, String name) {
|
||||||
|
this.fd = fd;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,368 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2022 TeaVM Contributors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.backend.wasm.runtime.fs;
|
||||||
|
|
||||||
|
import static org.teavm.backend.wasm.wasi.Wasi.DIRFLAGS_FOLLOW_SYMLINKS;
|
||||||
|
import static org.teavm.backend.wasm.wasi.Wasi.ERRNO_EXIST;
|
||||||
|
import static org.teavm.backend.wasm.wasi.Wasi.ERRNO_SUCCESS;
|
||||||
|
import static org.teavm.backend.wasm.wasi.Wasi.FDFLAGS_APPEND;
|
||||||
|
import static org.teavm.backend.wasm.wasi.Wasi.FILETYPE_DIRECTORY;
|
||||||
|
import static org.teavm.backend.wasm.wasi.Wasi.FILETYPE_REGULAR_FILE;
|
||||||
|
import static org.teavm.backend.wasm.wasi.Wasi.FSTFLAGS_MTIME;
|
||||||
|
import static org.teavm.backend.wasm.wasi.Wasi.OFLAGS_CREATE;
|
||||||
|
import static org.teavm.backend.wasm.wasi.Wasi.OFLAGS_DIRECTORY;
|
||||||
|
import static org.teavm.backend.wasm.wasi.Wasi.OFLAGS_EXCLUSIVE;
|
||||||
|
import static org.teavm.backend.wasm.wasi.Wasi.RIGHTS_FD_FILESTAT_GET;
|
||||||
|
import static org.teavm.backend.wasm.wasi.Wasi.RIGHTS_FD_FILESTAT_SET_SIZE;
|
||||||
|
import static org.teavm.backend.wasm.wasi.Wasi.RIGHTS_READ;
|
||||||
|
import static org.teavm.backend.wasm.wasi.Wasi.RIGHTS_SEEK;
|
||||||
|
import static org.teavm.backend.wasm.wasi.Wasi.RIGHTS_SYNC;
|
||||||
|
import static org.teavm.backend.wasm.wasi.Wasi.RIGHTS_TELL;
|
||||||
|
import static org.teavm.backend.wasm.wasi.Wasi.RIGHTS_WRITE;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import org.teavm.backend.wasm.runtime.WasiBuffer;
|
||||||
|
import org.teavm.backend.wasm.wasi.Dirent;
|
||||||
|
import org.teavm.backend.wasm.wasi.FdResult;
|
||||||
|
import org.teavm.backend.wasm.wasi.Filestat;
|
||||||
|
import org.teavm.backend.wasm.wasi.SizeResult;
|
||||||
|
import org.teavm.backend.wasm.wasi.Wasi;
|
||||||
|
import org.teavm.interop.Address;
|
||||||
|
import org.teavm.interop.Structure;
|
||||||
|
import org.teavm.runtime.fs.VirtualFile;
|
||||||
|
import org.teavm.runtime.fs.VirtualFileAccessor;
|
||||||
|
|
||||||
|
public class WasiVirtualFile implements VirtualFile {
|
||||||
|
private final WasiFileSystem fs;
|
||||||
|
private final String fullPath;
|
||||||
|
private boolean initialized;
|
||||||
|
private int baseFd;
|
||||||
|
private String path;
|
||||||
|
|
||||||
|
WasiVirtualFile(WasiFileSystem fs, String path) {
|
||||||
|
this.fs = fs;
|
||||||
|
fullPath = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void init() {
|
||||||
|
if (initialized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
initialized = true;
|
||||||
|
|
||||||
|
fs.findBestPreopened(path);
|
||||||
|
path = fs.bestPreopenedPath;
|
||||||
|
baseFd = fs.bestPreopenedId;
|
||||||
|
fs.bestPreopenedPath = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return path.substring(path.lastIndexOf('/') + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Stat stat() {
|
||||||
|
init();
|
||||||
|
if (baseFd < 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
Filestat filestat = Address.align(WasiBuffer.getBuffer(), 8).toStructure();
|
||||||
|
int errno;
|
||||||
|
if (path != null) {
|
||||||
|
byte[] bytes = path.getBytes(StandardCharsets.UTF_8);
|
||||||
|
errno = Wasi.pathFilestatGet(baseFd, DIRFLAGS_FOLLOW_SYMLINKS, Address.ofData(bytes), bytes.length,
|
||||||
|
filestat);
|
||||||
|
} else {
|
||||||
|
errno = Wasi.fdFilestatGet(baseFd, filestat);
|
||||||
|
}
|
||||||
|
if (errno == ERRNO_SUCCESS) {
|
||||||
|
return new Stat((byte) filestat.fileType, filestat.lastModified, filestat.size);
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isDirectory() {
|
||||||
|
Stat stat = stat();
|
||||||
|
return stat != null && stat.filetype == FILETYPE_DIRECTORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFile() {
|
||||||
|
Stat stat = stat();
|
||||||
|
return stat != null && stat.filetype == FILETYPE_REGULAR_FILE;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String[] listFiles(int fd) {
|
||||||
|
SizeResult sizePtr = WasiBuffer.getBuffer().toStructure();
|
||||||
|
ArrayList<String> list = new ArrayList<>();
|
||||||
|
final int direntSize = Structure.sizeOf(Dirent.class);
|
||||||
|
byte[] direntArray = fs.buffer;
|
||||||
|
Address direntBuffer = Address.align(Address.ofData(direntArray), 8);
|
||||||
|
int direntArrayOffset = (int) direntBuffer.diff(Address.ofData(direntArray).add(8));
|
||||||
|
int bufferSize = direntArray.length - direntArrayOffset;
|
||||||
|
long cookie = 0;
|
||||||
|
|
||||||
|
outer:
|
||||||
|
while (true) {
|
||||||
|
short errno = Wasi.fdReaddir(fd, direntBuffer, bufferSize, cookie, sizePtr);
|
||||||
|
if (errno != ERRNO_SUCCESS) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int remainingSize = bufferSize;
|
||||||
|
while (true) {
|
||||||
|
if (remainingSize < direntSize) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Address direntPtr = direntBuffer.add(direntArrayOffset);
|
||||||
|
Dirent dirent = direntPtr.toStructure();
|
||||||
|
int entryLength = direntSize + (int) dirent.nameLength;
|
||||||
|
if (entryLength > bufferSize) {
|
||||||
|
direntArray = new byte[entryLength * 3 / 2 + 8];
|
||||||
|
direntBuffer = Address.align(Address.ofData(direntArray), 8);
|
||||||
|
direntArrayOffset = (int) direntBuffer.diff(Address.ofData(direntArray));
|
||||||
|
bufferSize = direntArray.length - direntArrayOffset;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cookie = dirent.next;
|
||||||
|
list.add(new String(direntArray, direntArrayOffset + direntSize, (int) dirent.nameLength,
|
||||||
|
StandardCharsets.UTF_8));
|
||||||
|
remainingSize -= entryLength;
|
||||||
|
direntArrayOffset += entryLength;
|
||||||
|
if (direntArrayOffset == sizePtr.value) {
|
||||||
|
break outer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return list.toArray(new String[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] listFiles() {
|
||||||
|
init();
|
||||||
|
if (baseFd < 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
int fd = path != null ? open(OFLAGS_DIRECTORY, RIGHTS_READ, (short) 0) : baseFd;
|
||||||
|
if (fd < 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return listFiles(fd);
|
||||||
|
} finally {
|
||||||
|
if (path != null) {
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private int open(int fd, String path, short oflags, long rights, short fdflags) {
|
||||||
|
byte[] bytes = path.getBytes(StandardCharsets.UTF_8);
|
||||||
|
FdResult fdPtr = WasiBuffer.getBuffer().toStructure();
|
||||||
|
fs.errno = Wasi.pathOpen(fd, DIRFLAGS_FOLLOW_SYMLINKS, Address.ofData(bytes), bytes.length, oflags,
|
||||||
|
rights, rights, fdflags, fdPtr);
|
||||||
|
return fs.errno == ERRNO_SUCCESS ? fdPtr.value : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private int open(short oflags, long rights, short fdflags) {
|
||||||
|
return open(baseFd, path, oflags, rights, fdflags);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void close(int fd) {
|
||||||
|
// Ignore errno since this is only called in contexts where there's no need to handle the error.
|
||||||
|
Wasi.fdClose(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public VirtualFileAccessor createAccessor(boolean readable, boolean writable, boolean append) {
|
||||||
|
init();
|
||||||
|
if (baseFd < 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
long rights = 0;
|
||||||
|
if (readable) {
|
||||||
|
rights |= RIGHTS_FD_FILESTAT_GET | RIGHTS_SEEK | RIGHTS_TELL | RIGHTS_READ;
|
||||||
|
}
|
||||||
|
if (writable) {
|
||||||
|
rights |= RIGHTS_FD_FILESTAT_SET_SIZE | RIGHTS_WRITE | RIGHTS_SYNC;
|
||||||
|
}
|
||||||
|
short fdflags = (short) 0;
|
||||||
|
if (append) {
|
||||||
|
fdflags |= FDFLAGS_APPEND;
|
||||||
|
}
|
||||||
|
int fd = open((short) 0, rights, fdflags);
|
||||||
|
return fd >= 0 ? new WasiVirtualFileAccessor(fs, fd) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean createFile(String fileName) throws IOException {
|
||||||
|
init();
|
||||||
|
if (baseFd < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int fd = open(baseFd, constructPath(path, fileName), (short) (OFLAGS_CREATE | OFLAGS_EXCLUSIVE), 0, (short) 0);
|
||||||
|
if (fs.errno == ERRNO_EXIST) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (fs.errno != ERRNO_SUCCESS) {
|
||||||
|
throw new IOException("fd_open: " + fs.errno);
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean createDirectory(String fileName) {
|
||||||
|
init();
|
||||||
|
if (baseFd < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String filePath = constructPath(path, fileName);
|
||||||
|
byte[] bytes = filePath.getBytes(StandardCharsets.UTF_8);
|
||||||
|
return Wasi.pathCreateDirectory(baseFd, Address.ofData(bytes), bytes.length) == ERRNO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean delete() {
|
||||||
|
init();
|
||||||
|
if (fullPath == null || baseFd < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
byte[] bytes = path.getBytes(StandardCharsets.UTF_8);
|
||||||
|
short errno = Wasi.pathUnlinkFile(baseFd, Address.ofData(bytes), bytes.length);
|
||||||
|
return errno == ERRNO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean adopt(int fd, WasiVirtualFile file, String fileName) {
|
||||||
|
byte[] newBytes = fileName.getBytes(StandardCharsets.UTF_8);
|
||||||
|
byte[] oldBytes = file.path.getBytes(StandardCharsets.UTF_8);
|
||||||
|
short errno = Wasi.pathRename(file.baseFd, Address.ofData(oldBytes), oldBytes.length, fd,
|
||||||
|
Address.ofData(newBytes), newBytes.length);
|
||||||
|
return errno == ERRNO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean adopt(VirtualFile file, String fileName) {
|
||||||
|
if (!(file instanceof WasiVirtualFile)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
WasiVirtualFile wasiFile = (WasiVirtualFile) file;
|
||||||
|
wasiFile.init();
|
||||||
|
|
||||||
|
if (wasiFile.path == null || fileName == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
init();
|
||||||
|
if (baseFd < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path == null) {
|
||||||
|
return adopt(baseFd, wasiFile, fileName);
|
||||||
|
} else {
|
||||||
|
int fd = open(OFLAGS_DIRECTORY, RIGHTS_READ | RIGHTS_WRITE, (short) 0);
|
||||||
|
try {
|
||||||
|
return adopt(fd, wasiFile, fileName);
|
||||||
|
} finally {
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canRead() {
|
||||||
|
init();
|
||||||
|
int fd = open((short) 0, RIGHTS_READ, (short) 0);
|
||||||
|
if (fd >= 0) {
|
||||||
|
close(fd);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean canWrite() {
|
||||||
|
init();
|
||||||
|
int fd = open((short) 0, RIGHTS_WRITE, (short) 0);
|
||||||
|
if (fd >= 0) {
|
||||||
|
close(fd);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long lastModified() {
|
||||||
|
Stat stat = stat();
|
||||||
|
return stat == null ? 0 : stat.mtime / 1000000L;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setLastModified(long lastModified) {
|
||||||
|
init();
|
||||||
|
if (baseFd < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
short errno;
|
||||||
|
if (path == null) {
|
||||||
|
errno = Wasi.fdFilestatSetTimes(baseFd, 0, lastModified * 1000000L, FSTFLAGS_MTIME);
|
||||||
|
} else {
|
||||||
|
byte[] bytes = path.getBytes(StandardCharsets.UTF_8);
|
||||||
|
errno = Wasi.pathFilestatSetTimes(baseFd, DIRFLAGS_FOLLOW_SYMLINKS, Address.ofData(bytes), bytes.length,
|
||||||
|
0, lastModified * 1000000L, FSTFLAGS_MTIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
return errno == ERRNO_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean setReadOnly(boolean readOnly) {
|
||||||
|
// TODO: is this possible on WASI?
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int length() {
|
||||||
|
Stat stat = stat();
|
||||||
|
return stat == null ? 0 : (int) stat.filesize;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String constructPath(String parent, String child) {
|
||||||
|
if (parent == null) {
|
||||||
|
return child;
|
||||||
|
}
|
||||||
|
return !parent.isEmpty() && parent.charAt(parent.length() - 1) == '/'
|
||||||
|
? parent + child
|
||||||
|
: parent + '/' + child;
|
||||||
|
}
|
||||||
|
|
||||||
|
static class Stat {
|
||||||
|
final byte filetype;
|
||||||
|
final long mtime;
|
||||||
|
final long filesize;
|
||||||
|
|
||||||
|
Stat(byte filetype, long mtime, long filesize) {
|
||||||
|
this.filetype = filetype;
|
||||||
|
this.mtime = mtime;
|
||||||
|
this.filesize = filesize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,149 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2022 TeaVM Contributors.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.backend.wasm.runtime.fs;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import org.teavm.backend.wasm.runtime.WasiBuffer;
|
||||||
|
import org.teavm.interop.Address;
|
||||||
|
import org.teavm.runtime.fs.VirtualFileAccessor;
|
||||||
|
|
||||||
|
public class WasiVirtualFileAccessor implements VirtualFileAccessor {
|
||||||
|
// Enough room for an I32 plus padding for alignment:
|
||||||
|
private static final byte[] EIGHT_BYTE_BUFFER = new byte[8];
|
||||||
|
// Enough room for an I64 plus padding for alignment:
|
||||||
|
private static final byte[] SIXTEEN_BYTE_BUFFER = new byte[16];
|
||||||
|
|
||||||
|
private WasiFileSystem fs;
|
||||||
|
private int fd;
|
||||||
|
|
||||||
|
public WasiVirtualFileAccessor(WasiFileSystem fs, int fd) {
|
||||||
|
this.fs = fs;
|
||||||
|
this.fd = fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int read(byte[] buffer, int offset, int length) throws IOException {
|
||||||
|
byte[] vecBuffer = SIXTEEN_BYTE_BUFFER;
|
||||||
|
Address vec = WasiBuffer.getBuffer();
|
||||||
|
vec.putInt(Address.ofData(buffer).add(offset).toInt());
|
||||||
|
vec.add(4).putInt(length);
|
||||||
|
byte[] sizeBuffer = EIGHT_BYTE_BUFFER;
|
||||||
|
Address size = Address.align(Address.ofData(sizeBuffer), 4);
|
||||||
|
short errno = Wasi.fdRead(fd, vec, 1, size);
|
||||||
|
|
||||||
|
if (errno == ERRNO_SUCCESS) {
|
||||||
|
return size.getInt();
|
||||||
|
} else {
|
||||||
|
throw new IOException(errnoMessage("fd_read", errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(byte[] buffer, int offset, int length) throws IOException {
|
||||||
|
byte[] vecBuffer = SIXTEEN_BYTE_BUFFER;
|
||||||
|
Address vec = Address.align(Address.ofData(vecBuffer), 4);
|
||||||
|
byte[] sizeBuffer = EIGHT_BYTE_BUFFER;
|
||||||
|
Address size = Address.align(Address.ofData(sizeBuffer), 4);
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
while (true) {
|
||||||
|
vec.putInt(Address.ofData(buffer).add(offset + index).toInt());
|
||||||
|
vec.add(4).putInt(length - index);
|
||||||
|
short errno = Wasi.fdWrite(fd, vec, 1, size);
|
||||||
|
|
||||||
|
if (errno == ERRNO_SUCCESS) {
|
||||||
|
index += size.getInt();
|
||||||
|
if (index >= length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new IOException(errnoMessage("fd_write", errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int tell() throws IOException {
|
||||||
|
byte[] filesizeBuffer = SIXTEEN_BYTE_BUFFER;
|
||||||
|
Address filesize = Address.align(Address.ofData(filesizeBuffer), 8);
|
||||||
|
short errno = Wasi.fdTell(fd, filesize);
|
||||||
|
|
||||||
|
if (errno == ERRNO_SUCCESS) {
|
||||||
|
return (int) filesize.getLong();
|
||||||
|
} else {
|
||||||
|
throw new IOException(errnoMessage("fd_tell", errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private long seek(long offset, byte whence) throws IOException {
|
||||||
|
byte[] filesizeBuffer = SIXTEEN_BYTE_BUFFER;
|
||||||
|
Address filesize = Address.align(Address.ofData(filesizeBuffer), 8);
|
||||||
|
short errno = Wasi.fdSeek(fd, offset, whence, filesize);
|
||||||
|
|
||||||
|
if (errno == ERRNO_SUCCESS) {
|
||||||
|
return filesize.getLong();
|
||||||
|
} else {
|
||||||
|
throw new IOException(errnoMessage("fd_seek", errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void skip(int amount) throws IOException {
|
||||||
|
seek(amount, WHENCE_CURRENT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void seek(int target) throws IOException {
|
||||||
|
seek(target, WHENCE_START);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int size() throws IOException {
|
||||||
|
return (int) new WasiVirtualFile(fd, null).stat().filesize;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resize(int size) throws IOException {
|
||||||
|
short errno = Wasi.fdFilestatSetSize(fd, size);
|
||||||
|
|
||||||
|
if (errno != ERRNO_SUCCESS) {
|
||||||
|
throw new IOException(errnoMessage("fd_filestat_set_size", errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
if (this.fd >= 0) {
|
||||||
|
int fd = this.fd;
|
||||||
|
this.fd = -1;
|
||||||
|
|
||||||
|
short errno = Wasi.fdClose(fd);
|
||||||
|
|
||||||
|
if (errno != ERRNO_SUCCESS) {
|
||||||
|
throw new IOException(errnoMessage("fd_close", errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flush() throws IOException {
|
||||||
|
short errno = Wasi.fdSync(fd);
|
||||||
|
|
||||||
|
if (errno != ERRNO_SUCCESS) {
|
||||||
|
throw new IOException(errnoMessage("fd_sync", errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
25
core/src/main/java/org/teavm/backend/wasm/wasi/Dirent.java
Normal file
25
core/src/main/java/org/teavm/backend/wasm/wasi/Dirent.java
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2022 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.backend.wasm.wasi;
|
||||||
|
|
||||||
|
import org.teavm.interop.Structure;
|
||||||
|
|
||||||
|
public class Dirent extends Structure {
|
||||||
|
public long next;
|
||||||
|
public long inode;
|
||||||
|
public long nameLength;
|
||||||
|
public long fileType;
|
||||||
|
}
|
22
core/src/main/java/org/teavm/backend/wasm/wasi/FdResult.java
Normal file
22
core/src/main/java/org/teavm/backend/wasm/wasi/FdResult.java
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2022 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.backend.wasm.wasi;
|
||||||
|
|
||||||
|
import org.teavm.interop.Structure;
|
||||||
|
|
||||||
|
public class FdResult extends Structure {
|
||||||
|
public int value;
|
||||||
|
}
|
29
core/src/main/java/org/teavm/backend/wasm/wasi/Filestat.java
Normal file
29
core/src/main/java/org/teavm/backend/wasm/wasi/Filestat.java
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2022 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.backend.wasm.wasi;
|
||||||
|
|
||||||
|
import org.teavm.interop.Structure;
|
||||||
|
|
||||||
|
public class Filestat extends Structure {
|
||||||
|
public long deviceId;
|
||||||
|
public long inode;
|
||||||
|
public long fileType;
|
||||||
|
public long linkCount;
|
||||||
|
public long size;
|
||||||
|
public long lastAccess;
|
||||||
|
public long lastModified;
|
||||||
|
public long lastStatusChange;
|
||||||
|
}
|
22
core/src/main/java/org/teavm/backend/wasm/wasi/Prestat.java
Normal file
22
core/src/main/java/org/teavm/backend/wasm/wasi/Prestat.java
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2022 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.backend.wasm.wasi;
|
||||||
|
|
||||||
|
import org.teavm.interop.Structure;
|
||||||
|
|
||||||
|
public class Prestat extends Structure {
|
||||||
|
public int kind;
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2022 Alexey Andreev.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.teavm.backend.wasm.wasi;
|
||||||
|
|
||||||
|
public class PrestatDir extends Prestat {
|
||||||
|
public int nameLength;
|
||||||
|
}
|
|
@ -20,14 +20,44 @@ import org.teavm.interop.Import;
|
||||||
|
|
||||||
public final class Wasi {
|
public final class Wasi {
|
||||||
public static final int CLOCKID_REALTIME = 0;
|
public static final int CLOCKID_REALTIME = 0;
|
||||||
|
|
||||||
|
public static final byte PRESTAT_DIR = 0;
|
||||||
|
|
||||||
public static final short ERRNO_SUCCESS = 0;
|
public static final short ERRNO_SUCCESS = 0;
|
||||||
|
public static final short ERRNO_BADF = 8;
|
||||||
|
public static final short ERRNO_EXIST = 20;
|
||||||
|
public static final short ERRNO_NOENT = 44;
|
||||||
|
|
||||||
|
public static final byte FILETYPE_DIRECTORY = 3;
|
||||||
|
public static final byte FILETYPE_REGULAR_FILE = 4;
|
||||||
|
|
||||||
|
public static final int DIRFLAGS_FOLLOW_SYMLINKS = 1;
|
||||||
|
|
||||||
|
public static final short OFLAGS_CREATE = 1 << 0;
|
||||||
|
public static final short OFLAGS_DIRECTORY = 1 << 1;
|
||||||
|
public static final short OFLAGS_EXCLUSIVE = 1 << 2;
|
||||||
|
|
||||||
|
public static final long RIGHTS_READ = 1L << 1;
|
||||||
|
public static final long RIGHTS_SEEK = 1L << 2;
|
||||||
|
public static final long RIGHTS_TELL = 1L << 5;
|
||||||
|
public static final long RIGHTS_WRITE = 1L << 6;
|
||||||
|
public static final long RIGHTS_SYNC = 1L << 4;
|
||||||
|
public static final long RIGHTS_CREATE_DIRECTORY = 1L << 9;
|
||||||
|
public static final long RIGHTS_CREATE_FILE = 1L << 10;
|
||||||
|
public static final long RIGHTS_FD_FILESTAT_GET = 1L << 21;
|
||||||
|
public static final long RIGHTS_FD_FILESTAT_SET_SIZE = 1L << 22;
|
||||||
|
|
||||||
|
public static final short FDFLAGS_APPEND = 1 << 0;
|
||||||
|
|
||||||
|
public static final short FSTFLAGS_MTIME = 1 << 2;
|
||||||
|
|
||||||
|
public static final byte WHENCE_START = 0;
|
||||||
|
public static final byte WHENCE_CURRENT = 1;
|
||||||
|
public static final byte WHENCE_END = 2;
|
||||||
|
|
||||||
private Wasi() {
|
private Wasi() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Import(name = "fd_write", module = "wasi_snapshot_preview1")
|
|
||||||
public static native short fdWrite(int fd, IOVec vectors, int vectorsCont, SizeResult result);
|
|
||||||
|
|
||||||
@Import(name = "clock_time_get", module = "wasi_snapshot_preview1")
|
@Import(name = "clock_time_get", module = "wasi_snapshot_preview1")
|
||||||
public static native short clockTimeGet(int clockId, long precision, LongResult result);
|
public static native short clockTimeGet(int clockId, long precision, LongResult result);
|
||||||
|
|
||||||
|
@ -36,4 +66,47 @@ public final class Wasi {
|
||||||
|
|
||||||
@Import(name = "args_get", module = "wasi_snapshot_preview1")
|
@Import(name = "args_get", module = "wasi_snapshot_preview1")
|
||||||
public static native short argsGet(Address argv, Address argvBuf);
|
public static native short argsGet(Address argv, Address argvBuf);
|
||||||
|
|
||||||
|
@Import(name = "fd_write", module = "wasi_snapshot_preview1")
|
||||||
|
public static native short fdWrite(int fd, IOVec vectors, int vectorsCont, SizeResult result);
|
||||||
|
|
||||||
|
@Import(name = "fd_prestat_get", module = "wasi_snapshot_preview1")
|
||||||
|
public static native short fdPrestatGet(int fd, Prestat prestat);
|
||||||
|
|
||||||
|
@Import(name = "fd_prestat_dir_name", module = "wasi_snapshot_preview1")
|
||||||
|
public static native short fdPrestatDirName(int fd, Address buffer, int bufferLength);
|
||||||
|
|
||||||
|
@Import(name = "fd_filestat_get", module = "wasi_snapshot_preview1")
|
||||||
|
public static native short fdFilestatGet(int fd, Filestat filestat);
|
||||||
|
|
||||||
|
@Import(name = "path_filestat_get", module = "wasi_snapshot_preview1")
|
||||||
|
public static native short pathFilestatGet(int fd, int lookupFlags, Address path, int pathLength,
|
||||||
|
Filestat filestat);
|
||||||
|
|
||||||
|
@Import(name = "fd_readdir", module = "wasi_snapshot_preview1")
|
||||||
|
public static native short fdReaddir(int fd, Address dirent, int direntSize, long cookie, SizeResult size);
|
||||||
|
|
||||||
|
@Import(name = "path_open", module = "wasi_snapshot_preview1")
|
||||||
|
public static native short pathOpen(int dirFd, int lookupFlags, Address path, int pathLength, short oflags,
|
||||||
|
long baseRights, long inheritingRights, short fdflags, FdResult fd);
|
||||||
|
|
||||||
|
@Import(name = "fd_close", module = "wasi_snapshot_preview1")
|
||||||
|
public static native short fdClose(int fd);
|
||||||
|
|
||||||
|
@Import(name = "path_create_directory", module = "wasi_snapshot_preview1")
|
||||||
|
public static native short pathCreateDirectory(int fd, Address path, int pathLength);
|
||||||
|
|
||||||
|
@Import(name = "path_unlink_file", module = "wasi_snapshot_preview1")
|
||||||
|
public static native short pathUnlinkFile(int fd, Address path, int pathLength);
|
||||||
|
|
||||||
|
@Import(name = "path_rename", module = "wasi_snapshot_preview1")
|
||||||
|
public static native short pathRename(int oldFd, Address oldPath, int oldPathLength, int newFd, Address newPath,
|
||||||
|
int newPathLength);
|
||||||
|
|
||||||
|
@Import(name = "fd_filestat_set_times", module = "wasi_snapshot_preview1")
|
||||||
|
public static native short fdFilestatSetTimes(int fd, long atime, long mtime, short fstflags);
|
||||||
|
|
||||||
|
@Import(name = "path_filestat_set_times", module = "wasi_snapshot_preview1")
|
||||||
|
public static native short pathFilestatSetTimes(int fd, int lookupFlags, Address path, int pathLength,
|
||||||
|
long atime, long mtime, short fstflags);
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,4 +93,6 @@ public final class Address {
|
||||||
public long diff(Address that) {
|
public long diff(Address that) {
|
||||||
return toLong() - that.toLong();
|
return toLong() - that.toLong();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static native void pin(Object obj);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user