From 1dd48de141eb025917c2ecd700cada401dc450cd Mon Sep 17 00:00:00 2001 From: Trivikram Kamat <16024985+trivikr@users.noreply.github.com> Date: Tue, 8 Sep 2026 22:27:35 -0700 Subject: [PATCH] vfs: reject statfs for missing paths Validate mounted VFS paths before returning synthetic statfs data so fs.statfsSync() and fs.promises.statfs() report ENOENT for missing paths. Forward validation errors asynchronously to fs.statfs() callbacks. 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/65693 Fixes: https://github.com/nodejs/node/issues/65692 Reviewed-By: James M Snell Reviewed-By: Matteo Collina --- lib/fs.js | 8 +++++++- lib/internal/vfs/setup.js | 5 +++-- test/parallel/test-vfs-fs-promises.js | 5 +++++ test/parallel/test-vfs-fs-statSync.js | 17 ++++++++++++++++- 4 files changed, 31 insertions(+), 4 deletions(-) diff --git a/lib/fs.js b/lib/fs.js index ad90551f40f..10ab1cb2eca 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -2050,7 +2050,13 @@ function statfs(path, options = { __proto__: null, bigint: false }, callback) { const h = vfsState.handlers; if (h !== null) { - const result = h.statfsSync(path, options); + let result; + try { + result = h.statfsSync(path, options); + } catch (err) { + process.nextTick(callback, err); + return; + } if (result !== undefined) { process.nextTick(callback, null, result); return; diff --git a/lib/internal/vfs/setup.js b/lib/internal/vfs/setup.js index 7231d10825e..3e183e42283 100644 --- a/lib/internal/vfs/setup.js +++ b/lib/internal/vfs/setup.js @@ -320,6 +320,7 @@ function findVFSWith(filename, syscall, fn) { const r = findVFS(filename); if (r === null) return undefined; if (r.vfs.existsSync(filename)) { + if (fn === undefined) return true; return fn(r.vfs, filename); } throw createENOENT(syscall, filename); @@ -432,7 +433,7 @@ function createVfsHandlers() { }, statfsSync(path, options) { const pathStr = toPathStr(path); - if (pathStr !== null && findVFSForPath(pathStr) !== null) { + if (pathStr !== null && findVFSWith(pathStr, 'statfs')) { if (options?.bigint) { return { type: 0n, bsize: 4096n, blocks: 0n, @@ -709,7 +710,7 @@ function createVfsHandlers() { vfsOp(path, (vfs, n) => vfs.promises.lutimes(n, atime, mtime).then(() => true)), statfs(path, options) { const pathStr = toPathStr(path); - if (pathStr !== null && findVFSForPath(pathStr) !== null) { + if (pathStr !== null && findVFSWith(pathStr, 'statfs')) { if (options?.bigint) { return { __proto__: null, diff --git a/test/parallel/test-vfs-fs-promises.js b/test/parallel/test-vfs-fs-promises.js index af39fdf92b4..b720aad37cc 100644 --- a/test/parallel/test-vfs-fs-promises.js +++ b/test/parallel/test-vfs-fs-promises.js @@ -31,6 +31,11 @@ const vfs = require('node:vfs'); // statfs const sfs = await fsp.statfs(p('src/hello.txt')); assert.strictEqual(typeof sfs.bsize, 'number'); + await assert.rejects(fsp.statfs(p('missing')), { + code: 'ENOENT', + syscall: 'statfs', + path: p('missing'), + }); // Path-based writes await fsp.writeFile(p('src/pw.txt'), 'pdata'); diff --git a/test/parallel/test-vfs-fs-statSync.js b/test/parallel/test-vfs-fs-statSync.js index 5a48c4e426f..6e5d27c3059 100644 --- a/test/parallel/test-vfs-fs-statSync.js +++ b/test/parallel/test-vfs-fs-statSync.js @@ -4,7 +4,7 @@ // fs.statSync / fs.lstatSync / fs.statfsSync dispatch through the VFS layer, // including the `throwIfNoEntry: false` option. -require('../common'); +const common = require('../common'); const assert = require('assert'); const fs = require('fs'); const path = require('path'); @@ -57,4 +57,19 @@ assert.strictEqual( assert.strictEqual(typeof s.bsize, 'bigint'); } +// statfsSync on a missing path throws ENOENT +assert.throws(() => fs.statfsSync(path.join(mountPoint, 'missing')), + { + code: 'ENOENT', + syscall: 'statfs', + path: path.join(mountPoint, 'missing'), + }); + +// Statfs on a missing path reports ENOENT through the callback +fs.statfs(path.join(mountPoint, 'missing'), common.mustCall((err) => { + assert.strictEqual(err.code, 'ENOENT'); + assert.strictEqual(err.syscall, 'statfs'); + assert.strictEqual(err.path, path.join(mountPoint, 'missing')); +})); + myVfs.unmount();