Index: node_modules/tar/lib/write-entry.js
===================================================================
--- node_modules/tar/lib/write-entry.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/tar/lib/write-entry.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,546 @@
+'use strict'
+const { Minipass } = require('minipass')
+const Pax = require('./pax.js')
+const Header = require('./header.js')
+const fs = require('fs')
+const path = require('path')
+const normPath = require('./normalize-windows-path.js')
+const stripSlash = require('./strip-trailing-slashes.js')
+
+const prefixPath = (path, prefix) => {
+  if (!prefix) {
+    return normPath(path)
+  }
+  path = normPath(path).replace(/^\.(\/|$)/, '')
+  return stripSlash(prefix) + '/' + path
+}
+
+const maxReadSize = 16 * 1024 * 1024
+const PROCESS = Symbol('process')
+const FILE = Symbol('file')
+const DIRECTORY = Symbol('directory')
+const SYMLINK = Symbol('symlink')
+const HARDLINK = Symbol('hardlink')
+const HEADER = Symbol('header')
+const READ = Symbol('read')
+const LSTAT = Symbol('lstat')
+const ONLSTAT = Symbol('onlstat')
+const ONREAD = Symbol('onread')
+const ONREADLINK = Symbol('onreadlink')
+const OPENFILE = Symbol('openfile')
+const ONOPENFILE = Symbol('onopenfile')
+const CLOSE = Symbol('close')
+const MODE = Symbol('mode')
+const AWAITDRAIN = Symbol('awaitDrain')
+const ONDRAIN = Symbol('ondrain')
+const PREFIX = Symbol('prefix')
+const HAD_ERROR = Symbol('hadError')
+const warner = require('./warn-mixin.js')
+const winchars = require('./winchars.js')
+const stripAbsolutePath = require('./strip-absolute-path.js')
+
+const modeFix = require('./mode-fix.js')
+
+const WriteEntry = warner(class WriteEntry extends Minipass {
+  constructor (p, opt) {
+    opt = opt || {}
+    super(opt)
+    if (typeof p !== 'string') {
+      throw new TypeError('path is required')
+    }
+    this.path = normPath(p)
+    // suppress atime, ctime, uid, gid, uname, gname
+    this.portable = !!opt.portable
+    // until node has builtin pwnam functions, this'll have to do
+    this.myuid = process.getuid && process.getuid() || 0
+    this.myuser = process.env.USER || ''
+    this.maxReadSize = opt.maxReadSize || maxReadSize
+    this.linkCache = opt.linkCache || new Map()
+    this.statCache = opt.statCache || new Map()
+    this.preservePaths = !!opt.preservePaths
+    this.cwd = normPath(opt.cwd || process.cwd())
+    this.strict = !!opt.strict
+    this.noPax = !!opt.noPax
+    this.noMtime = !!opt.noMtime
+    this.mtime = opt.mtime || null
+    this.prefix = opt.prefix ? normPath(opt.prefix) : null
+
+    this.fd = null
+    this.blockLen = null
+    this.blockRemain = null
+    this.buf = null
+    this.offset = null
+    this.length = null
+    this.pos = null
+    this.remain = null
+
+    if (typeof opt.onwarn === 'function') {
+      this.on('warn', opt.onwarn)
+    }
+
+    let pathWarn = false
+    if (!this.preservePaths) {
+      const [root, stripped] = stripAbsolutePath(this.path)
+      if (root) {
+        this.path = stripped
+        pathWarn = root
+      }
+    }
+
+    this.win32 = !!opt.win32 || process.platform === 'win32'
+    if (this.win32) {
+      // force the \ to / normalization, since we might not *actually*
+      // be on windows, but want \ to be considered a path separator.
+      this.path = winchars.decode(this.path.replace(/\\/g, '/'))
+      p = p.replace(/\\/g, '/')
+    }
+
+    this.absolute = normPath(opt.absolute || path.resolve(this.cwd, p))
+
+    if (this.path === '') {
+      this.path = './'
+    }
+
+    if (pathWarn) {
+      this.warn('TAR_ENTRY_INFO', `stripping ${pathWarn} from absolute path`, {
+        entry: this,
+        path: pathWarn + this.path,
+      })
+    }
+
+    if (this.statCache.has(this.absolute)) {
+      this[ONLSTAT](this.statCache.get(this.absolute))
+    } else {
+      this[LSTAT]()
+    }
+  }
+
+  emit (ev, ...data) {
+    if (ev === 'error') {
+      this[HAD_ERROR] = true
+    }
+    return super.emit(ev, ...data)
+  }
+
+  [LSTAT] () {
+    fs.lstat(this.absolute, (er, stat) => {
+      if (er) {
+        return this.emit('error', er)
+      }
+      this[ONLSTAT](stat)
+    })
+  }
+
+  [ONLSTAT] (stat) {
+    this.statCache.set(this.absolute, stat)
+    this.stat = stat
+    if (!stat.isFile()) {
+      stat.size = 0
+    }
+    this.type = getType(stat)
+    this.emit('stat', stat)
+    this[PROCESS]()
+  }
+
+  [PROCESS] () {
+    switch (this.type) {
+      case 'File': return this[FILE]()
+      case 'Directory': return this[DIRECTORY]()
+      case 'SymbolicLink': return this[SYMLINK]()
+      // unsupported types are ignored.
+      default: return this.end()
+    }
+  }
+
+  [MODE] (mode) {
+    return modeFix(mode, this.type === 'Directory', this.portable)
+  }
+
+  [PREFIX] (path) {
+    return prefixPath(path, this.prefix)
+  }
+
+  [HEADER] () {
+    if (this.type === 'Directory' && this.portable) {
+      this.noMtime = true
+    }
+
+    this.header = new Header({
+      path: this[PREFIX](this.path),
+      // only apply the prefix to hard links.
+      linkpath: this.type === 'Link' ? this[PREFIX](this.linkpath)
+      : this.linkpath,
+      // only the permissions and setuid/setgid/sticky bitflags
+      // not the higher-order bits that specify file type
+      mode: this[MODE](this.stat.mode),
+      uid: this.portable ? null : this.stat.uid,
+      gid: this.portable ? null : this.stat.gid,
+      size: this.stat.size,
+      mtime: this.noMtime ? null : this.mtime || this.stat.mtime,
+      type: this.type,
+      uname: this.portable ? null :
+      this.stat.uid === this.myuid ? this.myuser : '',
+      atime: this.portable ? null : this.stat.atime,
+      ctime: this.portable ? null : this.stat.ctime,
+    })
+
+    if (this.header.encode() && !this.noPax) {
+      super.write(new Pax({
+        atime: this.portable ? null : this.header.atime,
+        ctime: this.portable ? null : this.header.ctime,
+        gid: this.portable ? null : this.header.gid,
+        mtime: this.noMtime ? null : this.mtime || this.header.mtime,
+        path: this[PREFIX](this.path),
+        linkpath: this.type === 'Link' ? this[PREFIX](this.linkpath)
+        : this.linkpath,
+        size: this.header.size,
+        uid: this.portable ? null : this.header.uid,
+        uname: this.portable ? null : this.header.uname,
+        dev: this.portable ? null : this.stat.dev,
+        ino: this.portable ? null : this.stat.ino,
+        nlink: this.portable ? null : this.stat.nlink,
+      }).encode())
+    }
+    super.write(this.header.block)
+  }
+
+  [DIRECTORY] () {
+    if (this.path.slice(-1) !== '/') {
+      this.path += '/'
+    }
+    this.stat.size = 0
+    this[HEADER]()
+    this.end()
+  }
+
+  [SYMLINK] () {
+    fs.readlink(this.absolute, (er, linkpath) => {
+      if (er) {
+        return this.emit('error', er)
+      }
+      this[ONREADLINK](linkpath)
+    })
+  }
+
+  [ONREADLINK] (linkpath) {
+    this.linkpath = normPath(linkpath)
+    this[HEADER]()
+    this.end()
+  }
+
+  [HARDLINK] (linkpath) {
+    this.type = 'Link'
+    this.linkpath = normPath(path.relative(this.cwd, linkpath))
+    this.stat.size = 0
+    this[HEADER]()
+    this.end()
+  }
+
+  [FILE] () {
+    if (this.stat.nlink > 1) {
+      const linkKey = this.stat.dev + ':' + this.stat.ino
+      if (this.linkCache.has(linkKey)) {
+        const linkpath = this.linkCache.get(linkKey)
+        if (linkpath.indexOf(this.cwd) === 0) {
+          return this[HARDLINK](linkpath)
+        }
+      }
+      this.linkCache.set(linkKey, this.absolute)
+    }
+
+    this[HEADER]()
+    if (this.stat.size === 0) {
+      return this.end()
+    }
+
+    this[OPENFILE]()
+  }
+
+  [OPENFILE] () {
+    fs.open(this.absolute, 'r', (er, fd) => {
+      if (er) {
+        return this.emit('error', er)
+      }
+      this[ONOPENFILE](fd)
+    })
+  }
+
+  [ONOPENFILE] (fd) {
+    this.fd = fd
+    if (this[HAD_ERROR]) {
+      return this[CLOSE]()
+    }
+
+    this.blockLen = 512 * Math.ceil(this.stat.size / 512)
+    this.blockRemain = this.blockLen
+    const bufLen = Math.min(this.blockLen, this.maxReadSize)
+    this.buf = Buffer.allocUnsafe(bufLen)
+    this.offset = 0
+    this.pos = 0
+    this.remain = this.stat.size
+    this.length = this.buf.length
+    this[READ]()
+  }
+
+  [READ] () {
+    const { fd, buf, offset, length, pos } = this
+    fs.read(fd, buf, offset, length, pos, (er, bytesRead) => {
+      if (er) {
+        // ignoring the error from close(2) is a bad practice, but at
+        // this point we already have an error, don't need another one
+        return this[CLOSE](() => this.emit('error', er))
+      }
+      this[ONREAD](bytesRead)
+    })
+  }
+
+  [CLOSE] (cb) {
+    fs.close(this.fd, cb)
+  }
+
+  [ONREAD] (bytesRead) {
+    if (bytesRead <= 0 && this.remain > 0) {
+      const er = new Error('encountered unexpected EOF')
+      er.path = this.absolute
+      er.syscall = 'read'
+      er.code = 'EOF'
+      return this[CLOSE](() => this.emit('error', er))
+    }
+
+    if (bytesRead > this.remain) {
+      const er = new Error('did not encounter expected EOF')
+      er.path = this.absolute
+      er.syscall = 'read'
+      er.code = 'EOF'
+      return this[CLOSE](() => this.emit('error', er))
+    }
+
+    // null out the rest of the buffer, if we could fit the block padding
+    // at the end of this loop, we've incremented bytesRead and this.remain
+    // to be incremented up to the blockRemain level, as if we had expected
+    // to get a null-padded file, and read it until the end.  then we will
+    // decrement both remain and blockRemain by bytesRead, and know that we
+    // reached the expected EOF, without any null buffer to append.
+    if (bytesRead === this.remain) {
+      for (let i = bytesRead; i < this.length && bytesRead < this.blockRemain; i++) {
+        this.buf[i + this.offset] = 0
+        bytesRead++
+        this.remain++
+      }
+    }
+
+    const writeBuf = this.offset === 0 && bytesRead === this.buf.length ?
+      this.buf : this.buf.slice(this.offset, this.offset + bytesRead)
+
+    const flushed = this.write(writeBuf)
+    if (!flushed) {
+      this[AWAITDRAIN](() => this[ONDRAIN]())
+    } else {
+      this[ONDRAIN]()
+    }
+  }
+
+  [AWAITDRAIN] (cb) {
+    this.once('drain', cb)
+  }
+
+  write (writeBuf) {
+    if (this.blockRemain < writeBuf.length) {
+      const er = new Error('writing more data than expected')
+      er.path = this.absolute
+      return this.emit('error', er)
+    }
+    this.remain -= writeBuf.length
+    this.blockRemain -= writeBuf.length
+    this.pos += writeBuf.length
+    this.offset += writeBuf.length
+    return super.write(writeBuf)
+  }
+
+  [ONDRAIN] () {
+    if (!this.remain) {
+      if (this.blockRemain) {
+        super.write(Buffer.alloc(this.blockRemain))
+      }
+      return this[CLOSE](er => er ? this.emit('error', er) : this.end())
+    }
+
+    if (this.offset >= this.length) {
+      // if we only have a smaller bit left to read, alloc a smaller buffer
+      // otherwise, keep it the same length it was before.
+      this.buf = Buffer.allocUnsafe(Math.min(this.blockRemain, this.buf.length))
+      this.offset = 0
+    }
+    this.length = this.buf.length - this.offset
+    this[READ]()
+  }
+})
+
+class WriteEntrySync extends WriteEntry {
+  [LSTAT] () {
+    this[ONLSTAT](fs.lstatSync(this.absolute))
+  }
+
+  [SYMLINK] () {
+    this[ONREADLINK](fs.readlinkSync(this.absolute))
+  }
+
+  [OPENFILE] () {
+    this[ONOPENFILE](fs.openSync(this.absolute, 'r'))
+  }
+
+  [READ] () {
+    let threw = true
+    try {
+      const { fd, buf, offset, length, pos } = this
+      const bytesRead = fs.readSync(fd, buf, offset, length, pos)
+      this[ONREAD](bytesRead)
+      threw = false
+    } finally {
+      // ignoring the error from close(2) is a bad practice, but at
+      // this point we already have an error, don't need another one
+      if (threw) {
+        try {
+          this[CLOSE](() => {})
+        } catch (er) {}
+      }
+    }
+  }
+
+  [AWAITDRAIN] (cb) {
+    cb()
+  }
+
+  [CLOSE] (cb) {
+    fs.closeSync(this.fd)
+    cb()
+  }
+}
+
+const WriteEntryTar = warner(class WriteEntryTar extends Minipass {
+  constructor (readEntry, opt) {
+    opt = opt || {}
+    super(opt)
+    this.preservePaths = !!opt.preservePaths
+    this.portable = !!opt.portable
+    this.strict = !!opt.strict
+    this.noPax = !!opt.noPax
+    this.noMtime = !!opt.noMtime
+
+    this.readEntry = readEntry
+    this.type = readEntry.type
+    if (this.type === 'Directory' && this.portable) {
+      this.noMtime = true
+    }
+
+    this.prefix = opt.prefix || null
+
+    this.path = normPath(readEntry.path)
+    this.mode = this[MODE](readEntry.mode)
+    this.uid = this.portable ? null : readEntry.uid
+    this.gid = this.portable ? null : readEntry.gid
+    this.uname = this.portable ? null : readEntry.uname
+    this.gname = this.portable ? null : readEntry.gname
+    this.size = readEntry.size
+    this.mtime = this.noMtime ? null : opt.mtime || readEntry.mtime
+    this.atime = this.portable ? null : readEntry.atime
+    this.ctime = this.portable ? null : readEntry.ctime
+    this.linkpath = normPath(readEntry.linkpath)
+
+    if (typeof opt.onwarn === 'function') {
+      this.on('warn', opt.onwarn)
+    }
+
+    let pathWarn = false
+    if (!this.preservePaths) {
+      const [root, stripped] = stripAbsolutePath(this.path)
+      if (root) {
+        this.path = stripped
+        pathWarn = root
+      }
+    }
+
+    this.remain = readEntry.size
+    this.blockRemain = readEntry.startBlockSize
+
+    this.header = new Header({
+      path: this[PREFIX](this.path),
+      linkpath: this.type === 'Link' ? this[PREFIX](this.linkpath)
+      : this.linkpath,
+      // only the permissions and setuid/setgid/sticky bitflags
+      // not the higher-order bits that specify file type
+      mode: this.mode,
+      uid: this.portable ? null : this.uid,
+      gid: this.portable ? null : this.gid,
+      size: this.size,
+      mtime: this.noMtime ? null : this.mtime,
+      type: this.type,
+      uname: this.portable ? null : this.uname,
+      atime: this.portable ? null : this.atime,
+      ctime: this.portable ? null : this.ctime,
+    })
+
+    if (pathWarn) {
+      this.warn('TAR_ENTRY_INFO', `stripping ${pathWarn} from absolute path`, {
+        entry: this,
+        path: pathWarn + this.path,
+      })
+    }
+
+    if (this.header.encode() && !this.noPax) {
+      super.write(new Pax({
+        atime: this.portable ? null : this.atime,
+        ctime: this.portable ? null : this.ctime,
+        gid: this.portable ? null : this.gid,
+        mtime: this.noMtime ? null : this.mtime,
+        path: this[PREFIX](this.path),
+        linkpath: this.type === 'Link' ? this[PREFIX](this.linkpath)
+        : this.linkpath,
+        size: this.size,
+        uid: this.portable ? null : this.uid,
+        uname: this.portable ? null : this.uname,
+        dev: this.portable ? null : this.readEntry.dev,
+        ino: this.portable ? null : this.readEntry.ino,
+        nlink: this.portable ? null : this.readEntry.nlink,
+      }).encode())
+    }
+
+    super.write(this.header.block)
+    readEntry.pipe(this)
+  }
+
+  [PREFIX] (path) {
+    return prefixPath(path, this.prefix)
+  }
+
+  [MODE] (mode) {
+    return modeFix(mode, this.type === 'Directory', this.portable)
+  }
+
+  write (data) {
+    const writeLen = data.length
+    if (writeLen > this.blockRemain) {
+      throw new Error('writing more to entry than is appropriate')
+    }
+    this.blockRemain -= writeLen
+    return super.write(data)
+  }
+
+  end () {
+    if (this.blockRemain) {
+      super.write(Buffer.alloc(this.blockRemain))
+    }
+    return super.end()
+  }
+})
+
+WriteEntry.Sync = WriteEntrySync
+WriteEntry.Tar = WriteEntryTar
+
+const getType = stat =>
+  stat.isFile() ? 'File'
+  : stat.isDirectory() ? 'Directory'
+  : stat.isSymbolicLink() ? 'SymbolicLink'
+  : 'Unsupported'
+
+module.exports = WriteEntry
