node/lib/internal/vfs/router.js
Matteo Collina 569369f927
vfs: dispatch fs/promises to mounted VFS instances
Add mount/unmount lifecycle on `VirtualFileSystem`, a handler registry
that fs.js and fs/promises.js consult via `vfsState.handlers`, and a
router that maps absolute paths to the VFS that owns them. When a VFS
is mounted, the public `fs.*` and `fs/promises` APIs (including
streams, `fs.watch`, and `opendir`) dispatch to the provider for paths
under the mount point, and fall through to the real filesystem
otherwise. Includes per-method dispatch tests, error-path coverage,
multi-mount routing tests, and router unit tests.

Ref: https://github.com/nodejs/node/pull/63115

Signed-off-by: Matteo Collina <hello@matteocollina.com>
PR-URL: https://github.com/nodejs/node/pull/63537
Refs: https://github.com/nodejs/node/pull/63115
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Paolo Insogna <paolo@cowtech.it>
2026-05-29 17:57:34 +00:00

46 lines
1.4 KiB
JavaScript

'use strict';
const {
ArrayPrototypeJoin,
StringPrototypeSplit,
StringPrototypeStartsWith,
} = primordials;
const { isAbsolute, relative, sep } = require('path');
// `path.sep` is required here because on Windows `path.resolve('/virtual')`
// produces 'C:\virtual' and all resolved paths use backslashes - a hardcoded
// '/' check would never match. The trailing-separator guard handles root
// mount points like 'C:\' so we don't end up with 'C:\\'.
function isUnderMountPoint(normalizedPath, mountPoint) {
if (normalizedPath === mountPoint) {
return true;
}
if (mountPoint === '/') {
return StringPrototypeStartsWith(normalizedPath, '/');
}
const prefix = mountPoint[mountPoint.length - 1] === sep ?
mountPoint : mountPoint + sep;
return StringPrototypeStartsWith(normalizedPath, prefix);
}
// Returns a POSIX-style relative path the provider can consume. Uses
// `path.relative()` so Windows backslash paths are handled correctly, then
// re-joins with forward slashes for the provider's internal POSIX format.
function getRelativePath(normalizedPath, mountPoint) {
if (normalizedPath === mountPoint) {
return '/';
}
if (mountPoint === '/') {
return normalizedPath;
}
const rel = relative(mountPoint, normalizedPath);
const segments = StringPrototypeSplit(rel, sep);
return '/' + ArrayPrototypeJoin(segments, '/');
}
module.exports = {
isUnderMountPoint,
getRelativePath,
isAbsolutePath: isAbsolute,
};