| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351 | var chownr = require('chownr')var tar = require('tar-stream')var pump = require('pump')var mkdirp = require('mkdirp-classic')var fs = require('fs')var path = require('path')var os = require('os')var win32 = os.platform() === 'win32'var noop = function () {}var echo = function (name) {  return name}var normalize = !win32 ? echo : function (name) {  return name.replace(/\\/g, '/').replace(/[:?<>|]/g, '_')}var statAll = function (fs, stat, cwd, ignore, entries, sort) {  var queue = entries || ['.']  return function loop (callback) {    if (!queue.length) return callback()    var next = queue.shift()    var nextAbs = path.join(cwd, next)    stat.call(fs, nextAbs, function (err, stat) {      if (err) return callback(err)      if (!stat.isDirectory()) return callback(null, next, stat)      fs.readdir(nextAbs, function (err, files) {        if (err) return callback(err)        if (sort) files.sort()        for (var i = 0; i < files.length; i++) {          if (!ignore(path.join(cwd, next, files[i]))) queue.push(path.join(next, files[i]))        }        callback(null, next, stat)      })    })  }}var strip = function (map, level) {  return function (header) {    header.name = header.name.split('/').slice(level).join('/')    var linkname = header.linkname    if (linkname && (header.type === 'link' || path.isAbsolute(linkname))) {      header.linkname = linkname.split('/').slice(level).join('/')    }    return map(header)  }}exports.pack = function (cwd, opts) {  if (!cwd) cwd = '.'  if (!opts) opts = {}  var xfs = opts.fs || fs  var ignore = opts.ignore || opts.filter || noop  var map = opts.map || noop  var mapStream = opts.mapStream || echo  var statNext = statAll(xfs, opts.dereference ? xfs.stat : xfs.lstat, cwd, ignore, opts.entries, opts.sort)  var strict = opts.strict !== false  var umask = typeof opts.umask === 'number' ? ~opts.umask : ~processUmask()  var dmode = typeof opts.dmode === 'number' ? opts.dmode : 0  var fmode = typeof opts.fmode === 'number' ? opts.fmode : 0  var pack = opts.pack || tar.pack()  var finish = opts.finish || noop  if (opts.strip) map = strip(map, opts.strip)  if (opts.readable) {    dmode |= parseInt(555, 8)    fmode |= parseInt(444, 8)  }  if (opts.writable) {    dmode |= parseInt(333, 8)    fmode |= parseInt(222, 8)  }  var onsymlink = function (filename, header) {    xfs.readlink(path.join(cwd, filename), function (err, linkname) {      if (err) return pack.destroy(err)      header.linkname = normalize(linkname)      pack.entry(header, onnextentry)    })  }  var onstat = function (err, filename, stat) {    if (err) return pack.destroy(err)    if (!filename) {      if (opts.finalize !== false) pack.finalize()      return finish(pack)    }    if (stat.isSocket()) return onnextentry() // tar does not support sockets...    var header = {      name: normalize(filename),      mode: (stat.mode | (stat.isDirectory() ? dmode : fmode)) & umask,      mtime: stat.mtime,      size: stat.size,      type: 'file',      uid: stat.uid,      gid: stat.gid    }    if (stat.isDirectory()) {      header.size = 0      header.type = 'directory'      header = map(header) || header      return pack.entry(header, onnextentry)    }    if (stat.isSymbolicLink()) {      header.size = 0      header.type = 'symlink'      header = map(header) || header      return onsymlink(filename, header)    }    // TODO: add fifo etc...    header = map(header) || header    if (!stat.isFile()) {      if (strict) return pack.destroy(new Error('unsupported type for ' + filename))      return onnextentry()    }    var entry = pack.entry(header, onnextentry)    if (!entry) return    var rs = mapStream(xfs.createReadStream(path.join(cwd, filename), { start: 0, end: header.size > 0 ? header.size - 1 : header.size }), header)    rs.on('error', function (err) { // always forward errors on destroy      entry.destroy(err)    })    pump(rs, entry)  }  var onnextentry = function (err) {    if (err) return pack.destroy(err)    statNext(onstat)  }  onnextentry()  return pack}var head = function (list) {  return list.length ? list[list.length - 1] : null}var processGetuid = function () {  return process.getuid ? process.getuid() : -1}var processUmask = function () {  return process.umask ? process.umask() : 0}exports.extract = function (cwd, opts) {  if (!cwd) cwd = '.'  if (!opts) opts = {}  var xfs = opts.fs || fs  var ignore = opts.ignore || opts.filter || noop  var map = opts.map || noop  var mapStream = opts.mapStream || echo  var own = opts.chown !== false && !win32 && processGetuid() === 0  var extract = opts.extract || tar.extract()  var stack = []  var now = new Date()  var umask = typeof opts.umask === 'number' ? ~opts.umask : ~processUmask()  var dmode = typeof opts.dmode === 'number' ? opts.dmode : 0  var fmode = typeof opts.fmode === 'number' ? opts.fmode : 0  var strict = opts.strict !== false  if (opts.strip) map = strip(map, opts.strip)  if (opts.readable) {    dmode |= parseInt(555, 8)    fmode |= parseInt(444, 8)  }  if (opts.writable) {    dmode |= parseInt(333, 8)    fmode |= parseInt(222, 8)  }  var utimesParent = function (name, cb) { // we just set the mtime on the parent dir again everytime we write an entry    var top    while ((top = head(stack)) && name.slice(0, top[0].length) !== top[0]) stack.pop()    if (!top) return cb()    xfs.utimes(top[0], now, top[1], cb)  }  var utimes = function (name, header, cb) {    if (opts.utimes === false) return cb()    if (header.type === 'directory') return xfs.utimes(name, now, header.mtime, cb)    if (header.type === 'symlink') return utimesParent(name, cb) // TODO: how to set mtime on link?    xfs.utimes(name, now, header.mtime, function (err) {      if (err) return cb(err)      utimesParent(name, cb)    })  }  var chperm = function (name, header, cb) {    var link = header.type === 'symlink'    /* eslint-disable node/no-deprecated-api */    var chmod = link ? xfs.lchmod : xfs.chmod    var chown = link ? xfs.lchown : xfs.chown    /* eslint-enable node/no-deprecated-api */    if (!chmod) return cb()    var mode = (header.mode | (header.type === 'directory' ? dmode : fmode)) & umask    if (chown && own) chown.call(xfs, name, header.uid, header.gid, onchown)    else onchown(null)    function onchown (err) {      if (err) return cb(err)      if (!chmod) return cb()      chmod.call(xfs, name, mode, cb)    }  }  extract.on('entry', function (header, stream, next) {    header = map(header) || header    header.name = normalize(header.name)    var name = path.join(cwd, path.join('/', header.name))    if (ignore(name, header)) {      stream.resume()      return next()    }    var stat = function (err) {      if (err) return next(err)      utimes(name, header, function (err) {        if (err) return next(err)        if (win32) return next()        chperm(name, header, next)      })    }    var onsymlink = function () {      if (win32) return next() // skip symlinks on win for now before it can be tested      xfs.unlink(name, function () {        xfs.symlink(header.linkname, name, stat)      })    }    var onlink = function () {      if (win32) return next() // skip links on win for now before it can be tested      xfs.unlink(name, function () {        var srcpath = path.join(cwd, path.join('/', header.linkname))        xfs.link(srcpath, name, function (err) {          if (err && err.code === 'EPERM' && opts.hardlinkAsFilesFallback) {            stream = xfs.createReadStream(srcpath)            return onfile()          }          stat(err)        })      })    }    var onfile = function () {      var ws = xfs.createWriteStream(name)      var rs = mapStream(stream, header)      ws.on('error', function (err) { // always forward errors on destroy        rs.destroy(err)      })      pump(rs, ws, function (err) {        if (err) return next(err)        ws.on('close', stat)      })    }    if (header.type === 'directory') {      stack.push([name, header.mtime])      return mkdirfix(name, {        fs: xfs, own: own, uid: header.uid, gid: header.gid      }, stat)    }    var dir = path.dirname(name)    validate(xfs, dir, path.join(cwd, '.'), function (err, valid) {      if (err) return next(err)      if (!valid) return next(new Error(dir + ' is not a valid path'))      mkdirfix(dir, {        fs: xfs, own: own, uid: header.uid, gid: header.gid      }, function (err) {        if (err) return next(err)        switch (header.type) {          case 'file': return onfile()          case 'link': return onlink()          case 'symlink': return onsymlink()        }        if (strict) return next(new Error('unsupported type for ' + name + ' (' + header.type + ')'))        stream.resume()        next()      })    })  })  if (opts.finish) extract.on('finish', opts.finish)  return extract}function validate (fs, name, root, cb) {  if (name === root) return cb(null, true)  fs.lstat(name, function (err, st) {    if (err && err.code !== 'ENOENT') return cb(err)    if (err || st.isDirectory()) return validate(fs, path.join(name, '..'), root, cb)    cb(null, false)  })}function mkdirfix (name, opts, cb) {  mkdirp(name, { fs: opts.fs }, function (err, made) {    if (!err && made && opts.own) {      chownr(made, opts.uid, opts.gid, cb)    } else {      cb(err)    }  })}
 |