2020-06-24 09:27:31 -04:00
|
|
|
/* eslint-disable */
|
|
|
|
|
|
|
|
import { resolve } from "../path/mod.ts";
|
|
|
|
|
|
|
|
const CLOCKID_REALTIME = 0;
|
|
|
|
const CLOCKID_MONOTONIC = 1;
|
|
|
|
const CLOCKID_PROCESS_CPUTIME_ID = 2;
|
|
|
|
const CLOCKID_THREAD_CPUTIME_ID = 3;
|
|
|
|
|
|
|
|
const ERRNO_SUCCESS = 0;
|
|
|
|
const ERRNO_2BIG = 1;
|
|
|
|
const ERRNO_ACCES = 2;
|
|
|
|
const ERRNO_ADDRINUSE = 3;
|
|
|
|
const ERRNO_ADDRNOTAVAIL = 4;
|
|
|
|
const ERRNO_AFNOSUPPORT = 5;
|
|
|
|
const ERRNO_AGAIN = 6;
|
|
|
|
const ERRNO_ALREADY = 7;
|
|
|
|
const ERRNO_BADF = 8;
|
|
|
|
const ERRNO_BADMSG = 9;
|
|
|
|
const ERRNO_BUSY = 10;
|
|
|
|
const ERRNO_CANCELED = 11;
|
|
|
|
const ERRNO_CHILD = 12;
|
|
|
|
const ERRNO_CONNABORTED = 13;
|
|
|
|
const ERRNO_CONNREFUSED = 14;
|
|
|
|
const ERRNO_CONNRESET = 15;
|
|
|
|
const ERRNO_DEADLK = 16;
|
|
|
|
const ERRNO_DESTADDRREQ = 17;
|
|
|
|
const ERRNO_DOM = 18;
|
|
|
|
const ERRNO_DQUOT = 19;
|
|
|
|
const ERRNO_EXIST = 20;
|
|
|
|
const ERRNO_FAULT = 21;
|
|
|
|
const ERRNO_FBIG = 22;
|
|
|
|
const ERRNO_HOSTUNREACH = 23;
|
|
|
|
const ERRNO_IDRM = 24;
|
|
|
|
const ERRNO_ILSEQ = 25;
|
|
|
|
const ERRNO_INPROGRESS = 26;
|
|
|
|
const ERRNO_INTR = 27;
|
|
|
|
const ERRNO_INVAL = 28;
|
|
|
|
const ERRNO_IO = 29;
|
|
|
|
const ERRNO_ISCONN = 30;
|
|
|
|
const ERRNO_ISDIR = 31;
|
|
|
|
const ERRNO_LOOP = 32;
|
|
|
|
const ERRNO_MFILE = 33;
|
|
|
|
const ERRNO_MLINK = 34;
|
|
|
|
const ERRNO_MSGSIZE = 35;
|
|
|
|
const ERRNO_MULTIHOP = 36;
|
|
|
|
const ERRNO_NAMETOOLONG = 37;
|
|
|
|
const ERRNO_NETDOWN = 38;
|
|
|
|
const ERRNO_NETRESET = 39;
|
|
|
|
const ERRNO_NETUNREACH = 40;
|
|
|
|
const ERRNO_NFILE = 41;
|
|
|
|
const ERRNO_NOBUFS = 42;
|
|
|
|
const ERRNO_NODEV = 43;
|
|
|
|
const ERRNO_NOENT = 44;
|
|
|
|
const ERRNO_NOEXEC = 45;
|
|
|
|
const ERRNO_NOLCK = 46;
|
|
|
|
const ERRNO_NOLINK = 47;
|
|
|
|
const ERRNO_NOMEM = 48;
|
|
|
|
const ERRNO_NOMSG = 49;
|
|
|
|
const ERRNO_NOPROTOOPT = 50;
|
|
|
|
const ERRNO_NOSPC = 51;
|
|
|
|
const ERRNO_NOSYS = 52;
|
|
|
|
const ERRNO_NOTCONN = 53;
|
|
|
|
const ERRNO_NOTDIR = 54;
|
|
|
|
const ERRNO_NOTEMPTY = 55;
|
|
|
|
const ERRNO_NOTRECOVERABLE = 56;
|
|
|
|
const ERRNO_NOTSOCK = 57;
|
|
|
|
const ERRNO_NOTSUP = 58;
|
|
|
|
const ERRNO_NOTTY = 59;
|
|
|
|
const ERRNO_NXIO = 60;
|
|
|
|
const ERRNO_OVERFLOW = 61;
|
|
|
|
const ERRNO_OWNERDEAD = 62;
|
|
|
|
const ERRNO_PERM = 63;
|
|
|
|
const ERRNO_PIPE = 64;
|
|
|
|
const ERRNO_PROTO = 65;
|
|
|
|
const ERRNO_PROTONOSUPPORT = 66;
|
|
|
|
const ERRNO_PROTOTYPE = 67;
|
|
|
|
const ERRNO_RANGE = 68;
|
|
|
|
const ERRNO_ROFS = 69;
|
|
|
|
const ERRNO_SPIPE = 70;
|
|
|
|
const ERRNO_SRCH = 71;
|
|
|
|
const ERRNO_STALE = 72;
|
|
|
|
const ERRNO_TIMEDOUT = 73;
|
|
|
|
const ERRNO_TXTBSY = 74;
|
|
|
|
const ERRNO_XDEV = 75;
|
|
|
|
const ERRNO_NOTCAPABLE = 76;
|
|
|
|
|
|
|
|
const RIGHTS_FD_DATASYNC = 0x0000000000000001n;
|
|
|
|
const RIGHTS_FD_READ = 0x0000000000000002n;
|
|
|
|
const RIGHTS_FD_SEEK = 0x0000000000000004n;
|
|
|
|
const RIGHTS_FD_FDSTAT_SET_FLAGS = 0x0000000000000008n;
|
|
|
|
const RIGHTS_FD_SYNC = 0x0000000000000010n;
|
|
|
|
const RIGHTS_FD_TELL = 0x0000000000000020n;
|
|
|
|
const RIGHTS_FD_WRITE = 0x0000000000000040n;
|
|
|
|
const RIGHTS_FD_ADVISE = 0x0000000000000080n;
|
|
|
|
const RIGHTS_FD_ALLOCATE = 0x0000000000000100n;
|
|
|
|
const RIGHTS_PATH_CREATE_DIRECTORY = 0x0000000000000200n;
|
|
|
|
const RIGHTS_PATH_CREATE_FILE = 0x0000000000000400n;
|
|
|
|
const RIGHTS_PATH_LINK_SOURCE = 0x0000000000000800n;
|
|
|
|
const RIGHTS_PATH_LINK_TARGET = 0x0000000000001000n;
|
|
|
|
const RIGHTS_PATH_OPEN = 0x0000000000002000n;
|
|
|
|
const RIGHTS_FD_READDIR = 0x0000000000004000n;
|
|
|
|
const RIGHTS_PATH_READLINK = 0x0000000000008000n;
|
|
|
|
const RIGHTS_PATH_RENAME_SOURCE = 0x0000000000010000n;
|
|
|
|
const RIGHTS_PATH_RENAME_TARGET = 0x0000000000020000n;
|
|
|
|
const RIGHTS_PATH_FILESTAT_GET = 0x0000000000040000n;
|
|
|
|
const RIGHTS_PATH_FILESTAT_SET_SIZE = 0x0000000000080000n;
|
|
|
|
const RIGHTS_PATH_FILESTAT_SET_TIMES = 0x0000000000100000n;
|
|
|
|
const RIGHTS_FD_FILESTAT_GET = 0x0000000000200000n;
|
|
|
|
const RIGHTS_FD_FILESTAT_SET_SIZE = 0x0000000000400000n;
|
|
|
|
const RIGHTS_FD_FILESTAT_SET_TIMES = 0x0000000000800000n;
|
|
|
|
const RIGHTS_PATH_SYMLINK = 0x0000000001000000n;
|
|
|
|
const RIGHTS_PATH_REMOVE_DIRECTORY = 0x0000000002000000n;
|
|
|
|
const RIGHTS_PATH_UNLINK_FILE = 0x0000000004000000n;
|
|
|
|
const RIGHTS_POLL_FD_READWRITE = 0x0000000008000000n;
|
|
|
|
const RIGHTS_SOCK_SHUTDOWN = 0x0000000010000000n;
|
|
|
|
|
|
|
|
const WHENCE_SET = 0;
|
|
|
|
const WHENCE_CUR = 1;
|
|
|
|
const WHENCE_END = 2;
|
|
|
|
|
|
|
|
const FILETYPE_UNKNOWN = 0;
|
|
|
|
const FILETYPE_BLOCK_DEVICE = 1;
|
|
|
|
const FILETYPE_CHARACTER_DEVICE = 2;
|
|
|
|
const FILETYPE_DIRECTORY = 3;
|
|
|
|
const FILETYPE_REGULAR_FILE = 4;
|
|
|
|
const FILETYPE_SOCKET_DGRAM = 5;
|
|
|
|
const FILETYPE_SOCKET_STREAM = 6;
|
|
|
|
const FILETYPE_SYMBOLIC_LINK = 7;
|
|
|
|
|
|
|
|
const ADVICE_NORMAL = 0;
|
|
|
|
const ADVICE_SEQUENTIAL = 1;
|
|
|
|
const ADVICE_RANDOM = 2;
|
|
|
|
const ADVICE_WILLNEED = 3;
|
|
|
|
const ADVICE_DONTNEED = 4;
|
|
|
|
const ADVICE_NOREUSE = 5;
|
|
|
|
|
|
|
|
const FDFLAGS_APPEND = 0x0001;
|
|
|
|
const FDFLAGS_DSYNC = 0x0002;
|
|
|
|
const FDFLAGS_NONBLOCK = 0x0004;
|
|
|
|
const FDFLAGS_RSYNC = 0x0008;
|
|
|
|
const FDFLAGS_SYNC = 0x0010;
|
|
|
|
|
|
|
|
const FSTFLAGS_ATIM = 0x0001;
|
|
|
|
const FSTFLAGS_ATIM_NOW = 0x0002;
|
|
|
|
const FSTFLAGS_MTIM = 0x0004;
|
|
|
|
const FSTFLAGS_MTIM_NOW = 0x0008;
|
|
|
|
|
|
|
|
const LOOKUPFLAGS_SYMLINK_FOLLOW = 0x0001;
|
|
|
|
|
|
|
|
const OFLAGS_CREAT = 0x0001;
|
|
|
|
const OFLAGS_DIRECTORY = 0x0002;
|
|
|
|
const OFLAGS_EXCL = 0x0004;
|
|
|
|
const OFLAGS_TRUNC = 0x0008;
|
|
|
|
|
|
|
|
const EVENTTYPE_CLOCK = 0;
|
|
|
|
const EVENTTYPE_FD_READ = 1;
|
|
|
|
const EVENTTYPE_FD_WRITE = 2;
|
|
|
|
|
|
|
|
const EVENTRWFLAGS_FD_READWRITE_HANGUP = 1;
|
|
|
|
const SUBCLOCKFLAGS_SUBSCRIPTION_CLOCK_ABSTIME = 1;
|
|
|
|
|
|
|
|
const SIGNAL_NONE = 0;
|
|
|
|
const SIGNAL_HUP = 1;
|
|
|
|
const SIGNAL_INT = 2;
|
|
|
|
const SIGNAL_QUIT = 3;
|
|
|
|
const SIGNAL_ILL = 4;
|
|
|
|
const SIGNAL_TRAP = 5;
|
|
|
|
const SIGNAL_ABRT = 6;
|
|
|
|
const SIGNAL_BUS = 7;
|
|
|
|
const SIGNAL_FPE = 8;
|
|
|
|
const SIGNAL_KILL = 9;
|
|
|
|
const SIGNAL_USR1 = 10;
|
|
|
|
const SIGNAL_SEGV = 11;
|
|
|
|
const SIGNAL_USR2 = 12;
|
|
|
|
const SIGNAL_PIPE = 13;
|
|
|
|
const SIGNAL_ALRM = 14;
|
|
|
|
const SIGNAL_TERM = 15;
|
|
|
|
const SIGNAL_CHLD = 16;
|
|
|
|
const SIGNAL_CONT = 17;
|
|
|
|
const SIGNAL_STOP = 18;
|
|
|
|
const SIGNAL_TSTP = 19;
|
|
|
|
const SIGNAL_TTIN = 20;
|
|
|
|
const SIGNAL_TTOU = 21;
|
|
|
|
const SIGNAL_URG = 22;
|
|
|
|
const SIGNAL_XCPU = 23;
|
|
|
|
const SIGNAL_XFSZ = 24;
|
|
|
|
const SIGNAL_VTALRM = 25;
|
|
|
|
const SIGNAL_PROF = 26;
|
|
|
|
const SIGNAL_WINCH = 27;
|
|
|
|
const SIGNAL_POLL = 28;
|
|
|
|
const SIGNAL_PWR = 29;
|
|
|
|
const SIGNAL_SYS = 30;
|
|
|
|
|
|
|
|
const RIFLAGS_RECV_PEEK = 0x0001;
|
|
|
|
const RIFLAGS_RECV_WAITALL = 0x0002;
|
|
|
|
|
|
|
|
const ROFLAGS_RECV_DATA_TRUNCATED = 0x0001;
|
|
|
|
|
|
|
|
const SDFLAGS_RD = 0x0001;
|
|
|
|
const SDFLAGS_WR = 0x0002;
|
|
|
|
|
|
|
|
const PREOPENTYPE_DIR = 0;
|
|
|
|
|
|
|
|
const clock_res_realtime = function (): bigint {
|
|
|
|
return BigInt(1e6);
|
|
|
|
};
|
|
|
|
|
|
|
|
const clock_res_monotonic = function (): bigint {
|
|
|
|
return BigInt(1e3);
|
|
|
|
};
|
|
|
|
|
|
|
|
const clock_res_process = clock_res_monotonic;
|
|
|
|
const clock_res_thread = clock_res_monotonic;
|
|
|
|
|
|
|
|
const clock_time_realtime = function (): bigint {
|
|
|
|
return BigInt(Date.now()) * BigInt(1e6);
|
|
|
|
};
|
|
|
|
|
|
|
|
const clock_time_monotonic = function (): bigint {
|
|
|
|
const t = performance.now();
|
|
|
|
const s = Math.trunc(t);
|
|
|
|
const ms = Math.floor((t - s) * 1e3);
|
|
|
|
|
|
|
|
return BigInt(s) * BigInt(1e9) + BigInt(ms) * BigInt(1e6);
|
|
|
|
};
|
|
|
|
|
|
|
|
const clock_time_process = clock_time_monotonic;
|
|
|
|
const clock_time_thread = clock_time_monotonic;
|
|
|
|
|
|
|
|
function errno(err: Error) {
|
|
|
|
switch (err.name) {
|
|
|
|
case "NotFound":
|
|
|
|
return ERRNO_NOENT;
|
|
|
|
|
|
|
|
case "PermissionDenied":
|
|
|
|
return ERRNO_ACCES;
|
|
|
|
|
|
|
|
case "ConnectionRefused":
|
|
|
|
return ERRNO_CONNREFUSED;
|
|
|
|
|
|
|
|
case "ConnectionReset":
|
|
|
|
return ERRNO_CONNRESET;
|
|
|
|
|
|
|
|
case "ConnectionAborted":
|
|
|
|
return ERRNO_CONNABORTED;
|
|
|
|
|
|
|
|
case "NotConnected":
|
|
|
|
return ERRNO_NOTCONN;
|
|
|
|
|
|
|
|
case "AddrInUse":
|
|
|
|
return ERRNO_ADDRINUSE;
|
|
|
|
|
|
|
|
case "AddrNotAvailable":
|
|
|
|
return ERRNO_ADDRNOTAVAIL;
|
|
|
|
|
|
|
|
case "BrokenPipe":
|
|
|
|
return ERRNO_PIPE;
|
|
|
|
|
|
|
|
case "InvalidData":
|
|
|
|
return ERRNO_INVAL;
|
|
|
|
|
|
|
|
case "TimedOut":
|
|
|
|
return ERRNO_TIMEDOUT;
|
|
|
|
|
|
|
|
case "Interrupted":
|
|
|
|
return ERRNO_INTR;
|
|
|
|
|
|
|
|
case "BadResource":
|
|
|
|
return ERRNO_BADF;
|
|
|
|
|
|
|
|
case "Busy":
|
|
|
|
return ERRNO_BUSY;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return ERRNO_INVAL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface ModuleOptions {
|
|
|
|
args?: string[];
|
|
|
|
env?: { [key: string]: string | undefined };
|
|
|
|
preopens?: { [key: string]: string };
|
|
|
|
memory?: WebAssembly.Memory;
|
|
|
|
}
|
|
|
|
|
|
|
|
export default class Module {
|
|
|
|
args: string[];
|
|
|
|
env: { [key: string]: string | undefined };
|
|
|
|
memory: WebAssembly.Memory;
|
|
|
|
|
|
|
|
// deno-lint-ignore no-explicit-any
|
|
|
|
fds: any[];
|
|
|
|
|
|
|
|
// deno-lint-ignore no-explicit-any
|
|
|
|
exports: { [key: string]: any };
|
|
|
|
|
|
|
|
constructor(options: ModuleOptions) {
|
|
|
|
this.args = options.args ? options.args : [];
|
|
|
|
this.env = options.env ? options.env : {};
|
|
|
|
this.memory = options.memory!;
|
|
|
|
|
|
|
|
this.fds = [
|
|
|
|
{
|
|
|
|
type: FILETYPE_CHARACTER_DEVICE,
|
|
|
|
handle: Deno.stdin,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: FILETYPE_CHARACTER_DEVICE,
|
|
|
|
handle: Deno.stdout,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
type: FILETYPE_CHARACTER_DEVICE,
|
|
|
|
handle: Deno.stderr,
|
|
|
|
},
|
|
|
|
];
|
|
|
|
|
|
|
|
if (options.preopens) {
|
|
|
|
for (const [vpath, path] of Object.entries(options.preopens)) {
|
|
|
|
const info = Deno.statSync(path);
|
|
|
|
if (!info.isDirectory) {
|
|
|
|
throw new TypeError(`${path} is not a directory`);
|
|
|
|
}
|
|
|
|
|
|
|
|
const type = FILETYPE_DIRECTORY;
|
|
|
|
|
|
|
|
const entry = {
|
|
|
|
type,
|
|
|
|
path,
|
|
|
|
vpath,
|
|
|
|
};
|
|
|
|
|
|
|
|
this.fds.push(entry);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
this.exports = {
|
|
|
|
args_get: (argv_ptr: number, argv_buf_ptr: number): number => {
|
|
|
|
const args = this.args;
|
|
|
|
const text = new TextEncoder();
|
|
|
|
const heap = new Uint8Array(this.memory.buffer);
|
|
|
|
const view = new DataView(this.memory.buffer);
|
|
|
|
|
|
|
|
for (let arg of args) {
|
|
|
|
view.setUint32(argv_ptr, argv_buf_ptr, true);
|
|
|
|
argv_ptr += 4;
|
|
|
|
|
|
|
|
const data = text.encode(`${arg}\0`);
|
|
|
|
heap.set(data, argv_buf_ptr);
|
|
|
|
argv_buf_ptr += data.length;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERRNO_SUCCESS;
|
|
|
|
},
|
|
|
|
|
|
|
|
args_sizes_get: (argc_out: number, argv_buf_size_out: number): number => {
|
|
|
|
const args = this.args;
|
|
|
|
const text = new TextEncoder();
|
|
|
|
const view = new DataView(this.memory.buffer);
|
|
|
|
|
|
|
|
view.setUint32(argc_out, args.length, true);
|
|
|
|
view.setUint32(
|
|
|
|
argv_buf_size_out,
|
|
|
|
args.reduce(function (acc, arg) {
|
|
|
|
return acc + text.encode(`${arg}\0`).length;
|
|
|
|
}, 0),
|
|
|
|
true
|
|
|
|
);
|
|
|
|
|
|
|
|
return ERRNO_SUCCESS;
|
|
|
|
},
|
|
|
|
|
|
|
|
environ_get: (environ_ptr: number, environ_buf_ptr: number): number => {
|
|
|
|
const entries = Object.entries(this.env);
|
|
|
|
const text = new TextEncoder();
|
|
|
|
const heap = new Uint8Array(this.memory.buffer);
|
|
|
|
const view = new DataView(this.memory.buffer);
|
|
|
|
|
|
|
|
for (let [key, value] of entries) {
|
|
|
|
view.setUint32(environ_ptr, environ_buf_ptr, true);
|
|
|
|
environ_ptr += 4;
|
|
|
|
|
|
|
|
const data = text.encode(`${key}=${value}\0`);
|
|
|
|
heap.set(data, environ_buf_ptr);
|
|
|
|
environ_buf_ptr += data.length;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERRNO_SUCCESS;
|
|
|
|
},
|
|
|
|
|
|
|
|
environ_sizes_get: (
|
|
|
|
environc_out: number,
|
|
|
|
environ_buf_size_out: number
|
|
|
|
): number => {
|
|
|
|
const entries = Object.entries(this.env);
|
|
|
|
const text = new TextEncoder();
|
|
|
|
const view = new DataView(this.memory.buffer);
|
|
|
|
|
|
|
|
view.setUint32(environc_out, entries.length, true);
|
|
|
|
view.setUint32(
|
|
|
|
environ_buf_size_out,
|
|
|
|
entries.reduce(function (acc, [key, value]) {
|
|
|
|
return acc + text.encode(`${key}=${value}\0`).length;
|
|
|
|
}, 0),
|
|
|
|
true
|
|
|
|
);
|
|
|
|
|
|
|
|
return ERRNO_SUCCESS;
|
|
|
|
},
|
|
|
|
|
|
|
|
clock_res_get: (id: number, resolution_out: number): number => {
|
|
|
|
const view = new DataView(this.memory.buffer);
|
|
|
|
|
|
|
|
switch (id) {
|
|
|
|
case CLOCKID_REALTIME:
|
|
|
|
view.setBigUint64(resolution_out, clock_res_realtime(), true);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CLOCKID_MONOTONIC:
|
|
|
|
view.setBigUint64(resolution_out, clock_res_monotonic(), true);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CLOCKID_PROCESS_CPUTIME_ID:
|
|
|
|
view.setBigUint64(resolution_out, clock_res_process(), true);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CLOCKID_THREAD_CPUTIME_ID:
|
|
|
|
view.setBigUint64(resolution_out, clock_res_thread(), true);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return ERRNO_INVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERRNO_SUCCESS;
|
|
|
|
},
|
|
|
|
|
|
|
|
clock_time_get: (
|
|
|
|
id: number,
|
|
|
|
precision: bigint,
|
|
|
|
time_out: number
|
|
|
|
): number => {
|
|
|
|
const view = new DataView(this.memory.buffer);
|
|
|
|
|
|
|
|
switch (id) {
|
|
|
|
case CLOCKID_REALTIME:
|
|
|
|
view.setBigUint64(time_out, clock_time_realtime(), true);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CLOCKID_MONOTONIC:
|
|
|
|
view.setBigUint64(time_out, clock_time_monotonic(), true);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CLOCKID_PROCESS_CPUTIME_ID:
|
|
|
|
view.setBigUint64(time_out, clock_time_process(), true);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CLOCKID_THREAD_CPUTIME_ID:
|
|
|
|
view.setBigUint64(time_out, clock_time_thread(), true);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return ERRNO_INVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERRNO_SUCCESS;
|
|
|
|
},
|
|
|
|
|
|
|
|
fd_advise: (
|
|
|
|
fd: number,
|
|
|
|
offset: bigint,
|
|
|
|
len: bigint,
|
|
|
|
advice: number
|
|
|
|
): number => {
|
|
|
|
return ERRNO_NOSYS;
|
|
|
|
},
|
|
|
|
|
|
|
|
fd_allocate: (fd: number, offset: bigint, len: bigint): number => {
|
|
|
|
return ERRNO_NOSYS;
|
|
|
|
},
|
|
|
|
|
|
|
|
fd_close: (fd: number): number => {
|
|
|
|
const entry = this.fds[fd];
|
|
|
|
if (!entry) {
|
|
|
|
return ERRNO_BADF;
|
|
|
|
}
|
|
|
|
|
|
|
|
entry.handle.close();
|
|
|
|
delete this.fds[fd];
|
|
|
|
|
|
|
|
return ERRNO_SUCCESS;
|
|
|
|
},
|
|
|
|
|
|
|
|
fd_datasync: (fd: number): number => {
|
|
|
|
return ERRNO_NOSYS;
|
|
|
|
},
|
|
|
|
|
|
|
|
fd_fdstat_get: (fd: number, stat_out: number): number => {
|
|
|
|
const entry = this.fds[fd];
|
|
|
|
if (!entry) {
|
|
|
|
return ERRNO_BADF;
|
|
|
|
}
|
|
|
|
|
|
|
|
const view = new DataView(this.memory.buffer);
|
|
|
|
view.setUint8(stat_out, entry.type);
|
|
|
|
view.setUint16(stat_out + 4, 0, true); // TODO
|
|
|
|
view.setBigUint64(stat_out + 8, 0n, true); // TODO
|
|
|
|
view.setBigUint64(stat_out + 16, 0n, true); // TODO
|
|
|
|
|
|
|
|
return ERRNO_SUCCESS;
|
|
|
|
},
|
|
|
|
|
|
|
|
fd_fdstat_set_flags: (fd: number, flags: number): number => {
|
|
|
|
return ERRNO_NOSYS;
|
|
|
|
},
|
|
|
|
|
|
|
|
fd_fdstat_set_rights: (
|
|
|
|
fd: number,
|
|
|
|
fs_rights_base: bigint,
|
|
|
|
fs_rights_inheriting: bigint
|
|
|
|
): number => {
|
|
|
|
return ERRNO_NOSYS;
|
|
|
|
},
|
|
|
|
|
|
|
|
fd_filestat_get: (fd: number, buf_out: number): number => {
|
|
|
|
return ERRNO_NOSYS;
|
|
|
|
},
|
|
|
|
|
|
|
|
fd_filestat_set_size: (fd: number, size: bigint): number => {
|
|
|
|
return ERRNO_NOSYS;
|
|
|
|
},
|
|
|
|
|
|
|
|
fd_filestat_set_times: (
|
|
|
|
fd: number,
|
|
|
|
atim: bigint,
|
|
|
|
mtim: bigint,
|
|
|
|
fst_flags: number
|
|
|
|
): number => {
|
|
|
|
const entry = this.fds[fd];
|
|
|
|
if (!entry) {
|
|
|
|
return ERRNO_BADF;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!entry.path) {
|
|
|
|
return ERRNO_INVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((fst_flags & FSTFLAGS_ATIM_NOW) == FSTFLAGS_ATIM_NOW) {
|
|
|
|
atim = BigInt(Date.now() * 1e6);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((fst_flags & FSTFLAGS_MTIM_NOW) == FSTFLAGS_MTIM_NOW) {
|
|
|
|
mtim = BigInt(Date.now() * 1e6);
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
Deno.utimeSync(entry.path, Number(atim), Number(mtim));
|
|
|
|
} catch (err) {
|
|
|
|
return errno(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERRNO_SUCCESS;
|
|
|
|
},
|
|
|
|
|
|
|
|
fd_pread: (
|
|
|
|
fd: number,
|
|
|
|
iovs_ptr: number,
|
|
|
|
iovs_len: number,
|
|
|
|
offset: bigint,
|
|
|
|
nread_out: number
|
|
|
|
): number => {
|
|
|
|
const entry = this.fds[fd];
|
|
|
|
if (!entry) {
|
|
|
|
return ERRNO_BADF;
|
|
|
|
}
|
|
|
|
|
|
|
|
const seek = entry.handle.seekSync(0, Deno.SeekMode.Current);
|
|
|
|
const view = new DataView(this.memory.buffer);
|
|
|
|
|
|
|
|
let nread = 0;
|
|
|
|
for (let i = 0; i < iovs_len; i++) {
|
|
|
|
const data_ptr = view.getUint32(iovs_ptr, true);
|
|
|
|
iovs_ptr += 4;
|
|
|
|
|
|
|
|
const data_len = view.getUint32(iovs_ptr, true);
|
|
|
|
iovs_ptr += 4;
|
|
|
|
|
|
|
|
const data = new Uint8Array(this.memory.buffer, data_ptr, data_len);
|
|
|
|
nread += entry.handle.readSync(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
entry.handle.seekSync(seek, Deno.SeekMode.Start);
|
|
|
|
view.setUint32(nread_out, nread, true);
|
|
|
|
|
|
|
|
return ERRNO_SUCCESS;
|
|
|
|
},
|
|
|
|
|
|
|
|
fd_prestat_get: (fd: number, buf_out: number): number => {
|
|
|
|
const entry = this.fds[fd];
|
|
|
|
if (!entry) {
|
|
|
|
return ERRNO_BADF;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!entry.vpath) {
|
|
|
|
return ERRNO_BADF;
|
|
|
|
}
|
|
|
|
|
|
|
|
const view = new DataView(this.memory.buffer);
|
|
|
|
view.setUint8(buf_out, PREOPENTYPE_DIR);
|
|
|
|
view.setUint32(
|
|
|
|
buf_out + 4,
|
|
|
|
new TextEncoder().encode(entry.vpath).byteLength,
|
|
|
|
true
|
|
|
|
);
|
|
|
|
|
|
|
|
return ERRNO_SUCCESS;
|
|
|
|
},
|
|
|
|
|
|
|
|
fd_prestat_dir_name: (
|
|
|
|
fd: number,
|
|
|
|
path_ptr: number,
|
|
|
|
path_len: number
|
|
|
|
): number => {
|
|
|
|
const entry = this.fds[fd];
|
|
|
|
if (!entry) {
|
|
|
|
return ERRNO_BADF;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!entry.vpath) {
|
|
|
|
return ERRNO_BADF;
|
|
|
|
}
|
|
|
|
|
|
|
|
const data = new Uint8Array(this.memory.buffer, path_ptr, path_len);
|
|
|
|
data.set(new TextEncoder().encode(entry.vpath));
|
|
|
|
|
|
|
|
return ERRNO_SUCCESS;
|
|
|
|
},
|
|
|
|
|
|
|
|
fd_pwrite: (
|
|
|
|
fd: number,
|
|
|
|
iovs_ptr: number,
|
|
|
|
iovs_len: number,
|
|
|
|
offset: bigint,
|
|
|
|
nwritten_out: number
|
|
|
|
): number => {
|
|
|
|
const entry = this.fds[fd];
|
|
|
|
if (!entry) {
|
|
|
|
return ERRNO_BADF;
|
|
|
|
}
|
|
|
|
|
|
|
|
const seek = entry.handle.seekSync(0, Deno.SeekMode.Current);
|
|
|
|
const view = new DataView(this.memory.buffer);
|
|
|
|
|
|
|
|
let nwritten = 0;
|
|
|
|
for (let i = 0; i < iovs_len; i++) {
|
|
|
|
const data_ptr = view.getUint32(iovs_ptr, true);
|
|
|
|
iovs_ptr += 4;
|
|
|
|
|
|
|
|
const data_len = view.getUint32(iovs_ptr, true);
|
|
|
|
iovs_ptr += 4;
|
|
|
|
|
|
|
|
const data = new Uint8Array(this.memory.buffer, data_ptr, data_len);
|
|
|
|
nwritten += entry.handle.writeSync(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
entry.handle.seekSync(seek, Deno.SeekMode.Start);
|
|
|
|
view.setUint32(nwritten_out, nwritten, true);
|
|
|
|
|
|
|
|
return ERRNO_SUCCESS;
|
|
|
|
},
|
|
|
|
|
|
|
|
fd_read: (
|
|
|
|
fd: number,
|
|
|
|
iovs_ptr: number,
|
|
|
|
iovs_len: number,
|
|
|
|
nread_out: number
|
|
|
|
): number => {
|
|
|
|
const entry = this.fds[fd];
|
|
|
|
if (!entry) {
|
|
|
|
return ERRNO_BADF;
|
|
|
|
}
|
|
|
|
|
|
|
|
const view = new DataView(this.memory.buffer);
|
|
|
|
|
|
|
|
let nread = 0;
|
|
|
|
for (let i = 0; i < iovs_len; i++) {
|
|
|
|
const data_ptr = view.getUint32(iovs_ptr, true);
|
|
|
|
iovs_ptr += 4;
|
|
|
|
|
|
|
|
const data_len = view.getUint32(iovs_ptr, true);
|
|
|
|
iovs_ptr += 4;
|
|
|
|
|
|
|
|
const data = new Uint8Array(this.memory.buffer, data_ptr, data_len);
|
|
|
|
nread += entry.handle.readSync(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
view.setUint32(nread_out, nread, true);
|
|
|
|
|
|
|
|
return ERRNO_SUCCESS;
|
|
|
|
},
|
|
|
|
|
|
|
|
fd_readdir: (
|
|
|
|
fd: number,
|
|
|
|
buf_ptr: number,
|
|
|
|
buf_len: number,
|
|
|
|
cookie: bigint,
|
|
|
|
bufused_out: number
|
|
|
|
): number => {
|
|
|
|
return ERRNO_NOSYS;
|
|
|
|
},
|
|
|
|
|
|
|
|
fd_renumber: (fd: number, to: number): number => {
|
|
|
|
if (!this.fds[fd]) {
|
|
|
|
return ERRNO_BADF;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!this.fds[to]) {
|
|
|
|
return ERRNO_BADF;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.fds[to].handle.close();
|
|
|
|
this.fds[to] = this.fds[fd];
|
|
|
|
delete this.fds[fd];
|
|
|
|
|
|
|
|
return ERRNO_SUCCESS;
|
|
|
|
},
|
|
|
|
|
|
|
|
fd_seek: (
|
|
|
|
fd: number,
|
|
|
|
offset: bigint,
|
|
|
|
whence: number,
|
|
|
|
newoffset_out: number
|
|
|
|
): number => {
|
|
|
|
const entry = this.fds[fd];
|
|
|
|
if (!entry) {
|
|
|
|
return ERRNO_BADF;
|
|
|
|
}
|
|
|
|
|
|
|
|
const view = new DataView(this.memory.buffer);
|
|
|
|
|
|
|
|
try {
|
|
|
|
// FIXME Deno does not support seeking with big integers
|
|
|
|
|
|
|
|
const newoffset = entry.handle.seekSync(Number(offset), whence);
|
|
|
|
view.setBigUint64(newoffset_out, BigInt(newoffset), true);
|
|
|
|
} catch (err) {
|
|
|
|
return ERRNO_INVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERRNO_SUCCESS;
|
|
|
|
},
|
|
|
|
|
|
|
|
fd_sync: (fd: number): number => {
|
|
|
|
return ERRNO_NOSYS;
|
|
|
|
},
|
|
|
|
|
|
|
|
fd_tell: (fd: number, offset_out: number): number => {
|
|
|
|
const entry = this.fds[fd];
|
|
|
|
if (!entry) {
|
|
|
|
return ERRNO_BADF;
|
|
|
|
}
|
|
|
|
|
|
|
|
const view = new DataView(this.memory.buffer);
|
|
|
|
|
|
|
|
try {
|
|
|
|
const offset = entry.handle.seekSync(0, Deno.SeekMode.Current);
|
|
|
|
view.setBigUint64(offset_out, offset, true);
|
|
|
|
} catch (err) {
|
|
|
|
return ERRNO_INVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERRNO_NOSYS;
|
|
|
|
},
|
|
|
|
|
|
|
|
fd_write: (
|
|
|
|
fd: number,
|
|
|
|
iovs_ptr: number,
|
|
|
|
iovs_len: number,
|
|
|
|
nwritten_out: number
|
|
|
|
): number => {
|
|
|
|
const entry = this.fds[fd];
|
|
|
|
if (!entry) {
|
|
|
|
return ERRNO_BADF;
|
|
|
|
}
|
|
|
|
|
|
|
|
const view = new DataView(this.memory.buffer);
|
|
|
|
|
|
|
|
let nwritten = 0;
|
|
|
|
for (let i = 0; i < iovs_len; i++) {
|
|
|
|
const data_ptr = view.getUint32(iovs_ptr, true);
|
|
|
|
iovs_ptr += 4;
|
|
|
|
|
|
|
|
const data_len = view.getUint32(iovs_ptr, true);
|
|
|
|
iovs_ptr += 4;
|
|
|
|
|
|
|
|
nwritten += entry.handle.writeSync(
|
|
|
|
new Uint8Array(this.memory.buffer, data_ptr, data_len)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
view.setUint32(nwritten_out, nwritten, true);
|
|
|
|
|
|
|
|
return ERRNO_SUCCESS;
|
|
|
|
},
|
|
|
|
|
|
|
|
path_create_directory: (
|
|
|
|
fd: number,
|
|
|
|
path_ptr: number,
|
|
|
|
path_len: number
|
|
|
|
): number => {
|
|
|
|
const entry = this.fds[fd];
|
|
|
|
if (!entry) {
|
|
|
|
return ERRNO_BADF;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!entry.path) {
|
|
|
|
return ERRNO_INVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
const text = new TextDecoder();
|
|
|
|
const data = new Uint8Array(this.memory.buffer, path_ptr, path_len);
|
|
|
|
const path = resolve(entry.path, text.decode(data));
|
|
|
|
|
|
|
|
try {
|
|
|
|
Deno.mkdirSync(path);
|
|
|
|
} catch (err) {
|
|
|
|
return errno(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERRNO_SUCCESS;
|
|
|
|
},
|
|
|
|
|
|
|
|
path_filestat_get: (
|
|
|
|
fd: number,
|
|
|
|
flags: number,
|
|
|
|
path_ptr: number,
|
|
|
|
path_len: number,
|
|
|
|
buf_out: number
|
|
|
|
): number => {
|
|
|
|
const entry = this.fds[fd];
|
|
|
|
if (!entry) {
|
|
|
|
return ERRNO_BADF;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!entry.path) {
|
|
|
|
return ERRNO_INVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
const text = new TextDecoder();
|
|
|
|
const data = new Uint8Array(this.memory.buffer, path_ptr, path_len);
|
|
|
|
const path = resolve(entry.path, text.decode(data));
|
|
|
|
|
|
|
|
const view = new DataView(this.memory.buffer);
|
|
|
|
|
|
|
|
try {
|
|
|
|
const info = Deno.statSync(path);
|
|
|
|
|
|
|
|
view.setBigUint64(buf_out, BigInt(info.dev ? info.dev : 0), true);
|
|
|
|
buf_out += 8;
|
|
|
|
|
|
|
|
view.setBigUint64(buf_out, BigInt(info.ino ? info.ino : 0), true);
|
|
|
|
buf_out += 8;
|
|
|
|
|
|
|
|
switch (true) {
|
|
|
|
case info.isFile:
|
|
|
|
view.setUint8(buf_out, FILETYPE_REGULAR_FILE);
|
2020-06-27 07:53:43 -04:00
|
|
|
buf_out += 8;
|
2020-06-24 09:27:31 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case info.isDirectory:
|
|
|
|
view.setUint8(buf_out, FILETYPE_DIRECTORY);
|
2020-06-27 07:53:43 -04:00
|
|
|
buf_out += 8;
|
2020-06-24 09:27:31 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
case info.isSymlink:
|
|
|
|
view.setUint8(buf_out, FILETYPE_SYMBOLIC_LINK);
|
2020-06-27 07:53:43 -04:00
|
|
|
buf_out += 8;
|
2020-06-24 09:27:31 -04:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
view.setUint8(buf_out, FILETYPE_UNKNOWN);
|
2020-06-27 07:53:43 -04:00
|
|
|
buf_out += 8;
|
2020-06-24 09:27:31 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
view.setUint32(buf_out, Number(info.nlink), true);
|
2020-06-27 07:53:43 -04:00
|
|
|
buf_out += 8;
|
2020-06-24 09:27:31 -04:00
|
|
|
|
|
|
|
view.setBigUint64(buf_out, BigInt(info.size), true);
|
|
|
|
buf_out += 8;
|
|
|
|
|
|
|
|
view.setBigUint64(
|
|
|
|
buf_out,
|
|
|
|
BigInt(info.atime ? info.atime.getTime() * 1e6 : 0),
|
|
|
|
true
|
|
|
|
);
|
|
|
|
buf_out += 8;
|
|
|
|
|
|
|
|
view.setBigUint64(
|
|
|
|
buf_out,
|
|
|
|
BigInt(info.mtime ? info.mtime.getTime() * 1e6 : 0),
|
|
|
|
true
|
|
|
|
);
|
|
|
|
buf_out += 8;
|
|
|
|
|
|
|
|
view.setBigUint64(
|
|
|
|
buf_out,
|
|
|
|
BigInt(info.birthtime ? info.birthtime.getTime() * 1e6 : 0),
|
|
|
|
true
|
|
|
|
);
|
|
|
|
buf_out += 8;
|
|
|
|
} catch (err) {
|
|
|
|
return errno(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERRNO_SUCCESS;
|
|
|
|
},
|
|
|
|
|
|
|
|
path_filestat_set_times: (
|
|
|
|
fd: number,
|
|
|
|
flags: number,
|
|
|
|
path_ptr: number,
|
|
|
|
path_len: number,
|
|
|
|
atim: bigint,
|
|
|
|
mtim: bigint,
|
|
|
|
fst_flags: number
|
|
|
|
): number => {
|
|
|
|
const entry = this.fds[fd];
|
|
|
|
if (!entry) {
|
|
|
|
return ERRNO_BADF;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!entry.path) {
|
|
|
|
return ERRNO_INVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
const text = new TextDecoder();
|
|
|
|
const data = new Uint8Array(this.memory.buffer, path_ptr, path_len);
|
|
|
|
const path = resolve(entry.path, text.decode(data));
|
|
|
|
|
|
|
|
if ((fst_flags & FSTFLAGS_ATIM_NOW) == FSTFLAGS_ATIM_NOW) {
|
|
|
|
atim = BigInt(Date.now()) * BigInt(1e6);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((fst_flags & FSTFLAGS_MTIM_NOW) == FSTFLAGS_MTIM_NOW) {
|
|
|
|
mtim = BigInt(Date.now()) * BigInt(1e6);
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
Deno.utimeSync(path, Number(atim), Number(mtim));
|
|
|
|
} catch (err) {
|
|
|
|
return errno(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERRNO_SUCCESS;
|
|
|
|
},
|
|
|
|
|
|
|
|
path_link: (
|
|
|
|
old_fd: number,
|
|
|
|
old_flags: number,
|
|
|
|
old_path_ptr: number,
|
|
|
|
old_path_len: number,
|
|
|
|
new_fd: number,
|
|
|
|
new_path_ptr: number,
|
|
|
|
new_path_len: number
|
|
|
|
): number => {
|
|
|
|
const old_entry = this.fds[old_fd];
|
|
|
|
const new_entry = this.fds[new_fd];
|
|
|
|
if (!old_entry || !new_entry) {
|
|
|
|
return ERRNO_BADF;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!old_entry.path || !new_entry.path) {
|
|
|
|
return ERRNO_INVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
const text = new TextDecoder();
|
|
|
|
const old_data = new Uint8Array(
|
|
|
|
this.memory.buffer,
|
|
|
|
old_path_ptr,
|
|
|
|
old_path_len
|
|
|
|
);
|
|
|
|
const old_path = resolve(old_entry.path, text.decode(old_data));
|
|
|
|
const new_data = new Uint8Array(
|
|
|
|
this.memory.buffer,
|
|
|
|
new_path_ptr,
|
|
|
|
new_path_len
|
|
|
|
);
|
|
|
|
const new_path = resolve(new_entry.path, text.decode(new_data));
|
|
|
|
|
|
|
|
try {
|
|
|
|
Deno.linkSync(old_path, new_path);
|
|
|
|
} catch (err) {
|
|
|
|
return errno(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERRNO_SUCCESS;
|
|
|
|
},
|
|
|
|
|
|
|
|
path_open: (
|
|
|
|
fd: number,
|
|
|
|
dirflags: number,
|
|
|
|
path_ptr: number,
|
|
|
|
path_len: number,
|
|
|
|
oflags: number,
|
|
|
|
fs_rights_base: number | bigint,
|
|
|
|
fs_rights_inherting: number | bigint,
|
|
|
|
fdflags: number,
|
|
|
|
opened_fd_out: number
|
|
|
|
): number => {
|
|
|
|
const entry = this.fds[fd];
|
|
|
|
if (!entry) {
|
|
|
|
return ERRNO_BADF;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!entry.path) {
|
|
|
|
return ERRNO_INVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
const text = new TextDecoder();
|
|
|
|
const data = new Uint8Array(this.memory.buffer, path_ptr, path_len);
|
|
|
|
const path = resolve(entry.path, text.decode(data));
|
|
|
|
|
|
|
|
const options = {
|
|
|
|
read: false,
|
|
|
|
write: false,
|
|
|
|
append: false,
|
|
|
|
truncate: false,
|
|
|
|
create: false,
|
|
|
|
createNew: false,
|
|
|
|
};
|
|
|
|
|
|
|
|
if ((oflags & OFLAGS_CREAT) !== 0) {
|
|
|
|
options.create = true;
|
|
|
|
options.write = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((oflags & OFLAGS_DIRECTORY) !== 0) {
|
|
|
|
// TODO (caspervonb) review if we can
|
|
|
|
// emulate this; unix supports opening
|
|
|
|
// directories, windows does not.
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((oflags & OFLAGS_EXCL) !== 0) {
|
|
|
|
options.createNew = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((oflags & OFLAGS_TRUNC) !== 0) {
|
|
|
|
options.truncate = true;
|
|
|
|
options.write = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (
|
|
|
|
(BigInt(fs_rights_base) &
|
|
|
|
BigInt(RIGHTS_FD_READ | RIGHTS_FD_READDIR)) !=
|
|
|
|
0n
|
|
|
|
) {
|
|
|
|
options.read = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (
|
|
|
|
(BigInt(fs_rights_base) &
|
|
|
|
BigInt(
|
|
|
|
RIGHTS_FD_DATASYNC |
|
|
|
|
RIGHTS_FD_WRITE |
|
|
|
|
RIGHTS_FD_ALLOCATE |
|
|
|
|
RIGHTS_FD_FILESTAT_SET_SIZE
|
|
|
|
)) !=
|
|
|
|
0n
|
|
|
|
) {
|
|
|
|
options.write = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((fdflags & FDFLAGS_APPEND) != 0) {
|
|
|
|
options.append = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((fdflags & FDFLAGS_DSYNC) != 0) {
|
|
|
|
// TODO (caspervonb) review if we can emulate this.
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((fdflags & FDFLAGS_NONBLOCK) != 0) {
|
|
|
|
// TODO (caspervonb) review if we can emulate this.
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((fdflags & FDFLAGS_RSYNC) != 0) {
|
|
|
|
// TODO (caspervonb) review if we can emulate this.
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((fdflags & FDFLAGS_SYNC) != 0) {
|
|
|
|
// TODO (caspervonb) review if we can emulate this.
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!options.read && !options.write && !options.truncate) {
|
|
|
|
options.read = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
try {
|
|
|
|
const handle = Deno.openSync(path, options);
|
|
|
|
const opened_fd =
|
|
|
|
this.fds.push({
|
|
|
|
handle,
|
|
|
|
path,
|
|
|
|
}) - 1;
|
|
|
|
|
|
|
|
const view = new DataView(this.memory.buffer);
|
|
|
|
view.setUint32(opened_fd_out, opened_fd, true);
|
|
|
|
} catch (err) {
|
|
|
|
return errno(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERRNO_SUCCESS;
|
|
|
|
},
|
|
|
|
|
|
|
|
path_readlink: (
|
|
|
|
fd: number,
|
|
|
|
path_ptr: number,
|
|
|
|
path_len: number,
|
|
|
|
buf_ptr: number,
|
|
|
|
buf_len: number,
|
|
|
|
bufused_out: number
|
|
|
|
): number => {
|
|
|
|
const entry = this.fds[fd];
|
|
|
|
if (!entry) {
|
|
|
|
return ERRNO_BADF;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!entry.path) {
|
|
|
|
return ERRNO_INVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
const view = new DataView(this.memory.buffer);
|
|
|
|
const heap = new Uint8Array(this.memory.buffer);
|
|
|
|
|
|
|
|
const data = new Uint8Array(this.memory.buffer, path_ptr, path_len);
|
|
|
|
const path = resolve(entry.path, new TextDecoder().decode(data));
|
|
|
|
|
|
|
|
try {
|
|
|
|
const link = Deno.readLinkSync(path);
|
|
|
|
const data = new TextEncoder().encode(link);
|
|
|
|
heap.set(new Uint8Array(data, 0, buf_len), buf_ptr);
|
|
|
|
|
|
|
|
const bufused = Math.min(data.byteLength, buf_len);
|
|
|
|
view.setUint32(bufused_out, bufused, true);
|
|
|
|
} catch (err) {
|
|
|
|
return errno(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERRNO_SUCCESS;
|
|
|
|
},
|
|
|
|
|
|
|
|
path_remove_directory: (
|
|
|
|
fd: number,
|
|
|
|
path_ptr: number,
|
|
|
|
path_len: number
|
|
|
|
): number => {
|
|
|
|
const entry = this.fds[fd];
|
|
|
|
if (!entry) {
|
|
|
|
return ERRNO_BADF;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!entry.path) {
|
|
|
|
return ERRNO_INVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
const text = new TextDecoder();
|
|
|
|
const data = new Uint8Array(this.memory.buffer, path_ptr, path_len);
|
|
|
|
const path = resolve(entry.path, text.decode(data));
|
|
|
|
|
|
|
|
try {
|
|
|
|
if (!Deno.statSync(path).isDirectory) {
|
|
|
|
return ERRNO_NOTDIR;
|
|
|
|
}
|
|
|
|
|
|
|
|
Deno.removeSync(path);
|
|
|
|
} catch (err) {
|
|
|
|
return errno(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERRNO_SUCCESS;
|
|
|
|
},
|
|
|
|
|
|
|
|
path_rename: (
|
|
|
|
fd: number,
|
|
|
|
old_path_ptr: number,
|
|
|
|
old_path_len: number,
|
|
|
|
new_fd: number,
|
|
|
|
new_path_ptr: number,
|
|
|
|
new_path_len: number
|
|
|
|
): number => {
|
|
|
|
const old_entry = this.fds[fd];
|
|
|
|
const new_entry = this.fds[new_fd];
|
|
|
|
if (!old_entry || !new_entry) {
|
|
|
|
return ERRNO_BADF;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!old_entry.path || !new_entry.path) {
|
|
|
|
return ERRNO_INVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
const text = new TextDecoder();
|
|
|
|
const old_data = new Uint8Array(
|
|
|
|
this.memory.buffer,
|
|
|
|
old_path_ptr,
|
|
|
|
old_path_len
|
|
|
|
);
|
|
|
|
const old_path = resolve(old_entry.path, text.decode(old_data));
|
|
|
|
const new_data = new Uint8Array(
|
|
|
|
this.memory.buffer,
|
|
|
|
new_path_ptr,
|
|
|
|
new_path_len
|
|
|
|
);
|
|
|
|
const new_path = resolve(new_entry.path, text.decode(new_data));
|
|
|
|
|
|
|
|
try {
|
|
|
|
Deno.renameSync(old_path, new_path);
|
|
|
|
} catch (err) {
|
|
|
|
return errno(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERRNO_SUCCESS;
|
|
|
|
},
|
|
|
|
|
|
|
|
path_symlink: (
|
|
|
|
old_path_ptr: number,
|
|
|
|
old_path_len: number,
|
|
|
|
fd: number,
|
|
|
|
new_path_ptr: number,
|
|
|
|
new_path_len: number
|
|
|
|
): number => {
|
|
|
|
const entry = this.fds[fd];
|
|
|
|
if (!entry) {
|
|
|
|
return ERRNO_BADF;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!entry.path) {
|
|
|
|
return ERRNO_INVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
const text = new TextDecoder();
|
|
|
|
const old_data = new Uint8Array(
|
|
|
|
this.memory.buffer,
|
|
|
|
old_path_ptr,
|
|
|
|
old_path_len
|
|
|
|
);
|
|
|
|
const old_path = text.decode(old_data);
|
|
|
|
const new_data = new Uint8Array(
|
|
|
|
this.memory.buffer,
|
|
|
|
new_path_ptr,
|
|
|
|
new_path_len
|
|
|
|
);
|
|
|
|
const new_path = resolve(entry.path, text.decode(new_data));
|
|
|
|
|
|
|
|
try {
|
|
|
|
Deno.symlinkSync(old_path, new_path);
|
|
|
|
} catch (err) {
|
|
|
|
return errno(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERRNO_SUCCESS;
|
|
|
|
},
|
|
|
|
|
|
|
|
path_unlink_file: (
|
|
|
|
fd: number,
|
|
|
|
path_ptr: number,
|
|
|
|
path_len: number
|
|
|
|
): number => {
|
|
|
|
const entry = this.fds[fd];
|
|
|
|
if (!entry) {
|
|
|
|
return ERRNO_BADF;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!entry.path) {
|
|
|
|
return ERRNO_INVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
const text = new TextDecoder();
|
|
|
|
const data = new Uint8Array(this.memory.buffer, path_ptr, path_len);
|
|
|
|
const path = resolve(entry.path, text.decode(data));
|
|
|
|
|
|
|
|
try {
|
|
|
|
Deno.removeSync(path);
|
|
|
|
} catch (err) {
|
|
|
|
return errno(err);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ERRNO_SUCCESS;
|
|
|
|
},
|
|
|
|
|
|
|
|
poll_oneoff: (
|
|
|
|
in_ptr: number,
|
|
|
|
out_ptr: number,
|
|
|
|
nsubscriptions: number,
|
|
|
|
nevents_out: number
|
|
|
|
): number => {
|
|
|
|
return ERRNO_NOSYS;
|
|
|
|
},
|
|
|
|
|
|
|
|
proc_exit: (rval: number): never => {
|
|
|
|
Deno.exit(rval);
|
|
|
|
},
|
|
|
|
|
|
|
|
proc_raise: (sig: number): number => {
|
|
|
|
return ERRNO_NOSYS;
|
|
|
|
},
|
|
|
|
|
|
|
|
sched_yield: (): number => {
|
|
|
|
return ERRNO_SUCCESS;
|
|
|
|
},
|
|
|
|
|
|
|
|
random_get: (buf_ptr: number, buf_len: number): number => {
|
|
|
|
const buffer = new Uint8Array(this.memory.buffer, buf_ptr, buf_len);
|
|
|
|
crypto.getRandomValues(buffer);
|
|
|
|
|
|
|
|
return ERRNO_SUCCESS;
|
|
|
|
},
|
|
|
|
|
|
|
|
sock_recv: (
|
|
|
|
fd: number,
|
|
|
|
ri_data_ptr: number,
|
|
|
|
ri_data_len: number,
|
|
|
|
ri_flags: number,
|
|
|
|
ro_datalen_out: number,
|
|
|
|
ro_flags_out: number
|
|
|
|
): number => {
|
|
|
|
return ERRNO_NOSYS;
|
|
|
|
},
|
|
|
|
|
|
|
|
sock_send: (
|
|
|
|
fd: number,
|
|
|
|
si_data_ptr: number,
|
|
|
|
si_data_len: number,
|
|
|
|
si_flags: number,
|
|
|
|
so_datalen_out: number
|
|
|
|
): number => {
|
|
|
|
return ERRNO_NOSYS;
|
|
|
|
},
|
|
|
|
|
|
|
|
sock_shutdown: (fd: number, how: number): number => {
|
|
|
|
return ERRNO_NOSYS;
|
|
|
|
},
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|