diff --git a/node_modules/fstream/lib/abstract.js b/node_modules/fstream/lib/abstract.js index add48b9..5675d4a 100644 --- a/node_modules/fstream/lib/abstract.js +++ b/node_modules/fstream/lib/abstract.js @@ -20,6 +20,11 @@ Abstract.prototype.on = function (ev, fn) { return this } +Abstract.prototype.abort = function () { + this._aborted = true + this.emit("abort") +} + Abstract.prototype.destroy = function () {} Abstract.prototype.warn = function (msg, code) { diff --git a/node_modules/fstream/lib/dir-reader.js b/node_modules/fstream/lib/dir-reader.js index ab990d1..6a418c0 100644 --- a/node_modules/fstream/lib/dir-reader.js +++ b/node_modules/fstream/lib/dir-reader.js @@ -11,6 +11,7 @@ var fs = require("graceful-fs") , mkdir = require("mkdirp") , path = require("path") , Reader = require("./reader.js") + , assert = require("assert").ok inherits(DirReader, Reader) @@ -24,25 +25,42 @@ function DirReader (props) { throw new Error("Non-directory type "+ props.type) } - me._entries = null + me.entries = null me._index = -1 me._paused = false me._length = -1 + if (props.sort) { + this.sort = props.sort + } + Reader.call(this, props) } DirReader.prototype._getEntries = function () { var me = this + + // race condition. might pause() before calling _getEntries, + // and then resume, and try to get them a second time. + if (me._gotEntries) return + me._gotEntries = true + fs.readdir(me._path, function (er, entries) { if (er) return me.error(er) - me._entries = entries - me._length = entries.length - // console.error("DR %s sort =", me.path, me.props.sort) - if (typeof me.props.sort === "function") { - me._entries.sort(me.props.sort) + + me.entries = entries + + me.emit("entries", entries) + if (me._paused) me.once("resume", processEntries) + else processEntries() + + function processEntries () { + me._length = me.entries.length + if (typeof me.sort === "function") { + me.entries = me.entries.sort(me.sort.bind(me)) + } + me._read() } - me._read() }) } @@ -50,7 +68,7 @@ DirReader.prototype._getEntries = function () { DirReader.prototype._read = function () { var me = this - if (!me._entries) return me._getEntries() + if (!me.entries) return me._getEntries() if (me._paused || me._currentEntry || me._aborted) { // console.error("DR paused=%j, current=%j, aborted=%j", me._paused, !!me._currentEntry, me._aborted) @@ -58,7 +76,7 @@ DirReader.prototype._read = function () { } me._index ++ - if (me._index >= me._length) { + if (me._index >= me.entries.length) { if (!me._ended) { me._ended = true me.emit("end") @@ -70,20 +88,26 @@ DirReader.prototype._read = function () { // ok, handle this one, then. // save creating a proxy, by stat'ing the thing now. - var p = path.resolve(me._path, me._entries[me._index]) + var p = path.resolve(me._path, me.entries[me._index]) + assert(p !== me._path) + assert(me.entries[me._index]) + // set this to prevent trying to _read() again in the stat time. me._currentEntry = p fs[ me.props.follow ? "stat" : "lstat" ](p, function (er, stat) { if (er) return me.error(er) - var entry = Reader({ path: p - , depth: me.depth + 1 - , root: me.root || me._proxy || me - , parent: me._proxy || me - , follow: me.follow - , filter: me.filter - , sort: me.props.sort - }, stat) + var who = me._proxy || me + + stat.path = p + stat.basename = path.basename(p) + stat.dirname = path.dirname(p) + var childProps = me.getChildProps.call(who, stat) + childProps.path = p + childProps.basename = path.basename(p) + childProps.dirname = path.dirname(p) + + var entry = Reader(childProps, stat) // console.error("DR Entry", p, stat.size) @@ -94,17 +118,25 @@ DirReader.prototype._read = function () { // This nomenclature is not completely final. entry.on("pause", function (who) { - if (!me._paused) { + if (!me._paused && !entry._disowned) { me.pause(who) } }) entry.on("resume", function (who) { - if (me._paused) { + if (me._paused && !entry._disowned) { me.resume(who) } }) + entry.on("stat", function (props) { + me.emit("_entryStat", entry, props) + if (entry._aborted) return + if (entry._paused) entry.once("resume", function () { + me.emit("entryStat", entry, props) + }) + }) + entry.on("ready", function EMITCHILD () { // console.error("DR emit child", entry._path) if (me._paused) { @@ -122,23 +154,25 @@ DirReader.prototype._read = function () { if (entry.type === "Socket") { me.emit("socket", entry) } else { - me.emit("entry", entry) - me.emit("child", entry) + me.emitEntry(entry) } }) var ended = false entry.on("close", onend) + entry.on("disown", onend) function onend () { if (ended) return ended = true me.emit("childEnd", entry) me.emit("entryEnd", entry) me._currentEntry = null - me._read() + if (!me._paused) { + me._read() + } } - // XXX Make this work in node. + // XXX Remove this. Works in node as of 0.6.2 or so. // Long filenames should not break stuff. entry.on("error", function (er) { if (entry._swallowErrors) { @@ -160,6 +194,26 @@ DirReader.prototype._read = function () { }) } +DirReader.prototype.disown = function (entry) { + entry.emit("beforeDisown") + entry._disowned = true + entry.parent = entry.root = null + if (entry === this._currentEntry) { + this._currentEntry = null + } + entry.emit("disown") +} + +DirReader.prototype.getChildProps = function (stat) { + return { depth: this.depth + 1 + , root: this.root || this + , parent: this + , follow: this.follow + , filter: this.filter + , sort: this.props.sort + } +} + DirReader.prototype.pause = function (who) { var me = this if (me._paused) return @@ -185,8 +239,11 @@ DirReader.prototype.resume = function (who) { } if (me._currentEntry) { - if (me._currentEntry.resume) { - me._currentEntry.resume(who) - } + if (me._currentEntry.resume) me._currentEntry.resume(who) } else me._read() } + +DirReader.prototype.emitEntry = function (entry) { + this.emit("entry", entry) + this.emit("child", entry) +} diff --git a/node_modules/fstream/lib/dir-writer.js b/node_modules/fstream/lib/dir-writer.js index 26338bd..7073b88 100644 --- a/node_modules/fstream/lib/dir-writer.js +++ b/node_modules/fstream/lib/dir-writer.js @@ -100,7 +100,9 @@ DirWriter.prototype._process = function () { // don't allow recursive copying var p = entry do { - if (p._path === me.root._path || p._path === me._path) { + var pp = p._path || p.path + if (pp === me.root._path || pp === me._path || + (pp && pp.indexOf(me._path) === 0)) { // console.error("DW Exit (recursive)", entry.basename, me._path) me._processing = false if (entry._collected) entry.pipe() diff --git a/node_modules/fstream/lib/link-writer.js b/node_modules/fstream/lib/link-writer.js index 8a98163..5c8f1e7 100644 --- a/node_modules/fstream/lib/link-writer.js +++ b/node_modules/fstream/lib/link-writer.js @@ -4,7 +4,6 @@ module.exports = LinkWriter var fs = require("graceful-fs") , Writer = require("./writer.js") , inherits = require("inherits") - , collect = require("./collect.js") , path = require("path") , rimraf = require("rimraf") diff --git a/node_modules/fstream/lib/proxy-reader.js b/node_modules/fstream/lib/proxy-reader.js index f5ddfc3..a0ece34 100644 --- a/node_modules/fstream/lib/proxy-reader.js +++ b/node_modules/fstream/lib/proxy-reader.js @@ -63,6 +63,7 @@ ProxyReader.prototype._addProxy = function (proxy) { , "child" , "childEnd" , "warn" + , "stat" ].forEach(function (ev) { // console.error("~~ proxy event", ev, me.path) proxy.on(ev, me.emit.bind(me, ev)) diff --git a/node_modules/fstream/lib/reader.js b/node_modules/fstream/lib/reader.js index 6aa67ad..e4e1b48 100644 --- a/node_modules/fstream/lib/reader.js +++ b/node_modules/fstream/lib/reader.js @@ -187,19 +187,38 @@ Reader.prototype._stat = function (currentStat) { // if the filter doesn't pass, then just skip over this one. // still have to emit end so that dir-walking can move on. if (me.filter) { + var who = me._proxy || me // special handling for ProxyReaders - if (!me.filter.call(me._proxy || me)) { - me._aborted = true - me.emit("end") - me.emit("close") + if (!me.filter.call(who, who, props)) { + if (!me._disowned) { + me.abort() + me.emit("end") + me.emit("close") + } return } } - me.emit("ready", props) + // last chance to abort or disown before the flow starts! + var events = ["_stat", "stat", "ready"] + var e = 0 + ;(function go () { + if (me._aborted) { + me.emit("end") + me.emit("close") + return + } - // if it's a directory, then we'll be emitting "entry" events. - me._read() + if (me._paused) { + me.once("resume", go) + return + } + + var ev = events[e ++] + if (!ev) return me._read() + me.emit(ev, props) + go() + })() } } diff --git a/node_modules/fstream/lib/writer.js b/node_modules/fstream/lib/writer.js index b7cd261..243f6b6 100644 --- a/node_modules/fstream/lib/writer.js +++ b/node_modules/fstream/lib/writer.js @@ -123,12 +123,13 @@ Writer.prototype._stat = function (current) { var me = this , props = me.props , stat = props.follow ? "stat" : "lstat" + , who = me._proxy || me if (current) statCb(null, current) else fs[stat](me._path, statCb) function statCb (er, current) { - if (me.filter && !me.filter.call(me._proxy || me, current)) { + if (me.filter && !me.filter.call(who, who, current)) { me._aborted = true me.emit("end") me.emit("close") @@ -165,13 +166,83 @@ function create (me) { // XXX Need to clobber non-dirs that are in the way, // unless { clobber: false } in the props. - mkdir(path.dirname(me._path), Writer.dirmode, function (er) { + mkdir(path.dirname(me._path), Writer.dirmode, function (er, made) { // console.error("W created", path.dirname(me._path), er) if (er) return me.error(er) - me._create() + + // later on, we have to set the mode and owner for these + me._madeDir = made + return me._create() }) } +function endChmod (me, want, current, path, cb) { + var wantMode = want.mode + , chmod = want.follow || me.type !== "SymbolicLink" + ? "chmod" : "lchmod" + + if (!fs[chmod]) return cb() + if (typeof wantMode !== "number") return cb() + + var curMode = current.mode & 0777 + wantMode = wantMode & 0777 + if (wantMode === curMode) return cb() + + fs[chmod](path, wantMode, cb) +} + + +function endChown (me, want, current, path, cb) { + // Don't even try it unless root. Too easy to EPERM. + if (process.platform === "win32") return cb() + if (!process.getuid || !process.getuid() === 0) return cb() + if (typeof want.uid !== "number" && + typeof want.gid !== "number" ) return cb() + + if (current.uid === want.uid && + current.gid === want.gid) return cb() + + var chown = (me.props.follow || me.type !== "SymbolicLink") + ? "chown" : "lchown" + if (!fs[chown]) return cb() + + if (typeof want.uid !== "number") want.uid = current.uid + if (typeof want.gid !== "number") want.gid = current.gid + + fs[chown](path, want.uid, want.gid, cb) +} + +function endUtimes (me, want, current, path, cb) { + if (!fs.utimes || process.platform === "win32") return cb() + + var utimes = (want.follow || me.type !== "SymbolicLink") + ? "utimes" : "lutimes" + + if (utimes === "lutimes" && !fs[utimes]) { + utimes = "utimes" + } + + if (!fs[utimes]) return cb() + + var curA = current.atime + , curM = current.mtime + , meA = want.atime + , meM = want.mtime + + if (meA === undefined) meA = curA + if (meM === undefined) meM = curM + + if (!isDate(meA)) meA = new Date(meA) + if (!isDate(meM)) meA = new Date(meM) + + if (meA.getTime() === curA.getTime() && + meM.getTime() === curM.getTime()) return cb() + + fs[utimes](path, meA, meM, cb) +} + + +// XXX This function is beastly. Break it up! Writer.prototype._finish = function () { var me = this @@ -219,88 +290,82 @@ Writer.prototype._finish = function () { return function setProps (current) { - // console.error(" W setprops", me._path) - // mode - var wantMode = me.props.mode - , chmod = me.props.follow || me.type !== "SymbolicLink" - ? "chmod" : "lchmod" - - if (fs[chmod] && typeof wantMode === "number") { - wantMode = wantMode & 0777 - todo ++ - // console.error(" W chmod", wantMode.toString(8), me.basename, "\r") - fs[chmod](me._path, wantMode, next(chmod)) - } - - // uid, gid - // Don't even try it unless root. Too easy to EPERM. - if (process.platform !== "win32" && - process.getuid && process.getuid() === 0 && - ( typeof me.props.uid === "number" || - typeof me.props.gid === "number" )) { - var chown = (me.props.follow || me.type !== "SymbolicLink") - ? "chown" : "lchown" - if (fs[chown]) { - if (typeof me.props.uid !== "number") me.props.uid = current.uid - if (typeof me.props.gid !== "number") me.props.gid = current.gid - if (me.props.uid !== current.uid || me.props.gid !== current.gid) { - todo ++ - // console.error(" W chown", me.props.uid, me.props.gid, me.basename) - fs[chown](me._path, me.props.uid, me.props.gid, next("chown")) - } - } - } - - // atime, mtime. - if (fs.utimes && process.platform !== "win32") { - var utimes = (me.props.follow || me.type !== "SymbolicLink") - ? "utimes" : "lutimes" - - if (utimes === "lutimes" && !fs[utimes]) { - utimes = "utimes" - } - - var curA = current.atime - , curM = current.mtime - , meA = me.props.atime - , meM = me.props.mtime - - if (meA === undefined) meA = curA - if (meM === undefined) meM = curM - - if (!isDate(meA)) meA = new Date(meA) - if (!isDate(meM)) meA = new Date(meM) - - if (meA.getTime() !== curA.getTime() || - meM.getTime() !== curM.getTime()) { - todo ++ - // console.error(" W utimes", meA, meM, me.basename) - fs[utimes](me._path, meA, meM, next("utimes")) - } - } - - // finally, handle the case if there was nothing to do. - if (todo === 0) { - // console.error(" W nothing to do", me.basename) - next("nothing to do")() - } + endChmod(me, me.props, current, me._path, next("chmod")) + endChown(me, me.props, current, me._path, next("chown")) + endUtimes(me, me.props, current, me._path, next("chown")) } - function next (what) { return function (er) { - // console.error(" W Finish", what, todo) - if (errState) return - if (er) { - er.fstream_finish_call = what - return me.error(errState = er) - } - if (--todo > 0) return - if (done) return - done = true + function next (what) { + todo ++ + return function (er) { + // console.error(" W Finish", what, todo) + if (errState) return + if (er) { + er.fstream_finish_call = what + return me.error(errState = er) + } + if (--todo > 0) return + if (done) return + done = true - // all the props have been set, so we're completely done. - me.emit("end") - me.emit("close") - }} + // we may still need to set the mode/etc. on some parent dirs + // that were created previously. delay end/close until then. + if (!me._madeDir) return end() + else endMadeDir(me, me._path, end) + + function end (er) { + if (er) { + er.fstream_finish_call = "setupMadeDir" + return me.error(er) + } + // all the props have been set, so we're completely done. + me.emit("end") + me.emit("close") + } + } + } +} + +function endMadeDir (me, p, cb) { + var made = me._madeDir + // everything *between* made and path.dirname(me._path) + // needs to be set up. Note that this may just be one dir. + var d = path.dirname(p) + + endMadeDir_(me, d, function (er) { + if (er) return cb(er) + if (d === made) { + return cb() + } + endMadeDir(me, d, cb) + }) +} + +function endMadeDir_ (me, p, cb) { + var dirProps = {} + Object.keys(me.props).forEach(function (k) { + dirProps[k] = me.props[k] + + // only make non-readable dirs if explicitly requested. + if (k === "mode" && me.type !== "Directory") { + dirProps[k] = dirProps[k] | 0111 + } + }) + + var todo = 3 + , errState = null + fs.stat(p, function (er, current) { + if (er) return cb(errState = er) + endChmod(me, dirProps, current, p, next) + endChown(me, dirProps, current, p, next) + endUtimes(me, dirProps, current, p, next) + }) + + function next (er) { + if (errState) return + if (er) return cb(errState = er) + if (-- todo === 0) return cb() + } } Writer.prototype.pipe = function () { diff --git a/node_modules/fstream/node_modules/inherits/package.json b/node_modules/fstream/node_modules/inherits/package.json index da2ff93..5d16866 100644 --- a/node_modules/fstream/node_modules/inherits/package.json +++ b/node_modules/fstream/node_modules/inherits/package.json @@ -31,8 +31,8 @@ "node": "*" }, "_engineSupported": true, - "_npmVersion": "1.1.10", - "_nodeVersion": "v0.6.13", + "_npmVersion": "1.1.18", + "_nodeVersion": "v0.6.18", "_defaultsLoaded": true, "_from": "inherits@~1.0.0" } diff --git a/node_modules/fstream/package.json b/node_modules/fstream/package.json index 9882a60..df5cff3 100644 --- a/node_modules/fstream/package.json +++ b/node_modules/fstream/package.json @@ -6,7 +6,7 @@ }, "name": "fstream", "description": "Advanced file system stream things", - "version": "0.1.14", + "version": "0.1.18", "repository": { "type": "git", "url": "git://github.com/isaacs/fstream.git" @@ -32,11 +32,14 @@ "name": "tootallnate", "email": "nathan@tootallnate.net" }, - "_id": "fstream@0.1.14", + "_id": "fstream@0.1.18", "optionalDependencies": {}, "_engineSupported": true, - "_npmVersion": "1.1.10", - "_nodeVersion": "v0.6.13", + "_npmVersion": "1.1.18", + "_nodeVersion": "v0.6.18", "_defaultsLoaded": true, + "dist": { + "shasum": "eb42721022505a2197b1f6dadf517189a5f63522" + }, "_from": "fstream@~0.1.13" }