refactor: rework fs error system

This commit is contained in:
TopchetoEU 2024-02-09 13:46:57 +02:00
parent cf99845f6b
commit 1aad92ecec
Signed by: topchetoeu
GPG Key ID: 6531B8583E5F6ED4
23 changed files with 596 additions and 432 deletions

View File

@ -10,12 +10,12 @@ import me.topchetoeu.jscript.utils.interop.WrapperName;
@WrapperName("File") @WrapperName("File")
public class FileLib { public class FileLib {
public final File file; public final File fd;
@Expose public PromiseLib __pointer(Arguments args) { @Expose public PromiseLib __pointer(Arguments args) {
return PromiseLib.await(args.ctx, () -> { return PromiseLib.await(args.ctx, () -> {
try { try {
return file.seek(0, 1); return fd.seek(0, 1);
} }
catch (FilesystemException e) { throw e.toEngineException(); } catch (FilesystemException e) { throw e.toEngineException(); }
}); });
@ -23,9 +23,9 @@ public class FileLib {
@Expose public PromiseLib __length(Arguments args) { @Expose public PromiseLib __length(Arguments args) {
return PromiseLib.await(args.ctx, () -> { return PromiseLib.await(args.ctx, () -> {
try { try {
long curr = file.seek(0, 1); long curr = fd.seek(0, 1);
long res = file.seek(0, 2); long res = fd.seek(0, 2);
file.seek(curr, 0); fd.seek(curr, 0);
return res; return res;
} }
catch (FilesystemException e) { throw e.toEngineException(); } catch (FilesystemException e) { throw e.toEngineException(); }
@ -38,7 +38,7 @@ public class FileLib {
try { try {
var buff = new byte[n]; var buff = new byte[n];
var res = new ArrayValue(); var res = new ArrayValue();
int resI = file.read(buff); int resI = fd.read(buff);
for (var i = resI - 1; i >= 0; i--) res.set(args.ctx, i, (int)buff[i]); for (var i = resI - 1; i >= 0; i--) res.set(args.ctx, i, (int)buff[i]);
return res; return res;
@ -53,7 +53,7 @@ public class FileLib {
var res = new byte[val.size()]; var res = new byte[val.size()];
for (var i = 0; i < val.size(); i++) res[i] = (byte)Values.toNumber(args.ctx, val.get(i)); for (var i = 0; i < val.size(); i++) res[i] = (byte)Values.toNumber(args.ctx, val.get(i));
file.write(res); fd.write(res);
return null; return null;
} }
@ -62,7 +62,7 @@ public class FileLib {
} }
@Expose public PromiseLib __close(Arguments args) { @Expose public PromiseLib __close(Arguments args) {
return PromiseLib.await(args.ctx, () -> { return PromiseLib.await(args.ctx, () -> {
file.close(); fd.close();
return null; return null;
}); });
} }
@ -72,13 +72,13 @@ public class FileLib {
var whence = args.getInt(1); var whence = args.getInt(1);
try { try {
return file.seek(ptr, whence); return fd.seek(ptr, whence);
} }
catch (FilesystemException e) { throw e.toEngineException(); } catch (FilesystemException e) { throw e.toEngineException(); }
}); });
} }
public FileLib(File file) { public FileLib(File fd) {
this.file = file; this.fd = fd;
} }
} }

View File

@ -8,13 +8,14 @@ import me.topchetoeu.jscript.core.engine.Context;
import me.topchetoeu.jscript.core.engine.values.ObjectValue; import me.topchetoeu.jscript.core.engine.values.ObjectValue;
import me.topchetoeu.jscript.core.engine.values.Values; import me.topchetoeu.jscript.core.engine.values.Values;
import me.topchetoeu.jscript.core.exceptions.EngineException; import me.topchetoeu.jscript.core.exceptions.EngineException;
import me.topchetoeu.jscript.utils.filesystem.ActionType;
import me.topchetoeu.jscript.utils.filesystem.EntryType; import me.topchetoeu.jscript.utils.filesystem.EntryType;
import me.topchetoeu.jscript.utils.filesystem.ErrorReason;
import me.topchetoeu.jscript.utils.filesystem.File; import me.topchetoeu.jscript.utils.filesystem.File;
import me.topchetoeu.jscript.utils.filesystem.FileStat; import me.topchetoeu.jscript.utils.filesystem.FileStat;
import me.topchetoeu.jscript.utils.filesystem.Filesystem; import me.topchetoeu.jscript.utils.filesystem.Filesystem;
import me.topchetoeu.jscript.utils.filesystem.FilesystemException; import me.topchetoeu.jscript.utils.filesystem.FilesystemException;
import me.topchetoeu.jscript.utils.filesystem.Mode; import me.topchetoeu.jscript.utils.filesystem.Mode;
import me.topchetoeu.jscript.utils.filesystem.FilesystemException.FSCode;
import me.topchetoeu.jscript.utils.interop.Arguments; import me.topchetoeu.jscript.utils.interop.Arguments;
import me.topchetoeu.jscript.utils.interop.Expose; import me.topchetoeu.jscript.utils.interop.Expose;
import me.topchetoeu.jscript.utils.interop.ExposeField; import me.topchetoeu.jscript.utils.interop.ExposeField;
@ -50,11 +51,10 @@ public class FilesystemLib {
try { try {
if (fs.stat(path).type != EntryType.FILE) { if (fs.stat(path).type != EntryType.FILE) {
throw new FilesystemException(path, FSCode.NOT_FILE); throw new FilesystemException(ErrorReason.DOESNT_EXIST, "Not a file").setAction(ActionType.OPEN);
} }
var file = fs.open(path, _mode); return new FileLib(fs.open(path, _mode));
return new FileLib(file);
} }
catch (FilesystemException e) { throw e.toEngineException(); } catch (FilesystemException e) { throw e.toEngineException(); }
}); });
@ -75,7 +75,7 @@ public class FilesystemLib {
var path = fs.normalize(args.getString(0)); var path = fs.normalize(args.getString(0));
if (fs.stat(path).type != EntryType.FOLDER) { if (fs.stat(path).type != EntryType.FOLDER) {
throw new FilesystemException(path, FSCode.NOT_FOLDER); throw new FilesystemException(ErrorReason.DOESNT_EXIST, "Not a directory").setAction(ActionType.OPEN);
} }
file = fs.open(path, Mode.READ); file = fs.open(path, Mode.READ);

View File

@ -152,6 +152,8 @@ public class Internals {
glob.define(null, "Encoding", false, wp.getNamespace(EncodingLib.class)); glob.define(null, "Encoding", false, wp.getNamespace(EncodingLib.class));
glob.define(null, "Filesystem", false, wp.getNamespace(FilesystemLib.class)); glob.define(null, "Filesystem", false, wp.getNamespace(FilesystemLib.class));
glob.define(false, wp.getConstr(FileLib.class));
glob.define(false, wp.getConstr(DateLib.class)); glob.define(false, wp.getConstr(DateLib.class));
glob.define(false, wp.getConstr(ObjectLib.class)); glob.define(false, wp.getConstr(ObjectLib.class));
glob.define(false, wp.getConstr(FunctionLib.class)); glob.define(false, wp.getConstr(FunctionLib.class));

View File

@ -24,6 +24,7 @@ import me.topchetoeu.jscript.utils.filesystem.MemoryFilesystem;
import me.topchetoeu.jscript.utils.filesystem.Mode; import me.topchetoeu.jscript.utils.filesystem.Mode;
import me.topchetoeu.jscript.utils.filesystem.PhysicalFilesystem; import me.topchetoeu.jscript.utils.filesystem.PhysicalFilesystem;
import me.topchetoeu.jscript.utils.filesystem.RootFilesystem; import me.topchetoeu.jscript.utils.filesystem.RootFilesystem;
import me.topchetoeu.jscript.utils.filesystem.STDFilesystem;
import me.topchetoeu.jscript.utils.modules.ModuleRepo; import me.topchetoeu.jscript.utils.modules.ModuleRepo;
import me.topchetoeu.jscript.utils.permissions.PermissionsManager; import me.topchetoeu.jscript.utils.permissions.PermissionsManager;
import me.topchetoeu.jscript.utils.permissions.PermissionsProvider; import me.topchetoeu.jscript.utils.permissions.PermissionsProvider;
@ -108,6 +109,7 @@ public class JScriptRepl {
var fs = new RootFilesystem(PermissionsProvider.get(environment)); var fs = new RootFilesystem(PermissionsProvider.get(environment));
fs.protocols.put("temp", new MemoryFilesystem(Mode.READ_WRITE)); fs.protocols.put("temp", new MemoryFilesystem(Mode.READ_WRITE));
fs.protocols.put("file", new PhysicalFilesystem(".")); fs.protocols.put("file", new PhysicalFilesystem("."));
fs.protocols.put("std", STDFilesystem.ofStd(System.in, System.out, System.err));
environment.add(PermissionsProvider.ENV_KEY, PermissionsManager.ALL_PERMS); environment.add(PermissionsProvider.ENV_KEY, PermissionsManager.ALL_PERMS);
environment.add(Filesystem.ENV_KEY, fs); environment.add(Filesystem.ENV_KEY, fs);

View File

@ -0,0 +1,28 @@
package me.topchetoeu.jscript.utils.filesystem;
public enum ActionType {
UNKNOWN(0, "An operation performed upon", "An operation was performed upon"),
READ(1, "Reading from", "Read from"),
WRITE(2, "Writting to", "Wrote to"),
SEEK(3, "Seeking in", "Sought in"),
CLOSE(4, "Closing", "Closed"),
STAT(5, "Stat of", "Statted"),
OPEN(6, "Opening", "Opened"),
CREATE(7, "Creating", "Created"),
DELETE(8, "Deleting", "Deleted"),
CLOSE_FS(9, "Closing filesystem", "Closed filesystem");
public final int code;
public final String continuous, past;
public String readable(boolean usePast) {
if (usePast) return past;
else return continuous;
}
private ActionType(int code, String continuous, String past) {
this.code = code;
this.continuous = continuous;
this.past = past;
}
}

View File

@ -0,0 +1,59 @@
package me.topchetoeu.jscript.utils.filesystem;
public abstract class BaseFile<T> implements File {
private T handle;
private Mode mode;
protected final T handle() {
return handle;
}
protected abstract int onRead(byte[] buff);
protected abstract void onWrite(byte[] buff);
protected abstract long onSeek(long offset, int pos);
protected abstract boolean onClose();
@Override public int read(byte[] buff) {
try {
if (handle == null) throw new FilesystemException(ErrorReason.CLOSED);
if (!mode.readable) throw new FilesystemException(ErrorReason.NO_PERMISSION, "File not open for reading.");
return onRead(buff);
}
catch (FilesystemException e) { throw e.setAction(ActionType.READ); }
}
@Override public void write(byte[] buff) {
try {
if (handle == null) throw new FilesystemException(ErrorReason.CLOSED);
if (!mode.writable) throw new FilesystemException(ErrorReason.NO_PERMISSION, "File not open for writting.");
onWrite(buff);
}
catch (FilesystemException e) { throw e.setAction(ActionType.WRITE); }
}
@Override public long seek(long offset, int pos) {
try {
if (handle == null) throw new FilesystemException(ErrorReason.CLOSED);
if (!mode.writable) throw new FilesystemException(ErrorReason.NO_PERMISSION, "File not open for seeking.");
return onSeek(offset, pos);
}
catch (FilesystemException e) { throw e.setAction(ActionType.SEEK); }
}
@Override public boolean close() {
if (handle != null) {
try {
var res = onClose();
handle = null;
mode = Mode.NONE;
return res;
}
catch (FilesystemException e) { throw e.setAction(ActionType.CLOSE); }
}
else return false;
}
public BaseFile(T handle, Mode mode) {
this.mode = mode;
this.handle = handle;
if (mode == Mode.NONE) this.handle = null;
}
}

View File

@ -0,0 +1,23 @@
package me.topchetoeu.jscript.utils.filesystem;
public enum ErrorReason {
UNKNOWN(0, "failed", false),
NO_PERMISSION(1, "is not allowed", false),
CLOSED(1, "that was closed", true),
UNSUPPORTED(2, "is not supported", false),
ILLEGAL_ARGS(3, "with illegal arguments", true),
DOESNT_EXIST(4, "that doesn't exist", true),
ALREADY_EXISTS(5, "that already exists", true),
ILLEGAL_PATH(6, "with illegal path", true),
NO_PARENT(7, "with a missing parent folder", true);
public final int code;
public final boolean usePast;
public final String readable;
private ErrorReason(int code, String readable, boolean usePast) {
this.code = code;
this.readable = readable;
this.usePast = usePast;
}
}

View File

@ -3,51 +3,42 @@ package me.topchetoeu.jscript.utils.filesystem;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.util.Iterator;
import java.util.LinkedList;
import me.topchetoeu.jscript.common.Buffer; import me.topchetoeu.jscript.common.Buffer;
import me.topchetoeu.jscript.utils.LineWriter;
import me.topchetoeu.jscript.utils.filesystem.FilesystemException.FSCode;
import me.topchetoeu.jscript.utils.permissions.Permission;
import me.topchetoeu.jscript.utils.permissions.PermissionsProvider;
public interface File { public interface File {
int read(byte[] buff); default int read(byte[] buff) { throw new FilesystemException(ErrorReason.UNSUPPORTED).setAction(ActionType.READ); }
void write(byte[] buff); default void write(byte[] buff) { throw new FilesystemException(ErrorReason.UNSUPPORTED).setAction(ActionType.WRITE); }
long seek(long offset, int pos); default long seek(long offset, int pos) { throw new FilesystemException(ErrorReason.UNSUPPORTED).setAction(ActionType.SEEK); }
void close(); default boolean close() { return false; }
default File wrap(String name, PermissionsProvider perms, Permission read, Permission write, Permission seek, Permission close) { default byte[] readAll() {
var self = this; var parts = new LinkedList<byte[]>();
var buff = new byte[1024];
var size = 0;
return new File() { while (true) {
@Override public int read(byte[] buff) { var n = read(buff);
if (read != null && perms.hasPermission(read, name)) return self.read(buff); if (n == 0) break;
else throw new FilesystemException(name, FSCode.NO_PERMISSIONS_R);
} parts.add(buff);
@Override public void write(byte[] buff) { size += n;
if (write != null && perms.hasPermission(write, name)) self.write(buff);
else throw new FilesystemException(name, FSCode.NO_PERMISSIONS_RW);
}
@Override public long seek(long offset, int pos) {
if (seek != null && perms.hasPermission(seek, name)) return self.seek(offset, pos);
else throw new FilesystemException(name, FSCode.NO_PERMISSIONS_R);
}
@Override public void close() {
if (close != null && perms.hasPermission(close, name)) self.close();
else throw new FilesystemException(name, FSCode.NO_PERMISSIONS_R);
}
};
} }
buff = new byte[size];
var i = 0;
for (var part : parts) {
System.arraycopy(part, 0, buff, i, part.length);
i += part.length;
}
return buff;
}
default String readToString() { default String readToString() {
long len = seek(0, 2); return new String(readAll());
if (len < 0) return null;
seek(0, 0);
byte[] res = new byte[(int)len];
len = read(res);
return new String(res);
} }
default String readLine() { default String readLine() {
var res = new Buffer(); var res = new Buffer();
@ -66,74 +57,105 @@ public interface File {
return new String(res.data()); return new String(res.data());
} }
public static File ofStream(String name, InputStream str) { public static File ofStream(InputStream str) {
return new File() { return new File() {
@Override public int read(byte[] buff) { @Override public int read(byte[] buff) {
try { try {
return str.read(buff); try { return str.read(buff); }
catch (NullPointerException e) { throw new FilesystemException(ErrorReason.ILLEGAL_ARGS, e.getMessage()); }
catch (IOException e) { throw new FilesystemException(ErrorReason.UNKNOWN, e.getMessage()); }
} }
catch (IOException e) { catch (FilesystemException e) { throw e.setAction(ActionType.READ); }
throw new FilesystemException(name, FSCode.NO_PERMISSIONS_R);
}
}
@Override public void write(byte[] buff) {
throw new FilesystemException(name, FSCode.NO_PERMISSIONS_RW);
}
@Override public long seek(long offset, int pos) {
throw new FilesystemException(name, FSCode.UNSUPPORTED_OPERATION);
}
@Override public void close() {
throw new FilesystemException(name, FSCode.UNSUPPORTED_OPERATION);
} }
}; };
} }
public static File ofStream(String name, OutputStream str) { public static File ofStream(OutputStream str) {
return new File() { return new File() {
@Override public int read(byte[] buff) {
throw new FilesystemException(name, FSCode.NO_PERMISSIONS_R);
}
@Override public void write(byte[] buff) { @Override public void write(byte[] buff) {
try { try {
str.write(buff); try { str.write(buff); }
catch (NullPointerException e) {throw new FilesystemException(ErrorReason.ILLEGAL_ARGS, e.getMessage()); }
catch (IOException e) { throw new FilesystemException(ErrorReason.UNKNOWN, e.getMessage()); }
} }
catch (IOException e) { catch (FilesystemException e) { throw e.setAction(ActionType.WRITE); }
throw new FilesystemException(name, FSCode.NO_PERMISSIONS_RW);
}
}
@Override public long seek(long offset, int pos) {
throw new FilesystemException(name, FSCode.UNSUPPORTED_OPERATION);
}
@Override public void close() {
throw new FilesystemException(name, FSCode.UNSUPPORTED_OPERATION);
} }
}; };
} }
public static File ofLineWriter(String name, LineWriter writer) { public static File ofLineWriter(LineWriter writer) {
var buff = new Buffer(); var buff = new Buffer();
return new File() { return new File() {
@Override public int read(byte[] buff) {
throw new FilesystemException(name, FSCode.NO_PERMISSIONS_R);
}
@Override public void write(byte[] val) { @Override public void write(byte[] val) {
try {
if (val == null) throw new FilesystemException(ErrorReason.ILLEGAL_ARGS, "Given buffer is null.");
for (var b : val) { for (var b : val) {
if (b == '\n') { if (b == '\n') {
try { try {
writer.writeLine(new String(buff.data())); writer.writeLine(new String(buff.data()));
} }
catch (IOException e) { catch (IOException e) {
throw new FilesystemException(name, FSCode.NO_PERMISSIONS_RW); throw new FilesystemException(ErrorReason.UNKNOWN, e.getMessage());
} }
} }
else buff.append(b); else buff.append(b);
} }
} }
@Override public long seek(long offset, int pos) { catch (FilesystemException e) { throw e.setAction(ActionType.WRITE); }
throw new FilesystemException(name, FSCode.UNSUPPORTED_OPERATION);
}
@Override public void close() {
throw new FilesystemException(name, FSCode.UNSUPPORTED_OPERATION);
} }
}; };
} }
public static File ofLineReader(LineReader reader) {
return new File() {
private int offset = 0;
private byte[] prev = new byte[0];
@Override
public int read(byte[] buff) {
try {
if (buff == null) throw new FilesystemException(ErrorReason.ILLEGAL_ARGS, "Given buffer is null.");
var ptr = 0;
while (true) {
if (prev == null) break;
if (offset >= prev.length) {
try {
var line = reader.readLine();
if (line == null) {
prev = null;
break;
}
else prev = (line + "\n").getBytes();
offset = 0;
}
catch (IOException e) {
throw new FilesystemException(ErrorReason.UNKNOWN, e.getMessage());
}
}
if (ptr + prev.length - offset > buff.length) {
var n = buff.length - ptr;
System.arraycopy(prev, offset, buff, ptr, buff.length - ptr);
offset += n;
ptr += n;
break;
}
else {
var n = prev.length - offset;
System.arraycopy(prev, offset, buff, ptr, n);
offset += n;
ptr += n;
}
}
return ptr;
}
catch (FilesystemException e) { throw e.setAction(ActionType.READ); }
}
};
}
public static File ofIterator(Iterator<String> it) {
return ofLineReader(LineReader.ofIterator(it));
}
} }

View File

@ -5,6 +5,9 @@ public class FileStat {
public final EntryType type; public final EntryType type;
public FileStat(Mode mode, EntryType type) { public FileStat(Mode mode, EntryType type) {
if (mode == Mode.NONE) type = EntryType.NONE;
if (type == EntryType.NONE) mode = Mode.NONE;
this.mode = mode; this.mode = mode;
this.type = type; this.type = type;
} }

View File

@ -6,10 +6,11 @@ import me.topchetoeu.jscript.core.engine.values.Symbol;
public interface Filesystem { public interface Filesystem {
public static final Symbol ENV_KEY = Symbol.get("Environment.fs"); public static final Symbol ENV_KEY = Symbol.get("Environment.fs");
String normalize(String... path); default String normalize(String... path) { return Paths.normalize(path); }
File open(String path, Mode mode) throws FilesystemException; default boolean create(String path, EntryType type) { throw new FilesystemException(ErrorReason.UNSUPPORTED).setAction(ActionType.CREATE); }
void create(String path, EntryType type) throws FilesystemException; File open(String path, Mode mode);
FileStat stat(String path) throws FilesystemException; FileStat stat(String path);
void close();
public static Filesystem get(Extensions exts) { public static Filesystem get(Extensions exts) {
return exts.get(ENV_KEY); return exts.get(ENV_KEY);

View File

@ -1,57 +1,90 @@
package me.topchetoeu.jscript.utils.filesystem; package me.topchetoeu.jscript.utils.filesystem;
import java.util.ArrayList;
import me.topchetoeu.jscript.core.engine.values.Values; import me.topchetoeu.jscript.core.engine.values.Values;
import me.topchetoeu.jscript.core.exceptions.EngineException; import me.topchetoeu.jscript.core.exceptions.EngineException;
public class FilesystemException extends RuntimeException { public class FilesystemException extends RuntimeException {
public static enum FSCode { public final ErrorReason reason;
DOESNT_EXIST(0x1), public final String details;
NOT_FILE(0x2), private ActionType action;
NOT_FOLDER(0x3), private EntryType entry = EntryType.FILE;
NO_PERMISSIONS_R(0x4), private String path;
NO_PERMISSIONS_RW(0x5),
FOLDER_NOT_EMPTY(0x6),
ALREADY_EXISTS(0x7),
FOLDER_EXISTS(0x8),
UNSUPPORTED_OPERATION(0x9);
public final int code; public FilesystemException setPath(String path) {
this.path = path;
return this;
}
public FilesystemException setAction(ActionType action) {
if (action == null) action = ActionType.UNKNOWN;
private FSCode(int code) { this.code = code; } this.action = action;
return this;
}
public FilesystemException setEntry(EntryType entry) {
if (entry == null) entry = EntryType.NONE;
this.entry = entry;
return this;
} }
public static final String[] MESSAGES = { public ActionType action() {
"How did we get here?", return action;
"The file or folder '%s' doesn't exist or is inaccessible.",
"'%s' is not a file",
"'%s' is not a folder",
"No permissions to read '%s'",
"No permissions to write '%s'",
"Can't delete '%s', since it is a full folder.",
"'%s' already exists.",
"An unsupported operation was performed on the file '%s'."
};
public final String message, filename;
public final FSCode code;
public FilesystemException(String message, String filename, FSCode code) {
super(code + ": " + String.format(message, filename));
this.message = message;
this.code = code;
this.filename = filename;
} }
public FilesystemException(String filename, FSCode code) { public String path() {
super(code + ": " + String.format(MESSAGES[code.code], filename)); return path;
this.message = MESSAGES[code.code]; }
this.code = code; public EntryType entry() {
this.filename = filename; return entry;
} }
public EngineException toEngineException() { public EngineException toEngineException() {
var res = EngineException.ofError("IOError", getMessage()); var res = EngineException.ofError("IOError", getMessage());
Values.setMember(null, res.value, "code", code);
Values.setMember(null, res.value, "filename", filename.toString()); Values.setMember(null, res.value, "action", action.code);
Values.setMember(null, res.value, "reason", reason.code);
Values.setMember(null, res.value, "path", path);
Values.setMember(null, res.value, "entry", entry.name);
if (details != null) Values.setMember(null, res.value, "details", details);
return res; return res;
} }
@Override public String getMessage() {
var parts = new ArrayList<String>(10);
path = String.join(" ", parts).trim();
if (path.isEmpty()) path = null;
parts.clear();
parts.add(action == null ? "An action performed upon " : action.readable(reason.usePast));
if (entry == EntryType.FILE) parts.add("file");
if (entry == EntryType.FOLDER) parts.add("folder");
if (path != null) parts.add(path);
parts.add(reason.readable);
var msg = String.join(" ", parts);
if (details != null) msg += ": " + details;
return msg;
}
public FilesystemException(ErrorReason type, String details) {
super();
if (type == null) type = ErrorReason.UNKNOWN;
this.details = details;
this.reason = type;
}
public FilesystemException(ErrorReason type) {
this(type, null);
}
public FilesystemException() {
this(null);
}
} }

View File

@ -0,0 +1,32 @@
package me.topchetoeu.jscript.utils.filesystem;
import java.util.HashSet;
import java.util.Set;
public class HandleManager {
private Set<File> files = new HashSet<>();
public File put(File val) {
var handle = new File() {
@Override public int read(byte[] buff) {
return val.read(buff);
}
@Override public void write(byte[] buff) {
val.write(buff);
}
@Override public long seek(long offset, int pos) {
return val.seek(offset, pos);
}
@Override public boolean close() {
return files.remove(this) && val.close();
}
};
files.add(handle);
return handle;
}
public void close() {
while (!files.isEmpty()) {
files.stream().findFirst().get().close();
}
}
}

View File

@ -0,0 +1,16 @@
package me.topchetoeu.jscript.utils.filesystem;
import java.io.IOException;
import java.util.Iterator;
public interface LineReader {
String readLine() throws IOException;
public static LineReader ofIterator(Iterator<String> it) {
return () -> {
if (it.hasNext()) return it.next();
else return null;
};
}
}

View File

@ -1,4 +1,4 @@
package me.topchetoeu.jscript.utils; package me.topchetoeu.jscript.utils.filesystem;
import java.io.IOException; import java.io.IOException;

View File

@ -1,73 +0,0 @@
package me.topchetoeu.jscript.utils.filesystem;
import java.io.IOException;
import java.util.Iterator;
import java.util.stream.Stream;
import me.topchetoeu.jscript.utils.filesystem.FilesystemException.FSCode;
public class ListFile implements File {
private Iterator<String> it;
private String filename;
private byte[] currFile;
private long ptr = 0, start = 0, end = 0;
private void next() {
if (it != null && it.hasNext()) {
start = end;
currFile = (it.next() + "\n").getBytes();
end = start + currFile.length;
}
else {
it = null;
currFile = null;
end = -1;
}
}
@Override
public void close() {
it = null;
currFile = null;
}
@Override
public int read(byte[] buff) {
if (ptr < start) return 0;
if (it == null) return 0;
var i = 0;
while (i < buff.length) {
while (i + ptr >= end) {
next();
if (it == null) return 0;
}
int cpyN = Math.min(currFile.length, buff.length - i);
System.arraycopy(currFile, (int)(ptr + i - start), buff, i, cpyN);
i += cpyN;
}
ptr += i;
return i;
}
@Override
public long seek(long offset, int pos) {
if (pos == 2) throw new FilesystemException(filename, FSCode.UNSUPPORTED_OPERATION);
if (pos == 1) offset += ptr;
return ptr = offset;
}
@Override
public void write(byte[] buff) {
throw new FilesystemException(filename, FSCode.NO_PERMISSIONS_RW);
}
public ListFile(String filename, Stream<String> stream) throws IOException {
this.it = stream.iterator();
this.filename = filename;
}
}

View File

@ -1,62 +1,35 @@
package me.topchetoeu.jscript.utils.filesystem; package me.topchetoeu.jscript.utils.filesystem;
import me.topchetoeu.jscript.common.Buffer; import me.topchetoeu.jscript.common.Buffer;
import me.topchetoeu.jscript.utils.filesystem.FilesystemException.FSCode;
public class MemoryFile implements File { class MemoryFile extends BaseFile<Buffer> {
private int ptr; private int ptr;
private Mode mode;
private Buffer data;
private String filename;
public Buffer data() { return data; } @Override protected int onRead(byte[] buff) {
var res = handle().read(ptr, buff);
@Override
public int read(byte[] buff) {
if (data == null || !mode.readable) throw new FilesystemException(filename, FSCode.NO_PERMISSIONS_R);
var res = data.read(ptr, buff);
ptr += res; ptr += res;
return res; return res;
} }
@Override @Override protected void onWrite(byte[] buff) {
public void write(byte[] buff) { handle().write(ptr, buff);
if (data == null || !mode.writable) throw new FilesystemException(filename, FSCode.NO_PERMISSIONS_RW);
data.write(ptr, buff);
ptr += buff.length; ptr += buff.length;
} }
@Override protected long onSeek(long offset, int pos) {
@Override
public long seek(long offset, int pos) {
if (data == null || !mode.readable) throw new FilesystemException(filename, FSCode.NO_PERMISSIONS_R);
if (pos == 0) ptr = (int)offset; if (pos == 0) ptr = (int)offset;
else if (pos == 1) ptr += (int)offset; else if (pos == 1) ptr += (int)offset;
else if (pos == 2) ptr = data.length() - (int)offset; else if (pos == 2) ptr = handle().length() - (int)offset;
if (ptr < 0) ptr = 0; if (ptr < 0) ptr = 0;
if (ptr > data.length()) ptr = data.length(); if (ptr > handle().length()) ptr = handle().length();
return pos; return pos;
} }
@Override protected boolean onClose() {
@Override
public void close() {
mode = Mode.NONE;
ptr = 0; ptr = 0;
return true;
} }
public MemoryFile(String filename, Buffer buff, Mode mode) { public MemoryFile(Buffer buff, Mode mode) {
this.filename = filename; super(buff, mode);
this.data = buff;
this.mode = mode;
}
public static MemoryFile fromFileList(String filename, java.io.File[] list) {
var res = new StringBuilder();
for (var el : list) res.append(el.getName()).append('\n');
return new MemoryFile(filename, new Buffer(res.toString().getBytes()), Mode.READ);
} }
} }

View File

@ -6,75 +6,79 @@ import java.util.HashSet;
import me.topchetoeu.jscript.common.Buffer; import me.topchetoeu.jscript.common.Buffer;
import me.topchetoeu.jscript.common.Filename; import me.topchetoeu.jscript.common.Filename;
import me.topchetoeu.jscript.utils.filesystem.FilesystemException.FSCode;
public class MemoryFilesystem implements Filesystem { public class MemoryFilesystem implements Filesystem {
public final Mode mode; public final Mode mode;
private HashMap<Path, Buffer> files = new HashMap<>(); private HashMap<Path, Buffer> files = new HashMap<>();
private HashSet<Path> folders = new HashSet<>(); private HashSet<Path> folders = new HashSet<>();
private HandleManager handles = new HandleManager();
private Path realPath(String path) { private Path realPath(String path) {
return Filename.normalize(path); return Filename.normalize(path);
} }
@Override @Override public String normalize(String... path) {
public String normalize(String... path) {
return Paths.normalize(path); return Paths.normalize(path);
} }
@Override public File open(String _path, Mode perms) {
@Override try {
public void create(String _path, EntryType type) {
var path = realPath(_path);
switch (type) {
case FILE:
if (!folders.contains(path.getParent())) throw new FilesystemException(path.toString(), FSCode.DOESNT_EXIST);
if (folders.contains(path) || files.containsKey(path)) throw new FilesystemException(path.toString(), FSCode.ALREADY_EXISTS);
if (folders.contains(path)) throw new FilesystemException(path.toString(), FSCode.ALREADY_EXISTS);
files.put(path, new Buffer());
break;
case FOLDER:
if (!folders.contains(path.getParent())) throw new FilesystemException(_path, FSCode.DOESNT_EXIST);
if (folders.contains(path) || files.containsKey(path)) throw new FilesystemException(path.toString(), FSCode.ALREADY_EXISTS);
folders.add(path);
break;
default:
case NONE:
if (!folders.remove(path) && files.remove(path) == null) throw new FilesystemException(path.toString(), FSCode.DOESNT_EXIST);
}
}
@Override
public File open(String _path, Mode perms) {
var path = realPath(_path); var path = realPath(_path);
var pcount = path.getNameCount(); var pcount = path.getNameCount();
if (files.containsKey(path)) return new MemoryFile(path.toString(), files.get(path), perms); if (files.containsKey(path)) return handles.put(new MemoryFile(files.get(path), perms));
else if (folders.contains(path)) { else if (folders.contains(path)) {
var res = new StringBuilder(); var res = new StringBuilder();
for (var folder : folders) { for (var folder : folders) {
if (pcount + 1 != folder.getNameCount()) continue; if (pcount + 1 != folder.getNameCount()) continue;
if (!folder.startsWith(path)) continue; if (!folder.startsWith(path)) continue;
res.append(folder.toFile().getName()).append('\n'); res.append(folder.toFile().getName()).append('\n');
} }
for (var file : files.keySet()) { for (var file : files.keySet()) {
if (pcount + 1 != file.getNameCount()) continue; if (pcount + 1 != file.getNameCount()) continue;
if (!file.startsWith(path)) continue; if (!file.startsWith(path)) continue;
res.append(file.toFile().getName()).append('\n'); res.append(file.toFile().getName()).append('\n');
} }
return new MemoryFile(path.toString(), new Buffer(res.toString().getBytes()), perms.intersect(Mode.READ));
}
else throw new FilesystemException(path.toString(), FSCode.DOESNT_EXIST);
}
@Override return handles.put(new MemoryFile(new Buffer(res.toString().getBytes()), perms.intersect(Mode.READ)));
public FileStat stat(String _path) { }
else throw new FilesystemException(ErrorReason.DOESNT_EXIST);
}
catch (FilesystemException e) { throw e.setPath(_path).setAction(ActionType.OPEN); }
}
@Override public boolean create(String _path, EntryType type) {
try {
var path = realPath(_path);
switch (type) {
case FILE:
if (!folders.contains(path.getParent())) throw new FilesystemException(ErrorReason.NO_PARENT);
if (folders.contains(path) || files.containsKey(path)) return false;
files.put(path, new Buffer());
return true;
case FOLDER:
if (!folders.contains(path.getParent())) throw new FilesystemException(ErrorReason.NO_PARENT);
if (folders.contains(path) || files.containsKey(path)) return false;
folders.add(path);
return true;
default:
case NONE:
return folders.remove(path) || files.remove(path) != null;
}
}
catch (FilesystemException e) { throw e.setPath(_path).setAction(ActionType.CREATE); }
}
@Override public FileStat stat(String _path) {
var path = realPath(_path); var path = realPath(_path);
if (files.containsKey(path)) return new FileStat(mode, EntryType.FILE); if (files.containsKey(path)) return new FileStat(mode, EntryType.FILE);
else if (folders.contains(path)) return new FileStat(mode, EntryType.FOLDER); else if (folders.contains(path)) return new FileStat(mode, EntryType.FOLDER);
else return new FileStat(Mode.NONE, EntryType.NONE); else return new FileStat(Mode.NONE, EntryType.NONE);
} }
@Override public void close() throws FilesystemException {
handles.close();
}
public MemoryFilesystem put(String path, byte[] data) { public MemoryFilesystem put(String path, byte[] data) {
var _path = realPath(path); var _path = realPath(path);

View File

@ -3,6 +3,7 @@ package me.topchetoeu.jscript.utils.filesystem;
public enum Mode { public enum Mode {
NONE("", false, false), NONE("", false, false),
READ("r", true, false), READ("r", true, false),
WRITE("rw", false, true),
READ_WRITE("rw", true, true); READ_WRITE("rw", true, true);
public final String name; public final String name;
@ -10,9 +11,7 @@ public enum Mode {
public final boolean writable; public final boolean writable;
public Mode intersect(Mode other) { public Mode intersect(Mode other) {
if (this == NONE || other == NONE) return NONE; return of(readable && other.readable, writable && other.writable);
if (this == READ_WRITE && other == READ_WRITE) return READ_WRITE;
return READ;
} }
private Mode(String mode, boolean r, boolean w) { private Mode(String mode, boolean r, boolean w) {
@ -21,9 +20,20 @@ public enum Mode {
this.writable = w; this.writable = w;
} }
public static Mode of(boolean read, boolean write) {
if (read && write) return READ_WRITE;
if (read) return READ;
if (write) return WRITE;
return NONE;
}
public static Mode parse(String mode) { public static Mode parse(String mode) {
switch (mode) { switch (mode.toLowerCase()) {
case "r": return READ; case "r": return READ;
case "w": return WRITE;
case "r+":
case "w+":
case "wr":
case "rw": return READ_WRITE; case "rw": return READ_WRITE;
default: return NONE; default: return NONE;
} }

View File

@ -3,55 +3,33 @@ package me.topchetoeu.jscript.utils.filesystem;
import java.io.FileNotFoundException; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.IOException;
import java.io.RandomAccessFile; import java.io.RandomAccessFile;
import java.nio.file.Path;
import me.topchetoeu.jscript.utils.filesystem.FilesystemException.FSCode; public class PhysicalFile extends BaseFile<RandomAccessFile> {
@Override protected int onRead(byte[] buff) {
public class PhysicalFile implements File { try { return handle().read(buff); }
private String filename; catch (IOException e) { throw new FilesystemException(ErrorReason.NO_PERMISSION).setAction(ActionType.READ); }
private RandomAccessFile file;
private Mode mode;
@Override
public int read(byte[] buff) {
if (file == null || !mode.readable) throw new FilesystemException(filename, FSCode.NO_PERMISSIONS_R);
else try { return file.read(buff); }
catch (IOException e) { throw new FilesystemException(filename, FSCode.NO_PERMISSIONS_R); }
} }
@Override @Override protected void onWrite(byte[] buff) {
public void write(byte[] buff) { try { handle().write(buff); }
if (file == null || !mode.writable) throw new FilesystemException(filename, FSCode.NO_PERMISSIONS_RW); catch (IOException e) { throw new FilesystemException(ErrorReason.NO_PERMISSION).setAction(ActionType.WRITE); }
else try { file.write(buff); }
catch (IOException e) { throw new FilesystemException(filename, FSCode.NO_PERMISSIONS_RW); }
} }
@Override protected long onSeek(long offset, int pos) {
@Override
public long seek(long offset, int pos) {
if (file == null || !mode.readable) throw new FilesystemException(filename, FSCode.NO_PERMISSIONS_R);
try { try {
if (pos == 1) offset += file.getFilePointer(); if (pos == 1) offset += handle().getFilePointer();
else if (pos == 2) offset += file.length(); else if (pos == 2) offset += handle().length();
file.seek(offset); handle().seek(offset);
return offset; return offset;
} }
catch (IOException e) { throw new FilesystemException(filename, FSCode.NO_PERMISSIONS_R); } catch (IOException e) { throw new FilesystemException(ErrorReason.NO_PERMISSION).setAction(ActionType.SEEK); }
} }
@Override protected boolean onClose() {
@Override try { handle().close(); }
public void close() {
if (file == null) return;
try { file.close(); }
catch (IOException e) {} // SHUT catch (IOException e) {} // SHUT
file = null; return true;
mode = Mode.NONE;
} }
public PhysicalFile(String name, String path, Mode mode) throws FileNotFoundException { public PhysicalFile(Path path, Mode mode) throws FileNotFoundException {
this.filename = name; super(new RandomAccessFile(path.toFile(), mode.name), mode);
this.mode = mode;
if (mode == Mode.NONE) file = null;
else try { file = new RandomAccessFile(path, mode.name); }
catch (FileNotFoundException e) { throw new FilesystemException(filename, FSCode.DOESNT_EXIST); }
} }
} }

View File

@ -1,50 +1,48 @@
package me.topchetoeu.jscript.utils.filesystem; package me.topchetoeu.jscript.utils.filesystem;
import java.io.IOException; import java.io.IOException;
import java.nio.file.FileAlreadyExistsException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path; import java.nio.file.Path;
import me.topchetoeu.jscript.utils.filesystem.FilesystemException.FSCode;
public class PhysicalFilesystem implements Filesystem { public class PhysicalFilesystem implements Filesystem {
public final String root; public final String root;
private HandleManager handles = new HandleManager();
private void checkMode(Path path, Mode mode) { private void checkMode(Path path, Mode mode) {
if (!path.startsWith(root)) throw new FilesystemException(path.toString(), FSCode.NO_PERMISSIONS_R); if (!path.startsWith(root)) throw new FilesystemException(ErrorReason.NO_PERMISSION, "Tried to jailbreak the sandbox.");
if (mode.readable && !Files.isReadable(path)) throw new FilesystemException(path.toString(), FSCode.NO_PERMISSIONS_R); if (mode.readable && !Files.isReadable(path)) throw new FilesystemException(ErrorReason.NO_PERMISSION, "No read permissions");
if (mode.writable && !Files.isWritable(path)) throw new FilesystemException(path.toString(), FSCode.NO_PERMISSIONS_RW); if (mode.writable && !Files.isWritable(path)) throw new FilesystemException(ErrorReason.NO_PERMISSION, "No write permissions");
} }
private Path realPath(String path) { private Path realPath(String path) {
return Path.of(Paths.chroot(root, path)); return Path.of(Paths.chroot(root, path));
} }
@Override @Override public String normalize(String... paths) {
public String normalize(String... paths) {
return Paths.normalize(paths); return Paths.normalize(paths);
} }
@Override public File open(String _path, Mode perms) {
@Override try {
public File open(String _path, Mode perms) { var path = realPath(normalize(_path));
_path = normalize(_path);
var path = realPath(_path);
checkMode(path, perms); checkMode(path, perms);
try { try {
if (Files.isDirectory(path)) return new ListFile(_path, Files.list(path).map((v -> v.getFileName().toString()))); if (Files.isDirectory(path)) return handles.put(File.ofIterator(
else return new PhysicalFile(_path, path.toString(), perms); Files.list(path).map(v -> v.getFileName().toString()).iterator()
));
else return handles.put(new PhysicalFile(path, perms));
} }
catch (IOException e) { throw new FilesystemException(path.toString(), FSCode.DOESNT_EXIST); } catch (IOException e) { throw new FilesystemException(ErrorReason.DOESNT_EXIST); }
} }
catch (FilesystemException e) { throw e.setAction(ActionType.OPEN).setPath(_path); }
@Override }
public void create(String _path, EntryType type) { @Override public boolean create(String _path, EntryType type) {
try {
var path = realPath(_path); var path = realPath(_path);
if (type == EntryType.NONE != Files.exists(path)) throw new FilesystemException(path.toString(), FSCode.ALREADY_EXISTS);
try { try {
switch (type) { switch (type) {
case FILE: case FILE:
@ -58,11 +56,14 @@ public class PhysicalFilesystem implements Filesystem {
Files.delete(path); Files.delete(path);
} }
} }
catch (IOException e) { throw new FilesystemException(path.toString(), FSCode.NO_PERMISSIONS_RW); } catch (FileAlreadyExistsException | NoSuchFileException e) { return false; }
catch (IOException e) { throw new FilesystemException(ErrorReason.NO_PARENT); }
} }
catch (FilesystemException e) { throw e.setAction(ActionType.CREATE).setPath(_path); }
@Override return true;
public FileStat stat(String _path) { }
@Override public FileStat stat(String _path) {
var path = realPath(_path); var path = realPath(_path);
if (!Files.exists(path)) return new FileStat(Mode.NONE, EntryType.NONE); if (!Files.exists(path)) return new FileStat(Mode.NONE, EntryType.NONE);
@ -81,6 +82,12 @@ public class PhysicalFilesystem implements Filesystem {
Files.isDirectory(path) ? EntryType.FOLDER : EntryType.FILE Files.isDirectory(path) ? EntryType.FOLDER : EntryType.FILE
); );
} }
@Override public void close() throws FilesystemException {
try {
handles.close();
}
catch (FilesystemException e) { throw e.setAction(ActionType.CLOSE_FS); }
}
public PhysicalFilesystem(String root) { public PhysicalFilesystem(String root) {
this.root = Paths.normalize(Path.of(root).toAbsolutePath().toString()); this.root = Paths.normalize(Path.of(root).toAbsolutePath().toString());

View File

@ -4,7 +4,6 @@ import java.util.HashMap;
import java.util.Map; import java.util.Map;
import me.topchetoeu.jscript.common.Filename; import me.topchetoeu.jscript.common.Filename;
import me.topchetoeu.jscript.utils.filesystem.FilesystemException.FSCode;
import me.topchetoeu.jscript.utils.permissions.Matcher; import me.topchetoeu.jscript.utils.permissions.Matcher;
import me.topchetoeu.jscript.utils.permissions.PermissionsProvider; import me.topchetoeu.jscript.utils.permissions.PermissionsProvider;
@ -20,8 +19,22 @@ public class RootFilesystem implements Filesystem {
} }
private void modeAllowed(String _path, Mode mode) throws FilesystemException { private void modeAllowed(String _path, Mode mode) throws FilesystemException {
if (mode.readable && perms != null && !canRead(_path)) throw new FilesystemException(_path, FSCode.NO_PERMISSIONS_R); if (mode.readable && perms != null && !canRead(_path)) {
if (mode.writable && perms != null && !canWrite(_path)) throw new FilesystemException(_path, FSCode.NO_PERMISSIONS_RW); throw new FilesystemException(ErrorReason.NO_PERMISSION, "No read permissions").setPath(_path);
}
if (mode.writable && perms != null && !canWrite(_path)) {
throw new FilesystemException(ErrorReason.NO_PERMISSION, "No wtrite permissions").setPath(_path);
}
}
private Filesystem getProtocol(Filename filename) {
var protocol = protocols.get(filename.protocol);
if (protocol == null) {
throw new FilesystemException(ErrorReason.DOESNT_EXIST, "The protocol '" + filename.protocol + "' doesn't exist.");
}
return protocol;
} }
@Override public String normalize(String... paths) { @Override public String normalize(String... paths) {
@ -37,30 +50,43 @@ public class RootFilesystem implements Filesystem {
} }
} }
@Override public File open(String path, Mode perms) throws FilesystemException { @Override public File open(String path, Mode perms) throws FilesystemException {
try {
var filename = Filename.parse(path); var filename = Filename.parse(path);
var protocol = protocols.get(filename.protocol); var protocol = getProtocol(filename);
if (protocol == null) throw new FilesystemException(filename.toString(), FSCode.DOESNT_EXIST);
modeAllowed(filename.toString(), perms); modeAllowed(filename.toString(), perms);
return protocol.open(filename.path, perms);
try { return protocol.open(filename.path, perms); }
catch (FilesystemException e) { throw new FilesystemException(filename.toString(), e.code); }
} }
@Override public void create(String path, EntryType type) throws FilesystemException { catch (FilesystemException e) { throw e.setPath(path).setAction(ActionType.OPEN); }
}
@Override public boolean create(String path, EntryType type) throws FilesystemException {
try {
var filename = Filename.parse(path); var filename = Filename.parse(path);
var protocol = protocols.get(filename.protocol); var protocol = getProtocol(filename);
if (protocol == null) throw new FilesystemException(filename.toString(), FSCode.DOESNT_EXIST);
modeAllowed(filename.toString(), Mode.READ_WRITE);
try { protocol.create(filename.path, type); } modeAllowed(filename.toString(), Mode.WRITE);
catch (FilesystemException e) { throw new FilesystemException(filename.toString(), e.code); } return protocol.create(filename.path, type);
}
catch (FilesystemException e) { throw e.setPath(path).setAction(ActionType.CREATE); }
} }
@Override public FileStat stat(String path) throws FilesystemException { @Override public FileStat stat(String path) throws FilesystemException {
try {
var filename = Filename.parse(path); var filename = Filename.parse(path);
var protocol = protocols.get(filename.protocol); var protocol = getProtocol(filename);
if (protocol == null) throw new FilesystemException(filename.toString(), FSCode.DOESNT_EXIST);
try { return protocol.stat(filename.path); } return protocol.stat(filename.path);
catch (FilesystemException e) { throw new FilesystemException(filename.toString(), e.code); } }
catch (FilesystemException e) { throw e.setPath(path).setAction(ActionType.STAT); }
}
@Override public void close() throws FilesystemException {
try {
for (var protocol : protocols.values()) {
protocol.close();
}
protocols.clear();
}
catch (FilesystemException e) { throw e.setAction(ActionType.CLOSE_FS); }
} }
public RootFilesystem(PermissionsProvider perms) { public RootFilesystem(PermissionsProvider perms) {

View File

@ -0,0 +1,42 @@
package me.topchetoeu.jscript.utils.filesystem;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
public class STDFilesystem implements Filesystem {
private final HashMap<String, File> handles = new HashMap<>();
@Override
public String normalize(String... path) {
var res = Paths.normalize(path);
while (res.startsWith("/")) res = res.substring(1);
return res;
}
@Override public File open(String path, Mode mode) {
path = normalize(path);
if (handles.containsKey(path)) return handles.get(path);
else throw new FilesystemException(ErrorReason.DOESNT_EXIST).setAction(ActionType.OPEN).setPath(path);
}
@Override public FileStat stat(String path) {
path = normalize(path);
if (handles.containsKey(path)) return new FileStat(Mode.READ_WRITE, EntryType.FILE);
else return new FileStat(Mode.NONE, EntryType.NONE);
}
@Override public void close() {
handles.clear();
}
public STDFilesystem add(String name, File handle) {
this.handles.put(name, handle);
return this;
}
public static STDFilesystem ofStd(InputStream in, OutputStream out, OutputStream err) {
return new STDFilesystem()
.add("in", File.ofStream(in))
.add("out", File.ofStream(out))
.add("err", File.ofStream(err));
}
}

View File

@ -1,24 +0,0 @@
package me.topchetoeu.jscript.utils.filesystem;
import me.topchetoeu.jscript.core.engine.Extensions;
import me.topchetoeu.jscript.core.engine.values.Symbol;
import me.topchetoeu.jscript.core.exceptions.EngineException;
public class Stdio {
public static final Symbol STDIN = Symbol.get("IO.stdin");
public static final Symbol STDOUT = Symbol.get("IO.stdout");
public static final Symbol STDERR = Symbol.get("IO.stderr");
public static File stdout(Extensions exts) {
if (exts.hasNotNull(STDOUT)) return exts.get(STDOUT);
else throw EngineException.ofError("stdout is not supported.");
}
public static File stdin(Extensions exts) {
if (exts.hasNotNull(STDIN)) return exts.get(STDIN);
else throw EngineException.ofError("stdin is not supported.");
}
public static File stderr(Extensions exts) {
if (exts.hasNotNull(STDERR)) return exts.get(STDERR);
else throw EngineException.ofError("stderr is not supported.");
}
}