diff --git a/lib/internal/vfs/fd.js b/lib/internal/vfs/fd.js index bd36ad218f48..1d1ffaabc78d 100644 --- a/lib/internal/vfs/fd.js +++ b/lib/internal/vfs/fd.js @@ -1,6 +1,8 @@ 'use strict'; const { + FunctionPrototypeBind, + ObjectDefineProperty, SafeMap, Symbol, } = primordials; @@ -46,6 +48,42 @@ class VirtualFD { get entry() { return this[kEntry]; } + + getAsyncId() { + return this[kFd]; + } + + async close() { + await this[kEntry].close(); + closeVirtualFd(this[kFd]); + } + + closeSync() { + this[kEntry].closeSync(); + closeVirtualFd(this[kFd]); + } +} + +const vfsFileHandleMethods = [ + 'appendFile', 'chmod', 'chown', 'datasync', 'sync', 'read', 'readv', + 'readFile', 'stat', 'truncate', 'utimes', 'write', 'writev', 'writeFile', +]; +let FileHandle; + +function createVfsFileHandle(vfd) { + FileHandle ??= require('internal/fs/promises').FileHandle; + const fileHandle = new FileHandle(vfd); + const entry = vfd.entry; + for (let i = 0; i < vfsFileHandleMethods.length; i++) { + const method = vfsFileHandleMethods[i]; + ObjectDefineProperty(fileHandle, method, { + __proto__: null, + configurable: true, + value: FunctionPrototypeBind(entry[method], entry), + writable: true, + }); + } + return fileHandle; } /** @@ -81,6 +119,7 @@ function closeVirtualFd(fd) { module.exports = { VFS_FD_MASK, VirtualFD, + createVfsFileHandle, openVirtualFd, getVirtualFd, closeVirtualFd, diff --git a/lib/internal/vfs/setup.js b/lib/internal/vfs/setup.js index 979990d1a855..a8bf9712ea41 100644 --- a/lib/internal/vfs/setup.js +++ b/lib/internal/vfs/setup.js @@ -30,7 +30,7 @@ const { getLayerIdFromPath, getNormalizedVfsRoot, } = require('internal/vfs/router'); -const { getVirtualFd, closeVirtualFd } = require('internal/vfs/fd'); +const { getVirtualFd, closeVirtualFd, createVfsFileHandle } = require('internal/vfs/fd'); const { assertEncoding, setVfsHandlers } = require('internal/fs/utils'); const permission = require('internal/process/permission'); const { getOptionValue } = require('internal/options'); @@ -764,8 +764,7 @@ function createVfsHandlers() { const r = findVFSForPath(pathStr); if (r !== null) { const fd = r.vfs.openSync(r.path, flags, mode); - const vfd = getVirtualFd(fd); - return PromiseResolve(vfd.entry); + return PromiseResolve(createVfsFileHandle(getVirtualFd(fd))); } } return undefined; diff --git a/test/parallel/test-vfs-fs-promises.js b/test/parallel/test-vfs-fs-promises.js index a5761d4ca5dd..af39fdf92b42 100644 --- a/test/parallel/test-vfs-fs-promises.js +++ b/test/parallel/test-vfs-fs-promises.js @@ -86,6 +86,9 @@ const vfs = require('node:vfs'); // FileHandle via fsp.open const handle = await fsp.open(p('src/hello.txt'), 'r'); + assert.strictEqual(handle.constructor.name, 'FileHandle'); + assert.strictEqual(typeof handle.fd, 'number'); + assert.strictEqual(typeof handle.createReadStream, 'function'); assert.strictEqual(await handle.readFile('utf8'), 'hello'); await handle.close();