Ohm-Management - Projektarbeit B-ME
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

rimraf.js 7.8KB

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