Skip to content

Commit

Permalink
fs: do not crash if the watched file is removed while setting up watch
Browse files Browse the repository at this point in the history
Signed-off-by: Matteo Collina <[email protected]>
PR-URL: nodejs#53452
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Moshe Atlow <[email protected]>
Reviewed-By: Marco Ippolito <[email protected]>
Reviewed-By: Chemi Atlow <[email protected]>
Reviewed-By: Luigi Pinca <[email protected]>
Reviewed-By: Yagiz Nizipli <[email protected]>
  • Loading branch information
mcollina authored and EliphazBouye committed Jun 20, 2024
1 parent e194df9 commit 208df39
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 5 deletions.
17 changes: 12 additions & 5 deletions lib/internal/fs/recursive_watch.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ class FSWatcher extends EventEmitter {
this.#closed = true;

for (const file of this.#files.keys()) {
this.#watchers.get(file).close();
this.#watchers.get(file)?.close();
this.#watchers.delete(file);
}

Expand All @@ -98,7 +98,7 @@ class FSWatcher extends EventEmitter {
for (const filename of this.#files.keys()) {
if (StringPrototypeStartsWith(filename, file)) {
this.#files.delete(filename);
this.#watchers.get(filename).close();
this.#watchers.get(filename)?.close();
this.#watchers.delete(filename);
}
}
Expand Down Expand Up @@ -126,9 +126,16 @@ class FSWatcher extends EventEmitter {
this.#symbolicFiles.add(f);
}

this.#watchFile(f);
if (file.isDirectory() && !file.isSymbolicLink()) {
this.#watchFolder(f);
try {
this.#watchFile(f);
if (file.isDirectory() && !file.isSymbolicLink()) {
this.#watchFolder(f);
}
} catch (err) {
// Ignore ENOENT
if (err.code !== 'ENOENT') {
throw err;
}
}
}
}
Expand Down
33 changes: 33 additions & 0 deletions test/parallel/test-fs-watch-recursive-linux-parallel-remove.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
'use strict';

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

if (!common.isLinux)
common.skip('This test can run only on Linux');

// Test that the watcher do not crash if the file "disappears" while
// watch is being set up.

const path = require('node:path');
const fs = require('node:fs');
const { spawn } = require('node:child_process');

const tmpdir = require('../common/tmpdir');
const testDir = tmpdir.path;
tmpdir.refresh();

const watcher = fs.watch(testDir, { recursive: true });
watcher.on('change', function(event, filename) {
// This console.log makes the error happen
// do not remove
console.log(filename, event);
});

const testFile = path.join(testDir, 'a');
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}') }`], {
stdio: 'inherit'
});

child.on('exit', function() {
watcher.close();
});

0 comments on commit 208df39

Please sign in to comment.