mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-31 12:24:10 -08:00
Wasi: fix bugs in IO implementation
This commit is contained in:
parent
d9fb2bc159
commit
70e37dfed9
|
@ -396,7 +396,7 @@ public class TFile implements Serializable, Comparable<TFile> {
|
||||||
|
|
||||||
public boolean createNewFile() throws IOException {
|
public boolean createNewFile() throws IOException {
|
||||||
VirtualFile parentVirtualFile = findParentFile();
|
VirtualFile parentVirtualFile = findParentFile();
|
||||||
if (parentVirtualFile == null) {
|
if (parentVirtualFile == null || !parentVirtualFile.isDirectory()) {
|
||||||
throw new IOException("Can't create file " + getPath() + " since parent directory does not exist");
|
throw new IOException("Can't create file " + getPath() + " since parent directory does not exist");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -405,7 +405,7 @@ public class TFile implements Serializable, Comparable<TFile> {
|
||||||
|
|
||||||
public boolean mkdir() {
|
public boolean mkdir() {
|
||||||
VirtualFile virtualFile = findParentFile();
|
VirtualFile virtualFile = findParentFile();
|
||||||
return virtualFile != null && virtualFile.createDirectory(getName());
|
return virtualFile != null && virtualFile.isDirectory() && virtualFile.createDirectory(getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean mkdirs() {
|
public boolean mkdirs() {
|
||||||
|
@ -416,7 +416,7 @@ public class TFile implements Serializable, Comparable<TFile> {
|
||||||
}
|
}
|
||||||
int i = path.length();
|
int i = path.length();
|
||||||
|
|
||||||
do {
|
while (true) {
|
||||||
VirtualFile file = fs().getFile(path.substring(0, i));
|
VirtualFile file = fs().getFile(path.substring(0, i));
|
||||||
if (file.isDirectory()) {
|
if (file.isDirectory()) {
|
||||||
break;
|
break;
|
||||||
|
@ -424,13 +424,18 @@ public class TFile implements Serializable, Comparable<TFile> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
i = path.lastIndexOf(separatorChar, i - 1);
|
int next = path.lastIndexOf(separatorChar, i - 1);
|
||||||
} while (i >= 0);
|
if (next < 0) {
|
||||||
|
break;
|
||||||
i++;
|
}
|
||||||
|
i = next;
|
||||||
|
if (i == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (i < path.length()) {
|
while (i < path.length()) {
|
||||||
int next = path.indexOf(separatorChar, i);
|
int next = path.indexOf(separatorChar, i + 1);
|
||||||
if (next < 0) {
|
if (next < 0) {
|
||||||
next = path.length();
|
next = path.length();
|
||||||
}
|
}
|
||||||
|
@ -438,11 +443,12 @@ public class TFile implements Serializable, Comparable<TFile> {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
VirtualFile file = fs().getFile(path.substring(0, i));
|
String dirPath = i == 0 && path.startsWith("/") ? "/" : path.substring(0, i);
|
||||||
if (!file.createDirectory(path.substring(i, next))) {
|
VirtualFile file = fs().getFile(dirPath);
|
||||||
|
if (!file.createDirectory(path.substring(i + 1, next))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
i = next + 1;
|
i = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -515,7 +521,9 @@ public class TFile implements Serializable, Comparable<TFile> {
|
||||||
if (directory == null) {
|
if (directory == null) {
|
||||||
String tmpDir = System.getProperty("java.io.tmpdir", ".");
|
String tmpDir = System.getProperty("java.io.tmpdir", ".");
|
||||||
tmpDirFile = new TFile(tmpDir);
|
tmpDirFile = new TFile(tmpDir);
|
||||||
tmpDirFile.mkdirs();
|
if (!tmpDirFile.mkdirs()) {
|
||||||
|
throw new IOException("Could not access temp dir");
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
tmpDirFile = directory;
|
tmpDirFile = directory;
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ public class TFileInputStream extends InputStream {
|
||||||
|
|
||||||
public TFileInputStream(TFile file) throws FileNotFoundException {
|
public TFileInputStream(TFile file) throws FileNotFoundException {
|
||||||
VirtualFile virtualFile = file.findVirtualFile();
|
VirtualFile virtualFile = file.findVirtualFile();
|
||||||
if (virtualFile == null || virtualFile.isDirectory()) {
|
if (virtualFile == null || !virtualFile.isFile()) {
|
||||||
throw new FileNotFoundException();
|
throw new FileNotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,7 +44,7 @@ public class TFileOutputStream extends OutputStream {
|
||||||
throw new FileNotFoundException("Invalid file name");
|
throw new FileNotFoundException("Invalid file name");
|
||||||
}
|
}
|
||||||
VirtualFile parentVirtualFile = file.findParentFile();
|
VirtualFile parentVirtualFile = file.findParentFile();
|
||||||
if (parentVirtualFile != null) {
|
if (parentVirtualFile != null && parentVirtualFile.isDirectory()) {
|
||||||
try {
|
try {
|
||||||
parentVirtualFile.createFile(file.getName());
|
parentVirtualFile.createFile(file.getName());
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -53,6 +53,9 @@ public class TFileOutputStream extends OutputStream {
|
||||||
}
|
}
|
||||||
|
|
||||||
VirtualFile virtualFile = file.findVirtualFile();
|
VirtualFile virtualFile = file.findVirtualFile();
|
||||||
|
if (virtualFile == null || !virtualFile.isFile()) {
|
||||||
|
throw new FileNotFoundException("Could not create file");
|
||||||
|
}
|
||||||
accessor = virtualFile.createAccessor(false, true, append);
|
accessor = virtualFile.createAccessor(false, true, append);
|
||||||
if (accessor == null) {
|
if (accessor == null) {
|
||||||
throw new FileNotFoundException();
|
throw new FileNotFoundException();
|
||||||
|
|
|
@ -55,7 +55,7 @@ public class TRandomAccessFile implements DataInput, DataOutput, Closeable {
|
||||||
}
|
}
|
||||||
|
|
||||||
VirtualFile virtualFile = file.findVirtualFile();
|
VirtualFile virtualFile = file.findVirtualFile();
|
||||||
if (virtualFile == null || virtualFile.isDirectory()) {
|
if (virtualFile == null || !virtualFile.isFile()) {
|
||||||
throw new FileNotFoundException();
|
throw new FileNotFoundException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1527,6 +1527,7 @@ public class TArrays extends TObject {
|
||||||
|
|
||||||
@SafeVarargs
|
@SafeVarargs
|
||||||
public static <T> TList<T> asList(final T... a) {
|
public static <T> TList<T> asList(final T... a) {
|
||||||
|
Objects.requireNonNull(a);
|
||||||
return new ArrayAsList<>(a);
|
return new ArrayAsList<>(a);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ public class WasiFileSystem implements VirtualFileSystem {
|
||||||
}
|
}
|
||||||
|
|
||||||
void findBestPreopened(String path) {
|
void findBestPreopened(String path) {
|
||||||
if (path.endsWith("/")) {
|
if (path.endsWith("/") && path.length() > 1) {
|
||||||
path = path.substring(0, path.length() - 1);
|
path = path.substring(0, path.length() - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,12 +81,11 @@ public class WasiFileSystem implements VirtualFileSystem {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getPrefixLength(String name, String dir) {
|
private static int getPrefixLength(String name, String dir) {
|
||||||
if (dir.equals("/")) {
|
if (dir.equals("/") && name.startsWith("/")) {
|
||||||
return 0;
|
return 1;
|
||||||
} else {
|
|
||||||
return name.startsWith(dir) && name.length() > dir.length() && name.charAt(dir.length()) == '/'
|
|
||||||
? dir.length() + 1 : -1;
|
|
||||||
}
|
}
|
||||||
|
return name.startsWith(dir) && name.length() > dir.length() && name.charAt(dir.length()) == '/'
|
||||||
|
? dir.length() + 1 : -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -27,6 +27,7 @@ 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.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_GET;
|
||||||
import static org.teavm.backend.wasm.wasi.Wasi.RIGHTS_FD_FILESTAT_SET_SIZE;
|
import static org.teavm.backend.wasm.wasi.Wasi.RIGHTS_FD_FILESTAT_SET_SIZE;
|
||||||
|
import static org.teavm.backend.wasm.wasi.Wasi.RIGHTS_FD_READDIR;
|
||||||
import static org.teavm.backend.wasm.wasi.Wasi.RIGHTS_READ;
|
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_SEEK;
|
||||||
import static org.teavm.backend.wasm.wasi.Wasi.RIGHTS_SYNC;
|
import static org.teavm.backend.wasm.wasi.Wasi.RIGHTS_SYNC;
|
||||||
|
@ -39,7 +40,7 @@ import org.teavm.backend.wasm.runtime.WasiBuffer;
|
||||||
import org.teavm.backend.wasm.wasi.Dirent;
|
import org.teavm.backend.wasm.wasi.Dirent;
|
||||||
import org.teavm.backend.wasm.wasi.FdResult;
|
import org.teavm.backend.wasm.wasi.FdResult;
|
||||||
import org.teavm.backend.wasm.wasi.Filestat;
|
import org.teavm.backend.wasm.wasi.Filestat;
|
||||||
import org.teavm.backend.wasm.wasi.SizeResult;
|
import org.teavm.backend.wasm.wasi.IntResult;
|
||||||
import org.teavm.backend.wasm.wasi.Wasi;
|
import org.teavm.backend.wasm.wasi.Wasi;
|
||||||
import org.teavm.interop.Address;
|
import org.teavm.interop.Address;
|
||||||
import org.teavm.interop.Structure;
|
import org.teavm.interop.Structure;
|
||||||
|
@ -109,12 +110,12 @@ public class WasiVirtualFile implements VirtualFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
private String[] listFiles(int fd) {
|
private String[] listFiles(int fd) {
|
||||||
SizeResult sizePtr = WasiBuffer.getBuffer().toStructure();
|
IntResult sizePtr = WasiBuffer.getBuffer().toStructure();
|
||||||
ArrayList<String> list = new ArrayList<>();
|
ArrayList<String> list = new ArrayList<>();
|
||||||
final int direntSize = Structure.sizeOf(Dirent.class);
|
final int direntSize = Structure.sizeOf(Dirent.class);
|
||||||
byte[] direntArray = fs.buffer;
|
byte[] direntArray = fs.buffer;
|
||||||
Address direntBuffer = Address.align(Address.ofData(direntArray), 8);
|
Address direntBuffer = Address.align(Address.ofData(direntArray), 8);
|
||||||
int direntArrayOffset = (int) direntBuffer.diff(Address.ofData(direntArray).add(8));
|
int direntArrayOffset = (int) direntBuffer.diff(Address.ofData(direntArray));
|
||||||
int bufferSize = direntArray.length - direntArrayOffset;
|
int bufferSize = direntArray.length - direntArrayOffset;
|
||||||
long cookie = 0;
|
long cookie = 0;
|
||||||
|
|
||||||
|
@ -124,27 +125,34 @@ public class WasiVirtualFile implements VirtualFile {
|
||||||
if (errno != ERRNO_SUCCESS) {
|
if (errno != ERRNO_SUCCESS) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
int size = sizePtr.value;
|
||||||
int remainingSize = bufferSize;
|
int remainingSize = bufferSize;
|
||||||
|
int entryOffset = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
if (remainingSize < direntSize) {
|
if (remainingSize < direntSize) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Address direntPtr = direntBuffer.add(direntArrayOffset);
|
Address direntPtr = direntBuffer.add(entryOffset);
|
||||||
Dirent dirent = direntPtr.toStructure();
|
Dirent dirent = direntPtr.toStructure();
|
||||||
int entryLength = direntSize + (int) dirent.nameLength;
|
int entryLength = direntSize + dirent.nameLength;
|
||||||
if (entryLength > bufferSize) {
|
if (entryLength > bufferSize) {
|
||||||
direntArray = new byte[entryLength * 3 / 2 + 8];
|
direntArray = new byte[entryLength * 3 / 2 + 8];
|
||||||
direntBuffer = Address.align(Address.ofData(direntArray), 8);
|
direntBuffer = Address.align(Address.ofData(direntArray), 8);
|
||||||
direntArrayOffset = (int) direntBuffer.diff(Address.ofData(direntArray));
|
direntArrayOffset = (int) direntBuffer.diff(Address.ofData(direntArray));
|
||||||
bufferSize = direntArray.length - direntArrayOffset;
|
bufferSize = direntArray.length - direntArrayOffset;
|
||||||
break;
|
break;
|
||||||
|
} else if (entryOffset + entryLength > bufferSize) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
cookie = dirent.next;
|
cookie = dirent.next;
|
||||||
list.add(new String(direntArray, direntArrayOffset + direntSize, (int) dirent.nameLength,
|
String name = new String(direntArray, direntArrayOffset + entryOffset + direntSize, dirent.nameLength,
|
||||||
StandardCharsets.UTF_8));
|
StandardCharsets.UTF_8);
|
||||||
|
if (!name.equals(".") && !name.equals("..")) {
|
||||||
|
list.add(name);
|
||||||
|
}
|
||||||
remainingSize -= entryLength;
|
remainingSize -= entryLength;
|
||||||
direntArrayOffset += entryLength;
|
entryOffset += entryLength;
|
||||||
if (direntArrayOffset == sizePtr.value) {
|
if (entryOffset == size) {
|
||||||
break outer;
|
break outer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -159,7 +167,7 @@ public class WasiVirtualFile implements VirtualFile {
|
||||||
if (baseFd < 0) {
|
if (baseFd < 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
int fd = path != null ? open(OFLAGS_DIRECTORY, RIGHTS_READ, (short) 0) : baseFd;
|
int fd = path != null ? open(OFLAGS_DIRECTORY, RIGHTS_READ | RIGHTS_FD_READDIR, (short) 0) : baseFd;
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -214,7 +222,7 @@ public class WasiVirtualFile implements VirtualFile {
|
||||||
public boolean createFile(String fileName) throws IOException {
|
public boolean createFile(String fileName) throws IOException {
|
||||||
init();
|
init();
|
||||||
if (baseFd < 0) {
|
if (baseFd < 0) {
|
||||||
return false;
|
throw new IOException("Can't create file: access to directory not granted by WASI runtime");
|
||||||
}
|
}
|
||||||
int fd = open(baseFd, constructPath(path, fileName), (short) (OFLAGS_CREATE | OFLAGS_EXCLUSIVE), 0, (short) 0);
|
int fd = open(baseFd, constructPath(path, fileName), (short) (OFLAGS_CREATE | OFLAGS_EXCLUSIVE), 0, (short) 0);
|
||||||
if (fs.errno == ERRNO_EXIST) {
|
if (fs.errno == ERRNO_EXIST) {
|
||||||
|
@ -241,12 +249,17 @@ public class WasiVirtualFile implements VirtualFile {
|
||||||
@Override
|
@Override
|
||||||
public boolean delete() {
|
public boolean delete() {
|
||||||
init();
|
init();
|
||||||
if (fullPath == null || baseFd < 0) {
|
if (path == null || baseFd < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
byte[] bytes = path.getBytes(StandardCharsets.UTF_8);
|
if (isFile()) {
|
||||||
short errno = Wasi.pathUnlinkFile(baseFd, Address.ofData(bytes), bytes.length);
|
byte[] bytes = path.getBytes(StandardCharsets.UTF_8);
|
||||||
return errno == ERRNO_SUCCESS;
|
return Wasi.pathUnlinkFile(baseFd, Address.ofData(bytes), bytes.length) == ERRNO_SUCCESS;
|
||||||
|
} else if (isDirectory()) {
|
||||||
|
byte[] bytes = path.getBytes(StandardCharsets.UTF_8);
|
||||||
|
return Wasi.pathRemoveDirectory(baseFd, Address.ofData(bytes), bytes.length) == ERRNO_SUCCESS;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean adopt(int fd, WasiVirtualFile file, String fileName) {
|
private static boolean adopt(int fd, WasiVirtualFile file, String fileName) {
|
||||||
|
|
|
@ -20,6 +20,6 @@ import org.teavm.interop.Structure;
|
||||||
public class Dirent extends Structure {
|
public class Dirent extends Structure {
|
||||||
public long next;
|
public long next;
|
||||||
public long inode;
|
public long inode;
|
||||||
public long nameLength;
|
public int nameLength;
|
||||||
public long fileType;
|
public int fileType;
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ public final class Wasi {
|
||||||
public static final long RIGHTS_SYNC = 1L << 4;
|
public static final long RIGHTS_SYNC = 1L << 4;
|
||||||
public static final long RIGHTS_CREATE_DIRECTORY = 1L << 9;
|
public static final long RIGHTS_CREATE_DIRECTORY = 1L << 9;
|
||||||
public static final long RIGHTS_CREATE_FILE = 1L << 10;
|
public static final long RIGHTS_CREATE_FILE = 1L << 10;
|
||||||
|
public static final long RIGHTS_FD_READDIR = 1L << 14;
|
||||||
public static final long RIGHTS_FD_FILESTAT_GET = 1L << 21;
|
public static final long RIGHTS_FD_FILESTAT_GET = 1L << 21;
|
||||||
public static final long RIGHTS_FD_FILESTAT_SET_SIZE = 1L << 22;
|
public static final long RIGHTS_FD_FILESTAT_SET_SIZE = 1L << 22;
|
||||||
|
|
||||||
|
@ -93,7 +94,7 @@ public final class Wasi {
|
||||||
Filestat filestat);
|
Filestat filestat);
|
||||||
|
|
||||||
@Import(name = "fd_readdir", module = "wasi_snapshot_preview1")
|
@Import(name = "fd_readdir", module = "wasi_snapshot_preview1")
|
||||||
public static native short fdReaddir(int fd, Address dirent, int direntSize, long cookie, SizeResult size);
|
public static native short fdReaddir(int fd, Address dirent, int direntSize, long cookie, IntResult size);
|
||||||
|
|
||||||
@Import(name = "path_open", module = "wasi_snapshot_preview1")
|
@Import(name = "path_open", module = "wasi_snapshot_preview1")
|
||||||
public static native short pathOpen(int dirFd, int lookupFlags, Address path, int pathLength, short oflags,
|
public static native short pathOpen(int dirFd, int lookupFlags, Address path, int pathLength, short oflags,
|
||||||
|
@ -108,6 +109,9 @@ public final class Wasi {
|
||||||
@Import(name = "path_unlink_file", module = "wasi_snapshot_preview1")
|
@Import(name = "path_unlink_file", module = "wasi_snapshot_preview1")
|
||||||
public static native short pathUnlinkFile(int fd, Address path, int pathLength);
|
public static native short pathUnlinkFile(int fd, Address path, int pathLength);
|
||||||
|
|
||||||
|
@Import(name = "path_remove_directory", module = "wasi_snapshot_preview1")
|
||||||
|
public static native short pathRemoveDirectory(int fd, Address path, int pathLength);
|
||||||
|
|
||||||
@Import(name = "path_rename", module = "wasi_snapshot_preview1")
|
@Import(name = "path_rename", module = "wasi_snapshot_preview1")
|
||||||
public static native short pathRename(int oldFd, Address oldPath, int oldPathLength, int newFd, Address newPath,
|
public static native short pathRename(int oldFd, Address oldPath, int oldPathLength, int newFd, Address newPath,
|
||||||
int newPathLength);
|
int newPathLength);
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
~/.wasmtime/bin/wasmtime run --dir target/wasi-testdir --mapdir /::target/wasi-testdir $1 $2
|
~/.wasmtime/bin/wasmtime run --mapdir /::target/wasi-testdir $1 $2
|
Loading…
Reference in New Issue
Block a user