Skip to content

vfs: lchmod follows symlinks instead of updating the link #64349

Description

@trivikr

Version

main

Platform

macOS 26.5.0

Subsystem

vfs

What steps will reproduce the bug?

import fs from 'node:fs/promises';
import path from 'node:path';
import vfs from 'node:vfs';

const mountPoint = path.resolve(`/tmp/vfs-lchmod-${process.pid}`);

const virtualFs = vfs.create({ emitExperimentalWarning: false });
virtualFs.writeFileSync('/target.txt', 'target');
virtualFs.symlinkSync('/target.txt', '/link.txt');
virtualFs.mount(mountPoint);

await fs.lchmod(path.join(mountPoint, 'link.txt'), 0o700);
virtualFs.unmount();

const targetStats = virtualFs.lstatSync('/target.txt');
const linkStats = virtualFs.lstatSync('/link.txt');

console.log({
  targetMode: targetStats.mode & 0o777,
  linkMode: linkStats.mode & 0o777,
});

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

Always

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

{ targetMode: 420, linkMode: 448 }

lchmod should operate on the symlink itself and leave the target metadata unchanged.

What do you see instead?

{ targetMode: 448, linkMode: 420 }

fs.promises.lchmod() changes the target file’s mode while the symlink’s own mode is unchanged.

Additional information

fs equivalent

import fs from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';

const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'fs-lchmod-'));
const target = path.join(dir, 'target.txt');
const link = path.join(dir, 'link.txt');

await fs.writeFile(target, 'target');
await fs.symlink(target, link);

await fs.lchmod(link, 0o700);

const targetStats = await fs.lstat(target);
const linkStats = await fs.lstat(link);

console.log({
  targetMode: targetStats.mode & 0o777,
  linkMode: linkStats.mode & 0o777,
});

await fs.rm(dir, { recursive: true, force: true });

Metadata

Metadata

Assignees

Labels

vfsIssues and PRs related to the virtual filesystem subsystem.

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions