Commit 76e8b64e5b5 for nodejs

commit 76e8b64e5b5514bd58ee5de5efdd57f0c4d77b8a
Author: Trivikram Kamat <trivikr.dev@gmail.com>
Date:   Mon Nov 2 13:19:09 2026 -0800

    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: https://github.com/nodejs/node/pull/66224
    Fixes: https://github.com/nodejs/node/issues/66223
    Reviewed-By: Matteo Collina <matteo.collina@gmail.com>

diff --git a/lib/internal/vfs/providers/real.js b/lib/internal/vfs/providers/real.js
index 2f25f582244..a3a5d6329a9 100644
--- a/lib/internal/vfs/providers/real.js
+++ b/lib/internal/vfs/providers/real.js
@@ -632,9 +632,9 @@ class RealFSProvider extends VirtualProvider {
     return fs.promises.watch(realPath, options);
   }

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

   unwatchFile(vfsPath, listener) {
diff --git a/test/parallel/test-vfs-real-provider-watch.js b/test/parallel/test-vfs-real-provider-watch.js
index 03563256202..fc1249837fa 100644
--- a/test/parallel/test-vfs-real-provider-watch.js
+++ b/test/parallel/test-vfs-real-provider-watch.js
@@ -35,10 +35,22 @@ assert.strictEqual(myVfs.provider.supportsWatch, true);
   await iter.return();
 })().then(common.mustCall());

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