You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					114 lines
				
				2.8 KiB
			
		
		
			
		
	
	
					114 lines
				
				2.8 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								'use strict'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								// tar -x
							 | 
						||
| 
								 | 
							
								const 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 included
							 | 
						||
| 
								 | 
							
								const 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)
							 |