diff --git a/lib/internal/vfs/file_system.js b/lib/internal/vfs/file_system.js index ae38639582581b..542b63d5f079b0 100644 --- a/lib/internal/vfs/file_system.js +++ b/lib/internal/vfs/file_system.js @@ -1255,7 +1255,7 @@ class VirtualFileSystem { async lchmod(filePath, mode) { const providerPath = toProviderPath(filePath); - provider.chmodSync(providerPath, mode); + provider.lchmodSync(providerPath, mode); }, watch(filePath, options) { diff --git a/lib/internal/vfs/providers/memory.js b/lib/internal/vfs/providers/memory.js index a5681dfab1ca43..8490340101bc07 100644 --- a/lib/internal/vfs/providers/memory.js +++ b/lib/internal/vfs/providers/memory.js @@ -957,6 +957,13 @@ class MemoryProvider extends VirtualProvider { entry.ctime = DateNow(); } + lchmodSync(path, mode) { + const entry = this.#getEntry(path, 'chmod', false); + // Preserve file type bits, update permission bits + entry.mode = (entry.mode & ~0o7777) | (mode & 0o7777); + entry.ctime = DateNow(); + } + chownSync(path, uid, gid) { const entry = this.#getEntry(path, 'chown', true); if (uid >= 0) entry.uid = uid; diff --git a/lib/internal/vfs/providers/real.js b/lib/internal/vfs/providers/real.js index 085485ca8a1a97..df9bd00ac1adc4 100644 --- a/lib/internal/vfs/providers/real.js +++ b/lib/internal/vfs/providers/real.js @@ -13,6 +13,9 @@ const { VirtualProvider } = require('internal/vfs/provider'); const { VirtualFileHandle } = require('internal/vfs/file_handle'); const { getValidatedPath } = require('internal/fs/utils'); const { setOwnProperty } = require('internal/util'); +const { + ERR_METHOD_NOT_IMPLEMENTED, +} = require('internal/errors').codes; const { createEACCES, createEBADF, @@ -517,6 +520,14 @@ class RealFSProvider extends VirtualProvider { return fs.promises.access(realPath, mode); } + lchmodSync(vfsPath, mode) { + if (fs.lchmodSync === undefined) { + throw new ERR_METHOD_NOT_IMPLEMENTED('lchmodSync'); + } + const realPath = this.#resolvePath(vfsPath, false); + fs.lchmodSync(realPath, mode); + } + copyFileSync(srcVfsPath, destVfsPath, mode) { const srcRealPath = this.#resolvePath(srcVfsPath); const destRealPath = this.#resolvePath(destVfsPath); diff --git a/test/parallel/test-vfs-fs-promises.js b/test/parallel/test-vfs-fs-promises.js index d4b151162f2802..0f09c96f83aec5 100644 --- a/test/parallel/test-vfs-fs-promises.js +++ b/test/parallel/test-vfs-fs-promises.js @@ -75,6 +75,16 @@ const vfs = require('node:vfs'); await fsp.utimes(p('src/hello.txt'), now, now); await fsp.lutimes(p('src/hello.txt'), now, now); + await fsp.lchmod(p('src/plnk.txt'), 0o700); + assert.strictEqual( + (await fsp.lstat(p('src/hello.txt'))).mode & 0o777, + 0o644, + ); + assert.strictEqual( + (await fsp.lstat(p('src/plnk.txt'))).mode & 0o777, + 0o700, + ); + // FileHandle via fsp.open const handle = await fsp.open(p('src/hello.txt'), 'r'); assert.strictEqual(await handle.readFile('utf8'), 'hello');