Skip to content

openAsBlob only looks at nanoseconds part of mtime to detect modifications #67283

Open

Description

@bakkot

Version

v28.0.0-pre

Platform

Darwin

Subsystem

fs

What steps will reproduce the bug?

On a filesystem with low-precision timestamps (e.g. FAT), openAsBlob a file, then edit the file but keep the size, then read from the blob. This should give NotReadableError because the file has changed, but it works because is_modified only checks tv_nsec, which is always 0 on FAT, and ignores tv_sec.

Runnable repro (from Claude), requires you to pass a path to a writable directory on a FAT volume:

'use strict';

const fs = require('fs');
const path = require('path');

if (process.argv.length !== 3) {
  console.error('must pass a path to a directory on a FAT volume');
  process.exit(1);
}

const dir = fs.mkdtempSync(path.join(process.argv[2], 'blob-mtime-'));
const file = path.join(dir, 'x');
fs.writeFileSync(file, 'from-a');

(async () => {
  const blob = await fs.openAsBlob(file);
  console.log('original:      ', await blob.text());
  await new Promise((r) => setTimeout(r, 2500));  // Past FAT's 2s granularity.
  fs.writeFileSync(file, 'EDITED');  // Same size.
  console.log('mtimeNs:       ', fs.statSync(file, { bigint: true }).mtimeNs);
  try {
    console.log('after rewrite: ', await blob.text());
  } catch (e) {
    console.log('after rewrite: ', e.name);
  }
  fs.rmSync(dir, { recursive: true });
})();

On MacOS you can make and mount a FAT volume like this:

hdiutil create -size 16m -fs MS-DOS -volname BLOBFAT -o fat.dmg
hdiutil attach -nobrowse fat.dmg      # mounts at /Volumes/BLOBFAT

then clean up with

hdiutil detach /Volumes/BLOBFAT
rm fat.dmg

when you're done.

How often does it reproduce? Is there a required condition?

Always.

What is the expected behavior? Why is that the expected behavior?

Should throw NotReadableError, like it would on a filesystem with high-precision timestamps.

What do you see instead?

"EDITED"

Additional information

This should at least check st_mtim.tv_sec, probably also both of those fields for st_ctim, arguably also st_ino and st_dev.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions