pax_global_header00006660000000000000000000000064123457062740014524gustar00rootroot0000000000000052 comment=0caa11544c0c9001db78bf593cf0c5805d149a41 node-graceful-fs-3.0.2/000077500000000000000000000000001234570627400146475ustar00rootroot00000000000000node-graceful-fs-3.0.2/.gitignore000066400000000000000000000000161234570627400166340ustar00rootroot00000000000000node_modules/ node-graceful-fs-3.0.2/LICENSE000066400000000000000000000024361234570627400156610ustar00rootroot00000000000000Copyright (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-3.0.2/README.md000066400000000000000000000021621234570627400161270ustar00rootroot00000000000000# 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](http://api.nodejs.org/fs.html) graceful-fs: * Queues up `open` and `readdir` calls, and retries them once something closes if there is an EMFILE error from too many file descriptors. * 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. ## USAGE ```javascript // use just like fs var fs = require('graceful-fs') // now go and do stuff with it... fs.readFileSync('some-file-or-whatever') ``` node-graceful-fs-3.0.2/fs.js000066400000000000000000000006011234570627400156120ustar00rootroot00000000000000// eeeeeevvvvviiiiiiillllll // more evil than monkey-patching the native builtin? // Not sure. var mod = require("module") var pre = '(function (exports, require, module, __filename, __dirname) { ' var post = '});' var src = pre + process.binding('natives').fs + post var vm = require('vm') var fn = vm.runInThisContext(src) return fn(exports, require, module, __filename, __dirname) node-graceful-fs-3.0.2/graceful-fs.js000066400000000000000000000060051234570627400174040ustar00rootroot00000000000000// Monkey-patching the fs module. // It's ugly, but there is simply no other way to do this. var fs = module.exports = require('./fs.js') var assert = require('assert') // fix up some busted stuff, mostly on windows and old nodes require('./polyfills.js') var util = require('util') function noop () {} var debug = noop 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) { if (files && files.sort) files = files.sort() 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) { var tryAgain = false if (er) { var code = er.code var tryAgain = code === "EMFILE" if (process.platform === "win32") tryAgain = tryAgain || code === "OK" } if (tryAgain) { 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-3.0.2/package.json000066400000000000000000000012611234570627400171350ustar00rootroot00000000000000{ "author": "Isaac Z. Schlueter (http://blog.izs.me)", "name": "graceful-fs", "description": "A drop-in replacement for fs, making various improvements.", "version": "3.0.2", "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-3.0.2/polyfills.js000066400000000000000000000145261234570627400172320ustar00rootroot00000000000000var fs = require('./fs.js') 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. // It should not fail on enosys ever, as this just indicates // that a fs doesn't support the intended operation. fs.chown = chownFix(fs.chown) fs.fchown = chownFix(fs.fchown) fs.lchown = chownFix(fs.lchown) fs.chmod = chownFix(fs.chmod) fs.fchmod = chownFix(fs.fchmod) fs.lchmod = chownFix(fs.lchmod) fs.chownSync = chownFixSync(fs.chownSync) fs.fchownSync = chownFixSync(fs.fchownSync) fs.lchownSync = chownFixSync(fs.lchownSync) fs.chmodSync = chownFix(fs.chmodSync) fs.fchmodSync = chownFix(fs.fchmodSync) fs.lchmodSync = chownFix(fs.lchmodSync) 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 } } } // ENOSYS means that the fs doesn't support the op. Just ignore // that, because it doesn't matter. // // 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. function chownErOk (er) { if (!er) return true if (er.code === "ENOSYS") return true var nonroot = !process.getuid || process.getuid() !== 0 if (nonroot) { if (er.code === "EINVAL" || er.code === "EPERM") return true } return false } // 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-3.0.2/test/000077500000000000000000000000001234570627400156265ustar00rootroot00000000000000node-graceful-fs-3.0.2/test/open.js000066400000000000000000000016011234570627400171230ustar00rootroot00000000000000var test = require('tap').test var fs = require('../graceful-fs.js') test('graceful fs is monkeypatched fs', function (t) { t.equal(fs, require('../fs.js')) 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() }) }) node-graceful-fs-3.0.2/test/readdir-sort.js000066400000000000000000000006321234570627400205640ustar00rootroot00000000000000var test = require("tap").test var fs = require("../fs.js") var readdir = fs.readdir fs.readdir = function(path, cb) { process.nextTick(function() { cb(null, ["b", "z", "a"]) }) } var g = require("../") test("readdir reorder", function (t) { g.readdir("whatevers", function (er, files) { if (er) throw er console.error(files) t.same(files, [ "a", "b", "z" ]) t.end() }) })