1 module.exports = rimraf
2 rimraf.sync = rimrafSync
4 var assert = require("assert")
5 var path = require("path")
7 var glob = require("glob")
8 var _0666 = parseInt('666', 8)
10 var defaultGlobOpts = {
15 // for EMFILE handling
18 var isWindows = (process.platform === "win32")
20 function defaults (options) {
29 methods.forEach(function(m) {
30 options[m] = options[m] || fs[m]
32 options[m] = options[m] || fs[m]
35 options.maxBusyTries = options.maxBusyTries || 3
36 options.emfileWait = options.emfileWait || 1000
37 if (options.glob === false) {
38 options.disableGlob = true
40 options.disableGlob = options.disableGlob || false
41 options.glob = options.glob || defaultGlobOpts
44 function rimraf (p, options, cb) {
45 if (typeof options === 'function') {
50 assert(p, 'rimraf: missing path')
51 assert.equal(typeof p, 'string', 'rimraf: path should be a string')
52 assert.equal(typeof cb, 'function', 'rimraf: callback function required')
53 assert(options, 'rimraf: invalid options argument provided')
54 assert.equal(typeof options, 'object', 'rimraf: options should be object')
62 if (options.disableGlob || !glob.hasMagic(p))
63 return afterGlob(null, [p])
65 options.lstat(p, function (er, stat) {
67 return afterGlob(null, [p])
69 glob(p, options.glob, afterGlob)
73 errState = errState || er
78 function afterGlob (er, results) {
86 results.forEach(function (p) {
87 rimraf_(p, options, function CB (er) {
89 if ((er.code === "EBUSY" || er.code === "ENOTEMPTY" || er.code === "EPERM") &&
90 busyTries < options.maxBusyTries) {
92 var time = busyTries * 100
93 // try again, with the same exact callback as this one.
94 return setTimeout(function () {
95 rimraf_(p, options, CB)
99 // this one won't happen if graceful-fs is used.
100 if (er.code === "EMFILE" && timeout < options.emfileWait) {
101 return setTimeout(function () {
102 rimraf_(p, options, CB)
107 if (er.code === "ENOENT") er = null
117 // Two possible strategies.
118 // 1. Assume it's a file. unlink it, then do the dir stuff on EPERM or EISDIR
119 // 2. Assume it's a directory. readdir, then do the file stuff on ENOTDIR
121 // Both result in an extra syscall when you guess wrong. However, there
122 // are likely far more normal files in the world than directories. This
123 // is based on the assumption that a the average number of files per
124 // directory is >= 1.
126 // If anyone ever complains about this, then I guess the strategy could
127 // be made configurable somehow. But until then, YAGNI.
128 function rimraf_ (p, options, cb) {
131 assert(typeof cb === 'function')
133 // sunos lets the root user unlink directories, which is... weird.
134 // so we have to lstat here and make sure it's not a dir.
135 options.lstat(p, function (er, st) {
136 if (er && er.code === "ENOENT")
139 // Windows can EPERM on stat. Life is suffering.
140 if (er && er.code === "EPERM" && isWindows)
141 fixWinEPERM(p, options, er, cb)
143 if (st && st.isDirectory())
144 return rmdir(p, options, er, cb)
146 options.unlink(p, function (er) {
148 if (er.code === "ENOENT")
150 if (er.code === "EPERM")
152 ? fixWinEPERM(p, options, er, cb)
153 : rmdir(p, options, er, cb)
154 if (er.code === "EISDIR")
155 return rmdir(p, options, er, cb)
162 function fixWinEPERM (p, options, er, cb) {
165 assert(typeof cb === 'function')
167 assert(er instanceof Error)
169 options.chmod(p, _0666, function (er2) {
171 cb(er2.code === "ENOENT" ? null : er)
173 options.stat(p, function(er3, stats) {
175 cb(er3.code === "ENOENT" ? null : er)
176 else if (stats.isDirectory())
177 rmdir(p, options, er, cb)
179 options.unlink(p, cb)
184 function fixWinEPERMSync (p, options, er) {
188 assert(er instanceof Error)
191 options.chmodSync(p, _0666)
193 if (er2.code === "ENOENT")
200 var stats = options.statSync(p)
202 if (er3.code === "ENOENT")
208 if (stats.isDirectory())
209 rmdirSync(p, options, er)
211 options.unlinkSync(p)
214 function rmdir (p, options, originalEr, cb) {
218 assert(originalEr instanceof Error)
219 assert(typeof cb === 'function')
221 // try to rmdir first, and only readdir on ENOTEMPTY or EEXIST (SunOS)
222 // if we guessed wrong, and it's not a directory, then
223 // raise the original error.
224 options.rmdir(p, function (er) {
225 if (er && (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM"))
226 rmkids(p, options, cb)
227 else if (er && er.code === "ENOTDIR")
234 function rmkids(p, options, cb) {
237 assert(typeof cb === 'function')
239 options.readdir(p, function (er, files) {
244 return options.rmdir(p, cb)
246 files.forEach(function (f) {
247 rimraf(path.join(p, f), options, function (er) {
251 return cb(errState = er)
259 // this looks simpler, and is strictly *faster*, but will
260 // tie up the JavaScript thread and fail on excessively
261 // deep directory trees.
262 function rimrafSync (p, options) {
263 options = options || {}
266 assert(p, 'rimraf: missing path')
267 assert.equal(typeof p, 'string', 'rimraf: path should be a string')
268 assert(options, 'rimraf: missing options')
269 assert.equal(typeof options, 'object', 'rimraf: options should be object')
273 if (options.disableGlob || !glob.hasMagic(p)) {
280 results = glob.sync(p, options.glob)
287 for (var i = 0; i < results.length; i++) {
291 var st = options.lstatSync(p)
293 if (er.code === "ENOENT")
296 // Windows can EPERM on stat. Life is suffering.
297 if (er.code === "EPERM" && isWindows)
298 fixWinEPERMSync(p, options, er)
302 // sunos lets the root user unlink directories, which is... weird.
303 if (st && st.isDirectory())
304 rmdirSync(p, options, null)
306 options.unlinkSync(p)
308 if (er.code === "ENOENT")
310 if (er.code === "EPERM")
311 return isWindows ? fixWinEPERMSync(p, options, er) : rmdirSync(p, options, er)
312 if (er.code !== "EISDIR")
315 rmdirSync(p, options, er)
320 function rmdirSync (p, options, originalEr) {
324 assert(originalEr instanceof Error)
329 if (er.code === "ENOENT")
331 if (er.code === "ENOTDIR")
333 if (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM")
334 rmkidsSync(p, options)
338 function rmkidsSync (p, options) {
341 options.readdirSync(p).forEach(function (f) {
342 rimrafSync(path.join(p, f), options)
345 // We only end up here once we got ENOTEMPTY at least once, and
346 // at this point, we are guaranteed to have removed all the kids.
347 // So, we know that it won't be ENOENT or ENOTDIR or anything else.
348 // try really hard to delete stuff on windows, because it has a
349 // PROFOUNDLY annoying habit of not closing handles promptly when
350 // files are deleted, resulting in spurious ENOTEMPTY errors.
351 var retries = isWindows ? 100 : 1
356 var ret = options.rmdirSync(p, options)
360 if (++i < retries && threw)