Permissions and filesystems #9
@ -1,7 +1,13 @@
|
|||||||
package me.topchetoeu.jscript.filesystem;
|
package me.topchetoeu.jscript.filesystem;
|
||||||
|
|
||||||
public enum EntryType {
|
public enum EntryType {
|
||||||
NONE,
|
NONE("none"),
|
||||||
FILE,
|
FILE("file"),
|
||||||
FOLDER,
|
FOLDER("folder");
|
||||||
|
|
||||||
|
public final String name;
|
||||||
|
|
||||||
|
private EntryType(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,27 +1,39 @@
|
|||||||
package me.topchetoeu.jscript.filesystem;
|
package me.topchetoeu.jscript.filesystem;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public interface File {
|
public interface File {
|
||||||
int read() throws IOException, InterruptedException;
|
int read(byte[] buff);
|
||||||
boolean write(byte val) throws IOException, InterruptedException;
|
void write(byte[] buff);
|
||||||
long tell() throws IOException, InterruptedException;
|
long getPtr();
|
||||||
void seek(long offset, int pos) throws IOException, InterruptedException;
|
void setPtr(long offset, int pos);
|
||||||
void close() throws IOException, InterruptedException;
|
void close();
|
||||||
Permissions perms();
|
Mode mode();
|
||||||
|
|
||||||
default String readToString() throws IOException, InterruptedException {
|
default String readToString() {
|
||||||
seek(0, 2);
|
setPtr(0, 2);
|
||||||
long len = tell();
|
long len = getPtr();
|
||||||
if (len < 0) return null;
|
if (len < 0) return null;
|
||||||
|
|
||||||
seek(0, 0);
|
setPtr(0, 0);
|
||||||
byte[] res = new byte[(int)len];
|
|
||||||
|
|
||||||
for (var i = 0; i < len; i++) {
|
byte[] res = new byte[(int)len];
|
||||||
res[i] = (byte)read();
|
read(res);
|
||||||
}
|
|
||||||
|
|
||||||
return new String(res);
|
return new String(res);
|
||||||
}
|
}
|
||||||
|
default String readLine() {
|
||||||
|
var res = new Buffer(new byte[0]);
|
||||||
|
var buff = new byte[1];
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
if (read(buff) == 0) {
|
||||||
|
if (res.length() == 0) return null;
|
||||||
|
else break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buff[0] == '\n') break;
|
||||||
|
|
||||||
|
res.write(res.length(), buff);
|
||||||
|
}
|
||||||
|
return new String(res.data());
|
||||||
|
}
|
||||||
}
|
}
|
11
src/me/topchetoeu/jscript/filesystem/FileStat.java
Normal file
11
src/me/topchetoeu/jscript/filesystem/FileStat.java
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
package me.topchetoeu.jscript.filesystem;
|
||||||
|
|
||||||
|
public class FileStat {
|
||||||
|
public final Mode mode;
|
||||||
|
public final EntryType type;
|
||||||
|
|
||||||
|
public FileStat(Mode mode, EntryType type) {
|
||||||
|
this.mode = mode;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
}
|
@ -1,10 +1,7 @@
|
|||||||
package me.topchetoeu.jscript.filesystem;
|
package me.topchetoeu.jscript.filesystem;
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public interface Filesystem {
|
public interface Filesystem {
|
||||||
File open(String path) throws IOException, InterruptedException;
|
File open(String path, Mode mode) throws FilesystemException;
|
||||||
boolean mkdir(String path) throws IOException, InterruptedException;
|
void create(String path, EntryType type) throws FilesystemException;
|
||||||
EntryType type(String path) throws IOException, InterruptedException;
|
FileStat stat(String path) throws FilesystemException;
|
||||||
boolean rm(String path) throws IOException, InterruptedException;
|
}
|
||||||
}
|
|
@ -0,0 +1,55 @@
|
|||||||
|
package me.topchetoeu.jscript.filesystem;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.engine.values.Values;
|
||||||
|
import me.topchetoeu.jscript.exceptions.EngineException;
|
||||||
|
|
||||||
|
public class FilesystemException extends RuntimeException {
|
||||||
|
public static enum FSCode {
|
||||||
|
DOESNT_EXIST(0x1),
|
||||||
|
NOT_FILE(0x2),
|
||||||
|
NOT_FOLDER(0x3),
|
||||||
|
NO_PERMISSIONS_R(0x4),
|
||||||
|
NO_PERMISSIONS_RW(0x5),
|
||||||
|
FOLDER_NOT_EMPTY(0x6),
|
||||||
|
ALREADY_EXISTS(0x7),
|
||||||
|
FOLDER_EXISTS(0x8);
|
||||||
|
|
||||||
|
public final int code;
|
||||||
|
|
||||||
|
private FSCode(int code) { this.code = code; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final String[] MESSAGES = {
|
||||||
|
"How did we get here?",
|
||||||
|
"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."
|
||||||
|
};
|
||||||
|
|
||||||
|
public final String message, filename;
|
||||||
|
public final FSCode code;
|
||||||
|
|
||||||
|
public FilesystemException(String message, String filename, FSCode code) {
|
||||||
|
super(code + ": " + message.formatted(filename));
|
||||||
|
this.message = message;
|
||||||
|
this.code = code;
|
||||||
|
this.filename = filename;
|
||||||
|
}
|
||||||
|
public FilesystemException(String filename, FSCode code) {
|
||||||
|
super(code + ": " + MESSAGES[code.code].formatted(filename));
|
||||||
|
this.message = MESSAGES[code.code];
|
||||||
|
this.code = code;
|
||||||
|
this.filename = filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EngineException toEngineException() {
|
||||||
|
var res = EngineException.ofError("IOError", getMessage());
|
||||||
|
Values.setMember(null, res.value, "code", code);
|
||||||
|
Values.setMember(null, res.value, "filename", filename.toString());
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
@ -1,35 +0,0 @@
|
|||||||
package me.topchetoeu.jscript.filesystem;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public class InaccessibleFile implements File {
|
|
||||||
public static final InaccessibleFile INSTANCE = new InaccessibleFile();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int read() throws IOException, InterruptedException {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean write(byte val) throws IOException, InterruptedException {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public long tell() throws IOException, InterruptedException {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void seek(long offset, int pos) throws IOException, InterruptedException { }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void close() throws IOException, InterruptedException { }
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Permissions perms() {
|
|
||||||
return Permissions.NONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
private InaccessibleFile() { }
|
|
||||||
}
|
|
31
src/me/topchetoeu/jscript/filesystem/Mode.java
Normal file
31
src/me/topchetoeu/jscript/filesystem/Mode.java
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package me.topchetoeu.jscript.filesystem;
|
||||||
|
|
||||||
|
public enum Mode {
|
||||||
|
NONE("", false, false),
|
||||||
|
READ("r", true, false),
|
||||||
|
READ_WRITE("rw", true, true);
|
||||||
|
|
||||||
|
public final String name;
|
||||||
|
public final boolean readable;
|
||||||
|
public final boolean writable;
|
||||||
|
|
||||||
|
public Mode intersect(Mode other) {
|
||||||
|
if (this == NONE || other == NONE) return NONE;
|
||||||
|
if (this == READ_WRITE && other == READ_WRITE) return READ_WRITE;
|
||||||
|
return READ;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Mode(String mode, boolean r, boolean w) {
|
||||||
|
this.name = mode;
|
||||||
|
this.readable = r;
|
||||||
|
this.writable = w;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Mode parse(String mode) {
|
||||||
|
switch (mode) {
|
||||||
|
case "r": return READ;
|
||||||
|
case "rw": return READ_WRITE;
|
||||||
|
default: return NONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,17 +0,0 @@
|
|||||||
package me.topchetoeu.jscript.filesystem;
|
|
||||||
|
|
||||||
public enum Permissions {
|
|
||||||
NONE("", false, false),
|
|
||||||
READ("r", true, false),
|
|
||||||
READ_WRITE("rw", true, true);
|
|
||||||
|
|
||||||
public final String readMode;
|
|
||||||
public final boolean readable;
|
|
||||||
public final boolean writable;
|
|
||||||
|
|
||||||
private Permissions(String mode, boolean r, boolean w) {
|
|
||||||
this.readMode = mode;
|
|
||||||
this.readable = r;
|
|
||||||
this.writable = w;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,50 +1,62 @@
|
|||||||
package me.topchetoeu.jscript.filesystem;
|
package me.topchetoeu.jscript.filesystem;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.RandomAccessFile;
|
import java.io.RandomAccessFile;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.filesystem.FilesystemException.FSCode;
|
||||||
|
|
||||||
public class PhysicalFile implements File {
|
public class PhysicalFile implements File {
|
||||||
|
private String filename;
|
||||||
private RandomAccessFile file;
|
private RandomAccessFile file;
|
||||||
private Permissions perms;
|
private Mode perms;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int read() throws IOException, InterruptedException {
|
public int read(byte[] buff) {
|
||||||
if (file == null || !perms.readable) return -1;
|
if (file == null || !perms.readable) throw new FilesystemException(filename, FSCode.NO_PERMISSIONS_R);
|
||||||
else return file.read();
|
else try { return file.read(buff); }
|
||||||
|
catch (IOException e) { throw new FilesystemException(filename, FSCode.NO_PERMISSIONS_R); }
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void write(byte[] buff) {
|
||||||
|
if (file == null || !perms.writable) throw new FilesystemException(filename, FSCode.NO_PERMISSIONS_RW);
|
||||||
|
else try { file.write(buff); }
|
||||||
|
catch (IOException e) { throw new FilesystemException(filename, FSCode.NO_PERMISSIONS_RW); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean write(byte val) throws IOException, InterruptedException {
|
public long getPtr() {
|
||||||
if (file == null || !perms.writable) return false;
|
if (file == null || !perms.readable) throw new FilesystemException(filename, FSCode.NO_PERMISSIONS_R);
|
||||||
file.write(val);
|
else try { return file.getFilePointer(); }
|
||||||
return true;
|
catch (IOException e) { throw new FilesystemException(filename, FSCode.NO_PERMISSIONS_R); }
|
||||||
|
}
|
||||||
|
@Override
|
||||||
|
public void setPtr(long offset, int pos) {
|
||||||
|
if (file == null || !perms.readable) throw new FilesystemException(filename, FSCode.NO_PERMISSIONS_R);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (pos == 1) pos += file.getFilePointer();
|
||||||
|
else if (pos == 2) pos += file.length();
|
||||||
|
file.seek(pos);
|
||||||
|
}
|
||||||
|
catch (IOException e) { throw new FilesystemException(filename, FSCode.NO_PERMISSIONS_R); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long tell() throws IOException, InterruptedException {
|
public void close() {
|
||||||
if (file == null) return 0;
|
|
||||||
return file.getFilePointer();
|
|
||||||
}
|
|
||||||
@Override
|
|
||||||
public void seek(long offset, int pos) throws IOException, InterruptedException {
|
|
||||||
if (file == null) return;
|
if (file == null) return;
|
||||||
if (pos == 0) file.seek(pos);
|
try { file.close(); }
|
||||||
else if (pos == 1) file.seek(file.getFilePointer() + pos);
|
catch (IOException e) {} // SHUT
|
||||||
else if (pos == 2) file.seek(file.length() + pos);
|
file = null;
|
||||||
|
perms = Mode.NONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException, InterruptedException {
|
public Mode mode() { return perms; }
|
||||||
if (file == null) return;
|
|
||||||
file.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
public PhysicalFile(String path, Mode mode) throws FileNotFoundException {
|
||||||
public Permissions perms() { return perms; }
|
if (mode == Mode.NONE) file = null;
|
||||||
|
else try { file = new RandomAccessFile(path, mode.name); }
|
||||||
public PhysicalFile(String path, Permissions mode) throws IOException {
|
catch (FileNotFoundException e) { throw new FilesystemException(filename, FSCode.DOESNT_EXIST); }
|
||||||
if (mode == Permissions.NONE) file = null;
|
|
||||||
else file = new RandomAccessFile(path, mode.readMode);
|
|
||||||
|
|
||||||
perms = mode;
|
perms = mode;
|
||||||
}
|
}
|
||||||
|
@ -1,74 +1,75 @@
|
|||||||
package me.topchetoeu.jscript.filesystem;
|
package me.topchetoeu.jscript.filesystem;
|
||||||
|
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
import me.topchetoeu.jscript.filesystem.FilesystemException.FSCode;
|
||||||
|
|
||||||
public class PhysicalFilesystem implements Filesystem {
|
public class PhysicalFilesystem implements Filesystem {
|
||||||
public final Path root;
|
public final Path root;
|
||||||
|
|
||||||
private Permissions getPerms(Path path) {
|
|
||||||
var file = path.toFile();
|
|
||||||
if (!path.startsWith(root)) return Permissions.NONE;
|
|
||||||
if (file.canRead() && file.canWrite()) return Permissions.READ_WRITE;
|
|
||||||
if (file.canRead()) return Permissions.READ;
|
|
||||||
|
|
||||||
return Permissions.NONE;
|
|
||||||
}
|
|
||||||
private Path getPath(String name) {
|
private Path getPath(String name) {
|
||||||
return root.resolve(name);
|
return root.resolve(name.replace("\\", "/")).normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public File open(String path) throws IOException, InterruptedException {
|
public File open(String path, Mode perms) {
|
||||||
var _path = root.resolve(path);
|
var _path = getPath(path);
|
||||||
|
|
||||||
var perms = getPerms(_path);
|
|
||||||
if (perms == Permissions.NONE) return InaccessibleFile.INSTANCE;
|
|
||||||
|
|
||||||
var f = _path.toFile();
|
var f = _path.toFile();
|
||||||
|
|
||||||
if (f.isDirectory()) {
|
checkMode(_path, perms);
|
||||||
var res = new StringBuilder();
|
|
||||||
|
|
||||||
for (var child : f.listFiles()) res.append(child.toString()).append('\n');
|
|
||||||
|
|
||||||
return new MemoryFile(res.toString().getBytes(), Permissions.READ);
|
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); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void create(String path, EntryType type) {
|
||||||
|
var _path = getPath(path);
|
||||||
|
var f = _path.toFile();
|
||||||
|
|
||||||
|
checkMode(_path, Mode.READ_WRITE);
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
else return new PhysicalFile(path, perms);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean mkdir(String path) throws IOException, InterruptedException {
|
public FileStat stat(String path) {
|
||||||
var _path = getPath(path);
|
var _path = getPath(path);
|
||||||
var perms = getPerms(_path);
|
|
||||||
var f = _path.toFile();
|
var f = _path.toFile();
|
||||||
|
|
||||||
if (!perms.writable) return false;
|
if (f.exists()) throw new FilesystemException(_path.toString(), FSCode.DOESNT_EXIST);
|
||||||
else return f.mkdir();
|
checkMode(_path, Mode.READ);
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
return new FileStat(
|
||||||
public EntryType type(String path) throws IOException, InterruptedException {
|
f.canWrite() ? Mode.READ_WRITE : Mode.READ,
|
||||||
var _path = getPath(path);
|
f.isFile() ? EntryType.FILE : EntryType.FOLDER
|
||||||
var perms = getPerms(_path);
|
);
|
||||||
var f = _path.toFile();
|
|
||||||
|
|
||||||
if (perms == Permissions.NONE) return EntryType.NONE;
|
|
||||||
else if (f.isFile()) return EntryType.FILE;
|
|
||||||
else return EntryType.FOLDER;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean rm(String path) throws IOException, InterruptedException {
|
|
||||||
var _path = getPath(path);
|
|
||||||
var perms = getPerms(_path);
|
|
||||||
var f = _path.toFile();
|
|
||||||
|
|
||||||
if (!perms.writable) return false;
|
|
||||||
else return f.delete();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public PhysicalFilesystem(Path root) {
|
public PhysicalFilesystem(Path root) {
|
||||||
this.root = root;
|
this.root = root.toAbsolutePath().normalize();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user