owner.js 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192
  1. const { dirname, resolve } = require('path')
  2. const fileURLToPath = require('./file-url-to-path/index.js')
  3. const fs = require('../fs.js')
  4. // given a path, find the owner of the nearest parent
  5. const find = async (path) => {
  6. // if we have no getuid, permissions are irrelevant on this platform
  7. if (!process.getuid) {
  8. return {}
  9. }
  10. // fs methods accept URL objects with a scheme of file: so we need to unwrap
  11. // those into an actual path string before we can resolve it
  12. const resolved = path != null && path.href && path.origin
  13. ? resolve(fileURLToPath(path))
  14. : resolve(path)
  15. let stat
  16. try {
  17. stat = await fs.lstat(resolved)
  18. } finally {
  19. // if we got a stat, return its contents
  20. if (stat) {
  21. return { uid: stat.uid, gid: stat.gid }
  22. }
  23. // try the parent directory
  24. if (resolved !== dirname(resolved)) {
  25. return find(dirname(resolved))
  26. }
  27. // no more parents, never got a stat, just return an empty object
  28. return {}
  29. }
  30. }
  31. // given a path, uid, and gid update the ownership of the path if necessary
  32. const update = async (path, uid, gid) => {
  33. // nothing to update, just exit
  34. if (uid === undefined && gid === undefined) {
  35. return
  36. }
  37. try {
  38. // see if the permissions are already the same, if they are we don't
  39. // need to do anything, so return early
  40. const stat = await fs.stat(path)
  41. if (uid === stat.uid && gid === stat.gid) {
  42. return
  43. }
  44. } catch (err) {}
  45. try {
  46. await fs.chown(path, uid, gid)
  47. } catch (err) {}
  48. }
  49. // accepts a `path` and the `owner` property of an options object and normalizes
  50. // it into an object with numerical `uid` and `gid`
  51. const validate = async (path, input) => {
  52. let uid
  53. let gid
  54. if (typeof input === 'string' || typeof input === 'number') {
  55. uid = input
  56. gid = input
  57. } else if (input && typeof input === 'object') {
  58. uid = input.uid
  59. gid = input.gid
  60. }
  61. if (uid === 'inherit' || gid === 'inherit') {
  62. const owner = await find(path)
  63. if (uid === 'inherit') {
  64. uid = owner.uid
  65. }
  66. if (gid === 'inherit') {
  67. gid = owner.gid
  68. }
  69. }
  70. return { uid, gid }
  71. }
  72. module.exports = {
  73. find,
  74. update,
  75. validate,
  76. }