Permissions and filesystems #9

Merged
TopchetoEU merged 36 commits from TopchetoEU/perms-and-fs into master 2023-11-25 18:10:59 +00:00
4 changed files with 227 additions and 24 deletions
Showing only changes of commit 55e3d46bc2 - Show all commits

View File

@ -0,0 +1,41 @@
package me.topchetoeu.jscript.filesystem;
public class Buffer {
private byte[] data;
private int length;
public void write(int i, byte[] val) {
if (i + val.length > data.length) {
var newCap = i + val.length + 1;
if (newCap < data.length * 2) newCap = data.length * 2;
var tmp = new byte[newCap];
System.arraycopy(this.data, 0, tmp, 0, length);
this.data = tmp;
}
System.arraycopy(val, 0, data, i, val.length);
if (i + val.length > length) length = i + val.length;
}
public int read(int i, byte[] buff) {
int n = buff.length;
if (i + n > length) n = length - i;
System.arraycopy(data, i, buff, 0, n);
return n;
}
public byte[] data() {
var res = new byte[length];
System.arraycopy(this.data, 0, res, 0, length);
return res;
}
public int length() {
return length;
}
public Buffer(byte[] data) {
this.data = new byte[data.length];
this.length = data.length;
System.arraycopy(data, 0, this.data, 0, data.length);
}
}

View File

@ -1,53 +1,66 @@
package me.topchetoeu.jscript.filesystem;
import java.io.IOException;
import me.topchetoeu.jscript.filesystem.FilesystemException.FSCode;
public class MemoryFile implements File {
private int ptr;
private Permissions mode;
public final byte[] data;
private Mode mode;
private Buffer data;
private String filename;
public Buffer data() { return data; }
@Override
public int read() throws IOException, InterruptedException {
if (data == null || !mode.readable || ptr >= data.length) return -1;
return data[ptr++];
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;
return res;
}
@Override
public void write(byte[] buff) {
if (data == null || !mode.writable) throw new FilesystemException(filename, FSCode.NO_PERMISSIONS_RW);
data.write(ptr, buff);
ptr += buff.length;
}
@Override
public boolean write(byte val) throws IOException, InterruptedException {
if (data == null || !mode.writable || ptr >= data.length) return false;
data[ptr++] = val;
return true;
}
@Override
public long tell() throws IOException, InterruptedException {
public long getPtr() {
if (data == null || !mode.readable) throw new FilesystemException(filename, FSCode.NO_PERMISSIONS_R);
return ptr;
}
@Override
public void seek(long offset, int pos) throws IOException, InterruptedException {
if (data == null) return;
public void setPtr(long offset, int pos) {
if (data == null || !mode.readable) throw new FilesystemException(filename, FSCode.NO_PERMISSIONS_R);
if (pos == 0) ptr = (int)offset;
else if (pos == 1) ptr += (int)offset;
else if (pos == 2) ptr = data.length - (int)offset;
else if (pos == 2) ptr = data.length() - (int)offset;
}
@Override
public void close() throws IOException, InterruptedException {
mode = null;
public void close() {
mode = Mode.NONE;
ptr = 0;
}
@Override
public Permissions perms() {
if (data == null) return Permissions.NONE;
public Mode mode() {
if (data == null) return Mode.NONE;
return mode;
}
public MemoryFile(byte[] buff, Permissions mode) {
public MemoryFile(String filename, Buffer buff, Mode mode) {
this.filename = filename;
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

@ -0,0 +1,89 @@
package me.topchetoeu.jscript.filesystem;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.HashSet;
import me.topchetoeu.jscript.filesystem.FilesystemException.FSCode;
public class MemoryFilesystem implements Filesystem {
public final Mode mode;
private HashMap<Path, Buffer> files = new HashMap<>();
private HashSet<Path> folders = new HashSet<>();
private Path getPath(String name) {
return Path.of("/" + name.replace("\\", "/")).normalize();
}
@Override
public void create(String path, EntryType type) {
var _path = getPath(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(new byte[0]));
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);
break;
default:
case NONE:
if (!folders.remove(_path) && files.remove(_path) == null) throw new FilesystemException(path, FSCode.DOESNT_EXIST);
}
}
@Override
public File open(String path, Mode perms) {
var _path = getPath(path);
var pcount = _path.getNameCount();
if (files.containsKey(_path)) return new MemoryFile(path, 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;
res.append(folder.toFile().getName()).append('\n');
}
for (var file : files.keySet()) {
if (pcount + 1 != file.getNameCount()) 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));
}
else throw new FilesystemException(path, FSCode.DOESNT_EXIST);
}
@Override
public FileStat stat(String path) {
var _path = getPath(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);
}
public MemoryFilesystem put(String path, byte[] data) {
var _path = getPath(path);
var _curr = "/";
for (var seg : _path) {
create(_curr, EntryType.FOLDER);
_curr += seg + "/";
}
files.put(_path, new Buffer(data));
return this;
}
public MemoryFilesystem(Mode mode) {
this.mode = mode;
folders.add(Path.of("/"));
}
}

View File

@ -0,0 +1,60 @@
package me.topchetoeu.jscript.filesystem;
import java.util.HashMap;
import java.util.Map;
import me.topchetoeu.jscript.Filename;
import me.topchetoeu.jscript.filesystem.FilesystemException.FSCode;
import me.topchetoeu.jscript.permissions.PermissionsManager;
public class RootFilesystem implements Filesystem {
public final Map<String, Filesystem> protocols = new HashMap<>();
public final PermissionsManager perms;
private boolean canRead(PermissionsManager perms, String _path) {
return perms.has("jscript.file.read:" + _path, '/');
}
private boolean canWrite(PermissionsManager perms, String _path) {
return perms.has("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);
}
@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);
modeAllowed(filename.toString(), 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 {
var filename = Filename.parse(path);
var protocol = protocols.get(filename.protocol);
if (protocol == null) throw new FilesystemException(filename.toString(), FSCode.DOESNT_EXIST);
modeAllowed(filename.toString(), Mode.READ_WRITE);
try { protocol.create(filename.path, type); }
catch (FilesystemException e) { throw new FilesystemException(filename.toString(), e.code); }
}
@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);
modeAllowed(filename.toString(), Mode.READ);
try { return protocol.stat(path); }
catch (FilesystemException e) { throw new FilesystemException(filename.toString(), e.code); }
}
public RootFilesystem(PermissionsManager perms) {
this.perms = perms;
}
}