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.
		
		
		
		
		
			
		
			
				
					
					
						
							547 lines
						
					
					
						
							15 KiB
						
					
					
				
			
		
		
	
	
							547 lines
						
					
					
						
							15 KiB
						
					
					
				'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
 |