eb96c46afde6d782568cd709578f790827aa1991
[yaffs-website] / node_modules / grunt / node_modules / rimraf / rimraf.js
1 module.exports = rimraf
2 rimraf.sync = rimrafSync
3
4 var assert = require("assert")
5 var path = require("path")
6 var fs = require("fs")
7
8 // for EMFILE handling
9 var timeout = 0
10 exports.EMFILE_MAX = 1000
11 exports.BUSYTRIES_MAX = 3
12
13 var isWindows = (process.platform === "win32")
14
15 function defaults (options) {
16   var methods = [
17     'unlink',
18     'chmod',
19     'stat',
20     'rmdir',
21     'readdir'
22   ]
23   methods.forEach(function(m) {
24     options[m] = options[m] || fs[m]
25     m = m + 'Sync'
26     options[m] = options[m] || fs[m]
27   })
28 }
29
30 function rimraf (p, options, cb) {
31   if (typeof options === 'function') {
32     cb = options
33     options = {}
34   }
35   assert(p)
36   assert(options)
37   assert(typeof cb === 'function')
38
39   defaults(options)
40
41   if (!cb) throw new Error("No callback passed to rimraf()")
42
43   var busyTries = 0
44   rimraf_(p, options, function CB (er) {
45     if (er) {
46       if (isWindows && (er.code === "EBUSY" || er.code === "ENOTEMPTY") &&
47           busyTries < exports.BUSYTRIES_MAX) {
48         busyTries ++
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)
53         }, time)
54       }
55
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)
60         }, timeout ++)
61       }
62
63       // already gone
64       if (er.code === "ENOENT") er = null
65     }
66
67     timeout = 0
68     cb(er)
69   })
70 }
71
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
75 //
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
79 // directory is >= 1.
80 //
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) {
84   assert(p)
85   assert(options)
86   assert(typeof cb === 'function')
87
88   options.unlink(p, function (er) {
89     if (er) {
90       if (er.code === "ENOENT")
91         return cb(null)
92       if (er.code === "EPERM")
93         return (isWindows)
94           ? fixWinEPERM(p, options, er, cb)
95           : rmdir(p, options, er, cb)
96       if (er.code === "EISDIR")
97         return rmdir(p, options, er, cb)
98     }
99     return cb(er)
100   })
101 }
102
103 function fixWinEPERM (p, options, er, cb) {
104   assert(p)
105   assert(options)
106   assert(typeof cb === 'function')
107   if (er)
108     assert(er instanceof Error)
109
110   options.chmod(p, 666, function (er2) {
111     if (er2)
112       cb(er2.code === "ENOENT" ? null : er)
113     else
114       options.stat(p, function(er3, stats) {
115         if (er3)
116           cb(er3.code === "ENOENT" ? null : er)
117         else if (stats.isDirectory())
118           rmdir(p, options, er, cb)
119         else
120           options.unlink(p, cb)
121       })
122   })
123 }
124
125 function fixWinEPERMSync (p, options, er) {
126   assert(p)
127   assert(options)
128   if (er)
129     assert(er instanceof Error)
130
131   try {
132     options.chmodSync(p, 666)
133   } catch (er2) {
134     if (er2.code === "ENOENT")
135       return
136     else
137       throw er
138   }
139
140   try {
141     var stats = options.statSync(p)
142   } catch (er3) {
143     if (er3.code === "ENOENT")
144       return
145     else
146       throw er
147   }
148
149   if (stats.isDirectory())
150     rmdirSync(p, options, er)
151   else
152     options.unlinkSync(p)
153 }
154
155 function rmdir (p, options, originalEr, cb) {
156   assert(p)
157   assert(options)
158   if (originalEr)
159     assert(originalEr instanceof Error)
160   assert(typeof cb === 'function')
161
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")
169       cb(originalEr)
170     else
171       cb(er)
172   })
173 }
174
175 function rmkids(p, options, cb) {
176   assert(p)
177   assert(options)
178   assert(typeof cb === 'function')
179
180   options.readdir(p, function (er, files) {
181     if (er)
182       return cb(er)
183     var n = files.length
184     if (n === 0)
185       return options.rmdir(p, cb)
186     var errState
187     files.forEach(function (f) {
188       rimraf(path.join(p, f), options, function (er) {
189         if (errState)
190           return
191         if (er)
192           return cb(errState = er)
193         if (--n === 0)
194           options.rmdir(p, cb)
195       })
196     })
197   })
198 }
199
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 || {}
205   defaults(options)
206
207   assert(p)
208   assert(options)
209
210   try {
211     options.unlinkSync(p)
212   } catch (er) {
213     if (er.code === "ENOENT")
214       return
215     if (er.code === "EPERM")
216       return isWindows ? fixWinEPERMSync(p, options, er) : rmdirSync(p, options, er)
217     if (er.code !== "EISDIR")
218       throw er
219     rmdirSync(p, options, er)
220   }
221 }
222
223 function rmdirSync (p, options, originalEr) {
224   assert(p)
225   assert(options)
226   if (originalEr)
227     assert(originalEr instanceof Error)
228
229   try {
230     options.rmdirSync(p)
231   } catch (er) {
232     if (er.code === "ENOENT")
233       return
234     if (er.code === "ENOTDIR")
235       throw originalEr
236     if (er.code === "ENOTEMPTY" || er.code === "EEXIST" || er.code === "EPERM")
237       rmkidsSync(p, options)
238   }
239 }
240
241 function rmkidsSync (p, options) {
242   assert(p)
243   assert(options)
244   options.readdirSync(p).forEach(function (f) {
245     rimrafSync(path.join(p, f), options)
246   })
247   options.rmdirSync(p, options)
248 }