basant307/AI_Governance_Project
048
1var constants = require('fs-constants')2var eos = require('end-of-stream')3var inherits = require('inherits')4var alloc = Buffer.alloc5 6var Readable = require('readable-stream').Readable7var Writable = require('readable-stream').Writable8var StringDecoder = require('string_decoder').StringDecoder9 10var headers = require('./headers')11 12var DMODE = parseInt('755', 8)13var FMODE = parseInt('644', 8)14 15var END_OF_TAR = alloc(1024)16 17var noop = function () {}18 19var overflow = function (self, size) {20 size &= 51121 if (size) self.push(END_OF_TAR.slice(0, 512 - size))22}23 24function modeToType (mode) {25 switch (mode & constants.S_IFMT) {26 case constants.S_IFBLK: return 'block-device'27 case constants.S_IFCHR: return 'character-device'28 case constants.S_IFDIR: return 'directory'29 case constants.S_IFIFO: return 'fifo'30 case constants.S_IFLNK: return 'symlink'31 }32 33 return 'file'34}35 36var Sink = function (to) {37 Writable.call(this)38 this.written = 039 this._to = to40 this._destroyed = false41}42 43inherits(Sink, Writable)44 45Sink.prototype._write = function (data, enc, cb) {46 this.written += data.length47 if (this._to.push(data)) return cb()48 this._to._drain = cb49}50 51Sink.prototype.destroy = function () {52 if (this._destroyed) return53 this._destroyed = true54 this.emit('close')55}56 57var LinkSink = function () {58 Writable.call(this)59 this.linkname = ''60 this._decoder = new StringDecoder('utf-8')61 this._destroyed = false62}63 64inherits(LinkSink, Writable)65 66LinkSink.prototype._write = function (data, enc, cb) {67 this.linkname += this._decoder.write(data)68 cb()69}70 71LinkSink.prototype.destroy = function () {72 if (this._destroyed) return73 this._destroyed = true74 this.emit('close')75}76 77var Void = function () {78 Writable.call(this)79 this._destroyed = false80}81 82inherits(Void, Writable)83 84Void.prototype._write = function (data, enc, cb) {85 cb(new Error('No body allowed for this entry'))86}87 88Void.prototype.destroy = function () {89 if (this._destroyed) return90 this._destroyed = true91 this.emit('close')92}93 94var Pack = function (opts) {95 if (!(this instanceof Pack)) return new Pack(opts)96 Readable.call(this, opts)97 98 this._drain = noop99 this._finalized = false100 this._finalizing = false101 this._destroyed = false102 this._stream = null103}104 105inherits(Pack, Readable)106 107Pack.prototype.entry = function (header, buffer, callback) {108 if (this._stream) throw new Error('already piping an entry')109 if (this._finalized || this._destroyed) return110 111 if (typeof buffer === 'function') {112 callback = buffer113 buffer = null114 }115 116 if (!callback) callback = noop117 118 var self = this119 120 if (!header.size || header.type === 'symlink') header.size = 0121 if (!header.type) header.type = modeToType(header.mode)122 if (!header.mode) header.mode = header.type === 'directory' ? DMODE : FMODE123 if (!header.uid) header.uid = 0124 if (!header.gid) header.gid = 0125 if (!header.mtime) header.mtime = new Date()126 127 if (typeof buffer === 'string') buffer = Buffer.from(buffer)128 if (Buffer.isBuffer(buffer)) {129 header.size = buffer.length130 this._encode(header)131 var ok = this.push(buffer)132 overflow(self, header.size)133 if (ok) process.nextTick(callback)134 else this._drain = callback135 return new Void()136 }137 138 if (header.type === 'symlink' && !header.linkname) {139 var linkSink = new LinkSink()140 eos(linkSink, function (err) {141 if (err) { // stream was closed142 self.destroy()143 return callback(err)144 }145 146 header.linkname = linkSink.linkname147 self._encode(header)148 callback()149 })150 151 return linkSink152 }153 154 this._encode(header)155 156 if (header.type !== 'file' && header.type !== 'contiguous-file') {157 process.nextTick(callback)158 return new Void()159 }160 161 var sink = new Sink(this)162 163 this._stream = sink164 165 eos(sink, function (err) {166 self._stream = null167 168 if (err) { // stream was closed169 self.destroy()170 return callback(err)171 }172 173 if (sink.written !== header.size) { // corrupting tar174 self.destroy()175 return callback(new Error('size mismatch'))176 }177 178 overflow(self, header.size)179 if (self._finalizing) self.finalize()180 callback()181 })182 183 return sink184}185 186Pack.prototype.finalize = function () {187 if (this._stream) {188 this._finalizing = true189 return190 }191 192 if (this._finalized) return193 this._finalized = true194 this.push(END_OF_TAR)195 this.push(null)196}197 198Pack.prototype.destroy = function (err) {199 if (this._destroyed) return200 this._destroyed = true201 202 if (err) this.emit('error', err)203 this.emit('close')204 if (this._stream && this._stream.destroy) this._stream.destroy()205}206 207Pack.prototype._encode = function (header) {208 if (!header.pax) {209 var buf = headers.encode(header)210 if (buf) {211 this.push(buf)212 return213 }214 }215 this._encodePax(header)216}217 218Pack.prototype._encodePax = function (header) {219 var paxHeader = headers.encodePax({220 name: header.name,221 linkname: header.linkname,222 pax: header.pax223 })224 225 var newHeader = {226 name: 'PaxHeader',227 mode: header.mode,228 uid: header.uid,229 gid: header.gid,230 size: paxHeader.length,231 mtime: header.mtime,232 type: 'pax-header',233 linkname: header.linkname && 'PaxHeader',234 uname: header.uname,235 gname: header.gname,236 devmajor: header.devmajor,237 devminor: header.devminor238 }239 240 this.push(headers.encode(newHeader))241 this.push(paxHeader)242 overflow(this, paxHeader.length)243 244 newHeader.size = header.size245 newHeader.type = header.type246 this.push(headers.encode(newHeader))247}248 249Pack.prototype._read = function (n) {250 var drain = this._drain251 this._drain = noop252 drain()253}254 255module.exports = Pack256 