@volter/tabnode 0.3.0 → 0.3.1
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.
|
@@ -7913,11 +7913,11 @@ function answerFilesystem(method, args) {
|
|
|
7913
7913
|
return answer2.apply(hostVfs, plain) ?? null;
|
|
7914
7914
|
}
|
|
7915
7915
|
const inodes = /* @__PURE__ */ new Map();
|
|
7916
|
-
let nextInode = 1;
|
|
7916
|
+
let nextInode$1 = 1;
|
|
7917
7917
|
function inodeOf(path2) {
|
|
7918
7918
|
let inode = inodes.get(path2);
|
|
7919
7919
|
if (inode === void 0) {
|
|
7920
|
-
inode = nextInode++;
|
|
7920
|
+
inode = nextInode$1++;
|
|
7921
7921
|
inodes.set(path2, inode);
|
|
7922
7922
|
}
|
|
7923
7923
|
return inode;
|
|
@@ -9431,6 +9431,8 @@ const fsBinding = {
|
|
|
9431
9431
|
if ((flags & bits.excl) !== 0 && (flags & bits.create) !== 0 && exists) throw createNodeError$1("EEXIST", "open", name);
|
|
9432
9432
|
if (!exists) {
|
|
9433
9433
|
if ((flags & bits.create) === 0) throw createNodeError$1("ENOENT", "open", name);
|
|
9434
|
+
const parent = name.slice(0, name.lastIndexOf("/")) || "/";
|
|
9435
|
+
if (!tree2.statSync(parent).isDirectory()) throw createNodeError$1("ENOTDIR", "open", name);
|
|
9434
9436
|
tree2.writeFileSync(name, "");
|
|
9435
9437
|
} else if ((flags & bits.truncate) !== 0) {
|
|
9436
9438
|
tree2.writeFileSync(name, "");
|
|
@@ -9443,6 +9445,7 @@ const fsBinding = {
|
|
|
9443
9445
|
},
|
|
9444
9446
|
close(fd2, req) {
|
|
9445
9447
|
return answer(req, () => {
|
|
9448
|
+
fileFor(fd2);
|
|
9446
9449
|
openFiles.delete(fd2);
|
|
9447
9450
|
return void 0;
|
|
9448
9451
|
});
|
|
@@ -9451,6 +9454,7 @@ const fsBinding = {
|
|
|
9451
9454
|
read(fd2, buffer2, offset2, length, position, req) {
|
|
9452
9455
|
return answer(req, () => {
|
|
9453
9456
|
const file = fileFor(fd2);
|
|
9457
|
+
if ((file.flags & 3) === 1) throw createNodeError$1("EBADF", "read", file.path);
|
|
9454
9458
|
if (file.cached === void 0) file.cached = file.tree.readFileSync(file.path);
|
|
9455
9459
|
const bytes2 = file.cached;
|
|
9456
9460
|
const from = position === null || position === void 0 || position < 0 ? file.position : position;
|
|
@@ -9473,17 +9477,27 @@ const fsBinding = {
|
|
|
9473
9477
|
});
|
|
9474
9478
|
},
|
|
9475
9479
|
/** Node's fast path for `readFile` with an encoding it can decode itself. */
|
|
9476
|
-
readFileUtf8(path2,
|
|
9477
|
-
|
|
9480
|
+
readFileUtf8(path2, flags) {
|
|
9481
|
+
const owned = typeof path2 !== "number";
|
|
9482
|
+
const fd2 = owned ? fsBinding.open(path2, flags, 438) : path2;
|
|
9483
|
+
try {
|
|
9484
|
+
const file = fileFor(fd2);
|
|
9485
|
+
const bytes2 = new Uint8Array(file.tree.statSync(file.path).size);
|
|
9486
|
+
const length = fsBinding.read(fd2, bytes2, 0, bytes2.length, -1);
|
|
9487
|
+
return new TextDecoder().decode(bytes2.subarray(0, length));
|
|
9488
|
+
} finally {
|
|
9489
|
+
if (owned) fsBinding.close(fd2);
|
|
9490
|
+
}
|
|
9478
9491
|
},
|
|
9479
9492
|
// ---- writing ------------------------------------------------------------
|
|
9480
9493
|
writeBuffer(fd2, buffer2, offset2, length, position, req) {
|
|
9481
9494
|
return answer(req, () => {
|
|
9482
9495
|
const file = fileFor(fd2);
|
|
9496
|
+
if ((file.flags & 3) === 0) throw createNodeError$1("EBADF", "write", file.path);
|
|
9483
9497
|
const tree2 = file.tree;
|
|
9484
9498
|
const slice = buffer2.subarray(offset2, offset2 + length);
|
|
9485
9499
|
const existing = file.cached ?? (tree2.existsSync(file.path) ? tree2.readFileSync(file.path) : new Uint8Array(0));
|
|
9486
|
-
const at3 = position === null || position === void 0 || position < 0 ? file.position : position;
|
|
9500
|
+
const at3 = (file.flags & flagBits().append) !== 0 ? existing.length : position === null || position === void 0 || position < 0 ? file.position : position;
|
|
9487
9501
|
const size = Math.max(existing.length, at3 + slice.length);
|
|
9488
9502
|
const next2 = new Uint8Array(size);
|
|
9489
9503
|
next2.set(existing, 0);
|
|
@@ -9513,15 +9527,14 @@ const fsBinding = {
|
|
|
9513
9527
|
const bytes2 = encoding === "utf8" || encoding === void 0 || encoding === "utf-8" ? new TextEncoder().encode(value) : Uint8Array.from(value, (character) => character.charCodeAt(0) & 255);
|
|
9514
9528
|
return fsBinding.writeBuffer(fd2, bytes2, 0, bytes2.length, position ?? null, req);
|
|
9515
9529
|
},
|
|
9516
|
-
writeFileUtf8(path2, data2, flags,
|
|
9517
|
-
const
|
|
9518
|
-
const
|
|
9519
|
-
|
|
9520
|
-
|
|
9521
|
-
|
|
9522
|
-
|
|
9530
|
+
writeFileUtf8(path2, data2, flags, mode) {
|
|
9531
|
+
const owned = typeof path2 !== "number";
|
|
9532
|
+
const fd2 = owned ? fsBinding.open(path2, flags, mode) : path2;
|
|
9533
|
+
try {
|
|
9534
|
+
fsBinding.writeString(fd2, data2, null, "utf8");
|
|
9535
|
+
} finally {
|
|
9536
|
+
if (owned) fsBinding.close(fd2);
|
|
9523
9537
|
}
|
|
9524
|
-
tree2.writeFileSync(name, data2);
|
|
9525
9538
|
return void 0;
|
|
9526
9539
|
},
|
|
9527
9540
|
// ---- metadata -----------------------------------------------------------
|
|
@@ -9802,6 +9815,7 @@ const fsBinding = {
|
|
|
9802
9815
|
ftruncate(fd2, length, req) {
|
|
9803
9816
|
return answer(req, () => {
|
|
9804
9817
|
const file = fileFor(fd2);
|
|
9818
|
+
if ((file.flags & 3) === 0) throw createNodeError$1("EBADF", "ftruncate", file.path);
|
|
9805
9819
|
const tree2 = file.tree;
|
|
9806
9820
|
const bytes2 = file.cached ?? tree2.readFileSync(file.path);
|
|
9807
9821
|
const next2 = new Uint8Array(length);
|
|
@@ -26098,6 +26112,16 @@ lazyExport("stream", "pipeline");
|
|
|
26098
26112
|
lazyExport("stream", "finished");
|
|
26099
26113
|
lazyModule("stream/promises");
|
|
26100
26114
|
const streamPromisesModule = lazyModule("stream/promises");
|
|
26115
|
+
const nodeInodes = /* @__PURE__ */ new WeakMap();
|
|
26116
|
+
let nextInode = 1;
|
|
26117
|
+
function inodeFor(node) {
|
|
26118
|
+
let inode = nodeInodes.get(node);
|
|
26119
|
+
if (inode === void 0) {
|
|
26120
|
+
inode = nextInode++;
|
|
26121
|
+
nodeInodes.set(node, inode);
|
|
26122
|
+
}
|
|
26123
|
+
return inode;
|
|
26124
|
+
}
|
|
26101
26125
|
function createNodeError(code2, syscall, path2, message) {
|
|
26102
26126
|
const errno = {
|
|
26103
26127
|
ENOENT: -2,
|
|
@@ -26414,7 +26438,7 @@ class VirtualFS {
|
|
|
26414
26438
|
uid: 1e3,
|
|
26415
26439
|
gid: 1e3,
|
|
26416
26440
|
dev: 0,
|
|
26417
|
-
ino:
|
|
26441
|
+
ino: inodeFor(node),
|
|
26418
26442
|
rdev: 0,
|
|
26419
26443
|
blksize: 4096,
|
|
26420
26444
|
blocks: Math.ceil(size / 512)
|
|
@@ -26453,7 +26477,7 @@ class VirtualFS {
|
|
|
26453
26477
|
uid: 1e3,
|
|
26454
26478
|
gid: 1e3,
|
|
26455
26479
|
dev: 0,
|
|
26456
|
-
ino:
|
|
26480
|
+
ino: inodeFor(node),
|
|
26457
26481
|
rdev: 0,
|
|
26458
26482
|
blksize: 4096,
|
|
26459
26483
|
blocks: 0
|
package/dist/index.mjs
CHANGED
|
@@ -7626,11 +7626,11 @@ function answerFilesystem(method, args) {
|
|
|
7626
7626
|
return answer2.apply(hostVfs, plain) ?? null;
|
|
7627
7627
|
}
|
|
7628
7628
|
const inodes = /* @__PURE__ */ new Map();
|
|
7629
|
-
let nextInode = 1;
|
|
7629
|
+
let nextInode$1 = 1;
|
|
7630
7630
|
function inodeOf(path2) {
|
|
7631
7631
|
let inode = inodes.get(path2);
|
|
7632
7632
|
if (inode === void 0) {
|
|
7633
|
-
inode = nextInode++;
|
|
7633
|
+
inode = nextInode$1++;
|
|
7634
7634
|
inodes.set(path2, inode);
|
|
7635
7635
|
}
|
|
7636
7636
|
return inode;
|
|
@@ -9144,6 +9144,8 @@ const fsBinding = {
|
|
|
9144
9144
|
if ((flags & bits.excl) !== 0 && (flags & bits.create) !== 0 && exists) throw createNodeError$1("EEXIST", "open", name);
|
|
9145
9145
|
if (!exists) {
|
|
9146
9146
|
if ((flags & bits.create) === 0) throw createNodeError$1("ENOENT", "open", name);
|
|
9147
|
+
const parent = name.slice(0, name.lastIndexOf("/")) || "/";
|
|
9148
|
+
if (!tree2.statSync(parent).isDirectory()) throw createNodeError$1("ENOTDIR", "open", name);
|
|
9147
9149
|
tree2.writeFileSync(name, "");
|
|
9148
9150
|
} else if ((flags & bits.truncate) !== 0) {
|
|
9149
9151
|
tree2.writeFileSync(name, "");
|
|
@@ -9156,6 +9158,7 @@ const fsBinding = {
|
|
|
9156
9158
|
},
|
|
9157
9159
|
close(fd, req) {
|
|
9158
9160
|
return answer(req, () => {
|
|
9161
|
+
fileFor(fd);
|
|
9159
9162
|
openFiles.delete(fd);
|
|
9160
9163
|
return void 0;
|
|
9161
9164
|
});
|
|
@@ -9164,6 +9167,7 @@ const fsBinding = {
|
|
|
9164
9167
|
read(fd, buffer2, offset2, length, position, req) {
|
|
9165
9168
|
return answer(req, () => {
|
|
9166
9169
|
const file = fileFor(fd);
|
|
9170
|
+
if ((file.flags & 3) === 1) throw createNodeError$1("EBADF", "read", file.path);
|
|
9167
9171
|
if (file.cached === void 0) file.cached = file.tree.readFileSync(file.path);
|
|
9168
9172
|
const bytes2 = file.cached;
|
|
9169
9173
|
const from = position === null || position === void 0 || position < 0 ? file.position : position;
|
|
@@ -9186,17 +9190,27 @@ const fsBinding = {
|
|
|
9186
9190
|
});
|
|
9187
9191
|
},
|
|
9188
9192
|
/** Node's fast path for `readFile` with an encoding it can decode itself. */
|
|
9189
|
-
readFileUtf8(path2,
|
|
9190
|
-
|
|
9193
|
+
readFileUtf8(path2, flags) {
|
|
9194
|
+
const owned = typeof path2 !== "number";
|
|
9195
|
+
const fd = owned ? fsBinding.open(path2, flags, 438) : path2;
|
|
9196
|
+
try {
|
|
9197
|
+
const file = fileFor(fd);
|
|
9198
|
+
const bytes2 = new Uint8Array(file.tree.statSync(file.path).size);
|
|
9199
|
+
const length = fsBinding.read(fd, bytes2, 0, bytes2.length, -1);
|
|
9200
|
+
return new TextDecoder().decode(bytes2.subarray(0, length));
|
|
9201
|
+
} finally {
|
|
9202
|
+
if (owned) fsBinding.close(fd);
|
|
9203
|
+
}
|
|
9191
9204
|
},
|
|
9192
9205
|
// ---- writing ------------------------------------------------------------
|
|
9193
9206
|
writeBuffer(fd, buffer2, offset2, length, position, req) {
|
|
9194
9207
|
return answer(req, () => {
|
|
9195
9208
|
const file = fileFor(fd);
|
|
9209
|
+
if ((file.flags & 3) === 0) throw createNodeError$1("EBADF", "write", file.path);
|
|
9196
9210
|
const tree2 = file.tree;
|
|
9197
9211
|
const slice = buffer2.subarray(offset2, offset2 + length);
|
|
9198
9212
|
const existing = file.cached ?? (tree2.existsSync(file.path) ? tree2.readFileSync(file.path) : new Uint8Array(0));
|
|
9199
|
-
const at2 = position === null || position === void 0 || position < 0 ? file.position : position;
|
|
9213
|
+
const at2 = (file.flags & flagBits().append) !== 0 ? existing.length : position === null || position === void 0 || position < 0 ? file.position : position;
|
|
9200
9214
|
const size = Math.max(existing.length, at2 + slice.length);
|
|
9201
9215
|
const next = new Uint8Array(size);
|
|
9202
9216
|
next.set(existing, 0);
|
|
@@ -9226,15 +9240,14 @@ const fsBinding = {
|
|
|
9226
9240
|
const bytes2 = encoding === "utf8" || encoding === void 0 || encoding === "utf-8" ? new TextEncoder().encode(value) : Uint8Array.from(value, (character) => character.charCodeAt(0) & 255);
|
|
9227
9241
|
return fsBinding.writeBuffer(fd, bytes2, 0, bytes2.length, position ?? null, req);
|
|
9228
9242
|
},
|
|
9229
|
-
writeFileUtf8(path2, data2, flags,
|
|
9230
|
-
const
|
|
9231
|
-
const
|
|
9232
|
-
|
|
9233
|
-
|
|
9234
|
-
|
|
9235
|
-
|
|
9243
|
+
writeFileUtf8(path2, data2, flags, mode) {
|
|
9244
|
+
const owned = typeof path2 !== "number";
|
|
9245
|
+
const fd = owned ? fsBinding.open(path2, flags, mode) : path2;
|
|
9246
|
+
try {
|
|
9247
|
+
fsBinding.writeString(fd, data2, null, "utf8");
|
|
9248
|
+
} finally {
|
|
9249
|
+
if (owned) fsBinding.close(fd);
|
|
9236
9250
|
}
|
|
9237
|
-
tree2.writeFileSync(name, data2);
|
|
9238
9251
|
return void 0;
|
|
9239
9252
|
},
|
|
9240
9253
|
// ---- metadata -----------------------------------------------------------
|
|
@@ -9515,6 +9528,7 @@ const fsBinding = {
|
|
|
9515
9528
|
ftruncate(fd, length, req) {
|
|
9516
9529
|
return answer(req, () => {
|
|
9517
9530
|
const file = fileFor(fd);
|
|
9531
|
+
if ((file.flags & 3) === 0) throw createNodeError$1("EBADF", "ftruncate", file.path);
|
|
9518
9532
|
const tree2 = file.tree;
|
|
9519
9533
|
const bytes2 = file.cached ?? tree2.readFileSync(file.path);
|
|
9520
9534
|
const next = new Uint8Array(length);
|
|
@@ -25831,6 +25845,16 @@ lazyExport("stream", "pipeline");
|
|
|
25831
25845
|
lazyExport("stream", "finished");
|
|
25832
25846
|
lazyModule("stream/promises");
|
|
25833
25847
|
const streamPromisesModule = lazyModule("stream/promises");
|
|
25848
|
+
const nodeInodes = /* @__PURE__ */ new WeakMap();
|
|
25849
|
+
let nextInode = 1;
|
|
25850
|
+
function inodeFor(node) {
|
|
25851
|
+
let inode = nodeInodes.get(node);
|
|
25852
|
+
if (inode === void 0) {
|
|
25853
|
+
inode = nextInode++;
|
|
25854
|
+
nodeInodes.set(node, inode);
|
|
25855
|
+
}
|
|
25856
|
+
return inode;
|
|
25857
|
+
}
|
|
25834
25858
|
function createNodeError(code2, syscall, path2, message) {
|
|
25835
25859
|
const errno = {
|
|
25836
25860
|
ENOENT: -2,
|
|
@@ -26147,7 +26171,7 @@ class VirtualFS {
|
|
|
26147
26171
|
uid: 1e3,
|
|
26148
26172
|
gid: 1e3,
|
|
26149
26173
|
dev: 0,
|
|
26150
|
-
ino:
|
|
26174
|
+
ino: inodeFor(node),
|
|
26151
26175
|
rdev: 0,
|
|
26152
26176
|
blksize: 4096,
|
|
26153
26177
|
blocks: Math.ceil(size / 512)
|
|
@@ -26186,7 +26210,7 @@ class VirtualFS {
|
|
|
26186
26210
|
uid: 1e3,
|
|
26187
26211
|
gid: 1e3,
|
|
26188
26212
|
dev: 0,
|
|
26189
|
-
ino:
|
|
26213
|
+
ino: inodeFor(node),
|
|
26190
26214
|
rdev: 0,
|
|
26191
26215
|
blksize: 4096,
|
|
26192
26216
|
blocks: 0
|
|
@@ -33786,7 +33810,7 @@ class WorkerRuntime {
|
|
|
33786
33810
|
this.worker = new Worker(
|
|
33787
33811
|
new URL(
|
|
33788
33812
|
/* @vite-ignore */
|
|
33789
|
-
"/assets/runtime-worker-
|
|
33813
|
+
"/assets/runtime-worker-CUO9SNFs.js",
|
|
33790
33814
|
import.meta.url
|
|
33791
33815
|
),
|
|
33792
33816
|
{ type: "module" }
|
|
@@ -95,11 +95,11 @@ export declare const fsBinding: {
|
|
|
95
95
|
read(fd: number, buffer: Uint8Array, offset: number, length: number, position: number, req?: FSReq): number | undefined;
|
|
96
96
|
readBuffers(fd: number, buffers: Uint8Array[], position: number, req?: FSReq): number | undefined;
|
|
97
97
|
/** Node's fast path for `readFile` with an encoding it can decode itself. */
|
|
98
|
-
readFileUtf8(path: unknown,
|
|
98
|
+
readFileUtf8(path: unknown, flags: number): string;
|
|
99
99
|
writeBuffer(fd: number, buffer: Uint8Array, offset: number, length: number, position: number | null, req?: FSReq): number | undefined;
|
|
100
100
|
writeBuffers(fd: number, buffers: Uint8Array[], position: number | null, req?: FSReq): number | undefined;
|
|
101
101
|
writeString(fd: number, value: string, position: number | null, encoding: string | undefined, req?: FSReq): number | undefined;
|
|
102
|
-
writeFileUtf8(path: unknown, data: string, flags: number,
|
|
102
|
+
writeFileUtf8(path: unknown, data: string, flags: number, mode: number): undefined;
|
|
103
103
|
stat(path: unknown, bigint: boolean, req?: FSReq, throwIfNoEntry?: boolean): Float64Array | BigInt64Array | undefined;
|
|
104
104
|
lstat(path: unknown, bigint: boolean, req?: FSReq, throwIfNoEntry?: boolean): Float64Array | BigInt64Array | undefined;
|
|
105
105
|
fstat(fd: number, bigint: boolean, req?: FSReq): Float64Array | BigInt64Array | undefined;
|
package/package.json
CHANGED
|
@@ -469,6 +469,9 @@ export const fsBinding = {
|
|
|
469
469
|
if ((flags & bits.excl) !== 0 && (flags & bits.create) !== 0 && exists) throw createNodeError('EEXIST', 'open', name);
|
|
470
470
|
if (!exists) {
|
|
471
471
|
if ((flags & bits.create) === 0) throw createNodeError('ENOENT', 'open', name);
|
|
472
|
+
// VirtualFS writes create parents for image loading; open(2) does not.
|
|
473
|
+
const parent = name.slice(0, name.lastIndexOf('/')) || '/';
|
|
474
|
+
if (!tree.statSync(parent).isDirectory()) throw createNodeError('ENOTDIR', 'open', name);
|
|
472
475
|
tree.writeFileSync(name, '');
|
|
473
476
|
} else if ((flags & bits.truncate) !== 0) {
|
|
474
477
|
tree.writeFileSync(name, '');
|
|
@@ -481,13 +484,14 @@ export const fsBinding = {
|
|
|
481
484
|
},
|
|
482
485
|
|
|
483
486
|
close(fd: number, req?: FSReq): undefined {
|
|
484
|
-
return answer(req, () => { openFiles.delete(fd); return undefined; });
|
|
487
|
+
return answer(req, () => { fileFor(fd); openFiles.delete(fd); return undefined; });
|
|
485
488
|
},
|
|
486
489
|
|
|
487
490
|
// ---- reading ------------------------------------------------------------
|
|
488
491
|
read(fd: number, buffer: Uint8Array, offset: number, length: number, position: number, req?: FSReq): number | undefined {
|
|
489
492
|
return answer(req, () => {
|
|
490
493
|
const file = fileFor(fd);
|
|
494
|
+
if ((file.flags & 3) === 1) throw createNodeError('EBADF', 'read', file.path);
|
|
491
495
|
if (file.cached === undefined) file.cached = file.tree.readFileSync(file.path) as Uint8Array;
|
|
492
496
|
const bytes = file.cached;
|
|
493
497
|
const from = position === null || position === undefined || position < 0 ? file.position : position;
|
|
@@ -512,18 +516,27 @@ export const fsBinding = {
|
|
|
512
516
|
},
|
|
513
517
|
|
|
514
518
|
/** Node's fast path for `readFile` with an encoding it can decode itself. */
|
|
515
|
-
readFileUtf8(path: unknown,
|
|
516
|
-
|
|
519
|
+
readFileUtf8(path: unknown, flags: number): string {
|
|
520
|
+
const owned = typeof path !== 'number';
|
|
521
|
+
const fd = owned ? fsBinding.open(path, flags, 0o666) as number : path as number;
|
|
522
|
+
try {
|
|
523
|
+
const file = fileFor(fd);
|
|
524
|
+
const bytes = new Uint8Array(file.tree.statSync(file.path).size);
|
|
525
|
+
const length = fsBinding.read(fd, bytes, 0, bytes.length, -1) as number;
|
|
526
|
+
return new TextDecoder().decode(bytes.subarray(0, length));
|
|
527
|
+
} finally { if (owned) fsBinding.close(fd); }
|
|
517
528
|
},
|
|
518
529
|
|
|
519
530
|
// ---- writing ------------------------------------------------------------
|
|
520
531
|
writeBuffer(fd: number, buffer: Uint8Array, offset: number, length: number, position: number | null, req?: FSReq): number | undefined {
|
|
521
532
|
return answer(req, () => {
|
|
522
533
|
const file = fileFor(fd);
|
|
534
|
+
if ((file.flags & 3) === 0) throw createNodeError('EBADF', 'write', file.path);
|
|
523
535
|
const tree = file.tree;
|
|
524
536
|
const slice = buffer.subarray(offset, offset + length);
|
|
525
537
|
const existing = file.cached ?? (tree.existsSync(file.path) ? tree.readFileSync(file.path) as Uint8Array : new Uint8Array(0));
|
|
526
|
-
const at =
|
|
538
|
+
const at = (file.flags & flagBits().append) !== 0 ? existing.length
|
|
539
|
+
: position === null || position === undefined || position < 0 ? file.position : position;
|
|
527
540
|
const size = Math.max(existing.length, at + slice.length);
|
|
528
541
|
const next = new Uint8Array(size);
|
|
529
542
|
next.set(existing, 0);
|
|
@@ -553,15 +566,13 @@ export const fsBinding = {
|
|
|
553
566
|
return fsBinding.writeBuffer(fd, bytes, 0, bytes.length, position ?? null, req);
|
|
554
567
|
},
|
|
555
568
|
|
|
556
|
-
writeFileUtf8(path: unknown, data: string, flags: number,
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
}
|
|
564
|
-
tree.writeFileSync(name, data);
|
|
569
|
+
writeFileUtf8(path: unknown, data: string, flags: number, mode: number): undefined {
|
|
570
|
+
// Node's UTF-8 fast path accepts a path OR an already-open descriptor.
|
|
571
|
+
// Reuse open/write so flags, offsets and errors match the buffer path.
|
|
572
|
+
const owned = typeof path !== 'number';
|
|
573
|
+
const fd = owned ? fsBinding.open(path, flags, mode) as number : path as number;
|
|
574
|
+
try { fsBinding.writeString(fd, data, null, 'utf8'); }
|
|
575
|
+
finally { if (owned) fsBinding.close(fd); }
|
|
565
576
|
return undefined;
|
|
566
577
|
},
|
|
567
578
|
|
|
@@ -843,6 +854,7 @@ export const fsBinding = {
|
|
|
843
854
|
ftruncate(fd: number, length: number, req?: FSReq): undefined {
|
|
844
855
|
return answer(req, () => {
|
|
845
856
|
const file = fileFor(fd);
|
|
857
|
+
if ((file.flags & 3) === 0) throw createNodeError('EBADF', 'ftruncate', file.path);
|
|
846
858
|
const tree = file.tree;
|
|
847
859
|
const bytes = file.cached ?? (tree.readFileSync(file.path) as Uint8Array);
|
|
848
860
|
const next = new Uint8Array(length);
|
package/src/virtual-fs.ts
CHANGED
|
@@ -45,6 +45,17 @@ export interface FSNode {
|
|
|
45
45
|
atime?: number;
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
+
// Identity belongs to the node, so writes and renames preserve it while an
|
|
49
|
+
// unlink followed by recreation receives a different inode. Weak keys do not
|
|
50
|
+
// retain deleted trees, and snapshots receive new identities when restored.
|
|
51
|
+
const nodeInodes = new WeakMap<FSNode, number>();
|
|
52
|
+
let nextInode = 1;
|
|
53
|
+
function inodeFor(node: FSNode): number {
|
|
54
|
+
let inode = nodeInodes.get(node);
|
|
55
|
+
if (inode === undefined) { inode = nextInode++; nodeInodes.set(node, inode); }
|
|
56
|
+
return inode;
|
|
57
|
+
}
|
|
58
|
+
|
|
48
59
|
// Simple EventEmitter for VFS change notifications
|
|
49
60
|
type VFSChangeListener = (path: string, content: string) => void;
|
|
50
61
|
type VFSDeleteListener = (path: string) => void;
|
|
@@ -491,7 +502,7 @@ export class VirtualFS {
|
|
|
491
502
|
uid: 1000,
|
|
492
503
|
gid: 1000,
|
|
493
504
|
dev: 0,
|
|
494
|
-
ino:
|
|
505
|
+
ino: inodeFor(node),
|
|
495
506
|
rdev: 0,
|
|
496
507
|
blksize: 4096,
|
|
497
508
|
blocks: Math.ceil(size / 512),
|
|
@@ -531,7 +542,7 @@ export class VirtualFS {
|
|
|
531
542
|
uid: 1000,
|
|
532
543
|
gid: 1000,
|
|
533
544
|
dev: 0,
|
|
534
|
-
ino:
|
|
545
|
+
ino: inodeFor(node),
|
|
535
546
|
rdev: 0,
|
|
536
547
|
blksize: 4096,
|
|
537
548
|
blocks: 0
|