Initial commit
[yaffs-website] / node_modules / path-type / node_modules / graceful-fs / polyfills.js
1 var fs = require('./fs.js')
2 var constants = require('constants')
3
4 var origCwd = process.cwd
5 var cwd = null
6
7 var platform = process.env.GRACEFUL_FS_PLATFORM || process.platform
8
9 process.cwd = function() {
10   if (!cwd)
11     cwd = origCwd.call(process)
12   return cwd
13 }
14 try {
15   process.cwd()
16 } catch (er) {}
17
18 var chdir = process.chdir
19 process.chdir = function(d) {
20   cwd = null
21   chdir.call(process, d)
22 }
23
24 module.exports = patch
25
26 function patch (fs) {
27   // (re-)implement some things that are known busted or missing.
28
29   // lchmod, broken prior to 0.6.2
30   // back-port the fix here.
31   if (constants.hasOwnProperty('O_SYMLINK') &&
32       process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
33     patchLchmod(fs)
34   }
35
36   // lutimes implementation, or no-op
37   if (!fs.lutimes) {
38     patchLutimes(fs)
39   }
40
41   // https://github.com/isaacs/node-graceful-fs/issues/4
42   // Chown should not fail on einval or eperm if non-root.
43   // It should not fail on enosys ever, as this just indicates
44   // that a fs doesn't support the intended operation.
45
46   fs.chown = chownFix(fs.chown)
47   fs.fchown = chownFix(fs.fchown)
48   fs.lchown = chownFix(fs.lchown)
49
50   fs.chmod = chmodFix(fs.chmod)
51   fs.fchmod = chmodFix(fs.fchmod)
52   fs.lchmod = chmodFix(fs.lchmod)
53
54   fs.chownSync = chownFixSync(fs.chownSync)
55   fs.fchownSync = chownFixSync(fs.fchownSync)
56   fs.lchownSync = chownFixSync(fs.lchownSync)
57
58   fs.chmodSync = chmodFixSync(fs.chmodSync)
59   fs.fchmodSync = chmodFixSync(fs.fchmodSync)
60   fs.lchmodSync = chmodFixSync(fs.lchmodSync)
61
62   fs.stat = statFix(fs.stat)
63   fs.fstat = statFix(fs.fstat)
64   fs.lstat = statFix(fs.lstat)
65
66   fs.statSync = statFixSync(fs.statSync)
67   fs.fstatSync = statFixSync(fs.fstatSync)
68   fs.lstatSync = statFixSync(fs.lstatSync)
69
70   // if lchmod/lchown do not exist, then make them no-ops
71   if (!fs.lchmod) {
72     fs.lchmod = function (path, mode, cb) {
73       if (cb) process.nextTick(cb)
74     }
75     fs.lchmodSync = function () {}
76   }
77   if (!fs.lchown) {
78     fs.lchown = function (path, uid, gid, cb) {
79       if (cb) process.nextTick(cb)
80     }
81     fs.lchownSync = function () {}
82   }
83
84   // on Windows, A/V software can lock the directory, causing this
85   // to fail with an EACCES or EPERM if the directory contains newly
86   // created files.  Try again on failure, for up to 60 seconds.
87
88   // Set the timeout this long because some Windows Anti-Virus, such as Parity
89   // bit9, may lock files for up to a minute, causing npm package install
90   // failures. Also, take care to yield the scheduler. Windows scheduling gives
91   // CPU to a busy looping process, which can cause the program causing the lock
92   // contention to be starved of CPU by node, so the contention doesn't resolve.
93   if (platform === "win32") {
94     fs.rename = (function (fs$rename) { return function (from, to, cb) {
95       var start = Date.now()
96       var backoff = 0;
97       fs$rename(from, to, function CB (er) {
98         if (er
99             && (er.code === "EACCES" || er.code === "EPERM")
100             && Date.now() - start < 60000) {
101           setTimeout(function() {
102             fs.stat(to, function (stater, st) {
103               if (stater && stater.code === "ENOENT")
104                 fs$rename(from, to, CB);
105               else
106                 cb(er)
107             })
108           }, backoff)
109           if (backoff < 100)
110             backoff += 10;
111           return;
112         }
113         if (cb) cb(er)
114       })
115     }})(fs.rename)
116   }
117
118   // if read() returns EAGAIN, then just try it again.
119   fs.read = (function (fs$read) { return function (fd, buffer, offset, length, position, callback_) {
120     var callback
121     if (callback_ && typeof callback_ === 'function') {
122       var eagCounter = 0
123       callback = function (er, _, __) {
124         if (er && er.code === 'EAGAIN' && eagCounter < 10) {
125           eagCounter ++
126           return fs$read.call(fs, fd, buffer, offset, length, position, callback)
127         }
128         callback_.apply(this, arguments)
129       }
130     }
131     return fs$read.call(fs, fd, buffer, offset, length, position, callback)
132   }})(fs.read)
133
134   fs.readSync = (function (fs$readSync) { return function (fd, buffer, offset, length, position) {
135     var eagCounter = 0
136     while (true) {
137       try {
138         return fs$readSync.call(fs, fd, buffer, offset, length, position)
139       } catch (er) {
140         if (er.code === 'EAGAIN' && eagCounter < 10) {
141           eagCounter ++
142           continue
143         }
144         throw er
145       }
146     }
147   }})(fs.readSync)
148 }
149
150 function patchLchmod (fs) {
151   fs.lchmod = function (path, mode, callback) {
152     fs.open( path
153            , constants.O_WRONLY | constants.O_SYMLINK
154            , mode
155            , function (err, fd) {
156       if (err) {
157         if (callback) callback(err)
158         return
159       }
160       // prefer to return the chmod error, if one occurs,
161       // but still try to close, and report closing errors if they occur.
162       fs.fchmod(fd, mode, function (err) {
163         fs.close(fd, function(err2) {
164           if (callback) callback(err || err2)
165         })
166       })
167     })
168   }
169
170   fs.lchmodSync = function (path, mode) {
171     var fd = fs.openSync(path, constants.O_WRONLY | constants.O_SYMLINK, mode)
172
173     // prefer to return the chmod error, if one occurs,
174     // but still try to close, and report closing errors if they occur.
175     var threw = true
176     var ret
177     try {
178       ret = fs.fchmodSync(fd, mode)
179       threw = false
180     } finally {
181       if (threw) {
182         try {
183           fs.closeSync(fd)
184         } catch (er) {}
185       } else {
186         fs.closeSync(fd)
187       }
188     }
189     return ret
190   }
191 }
192
193 function patchLutimes (fs) {
194   if (constants.hasOwnProperty("O_SYMLINK")) {
195     fs.lutimes = function (path, at, mt, cb) {
196       fs.open(path, constants.O_SYMLINK, function (er, fd) {
197         if (er) {
198           if (cb) cb(er)
199           return
200         }
201         fs.futimes(fd, at, mt, function (er) {
202           fs.close(fd, function (er2) {
203             if (cb) cb(er || er2)
204           })
205         })
206       })
207     }
208
209     fs.lutimesSync = function (path, at, mt) {
210       var fd = fs.openSync(path, constants.O_SYMLINK)
211       var ret
212       var threw = true
213       try {
214         ret = fs.futimesSync(fd, at, mt)
215         threw = false
216       } finally {
217         if (threw) {
218           try {
219             fs.closeSync(fd)
220           } catch (er) {}
221         } else {
222           fs.closeSync(fd)
223         }
224       }
225       return ret
226     }
227
228   } else {
229     fs.lutimes = function (_a, _b, _c, cb) { if (cb) process.nextTick(cb) }
230     fs.lutimesSync = function () {}
231   }
232 }
233
234 function chmodFix (orig) {
235   if (!orig) return orig
236   return function (target, mode, cb) {
237     return orig.call(fs, target, mode, function (er) {
238       if (chownErOk(er)) er = null
239       if (cb) cb.apply(this, arguments)
240     })
241   }
242 }
243
244 function chmodFixSync (orig) {
245   if (!orig) return orig
246   return function (target, mode) {
247     try {
248       return orig.call(fs, target, mode)
249     } catch (er) {
250       if (!chownErOk(er)) throw er
251     }
252   }
253 }
254
255
256 function chownFix (orig) {
257   if (!orig) return orig
258   return function (target, uid, gid, cb) {
259     return orig.call(fs, target, uid, gid, function (er) {
260       if (chownErOk(er)) er = null
261       if (cb) cb.apply(this, arguments)
262     })
263   }
264 }
265
266 function chownFixSync (orig) {
267   if (!orig) return orig
268   return function (target, uid, gid) {
269     try {
270       return orig.call(fs, target, uid, gid)
271     } catch (er) {
272       if (!chownErOk(er)) throw er
273     }
274   }
275 }
276
277
278 function statFix (orig) {
279   if (!orig) return orig
280   // Older versions of Node erroneously returned signed integers for
281   // uid + gid.
282   return function (target, cb) {
283     return orig.call(fs, target, function (er, stats) {
284       if (!stats) return cb.apply(this, arguments)
285       if (stats.uid < 0) stats.uid += 0x100000000
286       if (stats.gid < 0) stats.gid += 0x100000000
287       if (cb) cb.apply(this, arguments)
288     })
289   }
290 }
291
292 function statFixSync (orig) {
293   if (!orig) return orig
294   // Older versions of Node erroneously returned signed integers for
295   // uid + gid.
296   return function (target) {
297     var stats = orig.call(fs, target)
298     if (stats.uid < 0) stats.uid += 0x100000000
299     if (stats.gid < 0) stats.gid += 0x100000000
300     return stats;
301   }
302 }
303
304 // ENOSYS means that the fs doesn't support the op. Just ignore
305 // that, because it doesn't matter.
306 //
307 // if there's no getuid, or if getuid() is something other
308 // than 0, and the error is EINVAL or EPERM, then just ignore
309 // it.
310 //
311 // This specific case is a silent failure in cp, install, tar,
312 // and most other unix tools that manage permissions.
313 //
314 // When running as root, or if other types of errors are
315 // encountered, then it's strict.
316 function chownErOk (er) {
317   if (!er)
318     return true
319
320   if (er.code === "ENOSYS")
321     return true
322
323   var nonroot = !process.getuid || process.getuid() !== 0
324   if (nonroot) {
325     if (er.code === "EINVAL" || er.code === "EPERM")
326       return true
327   }
328
329   return false
330 }