| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 | 
							- 'use strict'
 
- const fs = require('fs')
 
- const path = require('path')
 
- /* istanbul ignore next */
 
- const LCHOWN = fs.lchown ? 'lchown' : 'chown'
 
- /* istanbul ignore next */
 
- const LCHOWNSYNC = fs.lchownSync ? 'lchownSync' : 'chownSync'
 
- /* istanbul ignore next */
 
- const needEISDIRHandled = fs.lchown &&
 
-   !process.version.match(/v1[1-9]+\./) &&
 
-   !process.version.match(/v10\.[6-9]/)
 
- const lchownSync = (path, uid, gid) => {
 
-   try {
 
-     return fs[LCHOWNSYNC](path, uid, gid)
 
-   } catch (er) {
 
-     if (er.code !== 'ENOENT')
 
-       throw er
 
-   }
 
- }
 
- /* istanbul ignore next */
 
- const chownSync = (path, uid, gid) => {
 
-   try {
 
-     return fs.chownSync(path, uid, gid)
 
-   } catch (er) {
 
-     if (er.code !== 'ENOENT')
 
-       throw er
 
-   }
 
- }
 
- /* istanbul ignore next */
 
- const handleEISDIR =
 
-   needEISDIRHandled ? (path, uid, gid, cb) => er => {
 
-     // Node prior to v10 had a very questionable implementation of
 
-     // fs.lchown, which would always try to call fs.open on a directory
 
-     // Fall back to fs.chown in those cases.
 
-     if (!er || er.code !== 'EISDIR')
 
-       cb(er)
 
-     else
 
-       fs.chown(path, uid, gid, cb)
 
-   }
 
-   : (_, __, ___, cb) => cb
 
- /* istanbul ignore next */
 
- const handleEISDirSync =
 
-   needEISDIRHandled ? (path, uid, gid) => {
 
-     try {
 
-       return lchownSync(path, uid, gid)
 
-     } catch (er) {
 
-       if (er.code !== 'EISDIR')
 
-         throw er
 
-       chownSync(path, uid, gid)
 
-     }
 
-   }
 
-   : (path, uid, gid) => lchownSync(path, uid, gid)
 
- // fs.readdir could only accept an options object as of node v6
 
- const nodeVersion = process.version
 
- let readdir = (path, options, cb) => fs.readdir(path, options, cb)
 
- let readdirSync = (path, options) => fs.readdirSync(path, options)
 
- /* istanbul ignore next */
 
- if (/^v4\./.test(nodeVersion))
 
-   readdir = (path, options, cb) => fs.readdir(path, cb)
 
- const chown = (cpath, uid, gid, cb) => {
 
-   fs[LCHOWN](cpath, uid, gid, handleEISDIR(cpath, uid, gid, er => {
 
-     // Skip ENOENT error
 
-     cb(er && er.code !== 'ENOENT' ? er : null)
 
-   }))
 
- }
 
- const chownrKid = (p, child, uid, gid, cb) => {
 
-   if (typeof child === 'string')
 
-     return fs.lstat(path.resolve(p, child), (er, stats) => {
 
-       // Skip ENOENT error
 
-       if (er)
 
-         return cb(er.code !== 'ENOENT' ? er : null)
 
-       stats.name = child
 
-       chownrKid(p, stats, uid, gid, cb)
 
-     })
 
-   if (child.isDirectory()) {
 
-     chownr(path.resolve(p, child.name), uid, gid, er => {
 
-       if (er)
 
-         return cb(er)
 
-       const cpath = path.resolve(p, child.name)
 
-       chown(cpath, uid, gid, cb)
 
-     })
 
-   } else {
 
-     const cpath = path.resolve(p, child.name)
 
-     chown(cpath, uid, gid, cb)
 
-   }
 
- }
 
- const chownr = (p, uid, gid, cb) => {
 
-   readdir(p, { withFileTypes: true }, (er, children) => {
 
-     // any error other than ENOTDIR or ENOTSUP means it's not readable,
 
-     // or doesn't exist.  give up.
 
-     if (er) {
 
-       if (er.code === 'ENOENT')
 
-         return cb()
 
-       else if (er.code !== 'ENOTDIR' && er.code !== 'ENOTSUP')
 
-         return cb(er)
 
-     }
 
-     if (er || !children.length)
 
-       return chown(p, uid, gid, cb)
 
-     let len = children.length
 
-     let errState = null
 
-     const then = er => {
 
-       if (errState)
 
-         return
 
-       if (er)
 
-         return cb(errState = er)
 
-       if (-- len === 0)
 
-         return chown(p, uid, gid, cb)
 
-     }
 
-     children.forEach(child => chownrKid(p, child, uid, gid, then))
 
-   })
 
- }
 
- const chownrKidSync = (p, child, uid, gid) => {
 
-   if (typeof child === 'string') {
 
-     try {
 
-       const stats = fs.lstatSync(path.resolve(p, child))
 
-       stats.name = child
 
-       child = stats
 
-     } catch (er) {
 
-       if (er.code === 'ENOENT')
 
-         return
 
-       else
 
-         throw er
 
-     }
 
-   }
 
-   if (child.isDirectory())
 
-     chownrSync(path.resolve(p, child.name), uid, gid)
 
-   handleEISDirSync(path.resolve(p, child.name), uid, gid)
 
- }
 
- const chownrSync = (p, uid, gid) => {
 
-   let children
 
-   try {
 
-     children = readdirSync(p, { withFileTypes: true })
 
-   } catch (er) {
 
-     if (er.code === 'ENOENT')
 
-       return
 
-     else if (er.code === 'ENOTDIR' || er.code === 'ENOTSUP')
 
-       return handleEISDirSync(p, uid, gid)
 
-     else
 
-       throw er
 
-   }
 
-   if (children && children.length)
 
-     children.forEach(child => chownrKidSync(p, child, uid, gid))
 
-   return handleEISDirSync(p, uid, gid)
 
- }
 
- module.exports = chownr
 
- chownr.sync = chownrSync
 
 
  |