Skip to content

Commit bc33a9c

Browse files
committed
fs: allow passing negative zero fd
Fixes: nodejs#37122
1 parent 7d0f680 commit bc33a9c

File tree

3 files changed

+40
-23
lines changed

3 files changed

+40
-23
lines changed

lib/fs.js

+24-23
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ const {
8989
Dirent,
9090
getDirents,
9191
getOptions,
92+
getValidatedFd,
9293
getValidatedPath,
9394
getValidMode,
9495
handleErrorFromBinding,
@@ -453,7 +454,7 @@ function close(fd, callback = defaultCloseCallback) {
453454
}
454455

455456
function closeSync(fd) {
456-
validateInt32(fd, 'fd', 0);
457+
fd = getValidatedFd(fd);
457458

458459
const ctx = {};
459460
binding.close(fd, undefined, ctx);
@@ -503,7 +504,7 @@ function openSync(path, flags, mode) {
503504
// OR
504505
// fs.read(fd, {}, callback)
505506
function read(fd, buffer, offset, length, position, callback) {
506-
validateInt32(fd, 'fd', 0);
507+
fd = getValidatedFd(fd);
507508

508509
if (arguments.length <= 3) {
509510
// Assume fs.read(fd, options, callback)
@@ -576,7 +577,7 @@ ObjectDefineProperty(read, internalUtil.customPromisifyArgs,
576577
// OR
577578
// fs.readSync(fd, buffer, {}) or fs.readSync(fd, buffer)
578579
function readSync(fd, buffer, offset, length, position) {
579-
validateInt32(fd, 'fd', 0);
580+
fd = getValidatedFd(fd);
580581

581582
if (arguments.length <= 3) {
582583
// Assume fs.read(fd, buffer, options)
@@ -623,7 +624,7 @@ function readv(fd, buffers, position, callback) {
623624
callback(err, read || 0, buffers);
624625
}
625626

626-
validateInt32(fd, 'fd', /* min */ 0);
627+
fd = getValidatedFd(fd);
627628
validateBufferArray(buffers);
628629
callback = maybeCallback(callback || position);
629630

@@ -640,7 +641,7 @@ ObjectDefineProperty(readv, internalUtil.customPromisifyArgs,
640641
{ value: ['bytesRead', 'buffers'], enumerable: false });
641642

642643
function readvSync(fd, buffers, position) {
643-
validateInt32(fd, 'fd', 0);
644+
fd = getValidatedFd(fd);
644645
validateBufferArray(buffers);
645646

646647
const ctx = {};
@@ -663,7 +664,7 @@ function write(fd, buffer, offset, length, position, callback) {
663664
callback(err, written || 0, buffer);
664665
}
665666

666-
validateInt32(fd, 'fd', 0);
667+
fd = getValidatedFd(fd);
667668

668669
if (isArrayBufferView(buffer)) {
669670
callback = maybeCallback(callback || position || length || offset);
@@ -709,7 +710,7 @@ ObjectDefineProperty(write, internalUtil.customPromisifyArgs,
709710
// OR
710711
// fs.writeSync(fd, string[, position[, encoding]]);
711712
function writeSync(fd, buffer, offset, length, position) {
712-
validateInt32(fd, 'fd', 0);
713+
fd = getValidatedFd(fd);
713714
const ctx = {};
714715
let result;
715716
if (isArrayBufferView(buffer)) {
@@ -744,7 +745,7 @@ function writev(fd, buffers, position, callback) {
744745
callback(err, written || 0, buffers);
745746
}
746747

747-
validateInt32(fd, 'fd', 0);
748+
fd = getValidatedFd(fd);
748749
validateBufferArray(buffers);
749750
callback = maybeCallback(callback || position);
750751

@@ -763,7 +764,7 @@ ObjectDefineProperty(writev, internalUtil.customPromisifyArgs, {
763764
});
764765

765766
function writevSync(fd, buffers, position) {
766-
validateInt32(fd, 'fd', 0);
767+
fd = getValidatedFd(fd);
767768
validateBufferArray(buffers);
768769

769770
const ctx = {};
@@ -849,7 +850,7 @@ function ftruncate(fd, len = 0, callback) {
849850
callback = len;
850851
len = 0;
851852
}
852-
validateInt32(fd, 'fd', 0);
853+
fd = getValidatedFd(fd);
853854
validateInteger(len, 'len');
854855
len = MathMax(0, len);
855856
callback = makeCallback(callback);
@@ -860,7 +861,7 @@ function ftruncate(fd, len = 0, callback) {
860861
}
861862

862863
function ftruncateSync(fd, len = 0) {
863-
validateInt32(fd, 'fd', 0);
864+
fd = getValidatedFd(fd);
864865
validateInteger(len, 'len');
865866
len = MathMax(0, len);
866867
const ctx = {};
@@ -942,28 +943,28 @@ function rmSync(path, options) {
942943
}
943944

944945
function fdatasync(fd, callback) {
945-
validateInt32(fd, 'fd', 0);
946+
fd = getValidatedFd(fd);
946947
const req = new FSReqCallback();
947948
req.oncomplete = makeCallback(callback);
948949
binding.fdatasync(fd, req);
949950
}
950951

951952
function fdatasyncSync(fd) {
952-
validateInt32(fd, 'fd', 0);
953+
fd = getValidatedFd(fd);
953954
const ctx = {};
954955
binding.fdatasync(fd, undefined, ctx);
955956
handleErrorFromBinding(ctx);
956957
}
957958

958959
function fsync(fd, callback) {
959-
validateInt32(fd, 'fd', 0);
960+
fd = getValidatedFd(fd);
960961
const req = new FSReqCallback();
961962
req.oncomplete = makeCallback(callback);
962963
binding.fsync(fd, req);
963964
}
964965

965966
function fsyncSync(fd) {
966-
validateInt32(fd, 'fd', 0);
967+
fd = getValidatedFd(fd);
967968
const ctx = {};
968969
binding.fsync(fd, undefined, ctx);
969970
handleErrorFromBinding(ctx);
@@ -1054,7 +1055,7 @@ function fstat(fd, options = { bigint: false }, callback) {
10541055
callback = options;
10551056
options = {};
10561057
}
1057-
validateInt32(fd, 'fd', 0);
1058+
fd = getValidatedFd(fd);
10581059
callback = makeStatsCallback(callback);
10591060

10601061
const req = new FSReqCallback(options.bigint);
@@ -1102,7 +1103,7 @@ function hasNoEntryError(ctx) {
11021103
}
11031104

11041105
function fstatSync(fd, options = { bigint: false, throwIfNoEntry: true }) {
1105-
validateInt32(fd, 'fd', 0);
1106+
fd = getValidatedFd(fd);
11061107
const ctx = { fd };
11071108
const stats = binding.fstat(fd, options.bigint, undefined, ctx);
11081109
handleErrorFromBinding(ctx);
@@ -1255,7 +1256,7 @@ function unlinkSync(path) {
12551256
}
12561257

12571258
function fchmod(fd, mode, callback) {
1258-
validateInt32(fd, 'fd', 0);
1259+
fd = getValidatedFd(fd);
12591260
mode = parseFileMode(mode, 'mode');
12601261
callback = makeCallback(callback);
12611262

@@ -1265,7 +1266,7 @@ function fchmod(fd, mode, callback) {
12651266
}
12661267

12671268
function fchmodSync(fd, mode) {
1268-
validateInt32(fd, 'fd', 0);
1269+
fd = getValidatedFd(fd);
12691270
mode = parseFileMode(mode, 'mode');
12701271
const ctx = {};
12711272
binding.fchmod(fd, mode, undefined, ctx);
@@ -1343,7 +1344,7 @@ function lchownSync(path, uid, gid) {
13431344
}
13441345

13451346
function fchown(fd, uid, gid, callback) {
1346-
validateInt32(fd, 'fd', 0);
1347+
fd = getValidatedFd(fd);
13471348
validateInteger(uid, 'uid', -1, kMaxUserId);
13481349
validateInteger(gid, 'gid', -1, kMaxUserId);
13491350
callback = makeCallback(callback);
@@ -1354,7 +1355,7 @@ function fchown(fd, uid, gid, callback) {
13541355
}
13551356

13561357
function fchownSync(fd, uid, gid) {
1357-
validateInt32(fd, 'fd', 0);
1358+
fd = getValidatedFd(fd);
13581359
validateInteger(uid, 'uid', -1, kMaxUserId);
13591360
validateInteger(gid, 'gid', -1, kMaxUserId);
13601361

@@ -1405,7 +1406,7 @@ function utimesSync(path, atime, mtime) {
14051406
}
14061407

14071408
function futimes(fd, atime, mtime, callback) {
1408-
validateInt32(fd, 'fd', 0);
1409+
fd = getValidatedFd(fd);
14091410
atime = toUnixTimestamp(atime, 'atime');
14101411
mtime = toUnixTimestamp(mtime, 'mtime');
14111412
callback = makeCallback(callback);
@@ -1416,7 +1417,7 @@ function futimes(fd, atime, mtime, callback) {
14161417
}
14171418

14181419
function futimesSync(fd, atime, mtime) {
1419-
validateInt32(fd, 'fd', 0);
1420+
fd = getValidatedFd(fd);
14201421
atime = toUnixTimestamp(atime, 'atime');
14211422
mtime = toUnixTimestamp(mtime, 'mtime');
14221423
const ctx = {};

lib/internal/fs/utils.js

+12
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ const {
1212
NumberIsFinite,
1313
NumberIsInteger,
1414
MathMin,
15+
ObjectIs,
1516
ObjectPrototypeHasOwnProperty,
1617
ObjectSetPrototypeOf,
1718
ReflectApply,
@@ -649,6 +650,16 @@ const getValidatedPath = hideStackFrames((fileURLOrPath, propName = 'path') => {
649650
return path;
650651
});
651652

653+
const getValidatedFd = hideStackFrames((fd, propName = 'fd') => {
654+
if (ObjectIs(fd, -0)) {
655+
fd = 0;
656+
}
657+
658+
validateInt32(fd, propName, 0);
659+
660+
return fd;
661+
});
662+
652663
const validateBufferArray = hideStackFrames((buffers, propName = 'buffers') => {
653664
if (!ArrayIsArray(buffers))
654665
throw new ERR_INVALID_ARG_TYPE(propName, 'ArrayBufferView[]', buffers);
@@ -843,6 +854,7 @@ module.exports = {
843854
getDirent,
844855
getDirents,
845856
getOptions,
857+
getValidatedFd,
846858
getValidatedPath,
847859
getValidMode,
848860
handleErrorFromBinding,

test/parallel/test-fs-stat.js

+4
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,10 @@ fs.lstat('.', common.mustSucceed(function(stats) {
4747
fs.open('.', 'r', undefined, common.mustSucceed(function(fd) {
4848
assert.ok(fd);
4949

50+
fs.fstat(-0, common.mustCall((err) => {
51+
assert.strictEqual(err, null);
52+
}));
53+
5054
fs.fstat(fd, common.mustSucceed(function(stats) {
5155
assert.ok(stats.mtime instanceof Date);
5256
fs.close(fd, assert.ifError);

0 commit comments

Comments
 (0)