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