1 var fs = require('./fs.js')
2 var constants = require('constants')
4 var origCwd = process.cwd
7 var platform = process.env.GRACEFUL_FS_PLATFORM || process.platform
9 process.cwd = function() {
11 cwd = origCwd.call(process)
18 var chdir = process.chdir
19 process.chdir = function(d) {
21 chdir.call(process, d)
24 module.exports = patch
27 // (re-)implement some things that are known busted or missing.
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\./)) {
36 // lutimes implementation, or no-op
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.
46 fs.chown = chownFix(fs.chown)
47 fs.fchown = chownFix(fs.fchown)
48 fs.lchown = chownFix(fs.lchown)
50 fs.chmod = chmodFix(fs.chmod)
51 fs.fchmod = chmodFix(fs.fchmod)
52 fs.lchmod = chmodFix(fs.lchmod)
54 fs.chownSync = chownFixSync(fs.chownSync)
55 fs.fchownSync = chownFixSync(fs.fchownSync)
56 fs.lchownSync = chownFixSync(fs.lchownSync)
58 fs.chmodSync = chmodFixSync(fs.chmodSync)
59 fs.fchmodSync = chmodFixSync(fs.fchmodSync)
60 fs.lchmodSync = chmodFixSync(fs.lchmodSync)
62 fs.stat = statFix(fs.stat)
63 fs.fstat = statFix(fs.fstat)
64 fs.lstat = statFix(fs.lstat)
66 fs.statSync = statFixSync(fs.statSync)
67 fs.fstatSync = statFixSync(fs.fstatSync)
68 fs.lstatSync = statFixSync(fs.lstatSync)
70 // if lchmod/lchown do not exist, then make them no-ops
72 fs.lchmod = function (path, mode, cb) {
73 if (cb) process.nextTick(cb)
75 fs.lchmodSync = function () {}
78 fs.lchown = function (path, uid, gid, cb) {
79 if (cb) process.nextTick(cb)
81 fs.lchownSync = function () {}
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.
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()
97 fs$rename(from, to, function CB (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);
118 // if read() returns EAGAIN, then just try it again.
119 fs.read = (function (fs$read) { return function (fd, buffer, offset, length, position, callback_) {
121 if (callback_ && typeof callback_ === 'function') {
123 callback = function (er, _, __) {
124 if (er && er.code === 'EAGAIN' && eagCounter < 10) {
126 return fs$read.call(fs, fd, buffer, offset, length, position, callback)
128 callback_.apply(this, arguments)
131 return fs$read.call(fs, fd, buffer, offset, length, position, callback)
134 fs.readSync = (function (fs$readSync) { return function (fd, buffer, offset, length, position) {
138 return fs$readSync.call(fs, fd, buffer, offset, length, position)
140 if (er.code === 'EAGAIN' && eagCounter < 10) {
150 function patchLchmod (fs) {
151 fs.lchmod = function (path, mode, callback) {
153 , constants.O_WRONLY | constants.O_SYMLINK
155 , function (err, fd) {
157 if (callback) callback(err)
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)
170 fs.lchmodSync = function (path, mode) {
171 var fd = fs.openSync(path, constants.O_WRONLY | constants.O_SYMLINK, mode)
173 // prefer to return the chmod error, if one occurs,
174 // but still try to close, and report closing errors if they occur.
178 ret = fs.fchmodSync(fd, mode)
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) {
201 fs.futimes(fd, at, mt, function (er) {
202 fs.close(fd, function (er2) {
203 if (cb) cb(er || er2)
209 fs.lutimesSync = function (path, at, mt) {
210 var fd = fs.openSync(path, constants.O_SYMLINK)
214 ret = fs.futimesSync(fd, at, mt)
229 fs.lutimes = function (_a, _b, _c, cb) { if (cb) process.nextTick(cb) }
230 fs.lutimesSync = function () {}
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)
244 function chmodFixSync (orig) {
245 if (!orig) return orig
246 return function (target, mode) {
248 return orig.call(fs, target, mode)
250 if (!chownErOk(er)) throw er
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)
266 function chownFixSync (orig) {
267 if (!orig) return orig
268 return function (target, uid, gid) {
270 return orig.call(fs, target, uid, gid)
272 if (!chownErOk(er)) throw er
278 function statFix (orig) {
279 if (!orig) return orig
280 // Older versions of Node erroneously returned signed integers for
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)
292 function statFixSync (orig) {
293 if (!orig) return orig
294 // Older versions of Node erroneously returned signed integers for
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
304 // ENOSYS means that the fs doesn't support the op. Just ignore
305 // that, because it doesn't matter.
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
311 // This specific case is a silent failure in cp, install, tar,
312 // and most other unix tools that manage permissions.
314 // When running as root, or if other types of errors are
315 // encountered, then it's strict.
316 function chownErOk (er) {
320 if (er.code === "ENOSYS")
323 var nonroot = !process.getuid || process.getuid() !== 0
325 if (er.code === "EINVAL" || er.code === "EPERM")