| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295 | var alloc = Buffer.allocvar ZEROS = '0000000000000000000'var SEVENS = '7777777777777777777'var ZERO_OFFSET = '0'.charCodeAt(0)var USTAR_MAGIC = Buffer.from('ustar\x00', 'binary')var USTAR_VER = Buffer.from('00', 'binary')var GNU_MAGIC = Buffer.from('ustar\x20', 'binary')var GNU_VER = Buffer.from('\x20\x00', 'binary')var MASK = parseInt('7777', 8)var MAGIC_OFFSET = 257var VERSION_OFFSET = 263var clamp = function (index, len, defaultValue) {  if (typeof index !== 'number') return defaultValue  index = ~~index // Coerce to integer.  if (index >= len) return len  if (index >= 0) return index  index += len  if (index >= 0) return index  return 0}var toType = function (flag) {  switch (flag) {    case 0:      return 'file'    case 1:      return 'link'    case 2:      return 'symlink'    case 3:      return 'character-device'    case 4:      return 'block-device'    case 5:      return 'directory'    case 6:      return 'fifo'    case 7:      return 'contiguous-file'    case 72:      return 'pax-header'    case 55:      return 'pax-global-header'    case 27:      return 'gnu-long-link-path'    case 28:    case 30:      return 'gnu-long-path'  }  return null}var toTypeflag = function (flag) {  switch (flag) {    case 'file':      return 0    case 'link':      return 1    case 'symlink':      return 2    case 'character-device':      return 3    case 'block-device':      return 4    case 'directory':      return 5    case 'fifo':      return 6    case 'contiguous-file':      return 7    case 'pax-header':      return 72  }  return 0}var indexOf = function (block, num, offset, end) {  for (; offset < end; offset++) {    if (block[offset] === num) return offset  }  return end}var cksum = function (block) {  var sum = 8 * 32  for (var i = 0; i < 148; i++) sum += block[i]  for (var j = 156; j < 512; j++) sum += block[j]  return sum}var encodeOct = function (val, n) {  val = val.toString(8)  if (val.length > n) return SEVENS.slice(0, n) + ' '  else return ZEROS.slice(0, n - val.length) + val + ' '}/* Copied from the node-tar repo and modified to meet * tar-stream coding standard. * * Source: https://github.com/npm/node-tar/blob/51b6627a1f357d2eb433e7378e5f05e83b7aa6cd/lib/header.js#L349 */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 tuple = []  for (var i = buf.length - 1; i > 0; i--) {    var byte = buf[i]    if (positive) tuple.push(byte)    else tuple.push(0xFF - byte)  }  var sum = 0  var l = tuple.length  for (i = 0; i < l; i++) {    sum += tuple[i] * Math.pow(256, i)  }  return positive ? sum : -1 * sum}var decodeOct = function (val, offset, length) {  val = val.slice(offset, offset + length)  offset = 0  // If prefixed with 0x80 then parse as a base-256 integer  if (val[offset] & 0x80) {    return parse256(val)  } else {    // Older versions of tar can prefix with spaces    while (offset < val.length && val[offset] === 32) offset++    var end = clamp(indexOf(val, 32, offset, val.length), val.length, val.length)    while (offset < end && val[offset] === 0) offset++    if (end === offset) return 0    return parseInt(val.slice(offset, end).toString(), 8)  }}var decodeStr = function (val, offset, length, encoding) {  return val.slice(offset, indexOf(val, 0, offset, offset + length)).toString(encoding)}var addLength = function (str) {  var len = Buffer.byteLength(str)  var digits = Math.floor(Math.log(len) / Math.log(10)) + 1  if (len + digits >= Math.pow(10, digits)) digits++  return (len + digits) + str}exports.decodeLongPath = function (buf, encoding) {  return decodeStr(buf, 0, buf.length, encoding)}exports.encodePax = function (opts) { // TODO: encode more stuff in pax  var result = ''  if (opts.name) result += addLength(' path=' + opts.name + '\n')  if (opts.linkname) result += addLength(' linkpath=' + opts.linkname + '\n')  var pax = opts.pax  if (pax) {    for (var key in pax) {      result += addLength(' ' + key + '=' + pax[key] + '\n')    }  }  return Buffer.from(result)}exports.decodePax = function (buf) {  var result = {}  while (buf.length) {    var i = 0    while (i < buf.length && buf[i] !== 32) i++    var len = parseInt(buf.slice(0, i).toString(), 10)    if (!len) return result    var b = buf.slice(i + 1, len - 1).toString()    var keyIndex = b.indexOf('=')    if (keyIndex === -1) return result    result[b.slice(0, keyIndex)] = b.slice(keyIndex + 1)    buf = buf.slice(len)  }  return result}exports.encode = function (opts) {  var buf = alloc(512)  var name = opts.name  var prefix = ''  if (opts.typeflag === 5 && name[name.length - 1] !== '/') name += '/'  if (Buffer.byteLength(name) !== name.length) return null // utf-8  while (Buffer.byteLength(name) > 100) {    var i = name.indexOf('/')    if (i === -1) return null    prefix += prefix ? '/' + name.slice(0, i) : name.slice(0, i)    name = name.slice(i + 1)  }  if (Buffer.byteLength(name) > 100 || Buffer.byteLength(prefix) > 155) return null  if (opts.linkname && Buffer.byteLength(opts.linkname) > 100) return null  buf.write(name)  buf.write(encodeOct(opts.mode & MASK, 6), 100)  buf.write(encodeOct(opts.uid, 6), 108)  buf.write(encodeOct(opts.gid, 6), 116)  buf.write(encodeOct(opts.size, 11), 124)  buf.write(encodeOct((opts.mtime.getTime() / 1000) | 0, 11), 136)  buf[156] = ZERO_OFFSET + toTypeflag(opts.type)  if (opts.linkname) buf.write(opts.linkname, 157)  USTAR_MAGIC.copy(buf, MAGIC_OFFSET)  USTAR_VER.copy(buf, VERSION_OFFSET)  if (opts.uname) buf.write(opts.uname, 265)  if (opts.gname) buf.write(opts.gname, 297)  buf.write(encodeOct(opts.devmajor || 0, 6), 329)  buf.write(encodeOct(opts.devminor || 0, 6), 337)  if (prefix) buf.write(prefix, 345)  buf.write(encodeOct(cksum(buf), 6), 148)  return buf}exports.decode = function (buf, filenameEncoding, allowUnknownFormat) {  var typeflag = buf[156] === 0 ? 0 : buf[156] - ZERO_OFFSET  var name = decodeStr(buf, 0, 100, filenameEncoding)  var mode = decodeOct(buf, 100, 8)  var uid = decodeOct(buf, 108, 8)  var gid = decodeOct(buf, 116, 8)  var size = decodeOct(buf, 124, 12)  var mtime = decodeOct(buf, 136, 12)  var type = toType(typeflag)  var linkname = buf[157] === 0 ? null : decodeStr(buf, 157, 100, filenameEncoding)  var uname = decodeStr(buf, 265, 32)  var gname = decodeStr(buf, 297, 32)  var devmajor = decodeOct(buf, 329, 8)  var devminor = decodeOct(buf, 337, 8)  var c = cksum(buf)  // checksum is still initial value if header was null.  if (c === 8 * 32) return null  // valid checksum  if (c !== decodeOct(buf, 148, 8)) throw new Error('Invalid tar header. Maybe the tar is corrupted or it needs to be gunzipped?')  if (USTAR_MAGIC.compare(buf, MAGIC_OFFSET, MAGIC_OFFSET + 6) === 0) {    // ustar (posix) format.    // prepend prefix, if present.    if (buf[345]) name = decodeStr(buf, 345, 155, filenameEncoding) + '/' + name  } else if (GNU_MAGIC.compare(buf, MAGIC_OFFSET, MAGIC_OFFSET + 6) === 0 &&             GNU_VER.compare(buf, VERSION_OFFSET, VERSION_OFFSET + 2) === 0) {    // 'gnu'/'oldgnu' format. Similar to ustar, but has support for incremental and    // multi-volume tarballs.  } else {    if (!allowUnknownFormat) {      throw new Error('Invalid tar header: unknown format.')    }  }  // to support old tar versions that use trailing / to indicate dirs  if (typeflag === 0 && name && name[name.length - 1] === '/') typeflag = 5  return {    name,    mode,    uid,    gid,    size,    mtime: new Date(1000 * mtime),    type,    linkname,    uname,    gname,    devmajor,    devminor  }}
 |