GeezerVison is showing github.com — vfs: make lchown update symlink metadata · nodejs/node@4345185
File treeExpand file treeCollapse file tree Open diff view settings Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: doc/api/vfs.md +1Lines changed: 1 addition & 0 deletions - Display the source diff
- Display the rich diff
| Original file line number | Diff line number | Diff line change |
|---|
@@ -156,6 +156,7 @@ signatures as their [`node:fs`][] counterparts: | 156 | 156 | * `linkSync(existingPath, newPath)` | 157 | 157 | * `chmodSync(path, mode)` | 158 | 158 | * `chownSync(path, uid, gid)` | | 159 | +* `lchownSync(path, uid, gid)` | 159 | 160 | * `utimesSync(path, atime, mtime)` | 160 | 161 | * `lutimesSync(path, atime, mtime)` | 161 | 162 | * `mkdtempSync(prefix)` | |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/vfs/file_system.js +6-1Lines changed: 6 additions & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -506,6 +506,11 @@ class VirtualFileSystem { | 506 | 506 | this[kProvider].chownSync(providerPath, uid, gid); | 507 | 507 | } | 508 | 508 |
| | 509 | + lchownSync(filePath, uid, gid) { | | 510 | + const providerPath = this.#toProviderPath(filePath); | | 511 | + this[kProvider].lchownSync(providerPath, uid, gid); | | 512 | + } | | 513 | + | 509 | 514 | utimesSync(filePath, atime, mtime) { | 510 | 515 | const providerPath = this.#toProviderPath(filePath); | 511 | 516 | this[kProvider].utimesSync(providerPath, atime, mtime); | @@ -1234,7 +1239,7 @@ class VirtualFileSystem { | 1234 | 1239 |
| 1235 | 1240 | async lchown(filePath, uid, gid) { | 1236 | 1241 | const providerPath = toProviderPath(filePath); | 1237 | | - provider.chownSync(providerPath, uid, gid); | | 1242 | + provider.lchownSync(providerPath, uid, gid); | 1238 | 1243 | }, | 1239 | 1244 |
| 1240 | 1245 | async utimes(filePath, atime, mtime) { | |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/vfs/provider.js +12Lines changed: 12 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -235,6 +235,18 @@ class VirtualProvider { | 235 | 235 | throw new ERR_METHOD_NOT_IMPLEMENTED('renameSync'); | 236 | 236 | } | 237 | 237 |
| | 238 | + /** | | 239 | + * Changes ownership of a path without following the final symbolic link. | | 240 | + * Providers with symlink support should override this. | | 241 | + * @param {string} path The path | | 242 | + * @param {number} uid The user id | | 243 | + * @param {number} gid The group id | | 244 | + * @returns {void} | | 245 | + */ | | 246 | + lchownSync(path, uid, gid) { | | 247 | + return this.chownSync(path, uid, gid); | | 248 | + } | | 249 | + | 238 | 250 | // === DEFAULT IMPLEMENTATIONS (built on primitives) === | 239 | 251 |
| 240 | 252 | /** | |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/vfs/providers/memory.js +7Lines changed: 7 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
@@ -986,6 +986,13 @@ class MemoryProvider extends VirtualProvider { | 986 | 986 | entry.ctime = DateNow(); | 987 | 987 | } | 988 | 988 |
| | 989 | + lchownSync(path, uid, gid) { | | 990 | + const entry = this.#getEntry(path, 'chown', false); | | 991 | + if (uid >= 0) entry.uid = uid; | | 992 | + if (gid >= 0) entry.gid = gid; | | 993 | + entry.ctime = DateNow(); | | 994 | + } | | 995 | + | 989 | 996 | utimesSync(path, atime, mtime) { | 990 | 997 | const entry = this.#getEntry(path, 'utime', true); | 991 | 998 | entry.atime = toMs(atime); | |
Collapse file Copy file name to clipboardExpand all lines: lib/internal/vfs/setup.js +1-1Lines changed: 1 addition & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -343,7 +343,7 @@ function createVfsHandlers() { | 343 | 343 | vfsOpVoid(path, (vfs, n) => vfs.symlinkSync(target, n, type)), | 344 | 344 | chmodSync: (path, mode) => vfsOpVoid(path, (vfs, n) => vfs.chmodSync(n, mode)), | 345 | 345 | chownSync: (path, uid, gid) => vfsOpVoid(path, (vfs, n) => vfs.chownSync(n, uid, gid)), | 346 | | - lchownSync: (path, uid, gid) => vfsOpVoid(path, (vfs, n) => vfs.chownSync(n, uid, gid)), | | 346 | + lchownSync: (path, uid, gid) => vfsOpVoid(path, (vfs, n) => vfs.lchownSync(n, uid, gid)), | 347 | 347 | utimesSync: (path, atime, mtime) => | 348 | 348 | vfsOpVoid(path, (vfs, n) => vfs.utimesSync(n, atime, mtime)), | 349 | 349 | lutimesSync: (path, atime, mtime) => | |
Collapse file Copy file name to clipboard +48Lines changed: 48 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +// Flags: --experimental-vfs | | 2 | +'use strict'; | | 3 | + | | 4 | +const common = require('../common'); | | 5 | +const assert = require('assert'); | | 6 | +const fs = require('fs'); | | 7 | +const fsp = require('fs/promises'); | | 8 | +const path = require('path'); | | 9 | +const vfs = require('node:vfs'); | | 10 | + | | 11 | +const mountPoint = path.resolve('/tmp/vfs-lchown-' + process.pid); | | 12 | +const myVfs = vfs.create(); | | 13 | +myVfs.writeFileSync('/sync-target.txt', 'target'); | | 14 | +myVfs.symlinkSync('/sync-target.txt', '/sync-link.txt'); | | 15 | +myVfs.writeFileSync('/async-target.txt', 'target'); | | 16 | +myVfs.symlinkSync('/async-target.txt', '/async-link.txt'); | | 17 | +myVfs.writeFileSync('/promise-target.txt', 'target'); | | 18 | +myVfs.symlinkSync('/promise-target.txt', '/promise-link.txt'); | | 19 | +myVfs.mount(mountPoint); | | 20 | + | | 21 | +function assertOwnership(filePath, uid, gid) { | | 22 | + const stats = fs.lstatSync(path.join(mountPoint, filePath)); | | 23 | + assert.strictEqual(stats.uid, uid); | | 24 | + assert.strictEqual(stats.gid, gid); | | 25 | +} | | 26 | + | | 27 | +(async () => { | | 28 | + try { | | 29 | + fs.lchownSync(path.join(mountPoint, 'sync-link.txt'), 123, 456); | | 30 | + assertOwnership('/sync-target.txt', 0, 0); | | 31 | + assertOwnership('/sync-link.txt', 123, 456); | | 32 | + | | 33 | + await new Promise((resolve, reject) => { | | 34 | + fs.lchown(path.join(mountPoint, 'async-link.txt'), 234, 567, (err) => { | | 35 | + if (err) reject(err); | | 36 | + else resolve(); | | 37 | + }); | | 38 | + }); | | 39 | + assertOwnership('/async-target.txt', 0, 0); | | 40 | + assertOwnership('/async-link.txt', 234, 567); | | 41 | + | | 42 | + await fsp.lchown(path.join(mountPoint, 'promise-link.txt'), 345, 678); | | 43 | + assertOwnership('/promise-target.txt', 0, 0); | | 44 | + assertOwnership('/promise-link.txt', 345, 678); | | 45 | + } finally { | | 46 | + myVfs.unmount(); | | 47 | + } | | 48 | +})().then(common.mustCall()); |
|