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) |