@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/kernel-worker.js
CHANGED
|
@@ -97,6 +97,9 @@ var MemoryMeta = class {
|
|
|
97
97
|
async get(paths) {
|
|
98
98
|
return paths.map((path) => this.entries.get(path));
|
|
99
99
|
}
|
|
100
|
+
async fresh(path) {
|
|
101
|
+
return this.entries.get(path);
|
|
102
|
+
}
|
|
100
103
|
async update(path, change) {
|
|
101
104
|
this.set(path, change(this.entries.get(path)));
|
|
102
105
|
}
|
|
@@ -193,6 +196,16 @@ var IndexedDbMeta = class {
|
|
|
193
196
|
}
|
|
194
197
|
return paths.map((path) => this.cache.get(path) ?? void 0);
|
|
195
198
|
}
|
|
199
|
+
async fresh(path) {
|
|
200
|
+
const [transaction, store] = this.transaction("readonly");
|
|
201
|
+
const request2 = store.get(path);
|
|
202
|
+
let entry;
|
|
203
|
+
request2.onsuccess = () => {
|
|
204
|
+
entry = request2.result ?? void 0;
|
|
205
|
+
};
|
|
206
|
+
await settle(transaction, () => void 0);
|
|
207
|
+
return entry;
|
|
208
|
+
}
|
|
196
209
|
async update(path, change) {
|
|
197
210
|
this.settleRemoves();
|
|
198
211
|
const [transaction, store] = this.transaction("readwrite");
|
|
@@ -207,6 +220,19 @@ var IndexedDbMeta = class {
|
|
|
207
220
|
this.changed({ paths: [path] });
|
|
208
221
|
this.cache.set(path, next2 ?? null);
|
|
209
222
|
}
|
|
223
|
+
async updateMany(changes) {
|
|
224
|
+
const [transaction, store] = this.transaction("readwrite");
|
|
225
|
+
for (const { path, change } of changes) {
|
|
226
|
+
const request2 = store.get(path);
|
|
227
|
+
request2.onsuccess = () => store.put(change(request2.result));
|
|
228
|
+
}
|
|
229
|
+
await settle(transaction, () => void 0);
|
|
230
|
+
this.changed({ paths: changes.map(({ path }) => path) });
|
|
231
|
+
}
|
|
232
|
+
close() {
|
|
233
|
+
this.channel.close();
|
|
234
|
+
this.db.close();
|
|
235
|
+
}
|
|
210
236
|
async move(from, to, root) {
|
|
211
237
|
this.settleRemoves();
|
|
212
238
|
const [transaction, store] = this.transaction("readwrite");
|
|
@@ -326,6 +352,12 @@ async function lutimesOf(fs, path, atime, mtime) {
|
|
|
326
352
|
function mayLink(fs, path) {
|
|
327
353
|
return fs.links?.(path) ?? true;
|
|
328
354
|
}
|
|
355
|
+
function modeOption(mode) {
|
|
356
|
+
if (!Number.isInteger(mode) || mode < 0 || mode > 4095) {
|
|
357
|
+
throw fsError("EINVAL", `not a mode: ${String(mode)}`);
|
|
358
|
+
}
|
|
359
|
+
return mode;
|
|
360
|
+
}
|
|
329
361
|
function fsError(code, path) {
|
|
330
362
|
return Object.assign(new Error(`${code}: ${path}`), { code });
|
|
331
363
|
}
|
|
@@ -857,7 +889,8 @@ function sidecar(meta) {
|
|
|
857
889
|
const guarded2 = (op) => (...args) => meta[op].apply(meta, args).catch((err) => {
|
|
858
890
|
throw translate(err, pathOf(args), "sidecar", false);
|
|
859
891
|
});
|
|
860
|
-
const
|
|
892
|
+
const names = meta.fresh ? [...META_OPS, "fresh"] : META_OPS;
|
|
893
|
+
const ops = Object.fromEntries(names.map((op) => [op, guarded2(op)]));
|
|
861
894
|
if (meta.absent) ops.absent = meta.absent.bind(meta);
|
|
862
895
|
const { removeFile } = meta;
|
|
863
896
|
if (removeFile)
|
|
@@ -985,6 +1018,24 @@ var OpfsFs = class {
|
|
|
985
1018
|
committed(target) {
|
|
986
1019
|
if (this.remote?.watched()) this.remote.wrote(target);
|
|
987
1020
|
}
|
|
1021
|
+
counted = [];
|
|
1022
|
+
async stamp(path) {
|
|
1023
|
+
const entry = this.meta.fresh ? await this.meta.fresh(path) : (await this.meta.get([path]))[0];
|
|
1024
|
+
return String(entry?.writes ?? 0);
|
|
1025
|
+
}
|
|
1026
|
+
async counting(target) {
|
|
1027
|
+
if (!isProtected(this.counted, target)) return;
|
|
1028
|
+
await this.meta.update(target, (entry) => ({
|
|
1029
|
+
...entry,
|
|
1030
|
+
path: target,
|
|
1031
|
+
writes: (entry?.writes ?? 0) + 1
|
|
1032
|
+
}));
|
|
1033
|
+
}
|
|
1034
|
+
async recounting(handle, target) {
|
|
1035
|
+
if (this.counted.length === 0) return;
|
|
1036
|
+
const where = await this.root.resolve(handle).catch(() => null);
|
|
1037
|
+
await this.counting(where ? `/${where.join("/")}` : target);
|
|
1038
|
+
}
|
|
988
1039
|
resolvePath(base, path) {
|
|
989
1040
|
return resolvePath(base, path);
|
|
990
1041
|
}
|
|
@@ -1043,6 +1094,7 @@ var OpfsFs = class {
|
|
|
1043
1094
|
guarded = [];
|
|
1044
1095
|
protect(prefixes2) {
|
|
1045
1096
|
this.guarded = prefixes2;
|
|
1097
|
+
this.counted = prefixes2;
|
|
1046
1098
|
}
|
|
1047
1099
|
unguarded() {
|
|
1048
1100
|
return Object.create(this, { guarded: { value: [] } });
|
|
@@ -1379,9 +1431,10 @@ var OpfsFs = class {
|
|
|
1379
1431
|
return this.retrying(
|
|
1380
1432
|
path,
|
|
1381
1433
|
async () => {
|
|
1434
|
+
const stamp = await this.stamp(path);
|
|
1382
1435
|
const file = await handle.getFile();
|
|
1383
1436
|
const bytes = new Uint8Array(await file.arrayBuffer());
|
|
1384
|
-
return { bytes, version: `${file.lastModified}:${file.size}` };
|
|
1437
|
+
return { bytes, version: `${file.lastModified}:${file.size}:${stamp}` };
|
|
1385
1438
|
},
|
|
1386
1439
|
false
|
|
1387
1440
|
);
|
|
@@ -1391,8 +1444,9 @@ var OpfsFs = class {
|
|
|
1391
1444
|
return this.retrying(
|
|
1392
1445
|
path,
|
|
1393
1446
|
async () => {
|
|
1447
|
+
const stamp = await this.stamp(path);
|
|
1394
1448
|
const file = await handle.getFile();
|
|
1395
|
-
return `${file.lastModified}:${file.size}`;
|
|
1449
|
+
return `${file.lastModified}:${file.size}:${stamp}`;
|
|
1396
1450
|
},
|
|
1397
1451
|
false
|
|
1398
1452
|
);
|
|
@@ -1407,14 +1461,24 @@ var OpfsFs = class {
|
|
|
1407
1461
|
}
|
|
1408
1462
|
async pwrite(path, offset, bytes) {
|
|
1409
1463
|
const [handle, , target] = await this.fileFor(path);
|
|
1410
|
-
await this.
|
|
1464
|
+
await this.counting(target);
|
|
1465
|
+
try {
|
|
1466
|
+
await this.retrying(path, () => positioned(handle, (io) => io.write(offset, bytes)), true);
|
|
1467
|
+
} finally {
|
|
1468
|
+
await this.recounting(handle, target);
|
|
1469
|
+
}
|
|
1411
1470
|
this.written(target);
|
|
1412
1471
|
}
|
|
1413
1472
|
async truncate(path, size) {
|
|
1414
1473
|
const handle = await this.existing(path, true);
|
|
1415
1474
|
const resolve2 = this.ranged || this.remote?.watched();
|
|
1416
|
-
const target = resolve2 ? (await this.locate(path, true)).path : path;
|
|
1417
|
-
await this.
|
|
1475
|
+
const target = resolve2 || this.counted.length > 0 ? (await this.locate(path, true)).path : path;
|
|
1476
|
+
await this.counting(target);
|
|
1477
|
+
try {
|
|
1478
|
+
await this.retrying(path, () => positioned(handle, (io) => io.truncate(size)), true);
|
|
1479
|
+
} finally {
|
|
1480
|
+
await this.recounting(handle, target);
|
|
1481
|
+
}
|
|
1418
1482
|
this.written(target);
|
|
1419
1483
|
}
|
|
1420
1484
|
async writeSession(path, truncate) {
|
|
@@ -2339,7 +2403,9 @@ function id(value) {
|
|
|
2339
2403
|
return value;
|
|
2340
2404
|
}
|
|
2341
2405
|
function changeCred(cur, change) {
|
|
2342
|
-
if (typeof change !== "object" || change === null
|
|
2406
|
+
if (typeof change !== "object" || change === null || Array.isArray(change)) {
|
|
2407
|
+
throw fsError("EINVAL", "not a change");
|
|
2408
|
+
}
|
|
2343
2409
|
const privileged = cur.euid === 0;
|
|
2344
2410
|
const next2 = copyCred(cur);
|
|
2345
2411
|
for (const keys of [UIDS, GIDS]) {
|
|
@@ -2514,6 +2580,10 @@ var KernelError = class extends Error {
|
|
|
2514
2580
|
if (detail !== void 0) this.detail = detail;
|
|
2515
2581
|
}
|
|
2516
2582
|
};
|
|
2583
|
+
function openAccess(flags2) {
|
|
2584
|
+
const mode = flags2 & 3;
|
|
2585
|
+
return mode === 0 ? "read" : mode === 1 ? "write" : "both";
|
|
2586
|
+
}
|
|
2517
2587
|
function pollFile(file) {
|
|
2518
2588
|
return file.poll?.() ?? { readable: !!file.read, writable: !!file.write, hangup: false };
|
|
2519
2589
|
}
|
|
@@ -13189,17 +13259,15 @@ var WasmProcess = class {
|
|
|
13189
13259
|
const file = tty.file();
|
|
13190
13260
|
return this.fds.install(this.options.outputFilter?.(file) ?? file, 3);
|
|
13191
13261
|
}
|
|
13192
|
-
openSealed() {
|
|
13262
|
+
openSealed(flags2) {
|
|
13193
13263
|
const broker = this.options.sealed;
|
|
13194
13264
|
if (!broker) throw new KernelError("ENOENT");
|
|
13195
|
-
return this.fds.install(broker.open(), 3);
|
|
13265
|
+
return this.fds.install(broker.open(openAccess(flags2)), 3);
|
|
13196
13266
|
}
|
|
13197
13267
|
async openClipboard(flags2) {
|
|
13198
13268
|
const broker = this.options.clipboard;
|
|
13199
13269
|
if (!broker) throw new KernelError("ENOENT");
|
|
13200
|
-
const
|
|
13201
|
-
const access2 = mode === 0 ? "read" : mode === 1 ? "write" : "both";
|
|
13202
|
-
const file = broker.open(access2, await this.clipboardStamp());
|
|
13270
|
+
const file = broker.open(openAccess(flags2), await this.clipboardStamp());
|
|
13203
13271
|
return this.fds.install(this.options.outputFilter?.(file) ?? file, 3);
|
|
13204
13272
|
}
|
|
13205
13273
|
async clipboardStamp() {
|
|
@@ -13358,7 +13426,7 @@ var WasmProcess = class {
|
|
|
13358
13426
|
case "fd-tty-names":
|
|
13359
13427
|
return { ok: true, kind: "json", json: this.options.jobs?.terminalNames() ?? [] };
|
|
13360
13428
|
case "fd-open-sealed":
|
|
13361
|
-
return { ok: true, kind: "json", json: this.openSealed() };
|
|
13429
|
+
return { ok: true, kind: "json", json: this.openSealed(req.flags) };
|
|
13362
13430
|
case "fd-open-clipboard":
|
|
13363
13431
|
return { ok: true, kind: "json", json: await this.openClipboard(req.flags) };
|
|
13364
13432
|
case "fd-tty-owner":
|
|
@@ -15077,14 +15145,19 @@ var SealedChannel = class {
|
|
|
15077
15145
|
offset = 0;
|
|
15078
15146
|
inflight;
|
|
15079
15147
|
broker;
|
|
15080
|
-
|
|
15148
|
+
access;
|
|
15149
|
+
constructor(broker, access2) {
|
|
15081
15150
|
this.broker = broker;
|
|
15151
|
+
this.access = access2;
|
|
15082
15152
|
}
|
|
15083
15153
|
send(bytes, caller, gone) {
|
|
15154
|
+
if (this.access === "read") {
|
|
15155
|
+
bytes.fill(0);
|
|
15156
|
+
throw new KernelError("EBADF");
|
|
15157
|
+
}
|
|
15084
15158
|
const length2 = bytes.length;
|
|
15085
15159
|
const fields = parseSealed(bytes);
|
|
15086
|
-
this.
|
|
15087
|
-
this.offset = 0;
|
|
15160
|
+
this.drop();
|
|
15088
15161
|
this.inflight?.control.abort("replaced");
|
|
15089
15162
|
const control = new AbortController();
|
|
15090
15163
|
const withdraw = () => control.abort("withdrawn");
|
|
@@ -15120,15 +15193,18 @@ var SealedChannel = class {
|
|
|
15120
15193
|
if (!signal.aborted) return reply;
|
|
15121
15194
|
return signal.reason === "timeout" ? errorReply("ETIMEDOUT", "the vault did not answer within 10 s") : void 0;
|
|
15122
15195
|
}
|
|
15196
|
+
drop() {
|
|
15197
|
+
this.reply?.fill(0);
|
|
15198
|
+
this.reply = void 0;
|
|
15199
|
+
this.offset = 0;
|
|
15200
|
+
}
|
|
15123
15201
|
async read(max, signal) {
|
|
15202
|
+
if (this.access === "write") throw new KernelError("EBADF");
|
|
15124
15203
|
for (; ; ) {
|
|
15125
15204
|
if (this.reply) {
|
|
15126
15205
|
const out = this.reply.slice(this.offset, this.offset + max);
|
|
15127
15206
|
this.offset += out.length;
|
|
15128
|
-
if (this.offset >= this.reply.length)
|
|
15129
|
-
this.reply = void 0;
|
|
15130
|
-
this.offset = 0;
|
|
15131
|
-
}
|
|
15207
|
+
if (this.offset >= this.reply.length) this.drop();
|
|
15132
15208
|
return out;
|
|
15133
15209
|
}
|
|
15134
15210
|
const flight = this.inflight;
|
|
@@ -15161,7 +15237,7 @@ var SealedChannel = class {
|
|
|
15161
15237
|
close() {
|
|
15162
15238
|
this.inflight?.control.abort("withdrawn");
|
|
15163
15239
|
this.inflight = void 0;
|
|
15164
|
-
this.
|
|
15240
|
+
this.drop();
|
|
15165
15241
|
}
|
|
15166
15242
|
};
|
|
15167
15243
|
function swapOf(reply) {
|
|
@@ -15218,12 +15294,14 @@ var SealedBroker = class {
|
|
|
15218
15294
|
control.abort("done");
|
|
15219
15295
|
}
|
|
15220
15296
|
}
|
|
15221
|
-
open() {
|
|
15222
|
-
const channel = new SealedChannel(this);
|
|
15297
|
+
open(access2 = "both") {
|
|
15298
|
+
const channel = new SealedChannel(this, access2);
|
|
15223
15299
|
return new OpenFile({
|
|
15224
|
-
read: (max, signal) => channel.read(max, signal),
|
|
15225
|
-
|
|
15226
|
-
|
|
15300
|
+
...access2 === "write" ? {} : { read: (max, signal) => channel.read(max, signal) },
|
|
15301
|
+
...access2 === "read" ? {} : {
|
|
15302
|
+
write: async () => {
|
|
15303
|
+
throw new KernelError("EINVAL");
|
|
15304
|
+
}
|
|
15227
15305
|
},
|
|
15228
15306
|
poll: () => channel.poll(),
|
|
15229
15307
|
changed: (signal) => channel.changed(signal),
|
|
@@ -16842,7 +16920,10 @@ var SECURE_PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
|
|
16842
16920
|
var DEFAULT_SUDOERS = "%sudo Cmnd *\n";
|
|
16843
16921
|
var SUDO_TIMEOUT_MS = 3e5;
|
|
16844
16922
|
var NAME3 = /^[a-z_][a-z0-9_.-]*$/;
|
|
16845
|
-
var
|
|
16923
|
+
var WORD = String.raw`(?:'[^']*'|"(?:[^"\\]|\\[\s\S])*"|\\[\s\S]|[^\s'"\\])+`;
|
|
16924
|
+
var RULE = new RegExp(
|
|
16925
|
+
String.raw`^(NOPASSWD\s+)?(\S+)\s+(?:\(([^()\s]+)\)\s+)?(?:Cwd\s+(${WORD})\s+)?Cmnd(?:\s+(.*))?$`
|
|
16926
|
+
);
|
|
16846
16927
|
var TERM = /^[A-Za-z0-9._+-]+$/;
|
|
16847
16928
|
var PLAIN = /^[A-Za-z0-9_@%+=:,./-]+$/;
|
|
16848
16929
|
var USAGE = "usage: sudo [-n] [-u user] [--] command [args...]\n sudo -l";
|
|
@@ -16877,17 +16958,25 @@ function validWho(who) {
|
|
|
16877
16958
|
if (who === "ALL") return true;
|
|
16878
16959
|
return NAME3.test(who.startsWith("%") ? who.slice(1) : who);
|
|
16879
16960
|
}
|
|
16961
|
+
function cwdOf(word) {
|
|
16962
|
+
const words2 = splitWords(word);
|
|
16963
|
+
const path = words2?.length === 1 ? words2[0] : "";
|
|
16964
|
+
return path.startsWith("/") ? normalizePath(path) : "";
|
|
16965
|
+
}
|
|
16880
16966
|
function parseRule(line) {
|
|
16881
16967
|
const text = line.trim();
|
|
16882
16968
|
if (text === "" || text.startsWith("#")) return null;
|
|
16883
16969
|
const m = RULE.exec(text);
|
|
16884
16970
|
if (!m) return void 0;
|
|
16885
|
-
const [, nopasswd, who = "", target = "root", rest2 = ""] = m;
|
|
16971
|
+
const [, nopasswd, who = "", target = "root", dir, rest2 = ""] = m;
|
|
16886
16972
|
if (!validWho(who) || target !== "ALL" && !NAME3.test(target)) return void 0;
|
|
16887
|
-
|
|
16973
|
+
const cwd = dir === void 0 ? void 0 : cwdOf(dir);
|
|
16974
|
+
if (cwd === "") return void 0;
|
|
16975
|
+
const rule = { nopasswd: !!nopasswd, who, target, ...cwd !== void 0 ? { cwd } : {} };
|
|
16976
|
+
if (rest2.trim() === "*") return { ...rule, cmnd: "*" };
|
|
16888
16977
|
const cmnd = splitWords(rest2);
|
|
16889
16978
|
if (!cmnd?.[0]?.startsWith("/")) return void 0;
|
|
16890
|
-
return {
|
|
16979
|
+
return { ...rule, cmnd };
|
|
16891
16980
|
}
|
|
16892
16981
|
function flags(parsed2, arg, next2) {
|
|
16893
16982
|
for (let j = 1; j < arg.length; j++) {
|
|
@@ -16926,7 +17015,8 @@ function parseArgs(args) {
|
|
|
16926
17015
|
}
|
|
16927
17016
|
function described(rule) {
|
|
16928
17017
|
const cmnd = rule.cmnd === "*" ? "ALL" : rule.cmnd.map(quoteWord).join(" ");
|
|
16929
|
-
|
|
17018
|
+
const cwd = rule.cwd === void 0 ? "" : `CWD=${quoteWord(rule.cwd)} `;
|
|
17019
|
+
return ` (${rule.target}) ${cwd}${rule.nopasswd ? "NOPASSWD: " : ""}${cmnd}`;
|
|
16930
17020
|
}
|
|
16931
17021
|
var Sudo = class {
|
|
16932
17022
|
o;
|
|
@@ -17066,7 +17156,7 @@ var Sudo = class {
|
|
|
17066
17156
|
if (untrusted) return untrusted;
|
|
17067
17157
|
const argv = [path, ...args];
|
|
17068
17158
|
const matching = rules.filter(
|
|
17069
|
-
(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]))
|
|
17159
|
+
(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]))
|
|
17070
17160
|
);
|
|
17071
17161
|
const grant = () => this.grant(self, target, cred, parsed2.command, path, cwd, call.term);
|
|
17072
17162
|
if (root || matching.some((rule) => rule.nopasswd)) return grant();
|
|
@@ -17088,7 +17178,7 @@ var Sudo = class {
|
|
|
17088
17178
|
}
|
|
17089
17179
|
const changed = await this.untrusted(path, cwd, word);
|
|
17090
17180
|
if (changed) return changed;
|
|
17091
|
-
if (answer === "always" && !await this.remember(self, target, argv)) {
|
|
17181
|
+
if (answer === "always" && !await this.remember(self, target, cwd, argv)) {
|
|
17092
17182
|
return failed2("EIO", "sudo: the rule could not be recorded");
|
|
17093
17183
|
}
|
|
17094
17184
|
return grant();
|
|
@@ -17153,7 +17243,7 @@ ${lines2}
|
|
|
17153
17243
|
requester.removeEventListener("abort", withdraw);
|
|
17154
17244
|
}
|
|
17155
17245
|
}
|
|
17156
|
-
async remember(self, target, argv) {
|
|
17246
|
+
async remember(self, target, cwd, argv) {
|
|
17157
17247
|
const { fs } = this.o;
|
|
17158
17248
|
const path = `${SUDOERS_D}/${self.name}`;
|
|
17159
17249
|
if (!NAME3.test(self.name)) return false;
|
|
@@ -17163,7 +17253,8 @@ ${lines2}
|
|
|
17163
17253
|
const st = await fs.lstat(path).catch(() => void 0);
|
|
17164
17254
|
if (st && !await this.trusted(path)) return false;
|
|
17165
17255
|
const old = st ? await fs.readFile(path) : "";
|
|
17166
|
-
const
|
|
17256
|
+
const words2 = argv.map(quoteWord).join(" ");
|
|
17257
|
+
const line = `NOPASSWD ${self.name} (${target.name}) Cwd ${quoteWord(cwd)} Cmnd ${words2}
|
|
17167
17258
|
`;
|
|
17168
17259
|
const text = old === "" || old.endsWith("\n") ? `${old}${line}` : `${old}
|
|
17169
17260
|
${line}`;
|
|
@@ -18613,17 +18704,21 @@ var Launcher = class {
|
|
|
18613
18704
|
const real = await this.realLayoutPath("/tmp");
|
|
18614
18705
|
const st = real === void 0 ? void 0 : await this.base.lstat(real).catch(() => void 0);
|
|
18615
18706
|
if (real !== void 0 && st?.isDirectory && this.base.hasOwner && !await this.base.hasOwner(real)) {
|
|
18707
|
+
const names = await this.base.readdir(real).catch(() => void 0);
|
|
18616
18708
|
let removed = 0;
|
|
18617
|
-
|
|
18709
|
+
let left = names === void 0 ? 1 : 0;
|
|
18710
|
+
for (const name2 of names ?? []) {
|
|
18618
18711
|
const path = joinName(real, name2);
|
|
18619
|
-
if (await this.base.hasOwner(path)
|
|
18620
|
-
const failed3 = await this.base.rm(path, { recursive: true, force: true }).catch(String);
|
|
18712
|
+
if (await this.base.hasOwner(path)) continue;
|
|
18713
|
+
const failed3 = this.inUse(path) ? "busy" : await this.base.rm(path, { recursive: true, force: true }).catch(String);
|
|
18621
18714
|
if (failed3 === void 0) removed++;
|
|
18715
|
+
else left++;
|
|
18622
18716
|
}
|
|
18623
18717
|
if (removed > 0) {
|
|
18624
18718
|
console.warn(`slicc-kernel users: removed ${removed} entries from /tmp that had no owner`);
|
|
18625
18719
|
}
|
|
18626
|
-
|
|
18720
|
+
if (left === 0)
|
|
18721
|
+
await this.base.chown?.(real, { uid: 0, gid: 0, mode: 1023, follow: false });
|
|
18627
18722
|
}
|
|
18628
18723
|
if (st?.isDirectory) await this.base.chmod(real, 1023);
|
|
18629
18724
|
}
|
|
@@ -19076,7 +19171,12 @@ var USERS_OPS = /* @__PURE__ */ new Set([
|
|
|
19076
19171
|
"groups-add-member",
|
|
19077
19172
|
"groups-remove-member"
|
|
19078
19173
|
]);
|
|
19079
|
-
var ATTEST_OPS = /* @__PURE__ */ new Set([
|
|
19174
|
+
var ATTEST_OPS = /* @__PURE__ */ new Set([
|
|
19175
|
+
"attest",
|
|
19176
|
+
"watch-files",
|
|
19177
|
+
"unwatch-files",
|
|
19178
|
+
"chmod"
|
|
19179
|
+
]);
|
|
19080
19180
|
function isAttestRequest(req) {
|
|
19081
19181
|
return ATTEST_OPS.has(req.op);
|
|
19082
19182
|
}
|
|
@@ -19092,6 +19192,7 @@ function attestOps(port) {
|
|
|
19092
19192
|
const watches = /* @__PURE__ */ new Map();
|
|
19093
19193
|
return async (l, req) => {
|
|
19094
19194
|
if (req.op === "attest") return l.attest(req.path);
|
|
19195
|
+
if (req.op === "chmod") return l.fs.chmod(req.path, modeOption(req.mode)).then(() => true);
|
|
19095
19196
|
if (req.op === "unwatch-files") {
|
|
19096
19197
|
watches.get(req.watch)?.();
|
|
19097
19198
|
return watches.delete(req.watch);
|