Initial
This commit is contained in:
287
resources/app/node_modules/tar-stream/pack.js
generated
vendored
Normal file
287
resources/app/node_modules/tar-stream/pack.js
generated
vendored
Normal file
@@ -0,0 +1,287 @@
|
||||
const { Readable, Writable, getStreamError } = require('streamx')
|
||||
const b4a = require('b4a')
|
||||
|
||||
const constants = require('./constants')
|
||||
const headers = require('./headers')
|
||||
|
||||
const DMODE = 0o755
|
||||
const FMODE = 0o644
|
||||
|
||||
const END_OF_TAR = b4a.alloc(1024)
|
||||
|
||||
class Sink extends Writable {
|
||||
constructor (pack, header, callback) {
|
||||
super({ mapWritable, eagerOpen: true })
|
||||
|
||||
this.written = 0
|
||||
this.header = header
|
||||
|
||||
this._callback = callback
|
||||
this._linkname = null
|
||||
this._isLinkname = header.type === 'symlink' && !header.linkname
|
||||
this._isVoid = header.type !== 'file' && header.type !== 'contiguous-file'
|
||||
this._finished = false
|
||||
this._pack = pack
|
||||
this._openCallback = null
|
||||
|
||||
if (this._pack._stream === null) this._pack._stream = this
|
||||
else this._pack._pending.push(this)
|
||||
}
|
||||
|
||||
_open (cb) {
|
||||
this._openCallback = cb
|
||||
if (this._pack._stream === this) this._continueOpen()
|
||||
}
|
||||
|
||||
_continuePack (err) {
|
||||
if (this._callback === null) return
|
||||
|
||||
const callback = this._callback
|
||||
this._callback = null
|
||||
|
||||
callback(err)
|
||||
}
|
||||
|
||||
_continueOpen () {
|
||||
if (this._pack._stream === null) this._pack._stream = this
|
||||
|
||||
const cb = this._openCallback
|
||||
this._openCallback = null
|
||||
if (cb === null) return
|
||||
|
||||
if (this._pack.destroying) return cb(new Error('pack stream destroyed'))
|
||||
if (this._pack._finalized) return cb(new Error('pack stream is already finalized'))
|
||||
|
||||
this._pack._stream = this
|
||||
|
||||
if (!this._isLinkname) {
|
||||
this._pack._encode(this.header)
|
||||
}
|
||||
|
||||
if (this._isVoid) {
|
||||
this._finish()
|
||||
this._continuePack(null)
|
||||
}
|
||||
|
||||
cb(null)
|
||||
}
|
||||
|
||||
_write (data, cb) {
|
||||
if (this._isLinkname) {
|
||||
this._linkname = this._linkname ? b4a.concat([this._linkname, data]) : data
|
||||
return cb(null)
|
||||
}
|
||||
|
||||
if (this._isVoid) {
|
||||
if (data.byteLength > 0) {
|
||||
return cb(new Error('No body allowed for this entry'))
|
||||
}
|
||||
return cb()
|
||||
}
|
||||
|
||||
this.written += data.byteLength
|
||||
if (this._pack.push(data)) return cb()
|
||||
this._pack._drain = cb
|
||||
}
|
||||
|
||||
_finish () {
|
||||
if (this._finished) return
|
||||
this._finished = true
|
||||
|
||||
if (this._isLinkname) {
|
||||
this.header.linkname = this._linkname ? b4a.toString(this._linkname, 'utf-8') : ''
|
||||
this._pack._encode(this.header)
|
||||
}
|
||||
|
||||
overflow(this._pack, this.header.size)
|
||||
|
||||
this._pack._done(this)
|
||||
}
|
||||
|
||||
_final (cb) {
|
||||
if (this.written !== this.header.size) { // corrupting tar
|
||||
return cb(new Error('Size mismatch'))
|
||||
}
|
||||
|
||||
this._finish()
|
||||
cb(null)
|
||||
}
|
||||
|
||||
_getError () {
|
||||
return getStreamError(this) || new Error('tar entry destroyed')
|
||||
}
|
||||
|
||||
_predestroy () {
|
||||
this._pack.destroy(this._getError())
|
||||
}
|
||||
|
||||
_destroy (cb) {
|
||||
this._pack._done(this)
|
||||
|
||||
this._continuePack(this._finished ? null : this._getError())
|
||||
|
||||
cb()
|
||||
}
|
||||
}
|
||||
|
||||
class Pack extends Readable {
|
||||
constructor (opts) {
|
||||
super(opts)
|
||||
this._drain = noop
|
||||
this._finalized = false
|
||||
this._finalizing = false
|
||||
this._pending = []
|
||||
this._stream = null
|
||||
}
|
||||
|
||||
entry (header, buffer, callback) {
|
||||
if (this._finalized || this.destroying) throw new Error('already finalized or destroyed')
|
||||
|
||||
if (typeof buffer === 'function') {
|
||||
callback = buffer
|
||||
buffer = null
|
||||
}
|
||||
|
||||
if (!callback) callback = noop
|
||||
|
||||
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 = b4a.from(buffer)
|
||||
|
||||
const sink = new Sink(this, header, callback)
|
||||
|
||||
if (b4a.isBuffer(buffer)) {
|
||||
header.size = buffer.byteLength
|
||||
sink.write(buffer)
|
||||
sink.end()
|
||||
return sink
|
||||
}
|
||||
|
||||
if (sink._isVoid) {
|
||||
return sink
|
||||
}
|
||||
|
||||
return sink
|
||||
}
|
||||
|
||||
finalize () {
|
||||
if (this._stream || this._pending.length > 0) {
|
||||
this._finalizing = true
|
||||
return
|
||||
}
|
||||
|
||||
if (this._finalized) return
|
||||
this._finalized = true
|
||||
|
||||
this.push(END_OF_TAR)
|
||||
this.push(null)
|
||||
}
|
||||
|
||||
_done (stream) {
|
||||
if (stream !== this._stream) return
|
||||
|
||||
this._stream = null
|
||||
|
||||
if (this._finalizing) this.finalize()
|
||||
if (this._pending.length) this._pending.shift()._continueOpen()
|
||||
}
|
||||
|
||||
_encode (header) {
|
||||
if (!header.pax) {
|
||||
const buf = headers.encode(header)
|
||||
if (buf) {
|
||||
this.push(buf)
|
||||
return
|
||||
}
|
||||
}
|
||||
this._encodePax(header)
|
||||
}
|
||||
|
||||
_encodePax (header) {
|
||||
const paxHeader = headers.encodePax({
|
||||
name: header.name,
|
||||
linkname: header.linkname,
|
||||
pax: header.pax
|
||||
})
|
||||
|
||||
const newHeader = {
|
||||
name: 'PaxHeader',
|
||||
mode: header.mode,
|
||||
uid: header.uid,
|
||||
gid: header.gid,
|
||||
size: paxHeader.byteLength,
|
||||
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.byteLength)
|
||||
|
||||
newHeader.size = header.size
|
||||
newHeader.type = header.type
|
||||
this.push(headers.encode(newHeader))
|
||||
}
|
||||
|
||||
_doDrain () {
|
||||
const drain = this._drain
|
||||
this._drain = noop
|
||||
drain()
|
||||
}
|
||||
|
||||
_predestroy () {
|
||||
const err = getStreamError(this)
|
||||
|
||||
if (this._stream) this._stream.destroy(err)
|
||||
|
||||
while (this._pending.length) {
|
||||
const stream = this._pending.shift()
|
||||
stream.destroy(err)
|
||||
stream._continueOpen()
|
||||
}
|
||||
|
||||
this._doDrain()
|
||||
}
|
||||
|
||||
_read (cb) {
|
||||
this._doDrain()
|
||||
cb()
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = function pack (opts) {
|
||||
return new Pack(opts)
|
||||
}
|
||||
|
||||
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'
|
||||
}
|
||||
|
||||
function noop () {}
|
||||
|
||||
function overflow (self, size) {
|
||||
size &= 511
|
||||
if (size) self.push(END_OF_TAR.subarray(0, 512 - size))
|
||||
}
|
||||
|
||||
function mapWritable (buf) {
|
||||
return b4a.isBuffer(buf) ? buf : b4a.from(buf)
|
||||
}
|
||||
Reference in New Issue
Block a user