summaryrefslogtreecommitdiff
path: root/deps/npm/node_modules/tar/old/generator.js
diff options
context:
space:
mode:
Diffstat (limited to 'deps/npm/node_modules/tar/old/generator.js')
-rw-r--r--deps/npm/node_modules/tar/old/generator.js387
1 files changed, 387 insertions, 0 deletions
diff --git a/deps/npm/node_modules/tar/old/generator.js b/deps/npm/node_modules/tar/old/generator.js
new file mode 100644
index 0000000000..c2506c4151
--- /dev/null
+++ b/deps/npm/node_modules/tar/old/generator.js
@@ -0,0 +1,387 @@
+module.exports = Generator
+Generator.create = create
+
+var tar = require("./tar")
+ , Stream = require("stream").Stream
+ , Parser = require("./parser")
+ , fs = require("fs")
+
+function create (opts) {
+ return new Generator(opts)
+}
+
+function Generator (opts) {
+ this.readable = true
+ this.currentFile = null
+
+ this._paused = false
+ this._ended = false
+ this._queue = []
+
+ this.options = { cwd: process.cwd() }
+ Object.keys(opts).forEach(function (o) {
+ this.options[o] = opts[o]
+ }, this)
+ if (this.options.cwd.slice(-1) !== "/") {
+ this.options.cwd += "/"
+ }
+
+ Stream.apply(this)
+}
+
+Generator.prototype = Object.create(Stream.prototype)
+
+Generator.prototype.pause = function () {
+ if (this.currentFile) this.currentFile.pause()
+ this.paused = true
+ this.emit("pause")
+}
+
+Generator.prototype.resume = function () {
+ this.paused = false
+ if (this.currentFile) this.currentFile.resume()
+ this.emit("resume")
+ this._processQueue()
+}
+
+Generator.prototype.end = function () {
+ this._ended = true
+ this._processQueue()
+}
+
+Generator.prototype.append = function (f, st) {
+ if (this._ended) return this.emit("error", new Error(
+ "Cannot append after ending"))
+
+ // if it's a string, then treat it as a filename.
+ // if it's a number, then treat it as a fd
+ // if it's a Stats, then treat it as a stat object
+ // if it's a Stream, then stream it in.
+ var s = toFileStream(f, st)
+ if (!s) return this.emit("error", new TypeError(
+ "Invalid argument: "+f))
+
+ // make sure it's in the folder being added.
+ if (s.name.indexOf(this.options.cwd) !== 0) {
+ this.emit("error", new Error(
+ "Invalid argument: "+s.name+"\nOutside of "+this.options.cwd))
+ }
+
+ s.name = s.name.substr(this.options.cwd.length)
+ s.pause()
+ this._queue.push(s)
+
+ if (!s._needStat) return this._processQueue()
+
+ var self = this
+ fs.lstat(s.name, function (er, st) {
+ if (er) return self.emit("error", new Error(
+ "invalid file "+s.name+"\n"+er.message))
+ s.mode = st.mode & 0777
+ s.uid = st.uid
+ s.gid = st.gid
+ s.size = st.size
+ s.mtime = +st.mtime / 1000
+ s.type = st.isFile() ? "0"
+ : st.isSymbolicLink() ? "2"
+ : st.isCharacterDevice() ? "3"
+ : st.isBlockDevice() ? "4"
+ : st.isDirectory() ? "5"
+ : st.isFIFO() ? "6"
+ : null
+
+ // TODO: handle all the types in
+ // http://cdrecord.berlios.de/private/man/star/star.4.html
+ // for now, skip over unknown ones.
+ if (s.type === null) {
+ console.error("Unknown file type: " + s.name)
+ // kick out of the queue
+ var i = self._queue.indexOf(s)
+ if (i !== -1) self._queue.splice(i, 1)
+ self._processQueue()
+ return
+ }
+
+ if (s.type === "2") return fs.readlink(s.name, function (er, n) {
+ if (er) return self.emit("error", new Error(
+ "error reading link value "+s.name+"\n"+er.message))
+ s.linkname = n
+ s._needStat = false
+ self._processQueue()
+ })
+ s._needStat = false
+ self._processQueue()
+ })
+ return false
+}
+
+function toFileStream (thing) {
+ if (typeof thing === "string") {
+ return toFileStream(fs.createReadStream(thing))
+ }
+
+ if (thing && typeof thing === "object") {
+ if (thing instanceof (Parser.File)) return thing
+
+ if (thing instanceof Stream) {
+ if (thing.hasOwnProperty("name") &&
+ thing.hasOwnProperty("mode") &&
+ thing.hasOwnProperty("uid") &&
+ thing.hasOwnProperty("gid") &&
+ thing.hasOwnProperty("size") &&
+ thing.hasOwnProperty("mtime") &&
+ thing.hasOwnProperty("type")) return thing
+
+ if (thing instanceof (fs.ReadStream)) {
+ thing.name = thing.path
+ }
+
+ if (thing.name) {
+ thing._needStat = true
+ return thing
+ }
+ }
+ }
+
+ return null
+}
+
+Generator.prototype._processQueue = function processQueue () {
+ console.error("processQueue", this._queue[0])
+ if (this._paused) return false
+
+ if (this.currentFile ||
+ this._queue.length && this._queue[0]._needStat) {
+ // either already processing one, or waiting on something.
+ return
+ }
+
+ var f = this.currentFile = this._queue.shift()
+ if (!f) {
+ if (this._ended) {
+ // close it off with 2 blocks of nulls.
+ this.emit("data", new Buffer(new Array(512 * 2)))
+ this.emit("end")
+ this.emit("close")
+ }
+ return true
+ }
+
+ if (f.type === Parser.File.types.Directory &&
+ f.name.slice(-1) !== "/") {
+ f.name += "/"
+ }
+
+ // write out a Pax header if the file isn't kosher.
+ if (this._needPax(f)) this._emitPax(f)
+
+ // write out the header
+ f.ustar = true
+ this._emitHeader(f)
+ var fpos = 0
+ , self = this
+ console.error("about to read body data", f)
+ f.on("data", function (c) {
+ self.emit("data", c)
+ self.fpos += c.length
+ })
+ f.on("error", function (er) { self.emit("error", er) })
+ f.on("end", function $END () {
+ // pad with \0 out to an even multiple of 512 bytes.
+ // this ensures that every file starts on a block.
+ var b = new Buffer(fpos % 512 || 512)
+
+ for (var i = 0, l = b.length; i < l; i ++) b[i] = 0
+ //console.log(b.length, b)
+ self.emit("data", b)
+ self.currentFile = null
+ self._processQueue()
+ })
+ f.resume()
+}
+
+Generator.prototype._needPax = function (f) {
+ // meh. why not?
+ return true
+
+ return oddTextField(f.name, "NAME") ||
+ oddTextField(f.link, "LINK") ||
+ oddTextField(f.gname, "GNAME") ||
+ oddTextField(f.uname, "UNAME") ||
+ oddTextField(f.prefix, "PREFIX")
+}
+
+// check if a text field is too long or non-ascii
+function oddTextField (val, field) {
+ var nl = Buffer.byteLength(val)
+ , len = tar.fieldSize[field]
+ if (nl > len || nl !== val.length) return true
+}
+
+// emit a Pax header of "key = val" for any file with
+// odd or too-long field values.
+Generator.prototype._emitPax = function (f) {
+ // since these tend to be relatively small, just go ahead
+ // and emit it all in-band. That saves having to keep
+ // track of the pax state in the generator, and we can
+ // go right back to emitting the file in the same tick.
+ var dir = f.name.replace(/[^\/]+\/?$/, "")
+ , base = f.name.substr(dir.length)
+ var pax = { name: dir + "PaxHeader/" +base
+ , mode: 0644
+ , uid: f.uid
+ , gid: f.gid
+ , mtime: +f.mtime
+ // don't know size yet.
+ , size: -1
+ , type: "x" // extended header
+ , ustar: true
+ , ustarVersion: "00"
+ , user: f.user || f.uname || ""
+ , group: f.group || f.gname || ""
+ , dev: { major: f.dev && f.dev.major || 0
+ , minor: f.dev && f.dev.minor || 0 }
+ , prefix: f.prefix
+ , linkname: "" }
+
+ // generate the Pax body
+ var kv = { path: (f.prefix ? f.prefix + "/" : "") + f.name
+ , atime: f.atime
+ , mtime: f.mtime
+ , ctime: f.ctime
+ , charset: "UTF-8"
+ , gid: f.gid
+ , uid: f.uid
+ , uname: f.user || f.uname || ""
+ , gname: f.group || f.gname || ""
+ , linkpath: f.linkpath || ""
+ , size: f.size
+ }
+ // "%d %s=%s\n", <length>, <keyword>, <value>
+ // length includes the length of the length number,
+ // the key=val, and the \n.
+ var body = new Buffer(Object.keys(kv).map(function (key) {
+ if (!kv[key]) return ["", ""]
+
+ var s = new Buffer(" " + key + "=" + kv[key]+"\n")
+ , digits = Math.floor(Math.log(s.length) / Math.log(10)) + 1
+
+ // if adding that many digits will make it go over that length,
+ // then add one to it
+ if (s.length > Math.pow(10, digits) - digits) digits ++
+
+ return [s.length + digits, s]
+ }).reduce(function (l, r) {
+ return l + r[0] + r[1]
+ }, ""))
+
+ pax.size = body.length
+ this._emitHeader(pax)
+ this.emit("data", body)
+ // now the trailing buffer to make it an even number of 512 blocks
+ var b = new Buffer(512 + (body.length % 512 || 512))
+ for (var i = 0, l = b.length; i < l; i ++) b[i] = 0
+ this.emit("data", b)
+}
+
+Generator.prototype._emitHeader = function (f) {
+ var header = new Buffer(new Array(512))
+ , fields = tar.fields
+ , offs = tar.fieldOffs
+ , sz = tar.fieldSize
+
+ addField(header, "NAME", f.name)
+ addField(header, "MODE", f.mode)
+ addField(header, "UID", f.uid)
+ addField(header, "GID", f.gid)
+ addField(header, "SIZE", f.size)
+ addField(header, "MTIME", +f.mtime)
+ // checksum is generated based on it being spaces
+ // then it's written as: "######\0 "
+ // where ### is a zero-lead 6-digit octal number
+ addField(header, "CKSUM", " ")
+
+ addField(header, "TYPE", f.type)
+ addField(header, "LINKNAME", f.linkname || "")
+ if (f.ustar) {
+ console.error(">>> ustar!!")
+ addField(header, "USTAR", tar.ustar)
+ addField(header, "USTARVER", 0)
+ addField(header, "UNAME", f.user || "")
+ addField(header, "GNAME", f.group || "")
+ if (f.dev) {
+ addField(header, "DEVMAJ", f.dev.major || 0)
+ addField(header, "DEVMIN", f.dev.minor || 0)
+ }
+ addField(header, "PREFIX", f.prefix)
+ } else {
+ console.error(">>> no ustar!")
+ }
+
+ // now the header is written except for checksum.
+ var ck = 0
+ for (var i = 0; i < 512; i ++) ck += header[i]
+ addField(header, "CKSUM", nF(ck, 7))
+ header[ offs[fields.CKSUM] + 7 ] = 0
+
+ this.emit("data", header)
+}
+
+function addField (buf, field, val) {
+ var f = tar.fields[field]
+ console.error("Adding field", field, val)
+ val = typeof val === "number"
+ ? nF(val, tar.fieldSize[f])
+ : new Buffer(val || "")
+ val.copy(buf, tar.fieldOffs[f])
+}
+
+function toBase256 (num, len) {
+ console.error("toBase256", num, len)
+ var positive = num > 0
+ , buf = new Buffer(len)
+ if (!positive) {
+ // rare and slow
+ var b = num.toString(2).substr(1)
+ , padTo = (len - 1) * 8
+ b = new Array(padTo - b.length + 1).join("0") + b
+
+ // take the 2's complement
+ var ht = b.match(/^([01]*)(10*)?$/)
+ , head = ht[1]
+ , tail = ht[2]
+ head = head.split("1").join("2")
+ .split("0").join("1")
+ .split("2").join("0")
+ b = head + tail
+
+ buf[0] = 0xFF
+ for (var i = 1; i < len; i ++) {
+ buf[i] = parseInt(buf.substr(i * 8, 8), 2)
+ }
+ return buf
+ }
+
+ buf[0] = 0x80
+ for (var i = 1, l = len, p = l - 1; i < l; i ++, p --) {
+ buf[p] = num % 256
+ num = Math.floor(num / 256)
+ }
+ return buf
+}
+
+function nF (num, size) {
+ var ns = num.toString(8)
+
+ if (num < 0 || ns.length >= size) {
+ // make a base 256 buffer
+ // then return it
+ return toBase256(num, size)
+ }
+
+ var buf = new Buffer(size)
+ ns = new Array(size - ns.length - 1).join("0") + ns + " "
+ buf[size - 1] = 0
+ buf.asciiWrite(ns)
+ return buf
+}