pax_global_header00006660000000000000000000000064121674550650014525gustar00rootroot0000000000000052 comment=30bb28a20548bcd1308897c5c661f9c6283bfe9b node-graceful-fs-2.0.0/000077500000000000000000000000001216745506500146455ustar00rootroot00000000000000node-graceful-fs-2.0.0/.gitignore000066400000000000000000000000161216745506500166320ustar00rootroot00000000000000node_modules/ node-graceful-fs-2.0.0/LICENSE000066400000000000000000000024361216745506500156570ustar00rootroot00000000000000Copyright (c) Isaac Z. Schlueter ("Author") All rights reserved. The BSD License Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. node-graceful-fs-2.0.0/README.md000066400000000000000000000023141216745506500161240ustar00rootroot00000000000000# graceful-fs graceful-fs functions as a drop-in replacement for the fs module, making various improvements. The improvements are meant to normalize behavior across different platforms and environments, and to make filesystem access more resilient to errors. ## Improvements over fs module graceful-fs: * keeps track of how many file descriptors are open, and by default limits this to 1024. Any further requests to open a file are put in a queue until new slots become available. If 1024 turns out to be too much, it decreases the limit further. * fixes `lchmod` for Node versions prior to 0.6.2. * implements `fs.lutimes` if possible. Otherwise it becomes a noop. * ignores `EINVAL` and `EPERM` errors in `chown`, `fchown` or `lchown` if the user isn't root. * makes `lchmod` and `lchown` become noops, if not available. * retries reading a file if `read` results in EAGAIN error. On Windows, it retries renaming a file for up to one second if `EACCESS` or `EPERM` error occurs, likely because antivirus software has locked the directory. ## Configuration The maximum number of open file descriptors that graceful-fs manages may be adjusted by setting `fs.MAX_OPEN` to a different number. The default is 1024. node-graceful-fs-2.0.0/graceful-fs.js000066400000000000000000000056431216745506500174110ustar00rootroot00000000000000// Monkey-patching the fs module. // It's ugly, but there is simply no other way to do this. var fs = module.exports = require('fs') var assert = require('assert') // fix up some busted stuff, mostly on windows and old nodes require('./polyfills.js') // The EMFILE enqueuing stuff var util = require('util') function noop () {} var debug = noop var util = require('util') if (util.debuglog) debug = util.debuglog('gfs') else if (/\bgfs\b/i.test(process.env.NODE_DEBUG || '')) debug = function() { var m = util.format.apply(util, arguments) m = 'GFS: ' + m.split(/\n/).join('\nGFS: ') console.error(m) } if (/\bgfs\b/i.test(process.env.NODE_DEBUG || '')) { process.on('exit', function() { debug('fds', fds) debug(queue) assert.equal(queue.length, 0) }) } var originalOpen = fs.open fs.open = open function open(path, flags, mode, cb) { if (typeof mode === "function") cb = mode, mode = null if (typeof cb !== "function") cb = noop new OpenReq(path, flags, mode, cb) } function OpenReq(path, flags, mode, cb) { this.path = path this.flags = flags this.mode = mode this.cb = cb Req.call(this) } util.inherits(OpenReq, Req) OpenReq.prototype.process = function() { originalOpen.call(fs, this.path, this.flags, this.mode, this.done) } var fds = {} OpenReq.prototype.done = function(er, fd) { debug('open done', er, fd) if (fd) fds['fd' + fd] = this.path Req.prototype.done.call(this, er, fd) } var originalReaddir = fs.readdir fs.readdir = readdir function readdir(path, cb) { if (typeof cb !== "function") cb = noop new ReaddirReq(path, cb) } function ReaddirReq(path, cb) { this.path = path this.cb = cb Req.call(this) } util.inherits(ReaddirReq, Req) ReaddirReq.prototype.process = function() { originalReaddir.call(fs, this.path, this.done) } ReaddirReq.prototype.done = function(er, files) { Req.prototype.done.call(this, er, files) onclose() } var originalClose = fs.close fs.close = close function close (fd, cb) { debug('close', fd) if (typeof cb !== "function") cb = noop delete fds['fd' + fd] originalClose.call(fs, fd, function(er) { onclose() cb(er) }) } var originalCloseSync = fs.closeSync fs.closeSync = closeSync function closeSync (fd) { try { return originalCloseSync(fd) } finally { onclose() } } // Req class function Req () { // start processing this.done = this.done.bind(this) this.failures = 0 this.process() } Req.prototype.done = function (er, result) { // if an error, and the code is EMFILE, then get in the queue if (er && er.code === "EMFILE") { this.failures ++ enqueue(this) } else { var cb = this.cb cb(er, result) } } var queue = [] function enqueue(req) { queue.push(req) debug('enqueue %d %s', queue.length, req.constructor.name, req) } function onclose() { var req = queue.shift() if (req) { debug('process', req.constructor.name, req) req.process() } } node-graceful-fs-2.0.0/package.json000066400000000000000000000012611216745506500171330ustar00rootroot00000000000000{ "author": "Isaac Z. Schlueter (http://blog.izs.me)", "name": "graceful-fs", "description": "A drop-in replacement for fs, making various improvements.", "version": "2.0.0", "repository": { "type": "git", "url": "git://github.com/isaacs/node-graceful-fs.git" }, "main": "graceful-fs.js", "engines": { "node": ">=0.4.0" }, "directories": { "test": "test" }, "scripts": { "test": "tap test/*.js" }, "keywords": [ "fs", "module", "reading", "retry", "retries", "queue", "error", "errors", "handling", "EMFILE", "EAGAIN", "EINVAL", "EPERM", "EACCESS" ], "license": "BSD" } node-graceful-fs-2.0.0/polyfills.js000066400000000000000000000134631216745506500172270ustar00rootroot00000000000000var fs = require('fs') var constants = require('constants') var origCwd = process.cwd var cwd = null process.cwd = function() { if (!cwd) cwd = origCwd.call(process) return cwd } var chdir = process.chdir process.chdir = function(d) { cwd = null chdir.call(process, d) } // (re-)implement some things that are known busted or missing. // lchmod, broken prior to 0.6.2 // back-port the fix here. if (constants.hasOwnProperty('O_SYMLINK') && process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) { fs.lchmod = function (path, mode, callback) { callback = callback || noop fs.open( path , constants.O_WRONLY | constants.O_SYMLINK , mode , function (err, fd) { if (err) { callback(err) return } // prefer to return the chmod error, if one occurs, // but still try to close, and report closing errors if they occur. fs.fchmod(fd, mode, function (err) { fs.close(fd, function(err2) { callback(err || err2) }) }) }) } fs.lchmodSync = function (path, mode) { var fd = fs.openSync(path, constants.O_WRONLY | constants.O_SYMLINK, mode) // prefer to return the chmod error, if one occurs, // but still try to close, and report closing errors if they occur. var err, err2 try { var ret = fs.fchmodSync(fd, mode) } catch (er) { err = er } try { fs.closeSync(fd) } catch (er) { err2 = er } if (err || err2) throw (err || err2) return ret } } // lutimes implementation, or no-op if (!fs.lutimes) { if (constants.hasOwnProperty("O_SYMLINK")) { fs.lutimes = function (path, at, mt, cb) { fs.open(path, constants.O_SYMLINK, function (er, fd) { cb = cb || noop if (er) return cb(er) fs.futimes(fd, at, mt, function (er) { fs.close(fd, function (er2) { return cb(er || er2) }) }) }) } fs.lutimesSync = function (path, at, mt) { var fd = fs.openSync(path, constants.O_SYMLINK) , err , err2 , ret try { var ret = fs.futimesSync(fd, at, mt) } catch (er) { err = er } try { fs.closeSync(fd) } catch (er) { err2 = er } if (err || err2) throw (err || err2) return ret } } else if (fs.utimensat && constants.hasOwnProperty("AT_SYMLINK_NOFOLLOW")) { // maybe utimensat will be bound soonish? fs.lutimes = function (path, at, mt, cb) { fs.utimensat(path, at, mt, constants.AT_SYMLINK_NOFOLLOW, cb) } fs.lutimesSync = function (path, at, mt) { return fs.utimensatSync(path, at, mt, constants.AT_SYMLINK_NOFOLLOW) } } else { fs.lutimes = function (_a, _b, _c, cb) { process.nextTick(cb) } fs.lutimesSync = function () {} } } // https://github.com/isaacs/node-graceful-fs/issues/4 // Chown should not fail on einval or eperm if non-root. fs.chown = chownFix(fs.chown) fs.fchown = chownFix(fs.fchown) fs.lchown = chownFix(fs.lchown) fs.chownSync = chownFixSync(fs.chownSync) fs.fchownSync = chownFixSync(fs.fchownSync) fs.lchownSync = chownFixSync(fs.lchownSync) function chownFix (orig) { if (!orig) return orig return function (target, uid, gid, cb) { return orig.call(fs, target, uid, gid, function (er, res) { if (chownErOk(er)) er = null cb(er, res) }) } } function chownFixSync (orig) { if (!orig) return orig return function (target, uid, gid) { try { return orig.call(fs, target, uid, gid) } catch (er) { if (!chownErOk(er)) throw er } } } function chownErOk (er) { // if there's no getuid, or if getuid() is something other than 0, // and the error is EINVAL or EPERM, then just ignore it. // This specific case is a silent failure in cp, install, tar, // and most other unix tools that manage permissions. // When running as root, or if other types of errors are encountered, // then it's strict. if (!er || (!process.getuid || process.getuid() !== 0) && (er.code === "EINVAL" || er.code === "EPERM")) return true } // if lchmod/lchown do not exist, then make them no-ops if (!fs.lchmod) { fs.lchmod = function (path, mode, cb) { process.nextTick(cb) } fs.lchmodSync = function () {} } if (!fs.lchown) { fs.lchown = function (path, uid, gid, cb) { process.nextTick(cb) } fs.lchownSync = function () {} } // on Windows, A/V software can lock the directory, causing this // to fail with an EACCES or EPERM if the directory contains newly // created files. Try again on failure, for up to 1 second. if (process.platform === "win32") { var rename_ = fs.rename fs.rename = function rename (from, to, cb) { var start = Date.now() rename_(from, to, function CB (er) { if (er && (er.code === "EACCES" || er.code === "EPERM") && Date.now() - start < 1000) { return rename_(from, to, CB) } cb(er) }) } } // if read() returns EAGAIN, then just try it again. var read = fs.read fs.read = function (fd, buffer, offset, length, position, callback_) { var callback if (callback_ && typeof callback_ === 'function') { var eagCounter = 0 callback = function (er, _, __) { if (er && er.code === 'EAGAIN' && eagCounter < 10) { eagCounter ++ return read.call(fs, fd, buffer, offset, length, position, callback) } callback_.apply(this, arguments) } } return read.call(fs, fd, buffer, offset, length, position, callback) } var readSync = fs.readSync fs.readSync = function (fd, buffer, offset, length, position) { var eagCounter = 0 while (true) { try { return readSync.call(fs, fd, buffer, offset, length, position) } catch (er) { if (er.code === 'EAGAIN' && eagCounter < 10) { eagCounter ++ continue } throw er } } } node-graceful-fs-2.0.0/test/000077500000000000000000000000001216745506500156245ustar00rootroot00000000000000node-graceful-fs-2.0.0/test/open.js000066400000000000000000000015731216745506500171310ustar00rootroot00000000000000var test = require('tap').test var fs = require('../graceful-fs.js') test('graceful fs is monkeypatched fs', function (t) { t.equal(fs, require('fs')) t.end() }) test('open an existing file works', function (t) { var fd = fs.openSync(__filename, 'r') fs.closeSync(fd) fs.open(__filename, 'r', function (er, fd) { if (er) throw er fs.close(fd, function (er) { if (er) throw er t.pass('works') t.end() }) }) }) test('open a non-existing file throws', function (t) { var er try { var fd = fs.openSync('this file does not exist', 'r') } catch (x) { er = x } t.ok(er, 'should throw') t.notOk(fd, 'should not get an fd') t.equal(er.code, 'ENOENT') fs.open('neither does this file', 'r', function (er, fd) { t.ok(er, 'should throw') t.notOk(fd, 'should not get an fd') t.equal(er.code, 'ENOENT') t.end() }) })