diff --git a/lib/fs.js b/lib/fs.js index 83c074bd579709..2a97274243b4a3 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -230,7 +230,7 @@ function access(path, mode, callback) { const req = new FSReqCallback(); req.oncomplete = callback; - binding.access(pathModule.toNamespacedPath(path), mode, req); + binding.access(path, mode, req); } /** @@ -241,8 +241,7 @@ function access(path, mode, callback) { * @returns {void} */ function accessSync(path, mode) { - path = getValidatedPath(path); - binding.access(pathModule.toNamespacedPath(path), mode); + binding.access(getValidatedPath(path), mode); } /** @@ -290,7 +289,7 @@ function existsSync(path) { return false; } - return binding.existsSync(pathModule.toNamespacedPath(path)); + return binding.existsSync(path); } function readFileAfterOpen(err, fd) { @@ -383,15 +382,10 @@ function readFile(path, options, callback) { return; const flagsNumber = stringToFlags(options.flag, 'options.flag'); - path = getValidatedPath(path); - const req = new FSReqCallback(); req.context = context; req.oncomplete = readFileAfterOpen; - binding.open(pathModule.toNamespacedPath(path), - flagsNumber, - 0o666, - req); + binding.open(getValidatedPath(path), flagsNumber, 0o666, req); } function tryStatSync(fd, isUserFd) { @@ -443,7 +437,7 @@ function readFileSync(path, options) { if (options.encoding === 'utf8' || options.encoding === 'utf-8') { if (!isInt32(path)) { - path = pathModule.toNamespacedPath(getValidatedPath(path)); + path = getValidatedPath(path); } return binding.readFileUtf8(path, stringToFlags(options.flag)); } @@ -554,10 +548,7 @@ function open(path, flags, mode, callback) { const req = new FSReqCallback(); req.oncomplete = callback; - binding.open(pathModule.toNamespacedPath(path), - flagsNumber, - mode, - req); + binding.open(path, flagsNumber, mode, req); } /** @@ -568,10 +559,8 @@ function open(path, flags, mode, callback) { * @returns {number} */ function openSync(path, flags, mode) { - path = getValidatedPath(path); - return binding.open( - pathModule.toNamespacedPath(path), + getValidatedPath(path), stringToFlags(flags), parseFileMode(mode, 'mode', 0o666), ); @@ -592,7 +581,7 @@ function openAsBlob(path, options = kEmptyObject) { // To give ourselves flexibility to maybe return the Blob asynchronously, // this API returns a Promise. path = getValidatedPath(path); - return PromiseResolve(createBlobFromFilePath(pathModule.toNamespacedPath(path), { type })); + return PromiseResolve(createBlobFromFilePath(path, { type })); } /** @@ -1005,13 +994,13 @@ function writevSync(fd, buffers, position) { */ function rename(oldPath, newPath, callback) { callback = makeCallback(callback); - oldPath = getValidatedPath(oldPath, 'oldPath'); - newPath = getValidatedPath(newPath, 'newPath'); const req = new FSReqCallback(); req.oncomplete = callback; - binding.rename(pathModule.toNamespacedPath(oldPath), - pathModule.toNamespacedPath(newPath), - req); + binding.rename( + getValidatedPath(oldPath, 'oldPath'), + getValidatedPath(newPath, 'newPath'), + req, + ); } @@ -1023,11 +1012,9 @@ function rename(oldPath, newPath, callback) { * @returns {void} */ function renameSync(oldPath, newPath) { - oldPath = getValidatedPath(oldPath, 'oldPath'); - newPath = getValidatedPath(newPath, 'newPath'); binding.rename( - pathModule.toNamespacedPath(oldPath), - pathModule.toNamespacedPath(newPath), + getValidatedPath(oldPath, 'oldPath'), + getValidatedPath(newPath, 'newPath'), ); } @@ -1121,8 +1108,7 @@ function ftruncate(fd, len = 0, callback) { */ function ftruncateSync(fd, len = 0) { validateInteger(len, 'len'); - len = MathMax(0, len); - binding.ftruncate(fd, len); + binding.ftruncate(fd, len < 0 ? 0 : len); } function lazyLoadCp() { @@ -1156,7 +1142,7 @@ function rmdir(path, options, callback) { } callback = makeCallback(callback); - path = pathModule.toNamespacedPath(getValidatedPath(path)); + path = getValidatedPath(path); if (options?.recursive) { emitRecursiveRmdirWarning(); @@ -1204,13 +1190,13 @@ function rmdirSync(path, options) { options = validateRmOptionsSync(path, { ...options, force: false }, true); if (options !== false) { lazyLoadRimraf(); - return rimrafSync(pathModule.toNamespacedPath(path), options); + return rimrafSync(path, options); } } else { validateRmdirOptions(options); } - binding.rmdir(pathModule.toNamespacedPath(path)); + binding.rmdir(path); } /** @@ -1238,7 +1224,7 @@ function rm(path, options, callback) { return callback(err); } lazyLoadRimraf(); - return rimraf(pathModule.toNamespacedPath(path), options, callback); + return rimraf(path, options, callback); }); } @@ -1255,11 +1241,11 @@ function rm(path, options, callback) { * @returns {void} */ function rmSync(path, options) { - path = getValidatedPath(path); - options = validateRmOptionsSync(path, options, false); - lazyLoadRimraf(); - return rimrafSync(pathModule.toNamespacedPath(path), options); + return rimrafSync( + getValidatedPath(path), + validateRmOptionsSync(path, options, false), + ); } /** @@ -1340,8 +1326,12 @@ function mkdir(path, options, callback) { const req = new FSReqCallback(); req.oncomplete = callback; - binding.mkdir(pathModule.toNamespacedPath(path), - parseFileMode(mode, 'mode'), recursive, req); + binding.mkdir( + path, + parseFileMode(mode, 'mode'), + recursive, + req, + ); } /** @@ -1368,7 +1358,7 @@ function mkdirSync(path, options) { validateBoolean(recursive, 'options.recursive'); const result = binding.mkdir( - pathModule.toNamespacedPath(path), + path, parseFileMode(mode, 'mode'), recursive, ); @@ -1395,7 +1385,7 @@ function readdirSyncRecursive(basePath, options) { function read(path) { const readdirResult = binding.readdir( - pathModule.toNamespacedPath(path), + path, encoding, withFileTypes, ); @@ -1447,7 +1437,7 @@ function readdirSyncRecursive(basePath, options) { * recursive?: boolean; * }} [options] * @param {( - * err?: Error, + * err?: Error; * files?: string[] | Buffer[] | Dirent[]; * ) => any} callback * @returns {void} @@ -1477,8 +1467,12 @@ function readdir(path, options, callback) { getDirents(path, result, callback); }; } - binding.readdir(pathModule.toNamespacedPath(path), options.encoding, - !!options.withFileTypes, req); + binding.readdir( + path, + options.encoding, + !!options.withFileTypes, + req, + ); } /** @@ -1503,7 +1497,7 @@ function readdirSync(path, options) { } const result = binding.readdir( - pathModule.toNamespacedPath(path), + path, options.encoding, !!options.withFileTypes, ); @@ -1519,7 +1513,7 @@ function readdirSync(path, options) { * @param {( * err?: Error, * stats?: Stats - * ) => any} callback + * ) => any} [callback] * @returns {void} */ function fstat(fd, options = { bigint: false }, callback) { @@ -1555,7 +1549,7 @@ function lstat(path, options = { bigint: false }, callback) { const req = new FSReqCallback(options.bigint); req.oncomplete = callback; - binding.lstat(pathModule.toNamespacedPath(path), options.bigint, req); + binding.lstat(path, options.bigint, req); } /** @@ -1574,11 +1568,10 @@ function stat(path, options = { bigint: false }, callback) { options = kEmptyObject; } callback = makeStatsCallback(callback); - path = getValidatedPath(path); const req = new FSReqCallback(options.bigint); req.oncomplete = callback; - binding.stat(pathModule.toNamespacedPath(path), options.bigint, req); + binding.stat(getValidatedPath(path), options.bigint, req); } function statfs(path, options = { bigint: false }, callback) { @@ -1596,16 +1589,14 @@ function statfs(path, options = { bigint: false }, callback) { callback(err, getStatFsFromBinding(stats)); }; - binding.statfs(pathModule.toNamespacedPath(path), options.bigint, req); + binding.statfs(getValidatedPath(path), options.bigint, req); } /** * Synchronously retrieves the `fs.Stats` for * the file descriptor. * @param {number} fd - * @param {{ - * bigint?: boolean; - * }} [options] + * @param {{ bigint?: boolean; }} [options] * @returns {Stats | undefined} */ function fstatSync(fd, options = { bigint: false }) { @@ -1627,9 +1618,8 @@ function fstatSync(fd, options = { bigint: false }) { * @returns {Stats | undefined} */ function lstatSync(path, options = { bigint: false, throwIfNoEntry: true }) { - path = getValidatedPath(path); const stats = binding.lstat( - pathModule.toNamespacedPath(path), + getValidatedPath(path), options.bigint, undefined, options.throwIfNoEntry, @@ -1652,9 +1642,8 @@ function lstatSync(path, options = { bigint: false, throwIfNoEntry: true }) { * @returns {Stats} */ function statSync(path, options = { bigint: false, throwIfNoEntry: true }) { - path = getValidatedPath(path); const stats = binding.stat( - pathModule.toNamespacedPath(path), + getValidatedPath(path), options.bigint, undefined, options.throwIfNoEntry, @@ -1666,8 +1655,7 @@ function statSync(path, options = { bigint: false, throwIfNoEntry: true }) { } function statfsSync(path, options = { bigint: false }) { - path = getValidatedPath(path); - const stats = binding.statfs(pathModule.toNamespacedPath(path), options.bigint); + const stats = binding.statfs(getValidatedPath(path), options.bigint); return getStatFsFromBinding(stats); } @@ -1685,10 +1673,9 @@ function statfsSync(path, options = { bigint: false }) { function readlink(path, options, callback) { callback = makeCallback(typeof options === 'function' ? options : callback); options = getOptions(options); - path = getValidatedPath(path, 'oldPath'); const req = new FSReqCallback(); req.oncomplete = callback; - binding.readlink(pathModule.toNamespacedPath(path), options.encoding, req); + binding.readlink(getValidatedPath(path), options.encoding, req); } /** @@ -1700,11 +1687,7 @@ function readlink(path, options, callback) { */ function readlinkSync(path, options) { options = getOptions(options); - path = getValidatedPath(path, 'oldPath'); - return binding.readlink( - pathModule.toNamespacedPath(path), - options.encoding, - ); + return binding.readlink(getValidatedPath(path), options.encoding); } /** @@ -1758,8 +1741,12 @@ function symlink(target, path, type_, callback_) { const req = new FSReqCallback(); req.oncomplete = callback; - binding.symlink(destination, - pathModule.toNamespacedPath(path), resolvedFlags, req); + binding.symlink( + destination, + path, + resolvedFlags, + req, + ); }); return; } @@ -1770,7 +1757,7 @@ function symlink(target, path, type_, callback_) { const flags = stringToSymlinkType(type); const req = new FSReqCallback(); req.oncomplete = callback; - binding.symlink(destination, pathModule.toNamespacedPath(path), flags, req); + binding.symlink(destination, path, flags, req); } /** @@ -1803,7 +1790,7 @@ function symlinkSync(target, path, type) { binding.symlink( preprocessSymlinkDestination(target, type, path), - pathModule.toNamespacedPath(path), + path, stringToSymlinkType(type), ); } @@ -1825,9 +1812,7 @@ function link(existingPath, newPath, callback) { const req = new FSReqCallback(); req.oncomplete = callback; - binding.link(pathModule.toNamespacedPath(existingPath), - pathModule.toNamespacedPath(newPath), - req); + binding.link(existingPath, newPath, req); } /** @@ -1842,8 +1827,8 @@ function linkSync(existingPath, newPath) { newPath = getValidatedPath(newPath, 'newPath'); binding.link( - pathModule.toNamespacedPath(existingPath), - pathModule.toNamespacedPath(newPath), + existingPath, + newPath, ); } @@ -1855,10 +1840,9 @@ function linkSync(existingPath, newPath) { */ function unlink(path, callback) { callback = makeCallback(callback); - path = getValidatedPath(path); const req = new FSReqCallback(); req.oncomplete = callback; - binding.unlink(pathModule.toNamespacedPath(path), req); + binding.unlink(getValidatedPath(path), req); } /** @@ -1867,8 +1851,7 @@ function unlink(path, callback) { * @returns {void} */ function unlinkSync(path) { - path = pathModule.toNamespacedPath(getValidatedPath(path)); - binding.unlink(path); + binding.unlink(getValidatedPath(path)); } /** @@ -1959,7 +1942,7 @@ function chmod(path, mode, callback) { const req = new FSReqCallback(); req.oncomplete = callback; - binding.chmod(pathModule.toNamespacedPath(path), mode, req); + binding.chmod(path, mode, req); } /** @@ -1972,10 +1955,7 @@ function chmodSync(path, mode) { path = getValidatedPath(path); mode = parseFileMode(mode, 'mode'); - binding.chmod( - pathModule.toNamespacedPath(path), - mode, - ); + binding.chmod(path, mode); } /** @@ -1993,7 +1973,7 @@ function lchown(path, uid, gid, callback) { validateInteger(gid, 'gid', -1, kMaxUserId); const req = new FSReqCallback(); req.oncomplete = callback; - binding.lchown(pathModule.toNamespacedPath(path), uid, gid, req); + binding.lchown(path, uid, gid, req); } /** @@ -2007,11 +1987,7 @@ function lchownSync(path, uid, gid) { path = getValidatedPath(path); validateInteger(uid, 'uid', -1, kMaxUserId); validateInteger(gid, 'gid', -1, kMaxUserId); - binding.lchown( - pathModule.toNamespacedPath(path), - uid, - gid, - ); + binding.lchown(path, uid, gid); } /** @@ -2063,7 +2039,7 @@ function chown(path, uid, gid, callback) { const req = new FSReqCallback(); req.oncomplete = callback; - binding.chown(pathModule.toNamespacedPath(path), uid, gid, req); + binding.chown(path, uid, gid, req); } /** @@ -2078,11 +2054,7 @@ function chownSync(path, uid, gid) { path = getValidatedPath(path); validateInteger(uid, 'uid', -1, kMaxUserId); validateInteger(gid, 'gid', -1, kMaxUserId); - binding.chown( - pathModule.toNamespacedPath(path), - uid, - gid, - ); + binding.chown(path, uid, gid); } /** @@ -2100,10 +2072,12 @@ function utimes(path, atime, mtime, callback) { const req = new FSReqCallback(); req.oncomplete = callback; - binding.utimes(pathModule.toNamespacedPath(path), - toUnixTimestamp(atime), - toUnixTimestamp(mtime), - req); + binding.utimes( + path, + toUnixTimestamp(atime), + toUnixTimestamp(mtime), + req, + ); } /** @@ -2115,9 +2089,8 @@ function utimes(path, atime, mtime, callback) { * @returns {void} */ function utimesSync(path, atime, mtime) { - path = getValidatedPath(path); binding.utimes( - pathModule.toNamespacedPath(path), + getValidatedPath(path), toUnixTimestamp(atime), toUnixTimestamp(mtime), ); @@ -2174,10 +2147,12 @@ function lutimes(path, atime, mtime, callback) { const req = new FSReqCallback(); req.oncomplete = callback; - binding.lutimes(pathModule.toNamespacedPath(path), - toUnixTimestamp(atime), - toUnixTimestamp(mtime), - req); + binding.lutimes( + path, + toUnixTimestamp(atime), + toUnixTimestamp(mtime), + req, + ); } /** @@ -2189,9 +2164,8 @@ function lutimes(path, atime, mtime, callback) { * @returns {void} */ function lutimesSync(path, atime, mtime) { - path = getValidatedPath(path); binding.lutimes( - pathModule.toNamespacedPath(path), + getValidatedPath(path), toUnixTimestamp(atime), toUnixTimestamp(mtime), ); @@ -2334,11 +2308,12 @@ function writeFileSync(path, data, options) { // C++ fast path for string data and UTF8 encoding if (typeof data === 'string' && (options.encoding === 'utf8' || options.encoding === 'utf-8')) { if (!isInt32(path)) { - path = pathModule.toNamespacedPath(getValidatedPath(path)); + path = getValidatedPath(path); } return binding.writeFileUtf8( - path, data, + path, + data, stringToFlags(flag), parseFileMode(options.mode, 'mode', 0o666), ); @@ -2655,7 +2630,7 @@ function realpathSync(p, options) { // On windows, check that the root exists. On unix there is no need. if (isWindows) { - const out = binding.lstat(pathModule.toNamespacedPath(base), false, undefined, true /* throwIfNoEntry */); + const out = binding.lstat(base, false, undefined, true /* throwIfNoEntry */); if (out === undefined) { return; } @@ -2697,8 +2672,7 @@ function realpathSync(p, options) { // Use stats array directly to avoid creating an fs.Stats instance just // for our internal use. - const baseLong = pathModule.toNamespacedPath(base); - const stats = binding.lstat(baseLong, true, undefined, true /* throwIfNoEntry */); + const stats = binding.lstat(base, true, undefined, true /* throwIfNoEntry */); if (stats === undefined) { return; } @@ -2722,8 +2696,8 @@ function realpathSync(p, options) { } } if (linkTarget === null) { - binding.stat(baseLong, false, undefined, true); - linkTarget = binding.readlink(baseLong, undefined); + binding.stat(base, false, undefined, true); + linkTarget = binding.readlink(base, undefined); } resolvedLink = pathModule.resolve(previous, linkTarget); @@ -2740,7 +2714,7 @@ function realpathSync(p, options) { // On windows, check that the root exists. On unix there is no need. if (isWindows && !knownHard.has(base)) { - const out = binding.lstat(pathModule.toNamespacedPath(base), false, undefined, true /* throwIfNoEntry */); + const out = binding.lstat(base, false, undefined, true /* throwIfNoEntry */); if (out === undefined) { return; } @@ -2760,9 +2734,8 @@ function realpathSync(p, options) { */ realpathSync.native = (path, options) => { options = getOptions(options); - path = getValidatedPath(path); return binding.realpath( - pathModule.toNamespacedPath(path), + getValidatedPath(path), options.encoding, ); }; @@ -2926,7 +2899,7 @@ realpath.native = (path, options, callback) => { path = getValidatedPath(path); const req = new FSReqCallback(); req.oncomplete = callback; - binding.realpath(pathModule.toNamespacedPath(path), options.encoding, req); + binding.realpath(path, options.encoding, req); }; /** @@ -2982,9 +2955,6 @@ function copyFile(src, dest, mode, callback) { src = getValidatedPath(src, 'src'); dest = getValidatedPath(dest, 'dest'); - - src = pathModule.toNamespacedPath(src); - dest = pathModule.toNamespacedPath(dest); callback = makeCallback(callback); const req = new FSReqCallback(); @@ -3001,12 +2971,9 @@ function copyFile(src, dest, mode, callback) { * @returns {void} */ function copyFileSync(src, dest, mode) { - src = getValidatedPath(src, 'src'); - dest = getValidatedPath(dest, 'dest'); - binding.copyFile( - pathModule.toNamespacedPath(src), - pathModule.toNamespacedPath(dest), + getValidatedPath(src, 'src'), + getValidatedPath(dest, 'dest'), mode, ); } @@ -3027,8 +2994,8 @@ function cp(src, dest, options, callback) { } callback = makeCallback(callback); options = validateCpOptions(options); - src = pathModule.toNamespacedPath(getValidatedPath(src, 'src')); - dest = pathModule.toNamespacedPath(getValidatedPath(dest, 'dest')); + src = getValidatedPath(src, 'src'); + dest = getValidatedPath(dest, 'dest'); lazyLoadCp(); cpFn(src, dest, options, callback); } @@ -3043,8 +3010,8 @@ function cp(src, dest, options, callback) { */ function cpSync(src, dest, options) { options = validateCpOptions(options); - src = pathModule.toNamespacedPath(getValidatedPath(src, 'src')); - dest = pathModule.toNamespacedPath(getValidatedPath(dest, 'dest')); + src = getValidatedPath(src, 'src'); + dest = getValidatedPath(dest, 'dest'); lazyLoadCp(); cpSyncFn(src, dest, options); } diff --git a/lib/internal/fs/promises.js b/lib/internal/fs/promises.js index 676583ffea5d00..c544688e7f04fd 100644 --- a/lib/internal/fs/promises.js +++ b/lib/internal/fs/promises.js @@ -597,10 +597,8 @@ async function readFileHandle(filehandle, options) { // All of the functions are defined as async in order to ensure that errors // thrown cause promise rejections rather than being thrown synchronously. async function access(path, mode = F_OK) { - path = getValidatedPath(path); - return await PromisePrototypeThen( - binding.access(pathModule.toNamespacedPath(path), mode, kUsePromises), + binding.access(getValidatedPath(path), mode, kUsePromises), undefined, handleErrorFromBinding, ); @@ -608,19 +606,19 @@ async function access(path, mode = F_OK) { async function cp(src, dest, options) { options = validateCpOptions(options); - src = pathModule.toNamespacedPath(getValidatedPath(src, 'src')); - dest = pathModule.toNamespacedPath(getValidatedPath(dest, 'dest')); + src = getValidatedPath(src, 'src'); + dest = getValidatedPath(dest, 'dest'); return lazyLoadCpPromises()(src, dest, options); } async function copyFile(src, dest, mode) { - src = getValidatedPath(src, 'src'); - dest = getValidatedPath(dest, 'dest'); return await PromisePrototypeThen( - binding.copyFile(pathModule.toNamespacedPath(src), - pathModule.toNamespacedPath(dest), - mode, - kUsePromises), + binding.copyFile( + getValidatedPath(src, 'src'), + getValidatedPath(dest, 'dest'), + mode, + kUsePromises, + ), undefined, handleErrorFromBinding, ); @@ -633,8 +631,7 @@ async function open(path, flags, mode) { const flagsNumber = stringToFlags(flags); mode = parseFileMode(mode, 'mode', 0o666); return new FileHandle(await PromisePrototypeThen( - binding.openFileHandle(pathModule.toNamespacedPath(path), - flagsNumber, mode, kUsePromises), + binding.openFileHandle(path, flagsNumber, mode, kUsePromises), undefined, handleErrorFromBinding, )); @@ -779,9 +776,7 @@ async function rename(oldPath, newPath) { oldPath = getValidatedPath(oldPath, 'oldPath'); newPath = getValidatedPath(newPath, 'newPath'); return await PromisePrototypeThen( - binding.rename(pathModule.toNamespacedPath(oldPath), - pathModule.toNamespacedPath(newPath), - kUsePromises), + binding.rename(oldPath, newPath, kUsePromises), undefined, handleErrorFromBinding, ); @@ -803,13 +798,13 @@ async function ftruncate(handle, len = 0) { } async function rm(path, options) { - path = pathModule.toNamespacedPath(getValidatedPath(path)); + path = getValidatedPath(path); options = await validateRmOptionsPromise(path, options, false); return lazyRimRaf()(path, options); } async function rmdir(path, options) { - path = pathModule.toNamespacedPath(getValidatedPath(path)); + path = getValidatedPath(path); options = validateRmdirOptions(options); if (options.recursive) { @@ -855,9 +850,12 @@ async function mkdir(path, options) { validateBoolean(recursive, 'options.recursive'); return await PromisePrototypeThen( - binding.mkdir(pathModule.toNamespacedPath(path), - parseFileMode(mode, 'mode', 0o777), recursive, - kUsePromises), + binding.mkdir( + path, + parseFileMode(mode, 'mode', 0o777), + recursive, + kUsePromises, + ), undefined, handleErrorFromBinding, ); @@ -870,7 +868,7 @@ async function readdirRecursive(originalPath, options) { originalPath, await PromisePrototypeThen( binding.readdir( - pathModule.toNamespacedPath(originalPath), + originalPath, options.encoding, !!options.withFileTypes, kUsePromises, @@ -921,7 +919,7 @@ async function readdirRecursive(originalPath, options) { direntPath, await PromisePrototypeThen( binding.readdir( - pathModule.toNamespacedPath(direntPath), + direntPath, options.encoding, false, kUsePromises, @@ -946,7 +944,7 @@ async function readdir(path, options) { } const result = await PromisePrototypeThen( binding.readdir( - pathModule.toNamespacedPath(path), + path, options.encoding, !!options.withFileTypes, kUsePromises, @@ -963,8 +961,7 @@ async function readlink(path, options) { options = getOptions(options); path = getValidatedPath(path, 'oldPath'); return await PromisePrototypeThen( - binding.readlink(pathModule.toNamespacedPath(path), - options.encoding, kUsePromises), + binding.readlink(path, options.encoding, kUsePromises), undefined, handleErrorFromBinding, ); @@ -993,10 +990,12 @@ async function symlink(target, path, type_) { target = getValidatedPath(target, 'target'); path = getValidatedPath(path); return await PromisePrototypeThen( - binding.symlink(preprocessSymlinkDestination(target, type, path), - pathModule.toNamespacedPath(path), - stringToSymlinkType(type), - kUsePromises), + binding.symlink( + preprocessSymlinkDestination(target, type, path), + path, + stringToSymlinkType(type), + kUsePromises, + ), undefined, handleErrorFromBinding, ); @@ -1012,10 +1011,8 @@ async function fstat(handle, options = { bigint: false }) { } async function lstat(path, options = { bigint: false }) { - path = getValidatedPath(path); const result = await PromisePrototypeThen( - binding.lstat(pathModule.toNamespacedPath(path), - options.bigint, kUsePromises), + binding.lstat(getValidatedPath(path), options.bigint, kUsePromises), undefined, handleErrorFromBinding, ); @@ -1023,10 +1020,8 @@ async function lstat(path, options = { bigint: false }) { } async function stat(path, options = { bigint: false }) { - path = getValidatedPath(path); const result = await PromisePrototypeThen( - binding.stat(pathModule.toNamespacedPath(path), - options.bigint, kUsePromises), + binding.stat(getValidatedPath(path), options.bigint, kUsePromises), undefined, handleErrorFromBinding, ); @@ -1034,10 +1029,8 @@ async function stat(path, options = { bigint: false }) { } async function statfs(path, options = { bigint: false }) { - path = getValidatedPath(path); const result = await PromisePrototypeThen( - binding.statfs(pathModule.toNamespacedPath(path), - options.bigint, kUsePromises), + binding.statfs(path, options.bigint, kUsePromises), undefined, handleErrorFromBinding, ); @@ -1048,18 +1041,15 @@ async function link(existingPath, newPath) { existingPath = getValidatedPath(existingPath, 'existingPath'); newPath = getValidatedPath(newPath, 'newPath'); return await PromisePrototypeThen( - binding.link(pathModule.toNamespacedPath(existingPath), - pathModule.toNamespacedPath(newPath), - kUsePromises), + binding.link(existingPath, newPath, kUsePromises), undefined, handleErrorFromBinding, ); } async function unlink(path) { - path = getValidatedPath(path); return await PromisePrototypeThen( - binding.unlink(pathModule.toNamespacedPath(path), kUsePromises), + binding.unlink(getValidatedPath(path), kUsePromises), undefined, handleErrorFromBinding, ); @@ -1078,7 +1068,7 @@ async function chmod(path, mode) { path = getValidatedPath(path); mode = parseFileMode(mode, 'mode'); return await PromisePrototypeThen( - binding.chmod(pathModule.toNamespacedPath(path), mode, kUsePromises), + binding.chmod(path, mode, kUsePromises), undefined, handleErrorFromBinding, ); @@ -1097,7 +1087,7 @@ async function lchown(path, uid, gid) { validateInteger(uid, 'uid', -1, kMaxUserId); validateInteger(gid, 'gid', -1, kMaxUserId); return await PromisePrototypeThen( - binding.lchown(pathModule.toNamespacedPath(path), uid, gid, kUsePromises), + binding.lchown(path, uid, gid, kUsePromises), undefined, handleErrorFromBinding, ); @@ -1118,7 +1108,7 @@ async function chown(path, uid, gid) { validateInteger(uid, 'uid', -1, kMaxUserId); validateInteger(gid, 'gid', -1, kMaxUserId); return await PromisePrototypeThen( - binding.chown(pathModule.toNamespacedPath(path), uid, gid, kUsePromises), + binding.chown(path, uid, gid, kUsePromises), undefined, handleErrorFromBinding, ); @@ -1127,10 +1117,12 @@ async function chown(path, uid, gid) { async function utimes(path, atime, mtime) { path = getValidatedPath(path); return await PromisePrototypeThen( - binding.utimes(pathModule.toNamespacedPath(path), - toUnixTimestamp(atime), - toUnixTimestamp(mtime), - kUsePromises), + binding.utimes( + path, + toUnixTimestamp(atime), + toUnixTimestamp(mtime), + kUsePromises, + ), undefined, handleErrorFromBinding, ); @@ -1147,12 +1139,13 @@ async function futimes(handle, atime, mtime) { } async function lutimes(path, atime, mtime) { - path = getValidatedPath(path); return await PromisePrototypeThen( - binding.lutimes(pathModule.toNamespacedPath(path), - toUnixTimestamp(atime), - toUnixTimestamp(mtime), - kUsePromises), + binding.lutimes( + getValidatedPath(path), + toUnixTimestamp(atime), + toUnixTimestamp(mtime), + kUsePromises, + ), undefined, handleErrorFromBinding, ); @@ -1160,9 +1153,8 @@ async function lutimes(path, atime, mtime) { async function realpath(path, options) { options = getOptions(options); - path = getValidatedPath(path); return await PromisePrototypeThen( - binding.realpath(pathModule.toNamespacedPath(path), options.encoding, kUsePromises), + binding.realpath(getValidatedPath(path), options.encoding, kUsePromises), undefined, handleErrorFromBinding, ); diff --git a/src/node_blob.cc b/src/node_blob.cc index 970117efc3dc1f..eae1b1812a62fc 100644 --- a/src/node_blob.cc +++ b/src/node_blob.cc @@ -8,6 +8,7 @@ #include "node_errors.h" #include "node_external_reference.h" #include "node_file.h" +#include "path.h" #include "permission/permission.h" #include "util.h" #include "v8.h" @@ -96,6 +97,7 @@ void BlobFromFilePath(const FunctionCallbackInfo& args) { Environment* env = Environment::GetCurrent(args); BufferValue path(env->isolate(), args[0]); CHECK_NOT_NULL(*path); + ToNamespacedPath(env, &path); THROW_IF_INSUFFICIENT_PERMISSIONS( env, permission::PermissionScope::kFileSystemRead, path.ToStringView()); auto entry = DataQueue::CreateFdEntry(env, args[0]); diff --git a/src/node_file.cc b/src/node_file.cc index 70c37d7f7ddad7..ad5d13ae147ea9 100644 --- a/src/node_file.cc +++ b/src/node_file.cc @@ -30,6 +30,7 @@ #include "node_process-inl.h" #include "node_stat_watcher.h" #include "node_url.h" +#include "path.h" #include "permission/permission.h" #include "util-inl.h" @@ -960,6 +961,7 @@ void Access(const FunctionCallbackInfo& args) { BufferValue path(isolate, args[0]); CHECK_NOT_NULL(*path); + ToNamespacedPath(env, &path); THROW_IF_INSUFFICIENT_PERMISSIONS( env, permission::PermissionScope::kFileSystemRead, path.ToStringView()); @@ -1011,6 +1013,7 @@ static void ExistsSync(const FunctionCallbackInfo& args) { BufferValue path(isolate, args[0]); CHECK_NOT_NULL(*path); + ToNamespacedPath(env, &path); THROW_IF_INSUFFICIENT_PERMISSIONS( env, permission::PermissionScope::kFileSystemRead, path.ToStringView()); @@ -1070,6 +1073,7 @@ static void Stat(const FunctionCallbackInfo& args) { BufferValue path(realm->isolate(), args[0]); CHECK_NOT_NULL(*path); + ToNamespacedPath(env, &path); THROW_IF_INSUFFICIENT_PERMISSIONS( env, permission::PermissionScope::kFileSystemRead, path.ToStringView()); @@ -1112,6 +1116,7 @@ static void LStat(const FunctionCallbackInfo& args) { BufferValue path(realm->isolate(), args[0]); CHECK_NOT_NULL(*path); + ToNamespacedPath(env, &path); bool use_bigint = args[1]->IsTrue(); if (!args[2]->IsUndefined()) { // lstat(path, use_bigint, req) @@ -1191,6 +1196,7 @@ static void StatFs(const FunctionCallbackInfo& args) { BufferValue path(realm->isolate(), args[0]); CHECK_NOT_NULL(*path); + ToNamespacedPath(env, &path); THROW_IF_INSUFFICIENT_PERMISSIONS( env, permission::PermissionScope::kFileSystemRead, path.ToStringView()); @@ -1244,6 +1250,7 @@ static void Symlink(const FunctionCallbackInfo& args) { BufferValue path(isolate, args[1]); CHECK_NOT_NULL(*path); + ToNamespacedPath(env, &path); THROW_IF_INSUFFICIENT_PERMISSIONS( env, permission::PermissionScope::kFileSystemWrite, path.ToStringView()); @@ -1278,6 +1285,7 @@ static void Link(const FunctionCallbackInfo& args) { BufferValue src(isolate, args[0]); CHECK_NOT_NULL(*src); + ToNamespacedPath(env, &src); const auto src_view = src.ToStringView(); // To avoid bypass the link target should be allowed to read and write @@ -1288,6 +1296,8 @@ static void Link(const FunctionCallbackInfo& args) { BufferValue dest(isolate, args[1]); CHECK_NOT_NULL(*dest); + ToNamespacedPath(env, &dest); + const auto dest_view = dest.ToStringView(); THROW_IF_INSUFFICIENT_PERMISSIONS( env, permission::PermissionScope::kFileSystemWrite, dest_view); @@ -1319,6 +1329,7 @@ static void ReadLink(const FunctionCallbackInfo& args) { BufferValue path(isolate, args[0]); CHECK_NOT_NULL(*path); + ToNamespacedPath(env, &path); THROW_IF_INSUFFICIENT_PERMISSIONS( env, permission::PermissionScope::kFileSystemRead, path.ToStringView()); @@ -1364,6 +1375,7 @@ static void Rename(const FunctionCallbackInfo& args) { BufferValue old_path(isolate, args[0]); CHECK_NOT_NULL(*old_path); + ToNamespacedPath(env, &old_path); auto view_old_path = old_path.ToStringView(); THROW_IF_INSUFFICIENT_PERMISSIONS( env, permission::PermissionScope::kFileSystemRead, view_old_path); @@ -1372,6 +1384,7 @@ static void Rename(const FunctionCallbackInfo& args) { BufferValue new_path(isolate, args[1]); CHECK_NOT_NULL(*new_path); + ToNamespacedPath(env, &new_path); THROW_IF_INSUFFICIENT_PERMISSIONS( env, permission::PermissionScope::kFileSystemWrite, @@ -1482,6 +1495,7 @@ static void Unlink(const FunctionCallbackInfo& args) { BufferValue path(env->isolate(), args[0]); CHECK_NOT_NULL(*path); + ToNamespacedPath(env, &path); THROW_IF_INSUFFICIENT_PERMISSIONS( env, permission::PermissionScope::kFileSystemWrite, path.ToStringView()); @@ -1508,6 +1522,7 @@ static void RMDir(const FunctionCallbackInfo& args) { BufferValue path(env->isolate(), args[0]); CHECK_NOT_NULL(*path); + ToNamespacedPath(env, &path); THROW_IF_INSUFFICIENT_PERMISSIONS( env, permission::PermissionScope::kFileSystemWrite, path.ToStringView()); @@ -1696,6 +1711,7 @@ static void MKDir(const FunctionCallbackInfo& args) { BufferValue path(env->isolate(), args[0]); CHECK_NOT_NULL(*path); + ToNamespacedPath(env, &path); THROW_IF_INSUFFICIENT_PERMISSIONS( env, permission::PermissionScope::kFileSystemWrite, path.ToStringView()); @@ -1752,6 +1768,7 @@ static void RealPath(const FunctionCallbackInfo& args) { BufferValue path(isolate, args[0]); CHECK_NOT_NULL(*path); + ToNamespacedPath(env, &path); const enum encoding encoding = ParseEncoding(isolate, args[1], UTF8); @@ -1796,6 +1813,7 @@ static void ReadDir(const FunctionCallbackInfo& args) { BufferValue path(isolate, args[0]); CHECK_NOT_NULL(*path); + ToNamespacedPath(env, &path); THROW_IF_INSUFFICIENT_PERMISSIONS( env, permission::PermissionScope::kFileSystemRead, path.ToStringView()); @@ -1912,6 +1930,7 @@ static void Open(const FunctionCallbackInfo& args) { BufferValue path(env->isolate(), args[0]); CHECK_NOT_NULL(*path); + ToNamespacedPath(env, &path); CHECK(args[1]->IsInt32()); const int flags = args[1].As()->Value(); @@ -1951,6 +1970,7 @@ static void OpenFileHandle(const FunctionCallbackInfo& args) { BufferValue path(realm->isolate(), args[0]); CHECK_NOT_NULL(*path); + ToNamespacedPath(env, &path); CHECK(args[1]->IsInt32()); const int flags = args[1].As()->Value(); @@ -1996,11 +2016,13 @@ static void CopyFile(const FunctionCallbackInfo& args) { BufferValue src(isolate, args[0]); CHECK_NOT_NULL(*src); + ToNamespacedPath(env, &src); THROW_IF_INSUFFICIENT_PERMISSIONS( env, permission::PermissionScope::kFileSystemRead, src.ToStringView()); BufferValue dest(isolate, args[1]); CHECK_NOT_NULL(*dest); + ToNamespacedPath(env, &dest); THROW_IF_INSUFFICIENT_PERMISSIONS( env, permission::PermissionScope::kFileSystemWrite, dest.ToStringView()); @@ -2264,6 +2286,7 @@ static void WriteFileUtf8(const FunctionCallbackInfo& args) { } else { BufferValue path(isolate, args[0]); CHECK_NOT_NULL(*path); + ToNamespacedPath(env, &path); if (CheckOpenPermissions(env, path, flags).IsNothing()) return; FSReqWrapSync req_open("open", *path); @@ -2399,6 +2422,7 @@ static void ReadFileUtf8(const FunctionCallbackInfo& args) { } else { BufferValue path(env->isolate(), args[0]); CHECK_NOT_NULL(*path); + ToNamespacedPath(env, &path); if (CheckOpenPermissions(env, path, flags).IsNothing()) return; FS_SYNC_TRACE_BEGIN(open); @@ -2503,6 +2527,7 @@ static void Chmod(const FunctionCallbackInfo& args) { BufferValue path(env->isolate(), args[0]); CHECK_NOT_NULL(*path); + ToNamespacedPath(env, &path); THROW_IF_INSUFFICIENT_PERMISSIONS( env, permission::PermissionScope::kFileSystemWrite, path.ToStringView()); @@ -2565,6 +2590,7 @@ static void Chown(const FunctionCallbackInfo& args) { BufferValue path(env->isolate(), args[0]); CHECK_NOT_NULL(*path); + ToNamespacedPath(env, &path); THROW_IF_INSUFFICIENT_PERMISSIONS( env, permission::PermissionScope::kFileSystemWrite, path.ToStringView()); @@ -2631,6 +2657,7 @@ static void LChown(const FunctionCallbackInfo& args) { BufferValue path(env->isolate(), args[0]); CHECK_NOT_NULL(*path); + ToNamespacedPath(env, &path); THROW_IF_INSUFFICIENT_PERMISSIONS( env, permission::PermissionScope::kFileSystemWrite, path.ToStringView()); @@ -2663,6 +2690,7 @@ static void UTimes(const FunctionCallbackInfo& args) { BufferValue path(env->isolate(), args[0]); CHECK_NOT_NULL(*path); + ToNamespacedPath(env, &path); THROW_IF_INSUFFICIENT_PERMISSIONS( env, permission::PermissionScope::kFileSystemWrite, path.ToStringView()); @@ -2726,6 +2754,7 @@ static void LUTimes(const FunctionCallbackInfo& args) { BufferValue path(env->isolate(), args[0]); CHECK_NOT_NULL(*path); + ToNamespacedPath(env, &path); THROW_IF_INSUFFICIENT_PERMISSIONS( env, permission::PermissionScope::kFileSystemWrite, path.ToStringView()); diff --git a/src/node_url.cc b/src/node_url.cc index 95d15c78407359..57b22123f96f60 100644 --- a/src/node_url.cc +++ b/src/node_url.cc @@ -6,6 +6,7 @@ #include "node_i18n.h" #include "node_metadata.h" #include "node_process-inl.h" +#include "path.h" #include "util-inl.h" #include "v8-fast-api-calls.h" #include "v8.h" diff --git a/src/path.cc b/src/path.cc index 78dd5804fc391d..39c96dc7bfe5ca 100644 --- a/src/path.cc +++ b/src/path.cc @@ -3,7 +3,6 @@ #include #include "env-inl.h" #include "node_internals.h" -#include "util.h" namespace node { @@ -89,7 +88,7 @@ std::string NormalizeString(const std::string_view path, } #ifdef _WIN32 -bool IsWindowsDeviceRoot(const char c) noexcept { +constexpr bool IsWindowsDeviceRoot(const char c) noexcept { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); } @@ -268,4 +267,44 @@ std::string PathResolve(Environment* env, } #endif // _WIN32 +void ToNamespacedPath(Environment* env, BufferValue* path) { +#ifdef _WIN32 + if (path->length() == 0) return; + auto resolved_path = node::PathResolve(env, {path->ToStringView()}); + + if (resolved_path.size() <= 2) { + path->SetLength(resolved_path.size()); + memcpy(&path, resolved_path.c_str(), resolved_path.size()); + return; + } + + // SAFETY: We know that resolved_path.size() > 2, therefore accessing [0], + // [1], and [2] is safe. + if (resolved_path[0] == '\\') { + // Possible UNC root + if (resolved_path[1] == '\\') { + if (resolved_path[2] != '?' && resolved_path[2] != '.') { + // Matched non-long UNC root, convert the path to a long UNC path + std::string_view unc_prefix = R"(\\?\UNC\")"; + std::string_view resolved_path2 = resolved_path.substr(2); + path->SetLength(unc_prefix.size() + resolved_path2.size()); + memcpy(&path, unc_prefix.data(), unc_prefix.size()); + memcpy(&path + unc_prefix.size(), + resolved_path2.data(), + resolved_path2.size()); + } + } else if (IsWindowsDeviceRoot(resolved_path[0]) && + resolved_path[1] == ':' && resolved_path[2] == '\\') { + // Matched device root, convert the path to a long UNC path + std::string_view new_prefix = R"(\\?\")"; + path->SetLength(new_prefix.size() + resolved_path.size()); + memcpy(&path, new_prefix.data(), new_prefix.size()); + memcpy(&path + new_prefix.size(), + resolved_path.data(), + resolved_path.size()); + } + } +#endif +} + } // namespace node diff --git a/src/path.h b/src/path.h index 532c5f5849652c..3d3354fe32b494 100644 --- a/src/path.h +++ b/src/path.h @@ -5,11 +5,11 @@ #include #include +#include "node_options-inl.h" +#include "util-inl.h" namespace node { -class Environment; - bool IsPathSeparator(const char c) noexcept; std::string NormalizeString(const std::string_view path, @@ -17,7 +17,14 @@ std::string NormalizeString(const std::string_view path, const std::string_view separator); std::string PathResolve(Environment* env, - const std::vector& args); + const std::vector& paths); + +#ifdef _WIN32 +constexpr bool IsWindowsDeviceRoot(const char c) noexcept; +#endif // _WIN32 + +void ToNamespacedPath(Environment* env, BufferValue* path); + } // namespace node #endif // defined(NODE_WANT_INTERNALS) && NODE_WANT_INTERNALS diff --git a/test/cctest/test_path.cc b/test/cctest/test_path.cc index 44f3b30ddff341..cfdd97a49a25f0 100644 --- a/test/cctest/test_path.cc +++ b/test/cctest/test_path.cc @@ -4,8 +4,12 @@ #include "node_options.h" #include "node_test_fixture.h" #include "path.h" +#include "util.h" +#include "v8.h" +using node::BufferValue; using node::PathResolve; +using node::ToNamespacedPath; class PathTest : public EnvironmentTestFixture {}; @@ -45,3 +49,26 @@ TEST_F(PathTest, PathResolve) { "/foo/tmp.3/cycles/root.js"); #endif } + +TEST_F(PathTest, ToNamespacedPath) { + const v8::HandleScope handle_scope(isolate_); + Argv argv; + Env env{handle_scope, argv, node::EnvironmentFlags::kNoBrowserGlobals}; +#ifdef _WIN32 + BufferValue data(isolate_, + v8::String::NewFromUtf8(isolate_, "").ToLocalChecked()); + ToNamespacedPath(*env, &data); + EXPECT_EQ(data.ToStringView(), ""); // Empty string should not be mutated + BufferValue data_2(isolate_, + v8::String::NewFromUtf8(isolate_, "c:").ToLocalChecked()); + EXPECT_EQ(data_2.ToStringView(), + "c:"); // Input less than equal to 2 characters + // should be returned directly +#else + BufferValue data( + isolate_, + v8::String::NewFromUtf8(isolate_, "hello world").ToLocalChecked()); + ToNamespacedPath(*env, &data); + EXPECT_EQ(data.ToStringView(), "hello world"); // Input should not be mutated +#endif +}