| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255 | var constants = require('fs-constants')var eos = require('end-of-stream')var inherits = require('inherits')var alloc = Buffer.allocvar Readable = require('readable-stream').Readablevar Writable = require('readable-stream').Writablevar StringDecoder = require('string_decoder').StringDecodervar headers = require('./headers')var DMODE = parseInt('755', 8)var FMODE = parseInt('644', 8)var END_OF_TAR = alloc(1024)var noop = function () {}var overflow = function (self, size) {  size &= 511  if (size) self.push(END_OF_TAR.slice(0, 512 - size))}function modeToType (mode) {  switch (mode & constants.S_IFMT) {    case constants.S_IFBLK: return 'block-device'    case constants.S_IFCHR: return 'character-device'    case constants.S_IFDIR: return 'directory'    case constants.S_IFIFO: return 'fifo'    case constants.S_IFLNK: return 'symlink'  }  return 'file'}var Sink = function (to) {  Writable.call(this)  this.written = 0  this._to = to  this._destroyed = false}inherits(Sink, Writable)Sink.prototype._write = function (data, enc, cb) {  this.written += data.length  if (this._to.push(data)) return cb()  this._to._drain = cb}Sink.prototype.destroy = function () {  if (this._destroyed) return  this._destroyed = true  this.emit('close')}var LinkSink = function () {  Writable.call(this)  this.linkname = ''  this._decoder = new StringDecoder('utf-8')  this._destroyed = false}inherits(LinkSink, Writable)LinkSink.prototype._write = function (data, enc, cb) {  this.linkname += this._decoder.write(data)  cb()}LinkSink.prototype.destroy = function () {  if (this._destroyed) return  this._destroyed = true  this.emit('close')}var Void = function () {  Writable.call(this)  this._destroyed = false}inherits(Void, Writable)Void.prototype._write = function (data, enc, cb) {  cb(new Error('No body allowed for this entry'))}Void.prototype.destroy = function () {  if (this._destroyed) return  this._destroyed = true  this.emit('close')}var Pack = function (opts) {  if (!(this instanceof Pack)) return new Pack(opts)  Readable.call(this, opts)  this._drain = noop  this._finalized = false  this._finalizing = false  this._destroyed = false  this._stream = null}inherits(Pack, Readable)Pack.prototype.entry = function (header, buffer, callback) {  if (this._stream) throw new Error('already piping an entry')  if (this._finalized || this._destroyed) return  if (typeof buffer === 'function') {    callback = buffer    buffer = null  }  if (!callback) callback = noop  var self = this  if (!header.size || header.type === 'symlink') header.size = 0  if (!header.type) header.type = modeToType(header.mode)  if (!header.mode) header.mode = header.type === 'directory' ? DMODE : FMODE  if (!header.uid) header.uid = 0  if (!header.gid) header.gid = 0  if (!header.mtime) header.mtime = new Date()  if (typeof buffer === 'string') buffer = Buffer.from(buffer)  if (Buffer.isBuffer(buffer)) {    header.size = buffer.length    this._encode(header)    var ok = this.push(buffer)    overflow(self, header.size)    if (ok) process.nextTick(callback)    else this._drain = callback    return new Void()  }  if (header.type === 'symlink' && !header.linkname) {    var linkSink = new LinkSink()    eos(linkSink, function (err) {      if (err) { // stream was closed        self.destroy()        return callback(err)      }      header.linkname = linkSink.linkname      self._encode(header)      callback()    })    return linkSink  }  this._encode(header)  if (header.type !== 'file' && header.type !== 'contiguous-file') {    process.nextTick(callback)    return new Void()  }  var sink = new Sink(this)  this._stream = sink  eos(sink, function (err) {    self._stream = null    if (err) { // stream was closed      self.destroy()      return callback(err)    }    if (sink.written !== header.size) { // corrupting tar      self.destroy()      return callback(new Error('size mismatch'))    }    overflow(self, header.size)    if (self._finalizing) self.finalize()    callback()  })  return sink}Pack.prototype.finalize = function () {  if (this._stream) {    this._finalizing = true    return  }  if (this._finalized) return  this._finalized = true  this.push(END_OF_TAR)  this.push(null)}Pack.prototype.destroy = function (err) {  if (this._destroyed) return  this._destroyed = true  if (err) this.emit('error', err)  this.emit('close')  if (this._stream && this._stream.destroy) this._stream.destroy()}Pack.prototype._encode = function (header) {  if (!header.pax) {    var buf = headers.encode(header)    if (buf) {      this.push(buf)      return    }  }  this._encodePax(header)}Pack.prototype._encodePax = function (header) {  var paxHeader = headers.encodePax({    name: header.name,    linkname: header.linkname,    pax: header.pax  })  var newHeader = {    name: 'PaxHeader',    mode: header.mode,    uid: header.uid,    gid: header.gid,    size: paxHeader.length,    mtime: header.mtime,    type: 'pax-header',    linkname: header.linkname && 'PaxHeader',    uname: header.uname,    gname: header.gname,    devmajor: header.devmajor,    devminor: header.devminor  }  this.push(headers.encode(newHeader))  this.push(paxHeader)  overflow(this, paxHeader.length)  newHeader.size = header.size  newHeader.type = header.type  this.push(headers.encode(newHeader))}Pack.prototype._read = function (n) {  var drain = this._drain  this._drain = noop  drain()}module.exports = Pack
 |