1 | var constants = require('constants')
|
2 |
|
3 | var origCwd = process.cwd
|
4 | var cwd = null
|
5 |
|
6 | var platform = process.env.GRACEFUL_FS_PLATFORM || process.platform
|
7 |
|
8 | process.cwd = function() {
|
9 | if (!cwd)
|
10 | cwd = origCwd.call(process)
|
11 | return cwd
|
12 | }
|
13 | try {
|
14 | process.cwd()
|
15 | } catch (er) {}
|
16 |
|
17 |
|
18 | if (typeof process.chdir === 'function') {
|
19 | var chdir = process.chdir
|
20 | process.chdir = function (d) {
|
21 | cwd = null
|
22 | chdir.call(process, d)
|
23 | }
|
24 | if (Object.setPrototypeOf) Object.setPrototypeOf(process.chdir, chdir)
|
25 | }
|
26 |
|
27 | module.exports = patch
|
28 |
|
29 | function patch (fs) {
|
30 |
|
31 |
|
32 |
|
33 |
|
34 | if (constants.hasOwnProperty('O_SYMLINK') &&
|
35 | process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
|
36 | patchLchmod(fs)
|
37 | }
|
38 |
|
39 |
|
40 | if (!fs.lutimes) {
|
41 | patchLutimes(fs)
|
42 | }
|
43 |
|
44 |
|
45 |
|
46 |
|
47 |
|
48 |
|
49 | fs.chown = chownFix(fs.chown)
|
50 | fs.fchown = chownFix(fs.fchown)
|
51 | fs.lchown = chownFix(fs.lchown)
|
52 |
|
53 | fs.chmod = chmodFix(fs.chmod)
|
54 | fs.fchmod = chmodFix(fs.fchmod)
|
55 | fs.lchmod = chmodFix(fs.lchmod)
|
56 |
|
57 | fs.chownSync = chownFixSync(fs.chownSync)
|
58 | fs.fchownSync = chownFixSync(fs.fchownSync)
|
59 | fs.lchownSync = chownFixSync(fs.lchownSync)
|
60 |
|
61 | fs.chmodSync = chmodFixSync(fs.chmodSync)
|
62 | fs.fchmodSync = chmodFixSync(fs.fchmodSync)
|
63 | fs.lchmodSync = chmodFixSync(fs.lchmodSync)
|
64 |
|
65 | fs.stat = statFix(fs.stat)
|
66 | fs.fstat = statFix(fs.fstat)
|
67 | fs.lstat = statFix(fs.lstat)
|
68 |
|
69 | fs.statSync = statFixSync(fs.statSync)
|
70 | fs.fstatSync = statFixSync(fs.fstatSync)
|
71 | fs.lstatSync = statFixSync(fs.lstatSync)
|
72 |
|
73 |
|
74 | if (fs.chmod && !fs.lchmod) {
|
75 | fs.lchmod = function (path, mode, cb) {
|
76 | if (cb) process.nextTick(cb)
|
77 | }
|
78 | fs.lchmodSync = function () {}
|
79 | }
|
80 | if (fs.chown && !fs.lchown) {
|
81 | fs.lchown = function (path, uid, gid, cb) {
|
82 | if (cb) process.nextTick(cb)
|
83 | }
|
84 | fs.lchownSync = function () {}
|
85 | }
|
86 |
|
87 |
|
88 |
|
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 |
|
95 |
|
96 | if (platform === "win32") {
|
97 | fs.rename = typeof fs.rename !== 'function' ? fs.rename
|
98 | : (function (fs$rename) {
|
99 | function rename (from, to, cb) {
|
100 | var start = Date.now()
|
101 | var backoff = 0;
|
102 | fs$rename(from, to, function CB (er) {
|
103 | if (er
|
104 | && (er.code === "EACCES" || er.code === "EPERM")
|
105 | && Date.now() - start < 60000) {
|
106 | setTimeout(function() {
|
107 | fs.stat(to, function (stater, st) {
|
108 | if (stater && stater.code === "ENOENT")
|
109 | fs$rename(from, to, CB);
|
110 | else
|
111 | cb(er)
|
112 | })
|
113 | }, backoff)
|
114 | if (backoff < 100)
|
115 | backoff += 10;
|
116 | return;
|
117 | }
|
118 | if (cb) cb(er)
|
119 | })
|
120 | }
|
121 | if (Object.setPrototypeOf) Object.setPrototypeOf(rename, fs$rename)
|
122 | return rename
|
123 | })(fs.rename)
|
124 | }
|
125 |
|
126 |
|
127 | fs.read = typeof fs.read !== 'function' ? fs.read
|
128 | : (function (fs$read) {
|
129 | function read (fd, buffer, offset, length, position, callback_) {
|
130 | var callback
|
131 | if (callback_ && typeof callback_ === 'function') {
|
132 | var eagCounter = 0
|
133 | callback = function (er, _, __) {
|
134 | if (er && er.code === 'EAGAIN' && eagCounter < 10) {
|
135 | eagCounter ++
|
136 | return fs$read.call(fs, fd, buffer, offset, length, position, callback)
|
137 | }
|
138 | callback_.apply(this, arguments)
|
139 | }
|
140 | }
|
141 | return fs$read.call(fs, fd, buffer, offset, length, position, callback)
|
142 | }
|
143 |
|
144 |
|
145 | if (Object.setPrototypeOf) Object.setPrototypeOf(read, fs$read)
|
146 | return read
|
147 | })(fs.read)
|
148 |
|
149 | fs.readSync = typeof fs.readSync !== 'function' ? fs.readSync
|
150 | : (function (fs$readSync) { return function (fd, buffer, offset, length, position) {
|
151 | var eagCounter = 0
|
152 | while (true) {
|
153 | try {
|
154 | return fs$readSync.call(fs, fd, buffer, offset, length, position)
|
155 | } catch (er) {
|
156 | if (er.code === 'EAGAIN' && eagCounter < 10) {
|
157 | eagCounter ++
|
158 | continue
|
159 | }
|
160 | throw er
|
161 | }
|
162 | }
|
163 | }})(fs.readSync)
|
164 |
|
165 | function patchLchmod (fs) {
|
166 | fs.lchmod = function (path, mode, callback) {
|
167 | fs.open( path
|
168 | , constants.O_WRONLY | constants.O_SYMLINK
|
169 | , mode
|
170 | , function (err, fd) {
|
171 | if (err) {
|
172 | if (callback) callback(err)
|
173 | return
|
174 | }
|
175 |
|
176 |
|
177 | fs.fchmod(fd, mode, function (err) {
|
178 | fs.close(fd, function(err2) {
|
179 | if (callback) callback(err || err2)
|
180 | })
|
181 | })
|
182 | })
|
183 | }
|
184 |
|
185 | fs.lchmodSync = function (path, mode) {
|
186 | var fd = fs.openSync(path, constants.O_WRONLY | constants.O_SYMLINK, mode)
|
187 |
|
188 |
|
189 |
|
190 | var threw = true
|
191 | var ret
|
192 | try {
|
193 | ret = fs.fchmodSync(fd, mode)
|
194 | threw = false
|
195 | } finally {
|
196 | if (threw) {
|
197 | try {
|
198 | fs.closeSync(fd)
|
199 | } catch (er) {}
|
200 | } else {
|
201 | fs.closeSync(fd)
|
202 | }
|
203 | }
|
204 | return ret
|
205 | }
|
206 | }
|
207 |
|
208 | function patchLutimes (fs) {
|
209 | if (constants.hasOwnProperty("O_SYMLINK") && fs.futimes) {
|
210 | fs.lutimes = function (path, at, mt, cb) {
|
211 | fs.open(path, constants.O_SYMLINK, function (er, fd) {
|
212 | if (er) {
|
213 | if (cb) cb(er)
|
214 | return
|
215 | }
|
216 | fs.futimes(fd, at, mt, function (er) {
|
217 | fs.close(fd, function (er2) {
|
218 | if (cb) cb(er || er2)
|
219 | })
|
220 | })
|
221 | })
|
222 | }
|
223 |
|
224 | fs.lutimesSync = function (path, at, mt) {
|
225 | var fd = fs.openSync(path, constants.O_SYMLINK)
|
226 | var ret
|
227 | var threw = true
|
228 | try {
|
229 | ret = fs.futimesSync(fd, at, mt)
|
230 | threw = false
|
231 | } finally {
|
232 | if (threw) {
|
233 | try {
|
234 | fs.closeSync(fd)
|
235 | } catch (er) {}
|
236 | } else {
|
237 | fs.closeSync(fd)
|
238 | }
|
239 | }
|
240 | return ret
|
241 | }
|
242 |
|
243 | } else if (fs.futimes) {
|
244 | fs.lutimes = function (_a, _b, _c, cb) { if (cb) process.nextTick(cb) }
|
245 | fs.lutimesSync = function () {}
|
246 | }
|
247 | }
|
248 |
|
249 | function chmodFix (orig) {
|
250 | if (!orig) return orig
|
251 | return function (target, mode, cb) {
|
252 | return orig.call(fs, target, mode, function (er) {
|
253 | if (chownErOk(er)) er = null
|
254 | if (cb) cb.apply(this, arguments)
|
255 | })
|
256 | }
|
257 | }
|
258 |
|
259 | function chmodFixSync (orig) {
|
260 | if (!orig) return orig
|
261 | return function (target, mode) {
|
262 | try {
|
263 | return orig.call(fs, target, mode)
|
264 | } catch (er) {
|
265 | if (!chownErOk(er)) throw er
|
266 | }
|
267 | }
|
268 | }
|
269 |
|
270 |
|
271 | function chownFix (orig) {
|
272 | if (!orig) return orig
|
273 | return function (target, uid, gid, cb) {
|
274 | return orig.call(fs, target, uid, gid, function (er) {
|
275 | if (chownErOk(er)) er = null
|
276 | if (cb) cb.apply(this, arguments)
|
277 | })
|
278 | }
|
279 | }
|
280 |
|
281 | function chownFixSync (orig) {
|
282 | if (!orig) return orig
|
283 | return function (target, uid, gid) {
|
284 | try {
|
285 | return orig.call(fs, target, uid, gid)
|
286 | } catch (er) {
|
287 | if (!chownErOk(er)) throw er
|
288 | }
|
289 | }
|
290 | }
|
291 |
|
292 | function statFix (orig) {
|
293 | if (!orig) return orig
|
294 |
|
295 |
|
296 | return function (target, options, cb) {
|
297 | if (typeof options === 'function') {
|
298 | cb = options
|
299 | options = null
|
300 | }
|
301 | function callback (er, stats) {
|
302 | if (stats) {
|
303 | if (stats.uid < 0) stats.uid += 0x100000000
|
304 | if (stats.gid < 0) stats.gid += 0x100000000
|
305 | }
|
306 | if (cb) cb.apply(this, arguments)
|
307 | }
|
308 | return options ? orig.call(fs, target, options, callback)
|
309 | : orig.call(fs, target, callback)
|
310 | }
|
311 | }
|
312 |
|
313 | function statFixSync (orig) {
|
314 | if (!orig) return orig
|
315 |
|
316 |
|
317 | return function (target, options) {
|
318 | var stats = options ? orig.call(fs, target, options)
|
319 | : orig.call(fs, target)
|
320 | if (stats) {
|
321 | if (stats.uid < 0) stats.uid += 0x100000000
|
322 | if (stats.gid < 0) stats.gid += 0x100000000
|
323 | }
|
324 | return stats;
|
325 | }
|
326 | }
|
327 |
|
328 |
|
329 |
|
330 |
|
331 |
|
332 |
|
333 |
|
334 |
|
335 |
|
336 |
|
337 |
|
338 |
|
339 |
|
340 | function chownErOk (er) {
|
341 | if (!er)
|
342 | return true
|
343 |
|
344 | if (er.code === "ENOSYS")
|
345 | return true
|
346 |
|
347 | var nonroot = !process.getuid || process.getuid() !== 0
|
348 | if (nonroot) {
|
349 | if (er.code === "EINVAL" || er.code === "EPERM")
|
350 | return true
|
351 | }
|
352 |
|
353 | return false
|
354 | }
|
355 | }
|