vfs: return FileHandle from fs.promises.open

Wrap mounted virtual file descriptors in the public FileHandle
interface while delegating operations to the underlying provider
handle.

Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: codex:gpt-5.6-sol
PR-URL: https://github.com/nodejs/node/pull/65730
Fixes: https://github.com/nodejs/node/issues/65729
Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
Trivikram Kamat authored and GitHub committed 2026-09-09 01:34:40 +00:00
1 parent 36f16e7eba
commit dfcfe251f8
3 files changed
+44 -3

No files matched your search

+39
View File
@@ -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,
+2 -3
View File
@@ -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');
@@ -786,8 +786,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;
+3
View File
@@ -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();