프로젝트

일반

사용자정보

통계
| 개정판:

root / HServer / 00.Server / 00.Program / node_modules / rimraf / rimraf.js

이력 | 보기 | 이력해설 | 다운로드 (7.75 KB)

1 39 HKM
module.exports = rimraf
2
rimraf.sync = rimrafSync
3
4
var assert = require("assert")
5
var path = require("path")
6
var fs = require("fs")
7
var glob = require("glob")
8
9
var globOpts = {
10
  nosort: true,
11
  nocomment: true,
12
  nonegate: true,
13
  silent: true
14
}
15
16
// for EMFILE handling
17
var timeout = 0
18
19
var isWindows = (process.platform === "win32")
20
21
function defaults (options) {
22
  var methods = [
23
    'unlink',
24
    'chmod',
25
    'stat',
26
    'lstat',
27
    'rmdir',
28
    'readdir'
29
  ]
30
  methods.forEach(function(m) {
31
    options[m] = options[m] || fs[m]
32
    m = m + 'Sync'
33
    options[m] = options[m] || fs[m]
34
  })
35
36
  options.maxBusyTries = options.maxBusyTries || 3
37
  options.emfileWait = options.emfileWait || 1000
38
  options.disableGlob = options.disableGlob || false
39
}
40
41
function rimraf (p, options, cb) {
42
  if (typeof options === 'function') {
43
    cb = options
44
    options = {}
45
  }
46
47
  assert(p, 'rimraf: missing path')
48
  assert.equal(typeof p, 'string', 'rimraf: path should be a string')
49
  assert(options, 'rimraf: missing options')
50
  assert.equal(typeof options, 'object', 'rimraf: options should be object')
51
  assert.equal(typeof cb, 'function', 'rimraf: callback function required')
52
53
  defaults(options)
54
55
  var busyTries = 0
56
  var errState = null
57
  var n = 0
58
59
  if (options.disableGlob || !glob.hasMagic(p))
60
    return afterGlob(null, [p])
61
62
  fs.lstat(p, function (er, stat) {
63
    if (!er)
64
      return afterGlob(null, [p])
65
66
    glob(p, globOpts, afterGlob)
67
  })
68
69
  function next (er) {
70
    errState = errState || er
71
    if (--n === 0)
72
      cb(errState)
73
  }
74
75
  function afterGlob (er, results) {
76
    if (er)
77
      return cb(er)
78
79
    n = results.length
80
    if (n === 0)
81
      return cb()
82
83
    results.forEach(function (p) {
84
      rimraf_(p, options, function CB (er) {
85
        if (er) {
86
          if (isWindows && (er.code === "EBUSY" || er.code === "ENOTEMPTY" || er.code === "EPERM") &&
87
              busyTries < options.maxBusyTries) {
88
            busyTries ++
89
            var time = busyTries * 100
90
            // try again, with the same exact callback as this one.
91
            return setTimeout(function () {
92
              rimraf_(p, options, CB)
93
            }, time)
94
          }
95
96
          // this one won't happen if graceful-fs is used.
97
          if (er.code === "EMFILE" && timeout < options.emfileWait) {
98
            return setTimeout(function () {
99
              rimraf_(p, options, CB)
100
            }, timeout ++)
101
          }
102
103
          // already gone
104
          if (er.code === "ENOENT") er = null
105
        }
106
107
        timeout = 0
108
        next(er)
109
      })
110
    })
111
  }
112
}
113
114
// Two possible strategies.
115
// 1. Assume it's a file.  unlink it, then do the dir stuff on EPERM or EISDIR
116
// 2. Assume it's a directory.  readdir, then do the file stuff on ENOTDIR
117
//
118
// Both result in an extra syscall when you guess wrong.  However, there
119
// are likely far more normal files in the world than directories.  This
120
// is based on the assumption that a the average number of files per
121
// directory is >= 1.
122
//
123
// If anyone ever complains about this, then I guess the strategy could
124
// be made configurable somehow.  But until then, YAGNI.
125
function rimraf_ (p, options, cb) {
126
  assert(p)
127
  assert(options)
128
  assert(typeof cb === 'function')
129
130
  // sunos lets the root user unlink directories, which is... weird.
131
  // so we have to lstat here and make sure it's not a dir.
132
  options.lstat(p, function (er, st) {
133
    if (er && er.code === "ENOENT")
134
      return cb(null)
135
136
    if (st && st.isDirectory())
137
      return rmdir(p, options, er, cb)
138
139
    options.unlink(p, function (er) {
140
      if (er) {
141
        if (er.code === "ENOENT")
142
          return cb(null)
143
        if (er.code === "EPERM")
144
          return (isWindows)
145
            ? fixWinEPERM(p, options, er, cb)
146
            : rmdir(p, options, er, cb)
147
        if (er.code === "EISDIR")
148
          return rmdir(p, options, er, cb)
149
      }
150
      return cb(er)
151
    })
152
  })
153
}
154
155
function fixWinEPERM (p, options, er, cb) {
156
  assert(p)
157
  assert(options)
158
  assert(typeof cb === 'function')
159
  if (er)
160
    assert(er instanceof Error)
161
162
  options.chmod(p, 666, function (er2) {
163
    if (er2)
164
      cb(er2.code === "ENOENT" ? null : er)
165
    else
166
      options.stat(p, function(er3, stats) {
167
        if (er3)
168
          cb(er3.code === "ENOENT" ? null : er)
169
        else if (stats.isDirectory())
170
          rmdir(p, options, er, cb)
171
        else
172
          options.unlink(p, cb)
173
      })
174
  })
175
}
176
177
function fixWinEPERMSync (p, options, er) {
178
  assert(p)
179
  assert(options)
180
  if (er)
181
    assert(er instanceof Error)
182
183
  try {
184
    options.chmodSync(p, 666)
185
  } catch (er2) {
186
    if (er2.code === "ENOENT")
187
      return
188
    else
189
      throw er
190
  }
191
192
  try {
193
    var stats = options.statSync(p)
194
  } catch (er3) {
195
    if (er3.code === "ENOENT")
196
      return
197
    else
198
      throw er
199
  }
200
201
  if (stats.isDirectory())
202
    rmdirSync(p, options, er)
203
  else
204
    options.unlinkSync(p)
205
}
206
207
function rmdir (p, options, originalEr, cb) {
208
  assert(p)
209
  assert(options)
210
  if (originalEr)
211
    assert(originalEr instanceof Error)
212
  assert(typeof cb === 'function')
213
214
  // try to rmdir first, and only readdir on ENOTEMPTY or EEXIST (SunOS)
215
  // if we guessed wrong, and it's not a directory, then
216
  // raise the original error.
217
  options.rmdir(p, function (er) {
218
    if (er && (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM"))
219
      rmkids(p, options, cb)
220
    else if (er && er.code === "ENOTDIR")
221
      cb(originalEr)
222
    else
223
      cb(er)
224
  })
225
}
226
227
function rmkids(p, options, cb) {
228
  assert(p)
229
  assert(options)
230
  assert(typeof cb === 'function')
231
232
  options.readdir(p, function (er, files) {
233
    if (er)
234
      return cb(er)
235
    var n = files.length
236
    if (n === 0)
237
      return options.rmdir(p, cb)
238
    var errState
239
    files.forEach(function (f) {
240
      rimraf(path.join(p, f), options, function (er) {
241
        if (errState)
242
          return
243
        if (er)
244
          return cb(errState = er)
245
        if (--n === 0)
246
          options.rmdir(p, cb)
247
      })
248
    })
249
  })
250
}
251
252
// this looks simpler, and is strictly *faster*, but will
253
// tie up the JavaScript thread and fail on excessively
254
// deep directory trees.
255
function rimrafSync (p, options) {
256
  options = options || {}
257
  defaults(options)
258
259
  assert(p, 'rimraf: missing path')
260
  assert.equal(typeof p, 'string', 'rimraf: path should be a string')
261
  assert(options, 'rimraf: missing options')
262
  assert.equal(typeof options, 'object', 'rimraf: options should be object')
263
264
  var results
265
266
  if (options.disableGlob || !glob.hasMagic(p)) {
267
    results = [p]
268
  } else {
269
    try {
270
      fs.lstatSync(p)
271
      results = [p]
272
    } catch (er) {
273
      results = glob.sync(p, globOpts)
274
    }
275
  }
276
277
  if (!results.length)
278
    return
279
280
  for (var i = 0; i < results.length; i++) {
281
    var p = results[i]
282
283
    try {
284
      var st = options.lstatSync(p)
285
    } catch (er) {
286
      if (er.code === "ENOENT")
287
        return
288
    }
289
290
    try {
291
      // sunos lets the root user unlink directories, which is... weird.
292
      if (st && st.isDirectory())
293
        rmdirSync(p, options, null)
294
      else
295
        options.unlinkSync(p)
296
    } catch (er) {
297
      if (er.code === "ENOENT")
298
        return
299
      if (er.code === "EPERM")
300
        return isWindows ? fixWinEPERMSync(p, options, er) : rmdirSync(p, options, er)
301
      if (er.code !== "EISDIR")
302
        throw er
303
      rmdirSync(p, options, er)
304
    }
305
  }
306
}
307
308
function rmdirSync (p, options, originalEr) {
309
  assert(p)
310
  assert(options)
311
  if (originalEr)
312
    assert(originalEr instanceof Error)
313
314
  try {
315
    options.rmdirSync(p)
316
  } catch (er) {
317
    if (er.code === "ENOENT")
318
      return
319
    if (er.code === "ENOTDIR")
320
      throw originalEr
321
    if (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM")
322
      rmkidsSync(p, options)
323
  }
324
}
325
326
function rmkidsSync (p, options) {
327
  assert(p)
328
  assert(options)
329
  options.readdirSync(p).forEach(function (f) {
330
    rimrafSync(path.join(p, f), options)
331
  })
332
  options.rmdirSync(p, options)
333
}