readonly filesystem functions mutate `mtime` of parent directories
While experimenting with memfs, I noticed a surprising behavior: calling fs.statSync(path) (or likely fs.stat) appears to mutate the mtime of the parent directory, even if no write operation is involved.
This seems counter to expectations — especially for applications treating the in-memory filesystem as read-only or deterministic.
Minimal reproduction
Here’s a minimal script to test and demonstrate the issue:
import { memfs } from 'memfs';
import { dirname } from 'path';
function test(json, path, cwd) {
const { fs } = memfs(json, cwd);
const dir = dirname(path);
// Set known mtime on parent directory
const initialMtime = 100000;
fs.utimesSync(dir, initialMtime, initialMtime);
const mtimeBefore = fs.statSync(dir).mtimeMs;
// Read metadata of target path
fs.statSync(path);
const mtimeAfter = fs.statSync(dir).mtimeMs;
const mutated = mtimeAfter !== mtimeBefore;
console.log(path, mutated ? `BUG: mtime changed! ${mtimeBefore} -> ${mtimeAfter}` : 'OK: mtime unchanged.');
return mutated;
}
// Try on a directory
test({ testDir: {} }, '/testDir');
// Try on a file
test({ testFile: 'hello' }, '/testFile');
Output observed
/testDir BUG: mtime changed! 100000 -> 1750326756327
/testFile BUG: mtime changed! 100000 -> 1750326756330
This suggests that even simple statSync calls are causing the parent directory's mtime to update to the current time.
Edit: this doesn't appear to just affect stat. Other read-only operations like readdir seem to cause the issue
Update: After investigation, I traced the mtime mutation to a specific line in Link.prototype.getChild, where this.getNode().mtime = new Date() is called unconditionally. This happens even during readonly operations like statSync() or readdirSync(), which violates POSIX expectations.
This method is a pure lookup and should not mutate timestamps.