fs: adjust typecheck for type
in fs.symlink()
Throws `TypeError` instead of `Error` Enables autodetection on Windows if `type === undefined` Explicitly disallows unknown strings and non-string values PR-URL: https://github.com/nodejs/node/pull/49741 Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Gireesh Punathil <gpunathi@in.ibm.com>
This commit is contained in:
parent
75884678d7
commit
f202322ea4
@ -1377,13 +1377,6 @@ Path is a directory.
|
|||||||
An attempt has been made to read a file whose size is larger than the maximum
|
An attempt has been made to read a file whose size is larger than the maximum
|
||||||
allowed size for a `Buffer`.
|
allowed size for a `Buffer`.
|
||||||
|
|
||||||
<a id="ERR_FS_INVALID_SYMLINK_TYPE"></a>
|
|
||||||
|
|
||||||
### `ERR_FS_INVALID_SYMLINK_TYPE`
|
|
||||||
|
|
||||||
An invalid symlink type was passed to the [`fs.symlink()`][] or
|
|
||||||
[`fs.symlinkSync()`][] methods.
|
|
||||||
|
|
||||||
<a id="ERR_HTTP_HEADERS_SENT"></a>
|
<a id="ERR_HTTP_HEADERS_SENT"></a>
|
||||||
|
|
||||||
### `ERR_HTTP_HEADERS_SENT`
|
### `ERR_HTTP_HEADERS_SENT`
|
||||||
@ -3276,6 +3269,17 @@ The UTF-16 encoding was used with [`hash.digest()`][]. While the
|
|||||||
causing the method to return a string rather than a `Buffer`, the UTF-16
|
causing the method to return a string rather than a `Buffer`, the UTF-16
|
||||||
encoding (e.g. `ucs` or `utf16le`) is not supported.
|
encoding (e.g. `ucs` or `utf16le`) is not supported.
|
||||||
|
|
||||||
|
<a id="ERR_FS_INVALID_SYMLINK_TYPE"></a>
|
||||||
|
|
||||||
|
### `ERR_FS_INVALID_SYMLINK_TYPE`
|
||||||
|
|
||||||
|
<!-- YAML
|
||||||
|
removed: REPLACEME
|
||||||
|
-->
|
||||||
|
|
||||||
|
An invalid symlink type was passed to the [`fs.symlink()`][] or
|
||||||
|
[`fs.symlinkSync()`][] methods.
|
||||||
|
|
||||||
<a id="ERR_HTTP2_FRAME_ERROR"></a>
|
<a id="ERR_HTTP2_FRAME_ERROR"></a>
|
||||||
|
|
||||||
### `ERR_HTTP2_FRAME_ERROR`
|
### `ERR_HTTP2_FRAME_ERROR`
|
||||||
|
@ -1693,7 +1693,7 @@ changes:
|
|||||||
Creates a symbolic link.
|
Creates a symbolic link.
|
||||||
|
|
||||||
The `type` argument is only used on Windows platforms and can be one of `'dir'`,
|
The `type` argument is only used on Windows platforms and can be one of `'dir'`,
|
||||||
`'file'`, or `'junction'`. If the `type` argument is not a string, Node.js will
|
`'file'`, or `'junction'`. If the `type` argument is `null`, Node.js will
|
||||||
autodetect `target` type and use `'file'` or `'dir'`. If the `target` does not
|
autodetect `target` type and use `'file'` or `'dir'`. If the `target` does not
|
||||||
exist, `'file'` will be used. Windows junction points require the destination
|
exist, `'file'` will be used. Windows junction points require the destination
|
||||||
path to be absolute. When using `'junction'`, the `target` argument will
|
path to be absolute. When using `'junction'`, the `target` argument will
|
||||||
@ -4444,7 +4444,7 @@ See the POSIX symlink(2) documentation for more details.
|
|||||||
|
|
||||||
The `type` argument is only available on Windows and ignored on other platforms.
|
The `type` argument is only available on Windows and ignored on other platforms.
|
||||||
It can be set to `'dir'`, `'file'`, or `'junction'`. If the `type` argument is
|
It can be set to `'dir'`, `'file'`, or `'junction'`. If the `type` argument is
|
||||||
not a string, Node.js will autodetect `target` type and use `'file'` or `'dir'`.
|
`null`, Node.js will autodetect `target` type and use `'file'` or `'dir'`.
|
||||||
If the `target` does not exist, `'file'` will be used. Windows junction points
|
If the `target` does not exist, `'file'` will be used. Windows junction points
|
||||||
require the destination path to be absolute. When using `'junction'`, the
|
require the destination path to be absolute. When using `'junction'`, the
|
||||||
`target` argument will automatically be normalized to absolute path. Junction
|
`target` argument will automatically be normalized to absolute path. Junction
|
||||||
|
21
lib/fs.js
21
lib/fs.js
@ -142,6 +142,7 @@ const {
|
|||||||
validateFunction,
|
validateFunction,
|
||||||
validateInteger,
|
validateInteger,
|
||||||
validateObject,
|
validateObject,
|
||||||
|
validateOneOf,
|
||||||
validateString,
|
validateString,
|
||||||
kValidateObjectAllowNullable,
|
kValidateObjectAllowNullable,
|
||||||
} = require('internal/validators');
|
} = require('internal/validators');
|
||||||
@ -1715,13 +1716,17 @@ function readlinkSync(path, options) {
|
|||||||
* Creates the link called `path` pointing to `target`.
|
* Creates the link called `path` pointing to `target`.
|
||||||
* @param {string | Buffer | URL} target
|
* @param {string | Buffer | URL} target
|
||||||
* @param {string | Buffer | URL} path
|
* @param {string | Buffer | URL} path
|
||||||
* @param {string | null} [type_]
|
* @param {string | null} [type]
|
||||||
* @param {(err?: Error) => any} callback_
|
* @param {(err?: Error) => any} callback
|
||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function symlink(target, path, type_, callback_) {
|
function symlink(target, path, type, callback) {
|
||||||
const type = (typeof type_ === 'string' ? type_ : null);
|
if (callback === undefined) {
|
||||||
const callback = makeCallback(arguments[arguments.length - 1]);
|
callback = makeCallback(type);
|
||||||
|
type = undefined;
|
||||||
|
} else {
|
||||||
|
validateOneOf(type, 'type', ['dir', 'file', 'junction', null, undefined]);
|
||||||
|
}
|
||||||
|
|
||||||
if (permission.isEnabled()) {
|
if (permission.isEnabled()) {
|
||||||
// The permission model's security guarantees fall apart in the presence of
|
// The permission model's security guarantees fall apart in the presence of
|
||||||
@ -1740,7 +1745,7 @@ function symlink(target, path, type_, callback_) {
|
|||||||
target = getValidatedPath(target, 'target');
|
target = getValidatedPath(target, 'target');
|
||||||
path = getValidatedPath(path);
|
path = getValidatedPath(path);
|
||||||
|
|
||||||
if (isWindows && type === null) {
|
if (isWindows && type == null) {
|
||||||
let absoluteTarget;
|
let absoluteTarget;
|
||||||
try {
|
try {
|
||||||
// Symlinks targets can be relative to the newly created path.
|
// Symlinks targets can be relative to the newly created path.
|
||||||
@ -1786,8 +1791,8 @@ function symlink(target, path, type_, callback_) {
|
|||||||
* @returns {void}
|
* @returns {void}
|
||||||
*/
|
*/
|
||||||
function symlinkSync(target, path, type) {
|
function symlinkSync(target, path, type) {
|
||||||
type = (typeof type === 'string' ? type : null);
|
validateOneOf(type, 'type', ['dir', 'file', 'junction', null, undefined]);
|
||||||
if (isWindows && type === null) {
|
if (isWindows && type == null) {
|
||||||
const absoluteTarget = pathModule.resolve(`${path}`, '..', `${target}`);
|
const absoluteTarget = pathModule.resolve(`${path}`, '..', `${target}`);
|
||||||
if (statSync(absoluteTarget, { throwIfNoEntry: false })?.isDirectory()) {
|
if (statSync(absoluteTarget, { throwIfNoEntry: false })?.isDirectory()) {
|
||||||
type = 'dir';
|
type = 'dir';
|
||||||
|
@ -1217,9 +1217,6 @@ E('ERR_FS_CP_SYMLINK_TO_SUBDIRECTORY',
|
|||||||
E('ERR_FS_CP_UNKNOWN', 'Cannot copy an unknown file type', SystemError);
|
E('ERR_FS_CP_UNKNOWN', 'Cannot copy an unknown file type', SystemError);
|
||||||
E('ERR_FS_EISDIR', 'Path is a directory', SystemError, HideStackFramesError);
|
E('ERR_FS_EISDIR', 'Path is a directory', SystemError, HideStackFramesError);
|
||||||
E('ERR_FS_FILE_TOO_LARGE', 'File size (%s) is greater than 2 GiB', RangeError);
|
E('ERR_FS_FILE_TOO_LARGE', 'File size (%s) is greater than 2 GiB', RangeError);
|
||||||
E('ERR_FS_INVALID_SYMLINK_TYPE',
|
|
||||||
'Symlink type must be one of "dir", "file", or "junction". Received "%s"',
|
|
||||||
Error); // Switch to TypeError. The current implementation does not seem right
|
|
||||||
E('ERR_HTTP2_ALTSVC_INVALID_ORIGIN',
|
E('ERR_HTTP2_ALTSVC_INVALID_ORIGIN',
|
||||||
'HTTP/2 ALTSVC frames require a valid origin', TypeError);
|
'HTTP/2 ALTSVC frames require a valid origin', TypeError);
|
||||||
E('ERR_HTTP2_ALTSVC_LENGTH',
|
E('ERR_HTTP2_ALTSVC_LENGTH',
|
||||||
|
@ -85,6 +85,7 @@ const {
|
|||||||
validateEncoding,
|
validateEncoding,
|
||||||
validateInteger,
|
validateInteger,
|
||||||
validateObject,
|
validateObject,
|
||||||
|
validateOneOf,
|
||||||
validateString,
|
validateString,
|
||||||
kValidateObjectAllowNullable,
|
kValidateObjectAllowNullable,
|
||||||
} = require('internal/validators');
|
} = require('internal/validators');
|
||||||
@ -973,9 +974,9 @@ async function readlink(path, options) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function symlink(target, path, type_) {
|
async function symlink(target, path, type) {
|
||||||
let type = (typeof type_ === 'string' ? type_ : null);
|
validateOneOf(type, 'type', ['dir', 'file', 'junction', null, undefined]);
|
||||||
if (isWindows && type === null) {
|
if (isWindows && type == null) {
|
||||||
try {
|
try {
|
||||||
const absoluteTarget = pathModule.resolve(`${path}`, '..', `${target}`);
|
const absoluteTarget = pathModule.resolve(`${path}`, '..', `${target}`);
|
||||||
type = (await stat(absoluteTarget)).isDirectory() ? 'dir' : 'file';
|
type = (await stat(absoluteTarget)).isDirectory() ? 'dir' : 'file';
|
||||||
|
@ -31,7 +31,6 @@ const {
|
|||||||
UVException,
|
UVException,
|
||||||
codes: {
|
codes: {
|
||||||
ERR_FS_EISDIR,
|
ERR_FS_EISDIR,
|
||||||
ERR_FS_INVALID_SYMLINK_TYPE,
|
|
||||||
ERR_INCOMPATIBLE_OPTION_PAIR,
|
ERR_INCOMPATIBLE_OPTION_PAIR,
|
||||||
ERR_INVALID_ARG_TYPE,
|
ERR_INVALID_ARG_TYPE,
|
||||||
ERR_INVALID_ARG_VALUE,
|
ERR_INVALID_ARG_VALUE,
|
||||||
@ -647,22 +646,16 @@ function stringToFlags(flags, name = 'flags') {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const stringToSymlinkType = hideStackFrames((type) => {
|
const stringToSymlinkType = hideStackFrames((type) => {
|
||||||
let flags = 0;
|
|
||||||
if (typeof type === 'string') {
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'dir':
|
case undefined:
|
||||||
flags |= UV_FS_SYMLINK_DIR;
|
case null:
|
||||||
break;
|
|
||||||
case 'junction':
|
|
||||||
flags |= UV_FS_SYMLINK_JUNCTION;
|
|
||||||
break;
|
|
||||||
case 'file':
|
case 'file':
|
||||||
break;
|
return 0;
|
||||||
default:
|
case 'dir':
|
||||||
throw new ERR_FS_INVALID_SYMLINK_TYPE(type);
|
return UV_FS_SYMLINK_DIR;
|
||||||
|
case 'junction':
|
||||||
|
return UV_FS_SYMLINK_JUNCTION;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return flags;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// converts Date or number to a fractional UNIX timestamp
|
// converts Date or number to a fractional UNIX timestamp
|
||||||
|
@ -76,14 +76,27 @@ fs.symlink(linkData, linkPath, common.mustSucceed(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const errObj = {
|
const errObj = {
|
||||||
code: 'ERR_FS_INVALID_SYMLINK_TYPE',
|
code: 'ERR_INVALID_ARG_VALUE',
|
||||||
name: 'Error',
|
name: 'TypeError',
|
||||||
message:
|
|
||||||
'Symlink type must be one of "dir", "file", or "junction". Received "🍏"'
|
|
||||||
};
|
};
|
||||||
assert.throws(() => fs.symlink('', '', '🍏', common.mustNotCall()), errObj);
|
assert.throws(() => fs.symlink('', '', '🍏', common.mustNotCall()), errObj);
|
||||||
assert.throws(() => fs.symlinkSync('', '', '🍏'), errObj);
|
assert.throws(() => fs.symlinkSync('', '', '🍏'), errObj);
|
||||||
|
|
||||||
|
assert.throws(() => fs.symlink('', '', 'nonExistentType', common.mustNotCall()), errObj);
|
||||||
|
assert.throws(() => fs.symlinkSync('', '', 'nonExistentType'), errObj);
|
||||||
|
assert.rejects(() => fs.promises.symlink('', '', 'nonExistentType'), errObj)
|
||||||
|
.then(common.mustCall());
|
||||||
|
|
||||||
|
assert.throws(() => fs.symlink('', '', false, common.mustNotCall()), errObj);
|
||||||
|
assert.throws(() => fs.symlinkSync('', '', false), errObj);
|
||||||
|
assert.rejects(() => fs.promises.symlink('', '', false), errObj)
|
||||||
|
.then(common.mustCall());
|
||||||
|
|
||||||
|
assert.throws(() => fs.symlink('', '', {}, common.mustNotCall()), errObj);
|
||||||
|
assert.throws(() => fs.symlinkSync('', '', {}), errObj);
|
||||||
|
assert.rejects(() => fs.promises.symlink('', '', {}), errObj)
|
||||||
|
.then(common.mustCall());
|
||||||
|
|
||||||
process.on('exit', () => {
|
process.on('exit', () => {
|
||||||
assert.notStrictEqual(linkTime, fileTime);
|
assert.notStrictEqual(linkTime, fileTime);
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user