You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					391 lines
				
				11 KiB
			
		
		
			
		
	
	
					391 lines
				
				11 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								module.exports = Writer
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var fs = require('graceful-fs')
							 | 
						||
| 
								 | 
							
								var inherits = require('inherits')
							 | 
						||
| 
								 | 
							
								var rimraf = require('rimraf')
							 | 
						||
| 
								 | 
							
								var mkdir = require('mkdirp')
							 | 
						||
| 
								 | 
							
								var path = require('path')
							 | 
						||
| 
								 | 
							
								var umask = process.platform === 'win32' ? 0 : process.umask()
							 | 
						||
| 
								 | 
							
								var getType = require('./get-type.js')
							 | 
						||
| 
								 | 
							
								var Abstract = require('./abstract.js')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Must do this *before* loading the child classes
							 | 
						||
| 
								 | 
							
								inherits(Writer, Abstract)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Writer.dirmode = parseInt('0777', 8) & (~umask)
							 | 
						||
| 
								 | 
							
								Writer.filemode = parseInt('0666', 8) & (~umask)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var DirWriter = require('./dir-writer.js')
							 | 
						||
| 
								 | 
							
								var LinkWriter = require('./link-writer.js')
							 | 
						||
| 
								 | 
							
								var FileWriter = require('./file-writer.js')
							 | 
						||
| 
								 | 
							
								var ProxyWriter = require('./proxy-writer.js')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// props is the desired state.  current is optionally the current stat,
							 | 
						||
| 
								 | 
							
								// provided here so that subclasses can avoid statting the target
							 | 
						||
| 
								 | 
							
								// more than necessary.
							 | 
						||
