-
Notifications
You must be signed in to change notification settings - Fork 29.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fs, test: one set of file attributes in Windows prevents fs.fchmod() from changing mode to RW and breaks incomplete test #12803
Comments
cc @nodejs/fs, @nodejs/testing, @nodejs/platform-windows, |
@vsemozhetbyt I've added links to the file named in first comment. |
BTW: I can repro:
|
It's not a edge case, it's a real regression. the test didn't detect that
Doesn't work on windows. |
Simplified reproducible test for Windows: test.js:/******************************************************************************/
'use strict';
/******************************************************************************/
const { strictEqual } = require('assert');
const { execSync } = require('child_process');
const { openSync, chmodSync, fchmodSync, statSync, fstatSync } = require('fs');
/******************************************************************************/
const RO = 0o100444; // 33060 0b1000000100100100
const RW = 0o100666; // 33206 0b1000000110110110
const filePath = 'abc.txt'; // or just __filename
const fd = openSync(filePath, 'a');
/******************************************************************************/
execSync(`attrib +a -i ${filePath}`); // the same with '-a +i' or '+a +i'
/******************************************************************************/
chmodSync(filePath, RW);
strictEqual(statSync(filePath).mode, RW);
chmodSync(filePath, RO);
strictEqual(statSync(filePath).mode, RO);
chmodSync(filePath, RW);
strictEqual(statSync(filePath).mode, RW);
/******************************************************************************/
fchmodSync(fd, RW);
strictEqual(fstatSync(fd).mode, RW);
fchmodSync(fd, RO);
strictEqual(fstatSync(fd).mode, RO);
fchmodSync(fd, RW);
strictEqual(fstatSync(fd).mode, RW);
/******************************************************************************/
execSync(`attrib -a -i ${filePath}`);
/******************************************************************************/
chmodSync(filePath, RW);
strictEqual(statSync(filePath).mode, RW);
chmodSync(filePath, RO);
strictEqual(statSync(filePath).mode, RO);
chmodSync(filePath, RW);
strictEqual(statSync(filePath).mode, RW);
/******************************************************************************/
fchmodSync(fd, RW);
strictEqual(fstatSync(fd).mode, RW);
fchmodSync(fd, RO);
strictEqual(fstatSync(fd).mode, RO);
fchmodSync(fd, RW); // This does not work.
strictEqual(fstatSync(fd).mode, RW); // BANG!
/******************************************************************************/ Output:assert.js:86
throw new assert.AssertionError({
^
AssertionError: 33060 === 33206
at Object.<anonymous> (test.js:52:1)
at Module._compile (module.js:582:30)
at Object.Module._extensions..js (module.js:593:10)
at Module.load (module.js:516:32)
at tryModuleLoad (module.js:466:12)
at Function.Module._load (module.js:458:3)
at Function.Module.runMain (module.js:618:10)
at startup (bootstrap_node.js:144:16)
at bootstrap_node.js:548:3 The last |
You are playing with fire manipulating |
@refack I've made it more abstract, but it still fails for a new file in the cwd. |
Cut some stuff out /******************************************************************************/
'use strict';
/******************************************************************************/
const { strictEqual } = require('assert');
const { execSync } = require('child_process');
const { openSync, chmodSync, fchmodSync, fstatSync } = require('fs');
/******************************************************************************/
const RO = 0o100444; // 33060 0b1000000100100100
const RW = 0o100666; // 33206 0b1000000110110110
const tmpFile = `${process.env['TEMP']}\\${Date.now()}gigi.js`;
const fd = openSync(tmpFile, 'a');
/******************************************************************************/
execSync(`attrib -a -i ${tmpFile}`);
/******************************************************************************/
fchmodSync(fd, RO);
const actual2 = fstatSync(fd).mode;
console.log(`${tmpFile} mode: ${actual2}`)
strictEqual(actual2, RO);
fchmodSync(fd, RW); // This does not work.
const actual3 = fstatSync(fd).mode;
console.log(`${tmpFile} mode: ${actual3}`)
strictEqual(actual3, RW); // BANG!
/******************************************************************************/ Now I got #12835 to fail with new files. |
@refack Well, the plot thickens :) I've tried to exhaust all sets of attributes. This is the more general test. test.js:/******************************************************************************/
'use strict';
/******************************************************************************/
const { strictEqual } = require('assert');
const { execSync } = require('child_process');
const { openSync, chmodSync, fchmodSync, statSync, fstatSync } = require('fs');
/******************************************************************************/
const winFileAttribs = ['a', 'h', 'i', 'r', 's'];
const toggles = { 0: '-', 1: '+' };
const winFileAttribSets =
(new Array(Object.keys(toggles).length ** winFileAttribs.length))
.fill(0)
.map((set, setIndex) => setIndex
.toString(2)
.padStart(winFileAttribs.length, 0)
.split('')
.map((num, numIndex) =>
`${toggles[num]}${winFileAttribs[numIndex]}`)
.join(' '));
/******************************************************************************/
const RO = 0o100444; // 33060 0b1000000100100100
const RW = 0o100666; // 33206 0b1000000110110110
const filePath = 'abc.txt'; // or just __filename
const fd = openSync(filePath, 'a');
/******************************************************************************/
winFileAttribSets.forEach((winFileAttribSet) => {
process.stdout.write(`${winFileAttribSet}: `);
try {
execSync(`attrib ${winFileAttribSet} ${filePath}`);
chmodSync(filePath, RO);
strictEqual(statSync(filePath).mode, RO, 'chmodSync -> RO');
execSync(`attrib ${winFileAttribSet} ${filePath}`);
chmodSync(filePath, RW);
strictEqual(statSync(filePath).mode, RW, 'chmodSync -> RW');
execSync(`attrib ${winFileAttribSet} ${filePath}`);
fchmodSync(fd, RO);
strictEqual(fstatSync(fd).mode, RO, 'fchmodSync -> RO');
execSync(`attrib ${winFileAttribSet} ${filePath}`);
fchmodSync(fd, RW);
strictEqual(fstatSync(fd).mode, RW, 'fchmodSync -> RW');
console.log('OK');
} catch (err) {
console.log('not OK');
console.error('\n', err, '\n');
}
});
/******************************************************************************/ Output:-a -h -i -r -s: OK
-a -h -i -r +s: OK
-a -h -i +r -s: not OK
{ AssertionError: fchmodSync -> RW
at winFileAttribSets.forEach (e:\DOC\prg\js\node\-test\test.js:46:5)
at Array.forEach (native)
at Object.<anonymous> (e:\DOC\prg\js\node\-test\test.js:28:19)
at Module._compile (module.js:582:30)
at Object.Module._extensions..js (module.js:593:10)
at Module.load (module.js:516:32)
at tryModuleLoad (module.js:466:12)
at Function.Module._load (module.js:458:3)
at Function.Module.runMain (module.js:618:10)
at startup (bootstrap_node.js:144:16)
name: 'AssertionError',
actual: 33060,
expected: 33206,
operator: '===',
message: 'fchmodSync -> RW',
generatedMessage: false }
-a -h -i +r +s: OK
-a -h +i -r -s: OK
-a -h +i -r +s: OK
-a -h +i +r -s: OK
-a -h +i +r +s: OK
-a +h -i -r -s: OK
-a +h -i -r +s: OK
-a +h -i +r -s: OK
-a +h -i +r +s: OK
-a +h +i -r -s: OK
-a +h +i -r +s: OK
-a +h +i +r -s: OK
-a +h +i +r +s: OK
+a -h -i -r -s: OK
+a -h -i -r +s: OK
+a -h -i +r -s: OK
+a -h -i +r +s: OK
+a -h +i -r -s: OK
+a -h +i -r +s: OK
+a -h +i +r -s: OK
+a -h +i +r +s: OK
+a +h -i -r -s: OK
+a +h -i -r +s: OK
+a +h -i +r -s: OK
+a +h -i +r +s: OK
+a +h +i -r -s: OK
+a +h +i -r +s: OK
+a +h +i +r -s: OK
+a +h +i +r +s: OK |
Need a good debugging session... I'll start a build... |
|
So it's probably something with either 0 or a bad bit-mask. |
This is a trace of the system calls 19:35:14.2105663 2180 node.exe Read Metadata SUCCESS QueryBasicInformationFile D:\code\node\test\tmp\a1.js CreationTime: 04/05/2017 19:35:13 LastAccessTime: 04/05/2017 19:35:13 LastWriteTime: 25/04/2017 07:37:43 ChangeTime: 04/05/2017 19:35:14 FileAttributes: N REFAELUX\refael 19:35:14.2106125 2180 node.exe Write Metadata SUCCESS SetBasicInformationFile D:\code\node\test\tmp\a1.js CreationTime: 04/05/2017 19:35:13 LastAccessTime: 04/05/2017 19:35:13 LastWriteTime: 25/04/2017 07:37:43 ChangeTime: 04/05/2017 19:35:14 FileAttributes: RN REFAELUX\refael 19:35:14.2190395 2180 node.exe Read Metadata SUCCESS QueryBasicInformationFile D:\code\node\test\tmp\a1.js CreationTime: 04/05/2017 19:35:13 LastAccessTime: 04/05/2017 19:35:13 LastWriteTime: 25/04/2017 07:37:43 ChangeTime: 04/05/2017 19:35:14 FileAttributes: R REFAELUX\refael 19:35:14.2191066 2180 node.exe Write Metadata SUCCESS SetBasicInformationFile D:\code\node\test\tmp\a1.js CreationTime: 04/05/2017 19:35:13 LastAccessTime: 04/05/2017 19:35:13 LastWriteTime: 25/04/2017 07:37:43 ChangeTime: 04/05/2017 19:35:14 FileAttributes: n/a REFAELUX\refael 19:35:14.2191973 2180 node.exe Read Metadata BUFFER OVERFLOW QueryAllInformationFile D:\code\node\test\tmp\a1.js CreationTime: 04/05/2017 19:35:13 LastAccessTime: 04/05/2017 19:35:13 LastWriteTime: 25/04/2017 07:37:43 ChangeTime: 04/05/2017 19:35:14 FileAttributes: R AllocationSize: 4,096 EndOfFile: 1,469 NumberOfLinks: 1 DeletePending: False Directory: False IndexNumber: 0x70000002134f1 EaSize: 0 Access: Append Data/Add Subdirectory/Create Pipe Instance Write EA Read Attributes Write Attributes Read Control Synchronize Position: 0 Mode: Synchronous IO Non-Alert AlignmentRequirement: Word REFAELUX\refael |
@refack Sorry! I was wrong and the test was wrong. I've fixed it now and updated the log. We need to reset the set of file attributes each time to detect the problematic set and what change it disables. New conclusion: only |
This https://github.com/nodejs/node/pull/12835/files#diff-745585b335912e43a534e6175f659c70 test I added to #12835 reproduces every time. |
It's like you said, we start with a regular file, remove attributes, set RO, then can't set RW. |
@refack Maybe it is worth to set |
Currently this uncovers a regression in `fs.fchmodSync(fd, mode_sync);` No solution yet... Also as issue on macOS in test-fs-chmod:94 fail to access file1 Fixes:nodejs#12803
@refack Is this still being worked on? If not, might it make sense to unassign and/or add a |
Refs: #14926 |
The test has been rewritten by #14926. Can this be closed or is there more work to be done? |
@vsemozhetbyt can this be closed now? |
@richardlau , @bzoz I am not sure if rewriting the test resolves the issue in See also #12835. |
This allows for running uv_fs_fchmod on files with Archive flag cleared Refs: nodejs/node#12803
This is a bug in libuv, PR to fix: libuv/libuv#1777 |
This allows for running uv_fs_fchmod on files with Archive flag cleared Refs: nodejs/node#12803 PR-URL: #1777 Reviewed-By: Santiago Gimeno <[email protected]> Reviewed-By: Colin Ihrig <[email protected]>
Notable changes: - uv_fs_copyfile() adds support for copy-on-write behavior. - uv_relative_path() now uses the long directory name for handle->dirw. - File operations on files > 2 GB on 32-bit platforms are working again. - uv_fs_fchmod() on Windows works on files with the Archive flag cleared. Fixes: #19170 Fixes: #19455 Fixes: #12803 PR-URL: #19758 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Santiago Gimeno <[email protected]> Reviewed-By: James M Snell <[email protected]>
Adds uv_fs_chmod support for files with the Archive attribute cleared Ref: libuv#1777 Ref: nodejs/node#12803
Adds uv_fs_chmod support for files with the Archive attribute cleared Ref: libuv#1777 Ref: nodejs/node#12803 PR-URL: libuv#1819
Adds uv_fs_chmod support for files with the Archive attribute cleared Ref: #1777 Ref: nodejs/node#12803 PR-URL: #1819 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Colin Ihrig <[email protected]>
Notable changes: - Building via cmake is now supported. PR-URL: libuv/libuv#1850 - Stricter checks have been added to prevent watching the same file descriptor multiple times. PR-URL: libuv/libuv#1851 Refs: nodejs#3604 - An IPC deadlock on Windows has been fixed. PR-URL: libuv/libuv#1843 Fixes: nodejs#9706 Fixes: nodejs#7657 - uv_fs_lchown() has been added. PR-URL: libuv/libuv#1826 Refs: nodejs#19868 - uv_fs_copyfile() sets errno on error. PR-URL: libuv/libuv#1881 Fixes: nodejs#21329 - uv_fs_fchmod() supports -A files on Windows. PR-URL: libuv/libuv#1819 Refs: nodejs#12803 PR-URL: nodejs#21466 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Santiago Gimeno <[email protected]> Reviewed-By: James M Snell <[email protected]>
Notable changes: - Building via cmake is now supported. PR-URL: libuv/libuv#1850 - Stricter checks have been added to prevent watching the same file descriptor multiple times. PR-URL: libuv/libuv#1851 Refs: #3604 - An IPC deadlock on Windows has been fixed. PR-URL: libuv/libuv#1843 Fixes: #9706 Fixes: #7657 - uv_fs_lchown() has been added. PR-URL: libuv/libuv#1826 Refs: #19868 - uv_fs_copyfile() sets errno on error. PR-URL: libuv/libuv#1881 Fixes: #21329 - uv_fs_fchmod() supports -A files on Windows. PR-URL: libuv/libuv#1819 Refs: #12803 PR-URL: #21466 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Santiago Gimeno <[email protected]> Reviewed-By: James M Snell <[email protected]>
Notable changes: - uv_fs_copyfile() adds support for copy-on-write behavior. - uv_relative_path() now uses the long directory name for handle->dirw. - File operations on files > 2 GB on 32-bit platforms are working again. - uv_fs_fchmod() on Windows works on files with the Archive flag cleared. Fixes: #19170 Fixes: #19455 Fixes: #12803 PR-URL: #19758 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Santiago Gimeno <[email protected]> Reviewed-By: James M Snell <[email protected]>
Notable changes: - uv_fs_copyfile() adds support for copy-on-write behavior. - uv_relative_path() now uses the long directory name for handle->dirw. - File operations on files > 2 GB on 32-bit platforms are working again. - uv_fs_fchmod() on Windows works on files with the Archive flag cleared. Fixes: nodejs#19170 Fixes: nodejs#19455 Fixes: nodejs#12803 PR-URL: nodejs#19758 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Santiago Gimeno <[email protected]> Reviewed-By: James M Snell <[email protected]>
Notable changes: - Building via cmake is now supported. PR-URL: libuv/libuv#1850 - Stricter checks have been added to prevent watching the same file descriptor multiple times. PR-URL: libuv/libuv#1851 Refs: nodejs#3604 - An IPC deadlock on Windows has been fixed. PR-URL: libuv/libuv#1843 Fixes: nodejs#9706 Fixes: nodejs#7657 - uv_fs_lchown() has been added. PR-URL: libuv/libuv#1826 Refs: nodejs#19868 - uv_fs_copyfile() sets errno on error. PR-URL: libuv/libuv#1881 Fixes: nodejs#21329 - uv_fs_fchmod() supports -A files on Windows. PR-URL: libuv/libuv#1819 Refs: nodejs#12803 PR-URL: nodejs#21466 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Santiago Gimeno <[email protected]> Reviewed-By: James M Snell <[email protected]>
Notable changes: - uv_fs_copyfile() adds support for copy-on-write behavior. - uv_relative_path() now uses the long directory name for handle->dirw. - File operations on files > 2 GB on 32-bit platforms are working again. - uv_fs_fchmod() on Windows works on files with the Archive flag cleared. Backport-PR-URL: #24103 Fixes: #19170 Fixes: #19455 Fixes: #12803 PR-URL: #19758 Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Santiago Gimeno <[email protected]> Reviewed-By: James M Snell <[email protected]>
Notable changes: - Building via cmake is now supported. PR-URL: libuv/libuv#1850 - Stricter checks have been added to prevent watching the same file descriptor multiple times. PR-URL: libuv/libuv#1851 Refs: #3604 - An IPC deadlock on Windows has been fixed. PR-URL: libuv/libuv#1843 Fixes: #9706 Fixes: #7657 - uv_fs_lchown() has been added. PR-URL: libuv/libuv#1826 Refs: #19868 - uv_fs_copyfile() sets errno on error. PR-URL: libuv/libuv#1881 Fixes: #21329 - uv_fs_fchmod() supports -A files on Windows. PR-URL: libuv/libuv#1819 Refs: #12803 Backport-PR-URL: #24103 PR-URL: #21466 Reviewed-By: Anna Henningsen <[email protected]> Reviewed-By: Ben Noordhuis <[email protected]> Reviewed-By: Santiago Gimeno <[email protected]> Reviewed-By: James M Snell <[email protected]>
This is a confusing story here, so I am sorry for possibly clumsy wording.
Prehistory
I was launching tests with own test runner, each test with various context several times, and I've found out that
parallel/test-fs-chmod.js
was OK on the first run and failed on all the next ones. Moreover, this happened not on all the machines.This turned up to be caused by some combination of a fixture file attributes.
Excursus
See this small attrib doc for context.
The test fails if both
-a
and-i
flags are unset for a fixture file used in the test. This unsetting combination, strangely enough, correlates with this GUI setting:Screenshot:
How to reproduce
Try to run these commands with repo root as cwd (firstly, we set a combination of the
-a
and-i
flags; then we check the current attributes; then we run the test twice; then we check if the attributes are the same.;--no-deprecation
key there is due to cause of #12795).Commands :
I see this output (some path details stripped, borders added after each iteration):
Output:
As you can see, in the last case the second test fails and the file mode is changed.
What is going on here?
test/parallel/test-fs-chmod.js
changes the mode offixtures/a.js
withfs.chmod()
and the mode offixtures/a1.js
withfs.fchmod()
twice on Windows: to read-only and back to read-write. In case offixtures/a.js
andfs.chmod()
, all is OK even with-a
and-i
attributes unset (I've checked this). But withfixtures/a1.js
andfs.fchmod()
, the beforementioned edge case preventsfs.fchmod()
from the second change here: thefixtures/a1.js
remains read-only after the first test run andfs.open()
in append mode fails here on the second test run.Why the test does not detect this?
This assertion before failed
fs.fchmod()
call and this assertion after the failed call check the same mode number in the failed case, but as long as this number is not falsy, the second assertion does not throw. On Windows, this number is not falsy in all the cases: it just differs in normal cases and remains the same in the edge case.What possibly should be done?
fs.fchmod()
binding should be checked for this edge case. Maybe the bug should be reported upstream forlibuv
or even for Windows.Unfortunately, I cannot be any more help in this case, as I am not good in this realm. Sorry.
The text was updated successfully, but these errors were encountered: