1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 | 5x 5x 5x 5x 5x 5x 34x 1x 33x 1x 34x 5x 34x 31x 3x 34x 34x 1x 33x 1x 32x 3x 32x 22x 32x 5x 22x 22x 255x 255x 72x 5x 6x 3x 3x 125x 125x 125x 125x 3x 32x 64x 5x 13x 13x 13x 13x 13x 12x 12x 10x 2x 2x 2x 2x 28x 27x 27x 1x 11x 13x 1x 5x 16x 16x 16x 16x 16x 16x 16x 16x 2x 14x 14x 14x 16x 16x | 'use strict' // XXX: This shares a lot in common with extract.js // maybe some DRY opportunity here? // tar -t const hlo = require('./high-level-opt.js') const Parser = require('./parse.js') const fs = require('fs') const fsm = require('fs-minipass') const path = require('path') const t = module.exports = (opt_, files, cb) => { if (typeof opt_ === 'function') cb = opt_, files = null, opt_ = {} else if (Array.isArray(opt_)) files = opt_, opt_ = {} if (typeof files === 'function') cb = files, files = null if (!files) files = [] else files = Array.from(files) const opt = hlo(opt_) if (opt.sync && typeof cb === 'function') throw new TypeError('callback not supported for sync tar functions') if (!opt.file && typeof cb === 'function') throw new TypeError('callback only supported with file option') if (files.length) filesFilter(opt, files) if (!opt.noResume) onentryFunction(opt) return opt.file && opt.sync ? listFileSync(opt) : opt.file ? listFile(opt, cb) : list(opt) } const onentryFunction = opt => { const onentry = opt.onentry opt.onentry = onentry ? e => { onentry(e) e.resume() } : e => e.resume() } // construct a filter that limits the file entries listed // include child entries if a dir is included const filesFilter = (opt, files) => { const map = new Map(files.map(f => [f.replace(/\/+$/, ''), true])) const filter = opt.filter const mapHas = (file, r) => { const root = r || path.parse(file).root || '.' const ret = file === root ? false : map.has(file) ? map.get(file) : mapHas(path.dirname(file), root) map.set(file, ret) return ret } opt.filter = filter ? (file, entry) => filter(file, entry) && mapHas(file.replace(/\/+$/, '')) : file => mapHas(file.replace(/\/+$/, '')) } const listFileSync = opt => { const p = list(opt) const file = opt.file let threw = true let fd try { const stat = fs.statSync(file) const readSize = opt.maxReadSize || 16*1024*1024 if (stat.size < readSize) { p.end(fs.readFileSync(file)) } else { let pos = 0 const buf = Buffer.allocUnsafe(readSize) fd = fs.openSync(file, 'r') while (pos < stat.size) { let bytesRead = fs.readSync(fd, buf, 0, readSize, pos) pos += bytesRead p.write(buf.slice(0, bytesRead)) } p.end() } threw = false } finally { if (threw && fd) try { fs.closeSync(fd) } catch (er) {} } } const listFile = (opt, cb) => { const parse = new Parser(opt) const readSize = opt.maxReadSize || 16*1024*1024 const file = opt.file const p = new Promise((resolve, reject) => { parse.on('error', reject) parse.on('end', resolve) fs.stat(file, (er, stat) => { if (er) reject(er) else { const stream = new fsm.ReadStream(file, { readSize: readSize, size: stat.size }) stream.on('error', reject) stream.pipe(parse) } }) }) return cb ? p.then(cb, cb) : p } const list = opt => new Parser(opt) |