| 
								 | 
							
								function Writer (props, current) {
							 | 
						||
| 
								 | 
							
								  var self = this
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (typeof props === 'string') {
							 | 
						||
| 
								 | 
							
								    props = { path: props }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // polymorphism.
							 | 
						||
| 
								 | 
							
								  // call fstream.Writer(dir) to get a DirWriter object, etc.
							 | 
						||
| 
								 | 
							
								  var type = getType(props)
							 | 
						||
| 
								 | 
							
								  var ClassType = Writer
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  switch (type) {
							 | 
						||
| 
								 | 
							
								    case 'Directory':
							 | 
						||
| 
								 | 
							
								      ClassType = DirWriter
							 | 
						||
| 
								 | 
							
								      break
							 | 
						||
| 
								 | 
							
								    case 'File':
							 | 
						||
| 
								 | 
							
								      ClassType = FileWriter
							 | 
						||
| 
								 | 
							
								      break
							 | 
						||
| 
								 | 
							
								    case 'Link':
							 | 
						||
| 
								 | 
							
								    case 'SymbolicLink':
							 | 
						||
| 
								 | 
							
								      ClassType = LinkWriter
							 | 
						||
| 
								 | 
							
								      break
							 | 
						||
| 
								 | 
							
								    case null:
							 | 
						||
| 
								 | 
							
								    default:
							 | 
						||
| 
								 | 
							
								      // Don't know yet what type to create, so we wrap in a proxy.
							 | 
						||
| 
								 | 
							
								      ClassType = ProxyWriter
							 | 
						||
| 
								 | 
							
								      break
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (!(self instanceof ClassType)) return new ClassType(props)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // now get down to business.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  Abstract.call(self)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (!props.path) self.error('Must provide a path', null, true)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // props is what we want to set.
							 | 
						||
| 
								 | 
							
								  // set some convenience properties as well.
							 | 
						||
| 
								 | 
							
								  self.type = props.type
							 | 
						||
| 
								 | 
							
								  self.props = props
							 | 
						||
| 
								 | 
							
								  self.depth = props.depth || 0
							 | 
						||
| 
								 | 
							
								  self.clobber = props.clobber === false ? props.clobber : true
							 | 
						||
| 
								 | 
							
								  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) {
							 | 
						||
| 
								 | 
							
								      self._swallowErrors = true
							 | 
						||
| 
								 | 
							
								      self._path = '\\\\?\\' + self.path.replace(/\//g, '\\')
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  self.basename = path.basename(props.path)
							 | 
						||
| 
								 | 
							
								  self.dirname = path.dirname(props.path)
							 | 
						||
| 
								 | 
							
								  self.linkpath = props.linkpath || null
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  props.parent = props.root = null
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // console.error("\n\n\n%s setting size to", props.path, props.size)
							 | 
						||
| 
								 | 
							
								  self.size = props.size
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (typeof props.mode === 'string') {
							 | 
						||
| 
								 | 
							
								    props.mode = parseInt(props.mode, 8)
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  self.readable = false
							 | 
						||
| 
								 | 
							
								  self.writable = true
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // buffer until ready, or while handling another entry
							 | 
						||
| 
								 | 
							
								  self._buffer = []
							 | 
						||
| 
								 | 
							
								  self.ready = false
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  self.filter = typeof props.filter === 'function' ? props.filter : null
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // start the ball rolling.
							 | 
						||
| 
								 | 
							
								  // this checks what's there already, and then calls
							 | 
						||
| 
								 | 
							
								  // self._create() to call the impl-specific creation stuff.
							 | 
						||
| 
								 | 
							
								  self._stat(current)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// Calling this means that it's something we can't create.
							 | 
						||
| 
								 | 
							
								// Just assert that it's already there, otherwise raise a warning.
							 | 
						||
| 
								 | 
							
								Writer.prototype._create = function () {
							 | 
						||
| 
								 | 
							
								  var self = this
							 | 
						||
| 
								 | 
							
								  fs[self.props.follow ? 'stat' : 'lstat'](self._path, function (er) {
							 | 
						||
| 
								 | 
							
								    if (er) {
							 | 
						||
| 
								 | 
							
								      return self.warn('Cannot create ' + self._path + '\n' +
							 | 
						||
| 
								 | 
							
								        'Unsupported type: ' + self.type, 'ENOTSUP')
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    self._finish()
							 | 
						||
| 
								 | 
							
								  })
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Writer.prototype._stat = function (current) {
							 | 
						||
| 
								 | 
							
								  var self = this
							 | 
						||
| 
								 | 
							
								  var props = self.props
							 | 
						||
| 
								 | 
							
								  var stat = props.follow ? 'stat' : 'lstat'
							 | 
						||
| 
								 | 
							
								  var who = self._proxy || self
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (current) statCb(null, current)
							 | 
						||
| 
								 | 
							
								  else fs[stat](self._path, statCb)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function statCb (er, current) {
							 | 
						||
| 
								 | 
							
								    if (self.filter && !self.filter.call(who, who, current)) {
							 | 
						||
| 
								 | 
							
								      self._aborted = true
							 | 
						||
| 
								 | 
							
								      self.emit('end')
							 | 
						||
| 
								 | 
							
								      self.emit('close')
							 | 
						||
| 
								 | 
							
								      return
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // if it's not there, great.  We'll just create it.
							 | 
						||
| 
								 | 
							
								    // if it is there, then we'll need to change whatever differs
							 | 
						||
| 
								 | 
							
								    if (er || !current) {
							 | 
						||
| 
								 | 
							
								      return create(self)
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    self._old = current
							 | 
						||
| 
								 | 
							
								    var currentType = getType(current)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // if it's a type change, then we need to clobber or error.
							 | 
						||
| 
								 | 
							
								    // if it's not a type change, then let the impl take care of it.
							 | 
						||
| 
								 | 
							
								    if (currentType !== self.type || self.type === 'File' && current.nlink > 1) {
							 | 
						||
| 
								 | 
							
								      return rimraf(self._path, function (er) {
							 | 
						||
| 
								 | 
							
								        if (er) return self.error(er)
							 | 
						||
| 
								 | 
							
								        self._old = null
							 | 
						||
| 
								 | 
							
								        create(self)
							 | 
						||
| 
								 | 
							
								      })
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // otherwise, just handle in the app-specific way
							 | 
						||
| 
								 | 
							
								    // this creates a fs.WriteStream, or mkdir's, or whatever
							 | 
						||
| 
								 | 
							
								    create(self)
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function create (self) {
							 | 
						||
| 
								 | 
							
								  // console.error("W create", self._path, Writer.dirmode)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // XXX Need to clobber non-dirs that are in the way,
							 | 
						||
| 
								 | 
							
								  // unless { clobber: false } in the props.
							 | 
						||
| 
								 | 
							
								  mkdir(path.dirname(self._path), Writer.dirmode, function (er, made) {
							 | 
						||
| 
								 | 
							
								    // console.error("W created", path.dirname(self._path), er)
							 | 
						||
| 
								 | 
							
								    if (er) return self.error(er)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // later on, we have to set the mode and owner for these
							 | 
						||
| 
								 | 
							
								    self._madeDir = made
							 | 
						||
| 
								 | 
							
								    return self._create()
							 | 
						||
| 
								 | 
							
								  })
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function endChmod (self, want, current, path, cb) {
							 | 
						||
| 
								 | 
							
								  var wantMode = want.mode
							 | 
						||
| 
								 | 
							
								  var chmod = want.follow || self.type !== 'SymbolicLink'
							 | 
						||
| 
								 | 
							
								    ? 'chmod' : 'lchmod'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (!fs[chmod]) return cb()
							 | 
						||
| 
								 | 
							
								  if (typeof wantMode !== 'number') return cb()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var curMode = current.mode & parseInt('0777', 8)
							 | 
						||
| 
								 | 
							
								  wantMode = wantMode & parseInt('0777', 8)
							 | 
						||
| 
								 | 
							
								  if (wantMode === curMode) return cb()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  fs[chmod](path, wantMode, cb)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function endChown (self, 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 = (self.props.follow || self.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 (self, want, current, path, cb) {
							 | 
						||
| 
								 | 
							
								  if (!fs.utimes || process.platform === 'win32') return cb()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var utimes = (want.follow || self.type !== 'SymbolicLink')
							 | 
						||
| 
								 | 
							
								    ? 'utimes' : 'lutimes'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (utimes === 'lutimes' && !fs[utimes]) {
							 | 
						||
| 
								 | 
							
								    utimes = 'utimes'
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (!fs[utimes]) return cb()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var curA = current.atime
							 | 
						||
| 
								 | 
							
								  var curM = current.mtime
							 | 
						||
| 
								 | 
							
								  var meA = want.atime
							 | 
						||
| 
								 | 
							
								  var 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 self = this
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (self._finishing) return
							 | 
						||
| 
								 | 
							
								  self._finishing = true
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // console.error(" W Finish", self._path, self.size)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  // set up all the things.
							 | 
						||
| 
								 | 
							
								  // At this point, we're already done writing whatever we've gotta write,
							 | 
						||
| 
								 | 
							
								  // adding files to the dir, etc.
							 | 
						||
| 
								 | 
							
								  var todo = 0
							 | 
						||
| 
								 | 
							
								  var errState = null
							 | 
						||
| 
								 | 
							
								  var done = false
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  if (self._old) {
							 | 
						||
| 
								 | 
							
								    // the times will almost *certainly* have changed.
							 | 
						||
| 
								 | 
							
								    // adds the utimes syscall, but remove another stat.
							 | 
						||
| 
								 | 
							
								    self._old.atime = new Date(0)
							 | 
						||
| 
								 | 
							
								    self._old.mtime = new Date(0)
							 | 
						||
| 
								 | 
							
								    // console.error(" W Finish Stale Stat", self._path, self.size)
							 | 
						||
| 
								 | 
							
								    setProps(self._old)
							 | 
						||
| 
								 | 
							
								  } else {
							 | 
						||
| 
								 | 
							
								    var stat = self.props.follow ? 'stat' : 'lstat'
							 | 
						||
| 
								 | 
							
								    // console.error(" W Finish Stating", self._path, self.size)
							 | 
						||
| 
								 | 
							
								    fs[stat](self._path, function (er, current) {
							 | 
						||
| 
								 | 
							
								      // console.error(" W Finish Stated", self._path, self.size, current)
							 | 
						||
| 
								 | 
							
								      if (er) {
							 | 
						||
| 
								 | 
							
								        // if we're in the process of writing out a
							 | 
						||
| 
								 | 
							
								        // directory, it's very possible that the thing we're linking to
							 | 
						||
| 
								 | 
							
								        // doesn't exist yet (especially if it was intended as a symlink),
							 | 
						||
| 
								 | 
							
								        // so swallow ENOENT errors here and just soldier on.
							 | 
						||
| 
								 | 
							
								        if (er.code === 'ENOENT' &&
							 | 
						||
| 
								 | 
							
								          (self.type === 'Link' || self.type === 'SymbolicLink') &&
							 | 
						||
| 
								 | 
							
								          process.platform === 'win32') {
							 | 
						||
| 
								 | 
							
								          self.ready = true
							 | 
						||
| 
								 | 
							
								          self.emit('ready')
							 | 
						||
| 
								 | 
							
								          self.emit('end')
							 | 
						||
| 
								 | 
							
								          self.emit('close')
							 | 
						||
| 
								 | 
							
								          self.end = self._finish = function () {}
							 | 
						||
| 
								 | 
							
								          return
							 | 
						||
| 
								 | 
							
								        } else return self.error(er)
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      setProps(self._old = current)
							 | 
						||
| 
								 | 
							
								    })
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  return
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function setProps (current) {
							 | 
						||
| 
								 | 
							
								    todo += 3
							 | 
						||
| 
								 | 
							
								    endChmod(self, self.props, current, self._path, next('chmod'))
							 | 
						||
| 
								 | 
							
								    endChown(self, self.props, current, self._path, next('chown'))
							 | 
						||
| 
								 | 
							
								    endUtimes(self, self.props, current, self._path, next('utimes'))
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  function next (what) {
							 | 
						||
| 
								 | 
							
								    return function (er) {
							 | 
						||
| 
								 | 
							
								      // console.error("   W Finish", what, todo)
							 | 
						||
| 
								 | 
							
								      if (errState) return
							 | 
						||
| 
								 | 
							
								      if (er) {
							 | 
						||
| 
								 | 
							
								        er.fstream_finish_call = what
							 | 
						||
| 
								 | 
							
								        return self.error(errState = er)
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								      if (--todo > 0) return
							 | 
						||
| 
								 | 
							
								      if (done) return
							 | 
						||
| 
								 | 
							
								      done = true
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      // we may still need to set the mode/etc. on some parent dirs
							 | 
						||
| 
								 | 
							
								      // that were created previously.  delay end/close until then.
							 | 
						||
| 
								 | 
							
								      if (!self._madeDir) return end()
							 | 
						||
| 
								 | 
							
								      else endMadeDir(self, self._path, end)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								      function end (er) {
							 | 
						||
| 
								 | 
							
								        if (er) {
							 | 
						||
| 
								 | 
							
								          er.fstream_finish_call = 'setupMadeDir'
							 | 
						||
| 
								 | 
							
								          return self.error(er)
							 | 
						||
| 
								 | 
							
								        }
							 | 
						||
| 
								 | 
							
								        // all the props have been set, so we're completely done.
							 | 
						||
| 
								 | 
							
								        self.emit('end')
							 | 
						||
| 
								 | 
							
								        self.emit('close')
							 | 
						||
| 
								 | 
							
								      }
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function endMadeDir (self, p, cb) {
							 | 
						||
| 
								 | 
							
								  var made = self._madeDir
							 | 
						||
| 
								 | 
							
								  // everything *between* made and path.dirname(self._path)
							 | 
						||
| 
								 | 
							
								  // needs to be set up.  Note that this may just be one dir.
							 | 
						||
| 
								 | 
							
								  var d = path.dirname(p)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  endMadeDir_(self, d, function (er) {
							 | 
						||
| 
								 | 
							
								    if (er) return cb(er)
							 | 
						||
| 
								 | 
							
								    if (d === made) {
							 | 
						||
| 
								 | 
							
								      return cb()
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								    endMadeDir(self, d, cb)
							 | 
						||
| 
								 | 
							
								  })
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function endMadeDir_ (self, p, cb) {
							 | 
						||
| 
								 | 
							
								  var dirProps = {}
							 | 
						||
| 
								 | 
							
								  Object.keys(self.props).forEach(function (k) {
							 | 
						||
| 
								 | 
							
								    dirProps[k] = self.props[k]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    // only make non-readable dirs if explicitly requested.
							 | 
						||
| 
								 | 
							
								    if (k === 'mode' && self.type !== 'Directory') {
							 | 
						||
| 
								 | 
							
								      dirProps[k] = dirProps[k] | parseInt('0111', 8)
							 | 
						||
| 
								 | 
							
								    }
							 | 
						||
| 
								 | 
							
								  })
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								  var todo = 3
							 | 
						||
| 
								 | 
							
								  var errState = null
							 | 
						||
| 
								 | 
							
								  fs.stat(p, function (er, current) {
							 | 
						||
| 
								 | 
							
								    if (er) return cb(errState = er)
							 | 
						||
| 
								 | 
							
								    endChmod(self, dirProps, current, p, next)
							 | 
						||
| 
								 | 
							
								    endChown(self, dirProps, current, p, next)
							 | 
						||
| 
								 | 
							
								    endUtimes(self, 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 () {
							 | 
						||
| 
								 | 
							
								  this.error("Can't pipe from writable stream")
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Writer.prototype.add = function () {
							 | 
						||
| 
								 | 
							
								  this.error("Can't add to non-Directory type")
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								Writer.prototype.write = function () {
							 | 
						||
| 
								 | 
							
								  return true
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function objectToString (d) {
							 | 
						||
| 
								 | 
							
								  return Object.prototype.toString.call(d)
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function isDate (d) {
							 | 
						||
| 
								 | 
							
								  return typeof d === 'object' && objectToString(d) === '[object Date]'
							 | 
						||
| 
								 | 
							
								}
							 |