11cb0ef41Sopenharmony_ci'use strict'
21cb0ef41Sopenharmony_ci
31cb0ef41Sopenharmony_ci// tar -x
41cb0ef41Sopenharmony_ciconst hlo = require('./high-level-opt.js')
51cb0ef41Sopenharmony_ciconst Unpack = require('./unpack.js')
61cb0ef41Sopenharmony_ciconst fs = require('fs')
71cb0ef41Sopenharmony_ciconst fsm = require('fs-minipass')
81cb0ef41Sopenharmony_ciconst path = require('path')
91cb0ef41Sopenharmony_ciconst stripSlash = require('./strip-trailing-slashes.js')
101cb0ef41Sopenharmony_ci
111cb0ef41Sopenharmony_cimodule.exports = (opt_, files, cb) => {
121cb0ef41Sopenharmony_ci  if (typeof opt_ === 'function') {
131cb0ef41Sopenharmony_ci    cb = opt_, files = null, opt_ = {}
141cb0ef41Sopenharmony_ci  } else if (Array.isArray(opt_)) {
151cb0ef41Sopenharmony_ci    files = opt_, opt_ = {}
161cb0ef41Sopenharmony_ci  }
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_ci  if (typeof files === 'function') {
191cb0ef41Sopenharmony_ci    cb = files, files = null
201cb0ef41Sopenharmony_ci  }
211cb0ef41Sopenharmony_ci
221cb0ef41Sopenharmony_ci  if (!files) {
231cb0ef41Sopenharmony_ci    files = []
241cb0ef41Sopenharmony_ci  } else {
251cb0ef41Sopenharmony_ci    files = Array.from(files)
261cb0ef41Sopenharmony_ci  }
271cb0ef41Sopenharmony_ci
281cb0ef41Sopenharmony_ci  const opt = hlo(opt_)
291cb0ef41Sopenharmony_ci
301cb0ef41Sopenharmony_ci  if (opt.sync && typeof cb === 'function') {
311cb0ef41Sopenharmony_ci    throw new TypeError('callback not supported for sync tar functions')
321cb0ef41Sopenharmony_ci  }
331cb0ef41Sopenharmony_ci
341cb0ef41Sopenharmony_ci  if (!opt.file && typeof cb === 'function') {
351cb0ef41Sopenharmony_ci    throw new TypeError('callback only supported with file option')
361cb0ef41Sopenharmony_ci  }
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_ci  if (files.length) {
391cb0ef41Sopenharmony_ci    filesFilter(opt, files)
401cb0ef41Sopenharmony_ci  }
411cb0ef41Sopenharmony_ci
421cb0ef41Sopenharmony_ci  return opt.file && opt.sync ? extractFileSync(opt)
431cb0ef41Sopenharmony_ci    : opt.file ? extractFile(opt, cb)
441cb0ef41Sopenharmony_ci    : opt.sync ? extractSync(opt)
451cb0ef41Sopenharmony_ci    : extract(opt)
461cb0ef41Sopenharmony_ci}
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ci// construct a filter that limits the file entries listed
491cb0ef41Sopenharmony_ci// include child entries if a dir is included
501cb0ef41Sopenharmony_ciconst filesFilter = (opt, files) => {
511cb0ef41Sopenharmony_ci  const map = new Map(files.map(f => [stripSlash(f), true]))
521cb0ef41Sopenharmony_ci  const filter = opt.filter
531cb0ef41Sopenharmony_ci
541cb0ef41Sopenharmony_ci  const mapHas = (file, r) => {
551cb0ef41Sopenharmony_ci    const root = r || path.parse(file).root || '.'
561cb0ef41Sopenharmony_ci    const ret = file === root ? false
571cb0ef41Sopenharmony_ci      : map.has(file) ? map.get(file)
581cb0ef41Sopenharmony_ci      : mapHas(path.dirname(file), root)
591cb0ef41Sopenharmony_ci
601cb0ef41Sopenharmony_ci    map.set(file, ret)
611cb0ef41Sopenharmony_ci    return ret
621cb0ef41Sopenharmony_ci  }
631cb0ef41Sopenharmony_ci
641cb0ef41Sopenharmony_ci  opt.filter = filter
651cb0ef41Sopenharmony_ci    ? (file, entry) => filter(file, entry) && mapHas(stripSlash(file))
661cb0ef41Sopenharmony_ci    : file => mapHas(stripSlash(file))
671cb0ef41Sopenharmony_ci}
681cb0ef41Sopenharmony_ci
691cb0ef41Sopenharmony_ciconst extractFileSync = opt => {
701cb0ef41Sopenharmony_ci  const u = new Unpack.Sync(opt)
711cb0ef41Sopenharmony_ci
721cb0ef41Sopenharmony_ci  const file = opt.file
731cb0ef41Sopenharmony_ci  const stat = fs.statSync(file)
741cb0ef41Sopenharmony_ci  // This trades a zero-byte read() syscall for a stat
751cb0ef41Sopenharmony_ci  // However, it will usually result in less memory allocation
761cb0ef41Sopenharmony_ci  const readSize = opt.maxReadSize || 16 * 1024 * 1024
771cb0ef41Sopenharmony_ci  const stream = new fsm.ReadStreamSync(file, {
781cb0ef41Sopenharmony_ci    readSize: readSize,
791cb0ef41Sopenharmony_ci    size: stat.size,
801cb0ef41Sopenharmony_ci  })
811cb0ef41Sopenharmony_ci  stream.pipe(u)
821cb0ef41Sopenharmony_ci}
831cb0ef41Sopenharmony_ci
841cb0ef41Sopenharmony_ciconst extractFile = (opt, cb) => {
851cb0ef41Sopenharmony_ci  const u = new Unpack(opt)
861cb0ef41Sopenharmony_ci  const readSize = opt.maxReadSize || 16 * 1024 * 1024
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_ci  const file = opt.file
891cb0ef41Sopenharmony_ci  const p = new Promise((resolve, reject) => {
901cb0ef41Sopenharmony_ci    u.on('error', reject)
911cb0ef41Sopenharmony_ci    u.on('close', resolve)
921cb0ef41Sopenharmony_ci
931cb0ef41Sopenharmony_ci    // This trades a zero-byte read() syscall for a stat
941cb0ef41Sopenharmony_ci    // However, it will usually result in less memory allocation
951cb0ef41Sopenharmony_ci    fs.stat(file, (er, stat) => {
961cb0ef41Sopenharmony_ci      if (er) {
971cb0ef41Sopenharmony_ci        reject(er)
981cb0ef41Sopenharmony_ci      } else {
991cb0ef41Sopenharmony_ci        const stream = new fsm.ReadStream(file, {
1001cb0ef41Sopenharmony_ci          readSize: readSize,
1011cb0ef41Sopenharmony_ci          size: stat.size,
1021cb0ef41Sopenharmony_ci        })
1031cb0ef41Sopenharmony_ci        stream.on('error', reject)
1041cb0ef41Sopenharmony_ci        stream.pipe(u)
1051cb0ef41Sopenharmony_ci      }
1061cb0ef41Sopenharmony_ci    })
1071cb0ef41Sopenharmony_ci  })
1081cb0ef41Sopenharmony_ci  return cb ? p.then(cb, cb) : p
1091cb0ef41Sopenharmony_ci}
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_ciconst extractSync = opt => new Unpack.Sync(opt)
1121cb0ef41Sopenharmony_ci
1131cb0ef41Sopenharmony_ciconst extract = opt => new Unpack(opt)
114