Skip to content

Commit acc3c77

Browse files
committed
fs: fix error handling
Right now there are multiple cases where the validated entry would not be returned or a wrong error is thrown. This fixes both cases. PR-URL: #19445 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net>
1 parent 058e7fb commit acc3c77

11 files changed

+178
-197
lines changed

lib/internal/fs.js

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,16 @@ function isUint32(n) { return n === (n >>> 0); }
7777
function modeNum(m, def) {
7878
if (typeof m === 'number')
7979
return m;
80-
if (typeof m === 'string')
81-
return parseInt(m, 8);
82-
if (def)
83-
return modeNum(def);
84-
return undefined;
80+
if (typeof m === 'string') {
81+
const parsed = parseInt(m, 8);
82+
if (Number.isNaN(parsed))
83+
return m;
84+
return parsed;
85+
}
86+
// TODO(BridgeAR): Only return `def` in case `m == null`
87+
if (def !== undefined)
88+
return def;
89+
return m;
8590
}
8691

8792
// Check if the path contains null types if it is a string nor Uint8Array,
@@ -333,8 +338,14 @@ function validateBuffer(buffer) {
333338
function validateLen(len) {
334339
let err;
335340

336-
if (!isInt32(len))
337-
err = new ERR_INVALID_ARG_TYPE('len', 'integer');
341+
if (!isInt32(len)) {
342+
if (typeof value !== 'number') {
343+
err = new ERR_INVALID_ARG_TYPE('len', 'number', len);
344+
} else {
345+
// TODO(BridgeAR): Improve this error message.
346+
err = new ERR_OUT_OF_RANGE('len', 'an integer', len);
347+
}
348+
}
338349

339350
if (err !== undefined) {
340351
Error.captureStackTrace(err, validateLen);
@@ -388,12 +399,16 @@ function validatePath(path, propName = 'path') {
388399
}
389400

390401
function validateUint32(value, propName) {
391-
let err;
392-
393-
if (!isUint32(value))
394-
err = new ERR_INVALID_ARG_TYPE(propName, 'integer');
395-
396-
if (err !== undefined) {
402+
if (!isUint32(value)) {
403+
let err;
404+
if (typeof value !== 'number') {
405+
err = new ERR_INVALID_ARG_TYPE(propName, 'number', value);
406+
} else if (!Number.isInteger(value)) {
407+
err = new ERR_OUT_OF_RANGE(propName, 'an integer', value);
408+
} else {
409+
// 2 ** 32 === 4294967296
410+
err = new ERR_OUT_OF_RANGE(propName, '>= 0 && < 4294967296', value);
411+
}
397412
Error.captureStackTrace(err, validateUint32);
398413
throw err;
399414
}

test/parallel/test-fs-chmod.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,8 @@ fs.open(file2, 'w', common.mustCall((err, fd) => {
114114
{
115115
code: 'ERR_INVALID_ARG_TYPE',
116116
type: TypeError,
117-
message: 'The "mode" argument must be of type integer'
117+
message: 'The "mode" argument must be of type number. ' +
118+
'Received type object'
118119
}
119120
);
120121

@@ -150,7 +151,8 @@ if (fs.lchmod) {
150151
const errObj = {
151152
code: 'ERR_INVALID_ARG_TYPE',
152153
name: 'TypeError [ERR_INVALID_ARG_TYPE]',
153-
message: 'The "fd" argument must be of type integer'
154+
message: 'The "fd" argument must be of type number. ' +
155+
`Received type ${typeof input}`
154156
};
155157
assert.throws(() => fs.fchmod(input, 0o000), errObj);
156158
assert.throws(() => fs.fchmodSync(input, 0o000), errObj);

test/parallel/test-fs-close-errors.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ const fs = require('fs');
1111
const errObj = {
1212
code: 'ERR_INVALID_ARG_TYPE',
1313
name: 'TypeError [ERR_INVALID_ARG_TYPE]',
14-
message: 'The "fd" argument must be of type integer'
14+
message: 'The "fd" argument must be of type number. ' +
15+
`Received type ${typeof input}`
1516
};
1617
assert.throws(() => fs.close(input), errObj);
1718
assert.throws(() => fs.closeSync(input), errObj);

test/parallel/test-fs-fchmod.js

Lines changed: 54 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,66 @@
11
'use strict';
22
const common = require('../common');
3+
const assert = require('assert');
34
const fs = require('fs');
45

56
// This test ensures that input for fchmod is valid, testing for valid
67
// inputs for fd and mode
78

89
// Check input type
9-
['', false, null, undefined, {}, [], Infinity, -1].forEach((i) => {
10-
common.expectsError(
11-
() => fs.fchmod(i),
12-
{
13-
code: 'ERR_INVALID_ARG_TYPE',
14-
type: TypeError,
15-
message: 'The "fd" argument must be of type integer'
16-
}
17-
);
18-
common.expectsError(
19-
() => fs.fchmodSync(i),
20-
{
21-
code: 'ERR_INVALID_ARG_TYPE',
22-
type: TypeError,
23-
message: 'The "fd" argument must be of type integer'
24-
}
25-
);
10+
[false, null, undefined, {}, [], ''].forEach((input) => {
11+
const errObj = {
12+
code: 'ERR_INVALID_ARG_TYPE',
13+
name: 'TypeError [ERR_INVALID_ARG_TYPE]',
14+
message: 'The "fd" argument must be of type number. Received type ' +
15+
typeof input
16+
};
17+
assert.throws(() => fs.fchmod(input), errObj);
18+
assert.throws(() => fs.fchmodSync(input), errObj);
19+
errObj.message = errObj.message.replace('fd', 'mode');
20+
assert.throws(() => fs.fchmod(1, input), errObj);
21+
assert.throws(() => fs.fchmodSync(1, input), errObj);
22+
});
23+
24+
[-1, 2 ** 32].forEach((input) => {
25+
const errObj = {
26+
code: 'ERR_OUT_OF_RANGE',
27+
name: 'RangeError [ERR_OUT_OF_RANGE]',
28+
message: 'The value of "fd" is out of range. It must be >= 0 && < ' +
29+
`${2 ** 32}. Received ${input}`
30+
};
31+
assert.throws(() => fs.fchmod(input), errObj);
32+
assert.throws(() => fs.fchmodSync(input), errObj);
33+
errObj.message = errObj.message.replace('fd', 'mode');
34+
assert.throws(() => fs.fchmod(1, input), errObj);
35+
assert.throws(() => fs.fchmodSync(1, input), errObj);
36+
});
2637

27-
common.expectsError(
28-
() => fs.fchmod(1, i),
29-
{
30-
code: 'ERR_INVALID_ARG_TYPE',
31-
type: TypeError,
32-
message: 'The "mode" argument must be of type integer'
33-
}
34-
);
35-
common.expectsError(
36-
() => fs.fchmodSync(1, i),
37-
{
38-
code: 'ERR_INVALID_ARG_TYPE',
39-
type: TypeError,
40-
message: 'The "mode" argument must be of type integer'
41-
}
42-
);
38+
[NaN, Infinity].forEach((input) => {
39+
const errObj = {
40+
code: 'ERR_OUT_OF_RANGE',
41+
name: 'RangeError [ERR_OUT_OF_RANGE]',
42+
message: 'The value of "fd" is out of range. It must be an integer. ' +
43+
`Received ${input}`
44+
};
45+
assert.throws(() => fs.fchmod(input), errObj);
46+
assert.throws(() => fs.fchmodSync(input), errObj);
47+
errObj.message = errObj.message.replace('fd', 'mode');
48+
assert.throws(() => fs.fchmod(1, input), errObj);
49+
assert.throws(() => fs.fchmodSync(1, input), errObj);
50+
});
51+
52+
[1.5].forEach((input) => {
53+
const errObj = {
54+
code: 'ERR_OUT_OF_RANGE',
55+
name: 'RangeError [ERR_OUT_OF_RANGE]',
56+
message: 'The value of "fd" is out of range. It must be an integer. ' +
57+
`Received ${input}`
58+
};
59+
assert.throws(() => fs.fchmod(input), errObj);
60+
assert.throws(() => fs.fchmodSync(input), errObj);
61+
errObj.message = errObj.message.replace('fd', 'mode');
62+
assert.throws(() => fs.fchmod(1, input), errObj);
63+
assert.throws(() => fs.fchmodSync(1, input), errObj);
4364
});
4465

4566
// Check for mode values range

test/parallel/test-fs-fchown.js

Lines changed: 39 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,46 @@
11
'use strict';
22

3-
const common = require('../common');
3+
require('../common');
4+
const assert = require('assert');
45
const fs = require('fs');
56

6-
['', false, null, undefined, {}, [], Infinity, -1].forEach((i) => {
7-
common.expectsError(
8-
() => fs.fchown(i),
9-
{
10-
code: 'ERR_INVALID_ARG_TYPE',
11-
type: TypeError,
12-
message: 'The "fd" argument must be of type integer'
13-
}
14-
);
15-
common.expectsError(
16-
() => fs.fchownSync(i),
17-
{
18-
code: 'ERR_INVALID_ARG_TYPE',
19-
type: TypeError,
20-
message: 'The "fd" argument must be of type integer'
21-
}
22-
);
7+
function test(input, errObj) {
8+
assert.throws(() => fs.fchown(input), errObj);
9+
assert.throws(() => fs.fchownSync(input), errObj);
10+
errObj.message = errObj.message.replace('fd', 'uid');
11+
assert.throws(() => fs.fchown(1, input), errObj);
12+
assert.throws(() => fs.fchownSync(1, input), errObj);
13+
errObj.message = errObj.message.replace('uid', 'gid');
14+
assert.throws(() => fs.fchown(1, 1, input), errObj);
15+
assert.throws(() => fs.fchownSync(1, 1, input), errObj);
16+
}
2317

24-
common.expectsError(
25-
() => fs.fchown(1, i),
26-
{
27-
code: 'ERR_INVALID_ARG_TYPE',
28-
type: TypeError,
29-
message: 'The "uid" argument must be of type integer'
30-
}
31-
);
32-
common.expectsError(
33-
() => fs.fchownSync(1, i),
34-
{
35-
code: 'ERR_INVALID_ARG_TYPE',
36-
type: TypeError,
37-
message: 'The "uid" argument must be of type integer'
38-
}
39-
);
18+
['', false, null, undefined, {}, []].forEach((input) => {
19+
const errObj = {
20+
code: 'ERR_INVALID_ARG_TYPE',
21+
name: 'TypeError [ERR_INVALID_ARG_TYPE]',
22+
message: 'The "fd" argument must be of type number. Received type ' +
23+
typeof input
24+
};
25+
test(input, errObj);
26+
});
27+
28+
[Infinity, NaN].forEach((input) => {
29+
const errObj = {
30+
code: 'ERR_OUT_OF_RANGE',
31+
name: 'RangeError [ERR_OUT_OF_RANGE]',
32+
message: 'The value of "fd" is out of range. It must be an integer. ' +
33+
`Received ${input}`
34+
};
35+
test(input, errObj);
36+
});
4037

41-
common.expectsError(
42-
() => fs.fchown(1, 1, i),
43-
{
44-
code: 'ERR_INVALID_ARG_TYPE',
45-
type: TypeError,
46-
message: 'The "gid" argument must be of type integer'
47-
}
48-
);
49-
common.expectsError(
50-
() => fs.fchownSync(1, 1, i),
51-
{
52-
code: 'ERR_INVALID_ARG_TYPE',
53-
type: TypeError,
54-
message: 'The "gid" argument must be of type integer'
55-
}
56-
);
38+
[-1, 2 ** 32].forEach((input) => {
39+
const errObj = {
40+
code: 'ERR_OUT_OF_RANGE',
41+
name: 'RangeError [ERR_OUT_OF_RANGE]',
42+
message: 'The value of "fd" is out of range. It must be ' +
43+
`>= 0 && < 4294967296. Received ${input}`
44+
};
45+
test(input, errObj);
5746
});

test/parallel/test-fs-fsync.js

Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -50,37 +50,15 @@ fs.open(fileTemp, 'a', 0o777, common.mustCall(function(err, fd) {
5050
}));
5151
}));
5252

53-
['', false, null, undefined, {}, []].forEach((i) => {
54-
common.expectsError(
55-
() => fs.fdatasync(i),
56-
{
57-
code: 'ERR_INVALID_ARG_TYPE',
58-
type: TypeError,
59-
message: 'The "fd" argument must be of type integer'
60-
}
61-
);
62-
common.expectsError(
63-
() => fs.fdatasyncSync(i),
64-
{
65-
code: 'ERR_INVALID_ARG_TYPE',
66-
type: TypeError,
67-
message: 'The "fd" argument must be of type integer'
68-
}
69-
);
70-
common.expectsError(
71-
() => fs.fsync(i),
72-
{
73-
code: 'ERR_INVALID_ARG_TYPE',
74-
type: TypeError,
75-
message: 'The "fd" argument must be of type integer'
76-
}
77-
);
78-
common.expectsError(
79-
() => fs.fsyncSync(i),
80-
{
81-
code: 'ERR_INVALID_ARG_TYPE',
82-
type: TypeError,
83-
message: 'The "fd" argument must be of type integer'
84-
}
85-
);
53+
['', false, null, undefined, {}, []].forEach((input) => {
54+
const errObj = {
55+
code: 'ERR_INVALID_ARG_TYPE',
56+
name: 'TypeError [ERR_INVALID_ARG_TYPE]',
57+
message: 'The "fd" argument must be of type number. Received type ' +
58+
typeof input
59+
};
60+
assert.throws(() => fs.fdatasync(input), errObj);
61+
assert.throws(() => fs.fdatasyncSync(input), errObj);
62+
assert.throws(() => fs.fsync(input), errObj);
63+
assert.throws(() => fs.fsyncSync(input), errObj);
8664
});

test/parallel/test-fs-read-type.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@ common.expectsError(
3030
}, {
3131
code: 'ERR_INVALID_ARG_TYPE',
3232
type: TypeError,
33-
message: 'The "fd" argument must be of type integer'
33+
message: 'The "fd" argument must be of type number. ' +
34+
`Received type ${typeof value}`
3435
});
3536
});
3637

@@ -75,7 +76,8 @@ common.expectsError(
7576
}, {
7677
code: 'ERR_INVALID_ARG_TYPE',
7778
type: TypeError,
78-
message: 'The "fd" argument must be of type integer'
79+
message: 'The "fd" argument must be of type number. ' +
80+
`Received type ${typeof value}`
7981
});
8082
});
8183

test/parallel/test-fs-stat.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,8 @@ fs.stat(__filename, common.mustCall(function(err, s) {
138138
{
139139
code: 'ERR_INVALID_ARG_TYPE',
140140
name: 'TypeError [ERR_INVALID_ARG_TYPE]',
141-
message: 'The "fd" argument must be of type integer'
141+
message: 'The "fd" argument must be of type number. ' +
142+
`Received type ${typeof input}`
142143
}
143144
);
144145
});

0 commit comments

Comments
 (0)