diff --git a/lib/fs.js b/lib/fs.js index d1280d20718569..2bb629d58af081 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -89,6 +89,7 @@ const { Dirent, getDirents, getOptions, + getValidatedFd, getValidatedPath, getValidMode, handleErrorFromBinding, @@ -128,7 +129,6 @@ const { validateCallback, validateFunction, validateInteger, - validateInt32, } = require('internal/validators'); // 2 ** 32 - 1 const kMaxUserId = 4294967295; @@ -443,7 +443,7 @@ function defaultCloseCallback(err) { } function close(fd, callback = defaultCloseCallback) { - validateInt32(fd, 'fd', 0); + fd = getValidatedFd(fd); if (callback !== defaultCloseCallback) callback = makeCallback(callback); @@ -453,7 +453,7 @@ function close(fd, callback = defaultCloseCallback) { } function closeSync(fd) { - validateInt32(fd, 'fd', 0); + fd = getValidatedFd(fd); const ctx = {}; binding.close(fd, undefined, ctx); @@ -503,7 +503,7 @@ function openSync(path, flags, mode) { // OR // fs.read(fd, {}, callback) function read(fd, buffer, offset, length, position, callback) { - validateInt32(fd, 'fd', 0); + fd = getValidatedFd(fd); if (arguments.length <= 3) { // Assume fs.read(fd, options, callback) @@ -576,7 +576,7 @@ ObjectDefineProperty(read, internalUtil.customPromisifyArgs, // OR // fs.readSync(fd, buffer, {}) or fs.readSync(fd, buffer) function readSync(fd, buffer, offset, length, position) { - validateInt32(fd, 'fd', 0); + fd = getValidatedFd(fd); if (arguments.length <= 3) { // Assume fs.read(fd, buffer, options) @@ -623,7 +623,7 @@ function readv(fd, buffers, position, callback) { callback(err, read || 0, buffers); } - validateInt32(fd, 'fd', /* min */ 0); + fd = getValidatedFd(fd); validateBufferArray(buffers); callback = maybeCallback(callback || position); @@ -640,7 +640,7 @@ ObjectDefineProperty(readv, internalUtil.customPromisifyArgs, { value: ['bytesRead', 'buffers'], enumerable: false }); function readvSync(fd, buffers, position) { - validateInt32(fd, 'fd', 0); + fd = getValidatedFd(fd); validateBufferArray(buffers); const ctx = {}; @@ -663,7 +663,7 @@ function write(fd, buffer, offset, length, position, callback) { callback(err, written || 0, buffer); } - validateInt32(fd, 'fd', 0); + fd = getValidatedFd(fd); if (isArrayBufferView(buffer)) { callback = maybeCallback(callback || position || length || offset); @@ -709,7 +709,7 @@ ObjectDefineProperty(write, internalUtil.customPromisifyArgs, // OR // fs.writeSync(fd, string[, position[, encoding]]); function writeSync(fd, buffer, offset, length, position) { - validateInt32(fd, 'fd', 0); + fd = getValidatedFd(fd); const ctx = {}; let result; if (isArrayBufferView(buffer)) { @@ -744,7 +744,7 @@ function writev(fd, buffers, position, callback) { callback(err, written || 0, buffers); } - validateInt32(fd, 'fd', 0); + fd = getValidatedFd(fd); validateBufferArray(buffers); callback = maybeCallback(callback || position); @@ -763,7 +763,7 @@ ObjectDefineProperty(writev, internalUtil.customPromisifyArgs, { }); function writevSync(fd, buffers, position) { - validateInt32(fd, 'fd', 0); + fd = getValidatedFd(fd); validateBufferArray(buffers); const ctx = {}; @@ -849,7 +849,7 @@ function ftruncate(fd, len = 0, callback) { callback = len; len = 0; } - validateInt32(fd, 'fd', 0); + fd = getValidatedFd(fd); validateInteger(len, 'len'); len = MathMax(0, len); callback = makeCallback(callback); @@ -860,7 +860,7 @@ function ftruncate(fd, len = 0, callback) { } function ftruncateSync(fd, len = 0) { - validateInt32(fd, 'fd', 0); + fd = getValidatedFd(fd); validateInteger(len, 'len'); len = MathMax(0, len); const ctx = {}; @@ -942,28 +942,28 @@ function rmSync(path, options) { } function fdatasync(fd, callback) { - validateInt32(fd, 'fd', 0); + fd = getValidatedFd(fd); const req = new FSReqCallback(); req.oncomplete = makeCallback(callback); binding.fdatasync(fd, req); } function fdatasyncSync(fd) { - validateInt32(fd, 'fd', 0); + fd = getValidatedFd(fd); const ctx = {}; binding.fdatasync(fd, undefined, ctx); handleErrorFromBinding(ctx); } function fsync(fd, callback) { - validateInt32(fd, 'fd', 0); + fd = getValidatedFd(fd); const req = new FSReqCallback(); req.oncomplete = makeCallback(callback); binding.fsync(fd, req); } function fsyncSync(fd) { - validateInt32(fd, 'fd', 0); + fd = getValidatedFd(fd); const ctx = {}; binding.fsync(fd, undefined, ctx); handleErrorFromBinding(ctx); @@ -1054,7 +1054,7 @@ function fstat(fd, options = { bigint: false }, callback) { callback = options; options = {}; } - validateInt32(fd, 'fd', 0); + fd = getValidatedFd(fd); callback = makeStatsCallback(callback); const req = new FSReqCallback(options.bigint); @@ -1102,7 +1102,7 @@ function hasNoEntryError(ctx) { } function fstatSync(fd, options = { bigint: false, throwIfNoEntry: true }) { - validateInt32(fd, 'fd', 0); + fd = getValidatedFd(fd); const ctx = { fd }; const stats = binding.fstat(fd, options.bigint, undefined, ctx); handleErrorFromBinding(ctx); @@ -1255,7 +1255,7 @@ function unlinkSync(path) { } function fchmod(fd, mode, callback) { - validateInt32(fd, 'fd', 0); + fd = getValidatedFd(fd); mode = parseFileMode(mode, 'mode'); callback = makeCallback(callback); @@ -1265,7 +1265,7 @@ function fchmod(fd, mode, callback) { } function fchmodSync(fd, mode) { - validateInt32(fd, 'fd', 0); + fd = getValidatedFd(fd); mode = parseFileMode(mode, 'mode'); const ctx = {}; binding.fchmod(fd, mode, undefined, ctx); @@ -1343,7 +1343,7 @@ function lchownSync(path, uid, gid) { } function fchown(fd, uid, gid, callback) { - validateInt32(fd, 'fd', 0); + fd = getValidatedFd(fd); validateInteger(uid, 'uid', -1, kMaxUserId); validateInteger(gid, 'gid', -1, kMaxUserId); callback = makeCallback(callback); @@ -1354,7 +1354,7 @@ function fchown(fd, uid, gid, callback) { } function fchownSync(fd, uid, gid) { - validateInt32(fd, 'fd', 0); + fd = getValidatedFd(fd); validateInteger(uid, 'uid', -1, kMaxUserId); validateInteger(gid, 'gid', -1, kMaxUserId); @@ -1405,7 +1405,7 @@ function utimesSync(path, atime, mtime) { } function futimes(fd, atime, mtime, callback) { - validateInt32(fd, 'fd', 0); + fd = getValidatedFd(fd); atime = toUnixTimestamp(atime, 'atime'); mtime = toUnixTimestamp(mtime, 'mtime'); callback = makeCallback(callback); @@ -1416,7 +1416,7 @@ function futimes(fd, atime, mtime, callback) { } function futimesSync(fd, atime, mtime) { - validateInt32(fd, 'fd', 0); + fd = getValidatedFd(fd); atime = toUnixTimestamp(atime, 'atime'); mtime = toUnixTimestamp(mtime, 'mtime'); const ctx = {}; diff --git a/lib/internal/fs/utils.js b/lib/internal/fs/utils.js index 41b74ce652137a..842c5266c6f677 100644 --- a/lib/internal/fs/utils.js +++ b/lib/internal/fs/utils.js @@ -12,6 +12,7 @@ const { NumberIsFinite, NumberIsInteger, MathMin, + ObjectIs, ObjectPrototypeHasOwnProperty, ObjectSetPrototypeOf, ReflectApply, @@ -649,6 +650,16 @@ const getValidatedPath = hideStackFrames((fileURLOrPath, propName = 'path') => { return path; }); +const getValidatedFd = hideStackFrames((fd, propName = 'fd') => { + if (ObjectIs(fd, -0)) { + return 0; + } + + validateInt32(fd, propName, 0); + + return fd; +}); + const validateBufferArray = hideStackFrames((buffers, propName = 'buffers') => { if (!ArrayIsArray(buffers)) throw new ERR_INVALID_ARG_TYPE(propName, 'ArrayBufferView[]', buffers); @@ -843,6 +854,7 @@ module.exports = { getDirent, getDirents, getOptions, + getValidatedFd, getValidatedPath, getValidMode, handleErrorFromBinding, diff --git a/test/parallel/test-fs-stat.js b/test/parallel/test-fs-stat.js index 31aec8fab00450..92a6ec8fa3280c 100644 --- a/test/parallel/test-fs-stat.js +++ b/test/parallel/test-fs-stat.js @@ -47,6 +47,8 @@ fs.lstat('.', common.mustSucceed(function(stats) { fs.open('.', 'r', undefined, common.mustSucceed(function(fd) { assert.ok(fd); + fs.fstat(-0, common.mustSucceed()); + fs.fstat(fd, common.mustSucceed(function(stats) { assert.ok(stats.mtime instanceof Date); fs.close(fd, assert.ifError);