Skip to content

Commit 7430638

Browse files
authored
fs: do not crash if the watched file is removed while setting up watch
Signed-off-by: Matteo Collina <hello@matteocollina.com> PR-URL: #53452 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Moshe Atlow <moshe@atlow.co.il> Reviewed-By: Marco Ippolito <marcoippolito54@gmail.com> Reviewed-By: Chemi Atlow <chemi@atlow.co.il> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Yagiz Nizipli <yagiz.nizipli@sentry.io>
1 parent ee5c6b6 commit 7430638

File tree

2 files changed

+45
-5
lines changed

2 files changed

+45
-5
lines changed

lib/internal/fs/recursive_watch.js

+12-5
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ class FSWatcher extends EventEmitter {
8383
this.#closed = true;
8484

8585
for (const file of this.#files.keys()) {
86-
this.#watchers.get(file).close();
86+
this.#watchers.get(file)?.close();
8787
this.#watchers.delete(file);
8888
}
8989

@@ -98,7 +98,7 @@ class FSWatcher extends EventEmitter {
9898
for (const filename of this.#files.keys()) {
9999
if (StringPrototypeStartsWith(filename, file)) {
100100
this.#files.delete(filename);
101-
this.#watchers.get(filename).close();
101+
this.#watchers.get(filename)?.close();
102102
this.#watchers.delete(filename);
103103
}
104104
}
@@ -126,9 +126,16 @@ class FSWatcher extends EventEmitter {
126126
this.#symbolicFiles.add(f);
127127
}
128128

129-
this.#watchFile(f);
130-
if (file.isDirectory() && !file.isSymbolicLink()) {
131-
this.#watchFolder(f);
129+
try {
130+
this.#watchFile(f);
131+
if (file.isDirectory() && !file.isSymbolicLink()) {
132+
this.#watchFolder(f);
133+
}
134+
} catch (err) {
135+
// Ignore ENOENT
136+
if (err.code !== 'ENOENT') {
137+
throw err;
138+
}
132139
}
133140
}
134141
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
'use strict';
2+
3+
const common = require('../common');
4+
5+
if (!common.isLinux)
6+
common.skip('This test can run only on Linux');
7+
8+
// Test that the watcher do not crash if the file "disappears" while
9+
// watch is being set up.
10+
11+
const path = require('node:path');
12+
const fs = require('node:fs');
13+
const { spawn } = require('node:child_process');
14+
15+
const tmpdir = require('../common/tmpdir');
16+
const testDir = tmpdir.path;
17+
tmpdir.refresh();
18+
19+
const watcher = fs.watch(testDir, { recursive: true });
20+
watcher.on('change', function(event, filename) {
21+
// This console.log makes the error happen
22+
// do not remove
23+
console.log(filename, event);
24+
});
25+
26+
const testFile = path.join(testDir, 'a');
27+
const child = spawn(process.argv[0], ['-e', `const fs = require('node:fs'); for (let i = 0; i < 10000; i++) { const fd = fs.openSync('${testFile}', 'w'); fs.writeSync(fd, Buffer.from('hello')); fs.rmSync('${testFile}') }`], {
28+
stdio: 'inherit'
29+
});
30+
31+
child.on('exit', function() {
32+
watcher.close();
33+
});

0 commit comments

Comments
 (0)