@componentor/fs 3.0.49 → 3.0.51

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/src/vfs/layout.ts","../../src/src/errors.ts","../../src/src/vfs/engine.ts","../../src/src/workers/repair.worker.ts"],"sourcesContent":["/**\n * VFS Binary Layout Constants\n *\n * Defines the on-disk structure of the virtual filesystem binary file.\n * All reads/writes go through a FileSystemSyncAccessHandle.\n */\n\n// Magic number: \"VFS!\" in ASCII\nexport const VFS_MAGIC = 0x56465321;\nexport const VFS_VERSION = 1;\n\n// Default sizes\nexport const DEFAULT_BLOCK_SIZE = 4096;\nexport const DEFAULT_INODE_COUNT = 100000;\nexport const INODE_SIZE = 64; // bytes per inode entry\n\n// Superblock layout (64 bytes)\nexport const SUPERBLOCK = {\n SIZE: 64,\n MAGIC: 0, // uint32 - 0x56465321\n VERSION: 4, // uint32\n INODE_COUNT: 8, // uint32 - total inodes allocated\n BLOCK_SIZE: 12, // uint32 - data block size (default 4096)\n TOTAL_BLOCKS: 16, // uint32 - total data blocks\n FREE_BLOCKS: 20, // uint32 - available data blocks\n INODE_OFFSET: 24, // float64 - byte offset to inode table\n PATH_OFFSET: 32, // float64 - byte offset to path table\n DATA_OFFSET: 40, // float64 - byte offset to data region\n BITMAP_OFFSET: 48, // float64 - byte offset to free block bitmap\n PATH_USED: 56, // uint32 - bytes used in path table\n RESERVED: 60, // uint32\n} as const;\n\n// Inode entry layout (64 bytes each)\nexport const INODE = {\n TYPE: 0, // uint8 - 0=free, 1=file, 2=directory, 3=symlink\n FLAGS: 1, // uint8[3] - reserved\n PATH_OFFSET: 4, // uint32 - byte offset into path table\n PATH_LENGTH: 8, // uint16 - length of path string\n NLINK: 10, // uint16 - hard link count\n MODE: 12, // uint32 - permissions (e.g. 0o100644)\n SIZE: 16, // float64 - file content size in bytes (using f64 for >4GB)\n FIRST_BLOCK: 24, // uint32 - index of first data block\n BLOCK_COUNT: 28, // uint32 - number of contiguous data blocks\n MTIME: 32, // float64 - last modification time (ms since epoch)\n CTIME: 40, // float64 - creation/change time (ms since epoch)\n ATIME: 48, // float64 - last access time (ms since epoch)\n UID: 56, // uint32 - owner\n GID: 60, // uint32 - group\n} as const;\n\n// Inode type constants\nexport const INODE_TYPE = {\n FREE: 0,\n FILE: 1,\n DIRECTORY: 2,\n SYMLINK: 3,\n} as const;\n\n// Default file modes\nexport const DEFAULT_FILE_MODE = 0o100644;\nexport const DEFAULT_DIR_MODE = 0o040755;\nexport const DEFAULT_SYMLINK_MODE = 0o120777;\nexport const DEFAULT_UMASK = 0o022;\n\n// POSIX file type bits\nexport const S_IFMT = 0o170000;\nexport const S_IFREG = 0o100000;\nexport const S_IFDIR = 0o040000;\nexport const S_IFLNK = 0o120000;\n\n// Max symlink depth for cycle detection\nexport const MAX_SYMLINK_DEPTH = 40;\n\n// Path table compaction threshold (25% dead space)\nexport const PATH_COMPACTION_THRESHOLD = 0.25;\n\n// Initial path table size (256KB)\nexport const INITIAL_PATH_TABLE_SIZE = 256 * 1024;\n\n// Initial data blocks (1024 blocks = 4MB with 4KB blocks)\nexport const INITIAL_DATA_BLOCKS = 1024;\n\n/**\n * Calculate section offsets for a fresh VFS.\n */\nexport function calculateLayout(inodeCount: number = DEFAULT_INODE_COUNT, blockSize: number = DEFAULT_BLOCK_SIZE, totalBlocks: number = INITIAL_DATA_BLOCKS) {\n const inodeTableOffset = SUPERBLOCK.SIZE;\n const inodeTableSize = inodeCount * INODE_SIZE;\n const pathTableOffset = inodeTableOffset + inodeTableSize;\n const pathTableSize = INITIAL_PATH_TABLE_SIZE;\n const bitmapOffset = pathTableOffset + pathTableSize;\n const bitmapSize = Math.ceil(totalBlocks / 8);\n // Align data region to block boundary\n const dataOffset = Math.ceil((bitmapOffset + bitmapSize) / blockSize) * blockSize;\n const totalSize = dataOffset + totalBlocks * blockSize;\n\n return {\n inodeTableOffset,\n inodeTableSize,\n pathTableOffset,\n pathTableSize,\n bitmapOffset,\n bitmapSize,\n dataOffset,\n totalSize,\n totalBlocks,\n };\n}\n","/**\n * Node.js compatible filesystem error classes\n */\n\nexport class FSError extends Error {\n code: string;\n errno: number;\n syscall?: string;\n path?: string;\n\n constructor(code: string, errno: number, message: string, syscall?: string, path?: string) {\n super(message);\n this.name = 'FSError';\n this.code = code;\n this.errno = errno;\n this.syscall = syscall;\n this.path = path;\n }\n}\n\nexport const ErrorCodes = {\n ENOENT: -2,\n EEXIST: -17,\n EISDIR: -21,\n ENOTDIR: -20,\n ENOTEMPTY: -39,\n EACCES: -13,\n EBADF: -9,\n EINVAL: -22,\n EMFILE: -24,\n ENOSPC: -28,\n EPERM: -1,\n ENOSYS: -38,\n ELOOP: -40,\n} as const;\n\n/** Binary protocol status codes → error code mapping */\nexport const STATUS_TO_CODE: Record<number, string> = {\n 0: 'OK',\n 1: 'ENOENT',\n 2: 'EEXIST',\n 3: 'EISDIR',\n 4: 'ENOTDIR',\n 5: 'ENOTEMPTY',\n 6: 'EACCES',\n 7: 'EINVAL',\n 8: 'EBADF',\n 9: 'ELOOP',\n 10: 'ENOSPC',\n};\n\n/** Error code → binary protocol status mapping */\nexport const CODE_TO_STATUS: Record<string, number> = {\n OK: 0,\n ENOENT: 1,\n EEXIST: 2,\n EISDIR: 3,\n ENOTDIR: 4,\n ENOTEMPTY: 5,\n EACCES: 6,\n EINVAL: 7,\n EBADF: 8,\n ELOOP: 9,\n ENOSPC: 10,\n};\n\nexport function createError(code: string, syscall: string, path: string): FSError {\n const errno = ErrorCodes[code as keyof typeof ErrorCodes] ?? -1;\n const messages: Record<string, string> = {\n ENOENT: 'no such file or directory',\n EEXIST: 'file already exists',\n EISDIR: 'illegal operation on a directory',\n ENOTDIR: 'not a directory',\n ENOTEMPTY: 'directory not empty',\n EACCES: 'permission denied',\n EINVAL: 'invalid argument',\n EBADF: 'bad file descriptor',\n ELOOP: 'too many symbolic links encountered',\n ENOSPC: 'no space left on device',\n };\n const msg = messages[code] ?? 'unknown error';\n return new FSError(code, errno, `${code}: ${msg}, ${syscall} '${path}'`, syscall, path);\n}\n\nexport function statusToError(status: number, syscall: string, path: string): FSError {\n const code = STATUS_TO_CODE[status] ?? 'EINVAL';\n return createError(code, syscall, path);\n}\n","/**\n * VFS Engine — operates on a FileSystemSyncAccessHandle\n *\n * Manages the binary VFS layout: superblock, inode table, path table,\n * free block bitmap, and data region. All operations are synchronous\n * and run inside the server worker.\n */\n\nimport {\n VFS_MAGIC, VFS_VERSION, SUPERBLOCK, INODE, INODE_SIZE, INODE_TYPE,\n DEFAULT_BLOCK_SIZE, DEFAULT_INODE_COUNT, DEFAULT_FILE_MODE, DEFAULT_DIR_MODE,\n DEFAULT_SYMLINK_MODE, DEFAULT_UMASK, S_IFMT, S_IFREG, S_IFDIR, S_IFLNK,\n MAX_SYMLINK_DEPTH, INITIAL_DATA_BLOCKS, INITIAL_PATH_TABLE_SIZE,\n calculateLayout,\n} from './layout.js';\nimport { CODE_TO_STATUS } from '../errors.js';\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\ninterface Inode {\n type: number;\n pathOffset: number;\n pathLength: number;\n mode: number;\n size: number;\n firstBlock: number;\n blockCount: number;\n mtime: number;\n ctime: number;\n atime: number;\n uid: number;\n gid: number;\n nlink: number;\n}\n\ninterface FdEntry {\n tabId: string;\n inodeIdx: number;\n position: number;\n flags: number;\n implicitPath?: string; // set when fd was opened via opendir on an implicit directory\n}\n\nexport class VFSEngine {\n private handle!: FileSystemSyncAccessHandle;\n private pathIndex = new Map<string, number>(); // path → inode index\n private inodeCount = 0;\n private blockSize = DEFAULT_BLOCK_SIZE;\n private totalBlocks = 0;\n private freeBlocks = 0;\n private inodeTableOffset = 0;\n private pathTableOffset = 0;\n private pathTableUsed = 0;\n private pathTableSize = 0;\n private bitmapOffset = 0;\n private dataOffset = 0;\n private umask = DEFAULT_UMASK;\n private processUid = 0;\n private processGid = 0;\n private strictPermissions = false;\n private debug = false;\n\n // File descriptor table\n private fdTable = new Map<number, FdEntry>();\n private nextFd = 3; // 0=stdin, 1=stdout, 2=stderr reserved\n\n // Reusable buffers to avoid allocations\n private inodeBuf = new Uint8Array(INODE_SIZE);\n private inodeView = new DataView(this.inodeBuf.buffer);\n\n // In-memory inode cache — eliminates disk reads for hot inodes\n private inodeCache = new Map<number, Inode>();\n private superblockBuf = new Uint8Array(SUPERBLOCK.SIZE);\n private superblockView = new DataView(this.superblockBuf.buffer);\n\n // In-memory bitmap cache — eliminates bitmap reads from OPFS\n private bitmap: Uint8Array | null = null;\n private bitmapDirtyLo = Infinity; // lowest dirty byte index\n private bitmapDirtyHi = -1; // highest dirty byte index (inclusive)\n private superblockDirty = false;\n\n // Free inode hint — skip O(n) scan\n private freeInodeHint = 0;\n\n // Implicit directory support — tracks all directory prefixes implied by file paths.\n // Rebuilt lazily when pathIndex changes (tracked via generation counter).\n // Map value is the stable timestamp (ms since epoch) assigned when the implicit\n // dir was first discovered, so that stat() returns consistent mtime/ctime/atime\n // across repeated calls.\n private implicitDirs = new Map<string, number>();\n private implicitDirsGen = -1; // generation when implicitDirs was last rebuilt\n private pathIndexGen = 0; // bumped on every pathIndex mutation\n\n // Configurable upper bounds\n private maxInodes = 4_000_000;\n private maxBlocks = 4_000_000;\n private maxPathTable = 256 * 1024 * 1024; // 256MB\n private maxVFSSize = 100 * 1024 * 1024 * 1024; // 100GB\n\n init(\n handle: FileSystemSyncAccessHandle,\n opts?: {\n uid?: number; gid?: number; umask?: number; strictPermissions?: boolean; debug?: boolean;\n limits?: { maxInodes?: number; maxBlocks?: number; maxPathTable?: number; maxVFSSize?: number };\n }\n ): void {\n this.handle = handle;\n this.processUid = opts?.uid ?? 0;\n this.processGid = opts?.gid ?? 0;\n this.umask = opts?.umask ?? DEFAULT_UMASK;\n this.strictPermissions = opts?.strictPermissions ?? false;\n this.debug = opts?.debug ?? false;\n if (opts?.limits) {\n if (opts.limits.maxInodes != null) this.maxInodes = opts.limits.maxInodes;\n if (opts.limits.maxBlocks != null) this.maxBlocks = opts.limits.maxBlocks;\n if (opts.limits.maxPathTable != null) this.maxPathTable = opts.limits.maxPathTable;\n if (opts.limits.maxVFSSize != null) this.maxVFSSize = opts.limits.maxVFSSize;\n }\n\n const size = handle.getSize();\n\n if (size === 0) {\n this.format();\n } else {\n try {\n this.mount();\n } catch (err) {\n // Ensure all mount errors are prefixed with \"Corrupt VFS:\" so the\n // sync-relay handler recognizes them as corruption (not OPFS contention)\n // and triggers fallback instead of infinite retry.\n const msg = (err as Error).message ?? String(err);\n if (msg.startsWith('Corrupt VFS:')) throw err;\n throw new Error(`Corrupt VFS: ${msg}`);\n }\n }\n }\n\n /** Release the sync access handle (call on fatal error or shutdown) */\n closeHandle(): void {\n try {\n this.handle?.close();\n } catch (_) {\n // Ignore — handle may already be closed\n }\n }\n\n /** Format a fresh VFS */\n private format(): void {\n const layout = calculateLayout(DEFAULT_INODE_COUNT, DEFAULT_BLOCK_SIZE, INITIAL_DATA_BLOCKS);\n\n this.inodeCount = DEFAULT_INODE_COUNT;\n this.blockSize = DEFAULT_BLOCK_SIZE;\n this.totalBlocks = layout.totalBlocks;\n this.freeBlocks = layout.totalBlocks;\n this.inodeTableOffset = layout.inodeTableOffset;\n this.pathTableOffset = layout.pathTableOffset;\n this.pathTableSize = layout.pathTableSize;\n this.pathTableUsed = 0;\n this.bitmapOffset = layout.bitmapOffset;\n this.dataOffset = layout.dataOffset;\n\n // Grow file to total size\n this.handle.truncate(layout.totalSize);\n\n // Write superblock\n this.writeSuperblock();\n\n // Zero out inode table (type=0 means free)\n const zeroBuf = new Uint8Array(layout.inodeTableSize);\n this.handle.write(zeroBuf, { at: this.inodeTableOffset });\n\n // Zero out bitmap and cache in memory\n this.bitmap = new Uint8Array(layout.bitmapSize);\n this.handle.write(this.bitmap, { at: this.bitmapOffset });\n\n // Create root directory inode\n this.createInode('/', INODE_TYPE.DIRECTORY, DEFAULT_DIR_MODE, 0);\n\n // Re-write superblock with updated pathTableUsed (createInode appended \"/\" to path table)\n this.writeSuperblock();\n this.handle.flush();\n }\n\n /** Mount an existing VFS from disk — validates superblock integrity */\n private mount(): void {\n const fileSize = this.handle.getSize();\n if (fileSize < SUPERBLOCK.SIZE) {\n throw new Error(`Corrupt VFS: file too small (${fileSize} bytes, need at least ${SUPERBLOCK.SIZE})`);\n }\n\n this.handle.read(this.superblockBuf, { at: 0 });\n const v = this.superblockView;\n\n // Validate magic\n const magic = v.getUint32(SUPERBLOCK.MAGIC, true);\n if (magic !== VFS_MAGIC) {\n throw new Error(`Corrupt VFS: bad magic 0x${magic.toString(16)} (expected 0x${VFS_MAGIC.toString(16)})`);\n }\n\n // Validate version\n const version = v.getUint32(SUPERBLOCK.VERSION, true);\n if (version !== VFS_VERSION) {\n throw new Error(`Corrupt VFS: unsupported version ${version} (expected ${VFS_VERSION})`);\n }\n\n // Read superblock fields\n const inodeCount = v.getUint32(SUPERBLOCK.INODE_COUNT, true);\n const blockSize = v.getUint32(SUPERBLOCK.BLOCK_SIZE, true);\n const totalBlocks = v.getUint32(SUPERBLOCK.TOTAL_BLOCKS, true);\n const freeBlocks = v.getUint32(SUPERBLOCK.FREE_BLOCKS, true);\n const inodeTableOffset = v.getFloat64(SUPERBLOCK.INODE_OFFSET, true);\n const pathTableOffset = v.getFloat64(SUPERBLOCK.PATH_OFFSET, true);\n const dataOffset = v.getFloat64(SUPERBLOCK.DATA_OFFSET, true);\n const bitmapOffset = v.getFloat64(SUPERBLOCK.BITMAP_OFFSET, true);\n const pathUsed = v.getUint32(SUPERBLOCK.PATH_USED, true);\n\n // Validate field sanity\n if (blockSize === 0 || (blockSize & (blockSize - 1)) !== 0) {\n throw new Error(`Corrupt VFS: invalid block size ${blockSize} (must be power of 2)`);\n }\n if (inodeCount === 0) {\n throw new Error('Corrupt VFS: inode count is 0');\n }\n if (freeBlocks > totalBlocks) {\n throw new Error(`Corrupt VFS: free blocks (${freeBlocks}) exceeds total blocks (${totalBlocks})`);\n }\n\n // Sane upper bounds — prevent huge allocations from corrupt values.\n // Configurable via opts.limits in init().\n if (inodeCount > this.maxInodes) {\n throw new Error(`Corrupt VFS: inode count ${inodeCount} exceeds maximum ${this.maxInodes}`);\n }\n if (totalBlocks > this.maxBlocks) {\n throw new Error(`Corrupt VFS: total blocks ${totalBlocks} exceeds maximum ${this.maxBlocks}`);\n }\n if (fileSize > this.maxVFSSize) {\n throw new Error(`Corrupt VFS: file size ${fileSize} exceeds maximum ${this.maxVFSSize}`);\n }\n\n // Validate all offsets are finite positive integers\n if (!Number.isFinite(inodeTableOffset) || inodeTableOffset < 0 ||\n !Number.isFinite(pathTableOffset) || pathTableOffset < 0 ||\n !Number.isFinite(bitmapOffset) || bitmapOffset < 0 ||\n !Number.isFinite(dataOffset) || dataOffset < 0) {\n throw new Error(`Corrupt VFS: non-finite or negative section offset`);\n }\n\n // Validate section ordering: superblock < inodes < paths < bitmap < data\n if (inodeTableOffset !== SUPERBLOCK.SIZE) {\n throw new Error(`Corrupt VFS: inode table offset ${inodeTableOffset} (expected ${SUPERBLOCK.SIZE})`);\n }\n const expectedPathOffset = inodeTableOffset + inodeCount * INODE_SIZE;\n if (pathTableOffset !== expectedPathOffset) {\n throw new Error(`Corrupt VFS: path table offset ${pathTableOffset} (expected ${expectedPathOffset})`);\n }\n if (bitmapOffset <= pathTableOffset) {\n throw new Error(`Corrupt VFS: bitmap offset ${bitmapOffset} must be after path table ${pathTableOffset}`);\n }\n if (dataOffset <= bitmapOffset) {\n throw new Error(`Corrupt VFS: data offset ${dataOffset} must be after bitmap ${bitmapOffset}`);\n }\n const pathTableSize = bitmapOffset - pathTableOffset;\n if (pathUsed > pathTableSize) {\n throw new Error(`Corrupt VFS: path used (${pathUsed}) exceeds path table size (${pathTableSize})`);\n }\n if (pathTableSize > this.maxPathTable) {\n throw new Error(`Corrupt VFS: path table size ${pathTableSize} exceeds maximum ${this.maxPathTable}`);\n }\n\n // Validate file is large enough for the declared layout\n const expectedMinSize = dataOffset + totalBlocks * blockSize;\n if (expectedMinSize > this.maxVFSSize) {\n throw new Error(`Corrupt VFS: computed layout size ${expectedMinSize} exceeds maximum ${this.maxVFSSize}`);\n }\n if (fileSize < expectedMinSize) {\n throw new Error(`Corrupt VFS: file size ${fileSize} too small for layout (need ${expectedMinSize})`);\n }\n\n // All checks passed — commit to engine state\n this.inodeCount = inodeCount;\n this.blockSize = blockSize;\n this.totalBlocks = totalBlocks;\n this.freeBlocks = freeBlocks;\n this.inodeTableOffset = inodeTableOffset;\n this.pathTableOffset = pathTableOffset;\n this.dataOffset = dataOffset;\n this.bitmapOffset = bitmapOffset;\n this.pathTableUsed = pathUsed;\n this.pathTableSize = pathTableSize;\n\n // Load bitmap into memory\n const bitmapSize = Math.ceil(this.totalBlocks / 8);\n this.bitmap = new Uint8Array(bitmapSize);\n this.handle.read(this.bitmap, { at: this.bitmapOffset });\n\n this.rebuildIndex();\n\n // Verify root directory exists\n if (!this.pathIndex.has('/')) {\n throw new Error('Corrupt VFS: root directory \"/\" not found in inode table');\n }\n }\n\n private writeSuperblock(): void {\n const v = this.superblockView;\n v.setUint32(SUPERBLOCK.MAGIC, VFS_MAGIC, true);\n v.setUint32(SUPERBLOCK.VERSION, VFS_VERSION, true);\n v.setUint32(SUPERBLOCK.INODE_COUNT, this.inodeCount, true);\n v.setUint32(SUPERBLOCK.BLOCK_SIZE, this.blockSize, true);\n v.setUint32(SUPERBLOCK.TOTAL_BLOCKS, this.totalBlocks, true);\n v.setUint32(SUPERBLOCK.FREE_BLOCKS, this.freeBlocks, true);\n v.setFloat64(SUPERBLOCK.INODE_OFFSET, this.inodeTableOffset, true);\n v.setFloat64(SUPERBLOCK.PATH_OFFSET, this.pathTableOffset, true);\n v.setFloat64(SUPERBLOCK.DATA_OFFSET, this.dataOffset, true);\n v.setFloat64(SUPERBLOCK.BITMAP_OFFSET, this.bitmapOffset, true);\n v.setUint32(SUPERBLOCK.PATH_USED, this.pathTableUsed, true);\n this.handle.write(this.superblockBuf, { at: 0 });\n }\n\n /** Flush pending bitmap and superblock writes to disk (one write each) */\n private markBitmapDirty(lo: number, hi: number): void {\n if (lo < this.bitmapDirtyLo) this.bitmapDirtyLo = lo;\n if (hi > this.bitmapDirtyHi) this.bitmapDirtyHi = hi;\n }\n\n private commitPending(): void {\n // Trim trailing free blocks before flushing bitmap/superblock\n if (this.blocksFreedsinceTrim) {\n this.trimTrailingBlocks();\n this.blocksFreedsinceTrim = false;\n }\n\n if (this.bitmapDirtyHi >= 0) {\n const lo = this.bitmapDirtyLo;\n const hi = this.bitmapDirtyHi;\n this.handle.write(this.bitmap!.subarray(lo, hi + 1), { at: this.bitmapOffset + lo });\n this.bitmapDirtyLo = Infinity;\n this.bitmapDirtyHi = -1;\n }\n if (this.superblockDirty) {\n this.writeSuperblock();\n this.superblockDirty = false;\n }\n }\n\n /** Shrink the OPFS file by removing trailing free blocks from the data region.\n * Scans bitmap from end to find the last used block, then truncates. */\n private trimTrailingBlocks(): void {\n const bitmap = this.bitmap!;\n\n // Find the last used block by scanning bitmap from the end\n let lastUsed = -1;\n for (let byteIdx = Math.ceil(this.totalBlocks / 8) - 1; byteIdx >= 0; byteIdx--) {\n if (bitmap[byteIdx] !== 0) {\n // Find highest set bit in this byte\n for (let bit = 7; bit >= 0; bit--) {\n const blockIdx = byteIdx * 8 + bit;\n if (blockIdx < this.totalBlocks && (bitmap[byteIdx] & (1 << bit))) {\n lastUsed = blockIdx;\n break;\n }\n }\n break;\n }\n }\n\n const newTotal = Math.max(lastUsed + 1, INITIAL_DATA_BLOCKS);\n if (newTotal >= this.totalBlocks) return; // nothing to trim\n\n // Truncate the OPFS file\n this.handle.truncate(this.dataOffset + newTotal * this.blockSize);\n\n // Shrink in-memory bitmap\n const newBitmapSize = Math.ceil(newTotal / 8);\n this.bitmap = bitmap.slice(0, newBitmapSize);\n\n // Update counters\n const trimmed = this.totalBlocks - newTotal;\n this.freeBlocks -= trimmed; // these free blocks no longer exist\n this.totalBlocks = newTotal;\n this.superblockDirty = true;\n\n // Re-mark entire bitmap dirty so the smaller bitmap is flushed\n this.bitmapDirtyLo = 0;\n this.bitmapDirtyHi = newBitmapSize - 1;\n }\n\n /** Rebuild in-memory path→inode index from disk.\n * Bulk-reads the entire inode table + path table in 2 I/O calls,\n * then parses in memory (avoids 10k+ individual reads). */\n private rebuildIndex(): void {\n this.pathIndex.clear();\n this.inodeCache.clear();\n\n // Bulk read entire inode table (e.g. 640KB for 10k inodes)\n const inodeTableSize = this.inodeCount * INODE_SIZE;\n const inodeBuf = new Uint8Array(inodeTableSize);\n this.handle.read(inodeBuf, { at: this.inodeTableOffset });\n const inodeView = new DataView(inodeBuf.buffer);\n\n // Bulk read used portion of path table\n const pathBuf = this.pathTableUsed > 0 ? new Uint8Array(this.pathTableUsed) : null;\n if (pathBuf) {\n this.handle.read(pathBuf, { at: this.pathTableOffset });\n }\n\n for (let i = 0; i < this.inodeCount; i++) {\n const off = i * INODE_SIZE;\n const type = inodeView.getUint8(off + INODE.TYPE);\n if (type === INODE_TYPE.FREE) continue;\n\n // Validate inode type\n if (type < INODE_TYPE.FILE || type > INODE_TYPE.SYMLINK) {\n throw new Error(`Corrupt VFS: inode ${i} has invalid type ${type}`);\n }\n\n const pathOffset = inodeView.getUint32(off + INODE.PATH_OFFSET, true);\n const pathLength = inodeView.getUint16(off + INODE.PATH_LENGTH, true);\n const size = inodeView.getFloat64(off + INODE.SIZE, true);\n const firstBlock = inodeView.getUint32(off + INODE.FIRST_BLOCK, true);\n const blockCount = inodeView.getUint32(off + INODE.BLOCK_COUNT, true);\n\n // Validate path bounds\n if (pathLength === 0 || pathOffset + pathLength > this.pathTableUsed) {\n throw new Error(`Corrupt VFS: inode ${i} path out of bounds (offset=${pathOffset}, len=${pathLength}, tableUsed=${this.pathTableUsed})`);\n }\n\n // Validate data bounds for files/symlinks\n if (type !== INODE_TYPE.DIRECTORY) {\n if (size < 0 || !isFinite(size)) {\n throw new Error(`Corrupt VFS: inode ${i} has invalid size ${size}`);\n }\n if (blockCount > 0 && firstBlock + blockCount > this.totalBlocks) {\n throw new Error(`Corrupt VFS: inode ${i} data blocks out of range (first=${firstBlock}, count=${blockCount}, total=${this.totalBlocks})`);\n }\n }\n\n const inode: Inode = {\n type,\n pathOffset,\n pathLength,\n nlink: inodeView.getUint16(off + INODE.NLINK, true) || 1,\n mode: inodeView.getUint32(off + INODE.MODE, true),\n size,\n firstBlock,\n blockCount,\n mtime: inodeView.getFloat64(off + INODE.MTIME, true),\n ctime: inodeView.getFloat64(off + INODE.CTIME, true),\n atime: inodeView.getFloat64(off + INODE.ATIME, true),\n uid: inodeView.getUint32(off + INODE.UID, true),\n gid: inodeView.getUint32(off + INODE.GID, true),\n };\n this.inodeCache.set(i, inode);\n\n // Decode path from in-memory path table buffer (no disk read)\n let path: string;\n if (pathBuf) {\n path = decoder.decode(pathBuf.subarray(inode.pathOffset, inode.pathOffset + inode.pathLength));\n } else {\n path = this.readPath(inode.pathOffset, inode.pathLength);\n }\n\n // Validate path format\n if (!path.startsWith('/') || path.includes('\\0')) {\n throw new Error(`Corrupt VFS: inode ${i} has invalid path \"${path.substring(0, 50)}\"`);\n }\n\n this.pathIndex.set(path, i);\n }\n this.pathIndexGen++;\n }\n\n // ========== Low-level inode I/O ==========\n\n private readInode(idx: number): Inode {\n const cached = this.inodeCache.get(idx);\n if (cached) return cached;\n\n const offset = this.inodeTableOffset + idx * INODE_SIZE;\n this.handle.read(this.inodeBuf, { at: offset });\n const v = this.inodeView;\n const inode: Inode = {\n type: v.getUint8(INODE.TYPE),\n pathOffset: v.getUint32(INODE.PATH_OFFSET, true),\n pathLength: v.getUint16(INODE.PATH_LENGTH, true),\n nlink: v.getUint16(INODE.NLINK, true) || 1,\n mode: v.getUint32(INODE.MODE, true),\n size: v.getFloat64(INODE.SIZE, true),\n firstBlock: v.getUint32(INODE.FIRST_BLOCK, true),\n blockCount: v.getUint32(INODE.BLOCK_COUNT, true),\n mtime: v.getFloat64(INODE.MTIME, true),\n ctime: v.getFloat64(INODE.CTIME, true),\n atime: v.getFloat64(INODE.ATIME, true),\n uid: v.getUint32(INODE.UID, true),\n gid: v.getUint32(INODE.GID, true),\n };\n this.inodeCache.set(idx, inode);\n return inode;\n }\n\n private writeInode(idx: number, inode: Inode): void {\n // Maintain inode cache\n if (inode.type === INODE_TYPE.FREE) {\n this.inodeCache.delete(idx);\n } else {\n this.inodeCache.set(idx, inode);\n }\n\n const v = this.inodeView;\n v.setUint8(INODE.TYPE, inode.type);\n v.setUint8(INODE.FLAGS, 0);\n v.setUint8(INODE.FLAGS + 1, 0);\n v.setUint8(INODE.FLAGS + 2, 0);\n v.setUint32(INODE.PATH_OFFSET, inode.pathOffset, true);\n v.setUint16(INODE.PATH_LENGTH, inode.pathLength, true);\n v.setUint16(INODE.NLINK, inode.nlink, true);\n v.setUint32(INODE.MODE, inode.mode, true);\n v.setFloat64(INODE.SIZE, inode.size, true);\n v.setUint32(INODE.FIRST_BLOCK, inode.firstBlock, true);\n v.setUint32(INODE.BLOCK_COUNT, inode.blockCount, true);\n v.setFloat64(INODE.MTIME, inode.mtime, true);\n v.setFloat64(INODE.CTIME, inode.ctime, true);\n v.setFloat64(INODE.ATIME, inode.atime, true);\n v.setUint32(INODE.UID, inode.uid, true);\n v.setUint32(INODE.GID, inode.gid, true);\n\n const offset = this.inodeTableOffset + idx * INODE_SIZE;\n this.handle.write(this.inodeBuf, { at: offset });\n }\n\n // ========== Path table I/O ==========\n\n private readPath(offset: number, length: number): string {\n const buf = new Uint8Array(length);\n this.handle.read(buf, { at: this.pathTableOffset + offset });\n return decoder.decode(buf);\n }\n\n private appendPath(path: string): { offset: number; length: number } {\n const bytes = encoder.encode(path);\n const offset = this.pathTableUsed;\n\n // Check if path table needs to grow\n if (offset + bytes.byteLength > this.pathTableSize) {\n this.growPathTable(offset + bytes.byteLength);\n }\n\n this.handle.write(bytes, { at: this.pathTableOffset + offset });\n this.pathTableUsed += bytes.byteLength;\n\n // Defer superblock write — committed in commitPending()\n this.superblockDirty = true;\n\n return { offset, length: bytes.byteLength };\n }\n\n private growPathTable(needed: number): void {\n // Double the path table or grow to fit needed, whichever is larger\n const newSize = Math.max(this.pathTableSize * 2, needed + INITIAL_PATH_TABLE_SIZE);\n const growth = newSize - this.pathTableSize;\n\n // Grow file first so the shifted data has somewhere to land.\n const newTotalSize = this.handle.getSize() + growth;\n this.handle.truncate(newTotalSize);\n\n // Shift the data region forward by `growth` bytes. We must NOT allocate\n // a single buffer the size of the whole data section — when the VFS\n // holds a large install (pnpm linking ~1300 Directus packages puts the\n // data section in the hundreds of MB) the one-shot\n // new Uint8Array(dataSize)\n // failed with \"Array buffer allocation failed\" because Chrome refuses\n // allocations near the 2 GB cap even with OS memory to spare.\n //\n // Copy back-to-front through a small scratch buffer so we never\n // overwrite bytes we haven't relocated yet, and the peak allocation\n // stays bounded at CHUNK regardless of how big the VFS has grown.\n const dataSize = this.totalBlocks * this.blockSize;\n const CHUNK = 4 * 1024 * 1024; // 4 MB\n const scratch = new Uint8Array(Math.min(CHUNK, Math.max(dataSize, 1)));\n let remaining = dataSize;\n while (remaining > 0) {\n const chunk = Math.min(remaining, CHUNK);\n const srcAt = this.dataOffset + (remaining - chunk);\n const dstAt = this.dataOffset + growth + (remaining - chunk);\n const slice = chunk < scratch.length ? scratch.subarray(0, chunk) : scratch;\n this.handle.read(slice, { at: srcAt });\n this.handle.write(slice, { at: dstAt });\n remaining -= chunk;\n }\n\n // Write the (in-memory) bitmap to its new offset.\n const newBitmapOffset = this.bitmapOffset + growth;\n const newDataOffset = this.dataOffset + growth;\n this.handle.write(this.bitmap!, { at: newBitmapOffset });\n\n // Update offsets\n this.pathTableSize = newSize;\n this.bitmapOffset = newBitmapOffset;\n this.dataOffset = newDataOffset;\n\n // Mark superblock dirty (will be written in commitPending)\n this.superblockDirty = true;\n }\n\n // ========== Bitmap I/O ==========\n\n // Write `length` zero bytes at absolute file offset `at` via a small\n // reusable scratch buffer. Used to materialize POSIX \"holes\" when a\n // write starts past the current file size — those bytes must read as\n // zeros rather than whatever stale data happened to live in the\n // underlying storage blocks.\n private zeroFileRange(at: number, length: number): void {\n if (length <= 0) return;\n const CHUNK = 4 * 1024 * 1024;\n const zeros = new Uint8Array(Math.min(length, CHUNK));\n let written = 0;\n while (written < length) {\n const n = Math.min(CHUNK, length - written);\n const slice = n < zeros.length ? zeros.subarray(0, n) : zeros;\n this.handle.write(slice, { at: at + written });\n written += n;\n }\n }\n\n private allocateBlocks(count: number): number {\n if (count === 0) return 0;\n\n const bitmap = this.bitmap!;\n let run = 0;\n let start = 0;\n\n for (let i = 0; i < this.totalBlocks; i++) {\n const byteIdx = i >>> 3;\n const bitIdx = i & 7;\n const used = (bitmap[byteIdx] >>> bitIdx) & 1;\n\n if (used) {\n run = 0;\n start = i + 1;\n } else {\n run++;\n if (run === count) {\n // Mark blocks as used in memory\n for (let j = start; j <= i; j++) {\n const bj = j >>> 3;\n const bi = j & 7;\n bitmap[bj] |= (1 << bi);\n }\n this.markBitmapDirty(start >>> 3, i >>> 3);\n this.freeBlocks -= count;\n this.superblockDirty = true;\n return start;\n }\n }\n }\n\n // No contiguous space — grow data region\n return this.growAndAllocate(count);\n }\n\n private growAndAllocate(count: number): number {\n const oldTotal = this.totalBlocks;\n // Grow by at least doubling or enough for the request\n const newTotal = Math.max(oldTotal * 2, oldTotal + count);\n const addedBlocks = newTotal - oldTotal;\n\n // Grow the file\n const newFileSize = this.dataOffset + newTotal * this.blockSize;\n this.handle.truncate(newFileSize);\n\n // Grow in-memory bitmap\n const newBitmapSize = Math.ceil(newTotal / 8);\n const newBitmap = new Uint8Array(newBitmapSize);\n newBitmap.set(this.bitmap!);\n this.bitmap = newBitmap;\n\n this.totalBlocks = newTotal;\n this.freeBlocks += addedBlocks;\n\n // Allocate from the newly freed area\n const start = oldTotal;\n for (let j = start; j < start + count; j++) {\n const bj = j >>> 3;\n const bi = j & 7;\n this.bitmap[bj] |= (1 << bi);\n }\n\n this.markBitmapDirty(start >>> 3, (start + count - 1) >>> 3);\n this.freeBlocks -= count;\n this.superblockDirty = true;\n\n return start;\n }\n\n private blocksFreedsinceTrim = false;\n\n private freeBlockRange(start: number, count: number): void {\n if (count === 0) return;\n const bitmap = this.bitmap!;\n\n for (let i = start; i < start + count; i++) {\n const byteIdx = i >>> 3;\n const bitIdx = i & 7;\n bitmap[byteIdx] &= ~(1 << bitIdx);\n }\n\n this.markBitmapDirty(start >>> 3, (start + count - 1) >>> 3);\n this.freeBlocks += count;\n this.superblockDirty = true;\n this.blocksFreedsinceTrim = true;\n }\n\n // updateSuperblockFreeBlocks is no longer needed — superblock writes are coalesced via commitPending()\n\n // ========== Inode allocation ==========\n\n private findFreeInode(): number {\n // Start from hint to skip already-used entries\n for (let i = this.freeInodeHint; i < this.inodeCount; i++) {\n // Check cache first — cached entries are never FREE\n if (this.inodeCache.has(i)) continue;\n\n const offset = this.inodeTableOffset + i * INODE_SIZE;\n const typeBuf = new Uint8Array(1);\n this.handle.read(typeBuf, { at: offset });\n if (typeBuf[0] === INODE_TYPE.FREE) {\n this.freeInodeHint = i + 1;\n return i;\n }\n }\n // All inodes used — grow inode table\n const idx = this.growInodeTable();\n this.freeInodeHint = idx + 1;\n return idx;\n }\n\n private growInodeTable(): number {\n const oldCount = this.inodeCount;\n const newCount = oldCount * 2;\n const growth = (newCount - oldCount) * INODE_SIZE;\n\n // Read everything after inode table\n const afterInodeOffset = this.inodeTableOffset + oldCount * INODE_SIZE;\n const afterSize = this.handle.getSize() - afterInodeOffset;\n const afterBuf = new Uint8Array(afterSize);\n this.handle.read(afterBuf, { at: afterInodeOffset });\n\n // Grow file\n this.handle.truncate(this.handle.getSize() + growth);\n\n // Write back shifted content\n this.handle.write(afterBuf, { at: afterInodeOffset + growth });\n\n // Zero out new inode entries\n const zeroes = new Uint8Array(growth);\n this.handle.write(zeroes, { at: afterInodeOffset });\n\n // Update offsets\n this.pathTableOffset += growth;\n this.bitmapOffset += growth;\n this.dataOffset += growth;\n this.inodeCount = newCount;\n\n this.superblockDirty = true;\n\n return oldCount; // First new free inode\n }\n\n // ========== Data I/O ==========\n\n private readData(firstBlock: number, blockCount: number, size: number): Uint8Array {\n const buf = new Uint8Array(size);\n const offset = this.dataOffset + firstBlock * this.blockSize;\n this.handle.read(buf, { at: offset });\n return buf;\n }\n\n private writeData(firstBlock: number, data: Uint8Array): void {\n const offset = this.dataOffset + firstBlock * this.blockSize;\n this.handle.write(data, { at: offset });\n }\n\n // ========== Path resolution ==========\n\n private resolvePath(path: string, depth: number = 0): number | undefined {\n if (depth > MAX_SYMLINK_DEPTH) return undefined; // ELOOP\n\n const idx = this.pathIndex.get(path);\n if (idx === undefined) {\n // Path not found directly — try component resolution (handles intermediate symlinks)\n return this.resolvePathComponents(path, true, depth);\n }\n\n const inode = this.readInode(idx);\n if (inode.type === INODE_TYPE.SYMLINK) {\n // Follow symlink\n const target = decoder.decode(this.readData(inode.firstBlock, inode.blockCount, inode.size));\n const resolved = target.startsWith('/') ? target : this.resolveRelative(path, target);\n return this.resolvePath(resolved, depth + 1);\n }\n\n return idx;\n }\n\n /** Resolve symlinks in intermediate path components */\n private resolvePathComponents(path: string, followLast: boolean = true, depth: number = 0): number | undefined {\n const result = this.resolvePathFull(path, followLast, depth);\n return result?.idx;\n }\n\n /**\n * Resolve a path following symlinks, returning both the inode index AND the\n * fully resolved path. This is needed by readdir: when listing a symlinked\n * directory, we must search for children under the resolved target path\n * (where files actually exist in pathIndex), not under the symlink path.\n */\n private resolvePathFull(path: string, followLast: boolean = true, depth: number = 0): { idx: number; resolvedPath: string } | undefined {\n if (depth > MAX_SYMLINK_DEPTH) return undefined; // ELOOP\n\n const parts = path.split('/').filter(Boolean);\n let current = '/';\n\n for (let i = 0; i < parts.length; i++) {\n const isLast = i === parts.length - 1;\n current = current === '/' ? '/' + parts[i] : current + '/' + parts[i];\n\n const idx = this.pathIndex.get(current);\n if (idx === undefined) return undefined;\n\n const inode = this.readInode(idx);\n if (inode.type === INODE_TYPE.SYMLINK && (!isLast || followLast)) {\n const target = decoder.decode(this.readData(inode.firstBlock, inode.blockCount, inode.size));\n const resolved = target.startsWith('/') ? target : this.resolveRelative(current, target);\n\n if (isLast) {\n // Use resolvePathFull (not resolvePath) so intermediate symlinks\n // in the resolved target path are also followed\n return this.resolvePathFull(resolved, true, depth + 1);\n }\n\n // Reconstruct remaining path with resolved symlink\n const remaining = parts.slice(i + 1).join('/');\n const newPath = resolved + (remaining ? '/' + remaining : '');\n return this.resolvePathFull(newPath, followLast, depth + 1);\n }\n }\n\n const finalIdx = this.pathIndex.get(current);\n if (finalIdx === undefined) return undefined;\n return { idx: finalIdx, resolvedPath: current };\n }\n\n private resolveRelative(from: string, target: string): string {\n const dir = from.substring(0, from.lastIndexOf('/')) || '/';\n const parts = (dir + '/' + target).split('/').filter(Boolean);\n const resolved: string[] = [];\n for (const p of parts) {\n if (p === '.') continue;\n if (p === '..') { resolved.pop(); continue; }\n resolved.push(p);\n }\n return '/' + resolved.join('/');\n }\n\n // ========== Core inode creation helper ==========\n\n private createInode(path: string, type: number, mode: number, size: number, data?: Uint8Array): number {\n const idx = this.findFreeInode();\n const { offset: pathOff, length: pathLen } = this.appendPath(path);\n const now = Date.now();\n\n let firstBlock = 0;\n let blockCount = 0;\n\n if (data && data.byteLength > 0) {\n blockCount = Math.ceil(data.byteLength / this.blockSize);\n firstBlock = this.allocateBlocks(blockCount);\n this.writeData(firstBlock, data);\n }\n\n const inode: Inode = {\n type,\n pathOffset: pathOff,\n pathLength: pathLen,\n nlink: type === INODE_TYPE.DIRECTORY ? 2 : 1,\n mode,\n size,\n firstBlock,\n blockCount,\n mtime: now,\n ctime: now,\n atime: now,\n uid: this.processUid,\n gid: this.processGid,\n };\n\n this.writeInode(idx, inode);\n this.pathIndex.set(path, idx);\n this.pathIndexGen++;\n\n return idx;\n }\n\n // ========== Public API — called by server worker dispatch ==========\n\n /** Normalize a path: ensure leading /, resolve . and .. */\n normalizePath(p: string): string {\n if (p.charCodeAt(0) !== 47) p = '/' + p; // 47 = '/'\n // Fast path: already normalized (no '.', '..', '//', trailing '/')\n if (p.length === 1) return p; // \"/\"\n if (p.indexOf('/.') === -1 && p.indexOf('//') === -1 && p.charCodeAt(p.length - 1) !== 47) {\n return p;\n }\n // Slow path: full normalize\n const parts = p.split('/').filter(Boolean);\n const resolved: string[] = [];\n for (const part of parts) {\n if (part === '.') continue;\n if (part === '..') { resolved.pop(); continue; }\n resolved.push(part);\n }\n return '/' + resolved.join('/');\n }\n\n // ---- READ ----\n read(path: string): { status: number; data: Uint8Array | null } {\n const t0 = this.debug ? performance.now() : 0;\n path = this.normalizePath(path);\n\n // Fast path: direct index lookup (skips component-by-component walk)\n let idx = this.pathIndex.get(path);\n if (idx !== undefined) {\n const inode = this.inodeCache.get(idx);\n if (inode) {\n // Symlink? Fall through to full resolve\n if (inode.type === INODE_TYPE.SYMLINK) {\n idx = this.resolvePathComponents(path, true);\n } else if (inode.type === INODE_TYPE.DIRECTORY) {\n return { status: CODE_TO_STATUS.EISDIR, data: null };\n } else {\n // Hot path: cached inode, no symlinks\n const data = inode.size > 0\n ? this.readData(inode.firstBlock, inode.blockCount, inode.size)\n : new Uint8Array(0);\n if (this.debug) {\n const t1 = performance.now();\n console.log(`[VFS read] path=${path} size=${inode.size} TOTAL=${(t1-t0).toFixed(3)}ms (fast)`);\n }\n return { status: 0, data };\n }\n }\n }\n\n // Slow path: full component resolution (handles symlinks, uncached inodes)\n if (idx === undefined) idx = this.resolvePathComponents(path, true);\n if (idx === undefined) return { status: CODE_TO_STATUS.ENOENT, data: null };\n\n const inode = this.readInode(idx);\n if (inode.type === INODE_TYPE.DIRECTORY) return { status: CODE_TO_STATUS.EISDIR, data: null };\n\n const data = inode.size > 0\n ? this.readData(inode.firstBlock, inode.blockCount, inode.size)\n : new Uint8Array(0);\n\n if (this.debug) {\n const t1 = performance.now();\n console.log(`[VFS read] path=${path} size=${inode.size} TOTAL=${(t1-t0).toFixed(3)}ms (slow path)`);\n }\n\n return { status: 0, data };\n }\n\n // ---- WRITE ----\n write(path: string, data: Uint8Array, flags: number = 0): { status: number } {\n const t0 = this.debug ? performance.now() : 0;\n path = this.normalizePath(path);\n const t1 = this.debug ? performance.now() : 0;\n\n // Ensure parent directory exists\n const parentStatus = this.ensureParent(path);\n if (parentStatus !== 0) return { status: parentStatus };\n const t2 = this.debug ? performance.now() : 0;\n\n const existingIdx = this.resolvePathComponents(path, true);\n const t3 = this.debug ? performance.now() : 0;\n\n let tAlloc = t3, tData = t3, tInode = t3;\n\n if (existingIdx !== undefined) {\n // Update existing file\n const inode = this.readInode(existingIdx);\n if (inode.type === INODE_TYPE.DIRECTORY) return { status: CODE_TO_STATUS.EISDIR };\n\n const neededBlocks = Math.ceil(data.byteLength / this.blockSize);\n\n if (neededBlocks <= inode.blockCount) {\n // Fits in current blocks\n tAlloc = this.debug ? performance.now() : 0;\n this.writeData(inode.firstBlock, data);\n tData = this.debug ? performance.now() : 0;\n if (neededBlocks < inode.blockCount) {\n this.freeBlockRange(inode.firstBlock + neededBlocks, inode.blockCount - neededBlocks);\n }\n } else {\n // Need more blocks — free old, allocate new\n this.freeBlockRange(inode.firstBlock, inode.blockCount);\n const newFirst = this.allocateBlocks(neededBlocks);\n tAlloc = this.debug ? performance.now() : 0;\n this.writeData(newFirst, data);\n tData = this.debug ? performance.now() : 0;\n inode.firstBlock = newFirst;\n }\n\n inode.size = data.byteLength;\n inode.blockCount = neededBlocks;\n inode.mtime = Date.now();\n this.writeInode(existingIdx, inode);\n tInode = this.debug ? performance.now() : 0;\n } else {\n // Refuse to create a regular file at a path that is an implicit\n // directory (children exist beneath it but no inode for the path\n // itself). Without this guard we'd register a FILE inode at `path`\n // while its descendants stay in pathIndex — the resulting \"file with\n // children\" state breaks every subsequent read of `path` and its\n // subtree.\n if (this.isImplicitDirectory(path)) return { status: CODE_TO_STATUS.EISDIR };\n // Create new file\n const mode = DEFAULT_FILE_MODE & ~(this.umask & 0o777);\n this.createInode(path, INODE_TYPE.FILE, mode, data.byteLength, data);\n tAlloc = this.debug ? performance.now() : 0;\n tData = tAlloc;\n tInode = tAlloc;\n }\n\n // Always commit pending superblock/bitmap changes (matches unlink, mkdir, etc.)\n // Without this, PATH_USED won't be persisted for newly created files,\n // causing \"path out of bounds\" corruption on reload.\n this.commitPending();\n if (flags & 1) {\n this.handle.flush();\n }\n const tFlush = this.debug ? performance.now() : 0;\n\n if (this.debug) {\n const existing = existingIdx !== undefined;\n console.log(`[VFS write] path=${path} size=${data.byteLength} ${existing ? 'UPDATE' : 'CREATE'} normalize=${(t1-t0).toFixed(3)}ms parent=${(t2-t1).toFixed(3)}ms resolve=${(t3-t2).toFixed(3)}ms alloc=${(tAlloc-t3).toFixed(3)}ms data=${(tData-tAlloc).toFixed(3)}ms inode=${(tInode-tData).toFixed(3)}ms flush=${(tFlush-tInode).toFixed(3)}ms TOTAL=${(tFlush-t0).toFixed(3)}ms`);\n }\n\n return { status: 0 };\n }\n\n // ---- APPEND ----\n append(path: string, data: Uint8Array): { status: number } {\n path = this.normalizePath(path);\n const existingIdx = this.resolvePathComponents(path, true);\n\n if (existingIdx === undefined) {\n // Create new file with the data\n return this.write(path, data);\n }\n\n const inode = this.readInode(existingIdx);\n if (inode.type === INODE_TYPE.DIRECTORY) return { status: CODE_TO_STATUS.EISDIR };\n\n // Avoid materializing the whole (existing + data) file in a single\n // Uint8Array — that blew up with \"Array buffer allocation failed\" on\n // large appends (e.g. appending a few MB to a multi-hundred-MB file).\n //\n // Strategy: allocate a new block run sized to the total, copy the\n // existing contents over in bounded chunks, then write the caller's\n // `data` at the end. Peak allocation stays at 4 MB regardless of\n // file size.\n const combinedSize = inode.size + data.byteLength;\n const neededBlocks = Math.ceil(combinedSize / this.blockSize);\n const newFirst = this.allocateBlocks(neededBlocks);\n const newBase = this.dataOffset + newFirst * this.blockSize;\n if (inode.size > 0) {\n const oldBase = this.dataOffset + inode.firstBlock * this.blockSize;\n const CHUNK = 4 * 1024 * 1024; // 4 MB\n const scratch = new Uint8Array(Math.min(CHUNK, inode.size));\n let copied = 0;\n while (copied < inode.size) {\n const n = Math.min(CHUNK, inode.size - copied);\n const slice = n < scratch.length ? scratch.subarray(0, n) : scratch;\n this.handle.read(slice, { at: oldBase + copied });\n this.handle.write(slice, { at: newBase + copied });\n copied += n;\n }\n }\n this.freeBlockRange(inode.firstBlock, inode.blockCount);\n this.handle.write(data, { at: newBase + inode.size });\n\n inode.firstBlock = newFirst;\n inode.blockCount = neededBlocks;\n inode.size = combinedSize;\n inode.mtime = Date.now();\n this.writeInode(existingIdx, inode);\n\n this.commitPending();\n return { status: 0 };\n }\n\n // ---- UNLINK ----\n unlink(path: string): { status: number } {\n path = this.normalizePath(path);\n const idx = this.pathIndex.get(path);\n if (idx === undefined) return { status: CODE_TO_STATUS.ENOENT };\n\n const inode = this.readInode(idx);\n if (inode.type === INODE_TYPE.DIRECTORY) return { status: CODE_TO_STATUS.EISDIR };\n\n // Decrement nlink; only free data when it reaches 0\n inode.nlink = Math.max(0, inode.nlink - 1);\n\n // Free data blocks\n this.freeBlockRange(inode.firstBlock, inode.blockCount);\n\n // Mark inode as free\n inode.type = INODE_TYPE.FREE;\n this.writeInode(idx, inode);\n\n // Remove from index\n this.pathIndex.delete(path);\n this.pathIndexGen++;\n // Reset free inode hint\n if (idx < this.freeInodeHint) this.freeInodeHint = idx;\n\n this.commitPending();\n return { status: 0 };\n }\n\n // ---- STAT ----\n stat(path: string): { status: number; data: Uint8Array | null } {\n path = this.normalizePath(path);\n const idx = this.resolvePathComponents(path, true);\n if (idx === undefined) {\n // Check for implicit directory (exists because files exist under it)\n if (this.isImplicitDirectory(path)) {\n return this.encodeImplicitDirStatResponse(path);\n }\n return { status: CODE_TO_STATUS.ENOENT, data: null };\n }\n\n return this.encodeStatResponse(idx);\n }\n\n // ---- LSTAT (no symlink follow for the FINAL component) ----\n lstat(path: string): { status: number; data: Uint8Array | null } {\n path = this.normalizePath(path);\n // Use resolvePathComponents with followLast=false — follows intermediate\n // symlinks but returns the symlink inode itself for the last component.\n // Direct pathIndex.get(path) fails for paths through symlinked directories\n // because children are stored under the symlink target path in pathIndex.\n let idx = this.resolvePathComponents(path, false);\n if (idx === undefined) {\n // Fallback: followLast=false can fail for paths through symlink chains\n // when pathIndex stores files under their resolved (real) path.\n // Try with followLast=true — if it resolves, use the result regardless\n // of whether the final component is a symlink or not. lstat on an\n // existing symlink should return the symlink's own stats, not ENOENT.\n idx = this.resolvePathComponents(path, true);\n if (idx === undefined) {\n // Check for implicit directory\n if (this.isImplicitDirectory(path)) {\n return this.encodeImplicitDirStatResponse(path);\n }\n return { status: CODE_TO_STATUS.ENOENT, data: null };\n }\n }\n\n return this.encodeStatResponse(idx);\n }\n\n private encodeStatResponse(idx: number): { status: number; data: Uint8Array } {\n const inode = this.readInode(idx);\n\n // Compute nlink for directories: 2 + number of child subdirectories\n // (including implicit subdirectories so nlink stays consistent with\n // what readdir reports).\n let nlink = inode.nlink;\n if (inode.type === INODE_TYPE.DIRECTORY) {\n const path = this.readPath(inode.pathOffset, inode.pathLength);\n const children = this.getDirectChildrenWithImplicit(path);\n let subdirCount = 0;\n for (const child of children) {\n if (child.type === 'implicit') {\n subdirCount++;\n } else {\n const childIdx = this.pathIndex.get(child.path);\n if (childIdx !== undefined) {\n const childInode = this.readInode(childIdx);\n if (childInode.type === INODE_TYPE.DIRECTORY) subdirCount++;\n }\n }\n }\n nlink = 2 + subdirCount;\n }\n\n // Encode stat into binary: type(1) + mode(4) + size(8) + mtime(8) + ctime(8) + atime(8) + uid(4) + gid(4) + ino(4) + nlink(4) = 53 bytes\n const buf = new Uint8Array(53);\n const view = new DataView(buf.buffer);\n view.setUint8(0, inode.type);\n view.setUint32(1, inode.mode, true);\n view.setFloat64(5, inode.size, true);\n view.setFloat64(13, inode.mtime, true);\n view.setFloat64(21, inode.ctime, true);\n view.setFloat64(29, inode.atime, true);\n view.setUint32(37, inode.uid, true);\n view.setUint32(41, inode.gid, true);\n view.setUint32(45, idx, true); // ino = inode index\n view.setUint32(49, nlink, true);\n\n return { status: 0, data: buf };\n }\n\n // ---- MKDIR ----\n mkdir(path: string, flags: number = 0): { status: number; data: Uint8Array | null } {\n path = this.normalizePath(path);\n const recursive = (flags & 1) !== 0;\n\n if (recursive) {\n return this.mkdirRecursive(path);\n }\n\n // Check if already exists (explicit or implicit)\n if (this.pathIndex.has(path) || this.isImplicitDirectory(path)) {\n return { status: CODE_TO_STATUS.EEXIST, data: null };\n }\n\n // Ensure parent exists\n const parentStatus = this.ensureParent(path);\n if (parentStatus !== 0) return { status: parentStatus, data: null };\n\n const mode = DEFAULT_DIR_MODE & ~(this.umask & 0o777);\n this.createInode(path, INODE_TYPE.DIRECTORY, mode, 0);\n\n this.commitPending();\n // Non-recursive mkdir returns undefined (null data) per Node.js spec\n return { status: 0, data: null };\n }\n\n private mkdirRecursive(path: string): { status: number; data: Uint8Array | null } {\n const parts = path.split('/').filter(Boolean);\n let current = '';\n let firstCreated: string | null = null;\n\n for (const part of parts) {\n current += '/' + part;\n\n if (this.pathIndex.has(current)) {\n const idx = this.pathIndex.get(current)!;\n const inode = this.readInode(idx);\n if (inode.type !== INODE_TYPE.DIRECTORY) {\n return { status: CODE_TO_STATUS.ENOTDIR, data: null };\n }\n continue;\n }\n\n const mode = DEFAULT_DIR_MODE & ~(this.umask & 0o777);\n this.createInode(current, INODE_TYPE.DIRECTORY, mode, 0);\n if (!firstCreated) firstCreated = current;\n }\n\n this.commitPending();\n const result = firstCreated ? encoder.encode(firstCreated) : undefined;\n return { status: 0, data: result ?? null };\n }\n\n // ---- RMDIR ----\n rmdir(path: string, flags: number = 0): { status: number } {\n path = this.normalizePath(path);\n const recursive = (flags & 1) !== 0;\n const idx = this.pathIndex.get(path);\n if (idx === undefined) {\n // Check for implicit directory — a dir that exists because files\n // exist under it but no explicit inode was created.\n if (this.isImplicitDirectory(path)) {\n const children = this.getDirectChildrenWithImplicit(path);\n if (children.length > 0) {\n if (!recursive) return { status: CODE_TO_STATUS.ENOTEMPTY };\n // Recursive: delete all real descendants; the implicit dir\n // disappears automatically when its children are gone.\n for (const desc of this.getAllDescendants(path)) {\n const descIdx = this.pathIndex.get(desc)!;\n const descInode = this.readInode(descIdx);\n this.freeBlockRange(descInode.firstBlock, descInode.blockCount);\n descInode.type = INODE_TYPE.FREE;\n this.writeInode(descIdx, descInode);\n this.pathIndex.delete(desc);\n }\n this.pathIndexGen++;\n this.commitPending();\n }\n // Empty implicit dir or just-emptied: no-op — it vanishes on its own.\n return { status: 0 };\n }\n return { status: CODE_TO_STATUS.ENOENT };\n }\n\n const inode = this.readInode(idx);\n if (inode.type !== INODE_TYPE.DIRECTORY) return { status: CODE_TO_STATUS.ENOTDIR };\n\n // Check for children\n const children = this.getDirectChildren(path);\n\n if (children.length > 0) {\n if (!recursive) return { status: CODE_TO_STATUS.ENOTEMPTY };\n\n // Recursive delete\n for (const child of this.getAllDescendants(path)) {\n const childIdx = this.pathIndex.get(child)!;\n const childInode = this.readInode(childIdx);\n this.freeBlockRange(childInode.firstBlock, childInode.blockCount);\n childInode.type = INODE_TYPE.FREE;\n this.writeInode(childIdx, childInode);\n this.pathIndex.delete(child);\n }\n }\n\n // Remove the directory itself\n inode.type = INODE_TYPE.FREE;\n this.writeInode(idx, inode);\n this.pathIndex.delete(path);\n this.pathIndexGen++;\n if (idx < this.freeInodeHint) this.freeInodeHint = idx;\n\n this.commitPending();\n return { status: 0 };\n }\n\n // ---- READDIR ----\n readdir(path: string, flags: number = 0): { status: number; data: Uint8Array | null } {\n path = this.normalizePath(path);\n const resolved = this.resolvePathFull(path, true);\n\n // Determine the effective directory path for child lookup\n let effectiveDirPath: string;\n\n if (resolved) {\n const inode = this.readInode(resolved.idx);\n if (inode.type !== INODE_TYPE.DIRECTORY) return { status: CODE_TO_STATUS.ENOTDIR, data: null };\n // Use the resolved path for child lookup — when path is a symlink,\n // the actual children are stored under the target path in pathIndex.\n effectiveDirPath = resolved.resolvedPath;\n } else if (this.isImplicitDirectory(path)) {\n effectiveDirPath = path;\n } else {\n return { status: CODE_TO_STATUS.ENOENT, data: null };\n }\n\n const withFileTypes = (flags & 1) !== 0;\n // Use getDirectChildrenWithImplicit to discover both real and implicit children\n const children = this.getDirectChildrenWithImplicit(effectiveDirPath);\n\n if (withFileTypes) {\n // Encode as: count(u32) + entries[name_len(u16) + name(bytes) + type(u8)]\n let totalSize = 4;\n const entries: { name: Uint8Array; type: number }[] = [];\n\n for (const child of children) {\n const name = child.path.substring(child.path.lastIndexOf('/') + 1);\n const nameBytes = encoder.encode(name);\n let type: number;\n if (child.type === 'implicit') {\n type = INODE_TYPE.DIRECTORY;\n } else {\n const childIdx = this.pathIndex.get(child.path)!;\n const childInode = this.readInode(childIdx);\n type = childInode.type;\n }\n entries.push({ name: nameBytes, type });\n totalSize += 2 + nameBytes.byteLength + 1; // nameLen + name + type\n }\n\n const buf = new Uint8Array(totalSize);\n const view = new DataView(buf.buffer);\n view.setUint32(0, entries.length, true);\n let offset = 4;\n\n for (const entry of entries) {\n view.setUint16(offset, entry.name.byteLength, true);\n offset += 2;\n buf.set(entry.name, offset);\n offset += entry.name.byteLength;\n buf[offset++] = entry.type;\n }\n\n return { status: 0, data: buf };\n }\n\n // Simple name list: count(u32) + entries[name_len(u16) + name(bytes)]\n let totalSize = 4;\n const nameEntries: Uint8Array[] = [];\n\n for (const child of children) {\n const name = child.path.substring(child.path.lastIndexOf('/') + 1);\n const nameBytes = encoder.encode(name);\n nameEntries.push(nameBytes);\n totalSize += 2 + nameBytes.byteLength;\n }\n\n const buf = new Uint8Array(totalSize);\n const view = new DataView(buf.buffer);\n view.setUint32(0, nameEntries.length, true);\n let offset = 4;\n\n for (const nameBytes of nameEntries) {\n view.setUint16(offset, nameBytes.byteLength, true);\n offset += 2;\n buf.set(nameBytes, offset);\n offset += nameBytes.byteLength;\n }\n\n return { status: 0, data: buf };\n }\n\n // ---- RENAME ----\n rename(oldPath: string, newPath: string): { status: number } {\n oldPath = this.normalizePath(oldPath);\n newPath = this.normalizePath(newPath);\n\n const idx = this.pathIndex.get(oldPath);\n if (idx === undefined) return { status: CODE_TO_STATUS.ENOENT };\n\n // Same path → no-op (matches Node.js semantics)\n if (oldPath === newPath) return { status: 0 };\n\n // Ensure parent of new path exists\n const parentStatus = this.ensureParent(newPath);\n if (parentStatus !== 0) return { status: parentStatus };\n\n // If target exists, remove it. For directory targets we MUST recursively\n // free every descendant inode and drop every descendant pathIndex entry —\n // otherwise the source's children get added on top, leaving a mix of\n // source children + leftover target children pointing at zombie inodes\n // (the target's old children still appear in pathIndex, while their\n // inodes are not freed so blocks are leaked too).\n //\n // Concrete consequence of the old behavior: Vite's deps optimization\n // commit (`.vite/deps_temp_<hash>` → `.vite/deps`) on the second run\n // returned success but produced a corrupt deps directory — subsequent\n // requests for `vue.js`, `@unhead/vue`, etc. resolved to stale chunks\n // from the previous round (or 404'd entirely).\n //\n // The target may also be an *implicit* directory (no inode of its own,\n // but children exist under it — the state produced by bulk OPFS import).\n // In that case there's no inode to free, but the descendants must still\n // be cleaned up for the same reason.\n const existingIdx = this.pathIndex.get(newPath);\n const targetIsImplicitDir =\n existingIdx === undefined && this.isImplicitDirectory(newPath);\n\n if (existingIdx !== undefined || targetIsImplicitDir) {\n let cleanDescendants = targetIsImplicitDir;\n\n if (existingIdx !== undefined) {\n const existingInode = this.readInode(existingIdx);\n cleanDescendants = existingInode.type === INODE_TYPE.DIRECTORY;\n this.freeBlockRange(existingInode.firstBlock, existingInode.blockCount);\n existingInode.type = INODE_TYPE.FREE;\n this.writeInode(existingIdx, existingInode);\n this.pathIndex.delete(newPath);\n if (existingIdx < this.freeInodeHint) this.freeInodeHint = existingIdx;\n }\n\n if (cleanDescendants) {\n // Free every descendant inode and remove its pathIndex entry.\n // Use getAllDescendants for the deepest-first ordering (matches\n // rmdir's recursive path) — though for a flat free pass order\n // doesn't affect correctness here.\n for (const desc of this.getAllDescendants(newPath)) {\n const descIdx = this.pathIndex.get(desc)!;\n const descInode = this.readInode(descIdx);\n this.freeBlockRange(descInode.firstBlock, descInode.blockCount);\n descInode.type = INODE_TYPE.FREE;\n this.writeInode(descIdx, descInode);\n this.pathIndex.delete(desc);\n if (descIdx < this.freeInodeHint) this.freeInodeHint = descIdx;\n }\n }\n }\n\n // Update inode with new path\n const inode = this.readInode(idx);\n const { offset: pathOff, length: pathLen } = this.appendPath(newPath);\n inode.pathOffset = pathOff;\n inode.pathLength = pathLen;\n inode.mtime = Date.now();\n this.writeInode(idx, inode);\n\n // Update index\n this.pathIndex.delete(oldPath);\n this.pathIndex.set(newPath, idx);\n this.pathIndexGen++;\n\n // If it's a directory, rename all descendants\n if (inode.type === INODE_TYPE.DIRECTORY) {\n const prefix = oldPath === '/' ? '/' : oldPath + '/';\n const toRename: [string, number][] = [];\n\n for (const [p, i] of this.pathIndex) {\n if (p.startsWith(prefix)) {\n toRename.push([p, i]);\n }\n }\n\n for (const [p, i] of toRename) {\n const suffix = p.substring(oldPath.length);\n const childNewPath = newPath + suffix;\n const childInode = this.readInode(i);\n const { offset: cpo, length: cpl } = this.appendPath(childNewPath);\n childInode.pathOffset = cpo;\n childInode.pathLength = cpl;\n this.writeInode(i, childInode);\n this.pathIndex.delete(p);\n this.pathIndex.set(childNewPath, i);\n }\n }\n\n this.commitPending();\n return { status: 0 };\n }\n\n // ---- EXISTS ----\n exists(path: string): { status: number; data: Uint8Array | null } {\n path = this.normalizePath(path);\n const idx = this.resolvePathComponents(path, true);\n const buf = new Uint8Array(1);\n buf[0] = (idx !== undefined || this.isImplicitDirectory(path)) ? 1 : 0;\n return { status: 0, data: buf };\n }\n\n // ---- TRUNCATE ----\n truncate(path: string, len: number = 0): { status: number } {\n path = this.normalizePath(path);\n const idx = this.resolvePathComponents(path, true);\n if (idx === undefined) return { status: CODE_TO_STATUS.ENOENT };\n\n const inode = this.readInode(idx);\n if (inode.type === INODE_TYPE.DIRECTORY) return { status: CODE_TO_STATUS.EISDIR };\n\n if (len === 0) {\n // Free all blocks\n this.freeBlockRange(inode.firstBlock, inode.blockCount);\n inode.firstBlock = 0;\n inode.blockCount = 0;\n inode.size = 0;\n } else if (len < inode.size) {\n // Shrink\n const neededBlocks = Math.ceil(len / this.blockSize);\n if (neededBlocks < inode.blockCount) {\n this.freeBlockRange(inode.firstBlock + neededBlocks, inode.blockCount - neededBlocks);\n }\n inode.blockCount = neededBlocks;\n inode.size = len;\n } else if (len > inode.size) {\n // Grow with POSIX zero-fill semantics. Old code staged the entire\n // new file as a single `new Uint8Array(len)` — OOMs for large\n // truncates and allocates way more than necessary. Instead, copy\n // old contents in bounded chunks and zero-fill the extension\n // directly on disk.\n const neededBlocks = Math.ceil(len / this.blockSize);\n if (neededBlocks > inode.blockCount) {\n // Allocate-then-copy-then-free so the old range is guaranteed\n // not to overlap the new one. See `fwrite` for the same pattern.\n const newFirst = this.allocateBlocks(neededBlocks);\n const newBase = this.dataOffset + newFirst * this.blockSize;\n if (inode.size > 0) {\n const oldBase = this.dataOffset + inode.firstBlock * this.blockSize;\n const CHUNK = 4 * 1024 * 1024; // 4 MB\n const scratch = new Uint8Array(Math.min(CHUNK, inode.size));\n let copied = 0;\n while (copied < inode.size) {\n const n = Math.min(CHUNK, inode.size - copied);\n const slice = n < scratch.length ? scratch.subarray(0, n) : scratch;\n this.handle.read(slice, { at: oldBase + copied });\n this.handle.write(slice, { at: newBase + copied });\n copied += n;\n }\n }\n this.freeBlockRange(inode.firstBlock, inode.blockCount);\n this.zeroFileRange(newBase + inode.size, len - inode.size);\n inode.firstBlock = newFirst;\n } else {\n // Same block count, just growing `size`. The tail of the last\n // existing block still contains whatever stale data was there\n // before — zero it so the extended region reads as zeros.\n this.zeroFileRange(\n this.dataOffset + inode.firstBlock * this.blockSize + inode.size,\n len - inode.size,\n );\n }\n inode.blockCount = neededBlocks;\n inode.size = len;\n }\n\n inode.mtime = Date.now();\n this.writeInode(idx, inode);\n\n this.commitPending();\n return { status: 0 };\n }\n\n // ---- COPY ----\n copy(srcPath: string, destPath: string, flags: number = 0): { status: number } {\n srcPath = this.normalizePath(srcPath);\n destPath = this.normalizePath(destPath);\n\n const srcIdx = this.resolvePathComponents(srcPath, true);\n if (srcIdx === undefined) return { status: CODE_TO_STATUS.ENOENT };\n\n const srcInode = this.readInode(srcIdx);\n if (srcInode.type === INODE_TYPE.DIRECTORY) return { status: CODE_TO_STATUS.EISDIR };\n\n // COPYFILE_EXCL check\n if ((flags & 1) && (this.pathIndex.has(destPath) || this.isImplicitDirectory(destPath))) {\n return { status: CODE_TO_STATUS.EEXIST };\n }\n\n // Self-copy — no-op.\n if (srcPath === destPath) return { status: 0 };\n\n const srcSize = srcInode.size;\n const srcFirstBlock = srcInode.firstBlock;\n\n // Stage 1: create the destination as an empty file. This goes through\n // the normal `write` path which handles parent-directory creation,\n // freeing any pre-existing blocks at `destPath`, and registering the\n // inode in `pathIndex`. Doing this first also means any side effects\n // (e.g. a `growPathTable` shift of the data region) happen BEFORE we\n // start allocating destination blocks, so the relative block indices\n // we capture below stay valid.\n const emptyStatus = this.write(destPath, new Uint8Array(0));\n if (emptyStatus.status !== 0) return emptyStatus;\n\n if (srcSize === 0) return { status: 0 };\n\n // Stage 2: allocate a destination block run sized to the source, then\n // copy the bytes directly between block ranges via the file handle in\n // bounded chunks. No full-file buffer is ever allocated — peak scratch\n // stays at 4 MB regardless of how big the source file is.\n const destIdx = this.resolvePathComponents(destPath, true);\n if (destIdx === undefined) return { status: CODE_TO_STATUS.EIO };\n const destInode = this.readInode(destIdx);\n\n const neededBlocks = Math.ceil(srcSize / this.blockSize);\n const newFirst = this.allocateBlocks(neededBlocks);\n const newBase = this.dataOffset + newFirst * this.blockSize;\n const srcBase = this.dataOffset + srcFirstBlock * this.blockSize;\n\n const CHUNK = 4 * 1024 * 1024; // 4 MB\n const scratch = new Uint8Array(Math.min(CHUNK, srcSize));\n let copied = 0;\n while (copied < srcSize) {\n const n = Math.min(CHUNK, srcSize - copied);\n const slice = n < scratch.length ? scratch.subarray(0, n) : scratch;\n this.handle.read(slice, { at: srcBase + copied });\n this.handle.write(slice, { at: newBase + copied });\n copied += n;\n }\n\n destInode.firstBlock = newFirst;\n destInode.blockCount = neededBlocks;\n destInode.size = srcSize;\n destInode.mtime = Date.now();\n this.writeInode(destIdx, destInode);\n this.commitPending();\n return { status: 0 };\n }\n\n // ---- ACCESS ----\n access(path: string, mode: number = 0): { status: number } {\n path = this.normalizePath(path);\n const idx = this.resolvePathComponents(path, true);\n if (idx === undefined) {\n // Check for implicit directory\n if (this.isImplicitDirectory(path)) return { status: 0 };\n return { status: CODE_TO_STATUS.ENOENT };\n }\n\n if (mode === 0) return { status: 0 }; // F_OK — just check existence\n\n if (!this.strictPermissions) return { status: 0 }; // Relaxed mode\n\n const inode = this.readInode(idx);\n // Check permission bits against process identity\n const filePerm = this.getEffectivePermission(inode);\n\n if ((mode & 4) && !(filePerm & 4)) return { status: CODE_TO_STATUS.EACCES }; // R_OK\n if ((mode & 2) && !(filePerm & 2)) return { status: CODE_TO_STATUS.EACCES }; // W_OK\n if ((mode & 1) && !(filePerm & 1)) return { status: CODE_TO_STATUS.EACCES }; // X_OK\n\n return { status: 0 };\n }\n\n private getEffectivePermission(inode: Inode): number {\n const modeBits = inode.mode & 0o777;\n if (this.processUid === inode.uid) return (modeBits >>> 6) & 7;\n if (this.processGid === inode.gid) return (modeBits >>> 3) & 7;\n return modeBits & 7;\n }\n\n // ---- REALPATH ----\n realpath(path: string): { status: number; data: Uint8Array | null } {\n path = this.normalizePath(path);\n const idx = this.resolvePathComponents(path, true);\n if (idx === undefined) {\n // Check for implicit directory\n if (this.isImplicitDirectory(path)) {\n return { status: 0, data: encoder.encode(path) };\n }\n return { status: CODE_TO_STATUS.ENOENT, data: null };\n }\n\n // Find the resolved path for this inode\n const inode = this.readInode(idx);\n const resolvedPath = this.readPath(inode.pathOffset, inode.pathLength);\n return { status: 0, data: encoder.encode(resolvedPath) };\n }\n\n // ---- CHMOD ----\n chmod(path: string, mode: number): { status: number } {\n path = this.normalizePath(path);\n const idx = this.resolvePathComponents(path, true);\n if (idx === undefined) return { status: CODE_TO_STATUS.ENOENT };\n\n const inode = this.readInode(idx);\n // Preserve file type bits, update permission bits\n inode.mode = (inode.mode & S_IFMT) | (mode & 0o7777);\n inode.ctime = Date.now();\n this.writeInode(idx, inode);\n\n return { status: 0 };\n }\n\n // ---- CHOWN ----\n chown(path: string, uid: number, gid: number): { status: number } {\n path = this.normalizePath(path);\n const idx = this.resolvePathComponents(path, true);\n if (idx === undefined) return { status: CODE_TO_STATUS.ENOENT };\n\n const inode = this.readInode(idx);\n inode.uid = uid;\n inode.gid = gid;\n inode.ctime = Date.now();\n this.writeInode(idx, inode);\n\n return { status: 0 };\n }\n\n // ---- UTIMES ----\n utimes(path: string, atime: number, mtime: number): { status: number } {\n path = this.normalizePath(path);\n const idx = this.resolvePathComponents(path, true);\n if (idx === undefined) return { status: CODE_TO_STATUS.ENOENT };\n\n const inode = this.readInode(idx);\n inode.atime = atime;\n inode.mtime = mtime;\n inode.ctime = Date.now();\n this.writeInode(idx, inode);\n\n return { status: 0 };\n }\n\n // ---- SYMLINK ----\n symlink(target: string, linkPath: string): { status: number } {\n linkPath = this.normalizePath(linkPath);\n if (this.pathIndex.has(linkPath) || this.isImplicitDirectory(linkPath)) {\n return { status: CODE_TO_STATUS.EEXIST };\n }\n\n const parentStatus = this.ensureParent(linkPath);\n if (parentStatus !== 0) return { status: parentStatus };\n\n const targetBytes = encoder.encode(target);\n this.createInode(linkPath, INODE_TYPE.SYMLINK, DEFAULT_SYMLINK_MODE, targetBytes.byteLength, targetBytes);\n\n this.commitPending();\n return { status: 0 };\n }\n\n // ---- READLINK ----\n readlink(path: string): { status: number; data: Uint8Array | null } {\n path = this.normalizePath(path);\n const idx = this.pathIndex.get(path);\n if (idx === undefined) return { status: CODE_TO_STATUS.ENOENT, data: null };\n\n const inode = this.readInode(idx);\n if (inode.type !== INODE_TYPE.SYMLINK) return { status: CODE_TO_STATUS.EINVAL, data: null };\n\n const target = this.readData(inode.firstBlock, inode.blockCount, inode.size);\n return { status: 0, data: target };\n }\n\n // ---- LINK (hard link — copies the file data, tracks nlink) ----\n link(existingPath: string, newPath: string): { status: number } {\n existingPath = this.normalizePath(existingPath);\n newPath = this.normalizePath(newPath);\n\n const srcIdx = this.resolvePathComponents(existingPath, true);\n if (srcIdx === undefined) return { status: CODE_TO_STATUS.ENOENT };\n\n const srcInode = this.readInode(srcIdx);\n if (srcInode.type === INODE_TYPE.DIRECTORY) return { status: CODE_TO_STATUS.EPERM };\n\n if (this.pathIndex.has(newPath) || this.isImplicitDirectory(newPath)) {\n return { status: CODE_TO_STATUS.EEXIST };\n }\n\n // Copy file data to new inode\n const result = this.copy(existingPath, newPath);\n if (result.status !== 0) return result;\n\n // Increment nlink on source\n srcInode.nlink++;\n this.writeInode(srcIdx, srcInode);\n\n // Set nlink on destination to match source\n const destIdx = this.pathIndex.get(newPath);\n if (destIdx !== undefined) {\n const destInode = this.readInode(destIdx);\n destInode.nlink = srcInode.nlink;\n this.writeInode(destIdx, destInode);\n }\n\n return { status: 0 };\n }\n\n // ---- OPEN (file descriptor) ----\n open(path: string, flags: number, tabId: string): { status: number; data: Uint8Array | null } {\n path = this.normalizePath(path);\n\n const hasCreate = (flags & 64) !== 0; // O_CREAT\n const hasTrunc = (flags & 512) !== 0; // O_TRUNC\n const hasExcl = (flags & 128) !== 0; // O_EXCL\n\n let idx = this.resolvePathComponents(path, true);\n\n if (idx === undefined) {\n if (!hasCreate) return { status: CODE_TO_STATUS.ENOENT, data: null };\n // Create file\n const mode = DEFAULT_FILE_MODE & ~(this.umask & 0o777);\n idx = this.createInode(path, INODE_TYPE.FILE, mode, 0);\n } else if (hasExcl && hasCreate) {\n return { status: CODE_TO_STATUS.EEXIST, data: null };\n }\n\n if (hasTrunc) {\n this.truncate(path, 0);\n }\n\n const fd = this.nextFd++;\n this.fdTable.set(fd, { tabId, inodeIdx: idx, position: 0, flags });\n\n const buf = new Uint8Array(4);\n new DataView(buf.buffer).setUint32(0, fd, true);\n return { status: 0, data: buf };\n }\n\n // ---- CLOSE ----\n close(fd: number): { status: number } {\n if (!this.fdTable.has(fd)) return { status: CODE_TO_STATUS.EBADF };\n this.fdTable.delete(fd);\n return { status: 0 };\n }\n\n // ---- FREAD ----\n fread(fd: number, length: number, position: number | null): { status: number; data: Uint8Array | null } {\n const entry = this.fdTable.get(fd);\n if (!entry) return { status: CODE_TO_STATUS.EBADF, data: null };\n\n const inode = this.readInode(entry.inodeIdx);\n const pos = position ?? entry.position;\n const readLen = Math.min(length, inode.size - pos);\n\n if (readLen <= 0) return { status: 0, data: new Uint8Array(0) };\n\n // Read from specific offset within the file's data blocks\n const dataOffset = this.dataOffset + inode.firstBlock * this.blockSize + pos;\n const buf = new Uint8Array(readLen);\n this.handle.read(buf, { at: dataOffset });\n\n // Update position\n if (position === null) {\n entry.position += readLen;\n }\n\n return { status: 0, data: buf };\n }\n\n // ---- FWRITE ----\n fwrite(fd: number, data: Uint8Array, position: number | null): { status: number; data: Uint8Array | null } {\n const entry = this.fdTable.get(fd);\n if (!entry) return { status: CODE_TO_STATUS.EBADF, data: null };\n\n const inode = this.readInode(entry.inodeIdx);\n const isAppend = (entry.flags & 1024) !== 0; // O_APPEND\n const pos = isAppend ? inode.size : (position ?? entry.position);\n const endPos = pos + data.byteLength;\n\n // Check if we need to grow\n if (endPos > inode.size) {\n const neededBlocks = Math.ceil(endPos / this.blockSize);\n if (neededBlocks > inode.blockCount) {\n // Grow by relocating to a larger block run. We used to stage the\n // entire new file contents in a single `new Uint8Array(endPos)`\n // and then call `writeData` once — that blew up with\n // \"Array buffer allocation failed\" on multi-hundred-MB writes\n // because Chrome refuses contiguous allocations near ~2 GB even\n // with plenty of OS RAM. Instead, allocate new blocks, copy the\n // old contents forward in chunks via the underlying file handle\n // (which is O(N) bytes but with a bounded scratch buffer), then\n // free the old blocks and write just the caller's `data` at its\n // offset inside the new region.\n const newFirst = this.allocateBlocks(neededBlocks);\n const newBase = this.dataOffset + newFirst * this.blockSize;\n const oldBase = this.dataOffset + inode.firstBlock * this.blockSize;\n // Copy oldData from old block run to new block run in chunks.\n if (inode.size > 0) {\n const CHUNK = 4 * 1024 * 1024; // 4 MB\n const scratch = new Uint8Array(Math.min(CHUNK, inode.size));\n let copied = 0;\n while (copied < inode.size) {\n const n = Math.min(CHUNK, inode.size - copied);\n const slice = n < scratch.length ? scratch.subarray(0, n) : scratch;\n this.handle.read(slice, { at: oldBase + copied });\n this.handle.write(slice, { at: newBase + copied });\n copied += n;\n }\n }\n this.freeBlockRange(inode.firstBlock, inode.blockCount);\n // POSIX \"hole\" — if the caller is writing past the current EOF\n // with a gap in between, those bytes must read back as zeros\n // rather than whatever stale data lives in the freshly allocated\n // blocks. `allocateBlocks` only flips bitmap bits, it never\n // zeroes the underlying storage.\n if (pos > inode.size) {\n this.zeroFileRange(newBase + inode.size, pos - inode.size);\n }\n // Write the caller's new data at its offset inside the new region.\n this.handle.write(data, { at: newBase + pos });\n inode.firstBlock = newFirst;\n inode.blockCount = neededBlocks;\n } else {\n // Fits within existing blocks. Same hole semantics as above —\n // stale bytes in the tail of the last allocated block (past the\n // old file size) must be zeroed before the caller's write lands.\n if (pos > inode.size) {\n this.zeroFileRange(\n this.dataOffset + inode.firstBlock * this.blockSize + inode.size,\n pos - inode.size,\n );\n }\n const dataOffset = this.dataOffset + inode.firstBlock * this.blockSize + pos;\n this.handle.write(data, { at: dataOffset });\n }\n inode.size = endPos;\n } else {\n // Write within existing bounds\n const dataOffset = this.dataOffset + inode.firstBlock * this.blockSize + pos;\n this.handle.write(data, { at: dataOffset });\n }\n\n inode.mtime = Date.now();\n this.writeInode(entry.inodeIdx, inode);\n\n // Update position\n if (position === null) {\n entry.position = endPos;\n }\n\n this.commitPending();\n const buf = new Uint8Array(4);\n new DataView(buf.buffer).setUint32(0, data.byteLength, true);\n return { status: 0, data: buf };\n }\n\n // ---- FSTAT ----\n fstat(fd: number): { status: number; data: Uint8Array | null } {\n const entry = this.fdTable.get(fd);\n if (!entry) return { status: CODE_TO_STATUS.EBADF, data: null };\n if (entry.implicitPath) return this.encodeImplicitDirStatResponse(entry.implicitPath);\n return this.encodeStatResponse(entry.inodeIdx);\n }\n\n // ---- FTRUNCATE ----\n ftruncate(fd: number, len: number = 0): { status: number } {\n const entry = this.fdTable.get(fd);\n if (!entry) return { status: CODE_TO_STATUS.EBADF };\n\n const inode = this.readInode(entry.inodeIdx);\n const path = this.readPath(inode.pathOffset, inode.pathLength);\n return this.truncate(path, len);\n }\n\n // ---- FSYNC ----\n fsync(): { status: number } {\n this.commitPending();\n this.handle.flush();\n return { status: 0 };\n }\n\n // ---- FCHMOD ----\n // fd-based chmod: look up the inode directly from the fd table and mutate\n // its mode bits. Native Node does the same thing at the libuv layer.\n fchmod(fd: number, mode: number): { status: number } {\n const entry = this.fdTable.get(fd);\n if (!entry) return { status: CODE_TO_STATUS.EBADF };\n if (entry.implicitPath) return { status: 0 }; // no-op for implicit dirs\n const inode = this.readInode(entry.inodeIdx);\n inode.mode = (inode.mode & S_IFMT) | (mode & 0o7777);\n inode.ctime = Date.now();\n this.writeInode(entry.inodeIdx, inode);\n return { status: 0 };\n }\n\n // ---- FCHOWN ----\n fchown(fd: number, uid: number, gid: number): { status: number } {\n const entry = this.fdTable.get(fd);\n if (!entry) return { status: CODE_TO_STATUS.EBADF };\n if (entry.implicitPath) return { status: 0 }; // no-op for implicit dirs\n const inode = this.readInode(entry.inodeIdx);\n inode.uid = uid;\n inode.gid = gid;\n inode.ctime = Date.now();\n this.writeInode(entry.inodeIdx, inode);\n return { status: 0 };\n }\n\n // ---- FUTIMES ----\n futimes(fd: number, atime: number, mtime: number): { status: number } {\n const entry = this.fdTable.get(fd);\n if (!entry) return { status: CODE_TO_STATUS.EBADF };\n if (entry.implicitPath) return { status: 0 }; // no-op for implicit dirs\n const inode = this.readInode(entry.inodeIdx);\n inode.atime = atime;\n inode.mtime = mtime;\n inode.ctime = Date.now();\n this.writeInode(entry.inodeIdx, inode);\n return { status: 0 };\n }\n\n // ---- OPENDIR ----\n opendir(path: string, tabId: string): { status: number; data: Uint8Array | null } {\n path = this.normalizePath(path);\n const idx = this.resolvePathComponents(path, true);\n if (idx === undefined) {\n // Check for implicit directory\n if (this.isImplicitDirectory(path)) {\n // Create fd with synthetic inode index -1 and the path stored so\n // fd-based operations (fstat, fchmod, etc.) can handle it.\n const fd = this.nextFd++;\n this.fdTable.set(fd, { tabId, inodeIdx: -1, position: 0, flags: 0, implicitPath: path });\n const buf = new Uint8Array(4);\n new DataView(buf.buffer).setUint32(0, fd, true);\n return { status: 0, data: buf };\n }\n return { status: CODE_TO_STATUS.ENOENT, data: null };\n }\n\n const inode = this.readInode(idx);\n if (inode.type !== INODE_TYPE.DIRECTORY) return { status: CODE_TO_STATUS.ENOTDIR, data: null };\n\n // Use fd table for dir handles too\n const fd = this.nextFd++;\n this.fdTable.set(fd, { tabId, inodeIdx: idx, position: 0, flags: 0 });\n\n const buf = new Uint8Array(4);\n new DataView(buf.buffer).setUint32(0, fd, true);\n return { status: 0, data: buf };\n }\n\n // ---- MKDTEMP ----\n mkdtemp(prefix: string): { status: number; data: Uint8Array | null } {\n const suffix = Math.random().toString(36).substring(2, 8);\n const path = this.normalizePath(prefix + suffix);\n\n // Ensure parent directories exist\n const parentStatus = this.ensureParent(path);\n if (parentStatus !== 0) {\n // Auto-create parent directories for mkdtemp\n const parentPath = path.substring(0, path.lastIndexOf('/'));\n if (parentPath) {\n this.mkdirRecursive(parentPath);\n }\n }\n\n const mode = DEFAULT_DIR_MODE & ~(this.umask & 0o777);\n this.createInode(path, INODE_TYPE.DIRECTORY, mode, 0);\n\n this.commitPending();\n return { status: 0, data: encoder.encode(path) };\n }\n\n // ========== Helpers ==========\n\n private getDirectChildren(dirPath: string): string[] {\n const prefix = dirPath === '/' ? '/' : dirPath + '/';\n const children: string[] = [];\n\n for (const path of this.pathIndex.keys()) {\n if (path === dirPath) continue;\n if (!path.startsWith(prefix)) continue;\n // Direct child: no more slashes after prefix\n const rest = path.substring(prefix.length);\n if (!rest.includes('/')) {\n children.push(path);\n }\n }\n\n return children.sort();\n }\n\n /**\n * Rebuild the set of all implicit directory paths.\n * An implicit directory is any ancestor path of a file/symlink in pathIndex\n * that doesn't itself have an explicit inode entry.\n * Only rebuilt when pathIndex has changed (tracked via generation counter).\n */\n private rebuildImplicitDirs(): void {\n if (this.implicitDirsGen === this.pathIndexGen) return;\n\n const now = Date.now();\n const prev = this.implicitDirs;\n this.implicitDirs = new Map<string, number>();\n for (const filePath of this.pathIndex.keys()) {\n // Walk up from each path, adding all ancestor dirs that aren't explicit\n let pos = filePath.length;\n while (true) {\n pos = filePath.lastIndexOf('/', pos - 1);\n if (pos <= 0) break; // reached root\n const ancestor = filePath.substring(0, pos);\n if (this.implicitDirs.has(ancestor)) break; // already tracked all ancestors from here up\n if (!this.pathIndex.has(ancestor)) {\n // Preserve timestamp if this implicit dir was already known,\n // otherwise stamp it with \"now\" so stat() stays stable.\n this.implicitDirs.set(ancestor, prev.get(ancestor) ?? now);\n }\n }\n }\n\n this.implicitDirsGen = this.pathIndexGen;\n }\n\n /**\n * Check if a path is an implicit directory (exists because files exist under it,\n * but no explicit directory inode was created for it).\n */\n private isImplicitDirectory(path: string): boolean {\n if (path === '/') return false; // root always has an explicit inode\n this.rebuildImplicitDirs();\n return this.implicitDirs.has(path);\n }\n\n /**\n * Get direct children of a directory path, including implicit subdirectories.\n * Returns unique child full paths. Each entry is tagged with whether it's a\n * real inode or an implicit directory.\n */\n private getDirectChildrenWithImplicit(dirPath: string): { path: string; type: 'real' | 'implicit' }[] {\n const prefix = dirPath === '/' ? '/' : dirPath + '/';\n const childNames = new Map<string, 'real' | 'implicit'>();\n\n for (const path of this.pathIndex.keys()) {\n if (path === dirPath) continue;\n if (!path.startsWith(prefix)) continue;\n const rest = path.substring(prefix.length);\n const slashPos = rest.indexOf('/');\n if (slashPos === -1) {\n // Direct child file/dir — it's a real inode\n childNames.set(rest, 'real');\n } else {\n // Deeper descendant — the first segment is an implicit subdirectory\n const childName = rest.substring(0, slashPos);\n if (!childNames.has(childName)) {\n // Only mark as implicit if there's no real inode for it\n const childFullPath = prefix + childName;\n childNames.set(childName, this.pathIndex.has(childFullPath) ? 'real' : 'implicit');\n }\n }\n }\n\n const result: { path: string; type: 'real' | 'implicit' }[] = [];\n for (const [name, type] of childNames) {\n result.push({ path: prefix + name, type });\n }\n result.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);\n return result;\n }\n\n /**\n * Encode a synthetic stat response for an implicit directory.\n * Returns directory stats with default mode, zero size, current timestamps.\n */\n private encodeImplicitDirStatResponse(path: string): { status: number; data: Uint8Array } {\n // Use the stable timestamp assigned when this implicit dir was first\n // discovered, so repeated stat() calls return the same mtime/ctime/atime.\n this.rebuildImplicitDirs();\n const ts = this.implicitDirs.get(path) ?? Date.now();\n const mode = DEFAULT_DIR_MODE & ~(this.umask & 0o777);\n\n // Count implicit subdirectories for nlink\n const children = this.getDirectChildrenWithImplicit(path);\n let subdirCount = 0;\n for (const child of children) {\n if (child.type === 'implicit') {\n subdirCount++;\n } else {\n const childIdx = this.pathIndex.get(child.path);\n if (childIdx !== undefined) {\n const childInode = this.readInode(childIdx);\n if (childInode.type === INODE_TYPE.DIRECTORY) subdirCount++;\n }\n }\n }\n const nlink = 2 + subdirCount;\n\n // Encode stat: type(1) + mode(4) + size(8) + mtime(8) + ctime(8) + atime(8) + uid(4) + gid(4) + ino(4) + nlink(4) = 53 bytes\n const buf = new Uint8Array(53);\n const view = new DataView(buf.buffer);\n view.setUint8(0, INODE_TYPE.DIRECTORY);\n view.setUint32(1, mode, true);\n view.setFloat64(5, 0, true); // size = 0\n view.setFloat64(13, ts, true); // mtime\n view.setFloat64(21, ts, true); // ctime\n view.setFloat64(29, ts, true); // atime\n view.setUint32(37, this.processUid, true);\n view.setUint32(41, this.processGid, true);\n view.setUint32(45, 0, true); // ino = 0 (synthetic)\n view.setUint32(49, nlink, true);\n\n return { status: 0, data: buf };\n }\n\n private getAllDescendants(dirPath: string): string[] {\n const prefix = dirPath === '/' ? '/' : dirPath + '/';\n const descendants: string[] = [];\n\n for (const path of this.pathIndex.keys()) {\n if (path.startsWith(prefix)) descendants.push(path);\n }\n\n // Sort by depth (deepest first) for safe deletion\n return descendants.sort((a, b) => {\n const da = a.split('/').length;\n const db = b.split('/').length;\n return db - da;\n });\n }\n\n private ensureParent(path: string): number {\n const lastSlash = path.lastIndexOf('/');\n if (lastSlash <= 0) return 0; // Parent is root, always exists\n\n const parentPath = path.substring(0, lastSlash);\n const parentIdx = this.pathIndex.get(parentPath);\n if (parentIdx === undefined) {\n // Check for implicit directory\n if (this.isImplicitDirectory(parentPath)) return 0;\n return CODE_TO_STATUS.ENOENT;\n }\n\n const parentInode = this.readInode(parentIdx);\n if (parentInode.type !== INODE_TYPE.DIRECTORY) return CODE_TO_STATUS.ENOTDIR;\n\n return 0;\n }\n\n /** Clean up all fds owned by a tab */\n cleanupTab(tabId: string): void {\n for (const [fd, entry] of this.fdTable) {\n if (entry.tabId === tabId) {\n this.fdTable.delete(fd);\n }\n }\n }\n\n /** Get all file paths and their data for OPFS sync */\n getAllFiles(): { path: string; idx: number }[] {\n const files: { path: string; idx: number }[] = [];\n for (const [path, idx] of this.pathIndex) {\n files.push({ path, idx });\n }\n return files;\n }\n\n /** Get file path for a file descriptor (used by OPFS sync for FD-based ops) */\n getPathForFd(fd: number): string | null {\n const entry = this.fdTable.get(fd);\n if (!entry) return null;\n const inode = this.readInode(entry.inodeIdx);\n return this.readPath(inode.pathOffset, inode.pathLength);\n }\n\n /** Get file data by inode index */\n getInodeData(idx: number): { type: number; data: Uint8Array; mtime: number } {\n const inode = this.readInode(idx);\n const data = inode.size > 0\n ? this.readData(inode.firstBlock, inode.blockCount, inode.size)\n : new Uint8Array(0);\n return { type: inode.type, data, mtime: inode.mtime };\n }\n\n /** Export all files/dirs/symlinks from the VFS */\n exportAll(): Array<{ path: string; type: number; data: Uint8Array | null; mode: number; mtime: number }> {\n const result: Array<{ path: string; type: number; data: Uint8Array | null; mode: number; mtime: number }> = [];\n for (const [path, idx] of this.pathIndex) {\n const inode = this.readInode(idx);\n let data: Uint8Array | null = null;\n if (inode.type === INODE_TYPE.FILE || inode.type === INODE_TYPE.SYMLINK) {\n data = inode.size > 0\n ? this.readData(inode.firstBlock, inode.blockCount, inode.size)\n : new Uint8Array(0);\n }\n result.push({ path, type: inode.type, data, mode: inode.mode, mtime: inode.mtime });\n }\n // Sort directories first so parents are created before children\n result.sort((a, b) => {\n if (a.type === INODE_TYPE.DIRECTORY && b.type !== INODE_TYPE.DIRECTORY) return -1;\n if (a.type !== INODE_TYPE.DIRECTORY && b.type === INODE_TYPE.DIRECTORY) return 1;\n return a.path.localeCompare(b.path);\n });\n return result;\n }\n\n flush(): void {\n this.handle.flush();\n }\n}\n","/**\n * Repair Worker — handles VFS repair and load operations.\n *\n * Spawned by helpers.ts when the caller doesn't have sync handle access\n * (e.g. main thread). All VFS writes go through createSyncAccessHandle\n * for direct disk I/O — no MemoryHandle, no RAM bloat.\n *\n * Operations:\n * - 'repair': Scan corrupt .vfs.bin, rebuild valid entries into fresh VFS\n * - 'load': Read OPFS files, create fresh VFS from them\n *\n * Safety guarantees:\n * - Original .vfs.bin is never deleted until the replacement is verified\n * - Temp file (.vfs.bin.tmp) is verified via re-mount before swap\n * - Orphaned .vfs.bin.tmp is cleaned up on entry\n * - Repair fails fast if critical operations exceed error threshold\n */\n\nimport { VFSEngine } from '../vfs/engine.js';\nimport {\n VFS_MAGIC, VFS_VERSION, SUPERBLOCK, INODE, INODE_SIZE, INODE_TYPE,\n DEFAULT_INODE_COUNT, DEFAULT_BLOCK_SIZE, INITIAL_DATA_BLOCKS,\n INITIAL_PATH_TABLE_SIZE, calculateLayout,\n} from '../vfs/layout.js';\n\nself.onmessage = async (event: MessageEvent) => {\n try {\n const msg = event.data;\n if (msg.type === 'repair') {\n (self as any).postMessage(await handleRepair(msg.root));\n } else if (msg.type === 'load') {\n (self as any).postMessage(await handleLoad(msg.root));\n } else {\n throw new Error(`Unknown message type: ${msg.type}`);\n }\n } catch (err: any) {\n (self as any).postMessage({ error: err.message || String(err) });\n }\n};\n\n// ========== OPFS navigation (duplicated for bundle isolation) ==========\n\nasync function navigateToRoot(root: string): Promise<FileSystemDirectoryHandle> {\n let dir = await navigator.storage.getDirectory();\n if (root && root !== '/') {\n for (const seg of root.split('/').filter(Boolean)) {\n dir = await dir.getDirectoryHandle(seg, { create: true });\n }\n }\n return dir;\n}\n\ninterface OPFSEntry {\n path: string;\n type: 'file' | 'directory';\n data?: ArrayBuffer;\n}\n\nasync function readOPFSRecursive(\n dir: FileSystemDirectoryHandle,\n prefix: string,\n skip: Set<string>,\n): Promise<OPFSEntry[]> {\n const result: OPFSEntry[] = [];\n for await (const [name, handle] of (dir as any).entries()) {\n if (prefix === '' && skip.has(name)) continue;\n const fullPath = prefix ? `${prefix}/${name}` : `/${name}`;\n if (handle.kind === 'directory') {\n result.push({ path: fullPath, type: 'directory' });\n const children = await readOPFSRecursive(handle as FileSystemDirectoryHandle, fullPath, skip);\n result.push(...children);\n } else {\n const file = await (handle as FileSystemFileHandle).getFile();\n const data = await file.arrayBuffer();\n result.push({ path: fullPath, type: 'file', data });\n }\n }\n return result;\n}\n\n// ========== Cleanup orphaned temp files ==========\n\nasync function cleanupTmpFile(rootDir: FileSystemDirectoryHandle): Promise<void> {\n try { await rootDir.removeEntry('.vfs.bin.tmp'); } catch {}\n}\n\n// ========== Verify VFS via re-mount ==========\n\n/**\n * Open the file, mount it as a VFS, verify superblock + inode table,\n * then close. Throws if the VFS is corrupt.\n */\nasync function verifyVFS(fileHandle: FileSystemFileHandle): Promise<void> {\n const handle = await (fileHandle as any).createSyncAccessHandle();\n try {\n const engine = new VFSEngine();\n engine.init(handle); // calls mount() which validates superblock + rebuilds index\n } finally {\n handle.close();\n }\n}\n\n// ========== Safe file swap: copy-then-delete ==========\n\n/**\n * Safely replace .vfs.bin with .vfs.bin.tmp:\n * 1. Verify the temp file is a valid VFS (re-mount test)\n * 2. Copy temp → .vfs.bin (overwrite via truncate + chunked write)\n * 3. Only then delete .vfs.bin.tmp\n *\n * If the copy is interrupted mid-write, the original .vfs.bin.tmp\n * still exists intact for retry.\n */\nasync function swapTmpToVFS(\n rootDir: FileSystemDirectoryHandle,\n tmpFileHandle: FileSystemFileHandle,\n): Promise<void> {\n // Step 1: Verify temp file is valid before touching original\n await verifyVFS(tmpFileHandle);\n\n // Step 2: Copy tmp → .vfs.bin (overwrite)\n const vfsFileHandle = await rootDir.getFileHandle('.vfs.bin', { create: true });\n\n const srcHandle = await (tmpFileHandle as any).createSyncAccessHandle();\n const dstHandle = await (vfsFileHandle as any).createSyncAccessHandle();\n try {\n const size: number = srcHandle.getSize();\n dstHandle.truncate(size);\n const CHUNK = 1024 * 1024; // 1MB\n const buf = new Uint8Array(CHUNK);\n for (let off = 0; off < size; off += CHUNK) {\n const n: number = srcHandle.read(buf, { at: off });\n dstHandle.write(n < CHUNK ? buf.subarray(0, n) : buf, { at: off });\n }\n dstHandle.flush();\n } finally {\n dstHandle.close();\n srcHandle.close();\n }\n\n // Step 3: Only delete tmp after successful copy\n try { await rootDir.removeEntry('.vfs.bin.tmp'); } catch {}\n}\n\n// ========== Repair handler ==========\n\nasync function handleRepair(root: string) {\n const rootDir = await navigateToRoot(root);\n\n // Clean up any orphaned temp file from a previous failed repair\n await cleanupTmpFile(rootDir);\n\n // Read old .vfs.bin\n const vfsFileHandle = await rootDir.getFileHandle('.vfs.bin');\n const file = await vfsFileHandle.getFile();\n const raw = new Uint8Array(await file.arrayBuffer());\n const fileSize = raw.byteLength;\n\n if (fileSize < SUPERBLOCK.SIZE) {\n throw new Error(`VFS file too small to repair (${fileSize} bytes)`);\n }\n\n // Parse superblock\n const view = new DataView(raw.buffer);\n let inodeCount: number;\n let blockSize: number;\n let totalBlocks: number;\n let inodeTableOffset: number;\n let pathTableOffset: number;\n let dataOffset: number;\n let bitmapOffset: number;\n let pathTableSize: number;\n\n const magic = view.getUint32(SUPERBLOCK.MAGIC, true);\n const version = view.getUint32(SUPERBLOCK.VERSION, true);\n const superblockValid = magic === VFS_MAGIC && version === VFS_VERSION;\n\n if (superblockValid) {\n inodeCount = view.getUint32(SUPERBLOCK.INODE_COUNT, true);\n blockSize = view.getUint32(SUPERBLOCK.BLOCK_SIZE, true);\n totalBlocks = view.getUint32(SUPERBLOCK.TOTAL_BLOCKS, true);\n inodeTableOffset = view.getFloat64(SUPERBLOCK.INODE_OFFSET, true);\n pathTableOffset = view.getFloat64(SUPERBLOCK.PATH_OFFSET, true);\n dataOffset = view.getFloat64(SUPERBLOCK.DATA_OFFSET, true);\n bitmapOffset = view.getFloat64(SUPERBLOCK.BITMAP_OFFSET, true);\n // Use the full allocated path table size (not PATH_USED) for repair validation.\n // PATH_USED may be stale if the superblock wasn't flushed after a write —\n // paths were written to OPFS but the superblock counter wasn't updated.\n pathTableSize = bitmapOffset - pathTableOffset;\n\n if (blockSize === 0 || (blockSize & (blockSize - 1)) !== 0 || inodeCount === 0 ||\n inodeTableOffset >= fileSize || pathTableOffset >= fileSize || dataOffset >= fileSize ||\n pathTableSize <= 0) {\n const layout = calculateLayout(DEFAULT_INODE_COUNT, DEFAULT_BLOCK_SIZE, INITIAL_DATA_BLOCKS);\n inodeCount = DEFAULT_INODE_COUNT;\n blockSize = DEFAULT_BLOCK_SIZE;\n totalBlocks = INITIAL_DATA_BLOCKS;\n inodeTableOffset = layout.inodeTableOffset;\n pathTableOffset = layout.pathTableOffset;\n dataOffset = layout.dataOffset;\n bitmapOffset = layout.bitmapOffset;\n pathTableSize = bitmapOffset - pathTableOffset;\n }\n } else {\n const layout = calculateLayout(DEFAULT_INODE_COUNT, DEFAULT_BLOCK_SIZE, INITIAL_DATA_BLOCKS);\n inodeCount = DEFAULT_INODE_COUNT;\n blockSize = DEFAULT_BLOCK_SIZE;\n totalBlocks = INITIAL_DATA_BLOCKS;\n inodeTableOffset = layout.inodeTableOffset;\n pathTableOffset = layout.pathTableOffset;\n dataOffset = layout.dataOffset;\n bitmapOffset = layout.bitmapOffset;\n pathTableSize = bitmapOffset - pathTableOffset;\n }\n\n // Scan inodes for recoverable entries\n const decoder = new TextDecoder('utf-8', { fatal: true });\n const recovered: Array<{\n path: string;\n type: number;\n dataOffset: number;\n dataSize: number;\n /** true when inode was found but data blocks were out of bounds */\n contentLost: boolean;\n }> = [];\n let lost = 0;\n\n const maxInodes = Math.min(inodeCount, Math.floor((fileSize - inodeTableOffset) / INODE_SIZE));\n\n for (let i = 0; i < maxInodes; i++) {\n const off = inodeTableOffset + i * INODE_SIZE;\n if (off + INODE_SIZE > fileSize) break;\n\n const type = raw[off + INODE.TYPE];\n if (type < INODE_TYPE.FILE || type > INODE_TYPE.SYMLINK) continue;\n\n const inodeView = new DataView(raw.buffer, off, INODE_SIZE);\n const pathOff = inodeView.getUint32(INODE.PATH_OFFSET, true);\n const pathLength = inodeView.getUint16(INODE.PATH_LENGTH, true);\n const size = inodeView.getFloat64(INODE.SIZE, true);\n const firstBlock = inodeView.getUint32(INODE.FIRST_BLOCK, true);\n\n // Validate path bounds against the allocated path table region and file size.\n // Use pathTableSize (not PATH_USED from superblock) because PATH_USED may be\n // stale if the superblock wasn't flushed — the path bytes are still on disk.\n const absPathOffset = pathTableOffset + pathOff;\n if (pathLength === 0 || pathLength > 4096 ||\n absPathOffset + pathLength > fileSize ||\n pathOff + pathLength > pathTableSize) {\n lost++;\n continue;\n }\n\n // Decode path with strict UTF-8 (fatal: true rejects invalid sequences)\n let entryPath: string;\n try {\n entryPath = decoder.decode(raw.subarray(absPathOffset, absPathOffset + pathLength));\n } catch {\n lost++;\n continue;\n }\n\n if (!entryPath.startsWith('/') || entryPath.includes('\\0')) {\n lost++;\n continue;\n }\n\n if (type === INODE_TYPE.DIRECTORY) {\n recovered.push({ path: entryPath, type, dataOffset: 0, dataSize: 0, contentLost: false });\n continue;\n }\n\n if (size < 0 || size > fileSize || !isFinite(size)) {\n lost++;\n continue;\n }\n\n const blockCount = inodeView.getUint32(INODE.BLOCK_COUNT, true);\n const dataStart = dataOffset + firstBlock * blockSize;\n if (dataStart + size > fileSize || firstBlock >= totalBlocks ||\n (blockCount > 0 && firstBlock + blockCount > totalBlocks)) {\n // Inode metadata is valid but data blocks are out of bounds — content is lost\n recovered.push({ path: entryPath, type, dataOffset: 0, dataSize: 0, contentLost: true });\n lost++;\n continue;\n }\n\n recovered.push({ path: entryPath, type, dataOffset: dataStart, dataSize: size, contentLost: false });\n }\n\n // Build repaired VFS in temp file — original .vfs.bin untouched until verified\n const tmpFileHandle = await rootDir.getFileHandle('.vfs.bin.tmp', { create: true });\n const tmpHandle = await (tmpFileHandle as any).createSyncAccessHandle();\n\n let repairOk = false;\n let criticalErrors = 0;\n const MAX_CRITICAL_ERRORS = 5;\n\n try {\n const engine = new VFSEngine();\n engine.init(tmpHandle);\n\n const dirs = recovered\n .filter(e => e.type === INODE_TYPE.DIRECTORY && e.path !== '/')\n .sort((a, b) => a.path.localeCompare(b.path));\n const files = recovered.filter(e => e.type === INODE_TYPE.FILE);\n const symlinks = recovered.filter(e => e.type === INODE_TYPE.SYMLINK);\n\n // Create directories — failure here is critical (blocks child files)\n for (const dir of dirs) {\n if (engine.mkdir(dir.path, 0o040755).status !== 0) {\n criticalErrors++;\n lost++;\n if (criticalErrors >= MAX_CRITICAL_ERRORS) {\n throw new Error(`Repair aborted: too many critical errors (${criticalErrors} mkdir failures)`);\n }\n }\n }\n\n // Write files\n for (const f of files) {\n const data = f.dataSize > 0\n ? raw.subarray(f.dataOffset, f.dataOffset + f.dataSize)\n : new Uint8Array(0);\n if (engine.write(f.path, data).status !== 0) {\n lost++;\n // File write failures are less critical than mkdir — parent may be missing\n }\n }\n\n // Write symlinks — validate target before creating\n for (const sym of symlinks) {\n if (sym.dataSize === 0 && sym.contentLost) {\n // Symlink target was lost — skip, don't create a broken symlink\n lost++;\n continue;\n }\n const data = sym.dataSize > 0\n ? raw.subarray(sym.dataOffset, sym.dataOffset + sym.dataSize)\n : new Uint8Array(0);\n let target: string;\n try {\n target = decoder.decode(data);\n } catch {\n // Invalid UTF-8 in symlink target — skip\n lost++;\n continue;\n }\n if (target.length === 0 || target.includes('\\0')) {\n lost++;\n continue;\n }\n if (engine.symlink(target, sym.path).status !== 0) lost++;\n }\n\n engine.flush();\n repairOk = true;\n } finally {\n tmpHandle.close();\n if (!repairOk) {\n await cleanupTmpFile(rootDir);\n }\n }\n\n // Verify repaired VFS via re-mount, then swap into place\n // swapTmpToVFS calls verifyVFS internally — if verification fails,\n // .vfs.bin.tmp still exists and .vfs.bin is untouched\n try {\n await swapTmpToVFS(rootDir, tmpFileHandle);\n } catch (err: any) {\n // Swap failed — clean up temp file, throw descriptive error\n await cleanupTmpFile(rootDir);\n throw new Error(`Repair built a VFS but verification failed: ${err.message}`);\n }\n\n const entries = recovered\n .filter(e => e.path !== '/')\n .map(e => ({\n path: e.path,\n type: (e.type === INODE_TYPE.FILE ? 'file' : e.type === INODE_TYPE.DIRECTORY ? 'directory' : 'symlink') as 'file' | 'directory' | 'symlink',\n size: e.dataSize,\n contentLost: e.contentLost,\n }));\n\n return { recovered: entries.length, lost, entries };\n}\n\n// ========== Load handler ==========\n\nasync function handleLoad(root: string) {\n const rootDir = await navigateToRoot(root);\n\n // Clean up any orphaned temp file\n await cleanupTmpFile(rootDir);\n\n // Read all OPFS files FIRST (before touching .vfs.bin)\n const opfsEntries = await readOPFSRecursive(rootDir, '', new Set(['.vfs.bin', '.vfs.bin.tmp']));\n\n // Build fresh VFS in temp file — original .vfs.bin untouched until verified\n const tmpFileHandle = await rootDir.getFileHandle('.vfs.bin.tmp', { create: true });\n const tmpHandle = await (tmpFileHandle as any).createSyncAccessHandle();\n\n let buildOk = false;\n let files = 0;\n let directories = 0;\n\n try {\n const engine = new VFSEngine();\n engine.init(tmpHandle);\n\n const dirs = opfsEntries\n .filter(e => e.type === 'directory')\n .sort((a, b) => a.path.localeCompare(b.path));\n\n for (const dir of dirs) {\n if (engine.mkdir(dir.path, 0o040755).status === 0) {\n directories++;\n }\n }\n\n const fileEntries = opfsEntries.filter(e => e.type === 'file');\n for (const file of fileEntries) {\n if (engine.write(file.path, new Uint8Array(file.data ?? new ArrayBuffer(0))).status === 0) {\n files++;\n }\n }\n\n engine.flush();\n buildOk = true;\n } finally {\n tmpHandle.close();\n if (!buildOk) {\n await cleanupTmpFile(rootDir);\n }\n }\n\n // Verify then swap (verifyVFS + copy-then-delete)\n try {\n await swapTmpToVFS(rootDir, tmpFileHandle);\n } catch (err: any) {\n await cleanupTmpFile(rootDir);\n throw new Error(`Load built a VFS but verification failed: ${err.message}`);\n }\n\n return { files, directories };\n}\n"],"mappings":"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","names":["inode","data","children","totalSize","buf","view","offset","fd","decoder"]}
1
+ {"version":3,"sources":["../../src/src/vfs/layout.ts","../../src/src/errors.ts","../../src/src/vfs/engine.ts","../../src/src/workers/repair.worker.ts"],"sourcesContent":["/**\n * VFS Binary Layout Constants\n *\n * Defines the on-disk structure of the virtual filesystem binary file.\n * All reads/writes go through a FileSystemSyncAccessHandle.\n */\n\n// Magic number: \"VFS!\" in ASCII\nexport const VFS_MAGIC = 0x56465321;\nexport const VFS_VERSION = 1;\n\n// Default sizes\nexport const DEFAULT_BLOCK_SIZE = 4096;\nexport const DEFAULT_INODE_COUNT = 100000;\nexport const INODE_SIZE = 64; // bytes per inode entry\n\n// Superblock layout (64 bytes)\nexport const SUPERBLOCK = {\n SIZE: 64,\n MAGIC: 0, // uint32 - 0x56465321\n VERSION: 4, // uint32\n INODE_COUNT: 8, // uint32 - total inodes allocated\n BLOCK_SIZE: 12, // uint32 - data block size (default 4096)\n TOTAL_BLOCKS: 16, // uint32 - total data blocks\n FREE_BLOCKS: 20, // uint32 - available data blocks\n INODE_OFFSET: 24, // float64 - byte offset to inode table\n PATH_OFFSET: 32, // float64 - byte offset to path table\n DATA_OFFSET: 40, // float64 - byte offset to data region\n BITMAP_OFFSET: 48, // float64 - byte offset to free block bitmap\n PATH_USED: 56, // uint32 - bytes used in path table\n RESERVED: 60, // uint32\n} as const;\n\n// Inode entry layout (64 bytes each)\nexport const INODE = {\n TYPE: 0, // uint8 - 0=free, 1=file, 2=directory, 3=symlink\n FLAGS: 1, // uint8[3] - reserved\n PATH_OFFSET: 4, // uint32 - byte offset into path table\n PATH_LENGTH: 8, // uint16 - length of path string\n NLINK: 10, // uint16 - hard link count\n MODE: 12, // uint32 - permissions (e.g. 0o100644)\n SIZE: 16, // float64 - file content size in bytes (using f64 for >4GB)\n FIRST_BLOCK: 24, // uint32 - index of first data block\n BLOCK_COUNT: 28, // uint32 - number of contiguous data blocks\n MTIME: 32, // float64 - last modification time (ms since epoch)\n CTIME: 40, // float64 - creation/change time (ms since epoch)\n ATIME: 48, // float64 - last access time (ms since epoch)\n UID: 56, // uint32 - owner\n GID: 60, // uint32 - group\n} as const;\n\n// Inode type constants\nexport const INODE_TYPE = {\n FREE: 0,\n FILE: 1,\n DIRECTORY: 2,\n SYMLINK: 3,\n} as const;\n\n// Default file modes\nexport const DEFAULT_FILE_MODE = 0o100644;\nexport const DEFAULT_DIR_MODE = 0o040755;\nexport const DEFAULT_SYMLINK_MODE = 0o120777;\nexport const DEFAULT_UMASK = 0o022;\n\n// POSIX file type bits\nexport const S_IFMT = 0o170000;\nexport const S_IFREG = 0o100000;\nexport const S_IFDIR = 0o040000;\nexport const S_IFLNK = 0o120000;\n\n// Max symlink depth for cycle detection\nexport const MAX_SYMLINK_DEPTH = 40;\n\n// Path table compaction threshold (25% dead space)\nexport const PATH_COMPACTION_THRESHOLD = 0.25;\n\n// Initial path table size (256KB)\nexport const INITIAL_PATH_TABLE_SIZE = 256 * 1024;\n\n// Initial data blocks (1024 blocks = 4MB with 4KB blocks)\nexport const INITIAL_DATA_BLOCKS = 1024;\n\n/**\n * Calculate section offsets for a fresh VFS.\n */\nexport function calculateLayout(inodeCount: number = DEFAULT_INODE_COUNT, blockSize: number = DEFAULT_BLOCK_SIZE, totalBlocks: number = INITIAL_DATA_BLOCKS) {\n const inodeTableOffset = SUPERBLOCK.SIZE;\n const inodeTableSize = inodeCount * INODE_SIZE;\n const pathTableOffset = inodeTableOffset + inodeTableSize;\n const pathTableSize = INITIAL_PATH_TABLE_SIZE;\n const bitmapOffset = pathTableOffset + pathTableSize;\n const bitmapSize = Math.ceil(totalBlocks / 8);\n // Align data region to block boundary\n const dataOffset = Math.ceil((bitmapOffset + bitmapSize) / blockSize) * blockSize;\n const totalSize = dataOffset + totalBlocks * blockSize;\n\n return {\n inodeTableOffset,\n inodeTableSize,\n pathTableOffset,\n pathTableSize,\n bitmapOffset,\n bitmapSize,\n dataOffset,\n totalSize,\n totalBlocks,\n };\n}\n","/**\n * Node.js compatible filesystem error classes\n */\n\nexport class FSError extends Error {\n code: string;\n errno: number;\n syscall?: string;\n path?: string;\n\n constructor(code: string, errno: number, message: string, syscall?: string, path?: string) {\n super(message);\n this.name = 'FSError';\n this.code = code;\n this.errno = errno;\n this.syscall = syscall;\n this.path = path;\n }\n}\n\nexport const ErrorCodes = {\n ENOENT: -2,\n EEXIST: -17,\n EISDIR: -21,\n ENOTDIR: -20,\n ENOTEMPTY: -39,\n EACCES: -13,\n EBADF: -9,\n EINVAL: -22,\n EMFILE: -24,\n ENOSPC: -28,\n EPERM: -1,\n ENOSYS: -38,\n ELOOP: -40,\n} as const;\n\n/** Binary protocol status codes → error code mapping */\nexport const STATUS_TO_CODE: Record<number, string> = {\n 0: 'OK',\n 1: 'ENOENT',\n 2: 'EEXIST',\n 3: 'EISDIR',\n 4: 'ENOTDIR',\n 5: 'ENOTEMPTY',\n 6: 'EACCES',\n 7: 'EINVAL',\n 8: 'EBADF',\n 9: 'ELOOP',\n 10: 'ENOSPC',\n};\n\n/** Error code → binary protocol status mapping */\nexport const CODE_TO_STATUS: Record<string, number> = {\n OK: 0,\n ENOENT: 1,\n EEXIST: 2,\n EISDIR: 3,\n ENOTDIR: 4,\n ENOTEMPTY: 5,\n EACCES: 6,\n EINVAL: 7,\n EBADF: 8,\n ELOOP: 9,\n ENOSPC: 10,\n};\n\nexport function createError(code: string, syscall: string, path: string): FSError {\n const errno = ErrorCodes[code as keyof typeof ErrorCodes] ?? -1;\n const messages: Record<string, string> = {\n ENOENT: 'no such file or directory',\n EEXIST: 'file already exists',\n EISDIR: 'illegal operation on a directory',\n ENOTDIR: 'not a directory',\n ENOTEMPTY: 'directory not empty',\n EACCES: 'permission denied',\n EINVAL: 'invalid argument',\n EBADF: 'bad file descriptor',\n ELOOP: 'too many symbolic links encountered',\n ENOSPC: 'no space left on device',\n };\n const msg = messages[code] ?? 'unknown error';\n return new FSError(code, errno, `${code}: ${msg}, ${syscall} '${path}'`, syscall, path);\n}\n\nexport function statusToError(status: number, syscall: string, path: string): FSError {\n const code = STATUS_TO_CODE[status] ?? 'EINVAL';\n return createError(code, syscall, path);\n}\n","/**\n * VFS Engine — operates on a FileSystemSyncAccessHandle\n *\n * Manages the binary VFS layout: superblock, inode table, path table,\n * free block bitmap, and data region. All operations are synchronous\n * and run inside the server worker.\n */\n\nimport {\n VFS_MAGIC, VFS_VERSION, SUPERBLOCK, INODE, INODE_SIZE, INODE_TYPE,\n DEFAULT_BLOCK_SIZE, DEFAULT_INODE_COUNT, DEFAULT_FILE_MODE, DEFAULT_DIR_MODE,\n DEFAULT_SYMLINK_MODE, DEFAULT_UMASK, S_IFMT, S_IFREG, S_IFDIR, S_IFLNK,\n MAX_SYMLINK_DEPTH, INITIAL_DATA_BLOCKS, INITIAL_PATH_TABLE_SIZE,\n calculateLayout,\n} from './layout.js';\nimport { CODE_TO_STATUS } from '../errors.js';\n\nconst encoder = new TextEncoder();\nconst decoder = new TextDecoder();\n\ninterface Inode {\n type: number;\n pathOffset: number;\n pathLength: number;\n mode: number;\n size: number;\n firstBlock: number;\n blockCount: number;\n mtime: number;\n ctime: number;\n atime: number;\n uid: number;\n gid: number;\n nlink: number;\n}\n\ninterface FdEntry {\n tabId: string;\n inodeIdx: number;\n position: number;\n flags: number;\n implicitPath?: string; // set when fd was opened via opendir on an implicit directory\n}\n\nexport class VFSEngine {\n private handle!: FileSystemSyncAccessHandle;\n private pathIndex = new Map<string, number>(); // path → inode index\n private inodeCount = 0;\n private blockSize = DEFAULT_BLOCK_SIZE;\n private totalBlocks = 0;\n private freeBlocks = 0;\n private inodeTableOffset = 0;\n private pathTableOffset = 0;\n private pathTableUsed = 0;\n private pathTableSize = 0;\n private bitmapOffset = 0;\n private dataOffset = 0;\n private umask = DEFAULT_UMASK;\n private processUid = 0;\n private processGid = 0;\n private strictPermissions = false;\n private debug = false;\n\n // File descriptor table\n private fdTable = new Map<number, FdEntry>();\n private nextFd = 3; // 0=stdin, 1=stdout, 2=stderr reserved\n\n // Reusable buffers to avoid allocations\n private inodeBuf = new Uint8Array(INODE_SIZE);\n private inodeView = new DataView(this.inodeBuf.buffer);\n\n // In-memory inode cache — eliminates disk reads for hot inodes\n private inodeCache = new Map<number, Inode>();\n private superblockBuf = new Uint8Array(SUPERBLOCK.SIZE);\n private superblockView = new DataView(this.superblockBuf.buffer);\n\n // In-memory bitmap cache — eliminates bitmap reads from OPFS\n private bitmap: Uint8Array | null = null;\n private bitmapDirtyLo = Infinity; // lowest dirty byte index\n private bitmapDirtyHi = -1; // highest dirty byte index (inclusive)\n private superblockDirty = false;\n\n // Free inode hint — skip O(n) scan\n private freeInodeHint = 0;\n\n // Implicit directory support — tracks all directory prefixes implied by file paths.\n // Rebuilt lazily when pathIndex changes (tracked via generation counter).\n // Map value is the stable timestamp (ms since epoch) assigned when the implicit\n // dir was first discovered, so that stat() returns consistent mtime/ctime/atime\n // across repeated calls.\n private implicitDirs = new Map<string, number>();\n private implicitDirsGen = -1; // generation when implicitDirs was last rebuilt\n private pathIndexGen = 0; // bumped on every pathIndex mutation\n\n // Incrementally maintained \"number of pathIndex entries that have this\n // path as a strict ancestor\" map. Lets `isImplicitDirectory` answer in\n // O(1) — an implicit dir P is exactly !pathIndex.has(P) && descCount[P] > 0.\n // Without this, every `isImplicitDirectory` call triggered an O(N×depth)\n // rebuild of `implicitDirs`, and the 3.0.49 fix put one of those calls on\n // the hot path of every fresh write/symlink/link/copy — making batch\n // writes O(N²) on total path count.\n private descCount = new Map<string, number>();\n // descCount is in sync with pathIndex iff descCountGen >= pathIndexGen.\n // Helpers `setPathIndex`/`deletePathIndex` keep them in sync. Code that\n // mutates `pathIndex` directly (only test scaffolding does this in\n // practice — see the implicit-directory tests in vfs-engine.test.ts)\n // bumps `pathIndexGen` without going through the helpers, which leaves\n // descCount stale; `isImplicitDirectory` notices the mismatch and\n // recomputes descCount on demand.\n private descCountGen = 0;\n\n // Configurable upper bounds\n private maxInodes = 4_000_000;\n private maxBlocks = 4_000_000;\n private maxPathTable = 256 * 1024 * 1024; // 256MB\n private maxVFSSize = 100 * 1024 * 1024 * 1024; // 100GB\n\n init(\n handle: FileSystemSyncAccessHandle,\n opts?: {\n uid?: number; gid?: number; umask?: number; strictPermissions?: boolean; debug?: boolean;\n limits?: { maxInodes?: number; maxBlocks?: number; maxPathTable?: number; maxVFSSize?: number };\n }\n ): void {\n this.handle = handle;\n this.processUid = opts?.uid ?? 0;\n this.processGid = opts?.gid ?? 0;\n this.umask = opts?.umask ?? DEFAULT_UMASK;\n this.strictPermissions = opts?.strictPermissions ?? false;\n this.debug = opts?.debug ?? false;\n if (opts?.limits) {\n if (opts.limits.maxInodes != null) this.maxInodes = opts.limits.maxInodes;\n if (opts.limits.maxBlocks != null) this.maxBlocks = opts.limits.maxBlocks;\n if (opts.limits.maxPathTable != null) this.maxPathTable = opts.limits.maxPathTable;\n if (opts.limits.maxVFSSize != null) this.maxVFSSize = opts.limits.maxVFSSize;\n }\n\n const size = handle.getSize();\n\n if (size === 0) {\n this.format();\n } else {\n try {\n this.mount();\n } catch (err) {\n // Ensure all mount errors are prefixed with \"Corrupt VFS:\" so the\n // sync-relay handler recognizes them as corruption (not OPFS contention)\n // and triggers fallback instead of infinite retry.\n const msg = (err as Error).message ?? String(err);\n if (msg.startsWith('Corrupt VFS:')) throw err;\n throw new Error(`Corrupt VFS: ${msg}`);\n }\n }\n }\n\n /** Release the sync access handle (call on fatal error or shutdown) */\n closeHandle(): void {\n try {\n this.handle?.close();\n } catch (_) {\n // Ignore — handle may already be closed\n }\n }\n\n /** Format a fresh VFS */\n private format(): void {\n const layout = calculateLayout(DEFAULT_INODE_COUNT, DEFAULT_BLOCK_SIZE, INITIAL_DATA_BLOCKS);\n\n this.inodeCount = DEFAULT_INODE_COUNT;\n this.blockSize = DEFAULT_BLOCK_SIZE;\n this.totalBlocks = layout.totalBlocks;\n this.freeBlocks = layout.totalBlocks;\n this.inodeTableOffset = layout.inodeTableOffset;\n this.pathTableOffset = layout.pathTableOffset;\n this.pathTableSize = layout.pathTableSize;\n this.pathTableUsed = 0;\n this.bitmapOffset = layout.bitmapOffset;\n this.dataOffset = layout.dataOffset;\n\n // Grow file to total size\n this.handle.truncate(layout.totalSize);\n\n // Write superblock\n this.writeSuperblock();\n\n // Zero out inode table (type=0 means free)\n const zeroBuf = new Uint8Array(layout.inodeTableSize);\n this.handle.write(zeroBuf, { at: this.inodeTableOffset });\n\n // Zero out bitmap and cache in memory\n this.bitmap = new Uint8Array(layout.bitmapSize);\n this.handle.write(this.bitmap, { at: this.bitmapOffset });\n\n // Create root directory inode\n this.createInode('/', INODE_TYPE.DIRECTORY, DEFAULT_DIR_MODE, 0);\n\n // Re-write superblock with updated pathTableUsed (createInode appended \"/\" to path table)\n this.writeSuperblock();\n this.handle.flush();\n }\n\n /** Mount an existing VFS from disk — validates superblock integrity */\n private mount(): void {\n const fileSize = this.handle.getSize();\n if (fileSize < SUPERBLOCK.SIZE) {\n throw new Error(`Corrupt VFS: file too small (${fileSize} bytes, need at least ${SUPERBLOCK.SIZE})`);\n }\n\n this.handle.read(this.superblockBuf, { at: 0 });\n const v = this.superblockView;\n\n // Validate magic\n const magic = v.getUint32(SUPERBLOCK.MAGIC, true);\n if (magic !== VFS_MAGIC) {\n throw new Error(`Corrupt VFS: bad magic 0x${magic.toString(16)} (expected 0x${VFS_MAGIC.toString(16)})`);\n }\n\n // Validate version\n const version = v.getUint32(SUPERBLOCK.VERSION, true);\n if (version !== VFS_VERSION) {\n throw new Error(`Corrupt VFS: unsupported version ${version} (expected ${VFS_VERSION})`);\n }\n\n // Read superblock fields\n const inodeCount = v.getUint32(SUPERBLOCK.INODE_COUNT, true);\n const blockSize = v.getUint32(SUPERBLOCK.BLOCK_SIZE, true);\n const totalBlocks = v.getUint32(SUPERBLOCK.TOTAL_BLOCKS, true);\n const freeBlocks = v.getUint32(SUPERBLOCK.FREE_BLOCKS, true);\n const inodeTableOffset = v.getFloat64(SUPERBLOCK.INODE_OFFSET, true);\n const pathTableOffset = v.getFloat64(SUPERBLOCK.PATH_OFFSET, true);\n const dataOffset = v.getFloat64(SUPERBLOCK.DATA_OFFSET, true);\n const bitmapOffset = v.getFloat64(SUPERBLOCK.BITMAP_OFFSET, true);\n const pathUsed = v.getUint32(SUPERBLOCK.PATH_USED, true);\n\n // Validate field sanity\n if (blockSize === 0 || (blockSize & (blockSize - 1)) !== 0) {\n throw new Error(`Corrupt VFS: invalid block size ${blockSize} (must be power of 2)`);\n }\n if (inodeCount === 0) {\n throw new Error('Corrupt VFS: inode count is 0');\n }\n if (freeBlocks > totalBlocks) {\n throw new Error(`Corrupt VFS: free blocks (${freeBlocks}) exceeds total blocks (${totalBlocks})`);\n }\n\n // Sane upper bounds — prevent huge allocations from corrupt values.\n // Configurable via opts.limits in init().\n if (inodeCount > this.maxInodes) {\n throw new Error(`Corrupt VFS: inode count ${inodeCount} exceeds maximum ${this.maxInodes}`);\n }\n if (totalBlocks > this.maxBlocks) {\n throw new Error(`Corrupt VFS: total blocks ${totalBlocks} exceeds maximum ${this.maxBlocks}`);\n }\n if (fileSize > this.maxVFSSize) {\n throw new Error(`Corrupt VFS: file size ${fileSize} exceeds maximum ${this.maxVFSSize}`);\n }\n\n // Validate all offsets are finite positive integers\n if (!Number.isFinite(inodeTableOffset) || inodeTableOffset < 0 ||\n !Number.isFinite(pathTableOffset) || pathTableOffset < 0 ||\n !Number.isFinite(bitmapOffset) || bitmapOffset < 0 ||\n !Number.isFinite(dataOffset) || dataOffset < 0) {\n throw new Error(`Corrupt VFS: non-finite or negative section offset`);\n }\n\n // Validate section ordering: superblock < inodes < paths < bitmap < data\n if (inodeTableOffset !== SUPERBLOCK.SIZE) {\n throw new Error(`Corrupt VFS: inode table offset ${inodeTableOffset} (expected ${SUPERBLOCK.SIZE})`);\n }\n const expectedPathOffset = inodeTableOffset + inodeCount * INODE_SIZE;\n if (pathTableOffset !== expectedPathOffset) {\n throw new Error(`Corrupt VFS: path table offset ${pathTableOffset} (expected ${expectedPathOffset})`);\n }\n if (bitmapOffset <= pathTableOffset) {\n throw new Error(`Corrupt VFS: bitmap offset ${bitmapOffset} must be after path table ${pathTableOffset}`);\n }\n if (dataOffset <= bitmapOffset) {\n throw new Error(`Corrupt VFS: data offset ${dataOffset} must be after bitmap ${bitmapOffset}`);\n }\n const pathTableSize = bitmapOffset - pathTableOffset;\n if (pathUsed > pathTableSize) {\n throw new Error(`Corrupt VFS: path used (${pathUsed}) exceeds path table size (${pathTableSize})`);\n }\n if (pathTableSize > this.maxPathTable) {\n throw new Error(`Corrupt VFS: path table size ${pathTableSize} exceeds maximum ${this.maxPathTable}`);\n }\n\n // Validate file is large enough for the declared layout\n const expectedMinSize = dataOffset + totalBlocks * blockSize;\n if (expectedMinSize > this.maxVFSSize) {\n throw new Error(`Corrupt VFS: computed layout size ${expectedMinSize} exceeds maximum ${this.maxVFSSize}`);\n }\n if (fileSize < expectedMinSize) {\n throw new Error(`Corrupt VFS: file size ${fileSize} too small for layout (need ${expectedMinSize})`);\n }\n\n // All checks passed — commit to engine state\n this.inodeCount = inodeCount;\n this.blockSize = blockSize;\n this.totalBlocks = totalBlocks;\n this.freeBlocks = freeBlocks;\n this.inodeTableOffset = inodeTableOffset;\n this.pathTableOffset = pathTableOffset;\n this.dataOffset = dataOffset;\n this.bitmapOffset = bitmapOffset;\n this.pathTableUsed = pathUsed;\n this.pathTableSize = pathTableSize;\n\n // Load bitmap into memory\n const bitmapSize = Math.ceil(this.totalBlocks / 8);\n this.bitmap = new Uint8Array(bitmapSize);\n this.handle.read(this.bitmap, { at: this.bitmapOffset });\n\n this.rebuildIndex();\n\n // Verify root directory exists\n if (!this.pathIndex.has('/')) {\n throw new Error('Corrupt VFS: root directory \"/\" not found in inode table');\n }\n }\n\n private writeSuperblock(): void {\n const v = this.superblockView;\n v.setUint32(SUPERBLOCK.MAGIC, VFS_MAGIC, true);\n v.setUint32(SUPERBLOCK.VERSION, VFS_VERSION, true);\n v.setUint32(SUPERBLOCK.INODE_COUNT, this.inodeCount, true);\n v.setUint32(SUPERBLOCK.BLOCK_SIZE, this.blockSize, true);\n v.setUint32(SUPERBLOCK.TOTAL_BLOCKS, this.totalBlocks, true);\n v.setUint32(SUPERBLOCK.FREE_BLOCKS, this.freeBlocks, true);\n v.setFloat64(SUPERBLOCK.INODE_OFFSET, this.inodeTableOffset, true);\n v.setFloat64(SUPERBLOCK.PATH_OFFSET, this.pathTableOffset, true);\n v.setFloat64(SUPERBLOCK.DATA_OFFSET, this.dataOffset, true);\n v.setFloat64(SUPERBLOCK.BITMAP_OFFSET, this.bitmapOffset, true);\n v.setUint32(SUPERBLOCK.PATH_USED, this.pathTableUsed, true);\n this.handle.write(this.superblockBuf, { at: 0 });\n }\n\n /** Flush pending bitmap and superblock writes to disk (one write each) */\n private markBitmapDirty(lo: number, hi: number): void {\n if (lo < this.bitmapDirtyLo) this.bitmapDirtyLo = lo;\n if (hi > this.bitmapDirtyHi) this.bitmapDirtyHi = hi;\n }\n\n private commitPending(): void {\n // Trim trailing free blocks before flushing bitmap/superblock\n if (this.blocksFreedsinceTrim) {\n this.trimTrailingBlocks();\n this.blocksFreedsinceTrim = false;\n }\n\n if (this.bitmapDirtyHi >= 0) {\n const lo = this.bitmapDirtyLo;\n const hi = this.bitmapDirtyHi;\n this.handle.write(this.bitmap!.subarray(lo, hi + 1), { at: this.bitmapOffset + lo });\n this.bitmapDirtyLo = Infinity;\n this.bitmapDirtyHi = -1;\n }\n if (this.superblockDirty) {\n this.writeSuperblock();\n this.superblockDirty = false;\n }\n }\n\n /** Shrink the OPFS file by removing trailing free blocks from the data region.\n * Scans bitmap from end to find the last used block, then truncates. */\n private trimTrailingBlocks(): void {\n const bitmap = this.bitmap!;\n\n // Find the last used block by scanning bitmap from the end\n let lastUsed = -1;\n for (let byteIdx = Math.ceil(this.totalBlocks / 8) - 1; byteIdx >= 0; byteIdx--) {\n if (bitmap[byteIdx] !== 0) {\n // Find highest set bit in this byte\n for (let bit = 7; bit >= 0; bit--) {\n const blockIdx = byteIdx * 8 + bit;\n if (blockIdx < this.totalBlocks && (bitmap[byteIdx] & (1 << bit))) {\n lastUsed = blockIdx;\n break;\n }\n }\n break;\n }\n }\n\n const newTotal = Math.max(lastUsed + 1, INITIAL_DATA_BLOCKS);\n if (newTotal >= this.totalBlocks) return; // nothing to trim\n\n // Truncate the OPFS file\n this.handle.truncate(this.dataOffset + newTotal * this.blockSize);\n\n // Shrink in-memory bitmap\n const newBitmapSize = Math.ceil(newTotal / 8);\n this.bitmap = bitmap.slice(0, newBitmapSize);\n\n // Update counters\n const trimmed = this.totalBlocks - newTotal;\n this.freeBlocks -= trimmed; // these free blocks no longer exist\n this.totalBlocks = newTotal;\n this.superblockDirty = true;\n\n // Re-mark entire bitmap dirty so the smaller bitmap is flushed\n this.bitmapDirtyLo = 0;\n this.bitmapDirtyHi = newBitmapSize - 1;\n }\n\n /** Rebuild in-memory path→inode index from disk.\n * Bulk-reads the entire inode table + path table in 2 I/O calls,\n * then parses in memory (avoids 10k+ individual reads). */\n private rebuildIndex(): void {\n this.pathIndex.clear();\n this.inodeCache.clear();\n\n // Bulk read entire inode table (e.g. 640KB for 10k inodes)\n const inodeTableSize = this.inodeCount * INODE_SIZE;\n const inodeBuf = new Uint8Array(inodeTableSize);\n this.handle.read(inodeBuf, { at: this.inodeTableOffset });\n const inodeView = new DataView(inodeBuf.buffer);\n\n // Bulk read used portion of path table\n const pathBuf = this.pathTableUsed > 0 ? new Uint8Array(this.pathTableUsed) : null;\n if (pathBuf) {\n this.handle.read(pathBuf, { at: this.pathTableOffset });\n }\n\n for (let i = 0; i < this.inodeCount; i++) {\n const off = i * INODE_SIZE;\n const type = inodeView.getUint8(off + INODE.TYPE);\n if (type === INODE_TYPE.FREE) continue;\n\n // Validate inode type\n if (type < INODE_TYPE.FILE || type > INODE_TYPE.SYMLINK) {\n throw new Error(`Corrupt VFS: inode ${i} has invalid type ${type}`);\n }\n\n const pathOffset = inodeView.getUint32(off + INODE.PATH_OFFSET, true);\n const pathLength = inodeView.getUint16(off + INODE.PATH_LENGTH, true);\n const size = inodeView.getFloat64(off + INODE.SIZE, true);\n const firstBlock = inodeView.getUint32(off + INODE.FIRST_BLOCK, true);\n const blockCount = inodeView.getUint32(off + INODE.BLOCK_COUNT, true);\n\n // Validate path bounds\n if (pathLength === 0 || pathOffset + pathLength > this.pathTableUsed) {\n throw new Error(`Corrupt VFS: inode ${i} path out of bounds (offset=${pathOffset}, len=${pathLength}, tableUsed=${this.pathTableUsed})`);\n }\n\n // Validate data bounds for files/symlinks\n if (type !== INODE_TYPE.DIRECTORY) {\n if (size < 0 || !isFinite(size)) {\n throw new Error(`Corrupt VFS: inode ${i} has invalid size ${size}`);\n }\n if (blockCount > 0 && firstBlock + blockCount > this.totalBlocks) {\n throw new Error(`Corrupt VFS: inode ${i} data blocks out of range (first=${firstBlock}, count=${blockCount}, total=${this.totalBlocks})`);\n }\n }\n\n const inode: Inode = {\n type,\n pathOffset,\n pathLength,\n nlink: inodeView.getUint16(off + INODE.NLINK, true) || 1,\n mode: inodeView.getUint32(off + INODE.MODE, true),\n size,\n firstBlock,\n blockCount,\n mtime: inodeView.getFloat64(off + INODE.MTIME, true),\n ctime: inodeView.getFloat64(off + INODE.CTIME, true),\n atime: inodeView.getFloat64(off + INODE.ATIME, true),\n uid: inodeView.getUint32(off + INODE.UID, true),\n gid: inodeView.getUint32(off + INODE.GID, true),\n };\n this.inodeCache.set(i, inode);\n\n // Decode path from in-memory path table buffer (no disk read)\n let path: string;\n if (pathBuf) {\n path = decoder.decode(pathBuf.subarray(inode.pathOffset, inode.pathOffset + inode.pathLength));\n } else {\n path = this.readPath(inode.pathOffset, inode.pathLength);\n }\n\n // Validate path format\n if (!path.startsWith('/') || path.includes('\\0')) {\n throw new Error(`Corrupt VFS: inode ${i} has invalid path \"${path.substring(0, 50)}\"`);\n }\n\n this.setPathIndex(path, i);\n }\n this.pathIndexGen++;\n }\n\n // ========== Low-level inode I/O ==========\n\n private readInode(idx: number): Inode {\n const cached = this.inodeCache.get(idx);\n if (cached) return cached;\n\n const offset = this.inodeTableOffset + idx * INODE_SIZE;\n this.handle.read(this.inodeBuf, { at: offset });\n const v = this.inodeView;\n const inode: Inode = {\n type: v.getUint8(INODE.TYPE),\n pathOffset: v.getUint32(INODE.PATH_OFFSET, true),\n pathLength: v.getUint16(INODE.PATH_LENGTH, true),\n nlink: v.getUint16(INODE.NLINK, true) || 1,\n mode: v.getUint32(INODE.MODE, true),\n size: v.getFloat64(INODE.SIZE, true),\n firstBlock: v.getUint32(INODE.FIRST_BLOCK, true),\n blockCount: v.getUint32(INODE.BLOCK_COUNT, true),\n mtime: v.getFloat64(INODE.MTIME, true),\n ctime: v.getFloat64(INODE.CTIME, true),\n atime: v.getFloat64(INODE.ATIME, true),\n uid: v.getUint32(INODE.UID, true),\n gid: v.getUint32(INODE.GID, true),\n };\n this.inodeCache.set(idx, inode);\n return inode;\n }\n\n private writeInode(idx: number, inode: Inode): void {\n // Maintain inode cache\n if (inode.type === INODE_TYPE.FREE) {\n this.inodeCache.delete(idx);\n } else {\n this.inodeCache.set(idx, inode);\n }\n\n const v = this.inodeView;\n v.setUint8(INODE.TYPE, inode.type);\n v.setUint8(INODE.FLAGS, 0);\n v.setUint8(INODE.FLAGS + 1, 0);\n v.setUint8(INODE.FLAGS + 2, 0);\n v.setUint32(INODE.PATH_OFFSET, inode.pathOffset, true);\n v.setUint16(INODE.PATH_LENGTH, inode.pathLength, true);\n v.setUint16(INODE.NLINK, inode.nlink, true);\n v.setUint32(INODE.MODE, inode.mode, true);\n v.setFloat64(INODE.SIZE, inode.size, true);\n v.setUint32(INODE.FIRST_BLOCK, inode.firstBlock, true);\n v.setUint32(INODE.BLOCK_COUNT, inode.blockCount, true);\n v.setFloat64(INODE.MTIME, inode.mtime, true);\n v.setFloat64(INODE.CTIME, inode.ctime, true);\n v.setFloat64(INODE.ATIME, inode.atime, true);\n v.setUint32(INODE.UID, inode.uid, true);\n v.setUint32(INODE.GID, inode.gid, true);\n\n const offset = this.inodeTableOffset + idx * INODE_SIZE;\n this.handle.write(this.inodeBuf, { at: offset });\n }\n\n // ========== Path table I/O ==========\n\n private readPath(offset: number, length: number): string {\n const buf = new Uint8Array(length);\n this.handle.read(buf, { at: this.pathTableOffset + offset });\n return decoder.decode(buf);\n }\n\n private appendPath(path: string): { offset: number; length: number } {\n const bytes = encoder.encode(path);\n const offset = this.pathTableUsed;\n\n // Check if path table needs to grow\n if (offset + bytes.byteLength > this.pathTableSize) {\n this.growPathTable(offset + bytes.byteLength);\n }\n\n this.handle.write(bytes, { at: this.pathTableOffset + offset });\n this.pathTableUsed += bytes.byteLength;\n\n // Defer superblock write — committed in commitPending()\n this.superblockDirty = true;\n\n return { offset, length: bytes.byteLength };\n }\n\n private growPathTable(needed: number): void {\n // Double the path table or grow to fit needed, whichever is larger\n const newSize = Math.max(this.pathTableSize * 2, needed + INITIAL_PATH_TABLE_SIZE);\n const growth = newSize - this.pathTableSize;\n\n // Grow file first so the shifted data has somewhere to land.\n const newTotalSize = this.handle.getSize() + growth;\n this.handle.truncate(newTotalSize);\n\n // Shift the data region forward by `growth` bytes. We must NOT allocate\n // a single buffer the size of the whole data section — when the VFS\n // holds a large install (pnpm linking ~1300 Directus packages puts the\n // data section in the hundreds of MB) the one-shot\n // new Uint8Array(dataSize)\n // failed with \"Array buffer allocation failed\" because Chrome refuses\n // allocations near the 2 GB cap even with OS memory to spare.\n //\n // Copy back-to-front through a small scratch buffer so we never\n // overwrite bytes we haven't relocated yet, and the peak allocation\n // stays bounded at CHUNK regardless of how big the VFS has grown.\n const dataSize = this.totalBlocks * this.blockSize;\n const CHUNK = 4 * 1024 * 1024; // 4 MB\n const scratch = new Uint8Array(Math.min(CHUNK, Math.max(dataSize, 1)));\n let remaining = dataSize;\n while (remaining > 0) {\n const chunk = Math.min(remaining, CHUNK);\n const srcAt = this.dataOffset + (remaining - chunk);\n const dstAt = this.dataOffset + growth + (remaining - chunk);\n const slice = chunk < scratch.length ? scratch.subarray(0, chunk) : scratch;\n this.handle.read(slice, { at: srcAt });\n this.handle.write(slice, { at: dstAt });\n remaining -= chunk;\n }\n\n // Write the (in-memory) bitmap to its new offset.\n const newBitmapOffset = this.bitmapOffset + growth;\n const newDataOffset = this.dataOffset + growth;\n this.handle.write(this.bitmap!, { at: newBitmapOffset });\n\n // Update offsets\n this.pathTableSize = newSize;\n this.bitmapOffset = newBitmapOffset;\n this.dataOffset = newDataOffset;\n\n // Mark superblock dirty (will be written in commitPending)\n this.superblockDirty = true;\n }\n\n // ========== Bitmap I/O ==========\n\n // Write `length` zero bytes at absolute file offset `at` via a small\n // reusable scratch buffer. Used to materialize POSIX \"holes\" when a\n // write starts past the current file size — those bytes must read as\n // zeros rather than whatever stale data happened to live in the\n // underlying storage blocks.\n private zeroFileRange(at: number, length: number): void {\n if (length <= 0) return;\n const CHUNK = 4 * 1024 * 1024;\n const zeros = new Uint8Array(Math.min(length, CHUNK));\n let written = 0;\n while (written < length) {\n const n = Math.min(CHUNK, length - written);\n const slice = n < zeros.length ? zeros.subarray(0, n) : zeros;\n this.handle.write(slice, { at: at + written });\n written += n;\n }\n }\n\n private allocateBlocks(count: number): number {\n if (count === 0) return 0;\n\n const bitmap = this.bitmap!;\n let run = 0;\n let start = 0;\n\n for (let i = 0; i < this.totalBlocks; i++) {\n const byteIdx = i >>> 3;\n const bitIdx = i & 7;\n const used = (bitmap[byteIdx] >>> bitIdx) & 1;\n\n if (used) {\n run = 0;\n start = i + 1;\n } else {\n run++;\n if (run === count) {\n // Mark blocks as used in memory\n for (let j = start; j <= i; j++) {\n const bj = j >>> 3;\n const bi = j & 7;\n bitmap[bj] |= (1 << bi);\n }\n this.markBitmapDirty(start >>> 3, i >>> 3);\n this.freeBlocks -= count;\n this.superblockDirty = true;\n return start;\n }\n }\n }\n\n // No contiguous space — grow data region\n return this.growAndAllocate(count);\n }\n\n private growAndAllocate(count: number): number {\n const oldTotal = this.totalBlocks;\n // Grow by at least doubling or enough for the request\n const newTotal = Math.max(oldTotal * 2, oldTotal + count);\n const addedBlocks = newTotal - oldTotal;\n\n // Grow the file\n const newFileSize = this.dataOffset + newTotal * this.blockSize;\n this.handle.truncate(newFileSize);\n\n // Grow in-memory bitmap\n const newBitmapSize = Math.ceil(newTotal / 8);\n const newBitmap = new Uint8Array(newBitmapSize);\n newBitmap.set(this.bitmap!);\n this.bitmap = newBitmap;\n\n this.totalBlocks = newTotal;\n this.freeBlocks += addedBlocks;\n\n // Allocate from the newly freed area\n const start = oldTotal;\n for (let j = start; j < start + count; j++) {\n const bj = j >>> 3;\n const bi = j & 7;\n this.bitmap[bj] |= (1 << bi);\n }\n\n this.markBitmapDirty(start >>> 3, (start + count - 1) >>> 3);\n this.freeBlocks -= count;\n this.superblockDirty = true;\n\n return start;\n }\n\n private blocksFreedsinceTrim = false;\n\n private freeBlockRange(start: number, count: number): void {\n if (count === 0) return;\n const bitmap = this.bitmap!;\n\n for (let i = start; i < start + count; i++) {\n const byteIdx = i >>> 3;\n const bitIdx = i & 7;\n bitmap[byteIdx] &= ~(1 << bitIdx);\n }\n\n this.markBitmapDirty(start >>> 3, (start + count - 1) >>> 3);\n this.freeBlocks += count;\n this.superblockDirty = true;\n this.blocksFreedsinceTrim = true;\n }\n\n // updateSuperblockFreeBlocks is no longer needed — superblock writes are coalesced via commitPending()\n\n // ========== Inode allocation ==========\n\n private findFreeInode(): number {\n // Start from hint to skip already-used entries\n for (let i = this.freeInodeHint; i < this.inodeCount; i++) {\n // Check cache first — cached entries are never FREE\n if (this.inodeCache.has(i)) continue;\n\n const offset = this.inodeTableOffset + i * INODE_SIZE;\n const typeBuf = new Uint8Array(1);\n this.handle.read(typeBuf, { at: offset });\n if (typeBuf[0] === INODE_TYPE.FREE) {\n this.freeInodeHint = i + 1;\n return i;\n }\n }\n // All inodes used — grow inode table\n const idx = this.growInodeTable();\n this.freeInodeHint = idx + 1;\n return idx;\n }\n\n private growInodeTable(): number {\n const oldCount = this.inodeCount;\n const newCount = oldCount * 2;\n const growth = (newCount - oldCount) * INODE_SIZE;\n\n // Read everything after inode table\n const afterInodeOffset = this.inodeTableOffset + oldCount * INODE_SIZE;\n const afterSize = this.handle.getSize() - afterInodeOffset;\n const afterBuf = new Uint8Array(afterSize);\n this.handle.read(afterBuf, { at: afterInodeOffset });\n\n // Grow file\n this.handle.truncate(this.handle.getSize() + growth);\n\n // Write back shifted content\n this.handle.write(afterBuf, { at: afterInodeOffset + growth });\n\n // Zero out new inode entries\n const zeroes = new Uint8Array(growth);\n this.handle.write(zeroes, { at: afterInodeOffset });\n\n // Update offsets\n this.pathTableOffset += growth;\n this.bitmapOffset += growth;\n this.dataOffset += growth;\n this.inodeCount = newCount;\n\n this.superblockDirty = true;\n\n return oldCount; // First new free inode\n }\n\n // ========== Data I/O ==========\n\n private readData(firstBlock: number, blockCount: number, size: number): Uint8Array {\n const buf = new Uint8Array(size);\n const offset = this.dataOffset + firstBlock * this.blockSize;\n this.handle.read(buf, { at: offset });\n return buf;\n }\n\n private writeData(firstBlock: number, data: Uint8Array): void {\n const offset = this.dataOffset + firstBlock * this.blockSize;\n this.handle.write(data, { at: offset });\n }\n\n // ========== Path resolution ==========\n\n private resolvePath(path: string, depth: number = 0): number | undefined {\n if (depth > MAX_SYMLINK_DEPTH) return undefined; // ELOOP\n\n const idx = this.pathIndex.get(path);\n if (idx === undefined) {\n // Path not found directly — try component resolution (handles intermediate symlinks)\n return this.resolvePathComponents(path, true, depth);\n }\n\n const inode = this.readInode(idx);\n if (inode.type === INODE_TYPE.SYMLINK) {\n // Follow symlink\n const target = decoder.decode(this.readData(inode.firstBlock, inode.blockCount, inode.size));\n const resolved = target.startsWith('/') ? target : this.resolveRelative(path, target);\n return this.resolvePath(resolved, depth + 1);\n }\n\n return idx;\n }\n\n /** Resolve symlinks in intermediate path components */\n private resolvePathComponents(path: string, followLast: boolean = true, depth: number = 0): number | undefined {\n const result = this.resolvePathFull(path, followLast, depth);\n return result?.idx;\n }\n\n /**\n * Resolve a path following symlinks, returning both the inode index AND the\n * fully resolved path. This is needed by readdir: when listing a symlinked\n * directory, we must search for children under the resolved target path\n * (where files actually exist in pathIndex), not under the symlink path.\n */\n private resolvePathFull(path: string, followLast: boolean = true, depth: number = 0): { idx: number; resolvedPath: string } | undefined {\n if (depth > MAX_SYMLINK_DEPTH) return undefined; // ELOOP\n\n const parts = path.split('/').filter(Boolean);\n let current = '/';\n\n for (let i = 0; i < parts.length; i++) {\n const isLast = i === parts.length - 1;\n current = current === '/' ? '/' + parts[i] : current + '/' + parts[i];\n\n const idx = this.pathIndex.get(current);\n if (idx === undefined) return undefined;\n\n const inode = this.readInode(idx);\n if (inode.type === INODE_TYPE.SYMLINK && (!isLast || followLast)) {\n const target = decoder.decode(this.readData(inode.firstBlock, inode.blockCount, inode.size));\n const resolved = target.startsWith('/') ? target : this.resolveRelative(current, target);\n\n if (isLast) {\n // Use resolvePathFull (not resolvePath) so intermediate symlinks\n // in the resolved target path are also followed\n return this.resolvePathFull(resolved, true, depth + 1);\n }\n\n // Reconstruct remaining path with resolved symlink\n const remaining = parts.slice(i + 1).join('/');\n const newPath = resolved + (remaining ? '/' + remaining : '');\n return this.resolvePathFull(newPath, followLast, depth + 1);\n }\n }\n\n const finalIdx = this.pathIndex.get(current);\n if (finalIdx === undefined) return undefined;\n return { idx: finalIdx, resolvedPath: current };\n }\n\n private resolveRelative(from: string, target: string): string {\n const dir = from.substring(0, from.lastIndexOf('/')) || '/';\n const parts = (dir + '/' + target).split('/').filter(Boolean);\n const resolved: string[] = [];\n for (const p of parts) {\n if (p === '.') continue;\n if (p === '..') { resolved.pop(); continue; }\n resolved.push(p);\n }\n return '/' + resolved.join('/');\n }\n\n // ========== Core inode creation helper ==========\n\n private createInode(path: string, type: number, mode: number, size: number, data?: Uint8Array): number {\n const idx = this.findFreeInode();\n const { offset: pathOff, length: pathLen } = this.appendPath(path);\n const now = Date.now();\n\n let firstBlock = 0;\n let blockCount = 0;\n\n if (data && data.byteLength > 0) {\n blockCount = Math.ceil(data.byteLength / this.blockSize);\n firstBlock = this.allocateBlocks(blockCount);\n this.writeData(firstBlock, data);\n }\n\n const inode: Inode = {\n type,\n pathOffset: pathOff,\n pathLength: pathLen,\n nlink: type === INODE_TYPE.DIRECTORY ? 2 : 1,\n mode,\n size,\n firstBlock,\n blockCount,\n mtime: now,\n ctime: now,\n atime: now,\n uid: this.processUid,\n gid: this.processGid,\n };\n\n this.writeInode(idx, inode);\n this.setPathIndex(path, idx);\n this.pathIndexGen++;\n\n return idx;\n }\n\n // ========== Public API — called by server worker dispatch ==========\n\n /** Normalize a path: ensure leading /, resolve . and .. */\n normalizePath(p: string): string {\n if (p.charCodeAt(0) !== 47) p = '/' + p; // 47 = '/'\n // Fast path: already normalized (no '.', '..', '//', trailing '/')\n if (p.length === 1) return p; // \"/\"\n if (p.indexOf('/.') === -1 && p.indexOf('//') === -1 && p.charCodeAt(p.length - 1) !== 47) {\n return p;\n }\n // Slow path: full normalize\n const parts = p.split('/').filter(Boolean);\n const resolved: string[] = [];\n for (const part of parts) {\n if (part === '.') continue;\n if (part === '..') { resolved.pop(); continue; }\n resolved.push(part);\n }\n return '/' + resolved.join('/');\n }\n\n // ---- READ ----\n read(path: string): { status: number; data: Uint8Array | null } {\n const t0 = this.debug ? performance.now() : 0;\n path = this.normalizePath(path);\n\n // Fast path: direct index lookup (skips component-by-component walk)\n let idx = this.pathIndex.get(path);\n if (idx !== undefined) {\n const inode = this.inodeCache.get(idx);\n if (inode) {\n // Symlink? Fall through to full resolve\n if (inode.type === INODE_TYPE.SYMLINK) {\n idx = this.resolvePathComponents(path, true);\n } else if (inode.type === INODE_TYPE.DIRECTORY) {\n return { status: CODE_TO_STATUS.EISDIR, data: null };\n } else {\n // Hot path: cached inode, no symlinks\n const data = inode.size > 0\n ? this.readData(inode.firstBlock, inode.blockCount, inode.size)\n : new Uint8Array(0);\n if (this.debug) {\n const t1 = performance.now();\n console.log(`[VFS read] path=${path} size=${inode.size} TOTAL=${(t1-t0).toFixed(3)}ms (fast)`);\n }\n return { status: 0, data };\n }\n }\n }\n\n // Slow path: full component resolution (handles symlinks, uncached inodes)\n if (idx === undefined) idx = this.resolvePathComponents(path, true);\n if (idx === undefined) return { status: CODE_TO_STATUS.ENOENT, data: null };\n\n const inode = this.readInode(idx);\n if (inode.type === INODE_TYPE.DIRECTORY) return { status: CODE_TO_STATUS.EISDIR, data: null };\n\n const data = inode.size > 0\n ? this.readData(inode.firstBlock, inode.blockCount, inode.size)\n : new Uint8Array(0);\n\n if (this.debug) {\n const t1 = performance.now();\n console.log(`[VFS read] path=${path} size=${inode.size} TOTAL=${(t1-t0).toFixed(3)}ms (slow path)`);\n }\n\n return { status: 0, data };\n }\n\n // ---- WRITE ----\n write(path: string, data: Uint8Array, flags: number = 0): { status: number } {\n const t0 = this.debug ? performance.now() : 0;\n path = this.normalizePath(path);\n const t1 = this.debug ? performance.now() : 0;\n\n // Ensure parent directory exists\n const parentStatus = this.ensureParent(path);\n if (parentStatus !== 0) return { status: parentStatus };\n const t2 = this.debug ? performance.now() : 0;\n\n const existingIdx = this.resolvePathComponents(path, true);\n const t3 = this.debug ? performance.now() : 0;\n\n let tAlloc = t3, tData = t3, tInode = t3;\n\n if (existingIdx !== undefined) {\n // Update existing file\n const inode = this.readInode(existingIdx);\n if (inode.type === INODE_TYPE.DIRECTORY) return { status: CODE_TO_STATUS.EISDIR };\n\n const neededBlocks = Math.ceil(data.byteLength / this.blockSize);\n\n if (neededBlocks <= inode.blockCount) {\n // Fits in current blocks\n tAlloc = this.debug ? performance.now() : 0;\n this.writeData(inode.firstBlock, data);\n tData = this.debug ? performance.now() : 0;\n if (neededBlocks < inode.blockCount) {\n this.freeBlockRange(inode.firstBlock + neededBlocks, inode.blockCount - neededBlocks);\n }\n } else {\n // Need more blocks — free old, allocate new\n this.freeBlockRange(inode.firstBlock, inode.blockCount);\n const newFirst = this.allocateBlocks(neededBlocks);\n tAlloc = this.debug ? performance.now() : 0;\n this.writeData(newFirst, data);\n tData = this.debug ? performance.now() : 0;\n inode.firstBlock = newFirst;\n }\n\n inode.size = data.byteLength;\n inode.blockCount = neededBlocks;\n inode.mtime = Date.now();\n this.writeInode(existingIdx, inode);\n tInode = this.debug ? performance.now() : 0;\n } else {\n // Refuse to create a regular file at a path that is an implicit\n // directory (children exist beneath it but no inode for the path\n // itself). Without this guard we'd register a FILE inode at `path`\n // while its descendants stay in pathIndex — the resulting \"file with\n // children\" state breaks every subsequent read of `path` and its\n // subtree.\n if (this.isImplicitDirectory(path)) return { status: CODE_TO_STATUS.EISDIR };\n // Create new file\n const mode = DEFAULT_FILE_MODE & ~(this.umask & 0o777);\n this.createInode(path, INODE_TYPE.FILE, mode, data.byteLength, data);\n tAlloc = this.debug ? performance.now() : 0;\n tData = tAlloc;\n tInode = tAlloc;\n }\n\n // Always commit pending superblock/bitmap changes (matches unlink, mkdir, etc.)\n // Without this, PATH_USED won't be persisted for newly created files,\n // causing \"path out of bounds\" corruption on reload.\n this.commitPending();\n if (flags & 1) {\n this.handle.flush();\n }\n const tFlush = this.debug ? performance.now() : 0;\n\n if (this.debug) {\n const existing = existingIdx !== undefined;\n console.log(`[VFS write] path=${path} size=${data.byteLength} ${existing ? 'UPDATE' : 'CREATE'} normalize=${(t1-t0).toFixed(3)}ms parent=${(t2-t1).toFixed(3)}ms resolve=${(t3-t2).toFixed(3)}ms alloc=${(tAlloc-t3).toFixed(3)}ms data=${(tData-tAlloc).toFixed(3)}ms inode=${(tInode-tData).toFixed(3)}ms flush=${(tFlush-tInode).toFixed(3)}ms TOTAL=${(tFlush-t0).toFixed(3)}ms`);\n }\n\n return { status: 0 };\n }\n\n // ---- APPEND ----\n append(path: string, data: Uint8Array): { status: number } {\n path = this.normalizePath(path);\n const existingIdx = this.resolvePathComponents(path, true);\n\n if (existingIdx === undefined) {\n // Create new file with the data\n return this.write(path, data);\n }\n\n const inode = this.readInode(existingIdx);\n if (inode.type === INODE_TYPE.DIRECTORY) return { status: CODE_TO_STATUS.EISDIR };\n\n // Avoid materializing the whole (existing + data) file in a single\n // Uint8Array — that blew up with \"Array buffer allocation failed\" on\n // large appends (e.g. appending a few MB to a multi-hundred-MB file).\n //\n // Strategy: allocate a new block run sized to the total, copy the\n // existing contents over in bounded chunks, then write the caller's\n // `data` at the end. Peak allocation stays at 4 MB regardless of\n // file size.\n const combinedSize = inode.size + data.byteLength;\n const neededBlocks = Math.ceil(combinedSize / this.blockSize);\n const newFirst = this.allocateBlocks(neededBlocks);\n const newBase = this.dataOffset + newFirst * this.blockSize;\n if (inode.size > 0) {\n const oldBase = this.dataOffset + inode.firstBlock * this.blockSize;\n const CHUNK = 4 * 1024 * 1024; // 4 MB\n const scratch = new Uint8Array(Math.min(CHUNK, inode.size));\n let copied = 0;\n while (copied < inode.size) {\n const n = Math.min(CHUNK, inode.size - copied);\n const slice = n < scratch.length ? scratch.subarray(0, n) : scratch;\n this.handle.read(slice, { at: oldBase + copied });\n this.handle.write(slice, { at: newBase + copied });\n copied += n;\n }\n }\n this.freeBlockRange(inode.firstBlock, inode.blockCount);\n this.handle.write(data, { at: newBase + inode.size });\n\n inode.firstBlock = newFirst;\n inode.blockCount = neededBlocks;\n inode.size = combinedSize;\n inode.mtime = Date.now();\n this.writeInode(existingIdx, inode);\n\n this.commitPending();\n return { status: 0 };\n }\n\n // ---- UNLINK ----\n unlink(path: string): { status: number } {\n path = this.normalizePath(path);\n const idx = this.pathIndex.get(path);\n if (idx === undefined) return { status: CODE_TO_STATUS.ENOENT };\n\n const inode = this.readInode(idx);\n if (inode.type === INODE_TYPE.DIRECTORY) return { status: CODE_TO_STATUS.EISDIR };\n\n // Decrement nlink; only free data when it reaches 0\n inode.nlink = Math.max(0, inode.nlink - 1);\n\n // Free data blocks\n this.freeBlockRange(inode.firstBlock, inode.blockCount);\n\n // Mark inode as free\n inode.type = INODE_TYPE.FREE;\n this.writeInode(idx, inode);\n\n // Remove from index\n this.deletePathIndex(path);\n this.pathIndexGen++;\n // Reset free inode hint\n if (idx < this.freeInodeHint) this.freeInodeHint = idx;\n\n this.commitPending();\n return { status: 0 };\n }\n\n // ---- STAT ----\n stat(path: string): { status: number; data: Uint8Array | null } {\n path = this.normalizePath(path);\n const idx = this.resolvePathComponents(path, true);\n if (idx === undefined) {\n // Check for implicit directory (exists because files exist under it)\n if (this.isImplicitDirectory(path)) {\n return this.encodeImplicitDirStatResponse(path);\n }\n return { status: CODE_TO_STATUS.ENOENT, data: null };\n }\n\n return this.encodeStatResponse(idx);\n }\n\n // ---- LSTAT (no symlink follow for the FINAL component) ----\n lstat(path: string): { status: number; data: Uint8Array | null } {\n path = this.normalizePath(path);\n // Use resolvePathComponents with followLast=false — follows intermediate\n // symlinks but returns the symlink inode itself for the last component.\n // Direct pathIndex.get(path) fails for paths through symlinked directories\n // because children are stored under the symlink target path in pathIndex.\n let idx = this.resolvePathComponents(path, false);\n if (idx === undefined) {\n // Fallback: followLast=false can fail for paths through symlink chains\n // when pathIndex stores files under their resolved (real) path.\n // Try with followLast=true — if it resolves, use the result regardless\n // of whether the final component is a symlink or not. lstat on an\n // existing symlink should return the symlink's own stats, not ENOENT.\n idx = this.resolvePathComponents(path, true);\n if (idx === undefined) {\n // Check for implicit directory\n if (this.isImplicitDirectory(path)) {\n return this.encodeImplicitDirStatResponse(path);\n }\n return { status: CODE_TO_STATUS.ENOENT, data: null };\n }\n }\n\n return this.encodeStatResponse(idx);\n }\n\n private encodeStatResponse(idx: number): { status: number; data: Uint8Array } {\n const inode = this.readInode(idx);\n\n // Compute nlink for directories: 2 + number of child subdirectories\n // (including implicit subdirectories so nlink stays consistent with\n // what readdir reports).\n let nlink = inode.nlink;\n if (inode.type === INODE_TYPE.DIRECTORY) {\n const path = this.readPath(inode.pathOffset, inode.pathLength);\n const children = this.getDirectChildrenWithImplicit(path);\n let subdirCount = 0;\n for (const child of children) {\n if (child.type === 'implicit') {\n subdirCount++;\n } else {\n const childIdx = this.pathIndex.get(child.path);\n if (childIdx !== undefined) {\n const childInode = this.readInode(childIdx);\n if (childInode.type === INODE_TYPE.DIRECTORY) subdirCount++;\n }\n }\n }\n nlink = 2 + subdirCount;\n }\n\n // Encode stat into binary: type(1) + mode(4) + size(8) + mtime(8) + ctime(8) + atime(8) + uid(4) + gid(4) + ino(4) + nlink(4) = 53 bytes\n const buf = new Uint8Array(53);\n const view = new DataView(buf.buffer);\n view.setUint8(0, inode.type);\n view.setUint32(1, inode.mode, true);\n view.setFloat64(5, inode.size, true);\n view.setFloat64(13, inode.mtime, true);\n view.setFloat64(21, inode.ctime, true);\n view.setFloat64(29, inode.atime, true);\n view.setUint32(37, inode.uid, true);\n view.setUint32(41, inode.gid, true);\n view.setUint32(45, idx, true); // ino = inode index\n view.setUint32(49, nlink, true);\n\n return { status: 0, data: buf };\n }\n\n // ---- MKDIR ----\n mkdir(path: string, flags: number = 0): { status: number; data: Uint8Array | null } {\n path = this.normalizePath(path);\n const recursive = (flags & 1) !== 0;\n\n if (recursive) {\n return this.mkdirRecursive(path);\n }\n\n // Check if already exists (explicit or implicit)\n if (this.pathIndex.has(path) || this.isImplicitDirectory(path)) {\n return { status: CODE_TO_STATUS.EEXIST, data: null };\n }\n\n // Ensure parent exists\n const parentStatus = this.ensureParent(path);\n if (parentStatus !== 0) return { status: parentStatus, data: null };\n\n const mode = DEFAULT_DIR_MODE & ~(this.umask & 0o777);\n this.createInode(path, INODE_TYPE.DIRECTORY, mode, 0);\n\n this.commitPending();\n // Non-recursive mkdir returns undefined (null data) per Node.js spec\n return { status: 0, data: null };\n }\n\n private mkdirRecursive(path: string): { status: number; data: Uint8Array | null } {\n const parts = path.split('/').filter(Boolean);\n let current = '';\n let firstCreated: string | null = null;\n\n for (const part of parts) {\n current += '/' + part;\n\n if (this.pathIndex.has(current)) {\n const idx = this.pathIndex.get(current)!;\n const inode = this.readInode(idx);\n if (inode.type !== INODE_TYPE.DIRECTORY) {\n return { status: CODE_TO_STATUS.ENOTDIR, data: null };\n }\n continue;\n }\n\n const mode = DEFAULT_DIR_MODE & ~(this.umask & 0o777);\n this.createInode(current, INODE_TYPE.DIRECTORY, mode, 0);\n if (!firstCreated) firstCreated = current;\n }\n\n this.commitPending();\n const result = firstCreated ? encoder.encode(firstCreated) : undefined;\n return { status: 0, data: result ?? null };\n }\n\n // ---- RMDIR ----\n rmdir(path: string, flags: number = 0): { status: number } {\n path = this.normalizePath(path);\n const recursive = (flags & 1) !== 0;\n const idx = this.pathIndex.get(path);\n if (idx === undefined) {\n // Check for implicit directory — a dir that exists because files\n // exist under it but no explicit inode was created.\n if (this.isImplicitDirectory(path)) {\n const children = this.getDirectChildrenWithImplicit(path);\n if (children.length > 0) {\n if (!recursive) return { status: CODE_TO_STATUS.ENOTEMPTY };\n // Recursive: delete all real descendants; the implicit dir\n // disappears automatically when its children are gone.\n for (const desc of this.getAllDescendants(path)) {\n const descIdx = this.pathIndex.get(desc)!;\n const descInode = this.readInode(descIdx);\n this.freeBlockRange(descInode.firstBlock, descInode.blockCount);\n descInode.type = INODE_TYPE.FREE;\n this.writeInode(descIdx, descInode);\n this.deletePathIndex(desc);\n }\n this.pathIndexGen++;\n this.commitPending();\n }\n // Empty implicit dir or just-emptied: no-op — it vanishes on its own.\n return { status: 0 };\n }\n return { status: CODE_TO_STATUS.ENOENT };\n }\n\n const inode = this.readInode(idx);\n if (inode.type !== INODE_TYPE.DIRECTORY) return { status: CODE_TO_STATUS.ENOTDIR };\n\n // Check for children\n const children = this.getDirectChildren(path);\n\n if (children.length > 0) {\n if (!recursive) return { status: CODE_TO_STATUS.ENOTEMPTY };\n\n // Recursive delete\n for (const child of this.getAllDescendants(path)) {\n const childIdx = this.pathIndex.get(child)!;\n const childInode = this.readInode(childIdx);\n this.freeBlockRange(childInode.firstBlock, childInode.blockCount);\n childInode.type = INODE_TYPE.FREE;\n this.writeInode(childIdx, childInode);\n this.deletePathIndex(child);\n }\n }\n\n // Remove the directory itself\n inode.type = INODE_TYPE.FREE;\n this.writeInode(idx, inode);\n this.deletePathIndex(path);\n this.pathIndexGen++;\n if (idx < this.freeInodeHint) this.freeInodeHint = idx;\n\n this.commitPending();\n return { status: 0 };\n }\n\n // ---- READDIR ----\n readdir(path: string, flags: number = 0): { status: number; data: Uint8Array | null } {\n path = this.normalizePath(path);\n const resolved = this.resolvePathFull(path, true);\n\n // Determine the effective directory path for child lookup\n let effectiveDirPath: string;\n\n if (resolved) {\n const inode = this.readInode(resolved.idx);\n if (inode.type !== INODE_TYPE.DIRECTORY) return { status: CODE_TO_STATUS.ENOTDIR, data: null };\n // Use the resolved path for child lookup — when path is a symlink,\n // the actual children are stored under the target path in pathIndex.\n effectiveDirPath = resolved.resolvedPath;\n } else if (this.isImplicitDirectory(path)) {\n effectiveDirPath = path;\n } else {\n return { status: CODE_TO_STATUS.ENOENT, data: null };\n }\n\n const withFileTypes = (flags & 1) !== 0;\n // Use getDirectChildrenWithImplicit to discover both real and implicit children\n const children = this.getDirectChildrenWithImplicit(effectiveDirPath);\n\n if (withFileTypes) {\n // Encode as: count(u32) + entries[name_len(u16) + name(bytes) + type(u8)]\n let totalSize = 4;\n const entries: { name: Uint8Array; type: number }[] = [];\n\n for (const child of children) {\n const name = child.path.substring(child.path.lastIndexOf('/') + 1);\n const nameBytes = encoder.encode(name);\n let type: number;\n if (child.type === 'implicit') {\n type = INODE_TYPE.DIRECTORY;\n } else {\n const childIdx = this.pathIndex.get(child.path)!;\n const childInode = this.readInode(childIdx);\n type = childInode.type;\n }\n entries.push({ name: nameBytes, type });\n totalSize += 2 + nameBytes.byteLength + 1; // nameLen + name + type\n }\n\n const buf = new Uint8Array(totalSize);\n const view = new DataView(buf.buffer);\n view.setUint32(0, entries.length, true);\n let offset = 4;\n\n for (const entry of entries) {\n view.setUint16(offset, entry.name.byteLength, true);\n offset += 2;\n buf.set(entry.name, offset);\n offset += entry.name.byteLength;\n buf[offset++] = entry.type;\n }\n\n return { status: 0, data: buf };\n }\n\n // Simple name list: count(u32) + entries[name_len(u16) + name(bytes)]\n let totalSize = 4;\n const nameEntries: Uint8Array[] = [];\n\n for (const child of children) {\n const name = child.path.substring(child.path.lastIndexOf('/') + 1);\n const nameBytes = encoder.encode(name);\n nameEntries.push(nameBytes);\n totalSize += 2 + nameBytes.byteLength;\n }\n\n const buf = new Uint8Array(totalSize);\n const view = new DataView(buf.buffer);\n view.setUint32(0, nameEntries.length, true);\n let offset = 4;\n\n for (const nameBytes of nameEntries) {\n view.setUint16(offset, nameBytes.byteLength, true);\n offset += 2;\n buf.set(nameBytes, offset);\n offset += nameBytes.byteLength;\n }\n\n return { status: 0, data: buf };\n }\n\n // ---- RENAME ----\n rename(oldPath: string, newPath: string): { status: number } {\n oldPath = this.normalizePath(oldPath);\n newPath = this.normalizePath(newPath);\n\n const idx = this.pathIndex.get(oldPath);\n if (idx === undefined) return { status: CODE_TO_STATUS.ENOENT };\n\n // Same path → no-op (matches Node.js semantics)\n if (oldPath === newPath) return { status: 0 };\n\n // Ensure parent of new path exists\n const parentStatus = this.ensureParent(newPath);\n if (parentStatus !== 0) return { status: parentStatus };\n\n // If target exists, remove it. For directory targets we MUST recursively\n // free every descendant inode and drop every descendant pathIndex entry —\n // otherwise the source's children get added on top, leaving a mix of\n // source children + leftover target children pointing at zombie inodes\n // (the target's old children still appear in pathIndex, while their\n // inodes are not freed so blocks are leaked too).\n //\n // Concrete consequence of the old behavior: Vite's deps optimization\n // commit (`.vite/deps_temp_<hash>` → `.vite/deps`) on the second run\n // returned success but produced a corrupt deps directory — subsequent\n // requests for `vue.js`, `@unhead/vue`, etc. resolved to stale chunks\n // from the previous round (or 404'd entirely).\n //\n // The target may also be an *implicit* directory (no inode of its own,\n // but children exist under it — the state produced by bulk OPFS import).\n // In that case there's no inode to free, but the descendants must still\n // be cleaned up for the same reason.\n const existingIdx = this.pathIndex.get(newPath);\n const targetIsImplicitDir =\n existingIdx === undefined && this.isImplicitDirectory(newPath);\n\n if (existingIdx !== undefined || targetIsImplicitDir) {\n let cleanDescendants = targetIsImplicitDir;\n\n if (existingIdx !== undefined) {\n const existingInode = this.readInode(existingIdx);\n cleanDescendants = existingInode.type === INODE_TYPE.DIRECTORY;\n this.freeBlockRange(existingInode.firstBlock, existingInode.blockCount);\n existingInode.type = INODE_TYPE.FREE;\n this.writeInode(existingIdx, existingInode);\n this.deletePathIndex(newPath);\n if (existingIdx < this.freeInodeHint) this.freeInodeHint = existingIdx;\n }\n\n if (cleanDescendants) {\n // Free every descendant inode and remove its pathIndex entry.\n // Use getAllDescendants for the deepest-first ordering (matches\n // rmdir's recursive path) — though for a flat free pass order\n // doesn't affect correctness here.\n for (const desc of this.getAllDescendants(newPath)) {\n const descIdx = this.pathIndex.get(desc)!;\n const descInode = this.readInode(descIdx);\n this.freeBlockRange(descInode.firstBlock, descInode.blockCount);\n descInode.type = INODE_TYPE.FREE;\n this.writeInode(descIdx, descInode);\n this.deletePathIndex(desc);\n if (descIdx < this.freeInodeHint) this.freeInodeHint = descIdx;\n }\n }\n }\n\n // Update inode with new path\n const inode = this.readInode(idx);\n const { offset: pathOff, length: pathLen } = this.appendPath(newPath);\n inode.pathOffset = pathOff;\n inode.pathLength = pathLen;\n inode.mtime = Date.now();\n this.writeInode(idx, inode);\n\n // Update index\n this.deletePathIndex(oldPath);\n this.setPathIndex(newPath, idx);\n this.pathIndexGen++;\n\n // If it's a directory, rename all descendants\n if (inode.type === INODE_TYPE.DIRECTORY) {\n const prefix = oldPath === '/' ? '/' : oldPath + '/';\n const toRename: [string, number][] = [];\n\n for (const [p, i] of this.pathIndex) {\n if (p.startsWith(prefix)) {\n toRename.push([p, i]);\n }\n }\n\n for (const [p, i] of toRename) {\n const suffix = p.substring(oldPath.length);\n const childNewPath = newPath + suffix;\n const childInode = this.readInode(i);\n const { offset: cpo, length: cpl } = this.appendPath(childNewPath);\n childInode.pathOffset = cpo;\n childInode.pathLength = cpl;\n this.writeInode(i, childInode);\n this.deletePathIndex(p);\n this.setPathIndex(childNewPath, i);\n }\n }\n\n this.commitPending();\n return { status: 0 };\n }\n\n // ---- EXISTS ----\n exists(path: string): { status: number; data: Uint8Array | null } {\n path = this.normalizePath(path);\n const idx = this.resolvePathComponents(path, true);\n const buf = new Uint8Array(1);\n buf[0] = (idx !== undefined || this.isImplicitDirectory(path)) ? 1 : 0;\n return { status: 0, data: buf };\n }\n\n // ---- TRUNCATE ----\n truncate(path: string, len: number = 0): { status: number } {\n path = this.normalizePath(path);\n const idx = this.resolvePathComponents(path, true);\n if (idx === undefined) return { status: CODE_TO_STATUS.ENOENT };\n\n const inode = this.readInode(idx);\n if (inode.type === INODE_TYPE.DIRECTORY) return { status: CODE_TO_STATUS.EISDIR };\n\n if (len === 0) {\n // Free all blocks\n this.freeBlockRange(inode.firstBlock, inode.blockCount);\n inode.firstBlock = 0;\n inode.blockCount = 0;\n inode.size = 0;\n } else if (len < inode.size) {\n // Shrink\n const neededBlocks = Math.ceil(len / this.blockSize);\n if (neededBlocks < inode.blockCount) {\n this.freeBlockRange(inode.firstBlock + neededBlocks, inode.blockCount - neededBlocks);\n }\n inode.blockCount = neededBlocks;\n inode.size = len;\n } else if (len > inode.size) {\n // Grow with POSIX zero-fill semantics. Old code staged the entire\n // new file as a single `new Uint8Array(len)` — OOMs for large\n // truncates and allocates way more than necessary. Instead, copy\n // old contents in bounded chunks and zero-fill the extension\n // directly on disk.\n const neededBlocks = Math.ceil(len / this.blockSize);\n if (neededBlocks > inode.blockCount) {\n // Allocate-then-copy-then-free so the old range is guaranteed\n // not to overlap the new one. See `fwrite` for the same pattern.\n const newFirst = this.allocateBlocks(neededBlocks);\n const newBase = this.dataOffset + newFirst * this.blockSize;\n if (inode.size > 0) {\n const oldBase = this.dataOffset + inode.firstBlock * this.blockSize;\n const CHUNK = 4 * 1024 * 1024; // 4 MB\n const scratch = new Uint8Array(Math.min(CHUNK, inode.size));\n let copied = 0;\n while (copied < inode.size) {\n const n = Math.min(CHUNK, inode.size - copied);\n const slice = n < scratch.length ? scratch.subarray(0, n) : scratch;\n this.handle.read(slice, { at: oldBase + copied });\n this.handle.write(slice, { at: newBase + copied });\n copied += n;\n }\n }\n this.freeBlockRange(inode.firstBlock, inode.blockCount);\n this.zeroFileRange(newBase + inode.size, len - inode.size);\n inode.firstBlock = newFirst;\n } else {\n // Same block count, just growing `size`. The tail of the last\n // existing block still contains whatever stale data was there\n // before — zero it so the extended region reads as zeros.\n this.zeroFileRange(\n this.dataOffset + inode.firstBlock * this.blockSize + inode.size,\n len - inode.size,\n );\n }\n inode.blockCount = neededBlocks;\n inode.size = len;\n }\n\n inode.mtime = Date.now();\n this.writeInode(idx, inode);\n\n this.commitPending();\n return { status: 0 };\n }\n\n // ---- COPY ----\n copy(srcPath: string, destPath: string, flags: number = 0): { status: number } {\n srcPath = this.normalizePath(srcPath);\n destPath = this.normalizePath(destPath);\n\n const srcIdx = this.resolvePathComponents(srcPath, true);\n if (srcIdx === undefined) return { status: CODE_TO_STATUS.ENOENT };\n\n const srcInode = this.readInode(srcIdx);\n if (srcInode.type === INODE_TYPE.DIRECTORY) return { status: CODE_TO_STATUS.EISDIR };\n\n // COPYFILE_EXCL check\n if ((flags & 1) && (this.pathIndex.has(destPath) || this.isImplicitDirectory(destPath))) {\n return { status: CODE_TO_STATUS.EEXIST };\n }\n\n // Self-copy — no-op.\n if (srcPath === destPath) return { status: 0 };\n\n const srcSize = srcInode.size;\n const srcFirstBlock = srcInode.firstBlock;\n\n // Stage 1: create the destination as an empty file. This goes through\n // the normal `write` path which handles parent-directory creation,\n // freeing any pre-existing blocks at `destPath`, and registering the\n // inode in `pathIndex`. Doing this first also means any side effects\n // (e.g. a `growPathTable` shift of the data region) happen BEFORE we\n // start allocating destination blocks, so the relative block indices\n // we capture below stay valid.\n const emptyStatus = this.write(destPath, new Uint8Array(0));\n if (emptyStatus.status !== 0) return emptyStatus;\n\n if (srcSize === 0) return { status: 0 };\n\n // Stage 2: allocate a destination block run sized to the source, then\n // copy the bytes directly between block ranges via the file handle in\n // bounded chunks. No full-file buffer is ever allocated — peak scratch\n // stays at 4 MB regardless of how big the source file is.\n const destIdx = this.resolvePathComponents(destPath, true);\n if (destIdx === undefined) return { status: CODE_TO_STATUS.EIO };\n const destInode = this.readInode(destIdx);\n\n const neededBlocks = Math.ceil(srcSize / this.blockSize);\n const newFirst = this.allocateBlocks(neededBlocks);\n const newBase = this.dataOffset + newFirst * this.blockSize;\n const srcBase = this.dataOffset + srcFirstBlock * this.blockSize;\n\n const CHUNK = 4 * 1024 * 1024; // 4 MB\n const scratch = new Uint8Array(Math.min(CHUNK, srcSize));\n let copied = 0;\n while (copied < srcSize) {\n const n = Math.min(CHUNK, srcSize - copied);\n const slice = n < scratch.length ? scratch.subarray(0, n) : scratch;\n this.handle.read(slice, { at: srcBase + copied });\n this.handle.write(slice, { at: newBase + copied });\n copied += n;\n }\n\n destInode.firstBlock = newFirst;\n destInode.blockCount = neededBlocks;\n destInode.size = srcSize;\n destInode.mtime = Date.now();\n this.writeInode(destIdx, destInode);\n this.commitPending();\n return { status: 0 };\n }\n\n // ---- ACCESS ----\n access(path: string, mode: number = 0): { status: number } {\n path = this.normalizePath(path);\n const idx = this.resolvePathComponents(path, true);\n if (idx === undefined) {\n // Check for implicit directory\n if (this.isImplicitDirectory(path)) return { status: 0 };\n return { status: CODE_TO_STATUS.ENOENT };\n }\n\n if (mode === 0) return { status: 0 }; // F_OK — just check existence\n\n if (!this.strictPermissions) return { status: 0 }; // Relaxed mode\n\n const inode = this.readInode(idx);\n // Check permission bits against process identity\n const filePerm = this.getEffectivePermission(inode);\n\n if ((mode & 4) && !(filePerm & 4)) return { status: CODE_TO_STATUS.EACCES }; // R_OK\n if ((mode & 2) && !(filePerm & 2)) return { status: CODE_TO_STATUS.EACCES }; // W_OK\n if ((mode & 1) && !(filePerm & 1)) return { status: CODE_TO_STATUS.EACCES }; // X_OK\n\n return { status: 0 };\n }\n\n private getEffectivePermission(inode: Inode): number {\n const modeBits = inode.mode & 0o777;\n if (this.processUid === inode.uid) return (modeBits >>> 6) & 7;\n if (this.processGid === inode.gid) return (modeBits >>> 3) & 7;\n return modeBits & 7;\n }\n\n // ---- REALPATH ----\n realpath(path: string): { status: number; data: Uint8Array | null } {\n path = this.normalizePath(path);\n const idx = this.resolvePathComponents(path, true);\n if (idx === undefined) {\n // Check for implicit directory\n if (this.isImplicitDirectory(path)) {\n return { status: 0, data: encoder.encode(path) };\n }\n return { status: CODE_TO_STATUS.ENOENT, data: null };\n }\n\n // Find the resolved path for this inode\n const inode = this.readInode(idx);\n const resolvedPath = this.readPath(inode.pathOffset, inode.pathLength);\n return { status: 0, data: encoder.encode(resolvedPath) };\n }\n\n // ---- CHMOD ----\n chmod(path: string, mode: number): { status: number } {\n path = this.normalizePath(path);\n const idx = this.resolvePathComponents(path, true);\n if (idx === undefined) return { status: CODE_TO_STATUS.ENOENT };\n\n const inode = this.readInode(idx);\n // Preserve file type bits, update permission bits\n inode.mode = (inode.mode & S_IFMT) | (mode & 0o7777);\n inode.ctime = Date.now();\n this.writeInode(idx, inode);\n\n return { status: 0 };\n }\n\n // ---- CHOWN ----\n chown(path: string, uid: number, gid: number): { status: number } {\n path = this.normalizePath(path);\n const idx = this.resolvePathComponents(path, true);\n if (idx === undefined) return { status: CODE_TO_STATUS.ENOENT };\n\n const inode = this.readInode(idx);\n inode.uid = uid;\n inode.gid = gid;\n inode.ctime = Date.now();\n this.writeInode(idx, inode);\n\n return { status: 0 };\n }\n\n // ---- UTIMES ----\n utimes(path: string, atime: number, mtime: number): { status: number } {\n path = this.normalizePath(path);\n const idx = this.resolvePathComponents(path, true);\n if (idx === undefined) return { status: CODE_TO_STATUS.ENOENT };\n\n const inode = this.readInode(idx);\n inode.atime = atime;\n inode.mtime = mtime;\n inode.ctime = Date.now();\n this.writeInode(idx, inode);\n\n return { status: 0 };\n }\n\n // ---- SYMLINK ----\n symlink(target: string, linkPath: string): { status: number } {\n linkPath = this.normalizePath(linkPath);\n if (this.pathIndex.has(linkPath) || this.isImplicitDirectory(linkPath)) {\n return { status: CODE_TO_STATUS.EEXIST };\n }\n\n const parentStatus = this.ensureParent(linkPath);\n if (parentStatus !== 0) return { status: parentStatus };\n\n const targetBytes = encoder.encode(target);\n this.createInode(linkPath, INODE_TYPE.SYMLINK, DEFAULT_SYMLINK_MODE, targetBytes.byteLength, targetBytes);\n\n this.commitPending();\n return { status: 0 };\n }\n\n // ---- READLINK ----\n readlink(path: string): { status: number; data: Uint8Array | null } {\n path = this.normalizePath(path);\n const idx = this.pathIndex.get(path);\n if (idx === undefined) return { status: CODE_TO_STATUS.ENOENT, data: null };\n\n const inode = this.readInode(idx);\n if (inode.type !== INODE_TYPE.SYMLINK) return { status: CODE_TO_STATUS.EINVAL, data: null };\n\n const target = this.readData(inode.firstBlock, inode.blockCount, inode.size);\n return { status: 0, data: target };\n }\n\n // ---- LINK (hard link — copies the file data, tracks nlink) ----\n link(existingPath: string, newPath: string): { status: number } {\n existingPath = this.normalizePath(existingPath);\n newPath = this.normalizePath(newPath);\n\n const srcIdx = this.resolvePathComponents(existingPath, true);\n if (srcIdx === undefined) return { status: CODE_TO_STATUS.ENOENT };\n\n const srcInode = this.readInode(srcIdx);\n if (srcInode.type === INODE_TYPE.DIRECTORY) return { status: CODE_TO_STATUS.EPERM };\n\n if (this.pathIndex.has(newPath) || this.isImplicitDirectory(newPath)) {\n return { status: CODE_TO_STATUS.EEXIST };\n }\n\n // Copy file data to new inode\n const result = this.copy(existingPath, newPath);\n if (result.status !== 0) return result;\n\n // Increment nlink on source\n srcInode.nlink++;\n this.writeInode(srcIdx, srcInode);\n\n // Set nlink on destination to match source\n const destIdx = this.pathIndex.get(newPath);\n if (destIdx !== undefined) {\n const destInode = this.readInode(destIdx);\n destInode.nlink = srcInode.nlink;\n this.writeInode(destIdx, destInode);\n }\n\n return { status: 0 };\n }\n\n // ---- OPEN (file descriptor) ----\n open(path: string, flags: number, tabId: string): { status: number; data: Uint8Array | null } {\n path = this.normalizePath(path);\n\n const hasCreate = (flags & 64) !== 0; // O_CREAT\n const hasTrunc = (flags & 512) !== 0; // O_TRUNC\n const hasExcl = (flags & 128) !== 0; // O_EXCL\n\n let idx = this.resolvePathComponents(path, true);\n\n if (idx === undefined) {\n if (!hasCreate) return { status: CODE_TO_STATUS.ENOENT, data: null };\n // Create file\n const mode = DEFAULT_FILE_MODE & ~(this.umask & 0o777);\n idx = this.createInode(path, INODE_TYPE.FILE, mode, 0);\n } else if (hasExcl && hasCreate) {\n return { status: CODE_TO_STATUS.EEXIST, data: null };\n }\n\n if (hasTrunc) {\n this.truncate(path, 0);\n }\n\n const fd = this.nextFd++;\n this.fdTable.set(fd, { tabId, inodeIdx: idx, position: 0, flags });\n\n const buf = new Uint8Array(4);\n new DataView(buf.buffer).setUint32(0, fd, true);\n return { status: 0, data: buf };\n }\n\n // ---- CLOSE ----\n close(fd: number): { status: number } {\n if (!this.fdTable.has(fd)) return { status: CODE_TO_STATUS.EBADF };\n this.fdTable.delete(fd);\n return { status: 0 };\n }\n\n // ---- FREAD ----\n fread(fd: number, length: number, position: number | null): { status: number; data: Uint8Array | null } {\n const entry = this.fdTable.get(fd);\n if (!entry) return { status: CODE_TO_STATUS.EBADF, data: null };\n\n const inode = this.readInode(entry.inodeIdx);\n const pos = position ?? entry.position;\n const readLen = Math.min(length, inode.size - pos);\n\n if (readLen <= 0) return { status: 0, data: new Uint8Array(0) };\n\n // Read from specific offset within the file's data blocks\n const dataOffset = this.dataOffset + inode.firstBlock * this.blockSize + pos;\n const buf = new Uint8Array(readLen);\n this.handle.read(buf, { at: dataOffset });\n\n // Update position\n if (position === null) {\n entry.position += readLen;\n }\n\n return { status: 0, data: buf };\n }\n\n // ---- FWRITE ----\n fwrite(fd: number, data: Uint8Array, position: number | null): { status: number; data: Uint8Array | null } {\n const entry = this.fdTable.get(fd);\n if (!entry) return { status: CODE_TO_STATUS.EBADF, data: null };\n\n const inode = this.readInode(entry.inodeIdx);\n const isAppend = (entry.flags & 1024) !== 0; // O_APPEND\n const pos = isAppend ? inode.size : (position ?? entry.position);\n const endPos = pos + data.byteLength;\n\n // Check if we need to grow\n if (endPos > inode.size) {\n const neededBlocks = Math.ceil(endPos / this.blockSize);\n if (neededBlocks > inode.blockCount) {\n // Grow by relocating to a larger block run. We used to stage the\n // entire new file contents in a single `new Uint8Array(endPos)`\n // and then call `writeData` once — that blew up with\n // \"Array buffer allocation failed\" on multi-hundred-MB writes\n // because Chrome refuses contiguous allocations near ~2 GB even\n // with plenty of OS RAM. Instead, allocate new blocks, copy the\n // old contents forward in chunks via the underlying file handle\n // (which is O(N) bytes but with a bounded scratch buffer), then\n // free the old blocks and write just the caller's `data` at its\n // offset inside the new region.\n const newFirst = this.allocateBlocks(neededBlocks);\n const newBase = this.dataOffset + newFirst * this.blockSize;\n const oldBase = this.dataOffset + inode.firstBlock * this.blockSize;\n // Copy oldData from old block run to new block run in chunks.\n if (inode.size > 0) {\n const CHUNK = 4 * 1024 * 1024; // 4 MB\n const scratch = new Uint8Array(Math.min(CHUNK, inode.size));\n let copied = 0;\n while (copied < inode.size) {\n const n = Math.min(CHUNK, inode.size - copied);\n const slice = n < scratch.length ? scratch.subarray(0, n) : scratch;\n this.handle.read(slice, { at: oldBase + copied });\n this.handle.write(slice, { at: newBase + copied });\n copied += n;\n }\n }\n this.freeBlockRange(inode.firstBlock, inode.blockCount);\n // POSIX \"hole\" — if the caller is writing past the current EOF\n // with a gap in between, those bytes must read back as zeros\n // rather than whatever stale data lives in the freshly allocated\n // blocks. `allocateBlocks` only flips bitmap bits, it never\n // zeroes the underlying storage.\n if (pos > inode.size) {\n this.zeroFileRange(newBase + inode.size, pos - inode.size);\n }\n // Write the caller's new data at its offset inside the new region.\n this.handle.write(data, { at: newBase + pos });\n inode.firstBlock = newFirst;\n inode.blockCount = neededBlocks;\n } else {\n // Fits within existing blocks. Same hole semantics as above —\n // stale bytes in the tail of the last allocated block (past the\n // old file size) must be zeroed before the caller's write lands.\n if (pos > inode.size) {\n this.zeroFileRange(\n this.dataOffset + inode.firstBlock * this.blockSize + inode.size,\n pos - inode.size,\n );\n }\n const dataOffset = this.dataOffset + inode.firstBlock * this.blockSize + pos;\n this.handle.write(data, { at: dataOffset });\n }\n inode.size = endPos;\n } else {\n // Write within existing bounds\n const dataOffset = this.dataOffset + inode.firstBlock * this.blockSize + pos;\n this.handle.write(data, { at: dataOffset });\n }\n\n inode.mtime = Date.now();\n this.writeInode(entry.inodeIdx, inode);\n\n // Update position\n if (position === null) {\n entry.position = endPos;\n }\n\n this.commitPending();\n const buf = new Uint8Array(4);\n new DataView(buf.buffer).setUint32(0, data.byteLength, true);\n return { status: 0, data: buf };\n }\n\n // ---- FSTAT ----\n fstat(fd: number): { status: number; data: Uint8Array | null } {\n const entry = this.fdTable.get(fd);\n if (!entry) return { status: CODE_TO_STATUS.EBADF, data: null };\n if (entry.implicitPath) return this.encodeImplicitDirStatResponse(entry.implicitPath);\n return this.encodeStatResponse(entry.inodeIdx);\n }\n\n // ---- FTRUNCATE ----\n ftruncate(fd: number, len: number = 0): { status: number } {\n const entry = this.fdTable.get(fd);\n if (!entry) return { status: CODE_TO_STATUS.EBADF };\n\n const inode = this.readInode(entry.inodeIdx);\n const path = this.readPath(inode.pathOffset, inode.pathLength);\n return this.truncate(path, len);\n }\n\n // ---- FSYNC ----\n fsync(): { status: number } {\n this.commitPending();\n this.handle.flush();\n return { status: 0 };\n }\n\n // ---- FCHMOD ----\n // fd-based chmod: look up the inode directly from the fd table and mutate\n // its mode bits. Native Node does the same thing at the libuv layer.\n fchmod(fd: number, mode: number): { status: number } {\n const entry = this.fdTable.get(fd);\n if (!entry) return { status: CODE_TO_STATUS.EBADF };\n if (entry.implicitPath) return { status: 0 }; // no-op for implicit dirs\n const inode = this.readInode(entry.inodeIdx);\n inode.mode = (inode.mode & S_IFMT) | (mode & 0o7777);\n inode.ctime = Date.now();\n this.writeInode(entry.inodeIdx, inode);\n return { status: 0 };\n }\n\n // ---- FCHOWN ----\n fchown(fd: number, uid: number, gid: number): { status: number } {\n const entry = this.fdTable.get(fd);\n if (!entry) return { status: CODE_TO_STATUS.EBADF };\n if (entry.implicitPath) return { status: 0 }; // no-op for implicit dirs\n const inode = this.readInode(entry.inodeIdx);\n inode.uid = uid;\n inode.gid = gid;\n inode.ctime = Date.now();\n this.writeInode(entry.inodeIdx, inode);\n return { status: 0 };\n }\n\n // ---- FUTIMES ----\n futimes(fd: number, atime: number, mtime: number): { status: number } {\n const entry = this.fdTable.get(fd);\n if (!entry) return { status: CODE_TO_STATUS.EBADF };\n if (entry.implicitPath) return { status: 0 }; // no-op for implicit dirs\n const inode = this.readInode(entry.inodeIdx);\n inode.atime = atime;\n inode.mtime = mtime;\n inode.ctime = Date.now();\n this.writeInode(entry.inodeIdx, inode);\n return { status: 0 };\n }\n\n // ---- OPENDIR ----\n opendir(path: string, tabId: string): { status: number; data: Uint8Array | null } {\n path = this.normalizePath(path);\n const idx = this.resolvePathComponents(path, true);\n if (idx === undefined) {\n // Check for implicit directory\n if (this.isImplicitDirectory(path)) {\n // Create fd with synthetic inode index -1 and the path stored so\n // fd-based operations (fstat, fchmod, etc.) can handle it.\n const fd = this.nextFd++;\n this.fdTable.set(fd, { tabId, inodeIdx: -1, position: 0, flags: 0, implicitPath: path });\n const buf = new Uint8Array(4);\n new DataView(buf.buffer).setUint32(0, fd, true);\n return { status: 0, data: buf };\n }\n return { status: CODE_TO_STATUS.ENOENT, data: null };\n }\n\n const inode = this.readInode(idx);\n if (inode.type !== INODE_TYPE.DIRECTORY) return { status: CODE_TO_STATUS.ENOTDIR, data: null };\n\n // Use fd table for dir handles too\n const fd = this.nextFd++;\n this.fdTable.set(fd, { tabId, inodeIdx: idx, position: 0, flags: 0 });\n\n const buf = new Uint8Array(4);\n new DataView(buf.buffer).setUint32(0, fd, true);\n return { status: 0, data: buf };\n }\n\n // ---- MKDTEMP ----\n mkdtemp(prefix: string): { status: number; data: Uint8Array | null } {\n const suffix = Math.random().toString(36).substring(2, 8);\n const path = this.normalizePath(prefix + suffix);\n\n // Ensure parent directories exist\n const parentStatus = this.ensureParent(path);\n if (parentStatus !== 0) {\n // Auto-create parent directories for mkdtemp\n const parentPath = path.substring(0, path.lastIndexOf('/'));\n if (parentPath) {\n this.mkdirRecursive(parentPath);\n }\n }\n\n const mode = DEFAULT_DIR_MODE & ~(this.umask & 0o777);\n this.createInode(path, INODE_TYPE.DIRECTORY, mode, 0);\n\n this.commitPending();\n return { status: 0, data: encoder.encode(path) };\n }\n\n // ========== Helpers ==========\n\n private getDirectChildren(dirPath: string): string[] {\n const prefix = dirPath === '/' ? '/' : dirPath + '/';\n const children: string[] = [];\n\n for (const path of this.pathIndex.keys()) {\n if (path === dirPath) continue;\n if (!path.startsWith(prefix)) continue;\n // Direct child: no more slashes after prefix\n const rest = path.substring(prefix.length);\n if (!rest.includes('/')) {\n children.push(path);\n }\n }\n\n return children.sort();\n }\n\n /**\n * Rebuild the set of all implicit directory paths.\n * An implicit directory is any ancestor path of a file/symlink in pathIndex\n * that doesn't itself have an explicit inode entry.\n * Only rebuilt when pathIndex has changed (tracked via generation counter).\n */\n private rebuildImplicitDirs(): void {\n if (this.implicitDirsGen === this.pathIndexGen) return;\n\n const now = Date.now();\n const prev = this.implicitDirs;\n this.implicitDirs = new Map<string, number>();\n for (const filePath of this.pathIndex.keys()) {\n // Walk up from each path, adding all ancestor dirs that aren't explicit\n let pos = filePath.length;\n while (true) {\n pos = filePath.lastIndexOf('/', pos - 1);\n if (pos <= 0) break; // reached root\n const ancestor = filePath.substring(0, pos);\n if (this.implicitDirs.has(ancestor)) break; // already tracked all ancestors from here up\n if (!this.pathIndex.has(ancestor)) {\n // Preserve timestamp if this implicit dir was already known,\n // otherwise stamp it with \"now\" so stat() stays stable.\n this.implicitDirs.set(ancestor, prev.get(ancestor) ?? now);\n }\n }\n }\n\n this.implicitDirsGen = this.pathIndexGen;\n }\n\n /**\n * Check if a path is an implicit directory (exists because files exist under it,\n * but no explicit directory inode was created for it).\n *\n * O(1) via the incrementally maintained `descCount` map (an implicit dir\n * is exactly !pathIndex.has(P) && descCount[P] > 0). If `pathIndex` was\n * mutated directly without going through the helpers (test scaffolding),\n * descCount is stale and we rebuild it from scratch — once — to resync.\n */\n private isImplicitDirectory(path: string): boolean {\n if (path === '/') return false; // root always has an explicit inode\n if (this.pathIndex.has(path)) return false;\n if (this.descCountGen < this.pathIndexGen) this.rebuildDescCount();\n return (this.descCount.get(path) ?? 0) > 0;\n }\n\n /**\n * Recompute `descCount` from scratch by walking every pathIndex entry's\n * ancestor chain. O(N×depth). Only triggered when something bypassed the\n * setPathIndex/deletePathIndex helpers — in production code that's\n * never; the tests exercise this path.\n */\n private rebuildDescCount(): void {\n this.descCount.clear();\n for (const path of this.pathIndex.keys()) {\n this.bumpDescCount(path);\n }\n this.descCountGen = this.pathIndexGen;\n }\n\n // ---- pathIndex helpers — keep `descCount` in sync ----\n // Every pathIndex.set/delete in the engine MUST go through these so the\n // `descCount` map (used by `isImplicitDirectory`) stays correct. We\n // anticipate the caller's `pathIndexGen++` by setting `descCountGen` to\n // `pathIndexGen + 1`; idempotent across multiple helper calls within a\n // single logical op (e.g. rmdir doing N deletes then one bump). Test\n // code that mutates `pathIndex` directly leaves descCountGen behind,\n // which is what triggers the rebuild path in `isImplicitDirectory`.\n\n private setPathIndex(path: string, idx: number): void {\n const had = this.pathIndex.has(path);\n this.pathIndex.set(path, idx);\n if (!had) this.bumpDescCount(path);\n this.descCountGen = this.pathIndexGen + 1;\n }\n\n private deletePathIndex(path: string): boolean {\n const had = this.pathIndex.delete(path);\n if (had) this.decDescCount(path);\n this.descCountGen = this.pathIndexGen + 1;\n return had;\n }\n\n private bumpDescCount(path: string): void {\n let pos = path.length;\n while (true) {\n pos = path.lastIndexOf('/', pos - 1);\n if (pos <= 0) break; // reached root, which has no descCount entry\n const ancestor = path.substring(0, pos);\n this.descCount.set(ancestor, (this.descCount.get(ancestor) ?? 0) + 1);\n }\n }\n\n private decDescCount(path: string): void {\n let pos = path.length;\n while (true) {\n pos = path.lastIndexOf('/', pos - 1);\n if (pos <= 0) break;\n const ancestor = path.substring(0, pos);\n const cur = this.descCount.get(ancestor);\n if (cur === undefined) break;\n if (cur <= 1) this.descCount.delete(ancestor);\n else this.descCount.set(ancestor, cur - 1);\n }\n }\n\n /**\n * Get direct children of a directory path, including implicit subdirectories.\n * Returns unique child full paths. Each entry is tagged with whether it's a\n * real inode or an implicit directory.\n */\n private getDirectChildrenWithImplicit(dirPath: string): { path: string; type: 'real' | 'implicit' }[] {\n const prefix = dirPath === '/' ? '/' : dirPath + '/';\n const childNames = new Map<string, 'real' | 'implicit'>();\n\n for (const path of this.pathIndex.keys()) {\n if (path === dirPath) continue;\n if (!path.startsWith(prefix)) continue;\n const rest = path.substring(prefix.length);\n const slashPos = rest.indexOf('/');\n if (slashPos === -1) {\n // Direct child file/dir — it's a real inode\n childNames.set(rest, 'real');\n } else {\n // Deeper descendant — the first segment is an implicit subdirectory\n const childName = rest.substring(0, slashPos);\n if (!childNames.has(childName)) {\n // Only mark as implicit if there's no real inode for it\n const childFullPath = prefix + childName;\n childNames.set(childName, this.pathIndex.has(childFullPath) ? 'real' : 'implicit');\n }\n }\n }\n\n const result: { path: string; type: 'real' | 'implicit' }[] = [];\n for (const [name, type] of childNames) {\n result.push({ path: prefix + name, type });\n }\n result.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);\n return result;\n }\n\n /**\n * Encode a synthetic stat response for an implicit directory.\n * Returns directory stats with default mode, zero size, current timestamps.\n */\n private encodeImplicitDirStatResponse(path: string): { status: number; data: Uint8Array } {\n // Use the stable timestamp assigned when this implicit dir was first\n // discovered, so repeated stat() calls return the same mtime/ctime/atime.\n this.rebuildImplicitDirs();\n const ts = this.implicitDirs.get(path) ?? Date.now();\n const mode = DEFAULT_DIR_MODE & ~(this.umask & 0o777);\n\n // Count implicit subdirectories for nlink\n const children = this.getDirectChildrenWithImplicit(path);\n let subdirCount = 0;\n for (const child of children) {\n if (child.type === 'implicit') {\n subdirCount++;\n } else {\n const childIdx = this.pathIndex.get(child.path);\n if (childIdx !== undefined) {\n const childInode = this.readInode(childIdx);\n if (childInode.type === INODE_TYPE.DIRECTORY) subdirCount++;\n }\n }\n }\n const nlink = 2 + subdirCount;\n\n // Encode stat: type(1) + mode(4) + size(8) + mtime(8) + ctime(8) + atime(8) + uid(4) + gid(4) + ino(4) + nlink(4) = 53 bytes\n const buf = new Uint8Array(53);\n const view = new DataView(buf.buffer);\n view.setUint8(0, INODE_TYPE.DIRECTORY);\n view.setUint32(1, mode, true);\n view.setFloat64(5, 0, true); // size = 0\n view.setFloat64(13, ts, true); // mtime\n view.setFloat64(21, ts, true); // ctime\n view.setFloat64(29, ts, true); // atime\n view.setUint32(37, this.processUid, true);\n view.setUint32(41, this.processGid, true);\n view.setUint32(45, 0, true); // ino = 0 (synthetic)\n view.setUint32(49, nlink, true);\n\n return { status: 0, data: buf };\n }\n\n private getAllDescendants(dirPath: string): string[] {\n const prefix = dirPath === '/' ? '/' : dirPath + '/';\n const descendants: string[] = [];\n\n for (const path of this.pathIndex.keys()) {\n if (path.startsWith(prefix)) descendants.push(path);\n }\n\n // Sort by depth (deepest first) for safe deletion\n return descendants.sort((a, b) => {\n const da = a.split('/').length;\n const db = b.split('/').length;\n return db - da;\n });\n }\n\n private ensureParent(path: string): number {\n const lastSlash = path.lastIndexOf('/');\n if (lastSlash <= 0) return 0; // Parent is root, always exists\n\n const parentPath = path.substring(0, lastSlash);\n const parentIdx = this.pathIndex.get(parentPath);\n if (parentIdx === undefined) {\n // Check for implicit directory\n if (this.isImplicitDirectory(parentPath)) return 0;\n return CODE_TO_STATUS.ENOENT;\n }\n\n const parentInode = this.readInode(parentIdx);\n if (parentInode.type !== INODE_TYPE.DIRECTORY) return CODE_TO_STATUS.ENOTDIR;\n\n return 0;\n }\n\n /** Clean up all fds owned by a tab */\n cleanupTab(tabId: string): void {\n for (const [fd, entry] of this.fdTable) {\n if (entry.tabId === tabId) {\n this.fdTable.delete(fd);\n }\n }\n }\n\n /** Get all file paths and their data for OPFS sync */\n getAllFiles(): { path: string; idx: number }[] {\n const files: { path: string; idx: number }[] = [];\n for (const [path, idx] of this.pathIndex) {\n files.push({ path, idx });\n }\n return files;\n }\n\n /** Get file path for a file descriptor (used by OPFS sync for FD-based ops) */\n getPathForFd(fd: number): string | null {\n const entry = this.fdTable.get(fd);\n if (!entry) return null;\n const inode = this.readInode(entry.inodeIdx);\n return this.readPath(inode.pathOffset, inode.pathLength);\n }\n\n /** Get file data by inode index */\n getInodeData(idx: number): { type: number; data: Uint8Array; mtime: number } {\n const inode = this.readInode(idx);\n const data = inode.size > 0\n ? this.readData(inode.firstBlock, inode.blockCount, inode.size)\n : new Uint8Array(0);\n return { type: inode.type, data, mtime: inode.mtime };\n }\n\n /** Export all files/dirs/symlinks from the VFS */\n exportAll(): Array<{ path: string; type: number; data: Uint8Array | null; mode: number; mtime: number }> {\n const result: Array<{ path: string; type: number; data: Uint8Array | null; mode: number; mtime: number }> = [];\n for (const [path, idx] of this.pathIndex) {\n const inode = this.readInode(idx);\n let data: Uint8Array | null = null;\n if (inode.type === INODE_TYPE.FILE || inode.type === INODE_TYPE.SYMLINK) {\n data = inode.size > 0\n ? this.readData(inode.firstBlock, inode.blockCount, inode.size)\n : new Uint8Array(0);\n }\n result.push({ path, type: inode.type, data, mode: inode.mode, mtime: inode.mtime });\n }\n // Sort directories first so parents are created before children\n result.sort((a, b) => {\n if (a.type === INODE_TYPE.DIRECTORY && b.type !== INODE_TYPE.DIRECTORY) return -1;\n if (a.type !== INODE_TYPE.DIRECTORY && b.type === INODE_TYPE.DIRECTORY) return 1;\n return a.path.localeCompare(b.path);\n });\n return result;\n }\n\n flush(): void {\n this.handle.flush();\n }\n}\n","/**\n * Repair Worker — handles VFS repair and load operations.\n *\n * Spawned by helpers.ts when the caller doesn't have sync handle access\n * (e.g. main thread). All VFS writes go through createSyncAccessHandle\n * for direct disk I/O — no MemoryHandle, no RAM bloat.\n *\n * Operations:\n * - 'repair': Scan corrupt .vfs.bin, rebuild valid entries into fresh VFS\n * - 'load': Read OPFS files, create fresh VFS from them\n *\n * Safety guarantees:\n * - Original .vfs.bin is never deleted until the replacement is verified\n * - Temp file (.vfs.bin.tmp) is verified via re-mount before swap\n * - Orphaned .vfs.bin.tmp is cleaned up on entry\n * - Repair fails fast if critical operations exceed error threshold\n */\n\nimport { VFSEngine } from '../vfs/engine.js';\nimport {\n VFS_MAGIC, VFS_VERSION, SUPERBLOCK, INODE, INODE_SIZE, INODE_TYPE,\n DEFAULT_INODE_COUNT, DEFAULT_BLOCK_SIZE, INITIAL_DATA_BLOCKS,\n INITIAL_PATH_TABLE_SIZE, calculateLayout,\n} from '../vfs/layout.js';\n\nself.onmessage = async (event: MessageEvent) => {\n try {\n const msg = event.data;\n if (msg.type === 'repair') {\n (self as any).postMessage(await handleRepair(msg.root));\n } else if (msg.type === 'load') {\n (self as any).postMessage(await handleLoad(msg.root));\n } else {\n throw new Error(`Unknown message type: ${msg.type}`);\n }\n } catch (err: any) {\n (self as any).postMessage({ error: err.message || String(err) });\n }\n};\n\n// ========== OPFS navigation (duplicated for bundle isolation) ==========\n\nasync function navigateToRoot(root: string): Promise<FileSystemDirectoryHandle> {\n let dir = await navigator.storage.getDirectory();\n if (root && root !== '/') {\n for (const seg of root.split('/').filter(Boolean)) {\n dir = await dir.getDirectoryHandle(seg, { create: true });\n }\n }\n return dir;\n}\n\ninterface OPFSEntry {\n path: string;\n type: 'file' | 'directory';\n data?: ArrayBuffer;\n}\n\nasync function readOPFSRecursive(\n dir: FileSystemDirectoryHandle,\n prefix: string,\n skip: Set<string>,\n): Promise<OPFSEntry[]> {\n const result: OPFSEntry[] = [];\n for await (const [name, handle] of (dir as any).entries()) {\n if (prefix === '' && skip.has(name)) continue;\n const fullPath = prefix ? `${prefix}/${name}` : `/${name}`;\n if (handle.kind === 'directory') {\n result.push({ path: fullPath, type: 'directory' });\n const children = await readOPFSRecursive(handle as FileSystemDirectoryHandle, fullPath, skip);\n result.push(...children);\n } else {\n const file = await (handle as FileSystemFileHandle).getFile();\n const data = await file.arrayBuffer();\n result.push({ path: fullPath, type: 'file', data });\n }\n }\n return result;\n}\n\n// ========== Cleanup orphaned temp files ==========\n\nasync function cleanupTmpFile(rootDir: FileSystemDirectoryHandle): Promise<void> {\n try { await rootDir.removeEntry('.vfs.bin.tmp'); } catch {}\n}\n\n// ========== Verify VFS via re-mount ==========\n\n/**\n * Open the file, mount it as a VFS, verify superblock + inode table,\n * then close. Throws if the VFS is corrupt.\n */\nasync function verifyVFS(fileHandle: FileSystemFileHandle): Promise<void> {\n const handle = await (fileHandle as any).createSyncAccessHandle();\n try {\n const engine = new VFSEngine();\n engine.init(handle); // calls mount() which validates superblock + rebuilds index\n } finally {\n handle.close();\n }\n}\n\n// ========== Safe file swap: copy-then-delete ==========\n\n/**\n * Safely replace .vfs.bin with .vfs.bin.tmp:\n * 1. Verify the temp file is a valid VFS (re-mount test)\n * 2. Copy temp → .vfs.bin (overwrite via truncate + chunked write)\n * 3. Only then delete .vfs.bin.tmp\n *\n * If the copy is interrupted mid-write, the original .vfs.bin.tmp\n * still exists intact for retry.\n */\nasync function swapTmpToVFS(\n rootDir: FileSystemDirectoryHandle,\n tmpFileHandle: FileSystemFileHandle,\n): Promise<void> {\n // Step 1: Verify temp file is valid before touching original\n await verifyVFS(tmpFileHandle);\n\n // Step 2: Copy tmp → .vfs.bin (overwrite)\n const vfsFileHandle = await rootDir.getFileHandle('.vfs.bin', { create: true });\n\n const srcHandle = await (tmpFileHandle as any).createSyncAccessHandle();\n const dstHandle = await (vfsFileHandle as any).createSyncAccessHandle();\n try {\n const size: number = srcHandle.getSize();\n dstHandle.truncate(size);\n const CHUNK = 1024 * 1024; // 1MB\n const buf = new Uint8Array(CHUNK);\n for (let off = 0; off < size; off += CHUNK) {\n const n: number = srcHandle.read(buf, { at: off });\n dstHandle.write(n < CHUNK ? buf.subarray(0, n) : buf, { at: off });\n }\n dstHandle.flush();\n } finally {\n dstHandle.close();\n srcHandle.close();\n }\n\n // Step 3: Only delete tmp after successful copy\n try { await rootDir.removeEntry('.vfs.bin.tmp'); } catch {}\n}\n\n// ========== Repair handler ==========\n\nasync function handleRepair(root: string) {\n const rootDir = await navigateToRoot(root);\n\n // Clean up any orphaned temp file from a previous failed repair\n await cleanupTmpFile(rootDir);\n\n // Read old .vfs.bin\n const vfsFileHandle = await rootDir.getFileHandle('.vfs.bin');\n const file = await vfsFileHandle.getFile();\n const raw = new Uint8Array(await file.arrayBuffer());\n const fileSize = raw.byteLength;\n\n if (fileSize < SUPERBLOCK.SIZE) {\n throw new Error(`VFS file too small to repair (${fileSize} bytes)`);\n }\n\n // Parse superblock\n const view = new DataView(raw.buffer);\n let inodeCount: number;\n let blockSize: number;\n let totalBlocks: number;\n let inodeTableOffset: number;\n let pathTableOffset: number;\n let dataOffset: number;\n let bitmapOffset: number;\n let pathTableSize: number;\n\n const magic = view.getUint32(SUPERBLOCK.MAGIC, true);\n const version = view.getUint32(SUPERBLOCK.VERSION, true);\n const superblockValid = magic === VFS_MAGIC && version === VFS_VERSION;\n\n if (superblockValid) {\n inodeCount = view.getUint32(SUPERBLOCK.INODE_COUNT, true);\n blockSize = view.getUint32(SUPERBLOCK.BLOCK_SIZE, true);\n totalBlocks = view.getUint32(SUPERBLOCK.TOTAL_BLOCKS, true);\n inodeTableOffset = view.getFloat64(SUPERBLOCK.INODE_OFFSET, true);\n pathTableOffset = view.getFloat64(SUPERBLOCK.PATH_OFFSET, true);\n dataOffset = view.getFloat64(SUPERBLOCK.DATA_OFFSET, true);\n bitmapOffset = view.getFloat64(SUPERBLOCK.BITMAP_OFFSET, true);\n // Use the full allocated path table size (not PATH_USED) for repair validation.\n // PATH_USED may be stale if the superblock wasn't flushed after a write —\n // paths were written to OPFS but the superblock counter wasn't updated.\n pathTableSize = bitmapOffset - pathTableOffset;\n\n if (blockSize === 0 || (blockSize & (blockSize - 1)) !== 0 || inodeCount === 0 ||\n inodeTableOffset >= fileSize || pathTableOffset >= fileSize || dataOffset >= fileSize ||\n pathTableSize <= 0) {\n const layout = calculateLayout(DEFAULT_INODE_COUNT, DEFAULT_BLOCK_SIZE, INITIAL_DATA_BLOCKS);\n inodeCount = DEFAULT_INODE_COUNT;\n blockSize = DEFAULT_BLOCK_SIZE;\n totalBlocks = INITIAL_DATA_BLOCKS;\n inodeTableOffset = layout.inodeTableOffset;\n pathTableOffset = layout.pathTableOffset;\n dataOffset = layout.dataOffset;\n bitmapOffset = layout.bitmapOffset;\n pathTableSize = bitmapOffset - pathTableOffset;\n }\n } else {\n const layout = calculateLayout(DEFAULT_INODE_COUNT, DEFAULT_BLOCK_SIZE, INITIAL_DATA_BLOCKS);\n inodeCount = DEFAULT_INODE_COUNT;\n blockSize = DEFAULT_BLOCK_SIZE;\n totalBlocks = INITIAL_DATA_BLOCKS;\n inodeTableOffset = layout.inodeTableOffset;\n pathTableOffset = layout.pathTableOffset;\n dataOffset = layout.dataOffset;\n bitmapOffset = layout.bitmapOffset;\n pathTableSize = bitmapOffset - pathTableOffset;\n }\n\n // Scan inodes for recoverable entries\n const decoder = new TextDecoder('utf-8', { fatal: true });\n const recovered: Array<{\n path: string;\n type: number;\n dataOffset: number;\n dataSize: number;\n /** true when inode was found but data blocks were out of bounds */\n contentLost: boolean;\n }> = [];\n let lost = 0;\n\n const maxInodes = Math.min(inodeCount, Math.floor((fileSize - inodeTableOffset) / INODE_SIZE));\n\n for (let i = 0; i < maxInodes; i++) {\n const off = inodeTableOffset + i * INODE_SIZE;\n if (off + INODE_SIZE > fileSize) break;\n\n const type = raw[off + INODE.TYPE];\n if (type < INODE_TYPE.FILE || type > INODE_TYPE.SYMLINK) continue;\n\n const inodeView = new DataView(raw.buffer, off, INODE_SIZE);\n const pathOff = inodeView.getUint32(INODE.PATH_OFFSET, true);\n const pathLength = inodeView.getUint16(INODE.PATH_LENGTH, true);\n const size = inodeView.getFloat64(INODE.SIZE, true);\n const firstBlock = inodeView.getUint32(INODE.FIRST_BLOCK, true);\n\n // Validate path bounds against the allocated path table region and file size.\n // Use pathTableSize (not PATH_USED from superblock) because PATH_USED may be\n // stale if the superblock wasn't flushed — the path bytes are still on disk.\n const absPathOffset = pathTableOffset + pathOff;\n if (pathLength === 0 || pathLength > 4096 ||\n absPathOffset + pathLength > fileSize ||\n pathOff + pathLength > pathTableSize) {\n lost++;\n continue;\n }\n\n // Decode path with strict UTF-8 (fatal: true rejects invalid sequences)\n let entryPath: string;\n try {\n entryPath = decoder.decode(raw.subarray(absPathOffset, absPathOffset + pathLength));\n } catch {\n lost++;\n continue;\n }\n\n if (!entryPath.startsWith('/') || entryPath.includes('\\0')) {\n lost++;\n continue;\n }\n\n if (type === INODE_TYPE.DIRECTORY) {\n recovered.push({ path: entryPath, type, dataOffset: 0, dataSize: 0, contentLost: false });\n continue;\n }\n\n if (size < 0 || size > fileSize || !isFinite(size)) {\n lost++;\n continue;\n }\n\n const blockCount = inodeView.getUint32(INODE.BLOCK_COUNT, true);\n const dataStart = dataOffset + firstBlock * blockSize;\n if (dataStart + size > fileSize || firstBlock >= totalBlocks ||\n (blockCount > 0 && firstBlock + blockCount > totalBlocks)) {\n // Inode metadata is valid but data blocks are out of bounds — content is lost\n recovered.push({ path: entryPath, type, dataOffset: 0, dataSize: 0, contentLost: true });\n lost++;\n continue;\n }\n\n recovered.push({ path: entryPath, type, dataOffset: dataStart, dataSize: size, contentLost: false });\n }\n\n // Build repaired VFS in temp file — original .vfs.bin untouched until verified\n const tmpFileHandle = await rootDir.getFileHandle('.vfs.bin.tmp', { create: true });\n const tmpHandle = await (tmpFileHandle as any).createSyncAccessHandle();\n\n let repairOk = false;\n let criticalErrors = 0;\n const MAX_CRITICAL_ERRORS = 5;\n\n try {\n const engine = new VFSEngine();\n engine.init(tmpHandle);\n\n const dirs = recovered\n .filter(e => e.type === INODE_TYPE.DIRECTORY && e.path !== '/')\n .sort((a, b) => a.path.localeCompare(b.path));\n const files = recovered.filter(e => e.type === INODE_TYPE.FILE);\n const symlinks = recovered.filter(e => e.type === INODE_TYPE.SYMLINK);\n\n // Create directories — failure here is critical (blocks child files)\n for (const dir of dirs) {\n if (engine.mkdir(dir.path, 0o040755).status !== 0) {\n criticalErrors++;\n lost++;\n if (criticalErrors >= MAX_CRITICAL_ERRORS) {\n throw new Error(`Repair aborted: too many critical errors (${criticalErrors} mkdir failures)`);\n }\n }\n }\n\n // Write files\n for (const f of files) {\n const data = f.dataSize > 0\n ? raw.subarray(f.dataOffset, f.dataOffset + f.dataSize)\n : new Uint8Array(0);\n if (engine.write(f.path, data).status !== 0) {\n lost++;\n // File write failures are less critical than mkdir — parent may be missing\n }\n }\n\n // Write symlinks — validate target before creating\n for (const sym of symlinks) {\n if (sym.dataSize === 0 && sym.contentLost) {\n // Symlink target was lost — skip, don't create a broken symlink\n lost++;\n continue;\n }\n const data = sym.dataSize > 0\n ? raw.subarray(sym.dataOffset, sym.dataOffset + sym.dataSize)\n : new Uint8Array(0);\n let target: string;\n try {\n target = decoder.decode(data);\n } catch {\n // Invalid UTF-8 in symlink target — skip\n lost++;\n continue;\n }\n if (target.length === 0 || target.includes('\\0')) {\n lost++;\n continue;\n }\n if (engine.symlink(target, sym.path).status !== 0) lost++;\n }\n\n engine.flush();\n repairOk = true;\n } finally {\n tmpHandle.close();\n if (!repairOk) {\n await cleanupTmpFile(rootDir);\n }\n }\n\n // Verify repaired VFS via re-mount, then swap into place\n // swapTmpToVFS calls verifyVFS internally — if verification fails,\n // .vfs.bin.tmp still exists and .vfs.bin is untouched\n try {\n await swapTmpToVFS(rootDir, tmpFileHandle);\n } catch (err: any) {\n // Swap failed — clean up temp file, throw descriptive error\n await cleanupTmpFile(rootDir);\n throw new Error(`Repair built a VFS but verification failed: ${err.message}`);\n }\n\n const entries = recovered\n .filter(e => e.path !== '/')\n .map(e => ({\n path: e.path,\n type: (e.type === INODE_TYPE.FILE ? 'file' : e.type === INODE_TYPE.DIRECTORY ? 'directory' : 'symlink') as 'file' | 'directory' | 'symlink',\n size: e.dataSize,\n contentLost: e.contentLost,\n }));\n\n return { recovered: entries.length, lost, entries };\n}\n\n// ========== Load handler ==========\n\nasync function handleLoad(root: string) {\n const rootDir = await navigateToRoot(root);\n\n // Clean up any orphaned temp file\n await cleanupTmpFile(rootDir);\n\n // Read all OPFS files FIRST (before touching .vfs.bin)\n const opfsEntries = await readOPFSRecursive(rootDir, '', new Set(['.vfs.bin', '.vfs.bin.tmp']));\n\n // Build fresh VFS in temp file — original .vfs.bin untouched until verified\n const tmpFileHandle = await rootDir.getFileHandle('.vfs.bin.tmp', { create: true });\n const tmpHandle = await (tmpFileHandle as any).createSyncAccessHandle();\n\n let buildOk = false;\n let files = 0;\n let directories = 0;\n\n try {\n const engine = new VFSEngine();\n engine.init(tmpHandle);\n\n const dirs = opfsEntries\n .filter(e => e.type === 'directory')\n .sort((a, b) => a.path.localeCompare(b.path));\n\n for (const dir of dirs) {\n if (engine.mkdir(dir.path, 0o040755).status === 0) {\n directories++;\n }\n }\n\n const fileEntries = opfsEntries.filter(e => e.type === 'file');\n for (const file of fileEntries) {\n if (engine.write(file.path, new Uint8Array(file.data ?? new ArrayBuffer(0))).status === 0) {\n files++;\n }\n }\n\n engine.flush();\n buildOk = true;\n } finally {\n tmpHandle.close();\n if (!buildOk) {\n await cleanupTmpFile(rootDir);\n }\n }\n\n // Verify then swap (verifyVFS + copy-then-delete)\n try {\n await swapTmpToVFS(rootDir, tmpFileHandle);\n } catch (err: any) {\n await cleanupTmpFile(rootDir);\n throw new Error(`Load built a VFS but verification failed: ${err.message}`);\n }\n\n return { files, directories };\n}\n"],"mappings":"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","names":["inode","data","children","totalSize","buf","view","offset","fd","decoder"]}