npm: Upgrade to 1.3.17
[platform/upstream/nodejs.git] / deps / npm / node_modules / rimraf / rimraf.js
1 module.exports = rimraf
2 rimraf.sync = rimrafSync
3
4 var path = require("path")
5 var fs = require("fs")
6
7 // for EMFILE handling
8 var timeout = 0
9 exports.EMFILE_MAX = 1000
10 exports.BUSYTRIES_MAX = 3
11
12 var isWindows = (process.platform === "win32")
13
14 function rimraf (p, cb) {
15   if (!cb) throw new Error("No callback passed to rimraf()")
16
17   var busyTries = 0
18   rimraf_(p, function CB (er) {
19     if (er) {
20       if (isWindows && (er.code === "EBUSY" || er.code === "ENOTEMPTY") &&
21           busyTries < exports.BUSYTRIES_MAX) {
22         busyTries ++
23         var time = busyTries * 100
24         // try again, with the same exact callback as this one.
25         return setTimeout(function () {
26           rimraf_(p, CB)
27         }, time)
28       }
29
30       // this one won't happen if graceful-fs is used.
31       if (er.code === "EMFILE" && timeout < exports.EMFILE_MAX) {
32         return setTimeout(function () {
33           rimraf_(p, CB)
34         }, timeout ++)
35       }
36
37       // already gone
38       if (er.code === "ENOENT") er = null
39     }
40
41     timeout = 0
42     cb(er)
43   })
44 }
45
46 // Two possible strategies.
47 // 1. Assume it's a file.  unlink it, then do the dir stuff on EPERM or EISDIR
48 // 2. Assume it's a directory.  readdir, then do the file stuff on ENOTDIR
49 //
50 // Both result in an extra syscall when you guess wrong.  However, there
51 // are likely far more normal files in the world than directories.  This
52 // is based on the assumption that a the average number of files per
53 // directory is >= 1.
54 //
55 // If anyone ever complains about this, then I guess the strategy could
56 // be made configurable somehow.  But until then, YAGNI.
57 function rimraf_ (p, cb) {
58   fs.unlink(p, function (er) {
59     if (er) {
60       if (er.code === "ENOENT")
61         return cb(null)
62       if (er.code === "EPERM")
63         return (isWindows) ? fixWinEPERM(p, er, cb) : rmdir(p, er, cb)
64       if (er.code === "EISDIR")
65         return rmdir(p, er, cb)
66     }
67     return cb(er)
68   })
69 }
70
71 function fixWinEPERM (p, er, cb) {
72   fs.chmod(p, 666, function (er2) {
73     if (er2)
74       cb(er2.code === "ENOENT" ? null : er)
75     else
76       fs.stat(p, function(er3, stats) {
77         if (er3)
78           cb(er3.code === "ENOENT" ? null : er)
79         else if (stats.isDirectory())
80           rmdir(p, er, cb)
81         else
82           fs.unlink(p, cb)
83       })
84   })
85 }
86
87 function fixWinEPERMSync (p, er, cb) {
88   try {
89     fs.chmodSync(p, 666)
90   } catch (er2) {
91     if (er2.code !== "ENOENT")
92       throw er
93   }
94
95   try {
96     var stats = fs.statSync(p)
97   } catch (er3) {
98     if (er3 !== "ENOENT")
99       throw er
100   }
101
102   if (stats.isDirectory())
103     rmdirSync(p, er)
104   else
105     fs.unlinkSync(p)
106 }
107
108 function rmdir (p, originalEr, cb) {
109   // try to rmdir first, and only readdir on ENOTEMPTY or EEXIST (SunOS)
110   // if we guessed wrong, and it's not a directory, then
111   // raise the original error.
112   fs.rmdir(p, function (er) {
113     if (er && (er.code === "ENOTEMPTY" || er.code === "EEXIST"))
114       rmkids(p, cb)
115     else if (er && er.code === "ENOTDIR")
116       cb(originalEr)
117     else
118       cb(er)
119   })
120 }
121
122 function rmkids(p, cb) {
123   fs.readdir(p, function (er, files) {
124     if (er)
125       return cb(er)
126     var n = files.length
127     if (n === 0)
128       return fs.rmdir(p, cb)
129     var errState
130     files.forEach(function (f) {
131       rimraf(path.join(p, f), function (er) {
132         if (errState)
133           return
134         if (er)
135           return cb(errState = er)
136         if (--n === 0)
137           fs.rmdir(p, cb)
138       })
139     })
140   })
141 }
142
143 // this looks simpler, and is strictly *faster*, but will
144 // tie up the JavaScript thread and fail on excessively
145 // deep directory trees.
146 function rimrafSync (p) {
147   try {
148     fs.unlinkSync(p)
149   } catch (er) {
150     if (er.code === "ENOENT")
151       return
152     if (er.code === "EPERM")
153       return isWindows ? fixWinEPERMSync(p, er) : rmdirSync(p, er)
154     if (er.code !== "EISDIR")
155       throw er
156     rmdirSync(p, er)
157   }
158 }
159
160 function rmdirSync (p, originalEr) {
161   try {
162     fs.rmdirSync(p)
163   } catch (er) {
164     if (er.code === "ENOENT")
165       return
166     if (er.code === "ENOTDIR")
167       throw originalEr
168     if (er.code === "ENOTEMPTY" || er.code === "EEXIST")
169       rmkidsSync(p)
170   }
171 }
172
173 function rmkidsSync (p) {
174   fs.readdirSync(p).forEach(function (f) {
175     rimrafSync(path.join(p, f))
176   })
177   fs.rmdirSync(p)
178 }