summaryrefslogtreecommitdiff
path: root/deps/npm/node_modules/node-gyp/node_modules/fstream/lib/writer.js
diff options
context:
space:
mode:
Diffstat (limited to 'deps/npm/node_modules/node-gyp/node_modules/fstream/lib/writer.js')
-rw-r--r--deps/npm/node_modules/node-gyp/node_modules/fstream/lib/writer.js390
1 files changed, 390 insertions, 0 deletions
diff --git a/deps/npm/node_modules/node-gyp/node_modules/fstream/lib/writer.js b/deps/npm/node_modules/node-gyp/node_modules/fstream/lib/writer.js
new file mode 100644
index 0000000000..140e449e06
--- /dev/null
+++ b/deps/npm/node_modules/node-gyp/node_modules/fstream/lib/writer.js
@@ -0,0 +1,390 @@
+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) {
+ 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]'
+}