Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit b4b7d36

Browse filesBrowse files
joyeecheungtargos
authored andcommitted
lib: unmask mode_t values with 0o777
This commit allows permission bits higher than 0o777 to go through the API (e.g. `S_ISVTX`=`0o1000`, `S_ISGID`=`0o2000`, `S_ISUID`=`0o4000`). Also documents that these bits are not exposed through `fs.constants` and their behaviors are platform-specific, so the users need to use them on their own risk. PR-URL: #20975 Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: James M Snell <jasnell@gmail.com> Backport-PR-URL: #21172
1 parent 9f9355d commit b4b7d36
Copy full SHA for b4b7d36

File tree

Expand file treeCollapse file tree

9 files changed

+43
-27
lines changed
Open diff view settings
Filter options
Expand file treeCollapse file tree

9 files changed

+43
-27
lines changed
Open diff view settings
Collapse file

‎doc/api/fs.md‎

Copy file name to clipboardExpand all lines: doc/api/fs.md
+6Lines changed: 6 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
Original file line numberDiff line numberDiff line change
@@ -1089,6 +1089,12 @@ For example, the octal value `0o765` means:
10891089
* The group may read and write the file.
10901090
* Others may read and execute the file.
10911091

1092+
Note: When using raw numbers where file modes are expected,
1093+
any value larger than `0o777` may result in platform-specific
1094+
behaviors that are not supported to work consistently.
1095+
Therefore constants like `S_ISVTX`, `S_ISGID` or `S_ISUID` are
1096+
not exposed in `fs.constants`.
1097+
10921098
Caveats: on Windows only the write permission can be changed, and the
10931099
distinction among the permissions of group, owner or others is not
10941100
implemented.
Collapse file

‎lib/fs.js‎

