1 module.exports = rimraf
2 rimraf.sync = rimrafSync
4 var assert = require("assert")
5 var path = require("path")
10 exports.EMFILE_MAX = 1000
11 exports.BUSYTRIES_MAX = 3
13 var isWindows = (process.platform === "win32")
15 function defaults (options) {
23 methods.forEach(function(m) {
24 options[m] = options[m] || fs[m]
26 options[m] = options[m] || fs[m]
30 function rimraf (p, options, cb) {
31 if (typeof options === 'function') {
37 assert(typeof cb === 'function')
41 if (!cb) throw new Error("No callback passed to rimraf()")
44 rimraf_(p, options, function CB (er) {
46 if (isWindows && (er.code === "EBUSY" || er.code === "ENOTEMPTY") &&
47 busyTries < exports.BUSYTRIES_MAX) {
49 var time = busyTries * 100
50 // try again, with the same exact callback as this one.
51 return setTimeout(function () {
52 rimraf_(p, options, CB)
56 // this one won't happen if graceful-fs is used.
57 if (er.code === "EMFILE" && timeout < exports.EMFILE_MAX) {
58 return setTimeout(function () {
59 rimraf_(p, options, CB)
64 if (er.code === "ENOENT") er = null
72 // Two possible strategies.
73 // 1. Assume it's a file. unlink it, then do the dir stuff on EPERM or EISDIR
74 // 2. Assume it's a directory. readdir, then do the file stuff on ENOTDIR
76 // Both result in an extra syscall when you guess wrong. However, there
77 // are likely far more normal files in the world than directories. This
78 // is based on the assumption that a the average number of files per
81 // If anyone ever complains about this, then I guess the strategy could
82 // be made configurable somehow. But until then, YAGNI.
83 function rimraf_ (p, options, cb) {
86 assert(typeof cb === 'function')
88 options.unlink(p, function (er) {
90 if (er.code === "ENOENT")
92 if (er.code === "EPERM")
94 ? fixWinEPERM(p, options, er, cb)
95 : rmdir(p, options, er, cb)
96 if (er.code === "EISDIR")
97 return rmdir(p, options, er, cb)
103 function fixWinEPERM (p, options, er, cb) {
106 assert(typeof cb === 'function')
108 assert(er instanceof Error)
110 options.chmod(p, 666, function (er2) {
112 cb(er2.code === "ENOENT" ? null : er)
114 options.stat(p, function(er3, stats) {
116 cb(er3.code === "ENOENT" ? null : er)
117 else if (stats.isDirectory())
118 rmdir(p, options, er, cb)
120 options.unlink(p, cb)
125 function fixWinEPERMSync (p, options, er) {
129 assert(er instanceof Error)
132 options.chmodSync(p, 666)
134 if (er2.code === "ENOENT")
141 var stats = options.statSync(p)
143 if (er3.code === "ENOENT")
149 if (stats.isDirectory())
150 rmdirSync(p, options, er)
152 options.unlinkSync(p)
155 function rmdir (p, options, originalEr, cb) {
159 assert(originalEr instanceof Error)
160 assert(typeof cb === 'function')
162 // try to rmdir first, and only readdir on ENOTEMPTY or EEXIST (SunOS)
163 // if we guessed wrong, and it's not a directory, then
164 // raise the original error.
165 options.rmdir(p, function (er) {
166 if (er && (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM"))
167 rmkids(p, options, cb)
168 else if (er && er.code === "ENOTDIR")
175 function rmkids(p, options, cb) {
178 assert(typeof cb === 'function')
180 options.readdir(p, function (er, files) {
185 return options.rmdir(p, cb)
187 files.forEach(function (f) {
188 rimraf(path.join(p, f), options, function (er) {
192 return cb(errState = er)
200 // this looks simpler, and is strictly *faster*, but will
201 // tie up the JavaScript thread and fail on excessively
202 // deep directory trees.
203 function rimrafSync (p, options) {
204 options = options || {}
211 options.unlinkSync(p)
213 if (er.code === "ENOENT")
215 if (er.code === "EPERM")
216 return isWindows ? fixWinEPERMSync(p, options, er) : rmdirSync(p, options, er)
217 if (er.code !== "EISDIR")
219 rmdirSync(p, options, er)
223 function rmdirSync (p, options, originalEr) {
227 assert(originalEr instanceof Error)
232 if (er.code === "ENOENT")
234 if (er.code === "ENOTDIR")
236 if (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM")
237 rmkidsSync(p, options)
241 function rmkidsSync (p, options) {
244 options.readdirSync(p).forEach(function (f) {
245 rimrafSync(path.join(p, f), options)
247 options.rmdirSync(p, options)