summaryrefslogtreecommitdiff
path: root/deps/npm/node_modules/fstream/lib/reader.js
diff options
context:
space:
mode:
Diffstat (limited to 'deps/npm/node_modules/fstream/lib/reader.js')
-rw-r--r--deps/npm/node_modules/fstream/lib/reader.js255
1 files changed, 255 insertions, 0 deletions
diff --git a/deps/npm/node_modules/fstream/lib/reader.js b/deps/npm/node_modules/fstream/lib/reader.js
new file mode 100644
index 0000000000..be4f570eeb
--- /dev/null
+++ b/deps/npm/node_modules/fstream/lib/reader.js
@@ -0,0 +1,255 @@
+module.exports = Reader
+
+var fs = require('graceful-fs')
+var Stream = require('stream').Stream
+var inherits = require('inherits')
+var path = require('path')
+var getType = require('./get-type.js')
+var hardLinks = Reader.hardLinks = {}
+var Abstract = require('./abstract.js')
+
+// Must do this *before* loading the child classes
+inherits(Reader, Abstract)
+
+var LinkReader = require('./link-reader.js')
+
+function Reader (props, currentStat) {
+ var self = this
+ if (!(self instanceof Reader)) return new Reader(props, currentStat)
+
+ if (typeof props === 'string') {
+ props = { path: props }
+ }
+
+ // polymorphism.
+ // call fstream.Reader(dir) to get a DirReader object, etc.
+ // Note that, unlike in the Writer case, ProxyReader is going
+ // to be the *normal* state of affairs, since we rarely know
+ // the type of a file prior to reading it.
+
+ var type
+ var ClassType
+
+ if (props.type && typeof props.type === 'function') {
+ type = props.type
+ ClassType = type
+ } else {
+ type = getType(props)
+ ClassType = Reader
+ }
+
+ if (currentStat && !type) {
+ type = getType(currentStat)
+ props[type] = true
+ props.type = type
+ }
+
+ switch (type) {
+ case 'Directory':
+ ClassType = require('./dir-reader.js')
+ break
+
+ case 'Link':
+ // XXX hard links are just files.
+ // However, it would be good to keep track of files' dev+inode
+ // and nlink values, and create a HardLinkReader that emits
+ // a linkpath value of the original copy, so that the tar
+ // writer can preserve them.
+ // ClassType = HardLinkReader
+ // break
+
+ case 'File':
+ ClassType = require('./file-reader.js')
+ break
+
+ case 'SymbolicLink':
+ ClassType = LinkReader
+ break
+
+ case 'Socket':
+ ClassType = require('./socket-reader.js')
+ break
+
+ case null:
+ ClassType = require('./proxy-reader.js')
+ break
+ }
+
+ if (!(self instanceof ClassType)) {
+ return new ClassType(props)
+ }
+
+ Abstract.call(self)
+
+ if (!props.path) {
+ self.error('Must provide a path', null, true)
+ }
+
+ self.readable = true
+ self.writable = false
+
+ self.type = type
+ self.props = props
+ self.depth = props.depth = props.depth || 0
+ self.parent = props.parent || null
+ self.root = props.root || (props.parent && props.parent.root) || self
+
+ self._path = self.path = path.resolve(props.path)
+ if (process.platform === 'win32') {
+ self.path = self._path = self.path.replace(/\?/g, '_')
+ if (self._path.length >= 260) {
+ // how DOES one create files on the moon?
+ // if the path has spaces in it, then UNC will fail.
+ self._swallowErrors = true
+ // if (self._path.indexOf(" ") === -1) {
+ self._path = '\\\\?\\' + self.path.replace(/\//g, '\\')
+ // }
+ }
+ }
+ self.basename = props.basename = path.basename(self.path)
+ self.dirname = props.dirname = path.dirname(self.path)
+
+ // these have served their purpose, and are now just noisy clutter
+ props.parent = props.root = null
+
+ // console.error("\n\n\n%s setting size to", props.path, props.size)
+ self.size = props.size
+ self.filter = typeof props.filter === 'function' ? props.filter : null
+ if (props.sort === 'alpha') props.sort = alphasort
+
+ // start the ball rolling.
+ // this will stat the thing, and then call self._read()
+ // to start reading whatever it is.
+ // console.error("calling stat", props.path, currentStat)
+ self._stat(currentStat)
+}
+
+function alphasort (a, b) {
+ return a === b ? 0
+ : a.toLowerCase() > b.toLowerCase() ? 1
+ : a.toLowerCase() < b.toLowerCase() ? -1
+ : a > b ? 1
+ : -1
+}
+
+Reader.prototype._stat = function (currentStat) {
+ var self = this
+ var props = self.props
+ var stat = props.follow ? 'stat' : 'lstat'
+ // console.error("Reader._stat", self._path, currentStat)
+ if (currentStat) process.nextTick(statCb.bind(null, null, currentStat))
+ else fs[stat](self._path, statCb)
+
+ function statCb (er, props_) {
+ // console.error("Reader._stat, statCb", self._path, props_, props_.nlink)
+ if (er) return self.error(er)
+
+ Object.keys(props_).forEach(function (k) {
+ props[k] = props_[k]
+ })
+
+ // if it's not the expected size, then abort here.
+ if (undefined !== self.size && props.size !== self.size) {
+ return self.error('incorrect size')
+ }
+ self.size = props.size
+
+ var type = getType(props)
+ var handleHardlinks = props.hardlinks !== false
+
+ // special little thing for handling hardlinks.
+ if (handleHardlinks && type !== 'Directory' && props.nlink && props.nlink > 1) {
+ var k = props.dev + ':' + props.ino
+ // console.error("Reader has nlink", self._path, k)
+ if (hardLinks[k] === self._path || !hardLinks[k]) {
+ hardLinks[k] = self._path
+ } else {
+ // switch into hardlink mode.
+ type = self.type = self.props.type = 'Link'
+ self.Link = self.props.Link = true
+ self.linkpath = self.props.linkpath = hardLinks[k]
+ // console.error("Hardlink detected, switching mode", self._path, self.linkpath)
+ // Setting __proto__ would arguably be the "correct"
+ // approach here, but that just seems too wrong.
+ self._stat = self._read = LinkReader.prototype._read
+ }
+ }
+
+ if (self.type && self.type !== type) {
+ self.error('Unexpected type: ' + type)
+ }
+
+ // 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 (self.filter) {
+ var who = self._proxy || self
+ // special handling for ProxyReaders
+ if (!self.filter.call(who, who, props)) {
+ if (!self._disowned) {
+ self.abort()
+ self.emit('end')
+ self.emit('close')
+ }
+ return
+ }
+ }
+
+ // last chance to abort or disown before the flow starts!
+ var events = ['_stat', 'stat', 'ready']
+ var e = 0
+ ;(function go () {
+ if (self._aborted) {
+ self.emit('end')
+ self.emit('close')
+ return
+ }
+
+ if (self._paused && self.type !== 'Directory') {
+ self.once('resume', go)
+ return
+ }
+
+ var ev = events[e++]
+ if (!ev) {
+ return self._read()
+ }
+ self.emit(ev, props)
+ go()
+ })()
+ }
+}
+
+Reader.prototype.pipe = function (dest) {
+ var self = this
+ if (typeof dest.add === 'function') {
+ // piping to a multi-compatible, and we've got directory entries.
+ self.on('entry', function (entry) {
+ var ret = dest.add(entry)
+ if (ret === false) {
+ self.pause()
+ }
+ })
+ }
+
+ // console.error("R Pipe apply Stream Pipe")
+ return Stream.prototype.pipe.apply(this, arguments)
+}
+
+Reader.prototype.pause = function (who) {
+ this._paused = true
+ who = who || this
+ this.emit('pause', who)
+ if (this._stream) this._stream.pause(who)
+}
+
+Reader.prototype.resume = function (who) {
+ this._paused = false
+ who = who || this
+ this.emit('resume', who)
+ if (this._stream) this._stream.resume(who)
+ this._read()
+}
+
+Reader.prototype._read = function () {
+ this.error('Cannot read unknown type: ' + this.type)
+}