From f52f47cdb4bdcaafe5a2ec5874923b5c3bb110f6 Mon Sep 17 00:00:00 2001 From: TopchetoEU <36534413+TopchetoEU@users.noreply.github.com> Date: Sat, 25 Nov 2023 19:36:18 +0200 Subject: [PATCH] feat: properly implement filesystems --- src/me/topchetoeu/jscript/Main.java | 9 ++-- .../jscript/engine/Environment.java | 16 ++++-- .../filesystem/PhysicalFilesystem.java | 2 +- .../jscript/filesystem/RootFilesystem.java | 27 +++++----- src/me/topchetoeu/jscript/js/lib.d.ts | 2 +- .../topchetoeu/jscript/lib/FilesystemLib.java | 54 ++++++++++--------- src/me/topchetoeu/jscript/lib/Internals.java | 1 + .../permissions/PermissionsManager.java | 21 +++----- .../permissions/PermissionsProvider.java | 13 +++++ 9 files changed, 81 insertions(+), 64 deletions(-) create mode 100644 src/me/topchetoeu/jscript/permissions/PermissionsProvider.java diff --git a/src/me/topchetoeu/jscript/Main.java b/src/me/topchetoeu/jscript/Main.java index 818b328..452660a 100644 --- a/src/me/topchetoeu/jscript/Main.java +++ b/src/me/topchetoeu/jscript/Main.java @@ -18,8 +18,7 @@ import me.topchetoeu.jscript.exceptions.InterruptException; import me.topchetoeu.jscript.exceptions.SyntaxException; import me.topchetoeu.jscript.filesystem.MemoryFilesystem; import me.topchetoeu.jscript.filesystem.Mode; -import me.topchetoeu.jscript.filesystem.RootFilesystem; -import me.topchetoeu.jscript.lib.FilesystemLib; +import me.topchetoeu.jscript.filesystem.PhysicalFilesystem; import me.topchetoeu.jscript.lib.Internals; public class Main { @@ -117,10 +116,8 @@ public class Main { } }); - var fs = new RootFilesystem(null); - fs.protocols.put("file", new MemoryFilesystem(Mode.READ_WRITE)); - - environment.global.define((Context)null, "fs", false, new FilesystemLib(fs)); + environment.filesystem.protocols.put("temp", new MemoryFilesystem(Mode.READ_WRITE)); + environment.filesystem.protocols.put("file", new PhysicalFilesystem(Path.of(".").toAbsolutePath())); } private static void initEngine() { debugServer.targets.put("target", (ws, req) -> new SimpleDebugger(ws, engine)); diff --git a/src/me/topchetoeu/jscript/engine/Environment.java b/src/me/topchetoeu/jscript/engine/Environment.java index 8bca1de..49d67c5 100644 --- a/src/me/topchetoeu/jscript/engine/Environment.java +++ b/src/me/topchetoeu/jscript/engine/Environment.java @@ -8,13 +8,15 @@ import me.topchetoeu.jscript.engine.values.NativeFunction; import me.topchetoeu.jscript.engine.values.ObjectValue; import me.topchetoeu.jscript.engine.values.Symbol; import me.topchetoeu.jscript.exceptions.EngineException; +import me.topchetoeu.jscript.filesystem.RootFilesystem; import me.topchetoeu.jscript.interop.Native; import me.topchetoeu.jscript.interop.NativeGetter; import me.topchetoeu.jscript.interop.NativeSetter; import me.topchetoeu.jscript.interop.NativeWrapperProvider; -import me.topchetoeu.jscript.permissions.PermissionsManager; +import me.topchetoeu.jscript.permissions.Permission; +import me.topchetoeu.jscript.permissions.PermissionsProvider; -public class Environment { +public class Environment implements PermissionsProvider { private HashMap prototypes = new HashMap<>(); public final Data data = new Data(); @@ -22,7 +24,8 @@ public class Environment { public GlobalScope global; public WrappersProvider wrappers; - public PermissionsManager permissions; + public PermissionsProvider permissions = null; + public final RootFilesystem filesystem = new RootFilesystem(this); private static int nextId = 0; @@ -74,6 +77,13 @@ public class Environment { return res; } + @Override public boolean hasPermission(Permission perm, char delim) { + return permissions == null || permissions.hasPermission(perm, delim); + } + @Override public boolean hasPermission(Permission perm) { + return permissions == null || permissions.hasPermission(perm); + } + public Context context(Engine engine) { return new Context(engine).pushEnv(this); } diff --git a/src/me/topchetoeu/jscript/filesystem/PhysicalFilesystem.java b/src/me/topchetoeu/jscript/filesystem/PhysicalFilesystem.java index a694520..5a75929 100644 --- a/src/me/topchetoeu/jscript/filesystem/PhysicalFilesystem.java +++ b/src/me/topchetoeu/jscript/filesystem/PhysicalFilesystem.java @@ -60,7 +60,7 @@ public class PhysicalFilesystem implements Filesystem { var _path = getPath(path); var f = _path.toFile(); - if (f.exists()) throw new FilesystemException(_path.toString(), FSCode.DOESNT_EXIST); + if (!f.exists()) throw new FilesystemException(_path.toString(), FSCode.DOESNT_EXIST); checkMode(_path, Mode.READ); return new FileStat( diff --git a/src/me/topchetoeu/jscript/filesystem/RootFilesystem.java b/src/me/topchetoeu/jscript/filesystem/RootFilesystem.java index ba9296a..9afd813 100644 --- a/src/me/topchetoeu/jscript/filesystem/RootFilesystem.java +++ b/src/me/topchetoeu/jscript/filesystem/RootFilesystem.java @@ -5,26 +5,25 @@ import java.util.Map; import me.topchetoeu.jscript.Filename; import me.topchetoeu.jscript.filesystem.FilesystemException.FSCode; -import me.topchetoeu.jscript.permissions.PermissionsManager; +import me.topchetoeu.jscript.permissions.PermissionsProvider; public class RootFilesystem implements Filesystem { public final Map protocols = new HashMap<>(); - public final PermissionsManager perms; + public final PermissionsProvider perms; - private boolean canRead(PermissionsManager perms, String _path) { - return perms.has("jscript.file.read:" + _path, '/'); + private boolean canRead(String _path) { + return perms.hasPermission("jscript.file.read:" + _path, '/'); } - private boolean canWrite(PermissionsManager perms, String _path) { - return perms.has("jscript.file.write:" + _path, '/'); + private boolean canWrite(String _path) { + return perms.hasPermission("jscript.file.write:" + _path, '/'); } private void modeAllowed(String _path, Mode mode) throws FilesystemException { - if (mode.readable && perms != null && !canRead(perms, _path)) throw new FilesystemException(_path, FSCode.NO_PERMISSIONS_R); - if (mode.writable && perms != null && !canWrite(perms, _path)) throw new FilesystemException(_path, FSCode.NO_PERMISSIONS_RW); + if (mode.readable && perms != null && !canRead(_path)) throw new FilesystemException(_path, FSCode.NO_PERMISSIONS_R); + if (mode.writable && perms != null && !canWrite(_path)) throw new FilesystemException(_path, FSCode.NO_PERMISSIONS_RW); } - @Override - public File open(String path, Mode perms) throws FilesystemException { + @Override public File open(String path, Mode perms) throws FilesystemException { var filename = Filename.parse(path); var protocol = protocols.get(filename.protocol); if (protocol == null) throw new FilesystemException(filename.toString(), FSCode.DOESNT_EXIST); @@ -33,8 +32,7 @@ public class RootFilesystem implements Filesystem { 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 { + @Override public void create(String path, EntryType type) throws FilesystemException { var filename = Filename.parse(path); var protocol = protocols.get(filename.protocol); if (protocol == null) throw new FilesystemException(filename.toString(), FSCode.DOESNT_EXIST); @@ -43,8 +41,7 @@ public class RootFilesystem implements Filesystem { try { protocol.create(filename.path, type); } catch (FilesystemException e) { throw new FilesystemException(filename.toString(), e.code); } } - @Override - public FileStat stat(String path) throws FilesystemException { + @Override public FileStat stat(String path) throws FilesystemException { var filename = Filename.parse(path); var protocol = protocols.get(filename.protocol); if (protocol == null) throw new FilesystemException(filename.toString(), FSCode.DOESNT_EXIST); @@ -54,7 +51,7 @@ public class RootFilesystem implements Filesystem { catch (FilesystemException e) { throw new FilesystemException(filename.toString(), e.code); } } - public RootFilesystem(PermissionsManager perms) { + public RootFilesystem(PermissionsProvider perms) { this.perms = perms; } } diff --git a/src/me/topchetoeu/jscript/js/lib.d.ts b/src/me/topchetoeu/jscript/js/lib.d.ts index 141e7cf..a128ca4 100644 --- a/src/me/topchetoeu/jscript/js/lib.d.ts +++ b/src/me/topchetoeu/jscript/js/lib.d.ts @@ -538,7 +538,7 @@ declare var Symbol: SymbolConstructor; declare var Promise: PromiseConstructor; declare var Math: MathObject; declare var Encoding: Encoding; -declare var fs: Filesystem; +declare var Filesystem: Filesystem; declare var Error: ErrorConstructor; declare var RangeError: RangeErrorConstructor; diff --git a/src/me/topchetoeu/jscript/lib/FilesystemLib.java b/src/me/topchetoeu/jscript/lib/FilesystemLib.java index 8a9aaab..98a14d3 100644 --- a/src/me/topchetoeu/jscript/lib/FilesystemLib.java +++ b/src/me/topchetoeu/jscript/lib/FilesystemLib.java @@ -8,36 +8,44 @@ import me.topchetoeu.jscript.Filename; import me.topchetoeu.jscript.engine.Context; import me.topchetoeu.jscript.engine.values.ObjectValue; import me.topchetoeu.jscript.engine.values.Values; +import me.topchetoeu.jscript.exceptions.EngineException; import me.topchetoeu.jscript.filesystem.EntryType; import me.topchetoeu.jscript.filesystem.File; import me.topchetoeu.jscript.filesystem.FileStat; +import me.topchetoeu.jscript.filesystem.Filesystem; import me.topchetoeu.jscript.filesystem.FilesystemException; import me.topchetoeu.jscript.filesystem.Mode; -import me.topchetoeu.jscript.filesystem.RootFilesystem; import me.topchetoeu.jscript.filesystem.FilesystemException.FSCode; import me.topchetoeu.jscript.interop.Native; @Native("Filesystem") public class FilesystemLib { - public final RootFilesystem fs; + private static Filesystem fs(Context ctx) { + var env = ctx.environment(); + if (env != null) { + var fs = ctx.environment().filesystem; + if (fs != null) return fs; + } + throw EngineException.ofError("Current environment doesn't have a file system."); + } - @Native public PromiseLib open(Context ctx, String _path, String mode) { + @Native public static PromiseLib open(Context ctx, String _path, String mode) { var filename = Filename.parse(_path); var _mode = Mode.parse(mode); return PromiseLib.await(ctx, () -> { try { - if (fs.stat(filename.path).type != EntryType.FILE) { + if (fs(ctx).stat(filename.path).type != EntryType.FILE) { throw new FilesystemException(filename.toString(), FSCode.NOT_FILE); } - var file = fs.open(filename.path, _mode); + var file = fs(ctx).open(filename.path, _mode); return new FileLib(file); } catch (FilesystemException e) { throw e.toEngineException(); } }); } - @Native public ObjectValue ls(Context ctx, String _path) throws IOException { + @Native public static ObjectValue ls(Context ctx, String _path) throws IOException { var filename = Filename.parse(_path); return Values.toJSAsyncIterator(ctx, new Iterator<>() { @@ -49,11 +57,11 @@ public class FilesystemLib { if (done) return; if (!failed) { if (file == null) { - if (fs.stat(filename.path).type != EntryType.FOLDER) { + if (fs(ctx).stat(filename.path).type != EntryType.FOLDER) { throw new FilesystemException(filename.toString(), FSCode.NOT_FOLDER); } - file = fs.open(filename.path, Mode.READ); + file = fs(ctx).open(filename.path, Mode.READ); } if (nextLine == null) { @@ -90,29 +98,29 @@ public class FilesystemLib { } }); } - @Native public PromiseLib mkdir(Context ctx, String _path) throws IOException { + @Native public static PromiseLib mkdir(Context ctx, String _path) throws IOException { return PromiseLib.await(ctx, () -> { try { - fs.create(Filename.parse(_path).toString(), EntryType.FOLDER); + fs(ctx).create(Filename.parse(_path).toString(), EntryType.FOLDER); return null; } catch (FilesystemException e) { throw e.toEngineException(); } }); } - @Native public PromiseLib mkfile(Context ctx, String _path) throws IOException { + @Native public static PromiseLib mkfile(Context ctx, String _path) throws IOException { return PromiseLib.await(ctx, () -> { try { - fs.create(Filename.parse(_path).toString(), EntryType.FILE); + fs(ctx).create(Filename.parse(_path).toString(), EntryType.FILE); return null; } catch (FilesystemException e) { throw e.toEngineException(); } }); } - @Native public PromiseLib rm(Context ctx, String _path, boolean recursive) throws IOException { + @Native public static PromiseLib rm(Context ctx, String _path, boolean recursive) throws IOException { return PromiseLib.await(ctx, () -> { try { - if (!recursive) fs.create(Filename.parse(_path).toString(), EntryType.NONE); + if (!recursive) fs(ctx).create(Filename.parse(_path).toString(), EntryType.NONE); else { var stack = new Stack(); stack.push(_path); @@ -121,13 +129,13 @@ public class FilesystemLib { var path = Filename.parse(stack.pop()).toString(); FileStat stat; - try { stat = fs.stat(path); } + try { stat = fs(ctx).stat(path); } catch (FilesystemException e) { continue; } if (stat.type == EntryType.FOLDER) { - for (var el : fs.open(path, Mode.READ).readToString().split("\n")) stack.push(el); + for (var el : fs(ctx).open(path, Mode.READ).readToString().split("\n")) stack.push(el); } - else fs.create(path, EntryType.NONE); + else fs(ctx).create(path, EntryType.NONE); } } return null; @@ -135,10 +143,10 @@ public class FilesystemLib { catch (FilesystemException e) { throw e.toEngineException(); } }); } - @Native public PromiseLib stat(Context ctx, String _path) throws IOException { + @Native public static PromiseLib stat(Context ctx, String _path) throws IOException { return PromiseLib.await(ctx, () -> { try { - var stat = fs.stat(_path); + var stat = fs(ctx).stat(_path); var res = new ObjectValue(); res.defineProperty(ctx, "type", stat.type.name); @@ -148,14 +156,10 @@ public class FilesystemLib { catch (FilesystemException e) { throw e.toEngineException(); } }); } - @Native public PromiseLib exists(Context ctx, String _path) throws IOException { + @Native public static PromiseLib exists(Context ctx, String _path) throws IOException { return PromiseLib.await(ctx, () -> { - try { fs.stat(_path); return true; } + try { fs(ctx).stat(_path); return true; } catch (FilesystemException e) { return false; } }); } - - public FilesystemLib(RootFilesystem fs) { - this.fs = fs; - } } diff --git a/src/me/topchetoeu/jscript/lib/Internals.java b/src/me/topchetoeu/jscript/lib/Internals.java index 1409289..d9473a5 100644 --- a/src/me/topchetoeu/jscript/lib/Internals.java +++ b/src/me/topchetoeu/jscript/lib/Internals.java @@ -120,6 +120,7 @@ public class Internals { glob.define(null, "Math", false, wp.getNamespace(MathLib.class)); glob.define(null, "JSON", false, wp.getNamespace(JSONLib.class)); glob.define(null, "Encoding", false, wp.getNamespace(EncodingLib.class)); + glob.define(null, "Filesystem", false, wp.getNamespace(FilesystemLib.class)); glob.define(null, "Date", false, wp.getConstr(DateLib.class)); glob.define(null, "Object", false, wp.getConstr(ObjectLib.class)); diff --git a/src/me/topchetoeu/jscript/permissions/PermissionsManager.java b/src/me/topchetoeu/jscript/permissions/PermissionsManager.java index 1505fb8..bea8355 100644 --- a/src/me/topchetoeu/jscript/permissions/PermissionsManager.java +++ b/src/me/topchetoeu/jscript/permissions/PermissionsManager.java @@ -2,38 +2,33 @@ package me.topchetoeu.jscript.permissions; import java.util.ArrayList; -public class PermissionsManager { - public static final PermissionsManager ALL_PERMS = new PermissionsManager().add(new Permission("**")); +public class PermissionsManager implements PermissionsProvider { + public static final PermissionsProvider ALL_PERMS = new PermissionsManager().add(new Permission("**")); public final ArrayList allowed = new ArrayList<>(); public final ArrayList denied = new ArrayList<>(); - public PermissionsManager add(Permission perm) { + public PermissionsProvider add(Permission perm) { allowed.add(perm); return this; } - public PermissionsManager add(String perm) { + public PermissionsProvider add(String perm) { allowed.add(new Permission(perm)); return this; } - public boolean has(Permission perm, char delim) { + @Override + public boolean hasPermission(Permission perm, char delim) { for (var el : denied) if (el.match(perm, delim)) return false; for (var el : allowed) if (el.match(perm, delim)) return true; return false; } - public boolean has(Permission perm) { + @Override + public boolean hasPermission(Permission perm) { for (var el : denied) if (el.match(perm)) return false; for (var el : allowed) if (el.match(perm)) return true; return false; } - - public boolean has(String perm, char delim) { - return has(new Permission(perm), delim); - } - public boolean has(String perm) { - return has(new Permission(perm)); - } } diff --git a/src/me/topchetoeu/jscript/permissions/PermissionsProvider.java b/src/me/topchetoeu/jscript/permissions/PermissionsProvider.java new file mode 100644 index 0000000..73c5ee6 --- /dev/null +++ b/src/me/topchetoeu/jscript/permissions/PermissionsProvider.java @@ -0,0 +1,13 @@ +package me.topchetoeu.jscript.permissions; + +public interface PermissionsProvider { + boolean hasPermission(Permission perm, char delim); + boolean hasPermission(Permission perm); + + default boolean hasPermission(String perm, char delim) { + return hasPermission(new Permission(perm), delim); + } + default boolean hasPermission(String perm) { + return hasPermission(new Permission(perm)); + } +} \ No newline at end of file