diff --git a/src/me/topchetoeu/jscript/filesystem/Filesystem.java b/src/me/topchetoeu/jscript/filesystem/Filesystem.java index 0cfea46..e75a00d 100644 --- a/src/me/topchetoeu/jscript/filesystem/Filesystem.java +++ b/src/me/topchetoeu/jscript/filesystem/Filesystem.java @@ -1,6 +1,8 @@ package me.topchetoeu.jscript.filesystem; public interface Filesystem { + String cwd(String cwd, String path); + String normalize(String path); File open(String path, Mode mode) throws FilesystemException; void create(String path, EntryType type) throws FilesystemException; FileStat stat(String path) throws FilesystemException; diff --git a/src/me/topchetoeu/jscript/filesystem/MemoryFilesystem.java b/src/me/topchetoeu/jscript/filesystem/MemoryFilesystem.java index 3b65ebb..2f2f162 100644 --- a/src/me/topchetoeu/jscript/filesystem/MemoryFilesystem.java +++ b/src/me/topchetoeu/jscript/filesystem/MemoryFilesystem.java @@ -5,6 +5,7 @@ import java.util.HashMap; import java.util.HashSet; import me.topchetoeu.jscript.Buffer; +import me.topchetoeu.jscript.Filename; import me.topchetoeu.jscript.filesystem.FilesystemException.FSCode; public class MemoryFilesystem implements Filesystem { @@ -12,66 +13,76 @@ public class MemoryFilesystem implements Filesystem { private HashMap files = new HashMap<>(); private HashSet folders = new HashSet<>(); - private Path getPath(String name) { - return Path.of("/" + name.replace("\\", "/")).normalize(); + private Path realPath(String path) { + return Filename.normalize(path); } @Override - public void create(String path, EntryType type) { - var _path = getPath(path); + public String normalize(String path) { + return Paths.normalize(path); + } + + @Override + public String cwd(String cwd, String path) { + return Paths.cwd(cwd, path); + } + + @Override + public void create(String _path, EntryType type) { + var path = realPath(_path); switch (type) { case FILE: - if (!folders.contains(_path.getParent())) throw new FilesystemException(path, FSCode.DOESNT_EXIST); - if (folders.contains(_path) || files.containsKey(_path)) throw new FilesystemException(path, FSCode.ALREADY_EXISTS); - if (folders.contains(_path)) throw new FilesystemException(path, FSCode.ALREADY_EXISTS); - files.put(_path, new Buffer()); + 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, FSCode.ALREADY_EXISTS); - folders.add(_path); + 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, FSCode.DOESNT_EXIST); + 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 = getPath(path); - var pcount = _path.getNameCount(); + public File open(String _path, Mode perms) { + var path = realPath(_path); + var pcount = path.getNameCount(); - if (files.containsKey(_path)) return new MemoryFile(path, files.get(_path), perms); - else if (folders.contains(_path)) { + if (files.containsKey(path)) return new MemoryFile(path.toString(), files.get(path), perms); + else if (folders.contains(path)) { var res = new StringBuilder(); for (var folder : folders) { if (pcount + 1 != folder.getNameCount()) continue; - if (!folder.startsWith(_path)) continue; + if (!folder.startsWith(path)) continue; res.append(folder.toFile().getName()).append('\n'); } for (var file : files.keySet()) { if (pcount + 1 != file.getNameCount()) continue; - if (!file.startsWith(_path)) continue; + if (!file.startsWith(path)) continue; res.append(file.toFile().getName()).append('\n'); } - return new MemoryFile(path, new Buffer(res.toString().getBytes()), perms.intersect(Mode.READ)); + return new MemoryFile(path.toString(), new Buffer(res.toString().getBytes()), perms.intersect(Mode.READ)); } - else throw new FilesystemException(path, FSCode.DOESNT_EXIST); + else throw new FilesystemException(path.toString(), FSCode.DOESNT_EXIST); } @Override - public FileStat stat(String path) { - var _path = getPath(path); + public FileStat stat(String _path) { + var path = realPath(_path); - if (files.containsKey(_path)) return new FileStat(mode, EntryType.FILE); - else if (folders.contains(_path)) return new FileStat(mode, EntryType.FOLDER); - else throw new FilesystemException(path, FSCode.DOESNT_EXIST); + if (files.containsKey(path)) return new FileStat(mode, EntryType.FILE); + else if (folders.contains(path)) return new FileStat(mode, EntryType.FOLDER); + else return new FileStat(Mode.NONE, EntryType.NONE); } public MemoryFilesystem put(String path, byte[] data) { - var _path = getPath(path); + var _path = realPath(path); var _curr = "/"; for (var seg : _path) { diff --git a/src/me/topchetoeu/jscript/filesystem/Paths.java b/src/me/topchetoeu/jscript/filesystem/Paths.java new file mode 100644 index 0000000..b59609e --- /dev/null +++ b/src/me/topchetoeu/jscript/filesystem/Paths.java @@ -0,0 +1,51 @@ +package me.topchetoeu.jscript.filesystem; + +import java.util.ArrayList; + +public class Paths { + public static String normalize(String path) { + var parts = path.split("[\\\\/]"); + var res = new ArrayList(); + + for (var part : parts) { + if (part.equals("...")) res.clear(); + else if (part.equals("..")) { + if (res.size() > 0) res.remove(res.size() - 1); + } + else if (!part.equals(".")) res.add(part); + } + + var sb = new StringBuilder(); + + for (var el : res) sb.append("/").append(el); + + return sb.toString(); + } + + public static String chroot(String root, String path) { + return normalize(root) + normalize(path); + } + + public static String cwd(String cwd, String path) { + return normalize(cwd + "/" + path); + } + + public static String filename(String path) { + var i = path.lastIndexOf('/'); + if (i < 0) i = path.lastIndexOf('\\'); + + if (i < 0) return path; + else return path.substring(i + 1); + } + + public static String extension(String path) { + var i = path.lastIndexOf('.'); + + if (i < 0) return ""; + else return path.substring(i + 1); + } + + public static String dir(String path) { + return normalize(path + "/.."); + } +} diff --git a/src/me/topchetoeu/jscript/filesystem/PhysicalFilesystem.java b/src/me/topchetoeu/jscript/filesystem/PhysicalFilesystem.java index 18bdb39..f590ee5 100644 --- a/src/me/topchetoeu/jscript/filesystem/PhysicalFilesystem.java +++ b/src/me/topchetoeu/jscript/filesystem/PhysicalFilesystem.java @@ -1,76 +1,92 @@ package me.topchetoeu.jscript.filesystem; -import java.io.FileNotFoundException; import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import me.topchetoeu.jscript.filesystem.FilesystemException.FSCode; public class PhysicalFilesystem implements Filesystem { - public final Path root; - - private Path getPath(String name) { - var absolutized = Path.of("/" + name.replace("\\", "/")).normalize().toString(); - var res = Path.of(root.toString() + absolutized).normalize(); - return res; - } + public final String root; private void checkMode(Path path, Mode mode) { if (!path.startsWith(root)) throw new FilesystemException(path.toString(), FSCode.NO_PERMISSIONS_R); - if (mode.readable && !path.toFile().canRead()) throw new FilesystemException(path.toString(), FSCode.NO_PERMISSIONS_R); - if (mode.writable && !path.toFile().canWrite()) throw new FilesystemException(path.toString(), FSCode.NO_PERMISSIONS_RW); + var stat = stat(path.toString()); + if (mode.readable && !stat.mode.readable) throw new FilesystemException(path.toString(), FSCode.NO_PERMISSIONS_R); + if (mode.writable && !stat.mode.writable) throw new FilesystemException(path.toString(), FSCode.NO_PERMISSIONS_RW); + } + + private Path realPath(String path) { + return Path.of(Paths.chroot(root, path)); } @Override - public File open(String path, Mode perms) { - var _path = getPath(path); - var f = _path.toFile(); - - checkMode(_path, perms); - - - if (f.isDirectory()) return MemoryFile.fromFileList(path, f.listFiles()); - else try { return new PhysicalFile(path, perms); } - catch (FileNotFoundException e) { throw new FilesystemException(_path.toString(), FSCode.DOESNT_EXIST); } + public String normalize(String path) { + return Paths.normalize(path); } @Override - public void create(String path, EntryType type) { - var _path = getPath(path); - var f = _path.toFile(); + public String cwd(String cwd, String path) { + return Paths.cwd(cwd, path); + } - switch (type) { - case FILE: - try { - if (!f.createNewFile()) throw new FilesystemException(_path.toString(), FSCode.ALREADY_EXISTS); - else break; - } - catch (IOException e) { throw new FilesystemException(_path.toString(), FSCode.NO_PERMISSIONS_RW); } - case FOLDER: - if (!f.mkdir()) throw new FilesystemException(_path.toString(), FSCode.ALREADY_EXISTS); - else break; - case NONE: - default: - if (!f.delete()) throw new FilesystemException(_path.toString(), FSCode.DOESNT_EXIST); - else break; + @Override + public File open(String _path, Mode perms) { + var path = realPath(_path); + + checkMode(path, perms); + + try { + if (Files.isDirectory(path)) return new ListFile(path); + else return new PhysicalFile(path.toString(), perms); } + catch (IOException e) { throw new FilesystemException(path.toString(), FSCode.DOESNT_EXIST); } } @Override - public FileStat stat(String path) { - var _path = getPath(path); - var f = _path.toFile(); + public void create(String _path, EntryType type) { + var path = realPath(_path); - if (!f.exists()) throw new FilesystemException(_path.toString(), FSCode.DOESNT_EXIST); - checkMode(_path, Mode.READ); + if (type == EntryType.NONE != Files.exists(path)) throw new FilesystemException(path.toString(), FSCode.ALREADY_EXISTS); + + try { + switch (type) { + case FILE: + Files.createFile(path); + break; + case FOLDER: + Files.createDirectories(path); + break; + case NONE: + default: + Files.delete(path); + } + } + catch (IOException e) { throw new FilesystemException(path.toString(), FSCode.NO_PERMISSIONS_RW); } + } + + @Override + public FileStat stat(String _path) { + var path = realPath(_path); + + if (!Files.exists(path)) return new FileStat(Mode.NONE, EntryType.NONE); + + var perms = Mode.NONE; + + if (Files.isReadable(path)) { + if (Files.isWritable(path)) perms = Mode.READ_WRITE; + else perms = Mode.READ; + } + + if (perms == Mode.NONE) return new FileStat(Mode.NONE, EntryType.NONE); return new FileStat( - f.canWrite() ? Mode.READ_WRITE : Mode.READ, - f.isFile() ? EntryType.FILE : EntryType.FOLDER + perms, + Files.isDirectory(path) ? EntryType.FOLDER : EntryType.FILE ); } - public PhysicalFilesystem(Path root) { - this.root = root.toAbsolutePath().normalize(); + public PhysicalFilesystem(String root) { + this.root = Paths.normalize(Path.of(root).toAbsolutePath().toString()); } } diff --git a/src/me/topchetoeu/jscript/filesystem/RootFilesystem.java b/src/me/topchetoeu/jscript/filesystem/RootFilesystem.java index 9afd813..74055c6 100644 --- a/src/me/topchetoeu/jscript/filesystem/RootFilesystem.java +++ b/src/me/topchetoeu/jscript/filesystem/RootFilesystem.java @@ -23,6 +23,18 @@ public class RootFilesystem implements Filesystem { if (mode.writable && perms != null && !canWrite(_path)) throw new FilesystemException(_path, FSCode.NO_PERMISSIONS_RW); } + @Override public String normalize(String path) { + var filename = Filename.parse(path); + var protocol = protocols.get(filename.protocol); + if (protocol == null) return filename.toString(); + else return new Filename(filename.protocol, protocol.normalize(filename.path)).toString(); + } + @Override public String cwd(String cwd, String path) { + var filename = Filename.parse(cwd); + var protocol = protocols.get(filename.protocol); + if (protocol == null) return filename.toString(); + else return new Filename(filename.protocol, protocol.cwd(filename.path, path)).toString(); + } @Override public File open(String path, Mode perms) throws FilesystemException { var filename = Filename.parse(path); var protocol = protocols.get(filename.protocol);