Skip to content

Commit

Permalink
fixup! fs,win: fix bug in paths with trailing slashes
Browse files Browse the repository at this point in the history
  • Loading branch information
huseyinacacak-janea committed Aug 9, 2024
1 parent 797c55c commit 6a733cc
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 23 deletions.
26 changes: 17 additions & 9 deletions lib/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,11 @@ function readFile(path, options, callback) {
const req = new FSReqCallback();
req.context = context;
req.oncomplete = readFileAfterOpen;
binding.open(getValidatedPath(path, 'path', true), flagsNumber, 0o666, req);
binding.open(
getValidatedPath(path, 'path', { expectFile: true, syscall: 'read' }),
flagsNumber,
0o666,
req);
}

function tryStatSync(fd, isUserFd) {
Expand Down Expand Up @@ -436,7 +440,9 @@ function readFileSync(path, options) {

if (options.encoding === 'utf8' || options.encoding === 'utf-8') {
if (!isInt32(path)) {
path = getValidatedPath(path, 'path', true);
path = getValidatedPath(path,
'path',
{ expectFile: true, syscall: 'read' });
}
return binding.readFileUtf8(path, stringToFlags(options.flag));
}
Expand Down Expand Up @@ -530,7 +536,7 @@ function closeSync(fd) {
* @returns {void}
*/
function open(path, flags, mode, callback) {
path = getValidatedPath(path, 'path', true);
path = getValidatedPath(path, 'path', { expectFile: true, syscall: 'open' });
if (arguments.length < 3) {
callback = flags;
flags = 'r';
Expand Down Expand Up @@ -559,7 +565,7 @@ function open(path, flags, mode, callback) {
*/
function openSync(path, flags, mode) {
return binding.open(
getValidatedPath(path, 'path', true),
getValidatedPath(path, 'path', { expectFile: true, syscall: 'open' }),
stringToFlags(flags),
parseFileMode(mode, 'mode', 0o666),
);
Expand Down Expand Up @@ -2336,7 +2342,9 @@ 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 = getValidatedPath(path, 'path', true);
path = getValidatedPath(path,
'path',
{ expectFile: true, syscall: 'write' });
}

return binding.writeFileUtf8(
Expand Down Expand Up @@ -2981,8 +2989,8 @@ function copyFile(src, dest, mode, callback) {
mode = 0;
}

src = getValidatedPath(src, 'src', true);
dest = getValidatedPath(dest, 'dest', true);
src = getValidatedPath(src, 'src', { expectFile: true, syscall: 'cp' });
dest = getValidatedPath(dest, 'dest', { expectFile: true, syscall: 'cp' });
callback = makeCallback(callback);

const req = new FSReqCallback();
Expand All @@ -3000,8 +3008,8 @@ function copyFile(src, dest, mode, callback) {
*/
function copyFileSync(src, dest, mode) {
binding.copyFile(
getValidatedPath(src, 'src', true),
getValidatedPath(dest, 'dest', true),
getValidatedPath(src, 'src', { expectFile: true, syscall: 'cp' }),
getValidatedPath(dest, 'dest', { expectFile: true, syscall: 'cp' }),
mode,
);
}
Expand Down
6 changes: 3 additions & 3 deletions lib/internal/fs/promises.js
Original file line number Diff line number Diff line change
Expand Up @@ -620,8 +620,8 @@ async function cp(src, dest, options) {
async function copyFile(src, dest, mode) {
return await PromisePrototypeThen(
binding.copyFile(
getValidatedPath(src, 'src', 'path', true),
getValidatedPath(dest, 'dest', 'path', true),
getValidatedPath(src, 'src', { expectFile: true, syscall: 'cp' }),
getValidatedPath(dest, 'dest', { expectFile: true, syscall: 'cp' }),
mode,
kUsePromises,
),
Expand All @@ -633,7 +633,7 @@ async function copyFile(src, dest, mode) {
// Note that unlike fs.open() which uses numeric file descriptors,
// fsPromises.open() uses the fs.FileHandle class.
async function open(path, flags, mode) {
path = getValidatedPath(path, 'path', true);
path = getValidatedPath(path, 'path', { expectFile: true, syscall: 'open' });
const flagsNumber = stringToFlags(flags);
mode = parseFileMode(mode, 'mode', 0o666);
return new FileHandle(await PromisePrototypeThen(
Expand Down
4 changes: 2 additions & 2 deletions lib/internal/fs/streams.js
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ function ReadStream(path, options) {
this.flags = options.flags === undefined ? 'r' : options.flags;
this.mode = options.mode === undefined ? 0o666 : options.mode;

validatePath(this.path, 'path', true);
validatePath(this.path, 'path', { expectFile: true, syscall: 'read' });
} else {
this.fd = getValidatedFd(importFd(this, options));
}
Expand Down Expand Up @@ -337,7 +337,7 @@ function WriteStream(path, options) {
this.flags = options.flags === undefined ? 'w' : options.flags;
this.mode = options.mode === undefined ? 0o666 : options.mode;

validatePath(this.path, 'path', true);
validatePath(this.path, 'path', { expectFile: true, syscall: 'write' });
} else {
this.fd = getValidatedFd(importFd(this, options));
}
Expand Down
20 changes: 11 additions & 9 deletions lib/internal/fs/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -711,22 +711,22 @@ const validateOffsetLengthWrite = hideStackFrames(

/**
* Validates the given path based on the expected type (file or directory).
*
* @param {string} path - The path to validate.
* @param {string} [propName='path'] - The name of the property being validated.
* @param {boolean} expectFile - If true, expects the path to be a file.
* @param {object} options - Additional options for validation.
* @param {boolean} [options.expectFile] - If true, expects the path to be a file.
* @param {string} [options.syscall] - The name of the syscall.
* @throws {TypeError} Throws if the path is not a string, Uint8Array, or URL without null bytes.
* @throws {Error} Throws if the path does not meet the expected type (file).
*/
const validatePath = hideStackFrames((path, propName = 'path', expectFile) => {
const validatePath = hideStackFrames((path, propName = 'path', options) => {
if (typeof path !== 'string' && !isUint8Array(path)) {
throw new ERR_INVALID_ARG_TYPE.HideStackFramesError(propName, ['string', 'Buffer', 'URL'], path);
}

const pathIsString = typeof path === 'string';
const pathIsUint8Array = isUint8Array(path);

if (expectFile) {
if (options && options.expectFile) {
const lastCharacter = path[path.length - 1];
if (
lastCharacter === '/' || lastCharacter === 47 ||
Expand All @@ -736,6 +736,7 @@ const validatePath = hideStackFrames((path, propName = 'path', expectFile) => {
code: 'ERR_FS_EISDIR',
message: 'is a directory',
path,
syscall: options.syscall,
errno: ERR_FS_EISDIR,
});
}
Expand All @@ -757,16 +758,17 @@ const validatePath = hideStackFrames((path, propName = 'path', expectFile) => {

/**
* Validates and returns the given file URL or path based on the expected type (file or directory).
*
* @param {string|URL} fileURLOrPath - The file URL or path to validate.
* @param {string} [propName='path'] - The name of the property being validated.
* @param {boolean} [expectFile=false] - If true, expects the path to be a file.
* @param {object} options - Additional options for validation.
* @param {boolean} [options.expectFile] - If true, expects the path to be a file.
* @param {string} [options.syscall] - The name of the syscall.
* @returns {string} The validated path.
*/
const getValidatedPath =
hideStackFrames((fileURLOrPath, propName = 'path', expectFile = false) => {
hideStackFrames((fileURLOrPath, propName = 'path', options) => {
const path = toPathIfFileURL(fileURLOrPath);
validatePath(path, propName, expectFile);
validatePath(path, propName, options);
return path;
});

Expand Down

0 comments on commit 6a733cc

Please sign in to comment.