Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

chownr.js 3.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. 'use strict'
  2. const fs = require('fs')
  3. const path = require('path')
  4. /* istanbul ignore next */
  5. const LCHOWN = fs.lchown ? 'lchown' : 'chown'
  6. /* istanbul ignore next */
  7. const LCHOWNSYNC = fs.lchownSync ? 'lchownSync' : 'chownSync'
  8. const needEISDIRHandled = fs.lchown &&
  9. !process.version.match(/v1[1-9]+\./) &&
  10. !process.version.match(/v10\.[6-9]/)
  11. /* istanbul ignore next */
  12. const handleEISDIR =
  13. needEISDIRHandled ? (path, uid, gid, cb) => er => {
  14. // Node prior to v10 had a very questionable implementation of
  15. // fs.lchown, which would always try to call fs.open on a directory
  16. // Fall back to fs.chown in those cases.
  17. if (!er || er.code !== 'EISDIR')
  18. cb(er)
  19. else
  20. fs.chown(path, uid, gid, cb)
  21. }
  22. : (_, __, ___, cb) => cb
  23. /* istanbul ignore next */
  24. const handleEISDirSync =
  25. needEISDIRHandled ? (path, uid, gid) => {
  26. try {
  27. return fs[LCHOWNSYNC](path, uid, gid)
  28. } catch (er) {
  29. if (er.code !== 'EISDIR')
  30. throw er
  31. fs.chownSync(path, uid, gid)
  32. }
  33. }
  34. : fs[LCHOWNSYNC]
  35. // fs.readdir could only accept an options object as of node v6
  36. const nodeVersion = process.version
  37. let readdir = (path, options, cb) => fs.readdir(path, options, cb)
  38. let readdirSync = (path, options) => fs.readdirSync(path, options)
  39. /* istanbul ignore next */
  40. if (/^v4\./.test(nodeVersion))
  41. readdir = (path, options, cb) => fs.readdir(path, cb)
  42. const chownrKid = (p, child, uid, gid, cb) => {
  43. if (typeof child === 'string')
  44. return fs.lstat(path.resolve(p, child), (er, stats) => {
  45. if (er)
  46. return cb(er)
  47. stats.name = child
  48. chownrKid(p, stats, uid, gid, cb)
  49. })
  50. if (child.isDirectory()) {
  51. chownr(path.resolve(p, child.name), uid, gid, er => {
  52. if (er)
  53. return cb(er)
  54. const cpath = path.resolve(p, child.name)
  55. fs[LCHOWN](cpath, uid, gid, handleEISDIR(cpath, uid, gid, cb))
  56. })
  57. } else {
  58. const cpath = path.resolve(p, child.name)
  59. fs[LCHOWN](cpath, uid, gid, handleEISDIR(cpath, uid, gid, cb))
  60. }
  61. }
  62. const chownr = (p, uid, gid, cb) => {
  63. readdir(p, { withFileTypes: true }, (er, children) => {
  64. // any error other than ENOTDIR or ENOTSUP means it's not readable,
  65. // or doesn't exist. give up.
  66. if (er && er.code !== 'ENOTDIR' && er.code !== 'ENOTSUP')
  67. return cb(er)
  68. if (er || !children.length)
  69. return fs[LCHOWN](p, uid, gid, handleEISDIR(p, uid, gid, cb))
  70. let len = children.length
  71. let errState = null
  72. const then = er => {
  73. if (errState)
  74. return
  75. if (er)
  76. return cb(errState = er)
  77. if (-- len === 0)
  78. return fs[LCHOWN](p, uid, gid, handleEISDIR(p, uid, gid, cb))
  79. }
  80. children.forEach(child => chownrKid(p, child, uid, gid, then))
  81. })
  82. }
  83. const chownrKidSync = (p, child, uid, gid) => {
  84. if (typeof child === 'string') {
  85. const stats = fs.lstatSync(path.resolve(p, child))
  86. stats.name = child
  87. child = stats
  88. }
  89. if (child.isDirectory())
  90. chownrSync(path.resolve(p, child.name), uid, gid)
  91. handleEISDirSync(path.resolve(p, child.name), uid, gid)
  92. }
  93. const chownrSync = (p, uid, gid) => {
  94. let children
  95. try {
  96. children = readdirSync(p, { withFileTypes: true })
  97. } catch (er) {
  98. if (er && er.code === 'ENOTDIR' && er.code !== 'ENOTSUP')
  99. return handleEISDirSync(p, uid, gid)
  100. throw er
  101. }
  102. if (children.length)
  103. children.forEach(child => chownrKidSync(p, child, uid, gid))
  104. return handleEISDirSync(p, uid, gid)
  105. }
  106. module.exports = chownr
  107. chownr.sync = chownrSync