pax_global_header00006660000000000000000000000064130151163140014505gustar00rootroot0000000000000052 comment=65cf80d1fd3413b823c16c626c1e7c326452bee5 node-graceful-fs-4.1.11/000077500000000000000000000000001301511631400147125ustar00rootroot00000000000000node-graceful-fs-4.1.11/.gitignore000066400000000000000000000000451301511631400167010ustar00rootroot00000000000000node_modules/ coverage/ .nyc_output/ node-graceful-fs-4.1.11/.travis.yml000066400000000000000000000001121301511631400170150ustar00rootroot00000000000000sudo: false language: node_js node_js: - '0.10' - '4' - '5' - '6' node-graceful-fs-4.1.11/LICENSE000066400000000000000000000014151301511631400157200ustar00rootroot00000000000000The ISC License Copyright (c) Isaac Z. Schlueter, Ben Noordhuis, and Contributors Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. node-graceful-fs-4.1.11/README.md000066400000000000000000000105461301511631400161770ustar00rootroot00000000000000# 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](https://nodejs.org/api/fs.html) * 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') ``` ## Global Patching If you want to patch the global fs module (or any other fs-like module) you can do this: ```javascript // Make sure to read the caveat below. var realFs = require('fs') var gracefulFs = require('graceful-fs') gracefulFs.gracefulify(realFs) ``` This should only ever be done at the top-level application layer, in order to delay on EMFILE errors from any fs-using dependencies. You should **not** do this in a library, because it can cause unexpected delays in other parts of the program. ## Changes This module is fairly stable at this point, and used by a lot of things. That being said, because it implements a subtle behavior change in a core part of the node API, even modest changes can be extremely breaking, and the versioning is thus biased towards bumping the major when in doubt. The main change between major versions has been switching between providing a fully-patched `fs` module vs monkey-patching the node core builtin, and the approach by which a non-monkey-patched `fs` was created. The goal is to trade `EMFILE` errors for slower fs operations. So, if you try to open a zillion files, rather than crashing, `open` operations will be queued up and wait for something else to `close`. There are advantages to each approach. Monkey-patching the fs means that no `EMFILE` errors can possibly occur anywhere in your application, because everything is using the same core `fs` module, which is patched. However, it can also obviously cause undesirable side-effects, especially if the module is loaded multiple times. Implementing a separate-but-identical patched `fs` module is more surgical (and doesn't run the risk of patching multiple times), but also imposes the challenge of keeping in sync with the core module. The current approach loads the `fs` module, and then creates a lookalike object that has all the same methods, except a few that are patched. It is safe to use in all versions of Node from 0.8 through 7.0. ### v4 * Do not monkey-patch the fs module. This module may now be used as a drop-in dep, and users can opt into monkey-patching the fs builtin if their app requires it. ### v3 * Monkey-patch fs, because the eval approach no longer works on recent node. * fixed possible type-error throw if rename fails on windows * verify that we *never* get EMFILE errors * Ignore ENOSYS from chmod/chown * clarify that graceful-fs must be used as a drop-in ### v2.1.0 * Use eval rather than monkey-patching fs. * readdir: Always sort the results * win32: requeue a file if error has an OK status ### v2.0 * A return to monkey patching * wrap process.cwd ### v1.1 * wrap readFile * Wrap fs.writeFile. * readdir protection * Don't clobber the fs builtin * Handle fs.read EAGAIN errors by trying again * Expose the curOpen counter * No-op lchown/lchmod if not implemented * fs.rename patch only for win32 * Patch fs.rename to handle AV software on Windows * Close #4 Chown should not fail on einval or eperm if non-root * Fix isaacs/fstream#1 Only wrap fs one time * Fix #3 Start at 1024 max files, then back off on EMFILE * lutimes that doens't blow up on Linux * A full on-rewrite using a queue instead of just swallowing the EMFILE error * Wrap Read/Write streams as well ### 1.0 * Update engines for node 0.6 * Be lstat-graceful on Windows * first node-graceful-fs-4.1.11/fs.js000066400000000000000000000006551301511631400156660ustar00rootroot00000000000000'use strict' var fs = require('fs') module.exports = clone(fs) function clone (obj) { if (obj === null || typeof obj !== 'object') return obj if (obj instanceof Object) var copy = { __proto__: obj.__proto__ } else var copy = Object.create(null) Object.getOwnPropertyNames(obj).forEach(function (key) { Object.defineProperty(copy, key, Object.getOwnPropertyDescriptor(obj, key)) }) return copy } node-graceful-fs-4.1.11/graceful-fs.js000066400000000000000000000154331301511631400174540ustar00rootroot00000000000000var fs = require('fs') var polyfills = require('./polyfills.js') var legacy = require('./legacy-streams.js') var queue = [] var util = require('util') function noop () {} var debug = noop if (util.debuglog) debug = util.debuglog('gfs4') else if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || '')) debug = function() { var m = util.format.apply(util, arguments) m = 'GFS4: ' + m.split(/\n/).join('\nGFS4: ') console.error(m) } if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || '')) { process.on('exit', function() { debug(queue) require('assert').equal(queue.length, 0) }) } module.exports = patch(require('./fs.js')) if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH) { module.exports = patch(fs) } // Always patch fs.close/closeSync, because we want to // retry() whenever a close happens *anywhere* in the program. // This is essential when multiple graceful-fs instances are // in play at the same time. module.exports.close = fs.close = (function (fs$close) { return function (fd, cb) { return fs$close.call(fs, fd, function (err) { if (!err) retry() if (typeof cb === 'function') cb.apply(this, arguments) }) }})(fs.close) module.exports.closeSync = fs.closeSync = (function (fs$closeSync) { return function (fd) { // Note that graceful-fs also retries when fs.closeSync() fails. // Looks like a bug to me, although it's probably a harmless one. var rval = fs$closeSync.apply(fs, arguments) retry() return rval }})(fs.closeSync) function patch (fs) { // Everything that references the open() function needs to be in here polyfills(fs) fs.gracefulify = patch fs.FileReadStream = ReadStream; // Legacy name. fs.FileWriteStream = WriteStream; // Legacy name. fs.createReadStream = createReadStream fs.createWriteStream = createWriteStream var fs$readFile = fs.readFile fs.readFile = readFile function readFile (path, options, cb) { if (typeof options === 'function') cb = options, options = null return go$readFile(path, options, cb) function go$readFile (path, options, cb) { return fs$readFile(path, options, function (err) { if (err && (err.code === 'EMFILE' || err.code === 'ENFILE')) enqueue([go$readFile, [path, options, cb]]) else { if (typeof cb === 'function') cb.apply(this, arguments) retry() } }) } } var fs$writeFile = fs.writeFile fs.writeFile = writeFile function writeFile (path, data, options, cb) { if (typeof options === 'function') cb = options, options = null return go$writeFile(path, data, options, cb) function go$writeFile (path, data, options, cb) { return fs$writeFile(path, data, options, function (err) { if (err && (err.code === 'EMFILE' || err.code === 'ENFILE')) enqueue([go$writeFile, [path, data, options, cb]]) else { if (typeof cb === 'function') cb.apply(this, arguments) retry() } }) } } var fs$appendFile = fs.appendFile if (fs$appendFile) fs.appendFile = appendFile function appendFile (path, data, options, cb) { if (typeof options === 'function') cb = options, options = null return go$appendFile(path, data, options, cb) function go$appendFile (path, data, options, cb) { return fs$appendFile(path, data, options, function (err) { if (err && (err.code === 'EMFILE' || err.code === 'ENFILE')) enqueue([go$appendFile, [path, data, options, cb]]) else { if (typeof cb === 'function') cb.apply(this, arguments) retry() } }) } } var fs$readdir = fs.readdir fs.readdir = readdir function readdir (path, options, cb) { var args = [path] if (typeof options !== 'function') { args.push(options) } else { cb = options } args.push(go$readdir$cb) return go$readdir(args) function go$readdir$cb (err, files) { if (files && files.sort) files.sort() if (err && (err.code === 'EMFILE' || err.code === 'ENFILE')) enqueue([go$readdir, [args]]) else { if (typeof cb === 'function') cb.apply(this, arguments) retry() } } } function go$readdir (args) { return fs$readdir.apply(fs, args) } if (process.version.substr(0, 4) === 'v0.8') { var legStreams = legacy(fs) ReadStream = legStreams.ReadStream WriteStream = legStreams.WriteStream } var fs$ReadStream = fs.ReadStream ReadStream.prototype = Object.create(fs$ReadStream.prototype) ReadStream.prototype.open = ReadStream$open var fs$WriteStream = fs.WriteStream WriteStream.prototype = Object.create(fs$WriteStream.prototype) WriteStream.prototype.open = WriteStream$open fs.ReadStream = ReadStream fs.WriteStream = WriteStream function ReadStream (path, options) { if (this instanceof ReadStream) return fs$ReadStream.apply(this, arguments), this else return ReadStream.apply(Object.create(ReadStream.prototype), arguments) } function ReadStream$open () { var that = this open(that.path, that.flags, that.mode, function (err, fd) { if (err) { if (that.autoClose) that.destroy() that.emit('error', err) } else { that.fd = fd that.emit('open', fd) that.read() } }) } function WriteStream (path, options) { if (this instanceof WriteStream) return fs$WriteStream.apply(this, arguments), this else return WriteStream.apply(Object.create(WriteStream.prototype), arguments) } function WriteStream$open () { var that = this open(that.path, that.flags, that.mode, function (err, fd) { if (err) { that.destroy() that.emit('error', err) } else { that.fd = fd that.emit('open', fd) } }) } function createReadStream (path, options) { return new ReadStream(path, options) } function createWriteStream (path, options) { return new WriteStream(path, options) } var fs$open = fs.open fs.open = open function open (path, flags, mode, cb) { if (typeof mode === 'function') cb = mode, mode = null return go$open(path, flags, mode, cb) function go$open (path, flags, mode, cb) { return fs$open(path, flags, mode, function (err, fd) { if (err && (err.code === 'EMFILE' || err.code === 'ENFILE')) enqueue([go$open, [path, flags, mode, cb]]) else { if (typeof cb === 'function') cb.apply(this, arguments) retry() } }) } } return fs } function enqueue (elem) { debug('ENQUEUE', elem[0].name, elem[1]) queue.push(elem) } function retry () { var elem = queue.shift() if (elem) { debug('RETRY', elem[0].name, elem[1]) elem[0].apply(null, elem[1]) } } node-graceful-fs-4.1.11/legacy-streams.js000066400000000000000000000051371301511631400201760ustar00rootroot00000000000000var Stream = require('stream').Stream module.exports = legacy function legacy (fs) { return { ReadStream: ReadStream, WriteStream: WriteStream } function ReadStream (path, options) { if (!(this instanceof ReadStream)) return new ReadStream(path, options); Stream.call(this); var self = this; this.path = path; this.fd = null; this.readable = true; this.paused = false; this.flags = 'r'; this.mode = 438; /*=0666*/ this.bufferSize = 64 * 1024; options = options || {}; // Mixin options into this var keys = Object.keys(options); for (var index = 0, length = keys.length; index < length; index++) { var key = keys[index]; this[key] = options[key]; } if (this.encoding) this.setEncoding(this.encoding); if (this.start !== undefined) { if ('number' !== typeof this.start) { throw TypeError('start must be a Number'); } if (this.end === undefined) { this.end = Infinity; } else if ('number' !== typeof this.end) { throw TypeError('end must be a Number'); } if (this.start > this.end) { throw new Error('start must be <= end'); } this.pos = this.start; } if (this.fd !== null) { process.nextTick(function() { self._read(); }); return; } fs.open(this.path, this.flags, this.mode, function (err, fd) { if (err) { self.emit('error', err); self.readable = false; return; } self.fd = fd; self.emit('open', fd); self._read(); }) } function WriteStream (path, options) { if (!(this instanceof WriteStream)) return new WriteStream(path, options); Stream.call(this); this.path = path; this.fd = null; this.writable = true; this.flags = 'w'; this.encoding = 'binary'; this.mode = 438; /*=0666*/ this.bytesWritten = 0; options = options || {}; // Mixin options into this var keys = Object.keys(options); for (var index = 0, length = keys.length; index < length; index++) { var key = keys[index]; this[key] = options[key]; } if (this.start !== undefined) { if ('number' !== typeof this.start) { throw TypeError('start must be a Number'); } if (this.start < 0) { throw new Error('start must be >= zero'); } this.pos = this.start; } this.busy = false; this._queue = []; if (this.fd === null) { this._open = fs.open; this._queue.push([this._open, this.path, this.flags, this.mode, undefined]); this.flush(); } } } node-graceful-fs-4.1.11/package.json000066400000000000000000000014661301511631400172070ustar00rootroot00000000000000{ "name": "graceful-fs", "description": "A drop-in replacement for fs, making various improvements.", "version": "4.1.11", "repository": { "type": "git", "url": "https://github.com/isaacs/node-graceful-fs" }, "main": "graceful-fs.js", "engines": { "node": ">=0.4.0" }, "directories": { "test": "test" }, "scripts": { "test": "node test.js | tap -" }, "keywords": [ "fs", "module", "reading", "retry", "retries", "queue", "error", "errors", "handling", "EMFILE", "EAGAIN", "EINVAL", "EPERM", "EACCESS" ], "license": "ISC", "devDependencies": { "mkdirp": "^0.5.0", "rimraf": "^2.2.8", "tap": "^5.4.2" }, "files": [ "fs.js", "graceful-fs.js", "legacy-streams.js", "polyfills.js" ] } node-graceful-fs-4.1.11/polyfills.js000066400000000000000000000212041301511631400172640ustar00rootroot00000000000000var fs = require('./fs.js') var constants = require('constants') var origCwd = process.cwd var cwd = null var platform = process.env.GRACEFUL_FS_PLATFORM || process.platform process.cwd = function() { if (!cwd) cwd = origCwd.call(process) return cwd } try { process.cwd() } catch (er) {} var chdir = process.chdir process.chdir = function(d) { cwd = null chdir.call(process, d) } module.exports = patch function patch (fs) { // (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\./)) { patchLchmod(fs) } // lutimes implementation, or no-op if (!fs.lutimes) { patchLutimes(fs) } // 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 = chmodFix(fs.chmod) fs.fchmod = chmodFix(fs.fchmod) fs.lchmod = chmodFix(fs.lchmod) fs.chownSync = chownFixSync(fs.chownSync) fs.fchownSync = chownFixSync(fs.fchownSync) fs.lchownSync = chownFixSync(fs.lchownSync) fs.chmodSync = chmodFixSync(fs.chmodSync) fs.fchmodSync = chmodFixSync(fs.fchmodSync) fs.lchmodSync = chmodFixSync(fs.lchmodSync) fs.stat = statFix(fs.stat) fs.fstat = statFix(fs.fstat) fs.lstat = statFix(fs.lstat) fs.statSync = statFixSync(fs.statSync) fs.fstatSync = statFixSync(fs.fstatSync) fs.lstatSync = statFixSync(fs.lstatSync) // if lchmod/lchown do not exist, then make them no-ops if (!fs.lchmod) { fs.lchmod = function (path, mode, cb) { if (cb) process.nextTick(cb) } fs.lchmodSync = function () {} } if (!fs.lchown) { fs.lchown = function (path, uid, gid, cb) { if (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 60 seconds. // Set the timeout this long because some Windows Anti-Virus, such as Parity // bit9, may lock files for up to a minute, causing npm package install // failures. Also, take care to yield the scheduler. Windows scheduling gives // CPU to a busy looping process, which can cause the program causing the lock // contention to be starved of CPU by node, so the contention doesn't resolve. if (platform === "win32") { fs.rename = (function (fs$rename) { return function (from, to, cb) { var start = Date.now() var backoff = 0; fs$rename(from, to, function CB (er) { if (er && (er.code === "EACCES" || er.code === "EPERM") && Date.now() - start < 60000) { setTimeout(function() { fs.stat(to, function (stater, st) { if (stater && stater.code === "ENOENT") fs$rename(from, to, CB); else cb(er) }) }, backoff) if (backoff < 100) backoff += 10; return; } if (cb) cb(er) }) }})(fs.rename) } // if read() returns EAGAIN, then just try it again. fs.read = (function (fs$read) { return 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 fs$read.call(fs, fd, buffer, offset, length, position, callback) } callback_.apply(this, arguments) } } return fs$read.call(fs, fd, buffer, offset, length, position, callback) }})(fs.read) fs.readSync = (function (fs$readSync) { return function (fd, buffer, offset, length, position) { var eagCounter = 0 while (true) { try { return fs$readSync.call(fs, fd, buffer, offset, length, position) } catch (er) { if (er.code === 'EAGAIN' && eagCounter < 10) { eagCounter ++ continue } throw er } } }})(fs.readSync) } function patchLchmod (fs) { fs.lchmod = function (path, mode, callback) { fs.open( path , constants.O_WRONLY | constants.O_SYMLINK , mode , function (err, fd) { if (err) { if (callback) 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) { if (callback) 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 threw = true var ret try { ret = fs.fchmodSync(fd, mode) threw = false } finally { if (threw) { try { fs.closeSync(fd) } catch (er) {} } else { fs.closeSync(fd) } } return ret } } function patchLutimes (fs) { if (constants.hasOwnProperty("O_SYMLINK")) { fs.lutimes = function (path, at, mt, cb) { fs.open(path, constants.O_SYMLINK, function (er, fd) { if (er) { if (cb) cb(er) return } fs.futimes(fd, at, mt, function (er) { fs.close(fd, function (er2) { if (cb) cb(er || er2) }) }) }) } fs.lutimesSync = function (path, at, mt) { var fd = fs.openSync(path, constants.O_SYMLINK) var ret var threw = true try { ret = fs.futimesSync(fd, at, mt) threw = false } finally { if (threw) { try { fs.closeSync(fd) } catch (er) {} } else { fs.closeSync(fd) } } return ret } } else { fs.lutimes = function (_a, _b, _c, cb) { if (cb) process.nextTick(cb) } fs.lutimesSync = function () {} } } function chmodFix (orig) { if (!orig) return orig return function (target, mode, cb) { return orig.call(fs, target, mode, function (er) { if (chownErOk(er)) er = null if (cb) cb.apply(this, arguments) }) } } function chmodFixSync (orig) { if (!orig) return orig return function (target, mode) { try { return orig.call(fs, target, mode) } catch (er) { if (!chownErOk(er)) throw er } } } function chownFix (orig) { if (!orig) return orig return function (target, uid, gid, cb) { return orig.call(fs, target, uid, gid, function (er) { if (chownErOk(er)) er = null if (cb) cb.apply(this, arguments) }) } } 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 statFix (orig) { if (!orig) return orig // Older versions of Node erroneously returned signed integers for // uid + gid. return function (target, cb) { return orig.call(fs, target, function (er, stats) { if (!stats) return cb.apply(this, arguments) if (stats.uid < 0) stats.uid += 0x100000000 if (stats.gid < 0) stats.gid += 0x100000000 if (cb) cb.apply(this, arguments) }) } } function statFixSync (orig) { if (!orig) return orig // Older versions of Node erroneously returned signed integers for // uid + gid. return function (target) { var stats = orig.call(fs, target) if (stats.uid < 0) stats.uid += 0x100000000 if (stats.gid < 0) stats.gid += 0x100000000 return stats; } } // 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 } node-graceful-fs-4.1.11/test.js000066400000000000000000000010771301511631400162340ustar00rootroot00000000000000var spawn = require('child_process').spawn var fs = require('fs') var tap = require('tap') var dir = __dirname + '/test' var node = process.execPath var files = fs.readdirSync(dir) var env = Object.keys(process.env).reduce(function (env, k) { env[k] = process.env[k] return env }, { TEST_GRACEFUL_FS_GLOBAL_PATCH: 1 }) files.filter(function (f) { if (/\.js$/.test(f) && fs.statSync(dir + '/' + f).isFile()) { tap.spawn(node, ['test/' + f]) return true } }).forEach(function (f) { tap.spawn(node, ['test/' + f], { env: env }, '🐵 test/' + f) }) node-graceful-fs-4.1.11/test/000077500000000000000000000000001301511631400156715ustar00rootroot00000000000000node-graceful-fs-4.1.11/test/chown-er-ok.js000066400000000000000000000022271301511631400203630ustar00rootroot00000000000000var t = require('tap') var realFs = require('fs') var methods = ['chown', 'chownSync', 'chmod', 'chmodSync'] methods.forEach(function (method) { causeErr(method, realFs[method]) }) function causeErr (method, original) { realFs[method] = function (path) { var err = makeErr(path, method) if (!/Sync$/.test(method)) { var cb = arguments[arguments.length - 1] process.nextTick(cb.bind(null, err)) } else { throw err } } } function makeErr (path, method) { var err = new Error('this is fine') err.syscall = method.replace(/Sync$/, '') err.code = path.toUpperCase() return err } var fs = require('../') var errs = ['ENOSYS', 'EINVAL', 'EPERM'] t.plan(errs.length * methods.length) errs.forEach(function (err) { methods.forEach(function (method) { var args = [err] if (/chmod/.test(method)) { args.push('some mode') } else { args.push('some uid', 'some gid') } if (method.match(/Sync$/)) { t.doesNotThrow(function () { fs[method].apply(fs, args) }) } else { args.push(function (err) { t.notOk(err) }) fs[method].apply(fs, args) } }) }) node-graceful-fs-4.1.11/test/close.js000066400000000000000000000004701301511631400173350ustar00rootroot00000000000000var test = require('tap').test var fs$close = require('fs').close; var fs$closeSync = require('fs').closeSync; var fs = require('../'); test('`close` is patched correctly', function(t) { t.notEqual(fs.close, fs$close, 'patch close'); t.notEqual(fs.closeSync, fs$closeSync, 'patch closeSync'); t.end(); }) node-graceful-fs-4.1.11/test/enoent.js000066400000000000000000000020611301511631400175160ustar00rootroot00000000000000// this test makes sure that various things get enoent, instead of // some other kind of throw. var t = require('tap') var g = require('../') var file = 'this file does not exist even a little bit' var methods = [ ['open', 'r'], ['readFile'], ['stat'], ['lstat'], ['utimes', new Date(), new Date()], ['readdir'] ] // any version > v6 can do readdir(path, options, cb) if (process.version.match(/^v([6-9]|[1-9][0-9])\./)) { methods.push(['readdir', {}]) } t.plan(methods.length) methods.forEach(function (method) { t.test(method[0], runTest(method)) }) function runTest (args) { return function (t) { var method = args.shift() args.unshift(file) var methodSync = method + 'Sync' t.isa(g[methodSync], 'function') t.throws(function () { g[methodSync].apply(g, args) }, { code: 'ENOENT' }) // add the callback args.push(verify(t)) t.isa(g[method], 'function') t.doesNotThrow(function () { g[method].apply(g, args) }) }} function verify (t) { return function (er) { t.isa(er, Error) t.equal(er.code, 'ENOENT') t.end() }} node-graceful-fs-4.1.11/test/max-open.js000066400000000000000000000026771301511631400177670ustar00rootroot00000000000000var test = require('tap').test var fs = require('../') test('open lots of stuff', function (t) { // Get around EBADF from libuv by making sure that stderr is opened // Otherwise Darwin will refuse to give us a FD for stderr! process.stderr.write('') // How many parallel open()'s to do var n = 1024 var opens = 0 var fds = [] var going = true var closing = false var doneCalled = 0 for (var i = 0; i < n; i++) { go() } function go() { opens++ fs.open(__filename, 'r', function (er, fd) { if (er) throw er fds.push(fd) if (going) go() }) } // should hit ulimit pretty fast setTimeout(function () { going = false t.equal(opens - fds.length, n) done() }, 100) function done () { if (closing) return doneCalled++ if (fds.length === 0) { // First because of the timeout // Then to close the fd's opened afterwards // Then this time, to complete. // Might take multiple passes, depending on CPU speed // and ulimit, but at least 3 in every case. t.ok(doneCalled >= 2) return t.end() } closing = true setTimeout(function () { // console.error('do closing again') closing = false done() }, 100) // console.error('closing time') var closes = fds.slice(0) fds.length = 0 closes.forEach(function (fd) { fs.close(fd, function (er) { if (er) throw er }) }) } }) node-graceful-fs-4.1.11/test/open.js000066400000000000000000000014131301511631400171670ustar00rootroot00000000000000var test = require('tap').test var fs = require('../') 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-4.1.11/test/read-write-stream.js000066400000000000000000000020001301511631400215530ustar00rootroot00000000000000'use strict' var fs = require('../') var rimraf = require('rimraf') var mkdirp = require('mkdirp') var test = require('tap').test var p = require('path').resolve(__dirname, 'files') process.chdir(__dirname) // Make sure to reserve the stderr fd process.stderr.write('') var num = 4097 var paths = new Array(num) test('write files', function (t) { rimraf.sync(p) mkdirp.sync(p) t.plan(num) for (var i = 0; i < num; ++i) { paths[i] = 'files/file-' + i var stream = fs.createWriteStream(paths[i]) stream.on('finish', function () { t.pass('success') }) stream.write('content') stream.end() } }) test('read files', function (t) { // now read them t.plan(num) for (var i = 0; i < num; ++i) (function (i) { var stream = fs.createReadStream(paths[i]) var data = '' stream.on('data', function (c) { data += c }) stream.on('end', function () { t.equal(data, 'content') }) })(i) }) test('cleanup', function (t) { rimraf.sync(p) t.end() }) node-graceful-fs-4.1.11/test/readdir-options.js000066400000000000000000000025251301511631400213360ustar00rootroot00000000000000var t = require("tap") var fs = require("fs") var currentTest var strings = ['b', 'z', 'a'] var buffs = strings.map(function (s) { return new Buffer(s) }) var hexes = buffs.map(function (b) { return b.toString('hex') }) function getRet (encoding) { switch (encoding) { case 'hex': return hexes case 'buffer': return buffs default: return strings } } var readdir = fs.readdir var failed = false fs.readdir = function(path, options, cb) { if (!failed) { // simulate an EMFILE and then open and close a thing to retry failed = true process.nextTick(function () { var er = new Error('synthetic emfile') er.code = 'EMFILE' cb(er) process.nextTick(function () { fs.closeSync(fs.openSync(__filename, 'r')) }) }) return } failed = false currentTest.isa(cb, 'function') currentTest.isa(options, 'object') currentTest.ok(options) process.nextTick(function() { var ret = getRet(options.encoding) cb(null, ret) }) } var g = require("../") var encodings = ['buffer', 'hex', 'utf8', null] encodings.forEach(function (enc) { t.test('encoding=' + enc, function (t) { currentTest = t g.readdir("whatevers", { encoding: enc }, function (er, files) { if (er) throw er t.same(files, getRet(enc).sort()) t.end() }) }) }) node-graceful-fs-4.1.11/test/readdir-sort.js000066400000000000000000000005731301511631400206330ustar00rootroot00000000000000var test = require("tap").test var fs = require("fs") 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 t.same(files, [ "a", "b", "z" ]) t.end() }) }) node-graceful-fs-4.1.11/test/readfile.js000066400000000000000000000016011301511631400200000ustar00rootroot00000000000000'use strict' var fs = require('../') var rimraf = require('rimraf') var mkdirp = require('mkdirp') var test = require('tap').test var p = require('path').resolve(__dirname, 'files') process.chdir(__dirname) // Make sure to reserve the stderr fd process.stderr.write('') var num = 4097 var paths = new Array(num) test('write files', function (t) { rimraf.sync(p) mkdirp.sync(p) t.plan(num) for (var i = 0; i < num; ++i) { paths[i] = 'files/file-' + i fs.writeFile(paths[i], 'content', 'ascii', function (er) { if (er) throw er t.pass('written') }) } }) test('read files', function (t) { // now read them t.plan(num) for (var i = 0; i < num; ++i) { fs.readFile(paths[i], 'ascii', function (er, data) { if (er) throw er t.equal(data, 'content') }) } }) test('cleanup', function (t) { rimraf.sync(p) t.end() }) node-graceful-fs-4.1.11/test/stats-uid-gid.js000066400000000000000000000021071301511631400207050ustar00rootroot00000000000000'use strict'; var test = require('tap').test var util = require('util') var fs = require('fs') // mock fs.statSync to return signed uids/gids var realStatSync = fs.statSync fs.statSync = function(path) { var stats = realStatSync.call(fs, path) stats.uid = -2 stats.gid = -2 return stats } var gfs = require('../graceful-fs.js') test('graceful fs uses same stats constructor as fs', function (t) { t.equal(gfs.Stats, fs.Stats, 'should reference the same constructor') if (!process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH) { t.equal(fs.statSync(__filename).uid, -2) t.equal(fs.statSync(__filename).gid, -2) } t.equal(gfs.statSync(__filename).uid, 0xfffffffe) t.equal(gfs.statSync(__filename).gid, 0xfffffffe) t.end() }) test('does not throw when async stat fails', function (t) { gfs.stat(__filename + ' this does not exist', function (er, stats) { t.ok(er) t.notOk(stats) t.end() }) }) test('throws ENOENT when sync stat fails', function (t) { t.throws(function() { gfs.statSync(__filename + ' this does not exist') }, /ENOENT/) t.end() }) node-graceful-fs-4.1.11/test/stats.js000066400000000000000000000006551301511631400173730ustar00rootroot00000000000000var test = require('tap').test var fs = require('fs') var gfs = require('../graceful-fs.js') test('graceful fs uses same stats constructor as fs', function (t) { t.equal(gfs.Stats, fs.Stats, 'should reference the same constructor') t.ok(fs.statSync(__filename) instanceof fs.Stats, 'should be instance of fs.Stats') t.ok(gfs.statSync(__filename) instanceof fs.Stats, 'should be instance of fs.Stats') t.end() }) node-graceful-fs-4.1.11/test/windows-rename-polyfill.js000066400000000000000000000012411301511631400230140ustar00rootroot00000000000000process.env.GRACEFUL_FS_PLATFORM = 'win32' var fs = require('fs') fs.rename = function (a, b, cb) { setTimeout(function () { var er = new Error('EPERM blerg') er.code = 'EPERM' cb(er) }) } var gfs = require('../') var t = require('tap') var a = __dirname + '/a' var b = __dirname + '/b' t.test('setup', function (t) { try { fs.mkdirSync(a) } catch (e) {} try { fs.mkdirSync(b) } catch (e) {} t.end() }) t.test('rename', { timeout: 100 }, function (t) { t.plan(1) gfs.rename(a, b, function (er) { t.ok(er) }) }) t.test('cleanup', function (t) { try { fs.rmdirSync(a) } catch (e) {} try { fs.rmdirSync(b) } catch (e) {} t.end() }) node-graceful-fs-4.1.11/test/write-then-read.js000066400000000000000000000014621301511631400212310ustar00rootroot00000000000000var fs = require('../'); var rimraf = require('rimraf'); var mkdirp = require('mkdirp'); var test = require('tap').test; var p = require('path').resolve(__dirname, 'files'); process.chdir(__dirname) // Make sure to reserve the stderr fd process.stderr.write(''); var num = 4097; var paths = new Array(num); test('make files', function (t) { rimraf.sync(p); mkdirp.sync(p); for (var i = 0; i < num; ++i) { paths[i] = 'files/file-' + i; fs.writeFileSync(paths[i], 'content'); } t.end(); }) test('read files', function (t) { // now read them t.plan(num) for (var i = 0; i < num; ++i) { fs.readFile(paths[i], 'ascii', function(err, data) { if (err) throw err; t.equal(data, 'content') }); } }); test('cleanup', function (t) { rimraf.sync(p); t.end(); });