Blame view

node_modules/chownr/chownr.js 2.43 KB
aaac7fed   liuqimichale   add
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
  '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'
  
  // 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 chownrKid = (p, child, uid, gid, cb) => {
    if (typeof child === 'string')
      return fs.lstat(path.resolve(p, child), (er, stats) => {
        if (er)
          return cb(er)
        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)
        fs[LCHOWN](path.resolve(p, child.name), uid, gid, cb)
      })
    } else
      fs[LCHOWN](path.resolve(p, child.name), 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 && er.code !== 'ENOTDIR' && er.code !== 'ENOTSUP')
        return cb(er)
      if (er || !children.length) return fs[LCHOWN](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 fs[LCHOWN](p, uid, gid, cb)
      }
  
      children.forEach(child => chownrKid(p, child, uid, gid, then))
    })
  }
  
  const chownrKidSync = (p, child, uid, gid) => {
    if (typeof child === 'string') {
      const stats = fs.lstatSync(path.resolve(p, child))
      stats.name = child
      child = stats
    }
  
    if (child.isDirectory())
      chownrSync(path.resolve(p, child.name), uid, gid)
  
    fs[LCHOWNSYNC](path.resolve(p, child.name), uid, gid)
  }
  
  const chownrSync = (p, uid, gid) => {
    let children
    try {
      children = readdirSync(p, { withFileTypes: true })
    } catch (er) {
      if (er && er.code === 'ENOTDIR' && er.code !== 'ENOTSUP')
        return fs[LCHOWNSYNC](p, uid, gid)
      throw er
    }
  
    if (children.length)
      children.forEach(child => chownrKidSync(p, child, uid, gid))
  
    return fs[LCHOWNSYNC](p, uid, gid)
  }
  
  module.exports = chownr
  chownr.sync = chownrSync