| var constants = require('fs-constants') | |
| var eos = require('end-of-stream') | |
| var inherits = require('inherits') | |
| var alloc = Buffer.alloc | |
| var Readable = require('readable-stream').Readable | |
| var Writable = require('readable-stream').Writable | |
| var StringDecoder = require('string_decoder').StringDecoder | |
| var 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 | |
Xet Storage Details
- Size:
- 5.63 kB
- Xet hash:
- af86e7b48b31d252e69e5651b223a4e0252932b02115369dd3ddbf73b0082f0a
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.