aboutsummaryrefslogtreecommitdiff
path: root/deps/npm/node_modules/tar/lib
diff options
context:
space:
mode:
Diffstat (limited to 'deps/npm/node_modules/tar/lib')
-rw-r--r--deps/npm/node_modules/tar/lib/buffer-entry.js30
-rw-r--r--deps/npm/node_modules/tar/lib/create.js110
-rw-r--r--deps/npm/node_modules/tar/lib/entry-writer.js169
-rw-r--r--deps/npm/node_modules/tar/lib/entry.js220
-rw-r--r--deps/npm/node_modules/tar/lib/extended-header-writer.js191
-rw-r--r--deps/npm/node_modules/tar/lib/extended-header.js140
-rw-r--r--deps/npm/node_modules/tar/lib/extract.js189
-rw-r--r--deps/npm/node_modules/tar/lib/global-header-writer.js14
-rw-r--r--deps/npm/node_modules/tar/lib/header.js583
-rw-r--r--deps/npm/node_modules/tar/lib/high-level-opt.js29
-rw-r--r--deps/npm/node_modules/tar/lib/large-numbers.js92
-rw-r--r--deps/npm/node_modules/tar/lib/list.js132
-rw-r--r--deps/npm/node_modules/tar/lib/mkdir.js207
-rw-r--r--deps/npm/node_modules/tar/lib/pack.js537
-rw-r--r--deps/npm/node_modules/tar/lib/parse.js632
-rw-r--r--deps/npm/node_modules/tar/lib/pax.js145
-rw-r--r--deps/npm/node_modules/tar/lib/read-entry.js94
-rw-r--r--deps/npm/node_modules/tar/lib/replace.js211
-rw-r--r--deps/npm/node_modules/tar/lib/types.js44
-rw-r--r--deps/npm/node_modules/tar/lib/unpack.js481
-rw-r--r--deps/npm/node_modules/tar/lib/update.js36
-rw-r--r--deps/npm/node_modules/tar/lib/warn-mixin.js14
-rw-r--r--deps/npm/node_modules/tar/lib/winchars.js23
-rw-r--r--deps/npm/node_modules/tar/lib/write-entry.js395
24 files changed, 3095 insertions, 1623 deletions
diff --git a/deps/npm/node_modules/tar/lib/buffer-entry.js b/deps/npm/node_modules/tar/lib/buffer-entry.js
deleted file mode 100644
index 6c1da2373a..0000000000
--- a/deps/npm/node_modules/tar/lib/buffer-entry.js
+++ /dev/null
@@ -1,30 +0,0 @@
-// just like the Entry class, but it buffers the contents
-//
-// XXX It would be good to set a maximum BufferEntry filesize,
-// since it eats up memory. In normal operation,
-// these are only for long filenames or link names, which are
-// rarely very big.
-
-module.exports = BufferEntry
-
-var inherits = require("inherits")
- , Entry = require("./entry.js")
-
-function BufferEntry () {
- Entry.apply(this, arguments)
- this._buffer = new Buffer(this.props.size)
- this._offset = 0
- this.body = ""
- this.on("end", function () {
- this.body = this._buffer.toString().slice(0, -1)
- })
-}
-
-inherits(BufferEntry, Entry)
-
-// collect the bytes as they come in.
-BufferEntry.prototype.write = function (c) {
- c.copy(this._buffer, this._offset)
- this._offset += c.length
- Entry.prototype.write.call(this, c)
-}
diff --git a/deps/npm/node_modules/tar/lib/create.js b/deps/npm/node_modules/tar/lib/create.js
new file mode 100644
index 0000000000..5d46b3ba70
--- /dev/null
+++ b/deps/npm/node_modules/tar/lib/create.js
@@ -0,0 +1,110 @@
+'use strict'
+
+// tar -c
+const hlo = require('./high-level-opt.js')
+
+const Pack = require('./pack.js')
+const fs = require('fs')
+const t = require('./list.js')
+const path = require('path')
+
+const c = module.exports = (opt_, files, cb) => {
+ if (typeof files === 'function')
+ cb = files
+
+ if (Array.isArray(opt_))
+ files = opt_, opt_ = {}
+
+ if (!files || !Array.isArray(files) || !files.length)
+ throw new TypeError('no files or directories specified')
+
+ files = Array.from(files)
+
+ const opt = hlo(opt_)
+
+ if (opt.sync && typeof cb === 'function')
+ throw new TypeError('callback not supported for sync tar functions')
+
+ if (!opt.file && typeof cb === 'function')
+ throw new TypeError('callback only supported with file option')
+
+ return opt.file && opt.sync ? createFileSync(opt, files)
+ : opt.file ? createFile(opt, files, cb)
+ : opt.sync ? createSync(opt, files)
+ : create(opt, files)
+}
+
+const createFileSync = (opt, files) => {
+ const p = new Pack.Sync(opt)
+
+ let threw = true
+ let fd
+ try {
+ fd = fs.openSync(opt.file, 'w', opt.mode || 0o666)
+ p.on('data', chunk => fs.writeSync(fd, chunk, 0, chunk.length))
+ p.on('end', _ => fs.closeSync(fd))
+ addFilesSync(p, files)
+ threw = false
+ } finally {
+ if (threw)
+ try { fs.closeSync(fd) } catch (er) {}
+ }
+}
+
+const createFile = (opt, files, cb) => {
+ const p = new Pack(opt)
+ const stream = fs.createWriteStream(opt.file, { mode: opt.mode || 0o666 })
+ p.pipe(stream)
+
+ const promise = new Promise((res, rej) => {
+ stream.on('error', rej)
+ stream.on('close', res)
+ p.on('error', rej)
+ })
+
+ addFilesAsync(p, files)
+
+ return cb ? promise.then(cb, cb) : promise
+}
+
+const addFilesSync = (p, files) => {
+ files.forEach(file => {
+ if (file.charAt(0) === '@')
+ t({
+ file: path.resolve(p.cwd, file.substr(1)),
+ sync: true,
+ noResume: true,
+ onentry: entry => p.add(entry)
+ })
+ else
+ p.add(file)
+ })
+ p.end()
+}
+
+const addFilesAsync = (p, files) => {
+ while (files.length) {
+ const file = files.shift()
+ if (file.charAt(0) === '@')
+ return t({
+ file: path.resolve(p.cwd, file.substr(1)),
+ noResume: true,
+ onentry: entry => p.add(entry)
+ }).then(_ => addFilesAsync(p, files))
+ else
+ p.add(file)
+ }
+ p.end()
+}
+
+const createSync = (opt, files) => {
+ const p = new Pack.Sync(opt)
+ addFilesSync(p, files)
+ return p
+}
+
+const create = (opt, files) => {
+ const p = new Pack(opt)
+ addFilesAsync(p, files)
+ return p
+}
diff --git a/deps/npm/node_modules/tar/lib/entry-writer.js b/deps/npm/node_modules/tar/lib/entry-writer.js
deleted file mode 100644
index 8e09042d01..0000000000
--- a/deps/npm/node_modules/tar/lib/entry-writer.js
+++ /dev/null
@@ -1,169 +0,0 @@
-module.exports = EntryWriter
-
-var tar = require("../tar.js")
- , TarHeader = require("./header.js")
- , Entry = require("./entry.js")
- , inherits = require("inherits")
- , BlockStream = require("block-stream")
- , ExtendedHeaderWriter
- , Stream = require("stream").Stream
- , EOF = {}
-
-inherits(EntryWriter, Stream)
-
-function EntryWriter (props) {
- var me = this
-
- if (!(me instanceof EntryWriter)) {
- return new EntryWriter(props)
- }
-
- Stream.apply(this)
-
- me.writable = true
- me.readable = true
-
- me._stream = new BlockStream(512)
-
- me._stream.on("data", function (c) {
- me.emit("data", c)
- })
-
- me._stream.on("drain", function () {
- me.emit("drain")
- })
-
- me._stream.on("end", function () {
- me.emit("end")
- me.emit("close")
- })
-
- me.props = props
- if (props.type === "Directory") {
- props.size = 0
- }
- props.ustar = "ustar\0"
- props.ustarver = "00"
- me.path = props.path
-
- me._buffer = []
- me._didHeader = false
- me._meta = false
-
- me.on("pipe", function () {
- me._process()
- })
-}
-
-EntryWriter.prototype.write = function (c) {
- // console.error(".. ew write")
- if (this._ended) return this.emit("error", new Error("write after end"))
- this._buffer.push(c)
- this._process()
- this._needDrain = this._buffer.length > 0
- return !this._needDrain
-}
-
-EntryWriter.prototype.end = function (c) {
- // console.error(".. ew end")
- if (c) this._buffer.push(c)
- this._buffer.push(EOF)
- this._ended = true
- this._process()
- this._needDrain = this._buffer.length > 0
-}
-
-EntryWriter.prototype.pause = function () {
- // console.error(".. ew pause")
- this._paused = true
- this.emit("pause")
-}
-
-EntryWriter.prototype.resume = function () {
- // console.error(".. ew resume")
- this._paused = false
- this.emit("resume")
- this._process()
-}
-
-EntryWriter.prototype.add = function (entry) {
- // console.error(".. ew add")
- if (!this.parent) return this.emit("error", new Error("no parent"))
-
- // make sure that the _header and such is emitted, and clear out
- // the _currentEntry link on the parent.
- if (!this._ended) this.end()
-
- return this.parent.add(entry)
-}
-
-EntryWriter.prototype._header = function () {
- // console.error(".. ew header")
- if (this._didHeader) return
- this._didHeader = true
-
- var headerBlock = TarHeader.encode(this.props)
-
- if (this.props.needExtended && !this._meta) {
- var me = this
-
- ExtendedHeaderWriter = ExtendedHeaderWriter ||
- require("./extended-header-writer.js")
-
- ExtendedHeaderWriter(this.props)
- .on("data", function (c) {
- me.emit("data", c)
- })
- .on("error", function (er) {
- me.emit("error", er)
- })
- .end()
- }
-
- // console.error(".. .. ew headerBlock emitting")
- this.emit("data", headerBlock)
- this.emit("header")
-}
-
-EntryWriter.prototype._process = function () {
- // console.error(".. .. ew process")
- if (!this._didHeader && !this._meta) {
- this._header()
- }
-
- if (this._paused || this._processing) {
- // console.error(".. .. .. paused=%j, processing=%j", this._paused, this._processing)
- return
- }
-
- this._processing = true
-
- var buf = this._buffer
- for (var i = 0; i < buf.length; i ++) {
- // console.error(".. .. .. i=%d", i)
-
- var c = buf[i]
-
- if (c === EOF) this._stream.end()
- else this._stream.write(c)
-
- if (this._paused) {
- // console.error(".. .. .. paused mid-emission")
- this._processing = false
- if (i < buf.length) {
- this._needDrain = true
- this._buffer = buf.slice(i + 1)
- }
- return
- }
- }
-
- // console.error(".. .. .. emitted")
- this._buffer.length = 0
- this._processing = false
-
- // console.error(".. .. .. emitting drain")
- this.emit("drain")
-}
-
-EntryWriter.prototype.destroy = function () {}
diff --git a/deps/npm/node_modules/tar/lib/entry.js b/deps/npm/node_modules/tar/lib/entry.js
deleted file mode 100644
index 591202bd3b..0000000000
--- a/deps/npm/node_modules/tar/lib/entry.js
+++ /dev/null
@@ -1,220 +0,0 @@
-// A passthrough read/write stream that sets its properties
-// based on a header, extendedHeader, and globalHeader
-//
-// Can be either a file system object of some sort, or
-// a pax/ustar metadata entry.
-
-module.exports = Entry
-
-var TarHeader = require("./header.js")
- , tar = require("../tar")
- , assert = require("assert").ok
- , Stream = require("stream").Stream
- , inherits = require("inherits")
- , fstream = require("fstream").Abstract
-
-function Entry (header, extended, global) {
- Stream.call(this)
- this.readable = true
- this.writable = true
-
- this._needDrain = false
- this._paused = false
- this._reading = false
- this._ending = false
- this._ended = false
- this._remaining = 0
- this._abort = false
- this._queue = []
- this._index = 0
- this._queueLen = 0
-
- this._read = this._read.bind(this)
-
- this.props = {}
- this._header = header
- this._extended = extended || {}
-
- // globals can change throughout the course of
- // a file parse operation. Freeze it at its current state.
- this._global = {}
- var me = this
- Object.keys(global || {}).forEach(function (g) {
- me._global[g] = global[g]
- })
-
- this._setProps()
-}
-
-inherits(Entry, Stream)
-
-Entry.prototype.write = function (c) {
- if (this._ending) this.error("write() after end()", null, true)
- if (this._remaining === 0) {
- this.error("invalid bytes past eof")
- }
-
- // often we'll get a bunch of \0 at the end of the last write,
- // since chunks will always be 512 bytes when reading a tarball.
- if (c.length > this._remaining) {
- c = c.slice(0, this._remaining)
- }
- this._remaining -= c.length
-
- // put it on the stack.
- var ql = this._queueLen
- this._queue.push(c)
- this._queueLen ++
-
- this._read()
-
- // either paused, or buffered
- if (this._paused || ql > 0) {
- this._needDrain = true
- return false
- }
-
- return true
-}
-
-Entry.prototype.end = function (c) {
- if (c) this.write(c)
- this._ending = true
- this._read()
-}
-
-Entry.prototype.pause = function () {
- this._paused = true
- this.emit("pause")
-}
-
-Entry.prototype.resume = function () {
- // console.error(" Tar Entry resume", this.path)
- this.emit("resume")
- this._paused = false
- this._read()
- return this._queueLen - this._index > 1
-}
-
- // This is bound to the instance
-Entry.prototype._read = function () {
- // console.error(" Tar Entry _read", this.path)
-
- if (this._paused || this._reading || this._ended) return
-
- // set this flag so that event handlers don't inadvertently
- // get multiple _read() calls running.
- this._reading = true
-
- // have any data to emit?
- while (this._index < this._queueLen && !this._paused) {
- var chunk = this._queue[this._index ++]
- this.emit("data", chunk)
- }
-
- // check if we're drained
- if (this._index >= this._queueLen) {
- this._queue.length = this._queueLen = this._index = 0
- if (this._needDrain) {
- this._needDrain = false
- this.emit("drain")
- }
- if (this._ending) {
- this._ended = true
- this.emit("end")
- }
- }
-
- // if the queue gets too big, then pluck off whatever we can.
- // this should be fairly rare.
- var mql = this._maxQueueLen
- if (this._queueLen > mql && this._index > 0) {
- mql = Math.min(this._index, mql)
- this._index -= mql
- this._queueLen -= mql
- this._queue = this._queue.slice(mql)
- }
-
- this._reading = false
-}
-
-Entry.prototype._setProps = function () {
- // props = extended->global->header->{}
- var header = this._header
- , extended = this._extended
- , global = this._global
- , props = this.props
-
- // first get the values from the normal header.
- var fields = tar.fields
- for (var f = 0; fields[f] !== null; f ++) {
- var field = fields[f]
- , val = header[field]
- if (typeof val !== "undefined") props[field] = val
- }
-
- // next, the global header for this file.
- // numeric values, etc, will have already been parsed.
- ;[global, extended].forEach(function (p) {
- Object.keys(p).forEach(function (f) {
- if (typeof p[f] !== "undefined") props[f] = p[f]
- })
- })
-
- // no nulls allowed in path or linkpath
- ;["path", "linkpath"].forEach(function (p) {
- if (props.hasOwnProperty(p)) {
- props[p] = props[p].split("\0")[0]
- }
- })
-
-
- // set date fields to be a proper date
- ;["mtime", "ctime", "atime"].forEach(function (p) {
- if (props.hasOwnProperty(p)) {
- props[p] = new Date(props[p] * 1000)
- }
- })
-
- // set the type so that we know what kind of file to create
- var type
- switch (tar.types[props.type]) {
- case "OldFile":
- case "ContiguousFile":
- type = "File"
- break
-
- case "GNUDumpDir":
- type = "Directory"
- break
-
- case undefined:
- type = "Unknown"
- break
-
- case "Link":
- case "SymbolicLink":
- case "CharacterDevice":
- case "BlockDevice":
- case "Directory":
- case "FIFO":
- default:
- type = tar.types[props.type]
- }
-
- this.type = type
- this.path = props.path
- this.size = props.size
-
- // size is special, since it signals when the file needs to end.
- this._remaining = props.size
-}
-
-// the parser may not call write if _abort is true.
-// useful for skipping data from some files quickly.
-Entry.prototype.abort = function(){
- this._abort = true
-}
-
-Entry.prototype.warn = fstream.warn
-Entry.prototype.error = fstream.error
diff --git a/deps/npm/node_modules/tar/lib/extended-header-writer.js b/deps/npm/node_modules/tar/lib/extended-header-writer.js
deleted file mode 100644
index 1728c4583a..0000000000
--- a/deps/npm/node_modules/tar/lib/extended-header-writer.js
+++ /dev/null
@@ -1,191 +0,0 @@
-
-module.exports = ExtendedHeaderWriter
-
-var inherits = require("inherits")
- , EntryWriter = require("./entry-writer.js")
-
-inherits(ExtendedHeaderWriter, EntryWriter)
-
-var tar = require("../tar.js")
- , path = require("path")
- , TarHeader = require("./header.js")
-
-// props is the props of the thing we need to write an
-// extended header for.
-// Don't be shy with it. Just encode everything.
-function ExtendedHeaderWriter (props) {
- // console.error(">> ehw ctor")
- var me = this
-
- if (!(me instanceof ExtendedHeaderWriter)) {
- return new ExtendedHeaderWriter(props)
- }
-
- me.fields = props
-
- var p =
- { path : ("PaxHeader" + path.join("/", props.path || ""))
- .replace(/\\/g, "/").substr(0, 100)
- , mode : props.mode || 0666
- , uid : props.uid || 0
- , gid : props.gid || 0
- , size : 0 // will be set later
- , mtime : props.mtime || Date.now() / 1000
- , type : "x"
- , linkpath : ""
- , ustar : "ustar\0"
- , ustarver : "00"
- , uname : props.uname || ""
- , gname : props.gname || ""
- , devmaj : props.devmaj || 0
- , devmin : props.devmin || 0
- }
-
-
- EntryWriter.call(me, p)
- // console.error(">> ehw props", me.props)
- me.props = p
-
- me._meta = true
-}
-
-ExtendedHeaderWriter.prototype.end = function () {
- // console.error(">> ehw end")
- var me = this
-
- if (me._ended) return
- me._ended = true
-
- me._encodeFields()
-
- if (me.props.size === 0) {
- // nothing to write!
- me._ready = true
- me._stream.end()
- return
- }
-
- me._stream.write(TarHeader.encode(me.props))
- me.body.forEach(function (l) {
- me._stream.write(l)
- })
- me._ready = true
-
- // console.error(">> ehw _process calling end()", me.props)
- this._stream.end()
-}
-
-ExtendedHeaderWriter.prototype._encodeFields = function () {
- // console.error(">> ehw _encodeFields")
- this.body = []
- if (this.fields.prefix) {
- this.fields.path = this.fields.prefix + "/" + this.fields.path
- this.fields.prefix = ""
- }
- encodeFields(this.fields, "", this.body, this.fields.noProprietary)
- var me = this
- this.body.forEach(function (l) {
- me.props.size += l.length
- })
-}
-
-function encodeFields (fields, prefix, body, nop) {
- // console.error(">> >> ehw encodeFields")
- // "%d %s=%s\n", <length>, <keyword>, <value>
- // The length is a decimal number, and includes itself and the \n
- // Numeric values are decimal strings.
-
- Object.keys(fields).forEach(function (k) {
- var val = fields[k]
- , numeric = tar.numeric[k]
-
- if (prefix) k = prefix + "." + k
-
- // already including NODETAR.type, don't need File=true also
- if (k === fields.type && val === true) return
-
- switch (k) {
- // don't include anything that's always handled just fine
- // in the normal header, or only meaningful in the context
- // of nodetar
- case "mode":
- case "cksum":
- case "ustar":
- case "ustarver":
- case "prefix":
- case "basename":
- case "dirname":
- case "needExtended":
- case "block":
- case "filter":
- return
-
- case "rdev":
- if (val === 0) return
- break
-
- case "nlink":
- case "dev": // Truly a hero among men, Creator of Star!
- case "ino": // Speak his name with reverent awe! It is:
- k = "SCHILY." + k
- break
-
- default: break
- }
-
- if (val && typeof val === "object" &&
- !Buffer.isBuffer(val)) encodeFields(val, k, body, nop)
- else if (val === null || val === undefined) return
- else body.push.apply(body, encodeField(k, val, nop))
- })
-
- return body
-}
-
-function encodeField (k, v, nop) {
- // lowercase keys must be valid, otherwise prefix with
- // "NODETAR."
- if (k.charAt(0) === k.charAt(0).toLowerCase()) {
- var m = k.split(".")[0]
- if (!tar.knownExtended[m]) k = "NODETAR." + k
- }
-
- // no proprietary
- if (nop && k.charAt(0) !== k.charAt(0).toLowerCase()) {
- return []
- }
-
- if (typeof val === "number") val = val.toString(10)
-
- var s = new Buffer(" " + k + "=" + v + "\n")
- , digits = Math.floor(Math.log(s.length) / Math.log(10)) + 1
-
- // console.error("1 s=%j digits=%j s.length=%d", s.toString(), digits, s.length)
-
- // if adding that many digits will make it go over that length,
- // then add one to it. For example, if the string is:
- // " foo=bar\n"
- // then that's 9 characters. With the "9", that bumps the length
- // up to 10. However, this is invalid:
- // "10 foo=bar\n"
- // but, since that's actually 11 characters, since 10 adds another
- // character to the length, and the length includes the number
- // itself. In that case, just bump it up again.
- if (s.length + digits >= Math.pow(10, digits)) digits += 1
- // console.error("2 s=%j digits=%j s.length=%d", s.toString(), digits, s.length)
-
- var len = digits + s.length
- // console.error("3 s=%j digits=%j s.length=%d len=%d", s.toString(), digits, s.length, len)
- var lenBuf = new Buffer("" + len)
- if (lenBuf.length + s.length !== len) {
- throw new Error("Bad length calculation\n"+
- "len="+len+"\n"+
- "lenBuf="+JSON.stringify(lenBuf.toString())+"\n"+
- "lenBuf.length="+lenBuf.length+"\n"+
- "digits="+digits+"\n"+
- "s="+JSON.stringify(s.toString())+"\n"+
- "s.length="+s.length)
- }
-
- return [lenBuf, s]
-}
diff --git a/deps/npm/node_modules/tar/lib/extended-header.js b/deps/npm/node_modules/tar/lib/extended-header.js
deleted file mode 100644
index 74f432ceee..0000000000
--- a/deps/npm/node_modules/tar/lib/extended-header.js
+++ /dev/null
@@ -1,140 +0,0 @@
-// An Entry consisting of:
-//
-// "%d %s=%s\n", <length>, <keyword>, <value>
-//
-// The length is a decimal number, and includes itself and the \n
-// \0 does not terminate anything. Only the length terminates the string.
-// Numeric values are decimal strings.
-
-module.exports = ExtendedHeader
-
-var Entry = require("./entry.js")
- , inherits = require("inherits")
- , tar = require("../tar.js")
- , numeric = tar.numeric
- , keyTrans = { "SCHILY.dev": "dev"
- , "SCHILY.ino": "ino"
- , "SCHILY.nlink": "nlink" }
-
-function ExtendedHeader () {
- Entry.apply(this, arguments)
- this.on("data", this._parse)
- this.fields = {}
- this._position = 0
- this._fieldPos = 0
- this._state = SIZE
- this._sizeBuf = []
- this._keyBuf = []
- this._valBuf = []
- this._size = -1
- this._key = ""
-}
-
-inherits(ExtendedHeader, Entry)
-ExtendedHeader.prototype._parse = parse
-
-var s = 0
- , states = ExtendedHeader.states = {}
- , SIZE = states.SIZE = s++
- , KEY = states.KEY = s++
- , VAL = states.VAL = s++
- , ERR = states.ERR = s++
-
-Object.keys(states).forEach(function (s) {
- states[states[s]] = states[s]
-})
-
-states[s] = null
-
-// char code values for comparison
-var _0 = "0".charCodeAt(0)
- , _9 = "9".charCodeAt(0)
- , point = ".".charCodeAt(0)
- , a = "a".charCodeAt(0)
- , Z = "Z".charCodeAt(0)
- , a = "a".charCodeAt(0)
- , z = "z".charCodeAt(0)
- , space = " ".charCodeAt(0)
- , eq = "=".charCodeAt(0)
- , cr = "\n".charCodeAt(0)
-
-function parse (c) {
- if (this._state === ERR) return
-
- for ( var i = 0, l = c.length
- ; i < l
- ; this._position++, this._fieldPos++, i++) {
- // console.error("top of loop, size="+this._size)
-
- var b = c[i]
-
- if (this._size >= 0 && this._fieldPos > this._size) {
- error(this, "field exceeds length="+this._size)
- return
- }
-
- switch (this._state) {
- case ERR: return
-
- case SIZE:
- // console.error("parsing size, b=%d, rest=%j", b, c.slice(i).toString())
- if (b === space) {
- this._state = KEY
- // this._fieldPos = this._sizeBuf.length
- this._size = parseInt(new Buffer(this._sizeBuf).toString(), 10)
- this._sizeBuf.length = 0
- continue
- }
- if (b < _0 || b > _9) {
- error(this, "expected [" + _0 + ".." + _9 + "], got " + b)
- return
- }
- this._sizeBuf.push(b)
- continue
-
- case KEY:
- // can be any char except =, not > size.
- if (b === eq) {
- this._state = VAL
- this._key = new Buffer(this._keyBuf).toString()
- if (keyTrans[this._key]) this._key = keyTrans[this._key]
- this._keyBuf.length = 0
- continue
- }
- this._keyBuf.push(b)
- continue
-
- case VAL:
- // field must end with cr
- if (this._fieldPos === this._size - 1) {
- // console.error("finished with "+this._key)
- if (b !== cr) {
- error(this, "expected \\n at end of field")
- return
- }
- var val = new Buffer(this._valBuf).toString()
- if (numeric[this._key]) {
- val = parseFloat(val)
- }
- this.fields[this._key] = val
-
- this._valBuf.length = 0
- this._state = SIZE
- this._size = -1
- this._fieldPos = -1
- continue
- }
- this._valBuf.push(b)
- continue
- }
- }
-}
-
-function error (me, msg) {
- msg = "invalid header: " + msg
- + "\nposition=" + me._position
- + "\nfield position=" + me._fieldPos
-
- me.error(msg)
- me.state = ERR
-}
diff --git a/deps/npm/node_modules/tar/lib/extract.js b/deps/npm/node_modules/tar/lib/extract.js
index fe1bb976eb..53ecf67894 100644
--- a/deps/npm/node_modules/tar/lib/extract.js
+++ b/deps/npm/node_modules/tar/lib/extract.js
@@ -1,94 +1,127 @@
-// give it a tarball and a path, and it'll dump the contents
+'use strict'
-module.exports = Extract
+// tar -x
+const hlo = require('./high-level-opt.js')
+const Unpack = require('./unpack.js')
+const fs = require('fs')
+const path = require('path')
-var tar = require("../tar.js")
- , fstream = require("fstream")
- , inherits = require("inherits")
- , path = require("path")
+const x = module.exports = (opt_, files, cb) => {
+ if (typeof opt_ === 'function')
+ cb = opt_, files = null, opt_ = {}
+ else if (Array.isArray(opt_))
+ files = opt_, opt_ = {}
-function Extract (opts) {
- if (!(this instanceof Extract)) return new Extract(opts)
- tar.Parse.apply(this)
+ if (typeof files === 'function')
+ cb = files, files = null
- if (typeof opts !== "object") {
- opts = { path: opts }
- }
+ if (!files)
+ files = []
+ else
+ files = Array.from(files)
- // better to drop in cwd? seems more standard.
- opts.path = opts.path || path.resolve("node-tar-extract")
- opts.type = "Directory"
- opts.Directory = true
-
- // similar to --strip or --strip-components
- opts.strip = +opts.strip
- if (!opts.strip || opts.strip <= 0) opts.strip = 0
-
- this._fst = fstream.Writer(opts)
-
- this.pause()
- var me = this
-
- // Hardlinks in tarballs are relative to the root
- // of the tarball. So, they need to be resolved against
- // the target directory in order to be created properly.
- me.on("entry", function (entry) {
- // if there's a "strip" argument, then strip off that many
- // path components.
- if (opts.strip) {
- var p = entry.path.split("/").slice(opts.strip).join("/")
- entry.path = entry.props.path = p
- if (entry.linkpath) {
- var lp = entry.linkpath.split("/").slice(opts.strip).join("/")
- entry.linkpath = entry.props.linkpath = lp
- }
- }
- if (entry.type === "Link") {
- entry.linkpath = entry.props.linkpath =
- path.join(opts.path, path.join("/", entry.props.linkpath))
- }
+ const opt = hlo(opt_)
- if (entry.type === "SymbolicLink") {
- var dn = path.dirname(entry.path) || ""
- var linkpath = entry.props.linkpath
- var target = path.resolve(opts.path, dn, linkpath)
- if (target.indexOf(opts.path) !== 0) {
- linkpath = path.join(opts.path, path.join("/", linkpath))
- }
- entry.linkpath = entry.props.linkpath = linkpath
- }
- })
+ if (opt.sync && typeof cb === 'function')
+ throw new TypeError('callback not supported for sync tar functions')
- this._fst.on("ready", function () {
- me.pipe(me._fst, { end: false })
- me.resume()
- })
+ if (!opt.file && typeof cb === 'function')
+ throw new TypeError('callback only supported with file option')
- this._fst.on('error', function(err) {
- me.emit('error', err)
- })
+ if (files.length)
+ filesFilter(opt, files)
- this._fst.on('drain', function() {
- me.emit('drain')
- })
+ return opt.file && opt.sync ? extractFileSync(opt)
+ : opt.file ? extractFile(opt, cb)
+ : opt.sync ? extractSync(opt)
+ : extract(opt)
+}
+
+// construct a filter that limits the file entries listed
+// include child entries if a dir is included
+const filesFilter = (opt, files) => {
+ const map = new Map(files.map(f => [f.replace(/\/+$/, ''), true]))
+ const filter = opt.filter
- // this._fst.on("end", function () {
- // console.error("\nEEEE Extract End", me._fst.path)
- // })
+ const mapHas = (file, r) => {
+ const root = r || path.parse(file).root || '.'
+ const ret = file === root ? false
+ : map.has(file) ? map.get(file)
+ : mapHas(path.dirname(file), root)
- this._fst.on("close", function () {
- // console.error("\nEEEE Extract End", me._fst.path)
- me.emit("finish")
- me.emit("end")
- me.emit("close")
+ map.set(file, ret)
+ return ret
+ }
+
+ opt.filter = filter
+ ? (file, entry) => filter(file, entry) && mapHas(file.replace(/\/+$/, ''))
+ : file => mapHas(file.replace(/\/+$/, ''))
+}
+
+const extractFileSync = opt => {
+ const u = new Unpack.Sync(opt)
+
+ const file = opt.file
+ let threw = true
+ let fd
+ try {
+ const stat = fs.statSync(file)
+ const readSize = opt.maxReadSize || 16*1024*1024
+ if (stat.size < readSize)
+ u.end(fs.readFileSync(file))
+ else {
+ let pos = 0
+ const buf = Buffer.allocUnsafe(readSize)
+ fd = fs.openSync(file, 'r')
+ while (pos < stat.size) {
+ let bytesRead = fs.readSync(fd, buf, 0, readSize, pos)
+ pos += bytesRead
+ u.write(buf.slice(0, bytesRead))
+ }
+ u.end()
+ fs.closeSync(fd)
+ }
+ threw = false
+ } finally {
+ if (threw && fd)
+ try { fs.closeSync(fd) } catch (er) {}
+ }
+}
+
+const extractFile = (opt, cb) => {
+ const u = new Unpack(opt)
+ const readSize = opt.maxReadSize || 16*1024*1024
+
+ const file = opt.file
+ const p = new Promise((resolve, reject) => {
+ u.on('error', reject)
+ u.on('close', resolve)
+
+ fs.stat(file, (er, stat) => {
+ if (er)
+ reject(er)
+ else if (stat.size < readSize)
+ fs.readFile(file, (er, data) => {
+ if (er)
+ return reject(er)
+ u.end(data)
+ })
+ else {
+ const stream = fs.createReadStream(file, {
+ highWaterMark: readSize
+ })
+ stream.on('error', reject)
+ stream.pipe(u)
+ }
+ })
})
+ return cb ? p.then(cb, cb) : p
}
-inherits(Extract, tar.Parse)
+const extractSync = opt => {
+ return new Unpack.Sync(opt)
+}
-Extract.prototype._streamEnd = function () {
- var me = this
- if (!me._ended || me._entry) me.error("unexpected eof")
- me._fst.end()
- // my .end() is coming later.
+const extract = opt => {
+ return new Unpack(opt)
}
diff --git a/deps/npm/node_modules/tar/lib/global-header-writer.js b/deps/npm/node_modules/tar/lib/global-header-writer.js
deleted file mode 100644
index 0bfc7b80aa..0000000000
--- a/deps/npm/node_modules/tar/lib/global-header-writer.js
+++ /dev/null
@@ -1,14 +0,0 @@
-module.exports = GlobalHeaderWriter
-
-var ExtendedHeaderWriter = require("./extended-header-writer.js")
- , inherits = require("inherits")
-
-inherits(GlobalHeaderWriter, ExtendedHeaderWriter)
-
-function GlobalHeaderWriter (props) {
- if (!(this instanceof GlobalHeaderWriter)) {
- return new GlobalHeaderWriter(props)
- }
- ExtendedHeaderWriter.call(this, props)
- this.props.type = "g"
-}
diff --git a/deps/npm/node_modules/tar/lib/header.js b/deps/npm/node_modules/tar/lib/header.js
index 05b237c0c7..db002e8c18 100644
--- a/deps/npm/node_modules/tar/lib/header.js
+++ b/deps/npm/node_modules/tar/lib/header.js
@@ -1,385 +1,272 @@
+'use strict'
// parse a 512-byte header block to a data object, or vice-versa
-// If the data won't fit nicely in a simple header, then generate
-// the appropriate extended header file, and return that.
-
-module.exports = TarHeader
-
-var tar = require("../tar.js")
- , fields = tar.fields
- , fieldOffs = tar.fieldOffs
- , fieldEnds = tar.fieldEnds
- , fieldSize = tar.fieldSize
- , numeric = tar.numeric
- , assert = require("assert").ok
- , space = " ".charCodeAt(0)
- , slash = "/".charCodeAt(0)
- , bslash = process.platform === "win32" ? "\\".charCodeAt(0) : null
-
-function TarHeader (block) {
- if (!(this instanceof TarHeader)) return new TarHeader(block)
- if (block) this.decode(block)
-}
-
-TarHeader.prototype =
- { decode : decode
- , encode: encode
- , calcSum: calcSum
- , checkSum: checkSum
+// encode returns `true` if a pax extended header is needed, because
+// the data could not be faithfully encoded in a simple header.
+// (Also, check header.needPax to see if it needs a pax header.)
+
+const types = require('./types.js')
+const pathModule = require('path')
+const large = require('./large-numbers.js')
+
+const TYPE = Symbol('type')
+
+class Header {
+ constructor (data, off) {
+ this.cksumValid = false
+ this.needPax = false
+ this.nullBlock = false
+
+ this.block = null
+ this.path = null
+ this.mode = null
+ this.uid = null
+ this.gid = null
+ this.size = null
+ this.mtime = null
+ this.cksum = null
+ this[TYPE] = '0'
+ this.linkpath = null
+ this.uname = null
+ this.gname = null
+ this.devmaj = 0
+ this.devmin = 0
+ this.atime = null
+ this.ctime = null
+
+ if (Buffer.isBuffer(data)) {
+ this.decode(data, off || 0)
+ } else if (data)
+ this.set(data)
}
-TarHeader.parseNumeric = parseNumeric
-TarHeader.encode = encode
-TarHeader.decode = decode
-
-// note that this will only do the normal ustar header, not any kind
-// of extended posix header file. If something doesn't fit comfortably,
-// then it will set obj.needExtended = true, and set the block to
-// the closest approximation.
-function encode (obj) {
- if (!obj && !(this instanceof TarHeader)) throw new Error(
- "encode must be called on a TarHeader, or supplied an object")
-
- obj = obj || this
- var block = obj.block = new Buffer(512)
-
- // if the object has a "prefix", then that's actually an extension of
- // the path field.
- if (obj.prefix) {
- // console.error("%% header encoding, got a prefix", obj.prefix)
- obj.path = obj.prefix + "/" + obj.path
- // console.error("%% header encoding, prefixed path", obj.path)
- obj.prefix = ""
- }
-
- obj.needExtended = false
-
- if (obj.mode) {
- if (typeof obj.mode === "string") obj.mode = parseInt(obj.mode, 8)
- obj.mode = obj.mode & 0777
- }
+ decode (buf, off) {
+ if (!off)
+ off = 0
+
+ if (!buf || !(buf.length >= off + 512))
+ throw new Error('need 512 bytes for header')
+
+ this.path = decString(buf, off, 100)
+ this.mode = decNumber(buf, off + 100, 8)
+ this.uid = decNumber(buf, off + 108, 8)
+ this.gid = decNumber(buf, off + 116, 8)
+ this.size = decNumber(buf, off + 124, 12)
+ this.mtime = decDate(buf, off + 136, 12)
+ this.cksum = decNumber(buf, off + 148, 12)
+
+ // old tar versions marked dirs as a file with a trailing /
+ this[TYPE] = decString(buf, off + 156, 1)
+ if (this[TYPE] === '')
+ this[TYPE] = '0'
+ if (this[TYPE] === '0' && this.path.substr(-1) === '/')
+ this[TYPE] = '5'
+
+ // tar implementations sometimes incorrectly put the stat(dir).size
+ // as the size in the tarball, even though Directory entries are
+ // not able to have any body at all. In the very rare chance that
+ // it actually DOES have a body, we weren't going to do anything with
+ // it anyway, and it'll just be a warning about an invalid header.
+ if (this[TYPE] === '5')
+ this.size = 0
+
+ this.linkpath = decString(buf, off + 157, 100)
+ if (buf.slice(off + 257, off + 265).toString() === 'ustar\u000000') {
+ this.uname = decString(buf, off + 265, 32)
+ this.gname = decString(buf, off + 297, 32)
+ this.devmaj = decNumber(buf, off + 329, 8)
+ this.devmin = decNumber(buf, off + 337, 8)
+ if (buf[off + 475] !== 0) {
+ // definitely a prefix, definitely >130 chars.
+ const prefix = decString(buf, off + 345, 155)
+ this.path = prefix + '/' + this.path
+ } else {
+ const prefix = decString(buf, off + 345, 130)
+ if (prefix)
+ this.path = prefix + '/' + this.path
+ this.atime = decDate(buf, off + 476, 12)
+ this.ctime = decDate(buf, off + 488, 12)
+ }
+ }
- for (var f = 0; fields[f] !== null; f ++) {
- var field = fields[f]
- , off = fieldOffs[f]
- , end = fieldEnds[f]
- , ret
-
- switch (field) {
- case "cksum":
- // special, done below, after all the others
- break
-
- case "prefix":
- // special, this is an extension of the "path" field.
- // console.error("%% header encoding, skip prefix later")
- break
-
- case "type":
- // convert from long name to a single char.
- var type = obj.type || "0"
- if (type.length > 1) {
- type = tar.types[obj.type]
- if (!type) type = "0"
- }
- writeText(block, off, end, type)
- break
-
- case "path":
- // uses the "prefix" field if > 100 bytes, but <= 255
- var pathLen = Buffer.byteLength(obj.path)
- , pathFSize = fieldSize[fields.path]
- , prefFSize = fieldSize[fields.prefix]
-
- // paths between 100 and 255 should use the prefix field.
- // longer than 255
- if (pathLen > pathFSize &&
- pathLen <= pathFSize + prefFSize) {
- // need to find a slash somewhere in the middle so that
- // path and prefix both fit in their respective fields
- var searchStart = pathLen - 1 - pathFSize
- , searchEnd = prefFSize
- , found = false
- , pathBuf = new Buffer(obj.path)
-
- for ( var s = searchStart
- ; (s <= searchEnd)
- ; s ++ ) {
- if (pathBuf[s] === slash || pathBuf[s] === bslash) {
- found = s
- break
- }
- }
-
- if (found !== false) {
- prefix = pathBuf.slice(0, found).toString("utf8")
- path = pathBuf.slice(found + 1).toString("utf8")
-
- ret = writeText(block, off, end, path)
- off = fieldOffs[fields.prefix]
- end = fieldEnds[fields.prefix]
- // console.error("%% header writing prefix", off, end, prefix)
- ret = writeText(block, off, end, prefix) || ret
- break
- }
- }
-
- // paths less than 100 chars don't need a prefix
- // and paths longer than 255 need an extended header and will fail
- // on old implementations no matter what we do here.
- // Null out the prefix, and fallthrough to default.
- // console.error("%% header writing no prefix")
- var poff = fieldOffs[fields.prefix]
- , pend = fieldEnds[fields.prefix]
- writeText(block, poff, pend, "")
- // fallthrough
-
- // all other fields are numeric or text
- default:
- ret = numeric[field]
- ? writeNumeric(block, off, end, obj[field])
- : writeText(block, off, end, obj[field] || "")
- break
+ let sum = 8 * 0x20
+ for (let i = off; i < off + 148; i++) {
+ sum += buf[i]
+ }
+ for (let i = off + 156; i < off + 512; i++) {
+ sum += buf[i]
}
- obj.needExtended = obj.needExtended || ret
+ this.cksumValid = sum === this.cksum
+ if (this.cksum === null && sum === 8 * 0x20)
+ this.nullBlock = true
}
- var off = fieldOffs[fields.cksum]
- , end = fieldEnds[fields.cksum]
-
- writeNumeric(block, off, end, calcSum.call(this, block))
+ encode (buf, off) {
+ if (!buf) {
+ buf = this.block = Buffer.alloc(512)
+ off = 0
+ }
- return block
-}
+ if (!off)
+ off = 0
+
+ if (!(buf.length >= off + 512))
+ throw new Error('need 512 bytes for header')
+
+ const prefixSize = this.ctime || this.atime ? 130 : 155
+ const split = splitPrefix(this.path || '', prefixSize)
+ const path = split[0]
+ const prefix = split[1]
+ this.needPax = split[2]
+
+ this.needPax = encString(buf, off, 100, path) || this.needPax
+ this.needPax = encNumber(buf, off + 100, 8, this.mode) || this.needPax
+ this.needPax = encNumber(buf, off + 108, 8, this.uid) || this.needPax
+ this.needPax = encNumber(buf, off + 116, 8, this.gid) || this.needPax
+ this.needPax = encNumber(buf, off + 124, 12, this.size) || this.needPax
+ this.needPax = encDate(buf, off + 136, 12, this.mtime) || this.needPax
+ buf[off + 156] = this[TYPE].charCodeAt(0)
+ this.needPax = encString(buf, off + 157, 100, this.linkpath) || this.needPax
+ buf.write('ustar\u000000', off + 257, 8)
+ this.needPax = encString(buf, off + 265, 32, this.uname) || this.needPax
+ this.needPax = encString(buf, off + 297, 32, this.gname) || this.needPax
+ this.needPax = encNumber(buf, off + 329, 8, this.devmaj) || this.needPax
+ this.needPax = encNumber(buf, off + 337, 8, this.devmin) || this.needPax
+ this.needPax = encString(buf, off + 345, prefixSize, prefix) || this.needPax
+ if (buf[off + 475] !== 0)
+ this.needPax = encString(buf, off + 345, 155, prefix) || this.needPax
+ else {
+ this.needPax = encString(buf, off + 345, 130, prefix) || this.needPax
+ this.needPax = encDate(buf, off + 476, 12, this.atime) || this.needPax
+ this.needPax = encDate(buf, off + 488, 12, this.ctime) || this.needPax
+ }
-// if it's a negative number, or greater than will fit,
-// then use write256.
-var MAXNUM = { 12: 077777777777
- , 11: 07777777777
- , 8 : 07777777
- , 7 : 0777777 }
-function writeNumeric (block, off, end, num) {
- var writeLen = end - off
- , maxNum = MAXNUM[writeLen] || 0
-
- num = num || 0
- // console.error(" numeric", num)
-
- if (num instanceof Date ||
- Object.prototype.toString.call(num) === "[object Date]") {
- num = num.getTime() / 1000
- }
+ let sum = 8 * 0x20
+ for (let i = off; i < off + 148; i++) {
+ sum += buf[i]
+ }
+ for (let i = off + 156; i < off + 512; i++) {
+ sum += buf[i]
+ }
+ this.cksum = sum
+ encNumber(buf, off + 148, 8, this.cksum)
+ this.cksumValid = true
- if (num > maxNum || num < 0) {
- write256(block, off, end, num)
- // need an extended header if negative or too big.
- return true
+ return this.needPax
}
- // god, tar is so annoying
- // if the string is small enough, you should put a space
- // between the octal string and the \0, but if it doesn't
- // fit, then don't.
- var numStr = Math.floor(num).toString(8)
- if (num < MAXNUM[writeLen - 1]) numStr += " "
-
- // pad with "0" chars
- if (numStr.length < writeLen) {
- numStr = (new Array(writeLen - numStr.length).join("0")) + numStr
+ set (data) {
+ for (let i in data) {
+ if (data[i] !== null && data[i] !== undefined)
+ this[i] = data[i]
+ }
}
- if (numStr.length !== writeLen - 1) {
- throw new Error("invalid length: " + JSON.stringify(numStr) + "\n" +
- "expected: "+writeLen)
+ get type () {
+ return types.name.get(this[TYPE]) || this[TYPE]
}
- block.write(numStr, off, writeLen, "utf8")
- block[end - 1] = 0
-}
-function write256 (block, off, end, num) {
- var buf = block.slice(off, end)
- var positive = num >= 0
- buf[0] = positive ? 0x80 : 0xFF
-
- // get the number as a base-256 tuple
- if (!positive) num *= -1
- var tuple = []
- do {
- var n = num % 256
- tuple.push(n)
- num = (num - n) / 256
- } while (num)
-
- var bytes = tuple.length
-
- var fill = buf.length - bytes
- for (var i = 1; i < fill; i ++) {
- buf[i] = positive ? 0 : 0xFF
+ get typeKey () {
+ return this[TYPE]
}
- // tuple is a base256 number, with [0] as the *least* significant byte
- // if it's negative, then we need to flip all the bits once we hit the
- // first non-zero bit. The 2's-complement is (0x100 - n), and the 1's-
- // complement is (0xFF - n).
- var zero = true
- for (i = bytes; i > 0; i --) {
- var byte = tuple[bytes - i]
- if (positive) buf[fill + i] = byte
- else if (zero && byte === 0) buf[fill + i] = 0
- else if (zero) {
- zero = false
- buf[fill + i] = 0x100 - byte
- } else buf[fill + i] = 0xFF - byte
+ set type (type) {
+ if (types.code.has(type))
+ this[TYPE] = types.code.get(type)
+ else
+ this[TYPE] = type
}
}
-function writeText (block, off, end, str) {
- // strings are written as utf8, then padded with \0
- var strLen = Buffer.byteLength(str)
- , writeLen = Math.min(strLen, end - off)
- // non-ascii fields need extended headers
- // long fields get truncated
- , needExtended = strLen !== str.length || strLen > writeLen
-
- // write the string, and null-pad
- if (writeLen > 0) block.write(str, off, writeLen, "utf8")
- for (var i = off + writeLen; i < end; i ++) block[i] = 0
-
- return needExtended
-}
-
-function calcSum (block) {
- block = block || this.block
- assert(Buffer.isBuffer(block) && block.length === 512)
-
- if (!block) throw new Error("Need block to checksum")
-
- // now figure out what it would be if the cksum was " "
- var sum = 0
- , start = fieldOffs[fields.cksum]
- , end = fieldEnds[fields.cksum]
-
- for (var i = 0; i < fieldOffs[fields.cksum]; i ++) {
- sum += block[i]
+const splitPrefix = (p, prefixSize) => {
+ const pathSize = 100
+ let pp = p
+ let prefix = ''
+ let ret
+ const root = pathModule.parse(p).root || '.'
+
+ if (Buffer.byteLength(pp) < pathSize)
+ ret = [pp, prefix, false]
+ else {
+ // first set prefix to the dir, and path to the base
+ prefix = pathModule.dirname(pp)
+ pp = pathModule.basename(pp)
+
+ do {
+ // both fit!
+ if (Buffer.byteLength(pp) <= pathSize &&
+ Buffer.byteLength(prefix) <= prefixSize)
+ ret = [pp, prefix, false]
+
+ // prefix fits in prefix, but path doesn't fit in path
+ else if (Buffer.byteLength(pp) > pathSize &&
+ Buffer.byteLength(prefix) <= prefixSize)
+ ret = [pp.substr(0, pathSize - 1), prefix, true]
+
+ else {
+ // make path take a bit from prefix
+ pp = pathModule.join(pathModule.basename(prefix), pp)
+ prefix = pathModule.dirname(prefix)
+ }
+ } while (prefix !== root && !ret)
+
+ // at this point, found no resolution, just truncate
+ if (!ret)
+ ret = [p.substr(0, pathSize - 1), '', true]
}
-
- for (var i = start; i < end; i ++) {
- sum += space
- }
-
- for (var i = end; i < 512; i ++) {
- sum += block[i]
- }
-
- return sum
+ return ret
}
+const decString = (buf, off, size) =>
+ buf.slice(off, off + size).toString('utf8').replace(/\0.*/, '')
-function checkSum (block) {
- var sum = calcSum.call(this, block)
- block = block || this.block
+const decDate = (buf, off, size) =>
+ numToDate(decNumber(buf, off, size))
- var cksum = block.slice(fieldOffs[fields.cksum], fieldEnds[fields.cksum])
- cksum = parseNumeric(cksum)
+const numToDate = num => num === null ? null : new Date(num * 1000)
- return cksum === sum
-}
+const decNumber = (buf, off, size) =>
+ buf[off] & 0x80 ? large.parse(buf.slice(off, off + size))
+ : decSmallNumber(buf, off, size)
-function decode (block) {
- block = block || this.block
- assert(Buffer.isBuffer(block) && block.length === 512)
-
- this.block = block
- this.cksumValid = this.checkSum()
-
- var prefix = null
-
- // slice off each field.
- for (var f = 0; fields[f] !== null; f ++) {
- var field = fields[f]
- , val = block.slice(fieldOffs[f], fieldEnds[f])
-
- switch (field) {
- case "ustar":
- // if not ustar, then everything after that is just padding.
- if (val.toString() !== "ustar\0") {
- this.ustar = false
- return
- } else {
- // console.error("ustar:", val, val.toString())
- this.ustar = val.toString()
- }
- break
-
- // prefix is special, since it might signal the xstar header
- case "prefix":
- var atime = parseNumeric(val.slice(131, 131 + 12))
- , ctime = parseNumeric(val.slice(131 + 12, 131 + 12 + 12))
- if ((val[130] === 0 || val[130] === space) &&
- typeof atime === "number" &&
- typeof ctime === "number" &&
- val[131 + 12] === space &&
- val[131 + 12 + 12] === space) {
- this.atime = atime
- this.ctime = ctime
- val = val.slice(0, 130)
- }
- prefix = val.toString("utf8").replace(/\0+$/, "")
- // console.error("%% header reading prefix", prefix)
- break
-
- // all other fields are null-padding text
- // or a number.
- default:
- if (numeric[field]) {
- this[field] = parseNumeric(val)
- } else {
- this[field] = val.toString("utf8").replace(/\0+$/, "")
- }
- break
- }
- }
+const nanNull = value => isNaN(value) ? null : value
- // if we got a prefix, then prepend it to the path.
- if (prefix) {
- this.path = prefix + "/" + this.path
- // console.error("%% header got a prefix", this.path)
- }
+const decSmallNumber = (buf, off, size) =>
+ nanNull(parseInt(
+ buf.slice(off, off + size)
+ .toString('utf8').replace(/\0.*$/, '').trim(), 8))
+
+// the maximum encodable as a null-terminated octal, by field size
+const MAXNUM = {
+ 12: 0o77777777777,
+ 8 : 0o7777777
}
-function parse256 (buf) {
- // first byte MUST be either 80 or FF
- // 80 for positive, FF for 2's comp
- var positive
- if (buf[0] === 0x80) positive = true
- else if (buf[0] === 0xFF) positive = false
- else return null
-
- // build up a base-256 tuple from the least sig to the highest
- var zero = false
- , tuple = []
- for (var i = buf.length - 1; i > 0; i --) {
- var byte = buf[i]
- if (positive) tuple.push(byte)
- else if (zero && byte === 0) tuple.push(0)
- else if (zero) {
- zero = false
- tuple.push(0x100 - byte)
- } else tuple.push(0xFF - byte)
- }
+const encNumber = (buf, off, size, number) =>
+ number === null ? false :
+ number > MAXNUM[size] || number < 0
+ ? (large.encode(number, buf.slice(off, off + size)), true)
+ : (encSmallNumber(buf, off, size, number), false)
- for (var sum = 0, i = 0, l = tuple.length; i < l; i ++) {
- sum += tuple[i] * Math.pow(256, i)
- }
+const encSmallNumber = (buf, off, size, number) =>
+ buf.write(octalString(number, size), off, size, 'ascii')
- return positive ? sum : -1 * sum
-}
+const octalString = (number, size) =>
+ padOctal(Math.floor(number).toString(8), size)
-function parseNumeric (f) {
- if (f[0] & 0x80) return parse256(f)
+const padOctal = (string, size) =>
+ (string.length === size - 1 ? string
+ : new Array(size - string.length - 1).join('0') + string + ' ') + '\0'
- var str = f.toString("utf8").split("\0")[0].trim()
- , res = parseInt(str, 8)
+const encDate = (buf, off, size, date) =>
+ date === null ? false :
+ encNumber(buf, off, size, date.getTime() / 1000)
- return isNaN(res) ? null : res
-}
+// enough to fill the longest string we've got
+const NULLS = new Array(156).join('\0')
+// pad with nulls, return true if it's longer or non-ascii
+const encString = (buf, off, size, string) =>
+ string === null ? false :
+ (buf.write(string + NULLS, off, size, 'utf8'),
+ string.length !== Buffer.byteLength(string) || string.length > size)
+module.exports = Header
diff --git a/deps/npm/node_modules/tar/lib/high-level-opt.js b/deps/npm/node_modules/tar/lib/high-level-opt.js
new file mode 100644
index 0000000000..7333db915c
--- /dev/null
+++ b/deps/npm/node_modules/tar/lib/high-level-opt.js
@@ -0,0 +1,29 @@
+'use strict'
+
+// turn tar(1) style args like `C` into the more verbose things like `cwd`
+
+const argmap = new Map([
+ ['C', 'cwd'],
+ ['f', 'file'],
+ ['z', 'gzip'],
+ ['P', 'preservePaths'],
+ ['U', 'unlink'],
+ ['strip-components', 'strip'],
+ ['stripComponents', 'strip'],
+ ['keep-newer', 'newer'],
+ ['keepNewer', 'newer'],
+ ['keep-newer-files', 'newer'],
+ ['keepNewerFiles', 'newer'],
+ ['k', 'keep'],
+ ['keep-existing', 'keep'],
+ ['keepExisting', 'keep'],
+ ['m', 'noMtime'],
+ ['no-mtime', 'noMtime'],
+ ['p', 'preserveOwner'],
+ ['L', 'follow'],
+ ['h', 'follow']
+])
+
+const parse = module.exports = opt => opt ? Object.keys(opt).map(k => [
+ argmap.has(k) ? argmap.get(k) : k, opt[k]
+]).reduce((set, kv) => (set[kv[0]] = kv[1], set), Object.create(null)) : {}
diff --git a/deps/npm/node_modules/tar/lib/large-numbers.js b/deps/npm/node_modules/tar/lib/large-numbers.js
new file mode 100644
index 0000000000..ff49992630
--- /dev/null
+++ b/deps/npm/node_modules/tar/lib/large-numbers.js
@@ -0,0 +1,92 @@
+'use strict'
+// Tar can encode large and negative numbers using a leading byte of
+// 0xff for negative, and 0x80 for positive. The trailing byte in the
+// section will always be 0x20, or in some implementations 0x00.
+// this module encodes and decodes these things.
+
+const encode = exports.encode = (num, buf) => {
+ buf[buf.length - 1] = 0x20
+ if (num < 0)
+ encodeNegative(num, buf)
+ else
+ encodePositive(num, buf)
+ return buf
+}
+
+const encodePositive = (num, buf) => {
+ buf[0] = 0x80
+ for (var i = buf.length - 2; i > 0; i--) {
+ if (num === 0)
+ buf[i] = 0
+ else {
+ buf[i] = num % 0x100
+ num = Math.floor(num / 0x100)
+ }
+ }
+}
+
+const encodeNegative = (num, buf) => {
+ buf[0] = 0xff
+ var flipped = false
+ num = num * -1
+ for (var i = buf.length - 2; i > 0; i--) {
+ var byte
+ if (num === 0)
+ byte = 0
+ else {
+ byte = num % 0x100
+ num = Math.floor(num / 0x100)
+ }
+ if (flipped)
+ buf[i] = onesComp(byte)
+ else if (byte === 0)
+ buf[i] = 0
+ else {
+ flipped = true
+ buf[i] = twosComp(byte)
+ }
+ }
+}
+
+const parse = exports.parse = (buf) => {
+ var post = buf[buf.length - 1]
+ var pre = buf[0]
+ return pre === 0x80 ? pos(buf.slice(1, buf.length - 1))
+ : twos(buf.slice(1, buf.length - 1))
+}
+
+const twos = (buf) => {
+ var len = buf.length
+ var sum = 0
+ var flipped = false
+ for (var i = len - 1; i > -1; i--) {
+ var byte = buf[i]
+ var f
+ if (flipped)
+ f = onesComp(byte)
+ else if (byte === 0)
+ f = byte
+ else {
+ flipped = true
+ f = twosComp(byte)
+ }
+ if (f !== 0)
+ sum += f * Math.pow(256, len - i - 1)
+ }
+ return sum * -1
+}
+
+const pos = (buf) => {
+ var len = buf.length
+ var sum = 0
+ for (var i = len - 1; i > -1; i--) {
+ var byte = buf[i]
+ if (byte !== 0)
+ sum += byte * Math.pow(256, len - i - 1)
+ }
+ return sum
+}
+
+const onesComp = byte => (0xff ^ byte) & 0xff
+
+const twosComp = byte => ((0xff ^ byte) + 1) & 0xff
diff --git a/deps/npm/node_modules/tar/lib/list.js b/deps/npm/node_modules/tar/lib/list.js
new file mode 100644
index 0000000000..1f5e70bd36
--- /dev/null
+++ b/deps/npm/node_modules/tar/lib/list.js
@@ -0,0 +1,132 @@
+'use strict'
+
+// XXX: This shares a lot in common with extract.js
+// maybe some DRY opportunity here?
+
+// tar -t
+const hlo = require('./high-level-opt.js')
+const Parser = require('./parse.js')
+const fs = require('fs')
+const path = require('path')
+
+const t = module.exports = (opt_, files, cb) => {
+ if (typeof opt_ === 'function')
+ cb = opt_, files = null, opt_ = {}
+ else if (Array.isArray(opt_))
+ files = opt_, opt_ = {}
+
+ if (typeof files === 'function')
+ cb = files, files = null
+
+ if (!files)
+ files = []
+ else
+ files = Array.from(files)
+
+ const opt = hlo(opt_)
+
+ if (opt.sync && typeof cb === 'function')
+ throw new TypeError('callback not supported for sync tar functions')
+
+ if (!opt.file && typeof cb === 'function')
+ throw new TypeError('callback only supported with file option')
+
+ if (files.length)
+ filesFilter(opt, files)
+
+ if (!opt.noResume)
+ onentryFunction(opt)
+
+ return opt.file && opt.sync ? listFileSync(opt)
+ : opt.file ? listFile(opt, cb)
+ : list(opt)
+}
+
+const onentryFunction = opt => {
+ const onentry = opt.onentry
+ opt.onentry = onentry ? e => {
+ onentry(e)
+ e.resume()
+ } : e => e.resume()
+}
+
+// construct a filter that limits the file entries listed
+// include child entries if a dir is included
+const filesFilter = (opt, files) => {
+ const map = new Map(files.map(f => [f.replace(/\/+$/, ''), true]))
+ const filter = opt.filter
+
+ const mapHas = (file, r) => {
+ const root = r || path.parse(file).root || '.'
+ const ret = file === root ? false
+ : map.has(file) ? map.get(file)
+ : mapHas(path.dirname(file), root)
+
+ map.set(file, ret)
+ return ret
+ }
+
+ opt.filter = filter
+ ? (file, entry) => filter(file, entry) && mapHas(file.replace(/\/+$/, ''))
+ : file => mapHas(file.replace(/\/+$/, ''))
+}
+
+const listFileSync = opt => {
+ const p = list(opt)
+ const file = opt.file
+ let threw = true
+ let fd
+ try {
+ const stat = fs.statSync(file)
+ const readSize = opt.maxReadSize || 16*1024*1024
+ if (stat.size < readSize) {
+ p.end(fs.readFileSync(file))
+ } else {
+ let pos = 0
+ const buf = Buffer.allocUnsafe(readSize)
+ fd = fs.openSync(file, 'r')
+ while (pos < stat.size) {
+ let bytesRead = fs.readSync(fd, buf, 0, readSize, pos)
+ pos += bytesRead
+ p.write(buf.slice(0, bytesRead))
+ }
+ p.end()
+ }
+ threw = false
+ } finally {
+ if (threw && fd)
+ try { fs.closeSync(fd) } catch (er) {}
+ }
+}
+
+const listFile = (opt, cb) => {
+ const parse = new Parser(opt)
+ const readSize = opt.maxReadSize || 16*1024*1024
+
+ const file = opt.file
+ const p = new Promise((resolve, reject) => {
+ parse.on('error', reject)
+ parse.on('end', resolve)
+
+ fs.stat(file, (er, stat) => {
+ if (er)
+ reject(er)
+ else if (stat.size < readSize)
+ fs.readFile(file, (er, data) => {
+ if (er)
+ return reject(er)
+ parse.end(data)
+ })
+ else {
+ const stream = fs.createReadStream(file, {
+ highWaterMark: readSize
+ })
+ stream.on('error', reject)
+ stream.pipe(parse)
+ }
+ })
+ })
+ return cb ? p.then(cb, cb) : p
+}
+
+const list = opt => new Parser(opt)
diff --git a/deps/npm/node_modules/tar/lib/mkdir.js b/deps/npm/node_modules/tar/lib/mkdir.js
new file mode 100644
index 0000000000..2a8f461afe
--- /dev/null
+++ b/deps/npm/node_modules/tar/lib/mkdir.js
@@ -0,0 +1,207 @@
+'use strict'
+// wrapper around mkdirp for tar's needs.
+
+// TODO: This should probably be a class, not functionally
+// passing around state in a gazillion args.
+
+const mkdirp = require('mkdirp')
+const fs = require('fs')
+const path = require('path')
+const chownr = require('chownr')
+
+class SymlinkError extends Error {
+ constructor (symlink, path) {
+ super('Cannot extract through symbolic link')
+ this.path = path
+ this.symlink = symlink
+ }
+
+ get name () {
+ return 'SylinkError'
+ }
+}
+
+class CwdError extends Error {
+ constructor (path, code) {
+ super(code + ': Cannot cd into \'' + path + '\'')
+ this.path = path
+ this.code = code
+ }
+
+ get name () {
+ return 'CwdError'
+ }
+}
+
+const mkdir = module.exports = (dir, opt, cb) => {
+ // if there's any overlap between mask and mode,
+ // then we'll need an explicit chmod
+ const umask = opt.umask
+ const mode = opt.mode | 0o0700
+ const needChmod = (mode & umask) !== 0
+
+ const uid = opt.uid
+ const gid = opt.gid
+ const doChown = typeof uid === 'number' &&
+ typeof gid === 'number' &&
+ ( uid !== opt.processUid || gid !== opt.processGid )
+
+ const preserve = opt.preserve
+ const unlink = opt.unlink
+ const cache = opt.cache
+ const cwd = opt.cwd
+
+ const done = (er, created) => {
+ if (er)
+ cb(er)
+ else {
+ cache.set(dir, true)
+ if (created && doChown)
+ chownr(created, uid, gid, er => done(er))
+ else if (needChmod)
+ fs.chmod(dir, mode, cb)
+ else
+ cb()
+ }
+ }
+
+ if (cache && cache.get(dir) === true)
+ return done()
+
+ if (dir === cwd)
+ return fs.lstat(dir, (er, st) => {
+ if (er || !st.isDirectory())
+ er = new CwdError(dir, er && er.code || 'ENOTDIR')
+ done(er)
+ })
+
+ if (preserve)
+ return mkdirp(dir, mode, done)
+
+ const sub = path.relative(cwd, dir)
+ const parts = sub.split(/\/|\\/)
+ mkdir_(cwd, parts, mode, cache, unlink, cwd, null, done)
+}
+
+const mkdir_ = (base, parts, mode, cache, unlink, cwd, created, cb) => {
+ if (!parts.length)
+ return cb(null, created)
+ const p = parts.shift()
+ const part = base + '/' + p
+ if (cache.get(part))
+ return mkdir_(part, parts, mode, cache, unlink, cwd, created, cb)
+ fs.mkdir(part, mode, onmkdir(part, parts, mode, cache, unlink, cwd, created, cb))
+}
+
+const onmkdir = (part, parts, mode, cache, unlink, cwd, created, cb) => er => {
+ if (er) {
+ if (er.path && path.dirname(er.path) === cwd &&
+ (er.code === 'ENOTDIR' || er.code === 'ENOENT'))
+ return cb(new CwdError(cwd, er.code))
+
+ fs.lstat(part, (statEr, st) => {
+ if (statEr)
+ cb(statEr)
+ else if (st.isDirectory())
+ mkdir_(part, parts, mode, cache, unlink, cwd, created, cb)
+ else if (unlink)
+ fs.unlink(part, er => {
+ if (er)
+ return cb(er)
+ fs.mkdir(part, mode, onmkdir(part, parts, mode, cache, unlink, cwd, created, cb))
+ })
+ else if (st.isSymbolicLink())
+ return cb(new SymlinkError(part, part + '/' + parts.join('/')))
+ else
+ cb(er)
+ })
+ } else {
+ created = created || part
+ mkdir_(part, parts, mode, cache, unlink, cwd, created, cb)
+ }
+}
+
+const mkdirSync = module.exports.sync = (dir, opt) => {
+ // if there's any overlap between mask and mode,
+ // then we'll need an explicit chmod
+ const umask = opt.umask
+ const mode = opt.mode | 0o0700
+ const needChmod = (mode & umask) !== 0
+
+ const uid = opt.uid
+ const gid = opt.gid
+ const doChown = typeof uid === 'number' &&
+ typeof gid === 'number' &&
+ ( uid !== opt.processUid || gid !== opt.processGid )
+
+ const preserve = opt.preserve
+ const unlink = opt.unlink
+ const cache = opt.cache
+ const cwd = opt.cwd
+
+ const done = (created) => {
+ cache.set(dir, true)
+ if (created && doChown)
+ chownr.sync(created, uid, gid)
+ if (needChmod)
+ fs.chmodSync(dir, mode)
+ cache.set(dir, true)
+ }
+
+ if (cache && cache.get(dir) === true)
+ return done()
+
+ if (dir === cwd) {
+ let ok = false
+ let code = 'ENOTDIR'
+ try {
+ ok = fs.lstatSync(dir).isDirectory()
+ } catch (er) {
+ code = er.code
+ } finally {
+ if (!ok)
+ throw new CwdError(dir, code)
+ }
+ done()
+ return
+ }
+
+ if (preserve)
+ return done(mkdirp.sync(dir, mode))
+
+ const sub = path.relative(cwd, dir)
+ const parts = sub.split(/\/|\\/)
+ let created = null
+ for (let p = parts.shift(), part = cwd;
+ p && (part += '/' + p);
+ p = parts.shift()) {
+
+ if (cache.get(part))
+ continue
+
+ try {
+ fs.mkdirSync(part, mode)
+ created = created || part
+ cache.set(part, true)
+ } catch (er) {
+ if (er.path && path.dirname(er.path) === cwd &&
+ (er.code === 'ENOTDIR' || er.code === 'ENOENT'))
+ return new CwdError(cwd, er.code)
+
+ const st = fs.lstatSync(part)
+ if (st.isDirectory()) {
+ cache.set(part, true)
+ continue
+ } else if (unlink) {
+ fs.unlinkSync(part)
+ fs.mkdirSync(part, mode)
+ created = created || part
+ cache.set(part, true)
+ continue
+ } else if (st.isSymbolicLink())
+ return new SymlinkError(part, part + '/' + parts.join('/'))
+ }
+ }
+
+ return done(created)
+}
diff --git a/deps/npm/node_modules/tar/lib/pack.js b/deps/npm/node_modules/tar/lib/pack.js
index 5a3bb95a12..09b6ac590b 100644
--- a/deps/npm/node_modules/tar/lib/pack.js
+++ b/deps/npm/node_modules/tar/lib/pack.js
@@ -1,236 +1,399 @@
-// pipe in an fstream, and it'll make a tarball.
-// key-value pair argument is global extended header props.
-
-module.exports = Pack
-
-var EntryWriter = require("./entry-writer.js")
- , Stream = require("stream").Stream
- , path = require("path")
- , inherits = require("inherits")
- , GlobalHeaderWriter = require("./global-header-writer.js")
- , collect = require("fstream").collect
- , eof = new Buffer(512)
-
-for (var i = 0; i < 512; i ++) eof[i] = 0
-
-inherits(Pack, Stream)
-
-function Pack (props) {
- // console.error("-- p ctor")
- var me = this
- if (!(me instanceof Pack)) return new Pack(props)
-
- if (props) me._noProprietary = props.noProprietary
- else me._noProprietary = false
-
- me._global = props
-
- me.readable = true
- me.writable = true
- me._buffer = []
- // console.error("-- -- set current to null in ctor")
- me._currentEntry = null
- me._processing = false
-
- me._pipeRoot = null
- me.on("pipe", function (src) {
- if (src.root === me._pipeRoot) return
- me._pipeRoot = src
- src.on("end", function () {
- me._pipeRoot = null
- })
- me.add(src)
- })
+'use strict'
+
+// A readable tar stream creator
+// Technically, this is a transform stream that you write paths into,
+// and tar format comes out of.
+// The `add()` method is like `write()` but returns this,
+// and end() return `this` as well, so you can
+// do `new Pack(opt).add('files').add('dir').end().pipe(output)
+// You could also do something like:
+// streamOfPaths().pipe(new Pack()).pipe(new fs.WriteStream('out.tar'))
+
+class PackJob {
+ constructor (path, absolute) {
+ this.path = path || './'
+ this.absolute = absolute
+ this.entry = null
+ this.stat = null
+ this.readdir = null
+ this.pending = false
+ this.ignore = false
+ this.piped = false
+ }
}
-Pack.prototype.addGlobal = function (props) {
- // console.error("-- p addGlobal")
- if (this._didGlobal) return
- this._didGlobal = true
-
- var me = this
- GlobalHeaderWriter(props)
- .on("data", function (c) {
- me.emit("data", c)
- })
- .end()
-}
+const MiniPass = require('minipass')
+const zlib = require('minizlib')
+const ReadEntry = require('./read-entry.js')
+const WriteEntry = require('./write-entry.js')
+const WriteEntrySync = WriteEntry.Sync
+const WriteEntryTar = WriteEntry.Tar
+const Yallist = require('yallist')
+const EOF = Buffer.alloc(1024)
+const ONSTAT = Symbol('onStat')
+const ENDED = Symbol('ended')
+const QUEUE = Symbol('queue')
+const CURRENT = Symbol('current')
+const PROCESS = Symbol('process')
+const PROCESSING = Symbol('processing')
+const PROCESSJOB = Symbol('processJob')
+const JOBS = Symbol('jobs')
+const JOBDONE = Symbol('jobDone')
+const ADDFSENTRY = Symbol('addFSEntry')
+const ADDTARENTRY = Symbol('addTarEntry')
+const STAT = Symbol('stat')
+const READDIR = Symbol('readdir')
+const ONREADDIR = Symbol('onreaddir')
+const PIPE = Symbol('pipe')
+const ENTRY = Symbol('entry')
+const ENTRYOPT = Symbol('entryOpt')
+const WRITEENTRYCLASS = Symbol('writeEntryClass')
+const WRITE = Symbol('write')
+const ONDRAIN = Symbol('ondrain')
+
+const fs = require('fs')
+const path = require('path')
+const warner = require('./warn-mixin.js')
+
+const Pack = warner(class Pack extends MiniPass {
+ constructor (opt) {
+ super(opt)
+ opt = opt || Object.create(null)
+ this.opt = opt
+ this.cwd = opt.cwd || process.cwd()
+ this.maxReadSize = opt.maxReadSize
+ this.preservePaths = !!opt.preservePaths
+ this.strict = !!opt.strict
+ this.noPax = !!opt.noPax
+ this.prefix = (opt.prefix || '').replace(/(\\|\/)+$/, '')
+ this.linkCache = opt.linkCache || new Map()
+ this.statCache = opt.statCache || new Map()
+ this.readdirCache = opt.readdirCache || new Map()
+ this[WRITEENTRYCLASS] = WriteEntry
+ if (typeof opt.onwarn === 'function')
+ this.on('warn', opt.onwarn)
+
+ this.zip = null
+ if (opt.gzip) {
+ if (typeof opt.gzip !== 'object')
+ opt.gzip = {}
+ this.zip = new zlib.Gzip(opt.gzip)
+ this.zip.on('data', chunk => super.write(chunk))
+ this.zip.on('end', _ => super.end())
+ this.zip.on('drain', _ => this[ONDRAIN]())
+ this.on('resume', _ => this.zip.resume())
+ } else
+ this.on('drain', this[ONDRAIN])
+
+ this.portable = !!opt.portable
+ this.noDirRecurse = !!opt.noDirRecurse
+ this.follow = !!opt.follow
+
+ this.filter = typeof opt.filter === 'function' ? opt.filter : _ => true
+
+ this[QUEUE] = new Yallist
+ this[JOBS] = 0
+ this.jobs = +opt.jobs || 4
+ this[PROCESSING] = false
+ this[ENDED] = false
+ }
-Pack.prototype.add = function (stream) {
- if (this._global && !this._didGlobal) this.addGlobal(this._global)
+ [WRITE] (chunk) {
+ return super.write(chunk)
+ }
- if (this._ended) return this.emit("error", new Error("add after end"))
+ add (path) {
+ this.write(path)
+ return this
+ }
- collect(stream)
- this._buffer.push(stream)
- this._process()
- this._needDrain = this._buffer.length > 0
- return !this._needDrain
-}
+ end (path) {
+ if (path)
+ this.write(path)
+ this[ENDED] = true
+ this[PROCESS]()
+ return this
+ }
-Pack.prototype.pause = function () {
- this._paused = true
- if (this._currentEntry) this._currentEntry.pause()
- this.emit("pause")
-}
+ write (path) {
+ if (this[ENDED])
+ throw new Error('write after end')
-Pack.prototype.resume = function () {
- this._paused = false
- if (this._currentEntry) this._currentEntry.resume()
- this.emit("resume")
- this._process()
-}
+ if (path instanceof ReadEntry)
+ this[ADDTARENTRY](path)
+ else
+ this[ADDFSENTRY](path)
+ return this.flowing
+ }
-Pack.prototype.end = function () {
- this._ended = true
- this._buffer.push(eof)
- this._process()
-}
+ [ADDTARENTRY] (p) {
+ const absolute = path.resolve(this.cwd, p.path)
+ if (this.prefix)
+ p.path = this.prefix + '/' + p.path.replace(/^\.(\/+|$)/, '')
+
+ // in this case, we don't have to wait for the stat
+ if (!this.filter(p.path, p))
+ p.resume()
+ else {
+ const job = new PackJob(p.path, absolute, false)
+ job.entry = new WriteEntryTar(p, this[ENTRYOPT](job))
+ job.entry.on('end', _ => this[JOBDONE](job))
+ this[JOBS] += 1
+ this[QUEUE].push(job)
+ }
-Pack.prototype._process = function () {
- var me = this
- if (me._paused || me._processing) {
- return
+ this[PROCESS]()
}
- var entry = me._buffer.shift()
+ [ADDFSENTRY] (p) {
+ const absolute = path.resolve(this.cwd, p)
+ if (this.prefix)
+ p = this.prefix + '/' + p.replace(/^\.(\/+|$)/, '')
- if (!entry) {
- if (me._needDrain) {
- me.emit("drain")
- }
- return
+ this[QUEUE].push(new PackJob(p, absolute))
+ this[PROCESS]()
}
- if (entry.ready === false) {
- // console.error("-- entry is not ready", entry)
- me._buffer.unshift(entry)
- entry.on("ready", function () {
- // console.error("-- -- ready!", entry)
- me._process()
+ [STAT] (job) {
+ job.pending = true
+ this[JOBS] += 1
+ const stat = this.follow ? 'stat' : 'lstat'
+ fs[stat](job.absolute, (er, stat) => {
+ job.pending = false
+ this[JOBS] -= 1
+ if (er)
+ this.emit('error', er)
+ else
+ this[ONSTAT](job, stat)
})
- return
}
- me._processing = true
+ [ONSTAT] (job, stat) {
+ this.statCache.set(job.absolute, stat)
+ job.stat = stat
+
+ // now we have the stat, we can filter it.
+ if (!this.filter(job.path, stat))
+ job.ignore = true
- if (entry === eof) {
- // need 2 ending null blocks.
- me.emit("data", eof)
- me.emit("data", eof)
- me.emit("end")
- me.emit("close")
- return
+ this[PROCESS]()
}
- // Change the path to be relative to the root dir that was
- // added to the tarball.
- //
- // XXX This should be more like how -C works, so you can
- // explicitly set a root dir, and also explicitly set a pathname
- // in the tarball to use. That way we can skip a lot of extra
- // work when resolving symlinks for bundled dependencies in npm.
+ [READDIR] (job) {
+ job.pending = true
+ this[JOBS] += 1
+ fs.readdir(job.absolute, (er, entries) => {
+ job.pending = false
+ this[JOBS] -= 1
+ if (er)
+ return this.emit('error', er)
+ this[ONREADDIR](job, entries)
+ })
+ }
- var root = path.dirname((entry.root || entry).path);
- if (me._global && me._global.fromBase && entry.root && entry.root.path) {
- // user set 'fromBase: true' indicating tar root should be directory itself
- root = entry.root.path;
+ [ONREADDIR] (job, entries) {
+ this.readdirCache.set(job.absolute, entries)
+ job.readdir = entries
+ this[PROCESS]()
}
- var wprops = {}
+ [PROCESS] () {
+ if (this[PROCESSING])
+ return
- Object.keys(entry.props || {}).forEach(function (k) {
- wprops[k] = entry.props[k]
- })
+ this[PROCESSING] = true
+ for (let w = this[QUEUE].head;
+ w !== null && this[JOBS] < this.jobs;
+ w = w.next) {
+ this[PROCESSJOB](w.value)
+ if (w.value.ignore) {
+ const p = w.next
+ this[QUEUE].removeNode(w)
+ w.next = p
+ }
+ }
- if (me._noProprietary) wprops.noProprietary = true
+ this[PROCESSING] = false
- wprops.path = path.relative(root, entry.path || '')
+ if (this[ENDED] && !this[QUEUE].length && this[JOBS] === 0) {
+ if (this.zip)
+ this.zip.end(EOF)
+ else {
+ super.write(EOF)
+ super.end()
+ }
+ }
+ }
- // actually not a matter of opinion or taste.
- if (process.platform === "win32") {
- wprops.path = wprops.path.replace(/\\/g, "/")
+ get [CURRENT] () {
+ return this[QUEUE] && this[QUEUE].head && this[QUEUE].head.value
}
- if (!wprops.type)
- wprops.type = 'Directory'
+ [JOBDONE] (job) {
+ this[QUEUE].shift()
+ this[JOBS] -= 1
+ this[PROCESS]()
+ }
- switch (wprops.type) {
- // sockets not supported
- case "Socket":
+ [PROCESSJOB] (job) {
+ if (job.pending)
return
- case "Directory":
- wprops.path += "/"
- wprops.size = 0
- break
-
- case "Link":
- var lp = path.resolve(path.dirname(entry.path), entry.linkpath)
- wprops.linkpath = path.relative(root, lp) || "."
- wprops.size = 0
- break
+ if (job.entry) {
+ if (job === this[CURRENT] && !job.piped)
+ this[PIPE](job)
+ return
+ }
- case "SymbolicLink":
- var lp = path.resolve(path.dirname(entry.path), entry.linkpath)
- wprops.linkpath = path.relative(path.dirname(entry.path), lp) || "."
- wprops.size = 0
- break
- }
+ if (!job.stat) {
+ if (this.statCache.has(job.absolute))
+ this[ONSTAT](job, this.statCache.get(job.absolute))
+ else
+ this[STAT](job)
+ }
+ if (!job.stat)
+ return
- // console.error("-- new writer", wprops)
- // if (!wprops.type) {
- // // console.error("-- no type?", entry.constructor.name, entry)
- // }
+ // filtered out!
+ if (job.ignore)
+ return
- // console.error("-- -- set current to new writer", wprops.path)
- var writer = me._currentEntry = EntryWriter(wprops)
+ if (!this.noDirRecurse && job.stat.isDirectory() && !job.readdir) {
+ if (this.readdirCache.has(job.absolute))
+ this[ONREADDIR](job, this.readdirCache.get(job.absolute))
+ else
+ this[READDIR](job)
+ if (!job.readdir)
+ return
+ }
- writer.parent = me
+ // we know it doesn't have an entry, because that got checked above
+ job.entry = this[ENTRY](job)
+ if (!job.entry) {
+ job.ignore = true
+ return
+ }
- // writer.on("end", function () {
- // // console.error("-- -- writer end", writer.path)
- // })
+ if (job === this[CURRENT] && !job.piped)
+ this[PIPE](job)
+ }
- writer.on("data", function (c) {
- me.emit("data", c)
- })
+ [ENTRYOPT] (job) {
+ return {
+ onwarn: (msg, data) => {
+ this.warn(msg, data)
+ },
+ noPax: this.noPax,
+ cwd: this.cwd,
+ absolute: job.absolute,
+ preservePaths: this.preservePaths,
+ maxReadSize: this.maxReadSize,
+ strict: this.strict,
+ portable: this.portable,
+ linkCache: this.linkCache,
+ statCache: this.statCache
+ }
+ }
- writer.on("header", function () {
- Buffer.prototype.toJSON = function () {
- return this.toString().split(/\0/).join(".")
+ [ENTRY] (job) {
+ this[JOBS] += 1
+ try {
+ return new this[WRITEENTRYCLASS](
+ job.path, this[ENTRYOPT](job)).on('end', _ => {
+ this[JOBDONE](job)
+ }).on('error', er => this.emit('error', er))
+ } catch (er) {
+ this.emit('error', er)
}
- // console.error("-- -- writer header %j", writer.props)
- if (writer.props.size === 0) nextEntry()
- })
- writer.on("close", nextEntry)
+ }
+
+ [ONDRAIN] () {
+ if (this[CURRENT] && this[CURRENT].entry)
+ this[CURRENT].entry.resume()
+ }
+
+ // like .pipe() but using super, because our write() is special
+ [PIPE] (job) {
+ job.piped = true
+
+ if (job.readdir)
+ job.readdir.forEach(entry => {
+ const p = this.prefix ?
+ job.path.slice(this.prefix.length + 1) || './'
+ : job.path
+
+ const base = p === './' ? '' : p.replace(/\/*$/, '/')
+ this[ADDFSENTRY](base + entry)
+ })
+
+ const source = job.entry
+ const zip = this.zip
+
+ if (zip)
+ source.on('data', chunk => {
+ if (!zip.write(chunk))
+ source.pause()
+ })
+ else
+ source.on('data', chunk => {
+ if (!super.write(chunk))
+ source.pause()
+ })
+ }
- var ended = false
- function nextEntry () {
- if (ended) return
- ended = true
+ pause () {
+ if (this.zip)
+ this.zip.pause()
+ return super.pause()
+ }
+})
- // console.error("-- -- writer close", writer.path)
- // console.error("-- -- set current to null", wprops.path)
- me._currentEntry = null
- me._processing = false
- me._process()
+class PackSync extends Pack {
+ constructor (opt) {
+ super(opt)
+ this[WRITEENTRYCLASS] = WriteEntrySync
}
- writer.on("error", function (er) {
- // console.error("-- -- writer error", writer.path)
- me.emit("error", er)
- })
+ // pause/resume are no-ops in sync streams.
+ pause () {}
+ resume () {}
+
+ [STAT] (job) {
+ const stat = this.follow ? 'statSync' : 'lstatSync'
+ this[ONSTAT](job, fs[stat](job.absolute))
+ }
- // if it's the root, then there's no need to add its entries,
- // or data, since they'll be added directly.
- if (entry === me._pipeRoot) {
- // console.error("-- is the root, don't auto-add")
- writer.add = null
+ [READDIR] (job, stat) {
+ this[ONREADDIR](job, fs.readdirSync(job.absolute))
}
- entry.pipe(writer)
+ // gotta get it all in this tick
+ [PIPE] (job) {
+ const source = job.entry
+ const zip = this.zip
+
+ if (job.readdir)
+ job.readdir.forEach(entry => {
+ const p = this.prefix ?
+ job.path.slice(this.prefix.length + 1) || './'
+ : job.path
+
+
+ const base = p === './' ? '' : p.replace(/\/*$/, '/')
+ this[ADDFSENTRY](base + entry)
+ })
+
+ if (zip)
+ source.on('data', chunk => {
+ zip.write(chunk)
+ })
+ else
+ source.on('data', chunk => {
+ super[WRITE](chunk)
+ })
+ }
}
-Pack.prototype.destroy = function () {}
-Pack.prototype.write = function () {}
+Pack.Sync = PackSync
+
+module.exports = Pack
diff --git a/deps/npm/node_modules/tar/lib/parse.js b/deps/npm/node_modules/tar/lib/parse.js
index 600ad782f0..63c7ee9cef 100644
--- a/deps/npm/node_modules/tar/lib/parse.js
+++ b/deps/npm/node_modules/tar/lib/parse.js
@@ -1,275 +1,415 @@
+'use strict'
+
+// this[BUFFER] is the remainder of a chunk if we're waiting for
+// the full 512 bytes of a header to come in. We will Buffer.concat()
+// it to the next write(), which is a mem copy, but a small one.
+//
+// this[QUEUE] is a Yallist of entries that haven't been emitted
+// yet this can only get filled up if the user keeps write()ing after
+// a write() returns false, or does a write() with more than one entry
+//
+// We don't buffer chunks, we always parse them and either create an
+// entry, or push it into the active entry. The ReadEntry class knows
+// to throw data away if .ignore=true
+//
+// Shift entry off the buffer when it emits 'end', and emit 'entry' for
+// the next one in the list.
+//
+// At any time, we're pushing body chunks into the entry at WRITEENTRY,
+// and waiting for 'end' on the entry at READENTRY
+//
+// ignored entries get .resume() called on them straight away
+
+const warner = require('./warn-mixin.js')
+const path = require('path')
+const Header = require('./header.js')
+const EE = require('events')
+const Yallist = require('yallist')
+const maxMetaEntrySize = 1024 * 1024
+const Entry = require('./read-entry.js')
+const Pax = require('./pax.js')
+const zlib = require('minizlib')
+
+const gzipHeader = new Buffer([0x1f, 0x8b])
+const STATE = Symbol('state')
+const WRITEENTRY = Symbol('writeEntry')
+const READENTRY = Symbol('readEntry')
+const NEXTENTRY = Symbol('nextEntry')
+const PROCESSENTRY = Symbol('processEntry')
+const EX = Symbol('extendedHeader')
+const GEX = Symbol('globalExtendedHeader')
+const META = Symbol('meta')
+const EMITMETA = Symbol('emitMeta')
+const BUFFER = Symbol('buffer')
+const QUEUE = Symbol('queue')
+const ENDED = Symbol('ended')
+const EMITTEDEND = Symbol('emittedEnd')
+const EMIT = Symbol('emit')
+const UNZIP = Symbol('unzip')
+const CONSUMECHUNK = Symbol('consumeChunk')
+const CONSUMECHUNKSUB = Symbol('consumeChunkSub')
+const CONSUMEBODY = Symbol('consumeBody')
+const CONSUMEMETA = Symbol('consumeMeta')
+const CONSUMEHEADER = Symbol('consumeHeader')
+const CONSUMING = Symbol('consuming')
+const BUFFERCONCAT = Symbol('bufferConcat')
+const MAYBEEND = Symbol('maybeEnd')
+const WRITING = Symbol('writing')
+const ABORTED = Symbol('aborted')
+const DONE = Symbol('onDone')
+
+const noop = _ => true
+
+module.exports = warner(class Parser extends EE {
+ constructor (opt) {
+ opt = opt || {}
+ super(opt)
+
+ if (opt.ondone)
+ this.on(DONE, opt.ondone)
+ else
+ this.on(DONE, _ => {
+ this.emit('prefinish')
+ this.emit('finish')
+ this.emit('end')
+ this.emit('close')
+ })
+
+ this.strict = !!opt.strict
+ this.maxMetaEntrySize = opt.maxMetaEntrySize || maxMetaEntrySize
+ this.filter = typeof opt.filter === 'function' ? opt.filter : noop
+
+ // have to set this so that streams are ok piping into it
+ this.writable = true
+ this.readable = false
+
+ this[QUEUE] = new Yallist()
+ this[BUFFER] = null
+ this[READENTRY] = null
+ this[WRITEENTRY] = null
+ this[STATE] = 'begin'
+ this[META] = ''
+ this[EX] = null
+ this[GEX] = null
+ this[ENDED] = false
+ this[UNZIP] = null
+ this[ABORTED] = false
+ if (typeof opt.onwarn === 'function')
+ this.on('warn', opt.onwarn)
+ if (typeof opt.onentry === 'function')
+ this.on('entry', opt.onentry)
+ }
+
+ [CONSUMEHEADER] (chunk, position) {
+ const header = new Header(chunk, position)
-// A writable stream.
-// It emits "entry" events, which provide a readable stream that has
-// header info attached.
-
-module.exports = Parse.create = Parse
-
-var stream = require("stream")
- , Stream = stream.Stream
- , BlockStream = require("block-stream")
- , tar = require("../tar.js")
- , TarHeader = require("./header.js")
- , Entry = require("./entry.js")
- , BufferEntry = require("./buffer-entry.js")
- , ExtendedHeader = require("./extended-header.js")
- , assert = require("assert").ok
- , inherits = require("inherits")
- , fstream = require("fstream")
-
-// reading a tar is a lot like reading a directory
-// However, we're actually not going to run the ctor,
-// since it does a stat and various other stuff.
-// This inheritance gives us the pause/resume/pipe
-// behavior that is desired.
-inherits(Parse, fstream.Reader)
-
-function Parse () {
- var me = this
- if (!(me instanceof Parse)) return new Parse()
-
- // doesn't apply fstream.Reader ctor?
- // no, becasue we don't want to stat/etc, we just
- // want to get the entry/add logic from .pipe()
- Stream.apply(me)
-
- me.writable = true
- me.readable = true
- me._stream = new BlockStream(512)
- me.position = 0
- me._ended = false
-
- me._stream.on("error", function (e) {
- me.emit("error", e)
- })
-
- me._stream.on("data", function (c) {
- me._process(c)
- })
-
- me._stream.on("end", function () {
- me._streamEnd()
- })
-
- me._stream.on("drain", function () {
- me.emit("drain")
- })
-}
-
-// overridden in Extract class, since it needs to
-// wait for its DirWriter part to finish before
-// emitting "end"
-Parse.prototype._streamEnd = function () {
- var me = this
- if (!me._ended || me._entry) me.error("unexpected eof")
- me.emit("end")
-}
-
-// a tar reader is actually a filter, not just a readable stream.
-// So, you should pipe a tarball stream into it, and it needs these
-// write/end methods to do that.
-Parse.prototype.write = function (c) {
- if (this._ended) {
- // gnutar puts a LOT of nulls at the end.
- // you can keep writing these things forever.
- // Just ignore them.
- for (var i = 0, l = c.length; i > l; i ++) {
- if (c[i] !== 0) return this.error("write() after end()")
+ if (header.nullBlock)
+ this[EMIT]('nullBlock')
+ else if (!header.cksumValid)
+ this.warn('invalid entry', header)
+ else if (!header.path)
+ this.warn('invalid: path is required', header)
+ else {
+ const type = header.type
+ if (/^(Symbolic)?Link$/.test(type) && !header.linkpath)
+ this.warn('invalid: linkpath required', header)
+ else if (!/^(Symbolic)?Link$/.test(type) && header.linkpath)
+ this.warn('invalid: linkpath forbidden', header)
+ else {
+ const entry = this[WRITEENTRY] = new Entry(header, this[EX], this[GEX])
+
+ if (entry.meta) {
+ if (entry.size > this.maxMetaEntrySize) {
+ entry.ignore = true
+ this[EMIT]('ignoredEntry', entry)
+ this[STATE] = 'ignore'
+ } else if (entry.size > 0) {
+ this[META] = ''
+ entry.on('data', c => this[META] += c)
+ this[STATE] = 'meta'
+ }
+ } else {
+
+ this[EX] = null
+ entry.ignore = entry.ignore || !this.filter(entry.path, entry)
+ if (entry.ignore) {
+ this[EMIT]('ignoredEntry', entry)
+ this[STATE] = entry.remain ? 'ignore' : 'begin'
+ } else {
+ if (entry.remain)
+ this[STATE] = 'body'
+ else {
+ this[STATE] = 'begin'
+ entry.end()
+ }
+
+ if (!this[READENTRY]) {
+ this[QUEUE].push(entry)
+ this[NEXTENTRY]()
+ } else
+ this[QUEUE].push(entry)
+ }
+ }
+ }
}
- return
}
- return this._stream.write(c)
-}
-
-Parse.prototype.end = function (c) {
- this._ended = true
- return this._stream.end(c)
-}
-
-// don't need to do anything, since we're just
-// proxying the data up from the _stream.
-// Just need to override the parent's "Not Implemented"
-// error-thrower.
-Parse.prototype._read = function () {}
-
-Parse.prototype._process = function (c) {
- assert(c && c.length === 512, "block size should be 512")
-
- // one of three cases.
- // 1. A new header
- // 2. A part of a file/extended header
- // 3. One of two or more EOF null blocks
-
- if (this._entry) {
- var entry = this._entry
- if(!entry._abort) entry.write(c)
+
+ [PROCESSENTRY] (entry) {
+ let go = true
+
+ if (!entry) {
+ this[READENTRY] = null
+ go = false
+ } else if (Array.isArray(entry))
+ this.emit.apply(this, entry)
else {
- entry._remaining -= c.length
- if(entry._remaining < 0) entry._remaining = 0
+ this[READENTRY] = entry
+ this.emit('entry', entry)
+ if (!entry.emittedEnd) {
+ entry.on('end', _ => this[NEXTENTRY]())
+ go = false
+ }
}
- if (entry._remaining === 0) {
+
+ return go
+ }
+
+ [NEXTENTRY] () {
+ do {} while (this[PROCESSENTRY](this[QUEUE].shift()))
+
+ if (!this[QUEUE].length) {
+ // At this point, there's nothing in the queue, but we may have an
+ // entry which is being consumed (readEntry).
+ // If we don't, then we definitely can handle more data.
+ // If we do, and either it's flowing, or it has never had any data
+ // written to it, then it needs more.
+ // The only other possibility is that it has returned false from a
+ // write() call, so we wait for the next drain to continue.
+ const re = this[READENTRY]
+ const drainNow = !re || re.flowing || re.size === re.remain
+ if (drainNow) {
+ if (!this[WRITING])
+ this.emit('drain')
+ } else
+ re.once('drain', _ => this.emit('drain'))
+ }
+ }
+
+ [CONSUMEBODY] (chunk, position) {
+ // write up to but no more than writeEntry.blockRemain
+ const entry = this[WRITEENTRY]
+ const br = entry.blockRemain
+ const c = (br >= chunk.length && position === 0) ? chunk
+ : chunk.slice(position, position + br)
+
+ entry.write(c)
+
+ if (!entry.blockRemain) {
+ this[STATE] = 'begin'
+ this[WRITEENTRY] = null
entry.end()
- this._entry = null
- }
- } else {
- // either zeroes or a header
- var zero = true
- for (var i = 0; i < 512 && zero; i ++) {
- zero = c[i] === 0
}
- // eof is *at least* 2 blocks of nulls, and then the end of the
- // file. you can put blocks of nulls between entries anywhere,
- // so appending one tarball to another is technically valid.
- // ending without the eof null blocks is not allowed, however.
- if (zero) {
- if (this._eofStarted)
- this._ended = true
- this._eofStarted = true
- } else {
- this._eofStarted = false
- this._startEntry(c)
+ return c.length
+ }
+
+ [CONSUMEMETA] (chunk, position) {
+ const entry = this[WRITEENTRY]
+ const ret = this[CONSUMEBODY](chunk, position)
+
+ // if we finished, then the entry is reset
+ if (!this[WRITEENTRY])
+ this[EMITMETA](entry)
+
+ return ret
+ }
+
+ [EMIT] (ev, data, extra) {
+ if (!this[QUEUE].length && !this[READENTRY])
+ this.emit(ev, data, extra)
+ else
+ this[QUEUE].push([ev, data, extra])
+ }
+
+ [EMITMETA] (entry) {
+ this[EMIT]('meta', this[META])
+ switch (entry.type) {
+ case 'ExtendedHeader':
+ case 'OldExtendedHeader':
+ this[EX] = Pax.parse(this[META], this[EX], false)
+ break
+
+ case 'GlobalExtendedHeader':
+ this[GEX] = Pax.parse(this[META], this[GEX], true)
+ break
+
+ case 'NextFileHasLongPath':
+ case 'OldGnuLongPath':
+ this[EX] = this[EX] || Object.create(null)
+ this[EX].path = this[META].replace(/\0.*/, '')
+ break
+
+ case 'NextFileHasLongLinkpath':
+ this[EX] = this[EX] || Object.create(null)
+ this[EX].linkpath = this[META].replace(/\0.*/, '')
+ break
+
+ /* istanbul ignore next */
+ default: throw new Error('unknown meta: ' + entry.type)
}
}
- this.position += 512
-}
-
-// take a header chunk, start the right kind of entry.
-Parse.prototype._startEntry = function (c) {
- var header = new TarHeader(c)
- , self = this
- , entry
- , ev
- , EntryType
- , onend
- , meta = false
-
- if (null === header.size || !header.cksumValid) {
- var e = new Error("invalid tar file")
- e.header = header
- e.tar_file_offset = this.position
- e.tar_block = this.position / 512
- return this.emit("error", e)
+ abort (msg, error) {
+ this[ABORTED] = true
+ this.warn(msg, error)
+ this.emit('abort')
}
- switch (tar.types[header.type]) {
- case "File":
- case "OldFile":
- case "Link":
- case "SymbolicLink":
- case "CharacterDevice":
- case "BlockDevice":
- case "Directory":
- case "FIFO":
- case "ContiguousFile":
- case "GNUDumpDir":
- // start a file.
- // pass in any extended headers
- // These ones consumers are typically most interested in.
- EntryType = Entry
- ev = "entry"
- break
-
- case "GlobalExtendedHeader":
- // extended headers that apply to the rest of the tarball
- EntryType = ExtendedHeader
- onend = function () {
- self._global = self._global || {}
- Object.keys(entry.fields).forEach(function (k) {
- self._global[k] = entry.fields[k]
- })
+ write (chunk) {
+ if (this[ABORTED])
+ return
+
+ // first write, might be gzipped
+ if (this[UNZIP] === null && chunk) {
+ if (this[BUFFER]) {
+ chunk = Buffer.concat([this[BUFFER], chunk])
+ this[BUFFER] = null
}
- ev = "globalExtendedHeader"
- meta = true
- break
-
- case "ExtendedHeader":
- case "OldExtendedHeader":
- // extended headers that apply to the next entry
- EntryType = ExtendedHeader
- onend = function () {
- self._extended = entry.fields
+ if (chunk.length < gzipHeader.length) {
+ this[BUFFER] = chunk
+ return true
}
- ev = "extendedHeader"
- meta = true
- break
-
- case "NextFileHasLongLinkpath":
- // set linkpath=<contents> in extended header
- EntryType = BufferEntry
- onend = function () {
- self._extended = self._extended || {}
- self._extended.linkpath = entry.body
+ for (let i = 0; this[UNZIP] === null && i < gzipHeader.length; i++) {
+ if (chunk[i] !== gzipHeader[i])
+ this[UNZIP] = false
}
- ev = "longLinkpath"
- meta = true
- break
-
- case "NextFileHasLongPath":
- case "OldGnuLongPath":
- // set path=<contents> in file-extended header
- EntryType = BufferEntry
- onend = function () {
- self._extended = self._extended || {}
- self._extended.path = entry.body
+ if (this[UNZIP] === null) {
+ const ended = this[ENDED]
+ this[ENDED] = false
+ this[UNZIP] = new zlib.Unzip()
+ this[UNZIP].on('data', chunk => this[CONSUMECHUNK](chunk))
+ this[UNZIP].on('error', er =>
+ this.abort('zlib error: ' + er.message, er))
+ this[UNZIP].on('end', _ => {
+ this[ENDED] = true
+ this[CONSUMECHUNK]()
+ })
+ return ended ? this[UNZIP].end(chunk) : this[UNZIP].write(chunk)
}
- ev = "longPath"
- meta = true
- break
-
- default:
- // all the rest we skip, but still set the _entry
- // member, so that we can skip over their data appropriately.
- // emit an event to say that this is an ignored entry type?
- EntryType = Entry
- ev = "ignoredEntry"
- break
- }
+ }
- var global, extended
- if (meta) {
- global = extended = null
- } else {
- var global = this._global
- var extended = this._extended
+ this[WRITING] = true
+ if (this[UNZIP])
+ this[UNZIP].write(chunk)
+ else
+ this[CONSUMECHUNK](chunk)
+ this[WRITING] = false
- // extendedHeader only applies to one entry, so once we start
- // an entry, it's over.
- this._extended = null
- }
- entry = new EntryType(header, extended, global)
- entry.meta = meta
-
- // only proxy data events of normal files.
- if (!meta) {
- entry.on("data", function (c) {
- me.emit("data", c)
- })
+ // return false if there's a queue, or if the current entry isn't flowing
+ const ret =
+ this[QUEUE].length ? false :
+ this[READENTRY] ? this[READENTRY].flowing :
+ true
+
+ // if we have no queue, then that means a clogged READENTRY
+ if (!ret && !this[QUEUE].length)
+ this[READENTRY].once('drain', _ => this.emit('drain'))
+
+ return ret
}
- if (onend) entry.on("end", onend)
+ [BUFFERCONCAT] (c) {
+ if (c && !this[ABORTED])
+ this[BUFFER] = this[BUFFER] ? Buffer.concat([this[BUFFER], c]) : c
+ }
- this._entry = entry
- var me = this
+ [MAYBEEND] () {
+ if (this[ENDED] && !this[EMITTEDEND] && !this[ABORTED]) {
+ this[EMITTEDEND] = true
+ const entry = this[WRITEENTRY]
+ if (entry && entry.blockRemain) {
+ const have = this[BUFFER] ? this[BUFFER].length : 0
+ this.warn('Truncated input (needed ' + entry.blockRemain +
+ ' more bytes, only ' + have + ' available)', entry)
+ if (this[BUFFER])
+ entry.write(this[BUFFER])
+ entry.end()
+ }
+ this[EMIT](DONE)
+ }
+ }
- entry.on("pause", function () {
- me.pause()
- })
+ [CONSUMECHUNK] (chunk) {
+ if (this[CONSUMING]) {
+ this[BUFFERCONCAT](chunk)
+ } else if (!chunk && !this[BUFFER]) {
+ this[MAYBEEND]()
+ } else {
+ this[CONSUMING] = true
+ if (this[BUFFER]) {
+ this[BUFFERCONCAT](chunk)
+ const c = this[BUFFER]
+ this[BUFFER] = null
+ this[CONSUMECHUNKSUB](c)
+ } else {
+ this[CONSUMECHUNKSUB](chunk)
+ }
- entry.on("resume", function () {
- me.resume()
- })
+ while (this[BUFFER] && this[BUFFER].length >= 512 && !this[ABORTED]) {
+ const c = this[BUFFER]
+ this[BUFFER] = null
+ this[CONSUMECHUNKSUB](c)
+ }
+ this[CONSUMING] = false
+ }
- if (this.listeners("*").length) {
- this.emit("*", ev, entry)
+ if (!this[BUFFER] || this[ENDED])
+ this[MAYBEEND]()
}
- this.emit(ev, entry)
+ [CONSUMECHUNKSUB] (chunk) {
+ // we know that we are in CONSUMING mode, so anything written goes into
+ // the buffer. Advance the position and put any remainder in the buffer.
+ let position = 0
+ let length = chunk.length
+ while (position + 512 <= length && !this[ABORTED]) {
+ switch (this[STATE]) {
+ case 'begin':
+ this[CONSUMEHEADER](chunk, position)
+ position += 512
+ break
+
+ case 'ignore':
+ case 'body':
+ position += this[CONSUMEBODY](chunk, position)
+ break
+
+ case 'meta':
+ position += this[CONSUMEMETA](chunk, position)
+ break
+
+ /* istanbul ignore next */
+ default:
+ throw new Error('invalid state: ' + this[STATE])
+ }
+ }
- // Zero-byte entry. End immediately.
- if (entry.props.size === 0) {
- entry.end()
- this._entry = null
+ if (position < length) {
+ if (this[BUFFER])
+ this[BUFFER] = Buffer.concat([chunk.slice(position), this[BUFFER]])
+ else
+ this[BUFFER] = chunk.slice(position)
+ }
+ }
+
+ end (chunk) {
+ if (!this[ABORTED]) {
+ if (this[UNZIP])
+ this[UNZIP].end(chunk)
+ else {
+ this[ENDED] = true
+ this.write(chunk)
+ }
+ }
}
-}
+})
diff --git a/deps/npm/node_modules/tar/lib/pax.js b/deps/npm/node_modules/tar/lib/pax.js
new file mode 100644
index 0000000000..214a459f3b
--- /dev/null
+++ b/deps/npm/node_modules/tar/lib/pax.js
@@ -0,0 +1,145 @@
+'use strict'
+const Header = require('./header.js')
+const path = require('path')
+
+class Pax {
+ constructor (obj, global) {
+ this.atime = obj.atime || null
+ this.charset = obj.charset || null
+ this.comment = obj.comment || null
+ this.ctime = obj.ctime || null
+ this.gid = obj.gid || null
+ this.gname = obj.gname || null
+ this.linkpath = obj.linkpath || null
+ this.mtime = obj.mtime || null
+ this.path = obj.path || null
+ this.size = obj.size || null
+ this.uid = obj.uid || null
+ this.uname = obj.uname || null
+ this.dev = obj.dev || null
+ this.ino = obj.ino || null
+ this.nlink = obj.nlink || null
+ this.global = global || false
+ }
+
+ encode () {
+ const body = this.encodeBody()
+ if (body === '')
+ return null
+
+ const bodyLen = Buffer.byteLength(body)
+ // round up to 512 bytes
+ // add 512 for header
+ const bufLen = 512 * Math.ceil(1 + bodyLen / 512)
+ const buf = Buffer.allocUnsafe(bufLen)
+
+ // 0-fill the header section, it might not hit every field
+ for (let i = 0; i < 512; i++) {
+ buf[i] = 0
+ }
+
+ new Header({
+ // XXX split the path
+ // then the path should be PaxHeader + basename, but less than 99,
+ // prepend with the dirname
+ path: ('PaxHeader/' + path.basename(this.path)).slice(0, 99),
+ mode: this.mode || 0o644,
+ uid: this.uid || null,
+ gid: this.gid || null,
+ size: bodyLen,
+ mtime: this.mtime || null,
+ type: this.global ? 'GlobalExtendedHeader' : 'ExtendedHeader',
+ linkpath: '',
+ uname: this.uname || '',
+ gname: this.gname || '',
+ devmaj: 0,
+ devmin: 0,
+ atime: this.atime || null,
+ ctime: this.ctime || null
+ }).encode(buf)
+
+ buf.write(body, 512, bodyLen, 'utf8')
+
+ // null pad after the body
+ for (let i = bodyLen + 512; i < buf.length; i++) {
+ buf[i] = 0
+ }
+
+ return buf
+ }
+
+ encodeBody () {
+ return (
+ this.encodeField('path') +
+ this.encodeField('ctime') +
+ this.encodeField('atime') +
+ this.encodeField('dev') +
+ this.encodeField('ino') +
+ this.encodeField('nlink') +
+ this.encodeField('charset') +
+ this.encodeField('comment') +
+ this.encodeField('gid') +
+ this.encodeField('gname') +
+ this.encodeField('linkpath') +
+ this.encodeField('mtime') +
+ this.encodeField('size') +
+ this.encodeField('uid') +
+ this.encodeField('uname')
+ )
+ }
+
+ encodeField (field) {
+ if (this[field] === null || this[field] === undefined)
+ return ''
+ const v = this[field] instanceof Date ? this[field].getTime() / 1000
+ : this[field]
+ const s = ' ' +
+ (field === 'dev' || field === 'ino' || field === 'nlink'
+ ? 'SCHILY.' : '') +
+ field + '=' + v + '\n'
+ const byteLen = Buffer.byteLength(s)
+ // the digits includes the length of the digits in ascii base-10
+ // so if it's 9 characters, then adding 1 for the 9 makes it 10
+ // which makes it 11 chars.
+ let digits = Math.floor(Math.log(byteLen) / Math.log(10)) + 1
+ if (byteLen + digits >= Math.pow(10, digits))
+ digits += 1
+ const len = digits + byteLen
+ return len + s
+ }
+}
+
+Pax.parse = (string, ex, g) => new Pax(merge(parseKV(string), ex), g)
+
+const merge = (a, b) =>
+ b ? Object.keys(a).reduce((s, k) => (s[k] = a[k], s), b) : a
+
+const parseKV = string =>
+ string
+ .replace(/\n$/, '')
+ .split('\n')
+ .reduce(parseKVLine, Object.create(null))
+
+const parseKVLine = (set, line) => {
+ const n = parseInt(line, 10)
+
+ // XXX Values with \n in them will fail this.
+ // Refactor to not be a naive line-by-line parse.
+ if (n !== Buffer.byteLength(line) + 1)
+ return set
+
+ line = line.substr((n + ' ').length)
+ const kv = line.split('=')
+ const k = kv.shift().replace(/^SCHILY\.(dev|ino|nlink)/, '$1')
+ if (!k)
+ return set
+
+ const v = kv.join('=')
+ set[k] = /^([A-Z]+\.)?([mac]|birth|creation)time$/.test(k)
+ ? new Date(v * 1000)
+ : /^[0-9]+$/.test(v) ? +v
+ : v
+ return set
+}
+
+module.exports = Pax
diff --git a/deps/npm/node_modules/tar/lib/read-entry.js b/deps/npm/node_modules/tar/lib/read-entry.js
new file mode 100644
index 0000000000..aa369c74f5
--- /dev/null
+++ b/deps/npm/node_modules/tar/lib/read-entry.js
@@ -0,0 +1,94 @@
+'use strict'
+const types = require('./types.js')
+const MiniPass = require('minipass')
+
+const SLURP = Symbol('slurp')
+module.exports = class ReadEntry extends MiniPass {
+ constructor (header, ex, gex) {
+ super()
+ this.extended = ex
+ this.globalExtended = gex
+ this.header = header
+ this.startBlockSize = 512 * Math.ceil(header.size / 512)
+ this.blockRemain = this.startBlockSize
+ this.remain = header.size
+ this.type = header.type
+ this.meta = false
+ this.ignore = false
+ switch (this.type) {
+ case 'File':
+ case 'OldFile':
+ case 'Link':
+ case 'SymbolicLink':
+ case 'CharacterDevice':
+ case 'BlockDevice':
+ case 'Directory':
+ case 'FIFO':
+ case 'ContiguousFile':
+ case 'GNUDumpDir':
+ break
+
+ case 'NextFileHasLongLinkpath':
+ case 'NextFileHasLongPath':
+ case 'OldGnuLongPath':
+ case 'GlobalExtendedHeader':
+ case 'ExtendedHeader':
+ case 'OldExtendedHeader':
+ this.meta = true
+ break
+
+ // NOTE: gnutar and bsdtar treat unrecognized types as 'File'
+ // it may be worth doing the same, but with a warning.
+ default:
+ this.ignore = true
+ }
+
+ this.path = header.path
+ this.mode = header.mode
+ if (this.mode)
+ this.mode = this.mode & 0o7777
+ this.uid = header.uid
+ this.gid = header.gid
+ this.uname = header.uname
+ this.gname = header.gname
+ this.size = header.size
+ this.mtime = header.mtime
+ this.atime = header.atime
+ this.ctime = header.ctime
+ this.linkpath = header.linkpath
+ this.uname = header.uname
+ this.gname = header.gname
+
+ if (ex) this[SLURP](ex)
+ if (gex) this[SLURP](gex, true)
+ }
+
+ write (data) {
+ const writeLen = data.length
+ if (writeLen > this.blockRemain)
+ throw new Error('writing more to entry than is appropriate')
+
+ const r = this.remain
+ const br = this.blockRemain
+ this.remain = Math.max(0, r - writeLen)
+ this.blockRemain = Math.max(0, br - writeLen)
+ if (this.ignore)
+ return true
+
+ if (r >= writeLen)
+ return super.write(data)
+
+ // r < writeLen
+ return super.write(data.slice(0, r))
+ }
+
+ [SLURP] (ex, global) {
+ for (let k in ex) {
+ // we slurp in everything except for the path attribute in
+ // a global extended header, because that's weird.
+ if (ex[k] !== null && ex[k] !== undefined &&
+ !(global && k === 'path'))
+ this[k] = ex[k]
+ }
+ }
+}
diff --git a/deps/npm/node_modules/tar/lib/replace.js b/deps/npm/node_modules/tar/lib/replace.js
new file mode 100644
index 0000000000..aac6b57fa8
--- /dev/null
+++ b/deps/npm/node_modules/tar/lib/replace.js
@@ -0,0 +1,211 @@
+'use strict'
+
+// tar -r
+const hlo = require('./high-level-opt.js')
+const Pack = require('./pack.js')
+const Parse = require('./parse.js')
+const fs = require('fs')
+const t = require('./list.js')
+const path = require('path')
+
+// starting at the head of the file, read a Header
+// If the checksum is invalid, that's our position to start writing
+// If it is, jump forward by the specified size (round up to 512)
+// and try again.
+// Write the new Pack stream starting there.
+
+const Header = require('./header.js')
+
+const r = module.exports = (opt_, files, cb) => {
+ const opt = hlo(opt_)
+
+ if (!opt.file)
+ throw new TypeError('file is required')
+
+ if (opt.gzip)
+ throw new TypeError('cannot append to compressed archives')
+
+ if (!files || !Array.isArray(files) || !files.length)
+ throw new TypeError('no files or directories specified')
+
+ files = Array.from(files)
+
+ return opt.sync ? replaceSync(opt, files)
+ : replace(opt, files, cb)
+}
+
+const replaceSync = (opt, files) => {
+ const p = new Pack.Sync(opt)
+
+ let threw = true
+ let fd
+ try {
+ try {
+ fd = fs.openSync(opt.file, 'r+')
+ } catch (er) {
+ if (er.code === 'ENOENT')
+ fd = fs.openSync(opt.file, 'w+')
+ else
+ throw er
+ }
+
+ const st = fs.fstatSync(fd)
+ const headBuf = Buffer.alloc(512)
+ let position
+
+ POSITION: for (position = 0; position < st.size; position += 512) {
+ for (let bufPos = 0, bytes = 0; bufPos < 512; bufPos += bytes) {
+ bytes = fs.readSync(
+ fd, headBuf, bufPos, headBuf.length - bufPos, position + bufPos
+ )
+
+ if (position === 0 && headBuf[0] === 0x1f && headBuf[1] === 0x8b)
+ throw new Error('cannot append to compressed archives')
+
+ if (!bytes)
+ break POSITION
+ }
+
+ let h = new Header(headBuf)
+ if (!h.cksumValid)
+ break
+ let entryBlockSize = 512 * Math.ceil(h.size / 512)
+ if (position + entryBlockSize + 512 > st.size)
+ break
+ // the 512 for the header we just parsed will be added as well
+ // also jump ahead all the blocks for the body
+ position += entryBlockSize
+ if (opt.mtimeCache)
+ opt.mtimeCache.set(h.path, h.mtime)
+ }
+
+ p.on('data', c => {
+ fs.writeSync(fd, c, 0, c.length, position)
+ position += c.length
+ })
+ p.on('end', _ => fs.closeSync(fd))
+
+ addFilesSync(p, files)
+ threw = false
+ } finally {
+ if (threw)
+ try { fs.closeSync(fd) } catch (er) {}
+ }
+}
+
+const replace = (opt, files, cb) => {
+ files = Array.from(files)
+ const p = new Pack(opt)
+
+ const getPos = (fd, size, cb_) => {
+ const cb = (er, pos) => {
+ if (er)
+ fs.close(fd, _ => cb_(er))
+ else
+ cb_(null, pos)
+ }
+
+ let position = 0
+ if (size === 0)
+ return cb(null, 0)
+
+ let bufPos = 0
+ const headBuf = Buffer.alloc(512)
+ const onread = (er, bytes) => {
+ if (er)
+ return cb(er)
+ bufPos += bytes
+ if (bufPos < 512 && bytes)
+ return fs.read(
+ fd, headBuf, bufPos, headBuf.length - bufPos,
+ position + bufPos, onread
+ )
+
+ if (position === 0 && headBuf[0] === 0x1f && headBuf[1] === 0x8b)
+ return cb(new Error('cannot append to compressed archives'))
+
+ // truncated header
+ if (bufPos < 512)
+ return cb(null, position)
+
+ const h = new Header(headBuf)
+ if (!h.cksumValid)
+ return cb(null, position)
+
+ const entryBlockSize = 512 * Math.ceil(h.size / 512)
+ if (position + entryBlockSize + 512 > size)
+ return cb(null, position)
+
+ position += entryBlockSize + 512
+ if (position >= size)
+ return cb(null, position)
+
+ if (opt.mtimeCache)
+ opt.mtimeCache.set(h.path, h.mtime)
+ bufPos = 0
+ fs.read(fd, headBuf, 0, 512, position, onread)
+ }
+ fs.read(fd, headBuf, 0, 512, position, onread)
+ }
+
+ const promise = new Promise((resolve, reject) => {
+ p.on('error', reject)
+ const onopen = (er, fd) => {
+ if (er) {
+ if (er.code === 'ENOENT')
+ return fs.open(opt.file, 'w+', onopen)
+ return reject(er)
+ }
+ fs.fstat(fd, (er, st) => {
+ if (er)
+ return reject(er)
+ getPos(fd, st.size, (er, position) => {
+ if (er)
+ return reject(er)
+ const stream = fs.createWriteStream(opt.file, {
+ fd: fd,
+ flags: 'r+',
+ start: position
+ })
+ p.pipe(stream)
+ stream.on('error', reject)
+ stream.on('close', resolve)
+ addFilesAsync(p, files)
+ })
+ })
+ }
+ fs.open(opt.file, 'r+', onopen)
+ })
+
+ return cb ? promise.then(cb, cb) : promise
+}
+
+const addFilesSync = (p, files) => {
+ files.forEach(file => {
+ if (file.charAt(0) === '@')
+ t({
+ file: path.resolve(p.cwd, file.substr(1)),
+ sync: true,
+ noResume: true,
+ onentry: entry => p.add(entry)
+ })
+ else
+ p.add(file)
+ })
+ p.end()
+}
+
+const addFilesAsync = (p, files) => {
+ while (files.length) {
+ const file = files.shift()
+ if (file.charAt(0) === '@')
+ return t({
+ file: path.resolve(p.cwd, file.substr(1)),
+ noResume: true,
+ onentry: entry => p.add(entry)
+ }).then(_ => addFilesAsync(p, files))
+ else
+ p.add(file)
+ }
+ p.end()
+}
diff --git a/deps/npm/node_modules/tar/lib/types.js b/deps/npm/node_modules/tar/lib/types.js
new file mode 100644
index 0000000000..df425652b5
--- /dev/null
+++ b/deps/npm/node_modules/tar/lib/types.js
@@ -0,0 +1,44 @@
+'use strict'
+// map types from key to human-friendly name
+exports.name = new Map([
+ ['0', 'File'],
+ // same as File
+ ['', 'OldFile'],
+ ['1', 'Link'],
+ ['2', 'SymbolicLink'],
+ // Devices and FIFOs aren't fully supported
+ // they are parsed, but skipped when unpacking
+ ['3', 'CharacterDevice'],
+ ['4', 'BlockDevice'],
+ ['5', 'Directory'],
+ ['6', 'FIFO'],
+ // same as File
+ ['7', 'ContiguousFile'],
+ // pax headers
+ ['g', 'GlobalExtendedHeader'],
+ ['x', 'ExtendedHeader'],
+ // vendor-specific stuff
+ // skip
+ ['A', 'SolarisACL'],
+ // like 5, but with data, which should be skipped
+ ['D', 'GNUDumpDir'],
+ // metadata only, skip
+ ['I', 'Inode'],
+ // data = link path of next file
+ ['K', 'NextFileHasLongLinkpath'],
+ // data = path of next file
+ ['L', 'NextFileHasLongPath'],
+ // skip
+ ['M', 'ContinuationFile'],
+ // like L
+ ['N', 'OldGnuLongPath'],
+ // skip
+ ['S', 'SparseFile'],
+ // skip
+ ['V', 'TapeVolumeHeader'],
+ // like x
+ ['X', 'OldExtendedHeader']
+])
+
+// map the other direction
+exports.code = new Map(Array.from(exports.name).map(kv => [kv[1], kv[0]]))
diff --git a/deps/npm/node_modules/tar/lib/unpack.js b/deps/npm/node_modules/tar/lib/unpack.js
new file mode 100644
index 0000000000..e8c80c6fd5
--- /dev/null
+++ b/deps/npm/node_modules/tar/lib/unpack.js
@@ -0,0 +1,481 @@
+'use strict'
+
+const assert = require('assert')
+const EE = require('events').EventEmitter
+const Parser = require('./parse.js')
+const fs = require('fs')
+const path = require('path')
+const mkdir = require('./mkdir.js')
+const mkdirSync = mkdir.sync
+const wc = require('./winchars.js')
+
+const ONENTRY = Symbol('onEntry')
+const CHECKFS = Symbol('checkFs')
+const MAKEFS = Symbol('makeFs')
+const FILE = Symbol('file')
+const DIRECTORY = Symbol('directory')
+const LINK = Symbol('link')
+const SYMLINK = Symbol('symlink')
+const HARDLINK = Symbol('hardlink')
+const UNSUPPORTED = Symbol('unsupported')
+const UNKNOWN = Symbol('unknown')
+const CHECKPATH = Symbol('checkPath')
+const MKDIR = Symbol('mkdir')
+const ONERROR = Symbol('onError')
+const PENDING = Symbol('pending')
+const PEND = Symbol('pend')
+const UNPEND = Symbol('unpend')
+const ENDED = Symbol('ended')
+const MAYBECLOSE = Symbol('maybeClose')
+const SKIP = Symbol('skip')
+const DOCHOWN = Symbol('doChown')
+const UID = Symbol('uid')
+const GID = Symbol('gid')
+
+class Unpack extends Parser {
+ constructor (opt) {
+ if (!opt)
+ opt = {}
+
+ opt.ondone = _ => {
+ this[ENDED] = true
+ this[MAYBECLOSE]()
+ }
+
+ super(opt)
+
+ this.writable = true
+ this.readable = false
+
+ this[PENDING] = 0
+ this[ENDED] = false
+
+ this.dirCache = opt.dirCache || new Map()
+
+ if (typeof opt.uid === 'number' || typeof opt.gid === 'number') {
+ // need both or neither
+ if (typeof opt.uid !== 'number' || typeof opt.gid !== 'number')
+ throw new TypeError('cannot set owner without number uid and gid')
+ if (opt.preserveOwner)
+ throw new TypeError(
+ 'cannot preserve owner in archive and also set owner explicitly')
+ this.uid = opt.uid
+ this.gid = opt.gid
+ this.setOwner = true
+ } else {
+ this.uid = null
+ this.gid = null
+ this.setOwner = false
+ }
+
+ // default true for root
+ if (opt.preserveOwner === undefined && typeof opt.uid !== 'number')
+ this.preserveOwner = process.getuid && process.getuid() === 0
+ else
+ this.preserveOwner = !!opt.preserveOwner
+
+ this.processUid = (this.preserveOwner || this.setOwner) && process.getuid ?
+ process.getuid() : null
+ this.processGid = (this.preserveOwner || this.setOwner) && process.getgid ?
+ process.getgid() : null
+
+ // turn ><?| in filenames into 0xf000-higher encoded forms
+ this.win32 = !!opt.win32 || process.platform === 'win32'
+
+ // do not unpack over files that are newer than what's in the archive
+ this.newer = !!opt.newer
+
+ // do not unpack over ANY files
+ this.keep = !!opt.keep
+
+ // do not set mtime/atime of extracted entries
+ this.noMtime = !!opt.noMtime
+
+ // allow .., absolute path entries, and unpacking through symlinks
+ // without this, warn and skip .., relativize absolutes, and error
+ // on symlinks in extraction path
+ this.preservePaths = !!opt.preservePaths
+
+ // unlink files and links before writing. This breaks existing hard
+ // links, and removes symlink directories rather than erroring
+ this.unlink = !!opt.unlink
+
+ this.cwd = path.resolve(opt.cwd || process.cwd())
+ this.strip = +opt.strip || 0
+ this.processUmask = process.umask()
+ this.umask = typeof opt.umask === 'number' ? opt.umask : this.processUmask
+ // default mode for dirs created as parents
+ this.dmode = opt.dmode || (0o0777 & (~this.umask))
+ this.fmode = opt.fmode || (0o0666 & (~this.umask))
+ this.on('entry', entry => this[ONENTRY](entry))
+ }
+
+ [MAYBECLOSE] () {
+ if (this[ENDED] && this[PENDING] === 0) {
+ this.emit('prefinish')
+ this.emit('finish')
+ this.emit('end')
+ this.emit('close')
+ }
+ }
+
+ [CHECKPATH] (entry) {
+ if (this.strip) {
+ const parts = entry.path.split(/\/|\\/)
+ if (parts.length < this.strip)
+ return false
+ entry.path = parts.slice(this.strip).join('/')
+ }
+
+ if (!this.preservePaths) {
+ const p = entry.path
+ if (p.match(/(^|\/|\\)\.\.(\\|\/|$)/)) {
+ this.warn('path contains \'..\'', p)
+ return false
+ }
+
+ // absolutes on posix are also absolutes on win32
+ // so we only need to test this one to get both
+ if (path.win32.isAbsolute(p)) {
+ const parsed = path.win32.parse(p)
+ this.warn('stripping ' + parsed.root + ' from absolute path', p)
+ entry.path = p.substr(parsed.root.length)
+ }
+ }
+
+ // only encode : chars that aren't drive letter indicators
+ if (this.win32) {
+ const parsed = path.win32.parse(entry.path)
+ entry.path = parsed.root === '' ? wc.encode(entry.path)
+ : parsed.root + wc.encode(entry.path.substr(parsed.root.length))
+ }
+
+ if (path.isAbsolute(entry.path))
+ entry.absolute = entry.path
+ else
+ entry.absolute = path.resolve(this.cwd, entry.path)
+
+ return true
+ }
+
+ [ONENTRY] (entry) {
+ if (!this[CHECKPATH](entry))
+ return entry.resume()
+
+ assert.equal(typeof entry.absolute, 'string')
+
+ switch (entry.type) {
+ case 'Directory':
+ case 'GNUDumpDir':
+ if (entry.mode)
+ entry.mode = entry.mode | 0o700
+
+ case 'File':
+ case 'OldFile':
+ case 'ContiguousFile':
+ case 'Link':
+ case 'SymbolicLink':
+ return this[CHECKFS](entry)
+
+ case 'CharacterDevice':
+ case 'BlockDevice':
+ case 'FIFO':
+ return this[UNSUPPORTED](entry)
+ }
+ }
+
+ [ONERROR] (er, entry) {
+ // Cwd has to exist, or else nothing works. That's serious.
+ // Other errors are warnings, which raise the error in strict
+ // mode, but otherwise continue on.
+ if (er.name === 'CwdError')
+ this.emit('error', er)
+ else {
+ this.warn(er.message, er)
+ this[UNPEND]()
+ entry.resume()
+ }
+ }
+
+ [MKDIR] (dir, mode, cb) {
+ mkdir(dir, {
+ uid: this.uid,
+ gid: this.gid,
+ processUid: this.processUid,
+ processGid: this.processGid,
+ umask: this.processUmask,
+ preserve: this.preservePaths,
+ unlink: this.unlink,
+ cache: this.dirCache,
+ cwd: this.cwd,
+ mode: mode
+ }, cb)
+ }
+
+ [DOCHOWN] (entry) {
+ // in preserve owner mode, chown if the entry doesn't match process
+ // in set owner mode, chown if setting doesn't match process
+ return this.preserveOwner &&
+ ( typeof entry.uid === 'number' && entry.uid !== this.processUid ||
+ typeof entry.gid === 'number' && entry.gid !== this.processGid )
+ ||
+ ( typeof this.uid === 'number' && this.uid !== this.processUid ||
+ typeof this.gid === 'number' && this.gid !== this.processGid )
+ }
+
+ [UID] (entry) {
+ return typeof this.uid === 'number' ? this.uid
+ : typeof entry.uid === 'number' ? entry.uid
+ : this.processUid
+ }
+
+ [GID] (entry) {
+ return typeof this.gid === 'number' ? this.gid
+ : typeof entry.gid === 'number' ? entry.gid
+ : this.processGid
+ }
+
+ [FILE] (entry) {
+ const mode = entry.mode & 0o7777 || this.fmode
+ const stream = fs.createWriteStream(entry.absolute, { mode: mode })
+ stream.on('error', er => this[ONERROR](er, entry))
+
+ const queue = []
+ const processQueue = _ => {
+ const action = queue.shift()
+ if (action)
+ action(processQueue)
+ else
+ this[UNPEND]()
+ }
+
+ stream.on('close', _ => {
+ if (entry.mtime && !this.noMtime)
+ queue.push(cb =>
+ fs.utimes(entry.absolute, entry.atime || new Date(), entry.mtime, cb))
+ if (this[DOCHOWN](entry))
+ queue.push(cb =>
+ fs.chown(entry.absolute, this[UID](entry), this[GID](entry), cb))
+ processQueue()
+ })
+ entry.pipe(stream)
+ }
+
+ [DIRECTORY] (entry) {
+ const mode = entry.mode & 0o7777 || this.dmode
+ this[MKDIR](entry.absolute, mode, er => {
+ if (er)
+ return this[ONERROR](er, entry)
+
+ const queue = []
+ const processQueue = _ => {
+ const action = queue.shift()
+ if (action)
+ action(processQueue)
+ else {
+ this[UNPEND]()
+ entry.resume()
+ }
+ }
+
+ if (entry.mtime && !this.noMtime)
+ queue.push(cb =>
+ fs.utimes(entry.absolute, entry.atime || new Date(), entry.mtime, cb))
+ if (this[DOCHOWN](entry))
+ queue.push(cb =>
+ fs.chown(entry.absolute, this[UID](entry), this[GID](entry), cb))
+
+ processQueue()
+ })
+ }
+
+ [UNSUPPORTED] (entry) {
+ this.warn('unsupported entry type: ' + entry.type, entry)
+ entry.resume()
+ }
+
+ [SYMLINK] (entry) {
+ this[LINK](entry, entry.linkpath, 'symlink')
+ }
+
+ [HARDLINK] (entry) {
+ this[LINK](entry, path.resolve(this.cwd, entry.linkpath), 'link')
+ }
+
+ [PEND] () {
+ this[PENDING]++
+ }
+
+ [UNPEND] () {
+ this[PENDING]--
+ this[MAYBECLOSE]()
+ }
+
+ [SKIP] (entry) {
+ this[UNPEND]()
+ entry.resume()
+ }
+
+ // check if a thing is there, and if so, try to clobber it
+ [CHECKFS] (entry) {
+ this[PEND]()
+ this[MKDIR](path.dirname(entry.absolute), this.dmode, er => {
+ if (er)
+ return this[ONERROR](er, entry)
+ fs.lstat(entry.absolute, (er, st) => {
+ if (st && (this.keep || this.newer && st.mtime > entry.mtime))
+ this[SKIP](entry)
+ else if (er || (entry.type === 'File' && !this.unlink && st.isFile()))
+ this[MAKEFS](null, entry)
+ else if (st.isDirectory()) {
+ if (entry.type === 'Directory') {
+ if (!entry.mode || (st.mode & 0o7777) === entry.mode)
+ this[MAKEFS](null, entry)
+ else
+ fs.chmod(entry.absolute, entry.mode, er => this[MAKEFS](er, entry))
+ } else
+ fs.rmdir(entry.absolute, er => this[MAKEFS](er, entry))
+ } else
+ fs.unlink(entry.absolute, er => this[MAKEFS](er, entry))
+ })
+ })
+ }
+
+ [MAKEFS] (er, entry) {
+ if (er)
+ return this[ONERROR](er, entry)
+
+ switch (entry.type) {
+ case 'File':
+ case 'OldFile':
+ case 'ContiguousFile':
+ return this[FILE](entry)
+
+ case 'Link':
+ return this[HARDLINK](entry)
+
+ case 'SymbolicLink':
+ return this[SYMLINK](entry)
+
+ case 'Directory':
+ case 'GNUDumpDir':
+ return this[DIRECTORY](entry)
+ }
+ }
+
+ [LINK] (entry, linkpath, link) {
+ // XXX: get the type ('file' or 'dir') for windows
+ fs[link](linkpath, entry.absolute, er => {
+ if (er)
+ return this[ONERROR](er, entry)
+ this[UNPEND]()
+ entry.resume()
+ })
+ }
+}
+
+class UnpackSync extends Unpack {
+ constructor (opt) {
+ super(opt)
+ }
+
+ [CHECKFS] (entry) {
+ const er = this[MKDIR](path.dirname(entry.absolute), this.dmode)
+ if (er)
+ return this[ONERROR](er, entry)
+ try {
+ const st = fs.lstatSync(entry.absolute)
+ if (this.keep || this.newer && st.mtime > entry.mtime)
+ return this[SKIP](entry)
+ else if (entry.type === 'File' && !this.unlink && st.isFile())
+ return this[MAKEFS](null, entry)
+ else {
+ try {
+ if (st.isDirectory()) {
+ if (entry.type === 'Directory') {
+ if (entry.mode && (st.mode & 0o7777) !== entry.mode)
+ fs.chmodSync(entry.absolute, entry.mode)
+ } else
+ fs.rmdirSync(entry.absolute)
+ } else
+ fs.unlinkSync(entry.absolute)
+ return this[MAKEFS](null, entry)
+ } catch (er) {
+ return this[ONERROR](er, entry)
+ }
+ }
+ } catch (er) {
+ return this[MAKEFS](null, entry)
+ }
+ }
+
+ [FILE] (entry) {
+ const mode = entry.mode & 0o7777 || this.fmode
+ try {
+ const fd = fs.openSync(entry.absolute, 'w', mode)
+ entry.on('data', buf => fs.writeSync(fd, buf, 0, buf.length, null))
+ entry.on('end', _ => {
+ if (entry.mtime && !this.noMtime) {
+ try {
+ fs.futimesSync(fd, entry.atime || new Date(), entry.mtime)
+ } catch (er) {}
+ }
+ if (this[DOCHOWN](entry)) {
+ try {
+ fs.fchownSync(fd, this[UID](entry), this[GID](entry))
+ } catch (er) {}
+ }
+ try { fs.closeSync(fd) } catch (er) { this[ONERROR](er, entry) }
+ })
+ } catch (er) { this[ONERROR](er, entry) }
+ }
+
+ [DIRECTORY] (entry) {
+ const mode = entry.mode & 0o7777 || this.dmode
+ const er = this[MKDIR](entry.absolute, mode)
+ if (er)
+ return this[ONERROR](er, entry)
+ if (entry.mtime && !this.noMtime) {
+ try {
+ fs.utimesSync(entry.absolute, entry.atime || new Date(), entry.mtime)
+ } catch (er) {}
+ }
+ if (this[DOCHOWN](entry)) {
+ try {
+ fs.chownSync(entry.absolute, this[UID](entry), this[GID](entry))
+ } catch (er) {}
+ }
+ entry.resume()
+ }
+
+ [MKDIR] (dir, mode) {
+ try {
+ return mkdir.sync(dir, {
+ uid: this.uid,
+ gid: this.gid,
+ processUid: this.processUid,
+ processGid: this.processGid,
+ umask: this.processUmask,
+ preserve: this.preservePaths,
+ unlink: this.unlink,
+ cache: this.dirCache,
+ cwd: this.cwd,
+ mode: mode
+ })
+ } catch (er) {
+ return er
+ }
+ }
+
+ [LINK] (entry, linkpath, link) {
+ try {
+ fs[link + 'Sync'](linkpath, entry.absolute)
+ entry.resume()
+ } catch (er) {
+ return this[ONERROR](er, entry)
+ }
+ }
+}
+
+Unpack.Sync = UnpackSync
+module.exports = Unpack
diff --git a/deps/npm/node_modules/tar/lib/update.js b/deps/npm/node_modules/tar/lib/update.js
new file mode 100644
index 0000000000..16c3e93ed5
--- /dev/null
+++ b/deps/npm/node_modules/tar/lib/update.js
@@ -0,0 +1,36 @@
+'use strict'
+
+// tar -u
+
+const hlo = require('./high-level-opt.js')
+const r = require('./replace.js')
+// just call tar.r with the filter and mtimeCache
+
+const u = module.exports = (opt_, files, cb) => {
+ const opt = hlo(opt_)
+
+ if (!opt.file)
+ throw new TypeError('file is required')
+
+ if (opt.gzip)
+ throw new TypeError('cannot append to compressed archives')
+
+ if (!files || !Array.isArray(files) || !files.length)
+ throw new TypeError('no files or directories specified')
+
+ files = Array.from(files)
+
+ mtimeFilter(opt)
+ return r(opt, files, cb)
+}
+
+const mtimeFilter = opt => {
+ const filter = opt.filter
+
+ if (!opt.mtimeCache)
+ opt.mtimeCache = new Map()
+
+ opt.filter = filter ? (path, stat) =>
+ filter(path, stat) && !(opt.mtimeCache.get(path) > stat.mtime)
+ : (path, stat) => !(opt.mtimeCache.get(path) > stat.mtime)
+}
diff --git a/deps/npm/node_modules/tar/lib/warn-mixin.js b/deps/npm/node_modules/tar/lib/warn-mixin.js
new file mode 100644
index 0000000000..94a4b9b990
--- /dev/null
+++ b/deps/npm/node_modules/tar/lib/warn-mixin.js
@@ -0,0 +1,14 @@
+'use strict'
+module.exports = Base => class extends Base {
+ warn (msg, data) {
+ if (!this.strict)
+ this.emit('warn', msg, data)
+ else if (data instanceof Error)
+ this.emit('error', data)
+ else {
+ const er = new Error(msg)
+ er.data = data
+ this.emit('error', er)
+ }
+ }
+}
diff --git a/deps/npm/node_modules/tar/lib/winchars.js b/deps/npm/node_modules/tar/lib/winchars.js
new file mode 100644
index 0000000000..cf6ea06061
--- /dev/null
+++ b/deps/npm/node_modules/tar/lib/winchars.js
@@ -0,0 +1,23 @@
+'use strict'
+
+// When writing files on Windows, translate the characters to their
+// 0xf000 higher-encoded versions.
+
+const raw = [
+ '|',
+ '<',
+ '>',
+ '?',
+ ':'
+]
+
+const win = raw.map(char =>
+ String.fromCharCode(0xf000 + char.charCodeAt(0)))
+
+const toWin = new Map(raw.map((char, i) => [char, win[i]]))
+const toRaw = new Map(win.map((char, i) => [char, raw[i]]))
+
+module.exports = {
+ encode: s => raw.reduce((s, c) => s.split(c).join(toWin.get(c)), s),
+ decode: s => win.reduce((s, c) => s.split(c).join(toRaw.get(c)), s)
+}
diff --git a/deps/npm/node_modules/tar/lib/write-entry.js b/deps/npm/node_modules/tar/lib/write-entry.js
new file mode 100644
index 0000000000..f562bf138a
--- /dev/null
+++ b/deps/npm/node_modules/tar/lib/write-entry.js
@@ -0,0 +1,395 @@
+'use strict'
+const MiniPass = require('minipass')
+const Pax = require('./pax.js')
+const Header = require('./header.js')
+const ReadEntry = require('./read-entry.js')
+const fs = require('fs')
+const path = require('path')
+
+const types = require('./types.js')
+const maxReadSize = 16 * 1024 * 1024
+const PROCESS = Symbol('process')
+const FILE = Symbol('file')
+const DIRECTORY = Symbol('directory')
+const SYMLINK = Symbol('symlink')
+const HARDLINK = Symbol('hardlink')
+const HEADER = Symbol('header')
+const READ = Symbol('read')
+const LSTAT = Symbol('lstat')
+const ONLSTAT = Symbol('onlstat')
+const ONREAD = Symbol('onread')
+const ONREADLINK = Symbol('onreadlink')
+const OPENFILE = Symbol('openfile')
+const ONOPENFILE = Symbol('onopenfile')
+const CLOSE = Symbol('close')
+const warner = require('./warn-mixin.js')
+const winchars = require('./winchars.js')
+
+const WriteEntry = warner(class WriteEntry extends MiniPass {
+ constructor (p, opt) {
+ opt = opt || {}
+ super(opt)
+ if (typeof p !== 'string')
+ throw new TypeError('path is required')
+ this.path = p
+ // suppress atime, ctime, uid, gid, uname, gname
+ this.portable = !!opt.portable
+ // until node has builtin pwnam functions, this'll have to do
+ this.myuid = process.getuid && process.getuid()
+ this.myuser = process.env.USER || ''
+ this.maxReadSize = opt.maxReadSize || maxReadSize
+ this.linkCache = opt.linkCache || new Map()
+ this.statCache = opt.statCache || new Map()
+ this.preservePaths = !!opt.preservePaths
+ this.cwd = opt.cwd || process.cwd()
+ this.strict = !!opt.strict
+ this.noPax = !!opt.noPax
+ if (typeof opt.onwarn === 'function')
+ this.on('warn', opt.onwarn)
+
+ if (!this.preservePaths && path.win32.isAbsolute(p)) {
+ // absolutes on posix are also absolutes on win32
+ // so we only need to test this one to get both
+ const parsed = path.win32.parse(p)
+ this.warn('stripping ' + parsed.root + ' from absolute path', p)
+ this.path = p.substr(parsed.root.length)
+ }
+
+ this.win32 = !!opt.win32 || process.platform === 'win32'
+ if (this.win32) {
+ this.path = winchars.decode(this.path.replace(/\\/g, '/'))
+ p = p.replace(/\\/g, '/')
+ }
+
+ this.absolute = opt.absolute || path.resolve(this.cwd, p)
+
+ if (this.path === '')
+ this.path = './'
+
+ if (this.statCache.has(this.absolute))
+ this[ONLSTAT](this.statCache.get(this.absolute))
+ else
+ this[LSTAT]()
+ }
+
+ [LSTAT] () {
+ fs.lstat(this.absolute, (er, stat) => {
+ if (er)
+ return this.emit('error', er)
+ this[ONLSTAT](stat)
+ })
+ }
+
+ [ONLSTAT] (stat) {
+ this.statCache.set(this.absolute, stat)
+ this.stat = stat
+ if (!stat.isFile())
+ stat.size = 0
+ this.type = getType(stat)
+ this.emit('stat', stat)
+ this[PROCESS]()
+ }
+
+ [PROCESS] () {
+ switch (this.type) {
+ case 'File': return this[FILE]()
+ case 'Directory': return this[DIRECTORY]()
+ case 'SymbolicLink': return this[SYMLINK]()
+ // unsupported types are ignored.
+ default: return this.end()
+ }
+ }
+
+ [HEADER] () {
+ this.header = new Header({
+ path: this.path,
+ linkpath: this.linkpath,
+ // only the permissions and setuid/setgid/sticky bitflags
+ // not the higher-order bits that specify file type
+ mode: this.stat.mode & 0o7777,
+ uid: this.portable ? null : this.stat.uid,
+ gid: this.portable ? null : this.stat.gid,
+ size: this.stat.size,
+ mtime: this.type === 'Directory' && this.portable
+ ? null : this.stat.mtime,
+ type: this.type,
+ uname: this.portable ? null :
+ this.stat.uid === this.myuid ? this.myuser : '',
+ atime: this.portable ? null : this.stat.atime,
+ ctime: this.portable ? null : this.stat.ctime
+ })
+
+ if (this.header.encode() && !this.noPax)
+ this.write(new Pax({
+ atime: this.portable ? null : this.header.atime,
+ ctime: this.portable ? null : this.header.ctime,
+ gid: this.portable ? null : this.header.gid,
+ mtime: this.header.mtime,
+ path: this.path,
+ linkpath: this.linkpath,
+ size: this.header.size,
+ uid: this.portable ? null : this.header.uid,
+ uname: this.portable ? null : this.header.uname,
+ dev: this.portable ? null : this.stat.dev,
+ ino: this.portable ? null : this.stat.ino,
+ nlink: this.portable ? null : this.stat.nlink
+ }).encode())
+ this.write(this.header.block)
+ }
+
+ [DIRECTORY] () {
+ if (this.path.substr(-1) !== '/')
+ this.path += '/'
+ this.stat.size = 0
+ this[HEADER]()
+ this.end()
+ }
+
+ [SYMLINK] () {
+ fs.readlink(this.absolute, (er, linkpath) => {
+ if (er)
+ return this.emit('error', er)
+ this[ONREADLINK](linkpath)
+ })
+ }
+
+ [ONREADLINK] (linkpath) {
+ this.linkpath = linkpath
+ this[HEADER]()
+ this.end()
+ }
+
+ [HARDLINK] (linkpath) {
+ this.type = 'Link'
+ this.linkpath = path.relative(this.cwd, linkpath)
+ this.stat.size = 0
+ this[HEADER]()
+ this.end()
+ }
+
+ [FILE] () {
+ if (this.stat.nlink > 1) {
+ const linkKey = this.stat.dev + ':' + this.stat.ino
+ if (this.linkCache.has(linkKey)) {
+ const linkpath = this.linkCache.get(linkKey)
+ if (linkpath.indexOf(this.cwd) === 0)
+ return this[HARDLINK](linkpath)
+ }
+ this.linkCache.set(linkKey, this.absolute)
+ }
+
+ this[HEADER]()
+ if (this.stat.size === 0)
+ return this.end()
+
+ this[OPENFILE]()
+ }
+
+ [OPENFILE] () {
+ fs.open(this.absolute, 'r', (er, fd) => {
+ if (er)
+ return this.emit('error', er)
+ this[ONOPENFILE](fd)
+ })
+ }
+
+ [ONOPENFILE] (fd) {
+ const blockLen = 512 * Math.ceil(this.stat.size / 512)
+ const bufLen = Math.min(blockLen, this.maxReadSize)
+ const buf = Buffer.allocUnsafe(bufLen)
+ this[READ](fd, buf, 0, buf.length, 0, this.stat.size, blockLen)
+ }
+
+ [READ] (fd, buf, offset, length, pos, remain, blockRemain) {
+ fs.read(fd, buf, offset, length, pos, (er, bytesRead) => {
+ if (er)
+ return this[CLOSE](fd, _ => this.emit('error', er))
+ this[ONREAD](fd, buf, offset, length, pos, remain, blockRemain, bytesRead)
+ })
+ }
+
+ [CLOSE] (fd, cb) {
+ fs.close(fd, cb)
+ }
+
+ [ONREAD] (fd, buf, offset, length, pos, remain, blockRemain, bytesRead) {
+ if (bytesRead <= 0 && remain > 0) {
+ const er = new Error('unexpected EOF')
+ er.path = this.absolute
+ er.syscall = 'read'
+ er.code = 'EOF'
+ this.emit('error', er)
+ }
+
+ // null out the rest of the buffer, if we could fit the block padding
+ if (bytesRead === remain) {
+ for (let i = bytesRead; i < length && bytesRead < blockRemain; i++) {
+ buf[i + offset] = 0
+ bytesRead ++
+ remain ++
+ }
+ }
+
+ const writeBuf = offset === 0 && bytesRead === buf.length ?
+ buf : buf.slice(offset, offset + bytesRead)
+ remain -= bytesRead
+ blockRemain -= bytesRead
+ pos += bytesRead
+ offset += bytesRead
+
+ this.write(writeBuf)
+
+ if (!remain) {
+ if (blockRemain)
+ this.write(Buffer.alloc(blockRemain))
+ this.end()
+ this[CLOSE](fd, _ => _)
+ return
+ }
+
+ if (offset >= length) {
+ buf = Buffer.allocUnsafe(length)
+ offset = 0
+ }
+ length = buf.length - offset
+ this[READ](fd, buf, offset, length, pos, remain, blockRemain)
+ }
+})
+
+class WriteEntrySync extends WriteEntry {
+ constructor (path, opt) {
+ super(path, opt)
+ }
+
+ [LSTAT] () {
+ this[ONLSTAT](fs.lstatSync(this.absolute))
+ }
+
+ [SYMLINK] () {
+ this[ONREADLINK](fs.readlinkSync(this.absolute))
+ }
+
+ [OPENFILE] () {
+ this[ONOPENFILE](fs.openSync(this.absolute, 'r'))
+ }
+
+ [READ] (fd, buf, offset, length, pos, remain, blockRemain) {
+ let threw = true
+ try {
+ const bytesRead = fs.readSync(fd, buf, offset, length, pos)
+ this[ONREAD](fd, buf, offset, length, pos, remain, blockRemain, bytesRead)
+ threw = false
+ } finally {
+ if (threw)
+ try { this[CLOSE](fd) } catch (er) {}
+ }
+ }
+
+ [CLOSE] (fd) {
+ fs.closeSync(fd)
+ }
+}
+
+const WriteEntryTar = warner(class WriteEntryTar extends MiniPass {
+ constructor (readEntry, opt) {
+ opt = opt || {}
+ super(opt)
+ this.readEntry = readEntry
+ this.type = readEntry.type
+ this.path = readEntry.path
+ this.mode = readEntry.mode
+ if (this.mode)
+ this.mode = this.mode & 0o7777
+ this.uid = readEntry.uid
+ this.gid = readEntry.gid
+ this.uname = readEntry.uname
+ this.gname = readEntry.gname
+ this.size = readEntry.size
+ this.mtime = readEntry.mtime
+ this.atime = readEntry.atime
+ this.ctime = readEntry.ctime
+ this.linkpath = readEntry.linkpath
+ this.uname = readEntry.uname
+ this.gname = readEntry.gname
+
+ this.preservePaths = !!opt.preservePaths
+ this.portable = !!opt.portable
+ this.strict = !!opt.strict
+ this.noPax = !!opt.noPax
+
+ if (typeof opt.onwarn === 'function')
+ this.on('warn', opt.onwarn)
+
+ if (path.isAbsolute(this.path) && !this.preservePaths) {
+ const parsed = path.parse(this.path)
+ this.warn(
+ 'stripping ' + parsed.root + ' from absolute path',
+ this.path
+ )
+ this.path = this.path.substr(parsed.root.length)
+ }
+
+ this.remain = readEntry.size
+ this.blockRemain = readEntry.startBlockSize
+
+ this.header = new Header({
+ path: this.path,
+ linkpath: this.linkpath,
+ // only the permissions and setuid/setgid/sticky bitflags
+ // not the higher-order bits that specify file type
+ mode: this.mode,
+ uid: this.portable ? null : this.uid,
+ gid: this.portable ? null : this.gid,
+ size: this.size,
+ mtime: this.mtime,
+ type: this.type,
+ uname: this.portable ? null : this.uname,
+ atime: this.portable ? null : this.atime,
+ ctime: this.portable ? null : this.ctime
+ })
+
+ if (this.header.encode() && !this.noPax)
+ super.write(new Pax({
+ atime: this.portable ? null : this.atime,
+ ctime: this.portable ? null : this.ctime,
+ gid: this.portable ? null : this.gid,
+ mtime: this.mtime,
+ path: this.path,
+ linkpath: this.linkpath,
+ size: this.size,
+ uid: this.portable ? null : this.uid,
+ uname: this.portable ? null : this.uname,
+ dev: this.portable ? null : this.readEntry.dev,
+ ino: this.portable ? null : this.readEntry.ino,
+ nlink: this.portable ? null : this.readEntry.nlink
+ }).encode())
+
+ super.write(this.header.block)
+ readEntry.pipe(this)
+ }
+
+ write (data) {
+ const writeLen = data.length
+ if (writeLen > this.blockRemain)
+ throw new Error('writing more to entry than is appropriate')
+ this.blockRemain -= writeLen
+ return super.write(data)
+ }
+
+ end () {
+ if (this.blockRemain)
+ this.write(Buffer.alloc(this.blockRemain))
+ return super.end()
+ }
+})
+
+WriteEntry.Sync = WriteEntrySync
+WriteEntry.Tar = WriteEntryTar
+
+const getType = stat =>
+ stat.isFile() ? 'File'
+ : stat.isDirectory() ? 'Directory'
+ : stat.isSymbolicLink() ? 'SymbolicLink'
+ : 'Unsupported'
+
+module.exports = WriteEntry