1'use strict' 2const types = require('./types.js') 3const MiniPass = require('minipass') 4 5const SLURP = Symbol('slurp') 6module.exports = class ReadEntry extends MiniPass { 7 constructor (header, ex, gex) { 8 super() 9 // read entries always start life paused. this is to avoid the 10 // situation where Minipass's auto-ending empty streams results 11 // in an entry ending before we're ready for it. 12 this.pause() 13 this.extended = ex 14 this.globalExtended = gex 15 this.header = header 16 this.startBlockSize = 512 * Math.ceil(header.size / 512) 17 this.blockRemain = this.startBlockSize 18 this.remain = header.size 19 this.type = header.type 20 this.meta = false 21 this.ignore = false 22 switch (this.type) { 23 case 'File': 24 case 'OldFile': 25 case 'Link': 26 case 'SymbolicLink': 27 case 'CharacterDevice': 28 case 'BlockDevice': 29 case 'Directory': 30 case 'FIFO': 31 case 'ContiguousFile': 32 case 'GNUDumpDir': 33 break 34 35 case 'NextFileHasLongLinkpath': 36 case 'NextFileHasLongPath': 37 case 'OldGnuLongPath': 38 case 'GlobalExtendedHeader': 39 case 'ExtendedHeader': 40 case 'OldExtendedHeader': 41 this.meta = true 42 break 43 44 // NOTE: gnutar and bsdtar treat unrecognized types as 'File' 45 // it may be worth doing the same, but with a warning. 46 default: 47 this.ignore = true 48 } 49 50 this.path = header.path 51 this.mode = header.mode 52 if (this.mode) 53 this.mode = this.mode & 0o7777 54 this.uid = header.uid 55 this.gid = header.gid 56 this.uname = header.uname 57 this.gname = header.gname 58 this.size = header.size 59 this.mtime = header.mtime 60 this.atime = header.atime 61 this.ctime = header.ctime 62 this.linkpath = header.linkpath 63 this.uname = header.uname 64 this.gname = header.gname 65 66 if (ex) this[SLURP](ex) 67 if (gex) this[SLURP](gex, true) 68 } 69 70 write (data) { 71 const writeLen = data.length 72 if (writeLen > this.blockRemain) 73 throw new Error('writing more to entry than is appropriate') 74 75 const r = this.remain 76 const br = this.blockRemain 77 this.remain = Math.max(0, r - writeLen) 78 this.blockRemain = Math.max(0, br - writeLen) 79 if (this.ignore) 80 return true 81 82 if (r >= writeLen) 83 return super.write(data) 84 85 // r < writeLen 86 return super.write(data.slice(0, r)) 87 } 88 89 [SLURP] (ex, global) { 90 for (let k in ex) { 91 // we slurp in everything except for the path attribute in 92 // a global extended header, because that's weird. 93 if (ex[k] !== null && ex[k] !== undefined && 94 !(global && k === 'path')) 95 this[k] = ex[k] 96 } 97 } 98} 99