| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107 | 'use strict'// tar -xconst hlo = require('./high-level-opt.js')const Unpack = require('./unpack.js')const fs = require('fs')const fsm = require('fs-minipass')const path = require('path')const stripSlash = require('./strip-trailing-slashes.js')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)  return opt.file && opt.sync ? extractFileSync(opt)    : opt.file ? extractFile(opt, cb)    : opt.sync ? extractSync(opt)    : extract(opt)}// construct a filter that limits the file entries listed// include child entries if a dir is includedconst filesFilter = (opt, files) => {  const map = new Map(files.map(f => [stripSlash(f), 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(stripSlash(file))    : file => mapHas(stripSlash(file))}const extractFileSync = opt => {  const u = new Unpack.Sync(opt)  const file = opt.file  const stat = fs.statSync(file)  // This trades a zero-byte read() syscall for a stat  // However, it will usually result in less memory allocation  const readSize = opt.maxReadSize || 16 * 1024 * 1024  const stream = new fsm.ReadStreamSync(file, {    readSize: readSize,    size: stat.size,  })  stream.pipe(u)}const extractFile = (opt, cb) => {  const u = new Unpack(opt)  const readSize = opt.maxReadSize || 16 * 1024 * 1024  const file = opt.file  const p = new Promise((resolve, reject) => {    u.on('error', reject)    u.on('close', resolve)    // This trades a zero-byte read() syscall for a stat    // However, it will usually result in less memory allocation    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(u)      }    })  })  return cb ? p.then(cb, cb) : p}const extractSync = opt => new Unpack.Sync(opt)const extract = opt => new Unpack(opt)
 |