@ai-ecoverse/slicc-kernel 1.85.1 → 1.87.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +20 -12
- package/dist/index.js +1 -0
- package/dist/index.js.map +2 -2
- package/dist/kernel-worker.js +141 -40
- package/dist/kernel-worker.js.map +3 -3
- package/dist/meta.js +384 -0
- package/dist/meta.js.map +7 -0
- package/dist/node-process-worker.js +153 -61
- package/dist/node-process-worker.js.map +3 -3
- package/dist/node.js +118 -40
- package/dist/node.js.map +3 -3
- package/dist/process-worker.js +153 -61
- package/dist/process-worker.js.map +3 -3
- package/package.json +3 -2
package/dist/node.js
CHANGED
|
@@ -107,6 +107,12 @@ async function lutimesOf(fs, path, atime, mtime) {
|
|
|
107
107
|
function mayLink(fs, path) {
|
|
108
108
|
return fs.links?.(path) ?? true;
|
|
109
109
|
}
|
|
110
|
+
function modeOption(mode) {
|
|
111
|
+
if (!Number.isInteger(mode) || mode < 0 || mode > 4095) {
|
|
112
|
+
throw fsError("EINVAL", `not a mode: ${String(mode)}`);
|
|
113
|
+
}
|
|
114
|
+
return mode;
|
|
115
|
+
}
|
|
110
116
|
function fsError(code, path) {
|
|
111
117
|
return Object.assign(new Error(`${code}: ${path}`), { code });
|
|
112
118
|
}
|
|
@@ -570,7 +576,9 @@ function id(value) {
|
|
|
570
576
|
return value;
|
|
571
577
|
}
|
|
572
578
|
function changeCred(cur, change) {
|
|
573
|
-
if (typeof change !== "object" || change === null
|
|
579
|
+
if (typeof change !== "object" || change === null || Array.isArray(change)) {
|
|
580
|
+
throw fsError("EINVAL", "not a change");
|
|
581
|
+
}
|
|
574
582
|
const privileged = cur.euid === 0;
|
|
575
583
|
const next2 = copyCred(cur);
|
|
576
584
|
for (const keys of [UIDS, GIDS]) {
|
|
@@ -745,6 +753,10 @@ var KernelError = class extends Error {
|
|
|
745
753
|
if (detail !== void 0) this.detail = detail;
|
|
746
754
|
}
|
|
747
755
|
};
|
|
756
|
+
function openAccess(flags2) {
|
|
757
|
+
const mode = flags2 & 3;
|
|
758
|
+
return mode === 0 ? "read" : mode === 1 ? "write" : "both";
|
|
759
|
+
}
|
|
748
760
|
function pollFile(file) {
|
|
749
761
|
return file.poll?.() ?? { readable: !!file.read, writable: !!file.write, hangup: false };
|
|
750
762
|
}
|
|
@@ -3002,6 +3014,9 @@ var MemoryMeta = class {
|
|
|
3002
3014
|
async get(paths) {
|
|
3003
3015
|
return paths.map((path) => this.entries.get(path));
|
|
3004
3016
|
}
|
|
3017
|
+
async fresh(path) {
|
|
3018
|
+
return this.entries.get(path);
|
|
3019
|
+
}
|
|
3005
3020
|
async update(path, change) {
|
|
3006
3021
|
this.set(path, change(this.entries.get(path)));
|
|
3007
3022
|
}
|
|
@@ -3473,7 +3488,8 @@ function sidecar(meta) {
|
|
|
3473
3488
|
const guarded3 = (op) => (...args) => meta[op].apply(meta, args).catch((err) => {
|
|
3474
3489
|
throw translate(err, pathOf(args), "sidecar", false);
|
|
3475
3490
|
});
|
|
3476
|
-
const
|
|
3491
|
+
const names = meta.fresh ? [...META_OPS, "fresh"] : META_OPS;
|
|
3492
|
+
const ops = Object.fromEntries(names.map((op) => [op, guarded3(op)]));
|
|
3477
3493
|
if (meta.absent) ops.absent = meta.absent.bind(meta);
|
|
3478
3494
|
const { removeFile } = meta;
|
|
3479
3495
|
if (removeFile)
|
|
@@ -3597,6 +3613,24 @@ var OpfsFs = class {
|
|
|
3597
3613
|
committed(target) {
|
|
3598
3614
|
if (this.remote?.watched()) this.remote.wrote(target);
|
|
3599
3615
|
}
|
|
3616
|
+
counted = [];
|
|
3617
|
+
async stamp(path) {
|
|
3618
|
+
const entry = this.meta.fresh ? await this.meta.fresh(path) : (await this.meta.get([path]))[0];
|
|
3619
|
+
return String(entry?.writes ?? 0);
|
|
3620
|
+
}
|
|
3621
|
+
async counting(target) {
|
|
3622
|
+
if (!isProtected(this.counted, target)) return;
|
|
3623
|
+
await this.meta.update(target, (entry) => ({
|
|
3624
|
+
...entry,
|
|
3625
|
+
path: target,
|
|
3626
|
+
writes: (entry?.writes ?? 0) + 1
|
|
3627
|
+
}));
|
|
3628
|
+
}
|
|
3629
|
+
async recounting(handle, target) {
|
|
3630
|
+
if (this.counted.length === 0) return;
|
|
3631
|
+
const where = await this.root.resolve(handle).catch(() => null);
|
|
3632
|
+
await this.counting(where ? `/${where.join("/")}` : target);
|
|
3633
|
+
}
|
|
3600
3634
|
resolvePath(base, path) {
|
|
3601
3635
|
return resolvePath(base, path);
|
|
3602
3636
|
}
|
|
@@ -3655,6 +3689,7 @@ var OpfsFs = class {
|
|
|
3655
3689
|
guarded = [];
|
|
3656
3690
|
protect(prefixes2) {
|
|
3657
3691
|
this.guarded = prefixes2;
|
|
3692
|
+
this.counted = prefixes2;
|
|
3658
3693
|
}
|
|
3659
3694
|
unguarded() {
|
|
3660
3695
|
return Object.create(this, { guarded: { value: [] } });
|
|
@@ -3991,9 +4026,10 @@ var OpfsFs = class {
|
|
|
3991
4026
|
return this.retrying(
|
|
3992
4027
|
path,
|
|
3993
4028
|
async () => {
|
|
4029
|
+
const stamp = await this.stamp(path);
|
|
3994
4030
|
const file = await handle.getFile();
|
|
3995
4031
|
const bytes = new Uint8Array(await file.arrayBuffer());
|
|
3996
|
-
return { bytes, version: `${file.lastModified}:${file.size}` };
|
|
4032
|
+
return { bytes, version: `${file.lastModified}:${file.size}:${stamp}` };
|
|
3997
4033
|
},
|
|
3998
4034
|
false
|
|
3999
4035
|
);
|
|
@@ -4003,8 +4039,9 @@ var OpfsFs = class {
|
|
|
4003
4039
|
return this.retrying(
|
|
4004
4040
|
path,
|
|
4005
4041
|
async () => {
|
|
4042
|
+
const stamp = await this.stamp(path);
|
|
4006
4043
|
const file = await handle.getFile();
|
|
4007
|
-
return `${file.lastModified}:${file.size}`;
|
|
4044
|
+
return `${file.lastModified}:${file.size}:${stamp}`;
|
|
4008
4045
|
},
|
|
4009
4046
|
false
|
|
4010
4047
|
);
|
|
@@ -4019,14 +4056,24 @@ var OpfsFs = class {
|
|
|
4019
4056
|
}
|
|
4020
4057
|
async pwrite(path, offset, bytes) {
|
|
4021
4058
|
const [handle, , target] = await this.fileFor(path);
|
|
4022
|
-
await this.
|
|
4059
|
+
await this.counting(target);
|
|
4060
|
+
try {
|
|
4061
|
+
await this.retrying(path, () => positioned(handle, (io) => io.write(offset, bytes)), true);
|
|
4062
|
+
} finally {
|
|
4063
|
+
await this.recounting(handle, target);
|
|
4064
|
+
}
|
|
4023
4065
|
this.written(target);
|
|
4024
4066
|
}
|
|
4025
4067
|
async truncate(path, size) {
|
|
4026
4068
|
const handle = await this.existing(path, true);
|
|
4027
4069
|
const resolve2 = this.ranged || this.remote?.watched();
|
|
4028
|
-
const target = resolve2 ? (await this.locate(path, true)).path : path;
|
|
4029
|
-
await this.
|
|
4070
|
+
const target = resolve2 || this.counted.length > 0 ? (await this.locate(path, true)).path : path;
|
|
4071
|
+
await this.counting(target);
|
|
4072
|
+
try {
|
|
4073
|
+
await this.retrying(path, () => positioned(handle, (io) => io.truncate(size)), true);
|
|
4074
|
+
} finally {
|
|
4075
|
+
await this.recounting(handle, target);
|
|
4076
|
+
}
|
|
4030
4077
|
this.written(target);
|
|
4031
4078
|
}
|
|
4032
4079
|
async writeSession(path, truncate) {
|
|
@@ -12854,17 +12901,15 @@ var WasmProcess = class {
|
|
|
12854
12901
|
const file = tty.file();
|
|
12855
12902
|
return this.fds.install(this.options.outputFilter?.(file) ?? file, 3);
|
|
12856
12903
|
}
|
|
12857
|
-
openSealed() {
|
|
12904
|
+
openSealed(flags2) {
|
|
12858
12905
|
const broker = this.options.sealed;
|
|
12859
12906
|
if (!broker) throw new KernelError("ENOENT");
|
|
12860
|
-
return this.fds.install(broker.open(), 3);
|
|
12907
|
+
return this.fds.install(broker.open(openAccess(flags2)), 3);
|
|
12861
12908
|
}
|
|
12862
12909
|
async openClipboard(flags2) {
|
|
12863
12910
|
const broker = this.options.clipboard;
|
|
12864
12911
|
if (!broker) throw new KernelError("ENOENT");
|
|
12865
|
-
const
|
|
12866
|
-
const access2 = mode === 0 ? "read" : mode === 1 ? "write" : "both";
|
|
12867
|
-
const file = broker.open(access2, await this.clipboardStamp());
|
|
12912
|
+
const file = broker.open(openAccess(flags2), await this.clipboardStamp());
|
|
12868
12913
|
return this.fds.install(this.options.outputFilter?.(file) ?? file, 3);
|
|
12869
12914
|
}
|
|
12870
12915
|
async clipboardStamp() {
|
|
@@ -13023,7 +13068,7 @@ var WasmProcess = class {
|
|
|
13023
13068
|
case "fd-tty-names":
|
|
13024
13069
|
return { ok: true, kind: "json", json: this.options.jobs?.terminalNames() ?? [] };
|
|
13025
13070
|
case "fd-open-sealed":
|
|
13026
|
-
return { ok: true, kind: "json", json: this.openSealed() };
|
|
13071
|
+
return { ok: true, kind: "json", json: this.openSealed(req.flags) };
|
|
13027
13072
|
case "fd-open-clipboard":
|
|
13028
13073
|
return { ok: true, kind: "json", json: await this.openClipboard(req.flags) };
|
|
13029
13074
|
case "fd-tty-owner":
|
|
@@ -14742,14 +14787,19 @@ var SealedChannel = class {
|
|
|
14742
14787
|
offset = 0;
|
|
14743
14788
|
inflight;
|
|
14744
14789
|
broker;
|
|
14745
|
-
|
|
14790
|
+
access;
|
|
14791
|
+
constructor(broker, access2) {
|
|
14746
14792
|
this.broker = broker;
|
|
14793
|
+
this.access = access2;
|
|
14747
14794
|
}
|
|
14748
14795
|
send(bytes, caller, gone) {
|
|
14796
|
+
if (this.access === "read") {
|
|
14797
|
+
bytes.fill(0);
|
|
14798
|
+
throw new KernelError("EBADF");
|
|
14799
|
+
}
|
|
14749
14800
|
const length2 = bytes.length;
|
|
14750
14801
|
const fields = parseSealed(bytes);
|
|
14751
|
-
this.
|
|
14752
|
-
this.offset = 0;
|
|
14802
|
+
this.drop();
|
|
14753
14803
|
this.inflight?.control.abort("replaced");
|
|
14754
14804
|
const control = new AbortController();
|
|
14755
14805
|
const withdraw = () => control.abort("withdrawn");
|
|
@@ -14785,15 +14835,18 @@ var SealedChannel = class {
|
|
|
14785
14835
|
if (!signal.aborted) return reply;
|
|
14786
14836
|
return signal.reason === "timeout" ? errorReply("ETIMEDOUT", "the vault did not answer within 10 s") : void 0;
|
|
14787
14837
|
}
|
|
14838
|
+
drop() {
|
|
14839
|
+
this.reply?.fill(0);
|
|
14840
|
+
this.reply = void 0;
|
|
14841
|
+
this.offset = 0;
|
|
14842
|
+
}
|
|
14788
14843
|
async read(max, signal) {
|
|
14844
|
+
if (this.access === "write") throw new KernelError("EBADF");
|
|
14789
14845
|
for (; ; ) {
|
|
14790
14846
|
if (this.reply) {
|
|
14791
14847
|
const out = this.reply.slice(this.offset, this.offset + max);
|
|
14792
14848
|
this.offset += out.length;
|
|
14793
|
-
if (this.offset >= this.reply.length)
|
|
14794
|
-
this.reply = void 0;
|
|
14795
|
-
this.offset = 0;
|
|
14796
|
-
}
|
|
14849
|
+
if (this.offset >= this.reply.length) this.drop();
|
|
14797
14850
|
return out;
|
|
14798
14851
|
}
|
|
14799
14852
|
const flight = this.inflight;
|
|
@@ -14826,7 +14879,7 @@ var SealedChannel = class {
|
|
|
14826
14879
|
close() {
|
|
14827
14880
|
this.inflight?.control.abort("withdrawn");
|
|
14828
14881
|
this.inflight = void 0;
|
|
14829
|
-
this.
|
|
14882
|
+
this.drop();
|
|
14830
14883
|
}
|
|
14831
14884
|
};
|
|
14832
14885
|
function swapOf(reply) {
|
|
@@ -14883,12 +14936,14 @@ var SealedBroker = class {
|
|
|
14883
14936
|
control.abort("done");
|
|
14884
14937
|
}
|
|
14885
14938
|
}
|
|
14886
|
-
open() {
|
|
14887
|
-
const channel = new SealedChannel(this);
|
|
14939
|
+
open(access2 = "both") {
|
|
14940
|
+
const channel = new SealedChannel(this, access2);
|
|
14888
14941
|
return new OpenFile({
|
|
14889
|
-
read: (max, signal) => channel.read(max, signal),
|
|
14890
|
-
|
|
14891
|
-
|
|
14942
|
+
...access2 === "write" ? {} : { read: (max, signal) => channel.read(max, signal) },
|
|
14943
|
+
...access2 === "read" ? {} : {
|
|
14944
|
+
write: async () => {
|
|
14945
|
+
throw new KernelError("EINVAL");
|
|
14946
|
+
}
|
|
14892
14947
|
},
|
|
14893
14948
|
poll: () => channel.poll(),
|
|
14894
14949
|
changed: (signal) => channel.changed(signal),
|
|
@@ -16610,7 +16665,10 @@ var SECURE_PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
|
|
16610
16665
|
var DEFAULT_SUDOERS = "%sudo Cmnd *\n";
|
|
16611
16666
|
var SUDO_TIMEOUT_MS = 3e5;
|
|
16612
16667
|
var NAME3 = /^[a-z_][a-z0-9_.-]*$/;
|
|
16613
|
-
var
|
|
16668
|
+
var WORD = String.raw`(?:'[^']*'|"(?:[^"\\]|\\[\s\S])*"|\\[\s\S]|[^\s'"\\])+`;
|
|
16669
|
+
var RULE = new RegExp(
|
|
16670
|
+
String.raw`^(NOPASSWD\s+)?(\S+)\s+(?:\(([^()\s]+)\)\s+)?(?:Cwd\s+(${WORD})\s+)?Cmnd(?:\s+(.*))?$`
|
|
16671
|
+
);
|
|
16614
16672
|
var TERM = /^[A-Za-z0-9._+-]+$/;
|
|
16615
16673
|
var PLAIN = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
16616
16674
|
var USAGE = "usage: sudo [-n] [-u user] [--] command [args...]\n sudo -l";
|
|
@@ -16645,17 +16703,25 @@ function validWho(who) {
|
|
|
16645
16703
|
if (who === "ALL") return true;
|
|
16646
16704
|
return NAME3.test(who.startsWith("%") ? who.slice(1) : who);
|
|
16647
16705
|
}
|
|
16706
|
+
function cwdOf(word) {
|
|
16707
|
+
const words2 = splitWords(word);
|
|
16708
|
+
const path = words2?.length === 1 ? words2[0] : "";
|
|
16709
|
+
return path.startsWith("/") ? normalizePath(path) : "";
|
|
16710
|
+
}
|
|
16648
16711
|
function parseRule(line) {
|
|
16649
16712
|
const text = line.trim();
|
|
16650
16713
|
if (text === "" || text.startsWith("#")) return null;
|
|
16651
16714
|
const m = RULE.exec(text);
|
|
16652
16715
|
if (!m) return void 0;
|
|
16653
|
-
const [, nopasswd, who = "", target = "root", rest2 = ""] = m;
|
|
16716
|
+
const [, nopasswd, who = "", target = "root", dir, rest2 = ""] = m;
|
|
16654
16717
|
if (!validWho(who) || target !== "ALL" && !NAME3.test(target)) return void 0;
|
|
16655
|
-
|
|
16718
|
+
const cwd = dir === void 0 ? void 0 : cwdOf(dir);
|
|
16719
|
+
if (cwd === "") return void 0;
|
|
16720
|
+
const rule = { nopasswd: !!nopasswd, who, target, ...cwd !== void 0 ? { cwd } : {} };
|
|
16721
|
+
if (rest2.trim() === "*") return { ...rule, cmnd: "*" };
|
|
16656
16722
|
const cmnd = splitWords(rest2);
|
|
16657
16723
|
if (!cmnd?.[0]?.startsWith("/")) return void 0;
|
|
16658
|
-
return {
|
|
16724
|
+
return { ...rule, cmnd };
|
|
16659
16725
|
}
|
|
16660
16726
|
function flags(parsed2, arg, next2) {
|
|
16661
16727
|
for (let j = 1; j < arg.length; j++) {
|
|
@@ -16694,7 +16760,8 @@ function parseArgs(args) {
|
|
|
16694
16760
|
}
|
|
16695
16761
|
function described(rule) {
|
|
16696
16762
|
const cmnd = rule.cmnd === "*" ? "ALL" : rule.cmnd.map(quoteWord).join(" ");
|
|
16697
|
-
|
|
16763
|
+
const cwd = rule.cwd === void 0 ? "" : `CWD=${quoteWord(rule.cwd)} `;
|
|
16764
|
+
return ` (${rule.target}) ${cwd}${rule.nopasswd ? "NOPASSWD: " : ""}${cmnd}`;
|
|
16698
16765
|
}
|
|
16699
16766
|
var Sudo = class {
|
|
16700
16767
|
o;
|
|
@@ -16834,7 +16901,7 @@ var Sudo = class {
|
|
|
16834
16901
|
if (untrusted) return untrusted;
|
|
16835
16902
|
const argv = [path, ...args];
|
|
16836
16903
|
const matching = rules.filter(
|
|
16837
|
-
(rule) => applies(rule) && (rule.target === "ALL" || rule.target === target.name) && (rule.cmnd === "*" || rule.cmnd.length === argv.length && rule.cmnd.every((w, i) => w === argv[i]))
|
|
16904
|
+
(rule) => applies(rule) && (rule.target === "ALL" || rule.target === target.name) && (rule.cwd === void 0 || rule.cwd === cwd) && (rule.cmnd === "*" || rule.cmnd.length === argv.length && rule.cmnd.every((w, i) => w === argv[i]))
|
|
16838
16905
|
);
|
|
16839
16906
|
const grant = () => this.grant(self, target, cred, parsed2.command, path, cwd, call.term);
|
|
16840
16907
|
if (root || matching.some((rule) => rule.nopasswd)) return grant();
|
|
@@ -16856,7 +16923,7 @@ var Sudo = class {
|
|
|
16856
16923
|
}
|
|
16857
16924
|
const changed = await this.untrusted(path, cwd, word);
|
|
16858
16925
|
if (changed) return changed;
|
|
16859
|
-
if (answer === "always" && !await this.remember(self, target, argv)) {
|
|
16926
|
+
if (answer === "always" && !await this.remember(self, target, cwd, argv)) {
|
|
16860
16927
|
return failed2("EIO", "sudo: the rule could not be recorded");
|
|
16861
16928
|
}
|
|
16862
16929
|
return grant();
|
|
@@ -16921,7 +16988,7 @@ ${lines2}
|
|
|
16921
16988
|
requester.removeEventListener("abort", withdraw);
|
|
16922
16989
|
}
|
|
16923
16990
|
}
|
|
16924
|
-
async remember(self, target, argv) {
|
|
16991
|
+
async remember(self, target, cwd, argv) {
|
|
16925
16992
|
const { fs } = this.o;
|
|
16926
16993
|
const path = `${SUDOERS_D}/${self.name}`;
|
|
16927
16994
|
if (!NAME3.test(self.name)) return false;
|
|
@@ -16931,7 +16998,8 @@ ${lines2}
|
|
|
16931
16998
|
const st = await fs.lstat(path).catch(() => void 0);
|
|
16932
16999
|
if (st && !await this.trusted(path)) return false;
|
|
16933
17000
|
const old = st ? await fs.readFile(path) : "";
|
|
16934
|
-
const
|
|
17001
|
+
const words2 = argv.map(quoteWord).join(" ");
|
|
17002
|
+
const line = `NOPASSWD ${self.name} (${target.name}) Cwd ${quoteWord(cwd)} Cmnd ${words2}
|
|
16935
17003
|
`;
|
|
16936
17004
|
const text = old === "" || old.endsWith("\n") ? `${old}${line}` : `${old}
|
|
16937
17005
|
${line}`;
|
|
@@ -18381,17 +18449,21 @@ var Launcher = class {
|
|
|
18381
18449
|
const real = await this.realLayoutPath("/tmp");
|
|
18382
18450
|
const st = real === void 0 ? void 0 : await this.base.lstat(real).catch(() => void 0);
|
|
18383
18451
|
if (real !== void 0 && st?.isDirectory && this.base.hasOwner && !await this.base.hasOwner(real)) {
|
|
18452
|
+
const names = await this.base.readdir(real).catch(() => void 0);
|
|
18384
18453
|
let removed = 0;
|
|
18385
|
-
|
|
18454
|
+
let left = names === void 0 ? 1 : 0;
|
|
18455
|
+
for (const name2 of names ?? []) {
|
|
18386
18456
|
const path = joinName(real, name2);
|
|
18387
|
-
if (await this.base.hasOwner(path)
|
|
18388
|
-
const failed3 = await this.base.rm(path, { recursive: true, force: true }).catch(String);
|
|
18457
|
+
if (await this.base.hasOwner(path)) continue;
|
|
18458
|
+
const failed3 = this.inUse(path) ? "busy" : await this.base.rm(path, { recursive: true, force: true }).catch(String);
|
|
18389
18459
|
if (failed3 === void 0) removed++;
|
|
18460
|
+
else left++;
|
|
18390
18461
|
}
|
|
18391
18462
|
if (removed > 0) {
|
|
18392
18463
|
console.warn(`slicc-kernel users: removed ${removed} entries from /tmp that had no owner`);
|
|
18393
18464
|
}
|
|
18394
|
-
|
|
18465
|
+
if (left === 0)
|
|
18466
|
+
await this.base.chown?.(real, { uid: 0, gid: 0, mode: 1023, follow: false });
|
|
18395
18467
|
}
|
|
18396
18468
|
if (st?.isDirectory) await this.base.chmod(real, 1023);
|
|
18397
18469
|
}
|
|
@@ -20060,11 +20132,17 @@ async function createNodeKernel(options = {}) {
|
|
|
20060
20132
|
close: () => session.close()
|
|
20061
20133
|
};
|
|
20062
20134
|
},
|
|
20063
|
-
async writeFile(path, data) {
|
|
20135
|
+
async writeFile(path, data, options2 = {}) {
|
|
20136
|
+
const mode = options2.mode === void 0 ? void 0 : modeOption(options2.mode);
|
|
20064
20137
|
const parent = path.slice(0, path.lastIndexOf("/")) || "/";
|
|
20065
20138
|
await launcher.fs.mkdir(parent, { recursive: true });
|
|
20139
|
+
if (mode !== void 0) {
|
|
20140
|
+
await launcher.fs.writeFile(path, "");
|
|
20141
|
+
await launcher.fs.chmod(path, mode);
|
|
20142
|
+
}
|
|
20066
20143
|
await launcher.fs.writeFile(path, data);
|
|
20067
20144
|
},
|
|
20145
|
+
chmod: async (path, mode) => launcher.fs.chmod(path, modeOption(mode)),
|
|
20068
20146
|
readFile: async (path) => launcher.fs.readFileBuffer(path),
|
|
20069
20147
|
mount: (spec) => guard2(() => launcher.mount(spec)),
|
|
20070
20148
|
umount: (target) => guard2(async () => launcher.umount(target)),
|