@componentor/fs 3.0.44 → 3.0.45

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/dist/index.js CHANGED
@@ -4560,14 +4560,23 @@ var VFSEngine = class {
4560
4560
  growPathTable(needed) {
4561
4561
  const newSize = Math.max(this.pathTableSize * 2, needed + INITIAL_PATH_TABLE_SIZE);
4562
4562
  const growth = newSize - this.pathTableSize;
4563
- const dataSize = this.totalBlocks * this.blockSize;
4564
- const dataBuf = new Uint8Array(dataSize);
4565
- this.handle.read(dataBuf, { at: this.dataOffset });
4566
4563
  const newTotalSize = this.handle.getSize() + growth;
4567
4564
  this.handle.truncate(newTotalSize);
4565
+ const dataSize = this.totalBlocks * this.blockSize;
4566
+ const CHUNK = 4 * 1024 * 1024;
4567
+ const scratch = new Uint8Array(Math.min(CHUNK, Math.max(dataSize, 1)));
4568
+ let remaining = dataSize;
4569
+ while (remaining > 0) {
4570
+ const chunk = Math.min(remaining, CHUNK);
4571
+ const srcAt = this.dataOffset + (remaining - chunk);
4572
+ const dstAt = this.dataOffset + growth + (remaining - chunk);
4573
+ const slice = chunk < scratch.length ? scratch.subarray(0, chunk) : scratch;
4574
+ this.handle.read(slice, { at: srcAt });
4575
+ this.handle.write(slice, { at: dstAt });
4576
+ remaining -= chunk;
4577
+ }
4568
4578
  const newBitmapOffset = this.bitmapOffset + growth;
4569
4579
  const newDataOffset = this.dataOffset + growth;
4570
- this.handle.write(dataBuf, { at: newDataOffset });
4571
4580
  this.handle.write(this.bitmap, { at: newBitmapOffset });
4572
4581
  this.pathTableSize = newSize;
4573
4582
  this.bitmapOffset = newBitmapOffset;
@@ -4575,6 +4584,23 @@ var VFSEngine = class {
4575
4584
  this.superblockDirty = true;
4576
4585
  }
4577
4586
  // ========== Bitmap I/O ==========
4587
+ // Write `length` zero bytes at absolute file offset `at` via a small
4588
+ // reusable scratch buffer. Used to materialize POSIX "holes" when a
4589
+ // write starts past the current file size — those bytes must read as
4590
+ // zeros rather than whatever stale data happened to live in the
4591
+ // underlying storage blocks.
4592
+ zeroFileRange(at, length) {
4593
+ if (length <= 0) return;
4594
+ const CHUNK = 4 * 1024 * 1024;
4595
+ const zeros = new Uint8Array(Math.min(length, CHUNK));
4596
+ let written = 0;
4597
+ while (written < length) {
4598
+ const n = Math.min(CHUNK, length - written);
4599
+ const slice = n < zeros.length ? zeros.subarray(0, n) : zeros;
4600
+ this.handle.write(slice, { at: at + written });
4601
+ written += n;
4602
+ }
4603
+ }
4578
4604
  allocateBlocks(count) {
4579
4605
  if (count === 0) return 0;
4580
4606
  const bitmap = this.bitmap;
@@ -4899,17 +4925,28 @@ var VFSEngine = class {
4899
4925
  }
4900
4926
  const inode = this.readInode(existingIdx);
4901
4927
  if (inode.type === INODE_TYPE.DIRECTORY) return { status: CODE_TO_STATUS.EISDIR };
4902
- const existing = inode.size > 0 ? this.readData(inode.firstBlock, inode.blockCount, inode.size) : new Uint8Array(0);
4903
- const combined = new Uint8Array(existing.byteLength + data.byteLength);
4904
- combined.set(existing);
4905
- combined.set(data, existing.byteLength);
4906
- const neededBlocks = Math.ceil(combined.byteLength / this.blockSize);
4907
- this.freeBlockRange(inode.firstBlock, inode.blockCount);
4928
+ const combinedSize = inode.size + data.byteLength;
4929
+ const neededBlocks = Math.ceil(combinedSize / this.blockSize);
4908
4930
  const newFirst = this.allocateBlocks(neededBlocks);
4909
- this.writeData(newFirst, combined);
4931
+ const newBase = this.dataOffset + newFirst * this.blockSize;
4932
+ if (inode.size > 0) {
4933
+ const oldBase = this.dataOffset + inode.firstBlock * this.blockSize;
4934
+ const CHUNK = 4 * 1024 * 1024;
4935
+ const scratch = new Uint8Array(Math.min(CHUNK, inode.size));
4936
+ let copied = 0;
4937
+ while (copied < inode.size) {
4938
+ const n = Math.min(CHUNK, inode.size - copied);
4939
+ const slice = n < scratch.length ? scratch.subarray(0, n) : scratch;
4940
+ this.handle.read(slice, { at: oldBase + copied });
4941
+ this.handle.write(slice, { at: newBase + copied });
4942
+ copied += n;
4943
+ }
4944
+ }
4945
+ this.freeBlockRange(inode.firstBlock, inode.blockCount);
4946
+ this.handle.write(data, { at: newBase + inode.size });
4910
4947
  inode.firstBlock = newFirst;
4911
4948
  inode.blockCount = neededBlocks;
4912
- inode.size = combined.byteLength;
4949
+ inode.size = combinedSize;
4913
4950
  inode.mtime = Date.now();
4914
4951
  this.writeInode(existingIdx, inode);
4915
4952
  this.commitPending();
@@ -5172,13 +5209,29 @@ var VFSEngine = class {
5172
5209
  } else if (len > inode.size) {
5173
5210
  const neededBlocks = Math.ceil(len / this.blockSize);
5174
5211
  if (neededBlocks > inode.blockCount) {
5175
- const oldData = this.readData(inode.firstBlock, inode.blockCount, inode.size);
5176
- this.freeBlockRange(inode.firstBlock, inode.blockCount);
5177
5212
  const newFirst = this.allocateBlocks(neededBlocks);
5178
- const newData = new Uint8Array(len);
5179
- newData.set(oldData);
5180
- this.writeData(newFirst, newData);
5213
+ const newBase = this.dataOffset + newFirst * this.blockSize;
5214
+ if (inode.size > 0) {
5215
+ const oldBase = this.dataOffset + inode.firstBlock * this.blockSize;
5216
+ const CHUNK = 4 * 1024 * 1024;
5217
+ const scratch = new Uint8Array(Math.min(CHUNK, inode.size));
5218
+ let copied = 0;
5219
+ while (copied < inode.size) {
5220
+ const n = Math.min(CHUNK, inode.size - copied);
5221
+ const slice = n < scratch.length ? scratch.subarray(0, n) : scratch;
5222
+ this.handle.read(slice, { at: oldBase + copied });
5223
+ this.handle.write(slice, { at: newBase + copied });
5224
+ copied += n;
5225
+ }
5226
+ }
5227
+ this.freeBlockRange(inode.firstBlock, inode.blockCount);
5228
+ this.zeroFileRange(newBase + inode.size, len - inode.size);
5181
5229
  inode.firstBlock = newFirst;
5230
+ } else {
5231
+ this.zeroFileRange(
5232
+ this.dataOffset + inode.firstBlock * this.blockSize + inode.size,
5233
+ len - inode.size
5234
+ );
5182
5235
  }
5183
5236
  inode.blockCount = neededBlocks;
5184
5237
  inode.size = len;
@@ -5199,8 +5252,36 @@ var VFSEngine = class {
5199
5252
  if (flags & 1 && this.pathIndex.has(destPath)) {
5200
5253
  return { status: CODE_TO_STATUS.EEXIST };
5201
5254
  }
5202
- const data = srcInode.size > 0 ? this.readData(srcInode.firstBlock, srcInode.blockCount, srcInode.size) : new Uint8Array(0);
5203
- return this.write(destPath, data);
5255
+ if (srcPath === destPath) return { status: 0 };
5256
+ const srcSize = srcInode.size;
5257
+ const srcFirstBlock = srcInode.firstBlock;
5258
+ const emptyStatus = this.write(destPath, new Uint8Array(0));
5259
+ if (emptyStatus.status !== 0) return emptyStatus;
5260
+ if (srcSize === 0) return { status: 0 };
5261
+ const destIdx = this.resolvePathComponents(destPath, true);
5262
+ if (destIdx === void 0) return { status: CODE_TO_STATUS.EIO };
5263
+ const destInode = this.readInode(destIdx);
5264
+ const neededBlocks = Math.ceil(srcSize / this.blockSize);
5265
+ const newFirst = this.allocateBlocks(neededBlocks);
5266
+ const newBase = this.dataOffset + newFirst * this.blockSize;
5267
+ const srcBase = this.dataOffset + srcFirstBlock * this.blockSize;
5268
+ const CHUNK = 4 * 1024 * 1024;
5269
+ const scratch = new Uint8Array(Math.min(CHUNK, srcSize));
5270
+ let copied = 0;
5271
+ while (copied < srcSize) {
5272
+ const n = Math.min(CHUNK, srcSize - copied);
5273
+ const slice = n < scratch.length ? scratch.subarray(0, n) : scratch;
5274
+ this.handle.read(slice, { at: srcBase + copied });
5275
+ this.handle.write(slice, { at: newBase + copied });
5276
+ copied += n;
5277
+ }
5278
+ destInode.firstBlock = newFirst;
5279
+ destInode.blockCount = neededBlocks;
5280
+ destInode.size = srcSize;
5281
+ destInode.mtime = Date.now();
5282
+ this.writeInode(destIdx, destInode);
5283
+ this.commitPending();
5284
+ return { status: 0 };
5204
5285
  }
5205
5286
  // ---- ACCESS ----
5206
5287
  access(path, mode = 0) {
@@ -5364,16 +5445,35 @@ var VFSEngine = class {
5364
5445
  if (endPos > inode.size) {
5365
5446
  const neededBlocks = Math.ceil(endPos / this.blockSize);
5366
5447
  if (neededBlocks > inode.blockCount) {
5367
- const oldData = inode.size > 0 ? this.readData(inode.firstBlock, inode.blockCount, inode.size) : new Uint8Array(0);
5368
- this.freeBlockRange(inode.firstBlock, inode.blockCount);
5369
5448
  const newFirst = this.allocateBlocks(neededBlocks);
5370
- const newBuf = new Uint8Array(endPos);
5371
- newBuf.set(oldData);
5372
- newBuf.set(data, pos);
5373
- this.writeData(newFirst, newBuf);
5449
+ const newBase = this.dataOffset + newFirst * this.blockSize;
5450
+ const oldBase = this.dataOffset + inode.firstBlock * this.blockSize;
5451
+ if (inode.size > 0) {
5452
+ const CHUNK = 4 * 1024 * 1024;
5453
+ const scratch = new Uint8Array(Math.min(CHUNK, inode.size));
5454
+ let copied = 0;
5455
+ while (copied < inode.size) {
5456
+ const n = Math.min(CHUNK, inode.size - copied);
5457
+ const slice = n < scratch.length ? scratch.subarray(0, n) : scratch;
5458
+ this.handle.read(slice, { at: oldBase + copied });
5459
+ this.handle.write(slice, { at: newBase + copied });
5460
+ copied += n;
5461
+ }
5462
+ }
5463
+ this.freeBlockRange(inode.firstBlock, inode.blockCount);
5464
+ if (pos > inode.size) {
5465
+ this.zeroFileRange(newBase + inode.size, pos - inode.size);
5466
+ }
5467
+ this.handle.write(data, { at: newBase + pos });
5374
5468
  inode.firstBlock = newFirst;
5375
5469
  inode.blockCount = neededBlocks;
5376
5470
  } else {
5471
+ if (pos > inode.size) {
5472
+ this.zeroFileRange(
5473
+ this.dataOffset + inode.firstBlock * this.blockSize + inode.size,
5474
+ pos - inode.size
5475
+ );
5476
+ }
5377
5477
  const dataOffset = this.dataOffset + inode.firstBlock * this.blockSize + pos;
5378
5478
  this.handle.write(data, { at: dataOffset });
5379
5479
  }