Files
node/lib/internal/vfs/errors.js
T
Philipp Dunkel a18fd89ac5 vfs: make the reserved root readable through fs
The reserved root `${os.devNull}/vfs`, which holds the mount points of
all virtual file systems, could not be read: fs calls on it fell through
to the real file system, so nothing could list what was mounted.

While any file system is mounted, serve the root as a read-only
directory. It lists every mount point by the last segment of its path, a
recursive listing descends into each mounted file system, and paths
under it that no mount serves report ENOENT. Creating, removing or
changing entries in it fails with EROFS. When nothing is mounted it does
not exist, as before.

Add vfs.vfsBase(), which returns the path of that directory, so that a
program can read it without spelling the path out.

A mount point cannot be removed or renamed, nor replaced by a rename:
rmdir() and rename() fail with EBUSY, and a recursive rm() empties the
file system and then fails the same way. Before, rmdir() of an empty
mount point reported success without doing anything.

The callback and promise forms of readdir() with `withFileTypes` now
report each Dirent's parentPath as a host path, as readdirSync() did,
instead of the provider-relative one, and split recursive names such as
`dir/file.txt` into their directory and base name. A recursive listing
joins subdirectories with the host separator rather than `/`, which
mixed separators on Windows. realpath() of a mount point no longer
returns it with a trailing separator.

Signed-off-by: Philipp Dunkel <pip@pipobscure.com>
PR-URL: https://github.com/nodejs/node/pull/66140
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
2026-09-25 09:37:00 +00:00

218 lines
4.3 KiB
JavaScript

'use strict';
const {
ErrorCaptureStackTrace,
} = primordials;
const {
UVException,
} = require('internal/errors');
const {
UV_ENOENT,
UV_ENOTDIR,
UV_ENOTEMPTY,
UV_EISDIR,
UV_EBADF,
UV_EEXIST,
UV_EROFS,
UV_EINVAL,
UV_ELOOP,
UV_EACCES,
UV_EBUSY,
UV_EXDEV,
} = internalBinding('uv');
/**
* Creates an ENOENT error for virtual file system operations.
* @param {string} syscall The system call name
* @param {string} path The path that was not found
* @returns {Error}
*/
function createENOENT(syscall, path) {
const err = new UVException({
errno: UV_ENOENT,
syscall,
path,
});
ErrorCaptureStackTrace(err, createENOENT);
return err;
}
/**
* Creates an ENOTDIR error.
* @param {string} syscall The system call name
* @param {string} path The path that is not a directory
* @returns {Error}
*/
function createENOTDIR(syscall, path) {
const err = new UVException({
errno: UV_ENOTDIR,
syscall,
path,
});
ErrorCaptureStackTrace(err, createENOTDIR);
return err;
}
/**
* Creates an ENOTEMPTY error for non-empty directory.
* @param {string} syscall The system call name
* @param {string} path The path of the non-empty directory
* @returns {Error}
*/
function createENOTEMPTY(syscall, path) {
const err = new UVException({
errno: UV_ENOTEMPTY,
syscall,
path,
});
ErrorCaptureStackTrace(err, createENOTEMPTY);
return err;
}
/**
* Creates an EISDIR error.
* @param {string} syscall The system call name
* @param {string} path The path that is a directory
* @returns {Error}
*/
function createEISDIR(syscall, path) {
const err = new UVException({
errno: UV_EISDIR,
syscall,
path,
});
ErrorCaptureStackTrace(err, createEISDIR);
return err;
}
/**
* Creates an EBADF error for invalid file descriptor operations.
* @param {string} syscall The system call name
* @returns {Error}
*/
function createEBADF(syscall) {
const err = new UVException({
errno: UV_EBADF,
syscall,
});
ErrorCaptureStackTrace(err, createEBADF);
return err;
}
/**
* Creates an EEXIST error.
* @param {string} syscall The system call name
* @param {string} path The path that already exists
* @returns {Error}
*/
function createEEXIST(syscall, path) {
const err = new UVException({
errno: UV_EEXIST,
syscall,
path,
});
ErrorCaptureStackTrace(err, createEEXIST);
return err;
}
/**
* Creates an EROFS error for read-only file system.
* @param {string} syscall The system call name
* @param {string} path The path
* @returns {Error}
*/
function createEROFS(syscall, path) {
const err = new UVException({
errno: UV_EROFS,
syscall,
path,
});
ErrorCaptureStackTrace(err, createEROFS);
return err;
}
/**
* Creates an EINVAL error for invalid argument.
* @param {string} syscall The system call name
* @param {string} path The path
* @returns {Error}
*/
function createEINVAL(syscall, path) {
const err = new UVException({
errno: UV_EINVAL,
syscall,
path,
});
ErrorCaptureStackTrace(err, createEINVAL);
return err;
}
/**
* Creates an ELOOP error for too many symbolic links.
* @param {string} syscall The system call name
* @param {string} path The path
* @returns {Error}
*/
function createELOOP(syscall, path) {
const err = new UVException({
errno: UV_ELOOP,
syscall,
path,
});
ErrorCaptureStackTrace(err, createELOOP);
return err;
}
/**
* Creates an EACCES error for permission denied.
* @param {string} syscall The system call name
* @param {string} path The path
* @returns {Error}
*/
function createEACCES(syscall, path) {
const err = new UVException({
errno: UV_EACCES,
syscall,
path,
});
ErrorCaptureStackTrace(err, createEACCES);
return err;
}
function createEBUSY(syscall, path) {
const err = new UVException({
errno: UV_EBUSY,
syscall,
path,
});
ErrorCaptureStackTrace(err, createEBUSY);
return err;
}
function createEXDEV(syscall, path) {
const err = new UVException({
errno: UV_EXDEV,
syscall,
path,
});
ErrorCaptureStackTrace(err, createEXDEV);
return err;
}
module.exports = {
createENOENT,
createENOTDIR,
createENOTEMPTY,
createEISDIR,
createEBADF,
createEEXIST,
createEROFS,
createEINVAL,
createELOOP,
createEACCES,
createEBUSY,
createEXDEV,
};