fs: extract path conversion and validation to getValidatedPath
Almost all path validations within our file system are combined with: ```js path = toPathIfFileURL(path); validatePath(path); ``` So simply extracted them out into `getValidatedPath` function to `internal/fs/utils.js` to DRY up the code and reduce duplicating them. PR-URL: https://github.com/nodejs/node/pull/27656 Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Anto Aravinth <anto.aravinth.cse@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com>
This commit is contained in:
parent
4a18b87a3f
commit
23ef3e4cfb
145
lib/fs.js
145
lib/fs.js
@ -63,6 +63,7 @@ const {
|
|||||||
Dirent,
|
Dirent,
|
||||||
getDirents,
|
getDirents,
|
||||||
getOptions,
|
getOptions,
|
||||||
|
getValidatedPath,
|
||||||
nullCheck,
|
nullCheck,
|
||||||
preprocessSymlinkDestination,
|
preprocessSymlinkDestination,
|
||||||
Stats,
|
Stats,
|
||||||
@ -164,8 +165,7 @@ function access(path, mode, callback) {
|
|||||||
mode = F_OK;
|
mode = F_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
|
|
||||||
mode = mode | 0;
|
mode = mode | 0;
|
||||||
const req = new FSReqCallback();
|
const req = new FSReqCallback();
|
||||||
@ -174,8 +174,7 @@ function access(path, mode, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function accessSync(path, mode) {
|
function accessSync(path, mode) {
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
|
|
||||||
if (mode === undefined)
|
if (mode === undefined)
|
||||||
mode = F_OK;
|
mode = F_OK;
|
||||||
@ -215,8 +214,7 @@ Object.defineProperty(exists, internalUtil.promisify.custom, {
|
|||||||
// TODO(joyeecheung): deprecate the never-throw-on-invalid-arguments behavior
|
// TODO(joyeecheung): deprecate the never-throw-on-invalid-arguments behavior
|
||||||
function existsSync(path) {
|
function existsSync(path) {
|
||||||
try {
|
try {
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
} catch {
|
} catch {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -285,8 +283,7 @@ function readFile(path, options, callback) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
binding.open(pathModule.toNamespacedPath(path),
|
binding.open(pathModule.toNamespacedPath(path),
|
||||||
stringToFlags(options.flag || 'r'),
|
stringToFlags(options.flag || 'r'),
|
||||||
0o666,
|
0o666,
|
||||||
@ -397,8 +394,7 @@ function closeSync(fd) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function open(path, flags, mode, callback) {
|
function open(path, flags, mode, callback) {
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
if (arguments.length < 3) {
|
if (arguments.length < 3) {
|
||||||
callback = flags;
|
callback = flags;
|
||||||
flags = 'r';
|
flags = 'r';
|
||||||
@ -424,8 +420,7 @@ function open(path, flags, mode, callback) {
|
|||||||
|
|
||||||
|
|
||||||
function openSync(path, flags, mode) {
|
function openSync(path, flags, mode) {
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
const flagsNumber = stringToFlags(flags || 'r');
|
const flagsNumber = stringToFlags(flags || 'r');
|
||||||
mode = parseMode(mode, 'mode', 0o666);
|
mode = parseMode(mode, 'mode', 0o666);
|
||||||
|
|
||||||
@ -580,10 +575,8 @@ function writeSync(fd, buffer, offset, length, position) {
|
|||||||
|
|
||||||
function rename(oldPath, newPath, callback) {
|
function rename(oldPath, newPath, callback) {
|
||||||
callback = makeCallback(callback);
|
callback = makeCallback(callback);
|
||||||
oldPath = toPathIfFileURL(oldPath);
|
oldPath = getValidatedPath(oldPath, 'oldPath');
|
||||||
validatePath(oldPath, 'oldPath');
|
newPath = getValidatedPath(newPath, 'newPath');
|
||||||
newPath = toPathIfFileURL(newPath);
|
|
||||||
validatePath(newPath, 'newPath');
|
|
||||||
const req = new FSReqCallback();
|
const req = new FSReqCallback();
|
||||||
req.oncomplete = callback;
|
req.oncomplete = callback;
|
||||||
binding.rename(pathModule.toNamespacedPath(oldPath),
|
binding.rename(pathModule.toNamespacedPath(oldPath),
|
||||||
@ -592,10 +585,8 @@ function rename(oldPath, newPath, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function renameSync(oldPath, newPath) {
|
function renameSync(oldPath, newPath) {
|
||||||
oldPath = toPathIfFileURL(oldPath);
|
oldPath = getValidatedPath(oldPath, 'oldPath');
|
||||||
validatePath(oldPath, 'oldPath');
|
newPath = getValidatedPath(newPath, 'newPath');
|
||||||
newPath = toPathIfFileURL(newPath);
|
|
||||||
validatePath(newPath, 'newPath');
|
|
||||||
const ctx = { path: oldPath, dest: newPath };
|
const ctx = { path: oldPath, dest: newPath };
|
||||||
binding.rename(pathModule.toNamespacedPath(oldPath),
|
binding.rename(pathModule.toNamespacedPath(oldPath),
|
||||||
pathModule.toNamespacedPath(newPath), undefined, ctx);
|
pathModule.toNamespacedPath(newPath), undefined, ctx);
|
||||||
@ -673,16 +664,14 @@ function ftruncateSync(fd, len = 0) {
|
|||||||
|
|
||||||
function rmdir(path, callback) {
|
function rmdir(path, callback) {
|
||||||
callback = makeCallback(callback);
|
callback = makeCallback(callback);
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
const req = new FSReqCallback();
|
const req = new FSReqCallback();
|
||||||
req.oncomplete = callback;
|
req.oncomplete = callback;
|
||||||
binding.rmdir(pathModule.toNamespacedPath(path), req);
|
binding.rmdir(pathModule.toNamespacedPath(path), req);
|
||||||
}
|
}
|
||||||
|
|
||||||
function rmdirSync(path) {
|
function rmdirSync(path) {
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
const ctx = { path };
|
const ctx = { path };
|
||||||
binding.rmdir(pathModule.toNamespacedPath(path), undefined, ctx);
|
binding.rmdir(pathModule.toNamespacedPath(path), undefined, ctx);
|
||||||
handleErrorFromBinding(ctx);
|
handleErrorFromBinding(ctx);
|
||||||
@ -728,9 +717,8 @@ function mkdir(path, options, callback) {
|
|||||||
mode = 0o777
|
mode = 0o777
|
||||||
} = options || {};
|
} = options || {};
|
||||||
callback = makeCallback(callback);
|
callback = makeCallback(callback);
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
|
|
||||||
validatePath(path);
|
|
||||||
if (typeof recursive !== 'boolean')
|
if (typeof recursive !== 'boolean')
|
||||||
throw new ERR_INVALID_ARG_TYPE('recursive', 'boolean', recursive);
|
throw new ERR_INVALID_ARG_TYPE('recursive', 'boolean', recursive);
|
||||||
|
|
||||||
@ -744,13 +732,12 @@ function mkdirSync(path, options) {
|
|||||||
if (typeof options === 'number' || typeof options === 'string') {
|
if (typeof options === 'number' || typeof options === 'string') {
|
||||||
options = { mode: options };
|
options = { mode: options };
|
||||||
}
|
}
|
||||||
path = toPathIfFileURL(path);
|
|
||||||
const {
|
const {
|
||||||
recursive = false,
|
recursive = false,
|
||||||
mode = 0o777
|
mode = 0o777
|
||||||
} = options || {};
|
} = options || {};
|
||||||
|
|
||||||
validatePath(path);
|
path = getValidatedPath(path);
|
||||||
if (typeof recursive !== 'boolean')
|
if (typeof recursive !== 'boolean')
|
||||||
throw new ERR_INVALID_ARG_TYPE('recursive', 'boolean', recursive);
|
throw new ERR_INVALID_ARG_TYPE('recursive', 'boolean', recursive);
|
||||||
|
|
||||||
@ -764,8 +751,7 @@ function mkdirSync(path, options) {
|
|||||||
function readdir(path, options, callback) {
|
function readdir(path, options, callback) {
|
||||||
callback = makeCallback(typeof options === 'function' ? options : callback);
|
callback = makeCallback(typeof options === 'function' ? options : callback);
|
||||||
options = getOptions(options, {});
|
options = getOptions(options, {});
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
|
|
||||||
const req = new FSReqCallback();
|
const req = new FSReqCallback();
|
||||||
if (!options.withFileTypes) {
|
if (!options.withFileTypes) {
|
||||||
@ -785,8 +771,7 @@ function readdir(path, options, callback) {
|
|||||||
|
|
||||||
function readdirSync(path, options) {
|
function readdirSync(path, options) {
|
||||||
options = getOptions(options, {});
|
options = getOptions(options, {});
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
const ctx = { path };
|
const ctx = { path };
|
||||||
const result = binding.readdir(pathModule.toNamespacedPath(path),
|
const result = binding.readdir(pathModule.toNamespacedPath(path),
|
||||||
options.encoding, !!options.withFileTypes,
|
options.encoding, !!options.withFileTypes,
|
||||||
@ -812,8 +797,7 @@ function lstat(path, options, callback) {
|
|||||||
options = {};
|
options = {};
|
||||||
}
|
}
|
||||||
callback = makeStatsCallback(callback);
|
callback = makeStatsCallback(callback);
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
const req = new FSReqCallback(options.bigint);
|
const req = new FSReqCallback(options.bigint);
|
||||||
req.oncomplete = callback;
|
req.oncomplete = callback;
|
||||||
binding.lstat(pathModule.toNamespacedPath(path), options.bigint, req);
|
binding.lstat(pathModule.toNamespacedPath(path), options.bigint, req);
|
||||||
@ -825,8 +809,7 @@ function stat(path, options, callback) {
|
|||||||
options = {};
|
options = {};
|
||||||
}
|
}
|
||||||
callback = makeStatsCallback(callback);
|
callback = makeStatsCallback(callback);
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
const req = new FSReqCallback(options.bigint);
|
const req = new FSReqCallback(options.bigint);
|
||||||
req.oncomplete = callback;
|
req.oncomplete = callback;
|
||||||
binding.stat(pathModule.toNamespacedPath(path), options.bigint, req);
|
binding.stat(pathModule.toNamespacedPath(path), options.bigint, req);
|
||||||
@ -841,8 +824,7 @@ function fstatSync(fd, options = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function lstatSync(path, options = {}) {
|
function lstatSync(path, options = {}) {
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
const ctx = { path };
|
const ctx = { path };
|
||||||
const stats = binding.lstat(pathModule.toNamespacedPath(path),
|
const stats = binding.lstat(pathModule.toNamespacedPath(path),
|
||||||
options.bigint, undefined, ctx);
|
options.bigint, undefined, ctx);
|
||||||
@ -851,8 +833,7 @@ function lstatSync(path, options = {}) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function statSync(path, options = {}) {
|
function statSync(path, options = {}) {
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
const ctx = { path };
|
const ctx = { path };
|
||||||
const stats = binding.stat(pathModule.toNamespacedPath(path),
|
const stats = binding.stat(pathModule.toNamespacedPath(path),
|
||||||
options.bigint, undefined, ctx);
|
options.bigint, undefined, ctx);
|
||||||
@ -863,8 +844,7 @@ function statSync(path, options = {}) {
|
|||||||
function readlink(path, options, callback) {
|
function readlink(path, options, callback) {
|
||||||
callback = makeCallback(typeof options === 'function' ? options : callback);
|
callback = makeCallback(typeof options === 'function' ? options : callback);
|
||||||
options = getOptions(options, {});
|
options = getOptions(options, {});
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path, 'oldPath');
|
||||||
validatePath(path, 'oldPath');
|
|
||||||
const req = new FSReqCallback();
|
const req = new FSReqCallback();
|
||||||
req.oncomplete = callback;
|
req.oncomplete = callback;
|
||||||
binding.readlink(pathModule.toNamespacedPath(path), options.encoding, req);
|
binding.readlink(pathModule.toNamespacedPath(path), options.encoding, req);
|
||||||
@ -872,8 +852,7 @@ function readlink(path, options, callback) {
|
|||||||
|
|
||||||
function readlinkSync(path, options) {
|
function readlinkSync(path, options) {
|
||||||
options = getOptions(options, {});
|
options = getOptions(options, {});
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path, 'oldPath');
|
||||||
validatePath(path, 'oldPath');
|
|
||||||
const ctx = { path };
|
const ctx = { path };
|
||||||
const result = binding.readlink(pathModule.toNamespacedPath(path),
|
const result = binding.readlink(pathModule.toNamespacedPath(path),
|
||||||
options.encoding, undefined, ctx);
|
options.encoding, undefined, ctx);
|
||||||
@ -885,10 +864,8 @@ function symlink(target, path, type_, callback_) {
|
|||||||
const type = (typeof type_ === 'string' ? type_ : null);
|
const type = (typeof type_ === 'string' ? type_ : null);
|
||||||
const callback = makeCallback(arguments[arguments.length - 1]);
|
const callback = makeCallback(arguments[arguments.length - 1]);
|
||||||
|
|
||||||
target = toPathIfFileURL(target);
|
target = getValidatedPath(target, 'target');
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(target, 'target');
|
|
||||||
validatePath(path);
|
|
||||||
|
|
||||||
const req = new FSReqCallback();
|
const req = new FSReqCallback();
|
||||||
req.oncomplete = callback;
|
req.oncomplete = callback;
|
||||||
@ -931,10 +908,8 @@ function symlinkSync(target, path, type) {
|
|||||||
}
|
}
|
||||||
} catch { }
|
} catch { }
|
||||||
}
|
}
|
||||||
target = toPathIfFileURL(target);
|
target = getValidatedPath(target, 'target');
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(target, 'target');
|
|
||||||
validatePath(path);
|
|
||||||
const flags = stringToSymlinkType(type);
|
const flags = stringToSymlinkType(type);
|
||||||
|
|
||||||
const ctx = { path: target, dest: path };
|
const ctx = { path: target, dest: path };
|
||||||
@ -947,10 +922,8 @@ function symlinkSync(target, path, type) {
|
|||||||
function link(existingPath, newPath, callback) {
|
function link(existingPath, newPath, callback) {
|
||||||
callback = makeCallback(callback);
|
callback = makeCallback(callback);
|
||||||
|
|
||||||
existingPath = toPathIfFileURL(existingPath);
|
existingPath = getValidatedPath(existingPath, 'existingPath');
|
||||||
newPath = toPathIfFileURL(newPath);
|
newPath = getValidatedPath(newPath, 'newPath');
|
||||||
validatePath(existingPath, 'existingPath');
|
|
||||||
validatePath(newPath, 'newPath');
|
|
||||||
|
|
||||||
const req = new FSReqCallback();
|
const req = new FSReqCallback();
|
||||||
req.oncomplete = callback;
|
req.oncomplete = callback;
|
||||||
@ -961,10 +934,8 @@ function link(existingPath, newPath, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function linkSync(existingPath, newPath) {
|
function linkSync(existingPath, newPath) {
|
||||||
existingPath = toPathIfFileURL(existingPath);
|
existingPath = getValidatedPath(existingPath, 'existingPath');
|
||||||
newPath = toPathIfFileURL(newPath);
|
newPath = getValidatedPath(newPath, 'newPath');
|
||||||
validatePath(existingPath, 'existingPath');
|
|
||||||
validatePath(newPath, 'newPath');
|
|
||||||
|
|
||||||
const ctx = { path: existingPath, dest: newPath };
|
const ctx = { path: existingPath, dest: newPath };
|
||||||
const result = binding.link(pathModule.toNamespacedPath(existingPath),
|
const result = binding.link(pathModule.toNamespacedPath(existingPath),
|
||||||
@ -976,16 +947,14 @@ function linkSync(existingPath, newPath) {
|
|||||||
|
|
||||||
function unlink(path, callback) {
|
function unlink(path, callback) {
|
||||||
callback = makeCallback(callback);
|
callback = makeCallback(callback);
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
const req = new FSReqCallback();
|
const req = new FSReqCallback();
|
||||||
req.oncomplete = callback;
|
req.oncomplete = callback;
|
||||||
binding.unlink(pathModule.toNamespacedPath(path), req);
|
binding.unlink(pathModule.toNamespacedPath(path), req);
|
||||||
}
|
}
|
||||||
|
|
||||||
function unlinkSync(path) {
|
function unlinkSync(path) {
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
const ctx = { path };
|
const ctx = { path };
|
||||||
binding.unlink(pathModule.toNamespacedPath(path), undefined, ctx);
|
binding.unlink(pathModule.toNamespacedPath(path), undefined, ctx);
|
||||||
handleErrorFromBinding(ctx);
|
handleErrorFromBinding(ctx);
|
||||||
@ -1042,8 +1011,7 @@ function lchmodSync(path, mode) {
|
|||||||
|
|
||||||
|
|
||||||
function chmod(path, mode, callback) {
|
function chmod(path, mode, callback) {
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
mode = parseMode(mode, 'mode');
|
mode = parseMode(mode, 'mode');
|
||||||
callback = makeCallback(callback);
|
callback = makeCallback(callback);
|
||||||
|
|
||||||
@ -1053,8 +1021,7 @@ function chmod(path, mode, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function chmodSync(path, mode) {
|
function chmodSync(path, mode) {
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
mode = parseMode(mode, 'mode');
|
mode = parseMode(mode, 'mode');
|
||||||
|
|
||||||
const ctx = { path };
|
const ctx = { path };
|
||||||
@ -1064,8 +1031,7 @@ function chmodSync(path, mode) {
|
|||||||
|
|
||||||
function lchown(path, uid, gid, callback) {
|
function lchown(path, uid, gid, callback) {
|
||||||
callback = makeCallback(callback);
|
callback = makeCallback(callback);
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
validateUint32(uid, 'uid');
|
validateUint32(uid, 'uid');
|
||||||
validateUint32(gid, 'gid');
|
validateUint32(gid, 'gid');
|
||||||
const req = new FSReqCallback();
|
const req = new FSReqCallback();
|
||||||
@ -1074,8 +1040,7 @@ function lchown(path, uid, gid, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function lchownSync(path, uid, gid) {
|
function lchownSync(path, uid, gid) {
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
validateUint32(uid, 'uid');
|
validateUint32(uid, 'uid');
|
||||||
validateUint32(gid, 'gid');
|
validateUint32(gid, 'gid');
|
||||||
const ctx = { path };
|
const ctx = { path };
|
||||||
@ -1105,8 +1070,7 @@ function fchownSync(fd, uid, gid) {
|
|||||||
|
|
||||||
function chown(path, uid, gid, callback) {
|
function chown(path, uid, gid, callback) {
|
||||||
callback = makeCallback(callback);
|
callback = makeCallback(callback);
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
validateUint32(uid, 'uid');
|
validateUint32(uid, 'uid');
|
||||||
validateUint32(gid, 'gid');
|
validateUint32(gid, 'gid');
|
||||||
|
|
||||||
@ -1116,8 +1080,7 @@ function chown(path, uid, gid, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function chownSync(path, uid, gid) {
|
function chownSync(path, uid, gid) {
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
validateUint32(uid, 'uid');
|
validateUint32(uid, 'uid');
|
||||||
validateUint32(gid, 'gid');
|
validateUint32(gid, 'gid');
|
||||||
const ctx = { path };
|
const ctx = { path };
|
||||||
@ -1127,8 +1090,7 @@ function chownSync(path, uid, gid) {
|
|||||||
|
|
||||||
function utimes(path, atime, mtime, callback) {
|
function utimes(path, atime, mtime, callback) {
|
||||||
callback = makeCallback(callback);
|
callback = makeCallback(callback);
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
|
|
||||||
const req = new FSReqCallback();
|
const req = new FSReqCallback();
|
||||||
req.oncomplete = callback;
|
req.oncomplete = callback;
|
||||||
@ -1139,8 +1101,7 @@ function utimes(path, atime, mtime, callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function utimesSync(path, atime, mtime) {
|
function utimesSync(path, atime, mtime) {
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
const ctx = { path };
|
const ctx = { path };
|
||||||
binding.utimes(pathModule.toNamespacedPath(path),
|
binding.utimes(pathModule.toNamespacedPath(path),
|
||||||
toUnixTimestamp(atime), toUnixTimestamp(mtime),
|
toUnixTimestamp(atime), toUnixTimestamp(mtime),
|
||||||
@ -1306,8 +1267,7 @@ function watch(filename, options, listener) {
|
|||||||
const statWatchers = new Map();
|
const statWatchers = new Map();
|
||||||
|
|
||||||
function watchFile(filename, options, listener) {
|
function watchFile(filename, options, listener) {
|
||||||
filename = toPathIfFileURL(filename);
|
filename = getValidatedPath(filename);
|
||||||
validatePath(filename);
|
|
||||||
filename = pathModule.resolve(filename);
|
filename = pathModule.resolve(filename);
|
||||||
let stat;
|
let stat;
|
||||||
|
|
||||||
@ -1344,8 +1304,7 @@ function watchFile(filename, options, listener) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function unwatchFile(filename, listener) {
|
function unwatchFile(filename, listener) {
|
||||||
filename = toPathIfFileURL(filename);
|
filename = getValidatedPath(filename);
|
||||||
validatePath(filename);
|
|
||||||
filename = pathModule.resolve(filename);
|
filename = pathModule.resolve(filename);
|
||||||
const stat = statWatchers.get(filename);
|
const stat = statWatchers.get(filename);
|
||||||
|
|
||||||
@ -1548,8 +1507,7 @@ function realpathSync(p, options) {
|
|||||||
|
|
||||||
realpathSync.native = (path, options) => {
|
realpathSync.native = (path, options) => {
|
||||||
options = getOptions(options, {});
|
options = getOptions(options, {});
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
const ctx = { path };
|
const ctx = { path };
|
||||||
const result = binding.realpath(path, options.encoding, undefined, ctx);
|
const result = binding.realpath(path, options.encoding, undefined, ctx);
|
||||||
handleErrorFromBinding(ctx);
|
handleErrorFromBinding(ctx);
|
||||||
@ -1690,8 +1648,7 @@ function realpath(p, options, callback) {
|
|||||||
realpath.native = (path, options, callback) => {
|
realpath.native = (path, options, callback) => {
|
||||||
callback = makeCallback(callback || options);
|
callback = makeCallback(callback || options);
|
||||||
options = getOptions(options, {});
|
options = getOptions(options, {});
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
const req = new FSReqCallback();
|
const req = new FSReqCallback();
|
||||||
req.oncomplete = callback;
|
req.oncomplete = callback;
|
||||||
return binding.realpath(path, options.encoding, req);
|
return binding.realpath(path, options.encoding, req);
|
||||||
@ -1735,10 +1692,8 @@ function copyFile(src, dest, flags, callback) {
|
|||||||
throw new ERR_INVALID_CALLBACK(callback);
|
throw new ERR_INVALID_CALLBACK(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
src = toPathIfFileURL(src);
|
src = getValidatedPath(src, 'src');
|
||||||
dest = toPathIfFileURL(dest);
|
dest = getValidatedPath(dest, 'dest');
|
||||||
validatePath(src, 'src');
|
|
||||||
validatePath(dest, 'dest');
|
|
||||||
|
|
||||||
src = pathModule._makeLong(src);
|
src = pathModule._makeLong(src);
|
||||||
dest = pathModule._makeLong(dest);
|
dest = pathModule._makeLong(dest);
|
||||||
@ -1750,10 +1705,8 @@ function copyFile(src, dest, flags, callback) {
|
|||||||
|
|
||||||
|
|
||||||
function copyFileSync(src, dest, flags) {
|
function copyFileSync(src, dest, flags) {
|
||||||
src = toPathIfFileURL(src);
|
src = getValidatedPath(src, 'src');
|
||||||
dest = toPathIfFileURL(dest);
|
dest = getValidatedPath(dest, 'dest');
|
||||||
validatePath(src, 'src');
|
|
||||||
validatePath(dest, 'dest');
|
|
||||||
|
|
||||||
const ctx = { path: src, dest }; // non-prefixed
|
const ctx = { path: src, dest }; // non-prefixed
|
||||||
|
|
||||||
|
@ -17,13 +17,13 @@ const {
|
|||||||
ERR_INVALID_ARG_VALUE,
|
ERR_INVALID_ARG_VALUE,
|
||||||
ERR_METHOD_NOT_IMPLEMENTED
|
ERR_METHOD_NOT_IMPLEMENTED
|
||||||
} = require('internal/errors').codes;
|
} = require('internal/errors').codes;
|
||||||
const { toPathIfFileURL } = require('internal/url');
|
|
||||||
const { isUint8Array } = require('internal/util/types');
|
const { isUint8Array } = require('internal/util/types');
|
||||||
const {
|
const {
|
||||||
copyObject,
|
copyObject,
|
||||||
getDirents,
|
getDirents,
|
||||||
getOptions,
|
getOptions,
|
||||||
getStatsFromBinding,
|
getStatsFromBinding,
|
||||||
|
getValidatedPath,
|
||||||
nullCheck,
|
nullCheck,
|
||||||
preprocessSymlinkDestination,
|
preprocessSymlinkDestination,
|
||||||
stringToFlags,
|
stringToFlags,
|
||||||
@ -31,7 +31,6 @@ const {
|
|||||||
toUnixTimestamp,
|
toUnixTimestamp,
|
||||||
validateOffsetLengthRead,
|
validateOffsetLengthRead,
|
||||||
validateOffsetLengthWrite,
|
validateOffsetLengthWrite,
|
||||||
validatePath,
|
|
||||||
warnOnNonPortableTemplate
|
warnOnNonPortableTemplate
|
||||||
} = require('internal/fs/utils');
|
} = require('internal/fs/utils');
|
||||||
const {
|
const {
|
||||||
@ -175,8 +174,7 @@ async function readFileHandle(filehandle, options) {
|
|||||||
// All of the functions are defined as async in order to ensure that errors
|
// All of the functions are defined as async in order to ensure that errors
|
||||||
// thrown cause promise rejections rather than being thrown synchronously.
|
// thrown cause promise rejections rather than being thrown synchronously.
|
||||||
async function access(path, mode = F_OK) {
|
async function access(path, mode = F_OK) {
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
|
|
||||||
mode = mode | 0;
|
mode = mode | 0;
|
||||||
return binding.access(pathModule.toNamespacedPath(path), mode,
|
return binding.access(pathModule.toNamespacedPath(path), mode,
|
||||||
@ -184,10 +182,8 @@ async function access(path, mode = F_OK) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function copyFile(src, dest, flags) {
|
async function copyFile(src, dest, flags) {
|
||||||
src = toPathIfFileURL(src);
|
src = getValidatedPath(src, 'src');
|
||||||
dest = toPathIfFileURL(dest);
|
dest = getValidatedPath(dest, 'dest');
|
||||||
validatePath(src, 'src');
|
|
||||||
validatePath(dest, 'dest');
|
|
||||||
flags = flags | 0;
|
flags = flags | 0;
|
||||||
return binding.copyFile(pathModule.toNamespacedPath(src),
|
return binding.copyFile(pathModule.toNamespacedPath(src),
|
||||||
pathModule.toNamespacedPath(dest),
|
pathModule.toNamespacedPath(dest),
|
||||||
@ -197,8 +193,7 @@ async function copyFile(src, dest, flags) {
|
|||||||
// Note that unlike fs.open() which uses numeric file descriptors,
|
// Note that unlike fs.open() which uses numeric file descriptors,
|
||||||
// fsPromises.open() uses the fs.FileHandle class.
|
// fsPromises.open() uses the fs.FileHandle class.
|
||||||
async function open(path, flags, mode) {
|
async function open(path, flags, mode) {
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
if (arguments.length < 2) flags = 'r';
|
if (arguments.length < 2) flags = 'r';
|
||||||
const flagsNumber = stringToFlags(flags);
|
const flagsNumber = stringToFlags(flags);
|
||||||
mode = parseMode(mode, 'mode', 0o666);
|
mode = parseMode(mode, 'mode', 0o666);
|
||||||
@ -261,10 +256,8 @@ async function write(handle, buffer, offset, length, position) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function rename(oldPath, newPath) {
|
async function rename(oldPath, newPath) {
|
||||||
oldPath = toPathIfFileURL(oldPath);
|
oldPath = getValidatedPath(oldPath, 'oldPath');
|
||||||
newPath = toPathIfFileURL(newPath);
|
newPath = getValidatedPath(newPath, 'newPath');
|
||||||
validatePath(oldPath, 'oldPath');
|
|
||||||
validatePath(newPath, 'newPath');
|
|
||||||
return binding.rename(pathModule.toNamespacedPath(oldPath),
|
return binding.rename(pathModule.toNamespacedPath(oldPath),
|
||||||
pathModule.toNamespacedPath(newPath),
|
pathModule.toNamespacedPath(newPath),
|
||||||
kUsePromises);
|
kUsePromises);
|
||||||
@ -282,8 +275,7 @@ async function ftruncate(handle, len = 0) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function rmdir(path) {
|
async function rmdir(path) {
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
return binding.rmdir(pathModule.toNamespacedPath(path), kUsePromises);
|
return binding.rmdir(pathModule.toNamespacedPath(path), kUsePromises);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,9 +297,7 @@ async function mkdir(path, options) {
|
|||||||
recursive = false,
|
recursive = false,
|
||||||
mode = 0o777
|
mode = 0o777
|
||||||
} = options || {};
|
} = options || {};
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
|
|
||||||
validatePath(path);
|
|
||||||
if (typeof recursive !== 'boolean')
|
if (typeof recursive !== 'boolean')
|
||||||
throw new ERR_INVALID_ARG_TYPE('recursive', 'boolean', recursive);
|
throw new ERR_INVALID_ARG_TYPE('recursive', 'boolean', recursive);
|
||||||
|
|
||||||
@ -318,8 +308,7 @@ async function mkdir(path, options) {
|
|||||||
|
|
||||||
async function readdir(path, options) {
|
async function readdir(path, options) {
|
||||||
options = getOptions(options, {});
|
options = getOptions(options, {});
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
const result = await binding.readdir(pathModule.toNamespacedPath(path),
|
const result = await binding.readdir(pathModule.toNamespacedPath(path),
|
||||||
options.encoding,
|
options.encoding,
|
||||||
!!options.withFileTypes,
|
!!options.withFileTypes,
|
||||||
@ -331,18 +320,15 @@ async function readdir(path, options) {
|
|||||||
|
|
||||||
async function readlink(path, options) {
|
async function readlink(path, options) {
|
||||||
options = getOptions(options, {});
|
options = getOptions(options, {});
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path, 'oldPath');
|
||||||
validatePath(path, 'oldPath');
|
|
||||||
return binding.readlink(pathModule.toNamespacedPath(path),
|
return binding.readlink(pathModule.toNamespacedPath(path),
|
||||||
options.encoding, kUsePromises);
|
options.encoding, kUsePromises);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function symlink(target, path, type_) {
|
async function symlink(target, path, type_) {
|
||||||
const type = (typeof type_ === 'string' ? type_ : null);
|
const type = (typeof type_ === 'string' ? type_ : null);
|
||||||
target = toPathIfFileURL(target);
|
target = getValidatedPath(target, 'target');
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(target, 'target');
|
|
||||||
validatePath(path);
|
|
||||||
return binding.symlink(preprocessSymlinkDestination(target, type, path),
|
return binding.symlink(preprocessSymlinkDestination(target, type, path),
|
||||||
pathModule.toNamespacedPath(path),
|
pathModule.toNamespacedPath(path),
|
||||||
stringToSymlinkType(type),
|
stringToSymlinkType(type),
|
||||||
@ -356,34 +342,29 @@ async function fstat(handle, options = { bigint: false }) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function lstat(path, options = { bigint: false }) {
|
async function lstat(path, options = { bigint: false }) {
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
const result = await binding.lstat(pathModule.toNamespacedPath(path),
|
const result = await binding.lstat(pathModule.toNamespacedPath(path),
|
||||||
options.bigint, kUsePromises);
|
options.bigint, kUsePromises);
|
||||||
return getStatsFromBinding(result);
|
return getStatsFromBinding(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function stat(path, options = { bigint: false }) {
|
async function stat(path, options = { bigint: false }) {
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
const result = await binding.stat(pathModule.toNamespacedPath(path),
|
const result = await binding.stat(pathModule.toNamespacedPath(path),
|
||||||
options.bigint, kUsePromises);
|
options.bigint, kUsePromises);
|
||||||
return getStatsFromBinding(result);
|
return getStatsFromBinding(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function link(existingPath, newPath) {
|
async function link(existingPath, newPath) {
|
||||||
existingPath = toPathIfFileURL(existingPath);
|
existingPath = getValidatedPath(existingPath, 'existingPath');
|
||||||
newPath = toPathIfFileURL(newPath);
|
newPath = getValidatedPath(newPath, 'newPath');
|
||||||
validatePath(existingPath, 'existingPath');
|
|
||||||
validatePath(newPath, 'newPath');
|
|
||||||
return binding.link(pathModule.toNamespacedPath(existingPath),
|
return binding.link(pathModule.toNamespacedPath(existingPath),
|
||||||
pathModule.toNamespacedPath(newPath),
|
pathModule.toNamespacedPath(newPath),
|
||||||
kUsePromises);
|
kUsePromises);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function unlink(path) {
|
async function unlink(path) {
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
return binding.unlink(pathModule.toNamespacedPath(path), kUsePromises);
|
return binding.unlink(pathModule.toNamespacedPath(path), kUsePromises);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,8 +375,7 @@ async function fchmod(handle, mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function chmod(path, mode) {
|
async function chmod(path, mode) {
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
mode = parseMode(mode, 'mode');
|
mode = parseMode(mode, 'mode');
|
||||||
return binding.chmod(pathModule.toNamespacedPath(path), mode, kUsePromises);
|
return binding.chmod(pathModule.toNamespacedPath(path), mode, kUsePromises);
|
||||||
}
|
}
|
||||||
@ -409,8 +389,7 @@ async function lchmod(path, mode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function lchown(path, uid, gid) {
|
async function lchown(path, uid, gid) {
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
validateUint32(uid, 'uid');
|
validateUint32(uid, 'uid');
|
||||||
validateUint32(gid, 'gid');
|
validateUint32(gid, 'gid');
|
||||||
return binding.lchown(pathModule.toNamespacedPath(path),
|
return binding.lchown(pathModule.toNamespacedPath(path),
|
||||||
@ -425,8 +404,7 @@ async function fchown(handle, uid, gid) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function chown(path, uid, gid) {
|
async function chown(path, uid, gid) {
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
validateUint32(uid, 'uid');
|
validateUint32(uid, 'uid');
|
||||||
validateUint32(gid, 'gid');
|
validateUint32(gid, 'gid');
|
||||||
return binding.chown(pathModule.toNamespacedPath(path),
|
return binding.chown(pathModule.toNamespacedPath(path),
|
||||||
@ -434,8 +412,7 @@ async function chown(path, uid, gid) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function utimes(path, atime, mtime) {
|
async function utimes(path, atime, mtime) {
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
return binding.utimes(pathModule.toNamespacedPath(path),
|
return binding.utimes(pathModule.toNamespacedPath(path),
|
||||||
toUnixTimestamp(atime),
|
toUnixTimestamp(atime),
|
||||||
toUnixTimestamp(mtime),
|
toUnixTimestamp(mtime),
|
||||||
@ -451,8 +428,7 @@ async function futimes(handle, atime, mtime) {
|
|||||||
|
|
||||||
async function realpath(path, options) {
|
async function realpath(path, options) {
|
||||||
options = getOptions(options, {});
|
options = getOptions(options, {});
|
||||||
path = toPathIfFileURL(path);
|
path = getValidatedPath(path);
|
||||||
validatePath(path);
|
|
||||||
return binding.realpath(path, options.encoding, kUsePromises);
|
return binding.realpath(path, options.encoding, kUsePromises);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ const {
|
|||||||
isDate
|
isDate
|
||||||
} = require('internal/util/types');
|
} = require('internal/util/types');
|
||||||
const { once } = require('internal/util');
|
const { once } = require('internal/util');
|
||||||
|
const { toPathIfFileURL } = require('internal/url');
|
||||||
const pathModule = require('path');
|
const pathModule = require('path');
|
||||||
const kType = Symbol('type');
|
const kType = Symbol('type');
|
||||||
const kStats = Symbol('stats');
|
const kStats = Symbol('stats');
|
||||||
@ -433,6 +434,12 @@ const validatePath = hideStackFrames((path, propName = 'path') => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const getValidatedPath = hideStackFrames((fileURLOrPath, propName = 'path') => {
|
||||||
|
const path = toPathIfFileURL(fileURLOrPath);
|
||||||
|
validatePath(path, propName);
|
||||||
|
return path;
|
||||||
|
});
|
||||||
|
|
||||||
let nonPortableTemplateWarn = true;
|
let nonPortableTemplateWarn = true;
|
||||||
|
|
||||||
function warnOnNonPortableTemplate(template) {
|
function warnOnNonPortableTemplate(template) {
|
||||||
@ -470,6 +477,7 @@ module.exports = {
|
|||||||
Dirent,
|
Dirent,
|
||||||
getDirents,
|
getDirents,
|
||||||
getOptions,
|
getOptions,
|
||||||
|
getValidatedPath,
|
||||||
nullCheck,
|
nullCheck,
|
||||||
preprocessSymlinkDestination,
|
preprocessSymlinkDestination,
|
||||||
realpathCacheKey: Symbol('realpathCacheKey'),
|
realpathCacheKey: Symbol('realpathCacheKey'),
|
||||||
|
@ -12,7 +12,7 @@ const { UV_ENOSPC } = internalBinding('uv');
|
|||||||
const { EventEmitter } = require('events');
|
const { EventEmitter } = require('events');
|
||||||
const {
|
const {
|
||||||
getStatsFromBinding,
|
getStatsFromBinding,
|
||||||
validatePath
|
getValidatedPath
|
||||||
} = require('internal/fs/utils');
|
} = require('internal/fs/utils');
|
||||||
const {
|
const {
|
||||||
defaultTriggerAsyncIdScope,
|
defaultTriggerAsyncIdScope,
|
||||||
@ -20,7 +20,6 @@ const {
|
|||||||
} = require('internal/async_hooks');
|
} = require('internal/async_hooks');
|
||||||
const { toNamespacedPath } = require('path');
|
const { toNamespacedPath } = require('path');
|
||||||
const { validateUint32 } = require('internal/validators');
|
const { validateUint32 } = require('internal/validators');
|
||||||
const { toPathIfFileURL } = require('internal/url');
|
|
||||||
const assert = require('internal/assert');
|
const assert = require('internal/assert');
|
||||||
|
|
||||||
const kOldStatus = Symbol('kOldStatus');
|
const kOldStatus = Symbol('kOldStatus');
|
||||||
@ -73,8 +72,7 @@ StatWatcher.prototype.start = function(filename, persistent, interval) {
|
|||||||
// the sake of backwards compatibility
|
// the sake of backwards compatibility
|
||||||
this[kOldStatus] = -1;
|
this[kOldStatus] = -1;
|
||||||
|
|
||||||
filename = toPathIfFileURL(filename);
|
filename = getValidatedPath(filename, 'filename');
|
||||||
validatePath(filename, 'filename');
|
|
||||||
validateUint32(interval, 'interval');
|
validateUint32(interval, 'interval');
|
||||||
const err = this._handle.start(toNamespacedPath(filename), interval);
|
const err = this._handle.start(toNamespacedPath(filename), interval);
|
||||||
if (err) {
|
if (err) {
|
||||||
@ -157,8 +155,7 @@ FSWatcher.prototype.start = function(filename,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
filename = toPathIfFileURL(filename);
|
filename = getValidatedPath(filename, 'filename');
|
||||||
validatePath(filename, 'filename');
|
|
||||||
|
|
||||||
const err = this._handle.start(toNamespacedPath(filename),
|
const err = this._handle.start(toNamespacedPath(filename),
|
||||||
persistent,
|
persistent,
|
||||||
|
@ -25,8 +25,7 @@ const {
|
|||||||
const assert = require('internal/assert');
|
const assert = require('internal/assert');
|
||||||
const { copy } = internalBinding('buffer');
|
const { copy } = internalBinding('buffer');
|
||||||
const { FastBuffer } = require('internal/buffer');
|
const { FastBuffer } = require('internal/buffer');
|
||||||
const { toPathIfFileURL } = require('internal/url');
|
const { getValidatedPath } = require('internal/fs/utils');
|
||||||
const { validatePath } = require('internal/fs/utils');
|
|
||||||
const { toNamespacedPath } = require('path');
|
const { toNamespacedPath } = require('path');
|
||||||
const {
|
const {
|
||||||
createHeapSnapshotStream,
|
createHeapSnapshotStream,
|
||||||
@ -43,8 +42,7 @@ const kHandle = Symbol('kHandle');
|
|||||||
|
|
||||||
function writeHeapSnapshot(filename) {
|
function writeHeapSnapshot(filename) {
|
||||||
if (filename !== undefined) {
|
if (filename !== undefined) {
|
||||||
filename = toPathIfFileURL(filename);
|
filename = getValidatedPath(filename);
|
||||||
validatePath(filename);
|
|
||||||
filename = toNamespacedPath(filename);
|
filename = toNamespacedPath(filename);
|
||||||
}
|
}
|
||||||
return triggerHeapSnapshot(filename);
|
return triggerHeapSnapshot(filename);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user