@ai-ecoverse/slicc-kernel 1.21.1 → 1.22.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.
@@ -87,6 +87,249 @@ var init_signals = __esm({
87
87
  }
88
88
  });
89
89
 
90
+ // src/fs/pages.ts
91
+ var PAGE, READAHEAD, CLEAN_LIMIT, WRITEBACK, RUN, Pages;
92
+ var init_pages = __esm({
93
+ "src/fs/pages.ts"() {
94
+ "use strict";
95
+ PAGE = 64 * 1024;
96
+ READAHEAD = 1024 * 1024;
97
+ CLEAN_LIMIT = 4 * 1024 * 1024;
98
+ WRITEBACK = 8 * 1024 * 1024;
99
+ RUN = 1024 * 1024;
100
+ Pages = class {
101
+ length;
102
+ stored;
103
+ shrink;
104
+ pages = /* @__PURE__ */ new Map();
105
+ dirty = /* @__PURE__ */ new Set();
106
+ free = [];
107
+ pinned = false;
108
+ constructor(size) {
109
+ this.length = size;
110
+ this.stored = size;
111
+ }
112
+ get dirtyBytes() {
113
+ return this.dirty.size * PAGE;
114
+ }
115
+ get changed() {
116
+ return this.dirty.size > 0 || this.shrink !== void 0 || this.length !== this.stored;
117
+ }
118
+ missing(at, length) {
119
+ this.evict();
120
+ const end = Math.min(this.stored, at + length, this.length);
121
+ const runs = [];
122
+ for (let page = Math.floor(at / PAGE); page * PAGE < end; page++) {
123
+ if (this.pages.has(page)) continue;
124
+ const last2 = runs[runs.length - 1];
125
+ if (last2 && last2[0] + last2[1] === page * PAGE) last2[1] += PAGE;
126
+ else runs.push([page * PAGE, PAGE]);
127
+ }
128
+ const last = runs[runs.length - 1];
129
+ if (last) last[1] = Math.max(last[1], Math.min(READAHEAD, this.stored - last[0]));
130
+ return runs.map(([start, n]) => [start, Math.min(n, this.stored - start)]);
131
+ }
132
+ partial(at, length) {
133
+ if (length === 0) return [];
134
+ this.evict();
135
+ const edges = /* @__PURE__ */ new Set([Math.floor(at / PAGE), Math.floor((at + length - 1) / PAGE)]);
136
+ const runs = [];
137
+ for (const page of edges) {
138
+ const start = page * PAGE;
139
+ const covered = at <= start && at + length >= start + PAGE;
140
+ if (covered || this.pages.has(page) || start >= this.stored) continue;
141
+ runs.push([start, Math.min(PAGE, this.stored - start)]);
142
+ }
143
+ return runs;
144
+ }
145
+ fill(start, bytes) {
146
+ for (let at = 0; at < bytes.length; at += PAGE) {
147
+ const page = (start + at) / PAGE;
148
+ if (this.pages.has(page)) continue;
149
+ const part = bytes.subarray(at, Math.min(at + PAGE, bytes.length));
150
+ const fresh = this.take(part.length);
151
+ fresh.set(part);
152
+ this.pages.set(page, fresh);
153
+ }
154
+ }
155
+ read(at, length) {
156
+ const out = new Uint8Array(Math.max(0, Math.min(this.length, at + length) - at));
157
+ this.readInto(at, out);
158
+ return out;
159
+ }
160
+ readInto(at, out) {
161
+ const end = Math.min(this.length, at + out.length);
162
+ for (let pos = at; pos < end; ) {
163
+ const page = Math.floor(pos / PAGE);
164
+ const from = pos - page * PAGE;
165
+ const n = Math.min(PAGE - from, end - pos);
166
+ const bytes = this.pages.get(page);
167
+ if (bytes) out.set(bytes.subarray(from, from + n), pos - at);
168
+ else out.fill(0, pos - at, pos - at + n);
169
+ pos += n;
170
+ }
171
+ return Math.max(0, end - at);
172
+ }
173
+ write(at, bytes) {
174
+ for (let done = 0; done < bytes.length; ) {
175
+ const pos = at + done;
176
+ const page = Math.floor(pos / PAGE);
177
+ const from = pos - page * PAGE;
178
+ const n = Math.min(PAGE - from, bytes.length - done);
179
+ let target = this.pages.get(page);
180
+ if (!target) {
181
+ target = this.take(0);
182
+ this.pages.set(page, target);
183
+ }
184
+ target.set(bytes.subarray(done, done + n), from);
185
+ this.dirty.add(page);
186
+ done += n;
187
+ }
188
+ this.length = Math.max(this.length, at + bytes.length);
189
+ }
190
+ truncate(size) {
191
+ if (size < this.stored) {
192
+ this.stored = size;
193
+ this.shrink = Math.min(this.shrink ?? size, size);
194
+ }
195
+ if (size < this.length) {
196
+ const edge = Math.floor(size / PAGE);
197
+ for (const page of [...this.pages.keys()]) {
198
+ if (page > edge || page === edge && size === edge * PAGE) this.drop(page);
199
+ }
200
+ this.pages.get(edge)?.fill(0, size - edge * PAGE);
201
+ }
202
+ this.length = size;
203
+ }
204
+ plan() {
205
+ const runs = [];
206
+ const sorted = [...this.dirty].sort((a, b) => a - b);
207
+ for (let i = 0; i < sorted.length; ) {
208
+ let j = i + 1;
209
+ const first = sorted[i];
210
+ while (j < sorted.length && sorted[j] === first + (j - i) && sorted[j] * PAGE % RUN !== 0) {
211
+ j++;
212
+ }
213
+ const start = first * PAGE;
214
+ const end = Math.min(this.length, (first + (j - i)) * PAGE);
215
+ const bytes = new Uint8Array(end - start);
216
+ for (let k = i; k < j; k++) {
217
+ const page = this.pages.get(sorted[k]);
218
+ bytes.set(page.subarray(0, Math.min(PAGE, end - (k - i) * PAGE - start)), (k - i) * PAGE);
219
+ }
220
+ runs.push({ offset: start, bytes });
221
+ i = j;
222
+ }
223
+ const written = Math.max(this.stored, ...runs.map((r) => r.offset + r.bytes.length));
224
+ return {
225
+ ...this.shrink !== void 0 ? { shrink: this.shrink } : {},
226
+ runs,
227
+ ...this.length > written ? { extend: this.length } : {}
228
+ };
229
+ }
230
+ flushed() {
231
+ this.dirty.clear();
232
+ this.shrink = void 0;
233
+ this.stored = this.length;
234
+ this.evict();
235
+ }
236
+ pin() {
237
+ this.pinned = true;
238
+ }
239
+ reset(size) {
240
+ if (this.pinned) return;
241
+ for (const page of [...this.pages.keys()]) if (!this.dirty.has(page)) this.drop(page);
242
+ if (this.changed) return;
243
+ this.length = size;
244
+ this.stored = size;
245
+ }
246
+ evict() {
247
+ if (this.pinned) return;
248
+ let clean = (this.pages.size - this.dirty.size) * PAGE;
249
+ for (const page of this.pages.keys()) {
250
+ if (clean <= CLEAN_LIMIT) return;
251
+ if (this.dirty.has(page)) continue;
252
+ this.drop(page);
253
+ clean -= PAGE;
254
+ }
255
+ }
256
+ take(used) {
257
+ const page = this.free.pop();
258
+ if (!page) return new Uint8Array(PAGE);
259
+ page.fill(0, used);
260
+ return page;
261
+ }
262
+ drop(page) {
263
+ const bytes = this.pages.get(page);
264
+ this.pages.delete(page);
265
+ this.dirty.delete(page);
266
+ if (this.free.length < CLEAN_LIMIT / PAGE) this.free.push(bytes);
267
+ }
268
+ };
269
+ }
270
+ });
271
+
272
+ // src/fs/ranged.ts
273
+ var RangedFile;
274
+ var init_ranged = __esm({
275
+ "src/fs/ranged.ts"() {
276
+ "use strict";
277
+ init_pages();
278
+ RangedFile = class {
279
+ pages;
280
+ io;
281
+ pinned = false;
282
+ path;
283
+ constructor(io, path, size) {
284
+ this.io = io;
285
+ this.path = path;
286
+ this.pages = new Pages(size);
287
+ }
288
+ get changed() {
289
+ return this.pages.changed;
290
+ }
291
+ size() {
292
+ return this.pages.length;
293
+ }
294
+ fetch(runs) {
295
+ for (const [start, n] of runs) this.pages.fill(start, this.io.pread(this.path, start, n));
296
+ }
297
+ read(at, length) {
298
+ this.fetch(this.pages.missing(at, length));
299
+ return this.pages.read(at, length);
300
+ }
301
+ readInto(at, out) {
302
+ this.fetch(this.pages.missing(at, out.length));
303
+ return this.pages.readInto(at, out);
304
+ }
305
+ write(at, bytes) {
306
+ this.fetch(this.pages.partial(at, bytes.length));
307
+ this.pages.write(at, bytes);
308
+ if (!this.pinned && this.pages.dirtyBytes >= WRITEBACK) this.flush();
309
+ }
310
+ truncate(size) {
311
+ this.pages.truncate(size);
312
+ }
313
+ flush() {
314
+ if (this.pinned || !this.pages.changed) return;
315
+ const plan = this.pages.plan();
316
+ if (plan.shrink !== void 0) this.io.truncate(this.path, plan.shrink);
317
+ for (const run of plan.runs) this.io.pwrite(this.path, run.offset, run.bytes, true);
318
+ if (plan.extend !== void 0) this.io.truncate(this.path, plan.extend);
319
+ this.pages.flushed();
320
+ }
321
+ pin() {
322
+ this.pinned = true;
323
+ this.pages.pin();
324
+ this.fetch(this.pages.missing(0, this.pages.length));
325
+ }
326
+ reset(size) {
327
+ this.pages.reset(size);
328
+ }
329
+ };
330
+ }
331
+ });
332
+
90
333
  // src/fs/types.ts
