Skip to content

Commit 76e8b64

Browse files
authored
vfs: forward the watchFile listener through RealFSProvider
fs.watchFile() on a path served by a real-directory mount dispatches to RealFSProvider.watchFile(), which ignored the supplied listener and registered an empty function instead. The user callback never fired after the file changed, and fs.unwatchFile(path, listener) could not match the anonymous stub, so the stat watcher's poll timer stayed registered and kept the process alive. Accept the listener and pass it through to fs.watchFile() so the callback fires on change and unwatchFile() removes it by identity. Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com> Assisted-by: opencode PR-URL: #66224 Fixes: #66223 Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
1 parent f72100b commit 76e8b64

2 files changed

Lines changed: 18 additions & 6 deletions

File tree

‎lib/internal/vfs/providers/real.js‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -632,9 +632,9 @@ class RealFSProvider extends VirtualProvider {
632632
return fs.promises.watch(realPath, options);
633633
}
634634

635-
watchFile(vfsPath, options) {
635+
watchFile(vfsPath, options, listener) {
636636
const realPath = this.#resolvePath(vfsPath);
637-
return fs.watchFile(realPath, options, () => {});
637+
return fs.watchFile(realPath, options, listener);
638638
}
639639

640640
unwatchFile(vfsPath, listener) {

‎test/parallel/test-vfs-real-provider-watch.js‎

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,22 @@ assert.strictEqual(myVfs.provider.supportsWatch, true);
3535
await iter.return();
3636
})().then(common.mustCall());
3737

38-
// watchFile / unwatchFile
38+
// watchFile / unwatchFile: the listener must be forwarded to the real fs
39+
// watcher (not stubbed), fire on change, and be removable by identity.
3940
{
4041
fs.writeFileSync(path.join(root, 'wf.txt'), 'a');
41-
const listener = () => {};
42-
myVfs.watchFile('/wf.txt', { persistent: false }, listener);
43-
myVfs.unwatchFile('/wf.txt', listener);
42+
// Unwatch on the first call because writeFileSync truncates before writing,
43+
// so a poll landing between the two would report a second change. The
44+
// watcher is persistent, so the process only exits once it has been removed.
45+
const listener = common.mustCall(() => {
46+
myVfs.unwatchFile('/wf.txt', listener);
47+
});
48+
myVfs.watchFile('/wf.txt', { interval: 10 }, listener);
49+
// uv_fs_poll records the first stat asynchronously as the baseline and
50+
// only reports subsequent changes, so mutate the file only after that
51+
// baseline reflects 'a'; otherwise the change is folded into the baseline
52+
// and the listener never fires. Change the size too, because some
53+
// platforms (e.g. AIX) only report timestamps to the second, so a
54+
// same-size rewrite within that second would look unchanged.
55+
setTimeout(() => fs.writeFileSync(path.join(root, 'wf.txt'), 'bb'), 100);
4456
}

0 commit comments

Comments
 (0)