Copy file name to clipboardExpand all lines: lib/fs.js
+9-9Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ const {
7777
} = require('internal/constants');
7878
const {
7979
isUint32,
80-
validateAndMaskMode,
80+
validateMode,
8181
validateInteger,
8282
validateInt32,
8383
validateUint32
@@ -416,7 +416,7 @@ function open(path, flags, mode, callback) {
416416
callback = makeCallback(mode);
417417
mode = 0o666;
418418
} else {
419-
mode = validateAndMaskMode(mode, 'mode', 0o666);
419+
mode = validateMode(mode, 'mode', 0o666);
420420
callback = makeCallback(callback);
421421
}
422422

@@ -434,7 +434,7 @@ function openSync(path, flags, mode) {
434434
path = getPathFromURL(path);
435435
validatePath(path);
436436
const flagsNumber = stringToFlags(flags);
437-
mode = validateAndMaskMode(mode, 'mode', 0o666);
437+
mode = validateMode(mode, 'mode', 0o666);
438438

439439
const ctx = { path };
440440
const result = binding.open(pathModule.toNamespacedPath(path),
@@ -721,7 +721,7 @@ function mkdir(path, mode, callback) {
721721
mode = 0o777;
722722
} else {
723723
callback = makeCallback(callback);
724-
mode = validateAndMaskMode(mode, 'mode', 0o777);
724+
mode = validateMode(mode, 'mode', 0o777);
725725
}
726726

727727
const req = new FSReqWrap();
@@ -732,7 +732,7 @@ function mkdir(path, mode, callback) {
732732
function mkdirSync(path, mode) {
733733
path = getPathFromURL(path);
734734
validatePath(path);
735-
mode = validateAndMaskMode(mode, 'mode', 0o777);
735+
mode = validateMode(mode, 'mode', 0o777);
736736
const ctx = { path };
737737
binding.mkdir(pathModule.toNamespacedPath(path), mode, undefined, ctx);
738738
handleErrorFromBinding(ctx);
@@ -915,7 +915,7 @@ function unlinkSync(path) {
915915

916916
function fchmod(fd, mode, callback) {
917917
validateInt32(fd, 'fd', 0);
918-
mode = validateAndMaskMode(mode, 'mode');
918+
mode = validateMode(mode, 'mode');
919919
callback = makeCallback(callback);
920920

921921
const req = new FSReqWrap();
@@ -925,7 +925,7 @@ function fchmod(fd, mode, callback) {
925925

926926
function fchmodSync(fd, mode) {
927927
validateInt32(fd, 'fd', 0);
928-
mode = validateAndMaskMode(mode, 'mode');
928+
mode = validateMode(mode, 'mode');
929929
const ctx = {};
930930
binding.fchmod(fd, mode, undefined, ctx);
931931
handleErrorFromBinding(ctx);
@@ -966,7 +966,7 @@ function lchmodSync(path, mode) {
966966
function chmod(path, mode, callback) {
967967
path = getPathFromURL(path);
968968
validatePath(path);
969-
mode = validateAndMaskMode(mode, 'mode');
969+
mode = validateMode(mode, 'mode');
970970
callback = makeCallback(callback);
971971

972972
const req = new FSReqWrap();
@@ -977,7 +977,7 @@ function chmod(path, mode, callback) {
977977
function chmodSync(path, mode) {
978978
path = getPathFromURL(path);
979979
validatePath(path);
980-
mode = validateAndMaskMode(mode, 'mode');
980+
mode = validateMode(mode, 'mode');
981981

982982
const ctx = { path };
983983
binding.chmod(pathModule.toNamespacedPath(path), mode, undefined, ctx);
Collapse file

‎lib/internal/fs/promises.js‎

Copy file name to clipboardExpand all lines: lib/internal/fs/promises.js
+5-5Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@ const {
3131
validatePath
3232
} = require('internal/fs/utils');
3333
const {
34-
validateAndMaskMode,
3534
validateInteger,
35+
validateMode,
3636
validateUint32
3737
} = require('internal/validators');
3838
const pathModule = require('path');
@@ -191,7 +191,7 @@ async function copyFile(src, dest, flags) {
191191
async function open(path, flags, mode) {
192192
path = getPathFromURL(path);
193193
validatePath(path);
194-
mode = validateAndMaskMode(mode, 'mode', 0o666);
194+
mode = validateMode(mode, 'mode', 0o666);
195195
return new FileHandle(
196196
await binding.openFileHandle(pathModule.toNamespacedPath(path),
197197
stringToFlags(flags),
@@ -286,7 +286,7 @@ async function fsync(handle) {
286286
async function mkdir(path, mode) {
287287
path = getPathFromURL(path);
288288
validatePath(path);
289-
mode = validateAndMaskMode(mode, 'mode', 0o777);
289+
mode = validateMode(mode, 'mode', 0o777);
290290
return binding.mkdir(pathModule.toNamespacedPath(path), mode, kUsePromises);
291291
}
292292

@@ -358,14 +358,14 @@ async function unlink(path) {
358358

359359
async function fchmod(handle, mode) {
360360
validateFileHandle(handle);
361-
mode = validateAndMaskMode(mode, 'mode');
361+
mode = validateMode(mode, 'mode');
362362
return binding.fchmod(handle.fd, mode, kUsePromises);
363363
}
364364

365365
async function chmod(path, mode) {
366366
path = getPathFromURL(path);
367367
validatePath(path);
368-
mode = validateAndMaskMode(mode, 'mode');
368+
mode = validateMode(mode, 'mode');
369369
return binding.chmod(pathModule.toNamespacedPath(path), mode, kUsePromises);
370370
}
371371

Collapse file

‎lib/internal/validators.js‎

Copy file name to clipboardExpand all lines: lib/internal/validators.js
+17-6Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,22 @@ function isUint32(value) {
1616

1717
const octalReg = /^[0-7]+$/;
1818
const modeDesc = 'must be a 32-bit unsigned integer or an octal string';
19-
// Validator for mode_t (the S_* constants). Valid numbers or octal strings
20-
// will be masked with 0o777 to be consistent with the behavior in POSIX APIs.
21-
function validateAndMaskMode(value, name, def) {
19+
20+
/**
21+
* Validate values that will be converted into mode_t (the S_* constants).
22+
* Only valid numbers and octal strings are allowed. They could be converted
23+
* to 32-bit unsigned integers or non-negative signed integers in the C++
24+
* land, but any value higher than 0o777 will result in platform-specific
25+
* behaviors.
26+
*
27+
* @param {*} value Values to be validated
28+
* @param {string} name Name of the argument
29+
* @param {number} def If specified, will be returned for invalid values
30+
* @returns {number}
31+
*/
32+
function validateMode(value, name, def) {
2233
if (isUint32(value)) {
23-
return value & 0o777;
34+
return value;
2435
}
2536

2637
if (typeof value === 'number') {
@@ -37,7 +48,7 @@ function validateAndMaskMode(value, name, def) {
3748
throw new ERR_INVALID_ARG_VALUE(name, value, modeDesc);
3849
}
3950
const parsed = parseInt(value, 8);
40-
return parsed & 0o777;
51+
return parsed;
4152
}
4253

4354
// TODO(BridgeAR): Only return `def` in case `value == null`
@@ -106,7 +117,7 @@ function validateUint32(value, name, positive) {
106117
module.exports = {
107118
isInt32,
108119
isUint32,
109-
validateAndMaskMode,
120+
validateMode,
110121
validateInteger,
111122
validateInt32,
112123
validateUint32
Collapse file

‎test/parallel/test-fs-chmod-mask.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-fs-chmod-mask.js
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22

3-
// This tests that mode > 0o777 will be masked off with 0o777 in fs APIs.
3+
// This tests that the lower bits of mode > 0o777 still works in fs APIs.
44

55
const common = require('../common');
66
const assert = require('assert');
Collapse file

‎test/parallel/test-fs-mkdir-mode-mask.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-fs-mkdir-mode-mask.js
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22

3-
// This tests that mode > 0o777 will be masked off with 0o777 in fs.mkdir().
3+
// This tests that the lower bits of mode > 0o777 still works in fs.mkdir().
44

55
const common = require('../common');
66
const assert = require('assert');
Collapse file

‎test/parallel/test-fs-open-mode-mask.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-fs-open-mode-mask.js
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22

3-
// This tests that mode > 0o777 will be masked off with 0o777 in fs.open().
3+
// This tests that the lower bits of mode > 0o777 still works in fs.open().
44

55
const common = require('../common');
66
const assert = require('assert');
Collapse file

‎test/parallel/test-fs-promises.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-fs-promises.js
+2-3Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -107,9 +107,8 @@ function verifyStatObject(stat) {
107107
await chmod(dest, 0o666);
108108
await handle.chmod(0o666);
109109

110-
// Mode larger than 0o777 should be masked off.
111-
await chmod(dest, (0o777 + 1));
112-
await handle.chmod(0o777 + 1);
110+
await chmod(dest, (0o10777));
111+
await handle.chmod(0o10777);
113112

114113
await utimes(dest, new Date(), new Date());
115114

Collapse file

‎test/parallel/test-process-umask-mask.js‎

Copy file name to clipboardExpand all lines: test/parallel/test-process-umask-mask.js
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22

3-
// This tests that mask > 0o777 will be masked off with 0o777 in
3+
// This tests that the lower bits of mode > 0o777 still works in
44
// process.umask()
55

66
const common = require('../common');

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.