Skip to content

Commit 1d4e86e

Browse files
authored
vfs: make lchmod update symlink mode
Use a non-following provider operation for lchmod so it updates the symbolic link metadata instead of changing the target file mode. Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com> Assisted-by: openai:gpt-5.5 PR-URL: #64350 Fixes: #64349 Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
1 parent 89df046 commit 1d4e86e

4 files changed

Lines changed: 29 additions & 1 deletion

File tree

lib/internal/vfs/file_system.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1255,7 +1255,7 @@ class VirtualFileSystem {
12551255

12561256
async lchmod(filePath, mode) {
12571257
const providerPath = toProviderPath(filePath);
1258-
provider.chmodSync(providerPath, mode);
1258+
provider.lchmodSync(providerPath, mode);
12591259
},
12601260

12611261
watch(filePath, options) {

lib/internal/vfs/providers/memory.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -957,6 +957,13 @@ class MemoryProvider extends VirtualProvider {
957957
entry.ctime = DateNow();
958958
}
959959

960+
lchmodSync(path, mode) {
961+
const entry = this.#getEntry(path, 'chmod', false);
962+
// Preserve file type bits, update permission bits
963+
entry.mode = (entry.mode & ~0o7777) | (mode & 0o7777);
964+
entry.ctime = DateNow();
965+
}
966+
960967
chownSync(path, uid, gid) {
961968
const entry = this.#getEntry(path, 'chown', true);
962969
if (uid >= 0) entry.uid = uid;

lib/internal/vfs/providers/real.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ const { VirtualProvider } = require('internal/vfs/provider');
1313
const { VirtualFileHandle } = require('internal/vfs/file_handle');
1414
const { getValidatedPath } = require('internal/fs/utils');
1515
const { setOwnProperty } = require('internal/util');
16+
const {
17+
ERR_METHOD_NOT_IMPLEMENTED,
18+
} = require('internal/errors').codes;
1619
const {
1720
createEACCES,
1821
createEBADF,
@@ -517,6 +520,14 @@ class RealFSProvider extends VirtualProvider {
517520
return fs.promises.access(realPath, mode);
518521
}
519522

523+
lchmodSync(vfsPath, mode) {
524+
if (fs.lchmodSync === undefined) {
525+
throw new ERR_METHOD_NOT_IMPLEMENTED('lchmodSync');
526+
}
527+
const realPath = this.#resolvePath(vfsPath, false);
528+
fs.lchmodSync(realPath, mode);
529+
}
530+
520531
copyFileSync(srcVfsPath, destVfsPath, mode) {
521532
const srcRealPath = this.#resolvePath(srcVfsPath);
522533
const destRealPath = this.#resolvePath(destVfsPath);

test/parallel/test-vfs-fs-promises.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,16 @@ const vfs = require('node:vfs');
7575
await fsp.utimes(p('src/hello.txt'), now, now);
7676
await fsp.lutimes(p('src/hello.txt'), now, now);
7777

78+
await fsp.lchmod(p('src/plnk.txt'), 0o700);
79+
assert.strictEqual(
80+
(await fsp.lstat(p('src/hello.txt'))).mode & 0o777,
81+
0o644,
82+
);
83+
assert.strictEqual(
84+
(await fsp.lstat(p('src/plnk.txt'))).mode & 0o777,
85+
0o700,
86+
);
87+
7888
// FileHandle via fsp.open
7989
const handle = await fsp.open(p('src/hello.txt'), 'r');
8090
assert.strictEqual(await handle.readFile('utf8'), 'hello');

0 commit comments

Comments
 (0)