You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					296 lines
				
				7.8 KiB
			
		
		
			
		
	
	
					296 lines
				
				7.8 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								var alloc = Buffer.alloc
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var 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 = 257
							 | 
						||
| 
								 | 
							
								var VERSION_OFFSET = 263
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								var 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
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 |