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.
		
		
		
		
		
			
		
			
				
					140 lines
				
				3.1 KiB
			
		
		
			
		
	
	
					140 lines
				
				3.1 KiB
			| 
											3 years ago
										 | '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 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) | ||
|  |   } | ||
|  | 
 | ||
|  |   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 => [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 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) { | ||
|  |         const 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) |