Skip to content

Commit 0ce7f61

Browse files
committed
fs: allow passing negative zero fd
Fixes: nodejs#37122
1 parent fec093b commit 0ce7f61

File tree

3 files changed

+41
-24
lines changed

3 files changed

+41
-24
lines changed

lib/fs.js

+25-24
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,
@@ -439,7 +440,7 @@ function readFileSync(path, options) {
439440
}
440441

441442
function close(fd, callback) {
442-
validateInt32(fd, 'fd', 0);
443+
fd = getValidatedFd(fd);
443444
callback = makeCallback(callback);
444445

445446
const req = new FSReqCallback();
@@ -448,7 +449,7 @@ function close(fd, callback) {
448449
}
449450

450451
function closeSync(fd) {
451-
validateInt32(fd, 'fd', 0);
452+
fd = getValidatedFd(fd);
452453

453454
const ctx = {};
454455
binding.close(fd, undefined, ctx);
@@ -498,7 +499,7 @@ function openSync(path, flags, mode) {
498499
// OR
499500
// fs.read(fd, {}, callback)
500501
function read(fd, buffer, offset, length, position, callback) {
501-
validateInt32(fd, 'fd', 0);
502+
fd = getValidatedFd(fd);
502503

503504
if (arguments.length <= 3) {
504505
// Assume fs.read(fd, options, callback)
@@ -571,7 +572,7 @@ ObjectDefineProperty(read, internalUtil.customPromisifyArgs,
571572
// OR
572573
// fs.readSync(fd, buffer, {}) or fs.readSync(fd, buffer)
573574
function readSync(fd, buffer, offset, length, position) {
574-
validateInt32(fd, 'fd', 0);
575+
fd = getValidatedFd(fd);
575576

576577
if (arguments.length <= 3) {
577578
// Assume fs.read(fd, buffer, options)
@@ -618,7 +619,7 @@ function readv(fd, buffers, position, callback) {
618619
callback(err, read || 0, buffers);
619620
}
620621

621-
validateInt32(fd, 'fd', /* min */ 0);
622+
fd = getValidatedFd(fd);
622623
validateBufferArray(buffers);
623624
callback = maybeCallback(callback || position);
624625

@@ -635,7 +636,7 @@ ObjectDefineProperty(readv, internalUtil.customPromisifyArgs,
635636
{ value: ['bytesRead', 'buffers'], enumerable: false });
636637

637638
function readvSync(fd, buffers, position) {
638-
validateInt32(fd, 'fd', 0);
639+
fd = getValidatedFd(fd);
639640
validateBufferArray(buffers);
640641

641642
const ctx = {};
@@ -658,7 +659,7 @@ function write(fd, buffer, offset, length, position, callback) {
658659
callback(err, written || 0, buffer);
659660
}
660661

661-
validateInt32(fd, 'fd', 0);
662+
fd = getValidatedFd(fd);
662663

663664
if (isArrayBufferView(buffer)) {
664665
callback = maybeCallback(callback || position || length || offset);
@@ -704,7 +705,7 @@ ObjectDefineProperty(write, internalUtil.customPromisifyArgs,
704705
// OR
705706
// fs.writeSync(fd, string[, position[, encoding]]);
706707
function writeSync(fd, buffer, offset, length, position) {
707-
validateInt32(fd, 'fd', 0);
708+
fd = getValidatedFd(fd);
708709
const ctx = {};
709710
let result;
710711
if (isArrayBufferView(buffer)) {
@@ -739,7 +740,7 @@ function writev(fd, buffers, position, callback) {
739740
callback(err, written || 0, buffers);
740741
}
741742

742-
validateInt32(fd, 'fd', 0);
743+
fd = getValidatedFd(fd);
743744
validateBufferArray(buffers);
744745
callback = maybeCallback(callback || position);
745746

@@ -758,7 +759,7 @@ ObjectDefineProperty(writev, internalUtil.customPromisifyArgs, {
758759
});
759760

760761
function writevSync(fd, buffers, position) {
761-
validateInt32(fd, 'fd', 0);
762+
fd = getValidatedFd(fd);
762763
validateBufferArray(buffers);
763764

764765
const ctx = {};
@@ -844,7 +845,7 @@ function ftruncate(fd, len = 0, callback) {
844845
callback = len;
845846
len = 0;
846847
}
847-
validateInt32(fd, 'fd', 0);
848+
fd = getValidatedFd(fd);
848849
validateInteger(len, 'len');
849850
len = MathMax(0, len);
850851
callback = makeCallback(callback);
@@ -855,7 +856,7 @@ function ftruncate(fd, len = 0, callback) {
855856
}
856857

857858
function ftruncateSync(fd, len = 0) {
858-
validateInt32(fd, 'fd', 0);
859+
fd = getValidatedFd(fd);
859860
validateInteger(len, 'len');
860861
len = MathMax(0, len);
861862
const ctx = {};
@@ -937,28 +938,28 @@ function rmSync(path, options) {
937938
}
938939

939940
function fdatasync(fd, callback) {
940-
validateInt32(fd, 'fd', 0);
941+
fd = getValidatedFd(fd);
941942
const req = new FSReqCallback();
942943
req.oncomplete = makeCallback(callback);
943944
binding.fdatasync(fd, req);
944945
}
945946

946947
function fdatasyncSync(fd) {
947-
validateInt32(fd, 'fd', 0);
948+
fd = getValidatedFd(fd);
948949
const ctx = {};
949950
binding.fdatasync(fd, undefined, ctx);
950951
handleErrorFromBinding(ctx);
951952
}
952953

953954
function fsync(fd, callback) {
954-
validateInt32(fd, 'fd', 0);
955+
fd = getValidatedFd(fd);
955956
const req = new FSReqCallback();
956957
req.oncomplete = makeCallback(callback);
957958
binding.fsync(fd, req);
958959
}
959960

960961
function fsyncSync(fd) {
961-
validateInt32(fd, 'fd', 0);
962+
fd = getValidatedFd(fd);
962963
const ctx = {};
963964
binding.fsync(fd, undefined, ctx);
964965
handleErrorFromBinding(ctx);
@@ -1049,7 +1050,7 @@ function fstat(fd, options = { bigint: false }, callback) {
10491050
callback = options;
10501051
options = {};
10511052
}
1052-
validateInt32(fd, 'fd', 0);
1053+
fd = getValidatedFd(fd);
10531054
callback = makeStatsCallback(callback);
10541055

10551056
const req = new FSReqCallback(options.bigint);
@@ -1097,7 +1098,7 @@ function hasNoEntryError(ctx) {
10971098
}
10981099

10991100
function fstatSync(fd, options = { bigint: false, throwIfNoEntry: true }) {
1100-
validateInt32(fd, 'fd', 0);
1101+
fd = getValidatedFd(fd);
11011102
const ctx = { fd };
11021103
const stats = binding.fstat(fd, options.bigint, undefined, ctx);
11031104
handleErrorFromBinding(ctx);
@@ -1250,7 +1251,7 @@ function unlinkSync(path) {
12501251
}
12511252

12521253
function fchmod(fd, mode, callback) {
1253-
validateInt32(fd, 'fd', 0);
1254+
fd = getValidatedFd(fd);
12541255
mode = parseFileMode(mode, 'mode');
12551256
callback = makeCallback(callback);
12561257

@@ -1260,7 +1261,7 @@ function fchmod(fd, mode, callback) {
12601261
}
12611262

12621263
function fchmodSync(fd, mode) {
1263-
validateInt32(fd, 'fd', 0);
1264+
fd = getValidatedFd(fd);
12641265
mode = parseFileMode(mode, 'mode');
12651266
const ctx = {};
12661267
binding.fchmod(fd, mode, undefined, ctx);
@@ -1338,7 +1339,7 @@ function lchownSync(path, uid, gid) {
13381339
}
13391340

13401341
function fchown(fd, uid, gid, callback) {
1341-
validateInt32(fd, 'fd', 0);
1342+
fd = getValidatedFd(fd);
13421343
validateInteger(uid, 'uid', -1, kMaxUserId);
13431344
validateInteger(gid, 'gid', -1, kMaxUserId);
13441345
callback = makeCallback(callback);
@@ -1349,7 +1350,7 @@ function fchown(fd, uid, gid, callback) {
13491350
}
13501351

13511352
function fchownSync(fd, uid, gid) {
1352-
validateInt32(fd, 'fd', 0);
1353+
fd = getValidatedFd(fd);
13531354
validateInteger(uid, 'uid', -1, kMaxUserId);
13541355
validateInteger(gid, 'gid', -1, kMaxUserId);
13551356

@@ -1400,7 +1401,7 @@ function utimesSync(path, atime, mtime) {
14001401
}
14011402

14021403
function futimes(fd, atime, mtime, callback) {
1403-
validateInt32(fd, 'fd', 0);
1404+
fd = getValidatedFd(fd);
14041405
atime = toUnixTimestamp(atime, 'atime');
14051406
mtime = toUnixTimestamp(mtime, 'mtime');
14061407
callback = makeCallback(callback);
@@ -1411,7 +1412,7 @@ function futimes(fd, atime, mtime, callback) {
14111412
}
14121413

14131414
function futimesSync(fd, atime, mtime) {
1414-
validateInt32(fd, 'fd', 0);
1415+
fd = getValidatedFd(fd);
14151416
atime = toUnixTimestamp(atime, 'atime');
14161417
mtime = toUnixTimestamp(mtime, 'mtime');
14171418
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)