91
334
  function normalizePath(path) {
92
335
  const parts = [];
@@ -171,7 +414,8 @@ function createHelpers(Fs, ops) {
171
414
  }
172
415
  function statOf(node) {
173
416
  if (node.live.orphan) {
174
- return { ...node.live.stat, size: node.live.len };
417
+ const size = node.live.ranged?.size() ?? node.live.len;
418
+ return { ...node.live.stat, size };
175
419
  }
176
420
  if (!node.live.stat) {
177
421
  const st = call2(() => bridgeOf(node).lstat(liveNodePath(node)));
@@ -192,6 +436,20 @@ function createHelpers(Fs, ops) {
192
436
  s.len = bytes.length;
193
437
  s.loaded = true;
194
438
  }
439
+ function rangedOf(node) {
440
+ const s = node.live;
441
+ if (s.ranged || !s.ranges) return s.ranged;
442
+ const bridge = bridgeOf(node);
443
+ const path = () => liveNodePath(node);
444
+ const io = {
445
+ pread: (_, at, n) => bridge.pread(path(), at, n),
446
+ pwrite: (_, at, bytes, transfer) => bridge.pwrite(path(), at, bytes, transfer),
447
+ truncate: (_, size) => bridge.truncate(path(), size)
448
+ };
449
+ const st = call2(() => bridge.stat(path()));
450
+ s.ranged = new RangedFile(io, path(), st.size);
451
+ return s.ranged;
452
+ }
195
453
  function ensureCapacity(node, need) {
196
454
  const s = node.live;
197
455
  const cur = s.data ?? new Uint8Array(0);
@@ -203,9 +461,12 @@ function createHelpers(Fs, ops) {
203
461
  }
204
462
  function flushNode(node) {
205
463
  const s = node.live;
206
- if (!s.dirty || !s.data || s.orphan) return;
207
- const bytes = s.data.slice(0, s.len);
208
- call2(() => bridgeOf(node).writeFile(liveNodePath(node), bytes));
464
+ if (!s.dirty || s.orphan || !(s.data || s.ranged)) return;
465
+ if (s.ranged) call2(() => s.ranged?.flush());
466
+ else {
467
+ const bytes = s.data.slice(0, s.len);
468
+ call2(() => bridgeOf(node).writeFile(liveNodePath(node), bytes));
469
+ }
209
470
  s.dirty = false;
210
471
  s.stat = void 0;
211
472
  }
@@ -218,6 +479,12 @@ function createHelpers(Fs, ops) {
218
479
  throw new Fs.ErrnoError(ERRNO_BY_CODE.EFBIG);
219
480
  }
220
481
  }
482
+ const ranged = s.openCount > 0 ? rangedOf(node) : void 0;
483
+ if (ranged) {
484
+ ranged.truncate(size);
485
+ s.dirty = true;
486
+ return;
487
+ }
221
488
  if (s.openCount > 0) {
222
489
  if (size > 0) ensureLoaded(node);
223
490
  else s.loaded = true;
@@ -228,6 +495,12 @@ function createHelpers(Fs, ops) {
228
495
  return;
229
496
  }
230
497
  const path = liveNodePath(node);
498
+ const bridge = bridgeOf(node);
499
+ if (statOf(node).ranged && bridge.truncate) {
500
+ call2(() => bridge.truncate?.(path, size));
501
+ s.stat = void 0;
502
+ return;
503
+ }
231
504
  const bytes = new Uint8Array(size);
232
505
  if (size > 0) {
233
506
  const cur = call2(() => bridgeOf(node).readFile(path));
@@ -246,6 +519,7 @@ function createHelpers(Fs, ops) {
246
519
  childPath,
247
520
  ensureLoaded,
248
521
  ensureCapacity,
522
+ rangedOf,
249
523
  flushNode,
250
524
  truncate
251
525
  };
@@ -257,7 +531,7 @@ function createNodeOps(h) {
257
531
  getattr(node) {
258
532
  const st = statOf(node);
259
533
  const s = node.live;
260
- const size = Fs.isDir(node.mode) ? 4096 : s.loaded ? s.len : st.size;
534
+ const size = Fs.isDir(node.mode) ? 4096 : s.ranged?.size() ?? (s.loaded ? s.len : st.size);
261
535
  const mtime = new Date(st.mtimeMs ?? 0);
262
536
  return {
263
537
  dev: st.dev ?? 1,
@@ -357,7 +631,9 @@ function createNodeOps(h) {
357
631
  }
358
632
  if (open) {
359
633
  statOf(open);
360
- ensureLoaded(open);
634
+ const ranged = h.rangedOf(open);
635
+ if (ranged) ranged.pin();
636
+ else ensureLoaded(open);
361
637
  }
362
638
  call2(() => bridgeOf(parent).unlink(childPath(parent, name)));
363
639
  if (open) open.live.orphan = true;
@@ -390,7 +666,7 @@ function createNodeOps(h) {
390
666
  };
391
667
  }
392
668
  function createStreamOps(h) {
393
- const { Fs, statOf, ensureLoaded, ensureCapacity, flushNode, bridgeOf } = h;
669
+ const { Fs, statOf, ensureLoaded, ensureCapacity, flushNode, bridgeOf, rangedOf } = h;
394
670
  const held = (stream, change) => {
395
671
  const s = stream.node.live;
396
672
  if ((stream.flags & 3) === 0 || s.orphan) return;
@@ -406,6 +682,11 @@ function createStreamOps(h) {
406
682
  return {
407
683
  open(stream) {
408
684
  if (!Fs.isFile(stream.node.mode)) return;
685
+ const s = stream.node.live;
686
+ if (s.openCount === 0 && !s.orphan) {
687
+ const bridge = bridgeOf(stream.node);
688
+ s.ranges = !!(bridge.pread && bridge.pwrite && bridge.truncate && statOf(stream.node).ranged);
689
+ }
409
690
  if ((stream.flags & 3) !== 0) {
410
691
  try {
411
692
  const st = statOf(stream.node);
@@ -437,6 +718,8 @@ function createStreamOps(h) {
437
718
  flushNode(node);
438
719
  } finally {
439
720
  s.data = void 0;
721
+ s.ranged = void 0;
722
+ s.ranges = false;
440
723
  s.len = 0;
441
724
  s.loaded = false;
442
725
  held(stream, -1);
@@ -445,6 +728,11 @@ function createStreamOps(h) {
445
728
  read(stream, buffer, offset, length, position) {
446
729
  const node = stream.node;
447
730
  if (Fs.isDir(node.mode)) throw new Fs.ErrnoError(ERRNO_BY_CODE.EISDIR);
731
+ const ranged = rangedOf(node);
732
+ if (ranged) {
733
+ const out2 = new Uint8Array(buffer.buffer, buffer.byteOffset + offset, Math.max(0, length));
734
+ return h.call(() => ranged.readInto(position, out2));
735
+ }
448
736
  ensureLoaded(node);
449
737
  const s = node.live;
450
738
  if (position >= s.len || length <= 0) return 0;
@@ -460,6 +748,13 @@ function createStreamOps(h) {
460
748
  const s = node.live;
461
749
  const end = position + length;
462
750
  if (s.maxFile !== void 0 && end > s.maxFile) throw new Fs.ErrnoError(ERRNO_BY_CODE.EFBIG);
751
+ const ranged = rangedOf(node);
752
+ if (ranged) {
753
+ const bytes = new Uint8Array(buffer.buffer, buffer.byteOffset + offset, length);
754
+ h.call(() => ranged.write(position, bytes));
755
+ s.dirty = true;
756
+ return length;
757
+ }
463
758
  ensureLoaded(node);
464
759
  const buf = ensureCapacity(node, end);
465
760
  if (position > s.len) buf.fill(0, s.len, position);
@@ -473,7 +768,7 @@ function createStreamOps(h) {
473
768
  if (whence === SEEK_CUR) pos += stream.position;
474
769
  else if (whence === SEEK_END && Fs.isFile(stream.node.mode)) {
475
770
  const s = stream.node.live;
476
- pos += s.loaded ? s.len : statOf(stream.node).size;
771
+ pos += rangedOf(stream.node)?.size() ?? (s.loaded ? s.len : statOf(stream.node).size);
477
772
  }
478
773
  if (pos < 0) throw new Fs.ErrnoError(ERRNO_BY_CODE.EINVAL);
479
774
  return pos;
@@ -510,11 +805,15 @@ function ownedBy(plugin, node) {
510
805
  function flushLiveVfs(Fs, plugin) {
511
806
  for (const head of Fs.nameTable ?? []) {
512
807
  for (let node = head; node; node = node.name_next ?? null) {
513
- if (!ownedBy(plugin, node) || !node.live.dirty || !node.live.data) continue;
808
+ const s = node.live;
809
+ if (!ownedBy(plugin, node) || !s.dirty || !(s.data || s.ranged)) continue;
514
810
  try {
515
- const bytes = node.live.data.slice(0, node.live.len);
516
- node.mount.opts.bridge.writeFile(liveNodePath(node), bytes);
517
- node.live.dirty = false;
811
+ if (s.ranged) s.ranged.flush();
812
+ else {
813
+ const bytes = s.data.slice(0, s.len);
814
+ node.mount.opts.bridge.writeFile(liveNodePath(node), bytes);
815
+ }
816
+ s.dirty = false;
518
817
  } catch (err) {
519
818
  throw toErrno(Fs, err);
520
819
  }
@@ -532,8 +831,9 @@ function invalidateLiveVfs(Fs, plugin) {
532
831
  s.listed = void 0;
533
832
  if (s.openCount === 0) {
534
833
  if (node !== node.mount.root && !node.mounted) drop.push(node);
535
- } else if (s.loaded && !s.dirty) {
834
+ } else if (!s.dirty && !s.orphan) {
536
835
  s.data = void 0;
836
+ s.ranged = void 0;
537
837
  s.len = 0;
538
838
  s.loaded = false;
539
839
  }
@@ -652,6 +952,7 @@ var ERRNO_BY_CODE, EIO, S_IFDIR, S_IFREG, S_IFLNK, PERM_MASK, DEFAULT_DIR_PERM,
652
952
  var init_live_vfs_fs = __esm({
653
953
  "src/realm/live-vfs-fs.ts"() {
654
954
  "use strict";
955
+ init_ranged();
655
956
  init_types();
656
957
  ERRNO_BY_CODE = {
657
958
  EACCES: 2,
@@ -761,7 +1062,8 @@ function parseSyncFsStat(json) {
761
1062
  ...typeof s.ino === "number" ? { ino: s.ino } : {},
762
1063
  ...typeof s.dev === "number" ? { dev: s.dev } : {},
763
1064
  ...s.readonly === true ? { readonly: true } : {},
764
- ...typeof s.maxFile === "number" ? { maxFile: s.maxFile } : {}
1065
+ ...typeof s.maxFile === "number" ? { maxFile: s.maxFile } : {},
1066
+ ...s.ranged === true ? { ranged: true } : {}
765
1067
  };
766
1068
  }
767
1069
  var SYNC_FS_REQUEST_TIMEOUT_MS;
@@ -870,7 +1172,7 @@ function createSyncSabTransport(sab, port2, deps = {}) {
870
1172
  }
871
1173
  }
872
1174
  return {
873
- call(req, timeoutMs, label) {
1175
+ call(req, timeoutMs, label, transfer = []) {
874
1176
  if (deps.memory) publishMemory(sab, deps.memory());
875
1177
  const id = ++seq;
876
1178
  const deadline = now() + timeoutMs;
@@ -883,7 +1185,8 @@ function createSyncSabTransport(sab, port2, deps = {}) {
883
1185
  Atomics.store(header, SAB_I_STATE, SAB_STATE_PENDING);
884
1186
  const msg = offset === 0 ? { type: SYNC_SAB_REQ_MSG, id, req } : { type: SYNC_SAB_NEXT_MSG, id, offset };
885
1187
  try {
886
- port2.postMessage(msg);
1188
+ if (offset === 0 && transfer.length > 0) port2.postMessage(msg, transfer);
1189
+ else port2.postMessage(msg);
887
1190
  } catch {
888
1191
  throw syncError("EIO", label);
889
1192
  }
@@ -916,8 +1219,8 @@ function errnoError(code2, path) {
916
1219
  }
917
1220
  function createSyncFsSabBridge(transport, opts = {}) {
918
1221
  const timeoutMs = opts.timeoutMs ?? SYNC_FS_REQUEST_TIMEOUT_MS;
919
- function run(req, path) {
920
- const result = transport.call(req, timeoutMs, `sync-sab bridge, '${path}'`);
1222
+ function run(req, path, transfer) {
1223
+ const result = transport.call(req, timeoutMs, `sync-sab bridge, '${path}'`, transfer);
921
1224
  if (!result.ok) throw errnoError(result.errno, path);
922
1225
  return result;
923
1226
  }
@@ -1001,7 +1304,16 @@ function createSyncFsSabBridge(transport, opts = {}) {
1001
1304
  hold: (path, held) => {
1002
1305
  run({ op: "hold", path, mode: held ? 1 : 0 }, path);
1003
1306
  },
1004
- statfs: (path = "/") => parseSyncFsUsage(json({ op: "statfs", path }, path))
1307
+ statfs: (path = "/") => parseSyncFsUsage(json({ op: "statfs", path }, path)),
1308
+ pread: (path, offset, length) => bytes({ op: "pread", path, offset, length }, path),
1309
+ pwrite: (path, offset, body, transfer) => {
1310
+ const whole = body.byteOffset === 0 && body.byteLength === body.buffer.byteLength;
1311
+ const owned = transfer && whole && body.buffer instanceof ArrayBuffer;
1312
+ run({ op: "pwrite", path, offset, body }, path, owned ? [body.buffer] : []);
1313
+ },
1314
+ truncate: (path, length) => {
1315
+ run({ op: "truncate", path, length }, path);
1316
+ }
1005
1317
  };
1006
1318
  }
1007
1319
  var init_sync_sab_bridge = __esm({
@@ -3468,6 +3780,11 @@ function cachingBridge(bridge, now = () => performance.now()) {
3468
3780
  symlink: (target, link) => mutating(() => bridge.symlink(target, link)),
3469
3781
  chmod: (p, mode) => mutating(() => bridge.chmod(p, mode)),
3470
3782
  utimes: (p, a, m) => mutating(() => bridge.utimes(p, a, m)),
3783
+ ...bridge.pread && bridge.pwrite && bridge.truncate ? {
3784
+ pread: bridge.pread.bind(bridge),
3785
+ pwrite: (p, at, bytes, transfer) => mutating(() => bridge.pwrite?.(p, at, bytes, transfer)),
3786
+ truncate: (p, size) => mutating(() => bridge.truncate?.(p, size))
3787
+ } : {},
3471
3788
  invalidate
3472
3789
  };
3473
3790
  }
@@ -3475,6 +3792,7 @@ var WasiError, FileBuffer, LocalFile, MISS_TTL_MS;
3475
3792
  var init_wasi_files = __esm({
3476
3793
  "src/process/wasi/wasi-files.ts"() {
3477
3794
  "use strict";
3795
+ init_ranged();
3478
3796
  WasiError = class extends Error {
3479
3797
  code;
3480
3798
  constructor(code2) {
@@ -3489,17 +3807,37 @@ var init_wasi_files = __esm({
3489
3807
  orphaned = false;
3490
3808
  opens = 0;
3491
3809
  fs;
3492
- path;
3810
+ where;
3811
+ ranged;
3493
3812
  maxFile;
3494
- constructor(fs, path, empty, maxFile) {
3813
+ constructor(fs, path, empty, maxFile, size) {
3495
3814
  this.fs = fs;
3496
- this.path = path;
3815
+ this.where = path;
3497
3816
  this.maxFile = maxFile;
3498
- if (empty) {
3817
+ const { pread, pwrite, truncate } = fs;
3818
+ if (size !== void 0 && pread && pwrite && truncate) {
3819
+ const io = { pread: pread.bind(fs), pwrite: pwrite.bind(fs), truncate: truncate.bind(fs) };
3820
+ this.ranged = new RangedFile(io, path, size);
3821
+ if (empty) this.truncate(0);
3822
+ } else if (empty) {
3499
3823
  this.data = new Uint8Array(0);
3500
3824
  this.dirty = true;
3501
3825
  }
3502
3826
  }
3827
+ get path() {
3828
+ return this.where;
3829
+ }
3830
+ set path(path) {
3831
+ this.where = path;
3832
+ if (this.ranged) this.ranged.path = path;
3833
+ }
3834
+ get isRanged() {
3835
+ return this.ranged !== void 0;
3836
+ }
3837
+ keep() {
3838
+ if (this.ranged) this.ranged.pin();
3839
+ else this.load();
3840
+ }
3503
3841
  load() {
3504
3842
  if (!this.data) {
3505
3843
  this.data = this.fs.readFile(this.path);
@@ -3508,10 +3846,12 @@ var init_wasi_files = __esm({
3508
3846
  return this.data;
3509
3847
  }
3510
3848
  size() {
3849
+ if (this.ranged) return this.ranged.size();
3511
3850
  this.load();
3512
3851
  return this.length;
3513
3852
  }
3514
3853
  pread(max, at) {
3854
+ if (this.ranged) return this.ranged.read(at, max);
3515
3855
  const bytes = this.load();
3516
3856
  const n = Math.max(0, Math.min(max, this.length - at));
3517
3857
  return bytes.subarray(at, at + n);
@@ -3523,22 +3863,30 @@ var init_wasi_files = __esm({
3523
3863
  if (bytes.length === 0) return 0;
3524
3864
  const end = at + bytes.length;
3525
3865
  this.fits(end);
3866
+ this.dirty = true;
3867
+ if (this.ranged) {
3868
+ this.ranged.write(at, bytes);
3869
+ return bytes.length;
3870
+ }
3526
3871
  this.load();
3527
3872
  this.ensure(end);
3528
3873
  const buf = this.data;
3529
3874
  if (at > this.length) buf.fill(0, this.length, at);
3530
3875
  buf.set(bytes, at);
3531
3876
  this.length = Math.max(this.length, end);
3532
- this.dirty = true;
3533
3877
  return bytes.length;
3534
3878
  }
3535
3879
  truncate(size) {
3536
3880
  this.fits(size);
3881
+ this.dirty = true;
3882
+ if (this.ranged) {
3883
+ this.ranged.truncate(size);
3884
+ return;
3885
+ }
3537
3886
  this.load();
3538
3887
  this.ensure(size);
3539
3888
  if (size > this.length) this.data.fill(0, this.length, size);
3540
3889
  this.length = size;
3541
- this.dirty = true;
3542
3890
  }
3543
3891
  ensure(need) {
3544
3892
  const cur = this.data;
@@ -3549,6 +3897,7 @@ var init_wasi_files = __esm({
3549
3897
  }
3550
3898
  orphan() {
3551
3899
  this.orphaned = true;
3900
+ this.ranged?.pin();
3552
3901
  }
3553
3902
  isOrphan() {
3554
3903
  return this.orphaned;
@@ -3557,11 +3906,14 @@ var init_wasi_files = __esm({
3557
3906
  return this.dirty;
3558
3907
  }
3559
3908
  contents() {
3909
+ if (this.ranged) return this.ranged.read(0, this.ranged.size());
3560
3910
  return this.load().slice(0, this.length);
3561
3911
  }
3562
3912
  flush() {
3563
- if (this.orphaned || !this.dirty || !this.data) return;
3564
- this.fs.writeFile(this.path, this.data.slice(0, this.length));
3913
+ if (this.orphaned || !this.dirty) return;
3914
+ if (this.ranged) this.ranged.flush();
3915
+ else if (this.data) this.fs.writeFile(this.path, this.data.slice(0, this.length));
3916
+ else return;
3565
3917
  this.dirty = false;
3566
3918
  }
3567
3919
  };
@@ -3771,7 +4123,8 @@ function openAccess(existing, oflags, rights) {
3771
4123
  }
3772
4124
  function promoteRequest(fd, f, handed) {
3773
4125
  const orphan = f.buffer.isOrphan();
3774
- const joins = !orphan && handed.has(f.buffer);
4126
+ if (!orphan && f.buffer.isRanged) f.buffer.flush();
4127
+ const joins = !orphan && (handed.has(f.buffer) || f.buffer.isRanged);
3775
4128
  return {
3776
4129
  op: "fd-promote",
3777
4130
  fd,
@@ -4113,7 +4466,7 @@ var init_wasi_fds = __esm({
4113
4466
  if (this.shared) this.kernel.call({ op: "fd-path-flush", path });
4114
4467
  }
4115
4468
  unlinking(path) {
4116
- this.buffers.get(path)?.load();
4469
+ this.buffers.get(path)?.keep();
4117
4470
  if (this.shared) this.kernel.call({ op: "fd-path-unlinking", path });
4118
4471
  }
4119
4472
  unlinked(path) {
@@ -4174,7 +4527,8 @@ var init_wasi_fds = __esm({
4174
4527
  } else {
4175
4528
  if (!existing) this.fs.writeFile(path, new Uint8Array(0));
4176
4529
  const empty = !existing || (oflags & OFLAGS.TRUNC) !== 0;
4177
- buffer = new FileBuffer(this.fs, path, empty, (existing ?? this.fs.stat(path)).maxFile);
4530
+ const st = existing ?? this.fs.stat(path);
4531
+ buffer = new FileBuffer(this.fs, path, empty, st.maxFile, st.ranged ? st.size : void 0);
4178
4532
  this.buffers.set(path, buffer);
4179
4533
  }
4180
4534
  buffer.opens++;
@@ -5486,7 +5840,7 @@ function align(n, to) {
5486
5840
  return Math.ceil(n / to) * to;
5487
5841
  }
5488
5842
  function growTo(memory, bytes) {
5489
- const pages2 = Math.ceil(bytes / PAGE) - memory.buffer.byteLength / PAGE;
5843
+ const pages2 = Math.ceil(bytes / PAGE2) - memory.buffer.byteLength / PAGE2;
5490
5844
  if (pages2 > 0) memory.grow(pages2);
5491
5845
  }
5492
5846
  function growTable(table, length) {
@@ -5496,14 +5850,14 @@ function call(instance, name) {
5496
5850
  const fn = instance.exports[name];
5497
5851
  if (typeof fn === "function") fn();
5498
5852
  }
5499
- var TABLE_BASE, PAGE, STACK_SIZE, LIBRARY_DIRS, DlError, WasixLinker;
5853
+ var TABLE_BASE, PAGE2, STACK_SIZE, LIBRARY_DIRS, DlError, WasixLinker;
5500
5854
  var init_wasix_linker = __esm({
5501
5855
  "src/process/wasi/wasix-linker.ts"() {
5502
5856
  "use strict";
5503
5857
  init_dylink();
5504
5858
  init_wasi_files();
5505
5859
  TABLE_BASE = 1;
5506
- PAGE = 65536;
5860
+ PAGE2 = 65536;
5507
5861
  STACK_SIZE = 8 * 1024 * 1024;
5508
5862
  LIBRARY_DIRS = ["/lib", "/usr/lib", "/usr/local/lib"];
5509
5863
  DlError = class extends Error {