mirror of
https://github.com/Eaglercraft-TeaVM-Fork/eagler-teavm.git
synced 2024-12-22 08:14:09 -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 {
|
||||
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");
|
||||
}
|
||||
|
||||
|
@ -405,7 +405,7 @@ public class TFile implements Serializable, Comparable<TFile> {
|
|||
|
||||
public boolean mkdir() {
|
||||
VirtualFile virtualFile = findParentFile();
|
||||
return virtualFile != null && virtualFile.createDirectory(getName());
|
||||
return virtualFile != null && virtualFile.isDirectory() && virtualFile.createDirectory(getName());
|
||||
}
|
||||
|
||||
public boolean mkdirs() {
|
||||
|
@ -416,7 +416,7 @@ public class TFile implements Serializable, Comparable<TFile> {
|
|||
}
|
||||
int i = path.length();
|
||||
|
||||
do {
|
||||
while (true) {
|
||||
VirtualFile file = fs().getFile(path.substring(0, i));
|
||||
if (file.isDirectory()) {
|
||||
break;
|
||||
|
@ -424,13 +424,18 @@ public class TFile implements Serializable, Comparable<TFile> {
|
|||
return false;
|
||||
}
|
||||
|
||||
i = path.lastIndexOf(separatorChar, i - 1);
|
||||
} while (i >= 0);
|
||||
|
||||
i++;
|
||||
int next = path.lastIndexOf(separatorChar, i - 1);
|
||||
if (next < 0) {
|
||||
break;
|
||||
}
|
||||
i = next;
|
||||
if (i == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (i < path.length()) {
|
||||
int next = path.indexOf(separatorChar, i);
|
||||
int next = path.indexOf(separatorChar, i + 1);
|
||||
if (next < 0) {
|
||||
next = path.length();
|
||||
}
|
||||
|
@ -438,11 +443,12 @@ public class TFile implements Serializable, Comparable<TFile> {
|
|||
break;
|
||||
}
|
||||
|
||||
VirtualFile file = fs().getFile(path.substring(0, i));
|
||||
if (!file.createDirectory(path.substring(i, next))) {
|
||||
String dirPath = i == 0 && path.startsWith("/") ? "/" : path.substring(0, i);
|
||||
VirtualFile file = fs().getFile(dirPath);
|
||||
if (!file.createDirectory(path.substring(i + 1, next))) {
|
||||
return false;
|
||||
}
|
||||
i = next + 1;
|
||||
i = next;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -515,7 +521,9 @@ public class TFile implements Serializable, Comparable<TFile> {
|
|||
if (directory == null) {
|
||||
String tmpDir = System.getProperty("java.io.tmpdir", ".");
|
||||
tmpDirFile = new TFile(tmpDir);
|
||||
tmpDirFile.mkdirs();
|
||||
if (!tmpDirFile.mkdirs()) {
|
||||
throw new IOException("Could not access temp dir");
|
||||
}
|
||||
} else {
|
||||
tmpDirFile = directory;
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ public class TFileInputStream extends InputStream {
|
|||
|
||||
public TFileInputStream(TFile file) throws FileNotFoundException {
|
||||
VirtualFile virtualFile = file.findVirtualFile();
|
||||
if (virtualFile == null || virtualFile.isDirectory()) {
|
||||
if (virtualFile == null || !virtualFile.isFile()) {
|
||||
throw new FileNotFoundException();
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ public class TFileOutputStream extends OutputStream {
|
|||
throw new FileNotFoundException("Invalid file name");
|
||||
}
|
||||
VirtualFile parentVirtualFile = file.findParentFile();
|
||||
if (parentVirtualFile != null) {
|
||||
if (parentVirtualFile != null && parentVirtualFile.isDirectory()) {
|
||||
try {
|
||||
parentVirtualFile.createFile(file.getName());
|
||||
} catch (IOException e) {
|
||||
|
@ -53,6 +53,9 @@ public class TFileOutputStream extends OutputStream {
|
|||
}
|
||||
|
||||
VirtualFile virtualFile = file.findVirtualFile();
|
||||
if (virtualFile == null || !virtualFile.isFile()) {
|
||||
throw new FileNotFoundException("Could not create file");
|
||||
}
|
||||
accessor = virtualFile.createAccessor(false, true, append);
|
||||
if (accessor == null) {
|
||||
throw new FileNotFoundException();
|
||||
|
|
|
@ -55,7 +55,7 @@ public class TRandomAccessFile implements DataInput, DataOutput, Closeable {
|
|||
}
|
||||
|
||||
VirtualFile virtualFile = file.findVirtualFile();
|
||||
if (virtualFile == null || virtualFile.isDirectory()) {
|
||||
if (virtualFile == null || !virtualFile.isFile()) {
|
||||
throw new FileNotFoundException();
|
||||
}
|
||||
|
||||
|
|
|
@ -1527,6 +1527,7 @@ public class TArrays extends TObject {
|
|||
|
||||
@SafeVarargs
|
||||
public static <T> TList<T> asList(final T... a) {
|
||||
Objects.requireNonNull(a);
|
||||
return new ArrayAsList<>(a);
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ public class WasiFileSystem implements VirtualFileSystem {
|
|||
}
|
||||
|
||||
void findBestPreopened(String path) {
|
||||
if (path.endsWith("/")) {
|
||||
if (path.endsWith("/") && 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) {
|
||||
if (dir.equals("/")) {
|
||||
return 0;
|
||||
} else {
|
||||
return name.startsWith(dir) && name.length() > dir.length() && name.charAt(dir.length()) == '/'
|
||||
? dir.length() + 1 : -1;
|
||||
if (dir.equals("/") && name.startsWith("/")) {
|
||||
return 1;
|
||||
}
|
||||
return name.startsWith(dir) && name.length() > dir.length() && name.charAt(dir.length()) == '/'
|
||||
? dir.length() + 1 : -1;
|
||||
}
|
||||
|
||||
@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.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_READDIR;
|
||||
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;
|
||||
|
@ -39,7 +40,7 @@ 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.IntResult;
|
||||
import org.teavm.backend.wasm.wasi.Wasi;
|
||||
import org.teavm.interop.Address;
|
||||
import org.teavm.interop.Structure;
|
||||
|
@ -109,12 +110,12 @@ public class WasiVirtualFile implements VirtualFile {
|
|||
}
|
||||
|
||||
private String[] listFiles(int fd) {
|
||||
SizeResult sizePtr = WasiBuffer.getBuffer().toStructure();
|
||||
IntResult 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 direntArrayOffset = (int) direntBuffer.diff(Address.ofData(direntArray));
|
||||
int bufferSize = direntArray.length - direntArrayOffset;
|
||||
long cookie = 0;
|
||||
|
||||
|
@ -124,27 +125,34 @@ public class WasiVirtualFile implements VirtualFile {
|
|||
if (errno != ERRNO_SUCCESS) {
|
||||
return null;
|
||||
}
|
||||
int size = sizePtr.value;
|
||||
int remainingSize = bufferSize;
|
||||
int entryOffset = 0;
|
||||
while (true) {
|
||||
if (remainingSize < direntSize) {
|
||||
break;
|
||||
}
|
||||
Address direntPtr = direntBuffer.add(direntArrayOffset);
|
||||
Address direntPtr = direntBuffer.add(entryOffset);
|
||||
Dirent dirent = direntPtr.toStructure();
|
||||
int entryLength = direntSize + (int) dirent.nameLength;
|
||||
int entryLength = direntSize + 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;
|
||||
} else if (entryOffset + entryLength > bufferSize) {
|
||||
break;
|
||||
}
|
||||
cookie = dirent.next;
|
||||
list.add(new String(direntArray, direntArrayOffset + direntSize, (int) dirent.nameLength,
|
||||
StandardCharsets.UTF_8));
|
||||
String name = new String(direntArray, direntArrayOffset + entryOffset + direntSize, dirent.nameLength,
|
||||
StandardCharsets.UTF_8);
|
||||
if (!name.equals(".") && !name.equals("..")) {
|
||||
list.add(name);
|
||||
}
|
||||
remainingSize -= entryLength;
|
||||
direntArrayOffset += entryLength;
|
||||
if (direntArrayOffset == sizePtr.value) {
|
||||
entryOffset += entryLength;
|
||||
if (entryOffset == size) {
|
||||
break outer;
|
||||
}
|
||||
}
|
||||
|
@ -159,7 +167,7 @@ public class WasiVirtualFile implements VirtualFile {
|
|||
if (baseFd < 0) {
|
||||
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) {
|
||||
return null;
|
||||
}
|
||||
|
@ -214,7 +222,7 @@ public class WasiVirtualFile implements VirtualFile {
|
|||
public boolean createFile(String fileName) throws IOException {
|
||||
init();
|
||||
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);
|
||||
if (fs.errno == ERRNO_EXIST) {
|
||||
|
@ -241,12 +249,17 @@ public class WasiVirtualFile implements VirtualFile {
|
|||
@Override
|
||||
public boolean delete() {
|
||||
init();
|
||||
if (fullPath == null || baseFd < 0) {
|
||||
if (path == 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;
|
||||
if (isFile()) {
|
||||
byte[] bytes = path.getBytes(StandardCharsets.UTF_8);
|
||||
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) {
|
||||
|
|
|
@ -20,6 +20,6 @@ import org.teavm.interop.Structure;
|
|||
public class Dirent extends Structure {
|
||||
public long next;
|
||||
public long inode;
|
||||
public long nameLength;
|
||||
public long fileType;
|
||||
public int nameLength;
|
||||
public int fileType;
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ public final class Wasi {
|
|||
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_READDIR = 1L << 14;
|
||||
public static final long RIGHTS_FD_FILESTAT_GET = 1L << 21;
|
||||
public static final long RIGHTS_FD_FILESTAT_SET_SIZE = 1L << 22;
|
||||
|
||||
|
@ -93,7 +94,7 @@ public final class Wasi {
|
|||
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);
|
||||
public static native short fdReaddir(int fd, Address dirent, int direntSize, long cookie, IntResult size);
|
||||
|
||||
@Import(name = "path_open", module = "wasi_snapshot_preview1")
|
||||
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")
|
||||
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")
|
||||
public static native short pathRename(int oldFd, Address oldPath, int oldPathLength, int newFd, Address newPath,
|
||||
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