| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252 | 
							- // A thing that emits "entry" events with Reader objects
 
- // Pausing it causes it to stop emitting entry events, and also
 
- // pauses the current entry if there is one.
 
- module.exports = DirReader
 
- var fs = require('graceful-fs')
 
- var inherits = require('inherits')
 
- var path = require('path')
 
- var Reader = require('./reader.js')
 
- var assert = require('assert').ok
 
- inherits(DirReader, Reader)
 
- function DirReader (props) {
 
-   var self = this
 
-   if (!(self instanceof DirReader)) {
 
-     throw new Error('DirReader must be called as constructor.')
 
-   }
 
-   // should already be established as a Directory type
 
-   if (props.type !== 'Directory' || !props.Directory) {
 
-     throw new Error('Non-directory type ' + props.type)
 
-   }
 
-   self.entries = null
 
-   self._index = -1
 
-   self._paused = false
 
-   self._length = -1
 
-   if (props.sort) {
 
-     this.sort = props.sort
 
-   }
 
-   Reader.call(this, props)
 
- }
 
- DirReader.prototype._getEntries = function () {
 
-   var self = this
 
-   // race condition.  might pause() before calling _getEntries,
 
-   // and then resume, and try to get them a second time.
 
-   if (self._gotEntries) return
 
-   self._gotEntries = true
 
-   fs.readdir(self._path, function (er, entries) {
 
-     if (er) return self.error(er)
 
-     self.entries = entries
 
-     self.emit('entries', entries)
 
-     if (self._paused) self.once('resume', processEntries)
 
-     else processEntries()
 
-     function processEntries () {
 
-       self._length = self.entries.length
 
-       if (typeof self.sort === 'function') {
 
-         self.entries = self.entries.sort(self.sort.bind(self))
 
-       }
 
-       self._read()
 
-     }
 
-   })
 
- }
 
- // start walking the dir, and emit an "entry" event for each one.
 
- DirReader.prototype._read = function () {
 
-   var self = this
 
-   if (!self.entries) return self._getEntries()
 
-   if (self._paused || self._currentEntry || self._aborted) {
 
-     // console.error('DR paused=%j, current=%j, aborted=%j', self._paused, !!self._currentEntry, self._aborted)
 
-     return
 
-   }
 
-   self._index++
 
-   if (self._index >= self.entries.length) {
 
-     if (!self._ended) {
 
-       self._ended = true
 
-       self.emit('end')
 
-       self.emit('close')
 
-     }
 
-     return
 
-   }
 
-   // ok, handle this one, then.
 
-   // save creating a proxy, by stat'ing the thing now.
 
-   var p = path.resolve(self._path, self.entries[self._index])
 
-   assert(p !== self._path)
 
-   assert(self.entries[self._index])
 
-   // set this to prevent trying to _read() again in the stat time.
 
-   self._currentEntry = p
 
-   fs[ self.props.follow ? 'stat' : 'lstat' ](p, function (er, stat) {
 
-     if (er) return self.error(er)
 
-     var who = self._proxy || self
 
-     stat.path = p
 
-     stat.basename = path.basename(p)
 
-     stat.dirname = path.dirname(p)
 
-     var childProps = self.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)
 
-     self._currentEntry = entry
 
-     // "entry" events are for direct entries in a specific dir.
 
-     // "child" events are for any and all children at all levels.
 
-     // This nomenclature is not completely final.
 
-     entry.on('pause', function (who) {
 
-       if (!self._paused && !entry._disowned) {
 
-         self.pause(who)
 
-       }
 
-     })
 
-     entry.on('resume', function (who) {
 
-       if (self._paused && !entry._disowned) {
 
-         self.resume(who)
 
-       }
 
-     })
 
-     entry.on('stat', function (props) {
 
-       self.emit('_entryStat', entry, props)
 
-       if (entry._aborted) return
 
-       if (entry._paused) {
 
-         entry.once('resume', function () {
 
-           self.emit('entryStat', entry, props)
 
-         })
 
-       } else self.emit('entryStat', entry, props)
 
-     })
 
-     entry.on('ready', function EMITCHILD () {
 
-       // console.error("DR emit child", entry._path)
 
-       if (self._paused) {
 
-         // console.error("  DR emit child - try again later")
 
-         // pause the child, and emit the "entry" event once we drain.
 
-         // console.error("DR pausing child entry")
 
-         entry.pause(self)
 
-         return self.once('resume', EMITCHILD)
 
-       }
 
-       // skip over sockets.  they can't be piped around properly,
 
-       // so there's really no sense even acknowledging them.
 
-       // if someone really wants to see them, they can listen to
 
-       // the "socket" events.
 
-       if (entry.type === 'Socket') {
 
-         self.emit('socket', entry)
 
-       } else {
 
-         self.emitEntry(entry)
 
-       }
 
-     })
 
-     var ended = false
 
-     entry.on('close', onend)
 
-     entry.on('disown', onend)
 
-     function onend () {
 
-       if (ended) return
 
-       ended = true
 
-       self.emit('childEnd', entry)
 
-       self.emit('entryEnd', entry)
 
-       self._currentEntry = null
 
-       if (!self._paused) {
 
-         self._read()
 
-       }
 
-     }
 
-     // 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) {
 
-         self.warn(er)
 
-         entry.emit('end')
 
-         entry.emit('close')
 
-       } else {
 
-         self.emit('error', er)
 
-       }
 
-     })
 
-     // proxy up some events.
 
-     ;[
 
-       'child',
 
-       'childEnd',
 
-       'warn'
 
-     ].forEach(function (ev) {
 
-       entry.on(ev, self.emit.bind(self, ev))
 
-     })
 
-   })
 
- }
 
- 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 () {
 
-   return {
 
-     depth: this.depth + 1,
 
-     root: this.root || this,
 
-     parent: this,
 
-     follow: this.follow,
 
-     filter: this.filter,
 
-     sort: this.props.sort,
 
-     hardlinks: this.props.hardlinks
 
-   }
 
- }
 
- DirReader.prototype.pause = function (who) {
 
-   var self = this
 
-   if (self._paused) return
 
-   who = who || self
 
-   self._paused = true
 
-   if (self._currentEntry && self._currentEntry.pause) {
 
-     self._currentEntry.pause(who)
 
-   }
 
-   self.emit('pause', who)
 
- }
 
- DirReader.prototype.resume = function (who) {
 
-   var self = this
 
-   if (!self._paused) return
 
-   who = who || self
 
-   self._paused = false
 
-   // console.error('DR Emit Resume', self._path)
 
-   self.emit('resume', who)
 
-   if (self._paused) {
 
-     // console.error('DR Re-paused', self._path)
 
-     return
 
-   }
 
-   if (self._currentEntry) {
 
-     if (self._currentEntry.resume) self._currentEntry.resume(who)
 
-   } else self._read()
 
- }
 
- DirReader.prototype.emitEntry = function (entry) {
 
-   this.emit('entry', entry)
 
-   this.emit('child', entry)
 
- }
 
 
  |