11cb0ef41Sopenharmony_ci'use strict'
21cb0ef41Sopenharmony_ciconst { Minipass } = require('minipass')
31cb0ef41Sopenharmony_ciconst Pax = require('./pax.js')
41cb0ef41Sopenharmony_ciconst Header = require('./header.js')
51cb0ef41Sopenharmony_ciconst fs = require('fs')
61cb0ef41Sopenharmony_ciconst path = require('path')
71cb0ef41Sopenharmony_ciconst normPath = require('./normalize-windows-path.js')
81cb0ef41Sopenharmony_ciconst stripSlash = require('./strip-trailing-slashes.js')
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ciconst prefixPath = (path, prefix) => {
111cb0ef41Sopenharmony_ci  if (!prefix) {
121cb0ef41Sopenharmony_ci    return normPath(path)
131cb0ef41Sopenharmony_ci  }
141cb0ef41Sopenharmony_ci  path = normPath(path).replace(/^\.(\/|$)/, '')
151cb0ef41Sopenharmony_ci  return stripSlash(prefix) + '/' + path
161cb0ef41Sopenharmony_ci}
171cb0ef41Sopenharmony_ci
181cb0ef41Sopenharmony_ciconst maxReadSize = 16 * 1024 * 1024
191cb0ef41Sopenharmony_ciconst PROCESS = Symbol('process')
201cb0ef41Sopenharmony_ciconst FILE = Symbol('file')
211cb0ef41Sopenharmony_ciconst DIRECTORY = Symbol('directory')
221cb0ef41Sopenharmony_ciconst SYMLINK = Symbol('symlink')
231cb0ef41Sopenharmony_ciconst HARDLINK = Symbol('hardlink')
241cb0ef41Sopenharmony_ciconst HEADER = Symbol('header')
251cb0ef41Sopenharmony_ciconst READ = Symbol('read')
261cb0ef41Sopenharmony_ciconst LSTAT = Symbol('lstat')
271cb0ef41Sopenharmony_ciconst ONLSTAT = Symbol('onlstat')
281cb0ef41Sopenharmony_ciconst ONREAD = Symbol('onread')
291cb0ef41Sopenharmony_ciconst ONREADLINK = Symbol('onreadlink')
301cb0ef41Sopenharmony_ciconst OPENFILE = Symbol('openfile')
311cb0ef41Sopenharmony_ciconst ONOPENFILE = Symbol('onopenfile')
321cb0ef41Sopenharmony_ciconst CLOSE = Symbol('close')
331cb0ef41Sopenharmony_ciconst MODE = Symbol('mode')
341cb0ef41Sopenharmony_ciconst AWAITDRAIN = Symbol('awaitDrain')
351cb0ef41Sopenharmony_ciconst ONDRAIN = Symbol('ondrain')
361cb0ef41Sopenharmony_ciconst PREFIX = Symbol('prefix')
371cb0ef41Sopenharmony_ciconst HAD_ERROR = Symbol('hadError')
381cb0ef41Sopenharmony_ciconst warner = require('./warn-mixin.js')
391cb0ef41Sopenharmony_ciconst winchars = require('./winchars.js')
401cb0ef41Sopenharmony_ciconst stripAbsolutePath = require('./strip-absolute-path.js')
411cb0ef41Sopenharmony_ci
421cb0ef41Sopenharmony_ciconst modeFix = require('./mode-fix.js')
431cb0ef41Sopenharmony_ci
441cb0ef41Sopenharmony_ciconst WriteEntry = warner(class WriteEntry extends Minipass {
451cb0ef41Sopenharmony_ci  constructor (p, opt) {
461cb0ef41Sopenharmony_ci    opt = opt || {}
471cb0ef41Sopenharmony_ci    super(opt)
481cb0ef41Sopenharmony_ci    if (typeof p !== 'string') {
491cb0ef41Sopenharmony_ci      throw new TypeError('path is required')
501cb0ef41Sopenharmony_ci    }
511cb0ef41Sopenharmony_ci    this.path = normPath(p)
521cb0ef41Sopenharmony_ci    // suppress atime, ctime, uid, gid, uname, gname
531cb0ef41Sopenharmony_ci    this.portable = !!opt.portable
541cb0ef41Sopenharmony_ci    // until node has builtin pwnam functions, this'll have to do
551cb0ef41Sopenharmony_ci    this.myuid = process.getuid && process.getuid() || 0
561cb0ef41Sopenharmony_ci    this.myuser = process.env.USER || ''
571cb0ef41Sopenharmony_ci    this.maxReadSize = opt.maxReadSize || maxReadSize
581cb0ef41Sopenharmony_ci    this.linkCache = opt.linkCache || new Map()
591cb0ef41Sopenharmony_ci    this.statCache = opt.statCache || new Map()
601cb0ef41Sopenharmony_ci    this.preservePaths = !!opt.preservePaths
611cb0ef41Sopenharmony_ci    this.cwd = normPath(opt.cwd || process.cwd())
621cb0ef41Sopenharmony_ci    this.strict = !!opt.strict
631cb0ef41Sopenharmony_ci    this.noPax = !!opt.noPax
641cb0ef41Sopenharmony_ci    this.noMtime = !!opt.noMtime
651cb0ef41Sopenharmony_ci    this.mtime = opt.mtime || null
661cb0ef41Sopenharmony_ci    this.prefix = opt.prefix ? normPath(opt.prefix) : null
671cb0ef41Sopenharmony_ci
681cb0ef41Sopenharmony_ci    this.fd = null
691cb0ef41Sopenharmony_ci    this.blockLen = null
701cb0ef41Sopenharmony_ci    this.blockRemain = null
711cb0ef41Sopenharmony_ci    this.buf = null
721cb0ef41Sopenharmony_ci    this.offset = null
731cb0ef41Sopenharmony_ci    this.length = null
741cb0ef41Sopenharmony_ci    this.pos = null
751cb0ef41Sopenharmony_ci    this.remain = null
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_ci    if (typeof opt.onwarn === 'function') {
781cb0ef41Sopenharmony_ci      this.on('warn', opt.onwarn)
791cb0ef41Sopenharmony_ci    }
801cb0ef41Sopenharmony_ci
811cb0ef41Sopenharmony_ci    let pathWarn = false
821cb0ef41Sopenharmony_ci    if (!this.preservePaths) {
831cb0ef41Sopenharmony_ci      const [root, stripped] = stripAbsolutePath(this.path)
841cb0ef41Sopenharmony_ci      if (root) {
851cb0ef41Sopenharmony_ci        this.path = stripped
861cb0ef41Sopenharmony_ci        pathWarn = root
871cb0ef41Sopenharmony_ci      }
881cb0ef41Sopenharmony_ci    }
891cb0ef41Sopenharmony_ci
901cb0ef41Sopenharmony_ci    this.win32 = !!opt.win32 || process.platform === 'win32'
911cb0ef41Sopenharmony_ci    if (this.win32) {
921cb0ef41Sopenharmony_ci      // force the \ to / normalization, since we might not *actually*
931cb0ef41Sopenharmony_ci      // be on windows, but want \ to be considered a path separator.
941cb0ef41Sopenharmony_ci      this.path = winchars.decode(this.path.replace(/\\/g, '/'))
951cb0ef41Sopenharmony_ci      p = p.replace(/\\/g, '/')
961cb0ef41Sopenharmony_ci    }
971cb0ef41Sopenharmony_ci
981cb0ef41Sopenharmony_ci    this.absolute = normPath(opt.absolute || path.resolve(this.cwd, p))
991cb0ef41Sopenharmony_ci
1001cb0ef41Sopenharmony_ci    if (this.path === '') {
1011cb0ef41Sopenharmony_ci      this.path = './'
1021cb0ef41Sopenharmony_ci    }
1031cb0ef41Sopenharmony_ci
1041cb0ef41Sopenharmony_ci    if (pathWarn) {
1051cb0ef41Sopenharmony_ci      this.warn('TAR_ENTRY_INFO', `stripping ${pathWarn} from absolute path`, {
1061cb0ef41Sopenharmony_ci        entry: this,
1071cb0ef41Sopenharmony_ci        path: pathWarn + this.path,
1081cb0ef41Sopenharmony_ci      })
1091cb0ef41Sopenharmony_ci    }
1101cb0ef41Sopenharmony_ci
1111cb0ef41Sopenharmony_ci    if (this.statCache.has(this.absolute)) {
1121cb0ef41Sopenharmony_ci      this[ONLSTAT](this.statCache.get(this.absolute))
1131cb0ef41Sopenharmony_ci    } else {
1141cb0ef41Sopenharmony_ci      this[LSTAT]()
1151cb0ef41Sopenharmony_ci    }
1161cb0ef41Sopenharmony_ci  }
1171cb0ef41Sopenharmony_ci
1181cb0ef41Sopenharmony_ci  emit (ev, ...data) {
1191cb0ef41Sopenharmony_ci    if (ev === 'error') {
1201cb0ef41Sopenharmony_ci      this[HAD_ERROR] = true
1211cb0ef41Sopenharmony_ci    }
1221cb0ef41Sopenharmony_ci    return super.emit(ev, ...data)
1231cb0ef41Sopenharmony_ci  }
1241cb0ef41Sopenharmony_ci
1251cb0ef41Sopenharmony_ci  [LSTAT] () {
1261cb0ef41Sopenharmony_ci    fs.lstat(this.absolute, (er, stat) => {
1271cb0ef41Sopenharmony_ci      if (er) {
1281cb0ef41Sopenharmony_ci        return this.emit('error', er)
1291cb0ef41Sopenharmony_ci      }
1301cb0ef41Sopenharmony_ci      this[ONLSTAT](stat)
1311cb0ef41Sopenharmony_ci    })
1321cb0ef41Sopenharmony_ci  }
1331cb0ef41Sopenharmony_ci
1341cb0ef41Sopenharmony_ci  [ONLSTAT] (stat) {
1351cb0ef41Sopenharmony_ci    this.statCache.set(this.absolute, stat)
1361cb0ef41Sopenharmony_ci    this.stat = stat
1371cb0ef41Sopenharmony_ci    if (!stat.isFile()) {
1381cb0ef41Sopenharmony_ci      stat.size = 0
1391cb0ef41Sopenharmony_ci    }
1401cb0ef41Sopenharmony_ci    this.type = getType(stat)
1411cb0ef41Sopenharmony_ci    this.emit('stat', stat)
1421cb0ef41Sopenharmony_ci    this[PROCESS]()
1431cb0ef41Sopenharmony_ci  }
1441cb0ef41Sopenharmony_ci
1451cb0ef41Sopenharmony_ci  [PROCESS] () {
1461cb0ef41Sopenharmony_ci    switch (this.type) {
1471cb0ef41Sopenharmony_ci      case 'File': return this[FILE]()
1481cb0ef41Sopenharmony_ci      case 'Directory': return this[DIRECTORY]()
1491cb0ef41Sopenharmony_ci      case 'SymbolicLink': return this[SYMLINK]()
1501cb0ef41Sopenharmony_ci      // unsupported types are ignored.
1511cb0ef41Sopenharmony_ci      default: return this.end()
1521cb0ef41Sopenharmony_ci    }
1531cb0ef41Sopenharmony_ci  }
1541cb0ef41Sopenharmony_ci
1551cb0ef41Sopenharmony_ci  [MODE] (mode) {
1561cb0ef41Sopenharmony_ci    return modeFix(mode, this.type === 'Directory', this.portable)
1571cb0ef41Sopenharmony_ci  }
1581cb0ef41Sopenharmony_ci
1591cb0ef41Sopenharmony_ci  [PREFIX] (path) {
1601cb0ef41Sopenharmony_ci    return prefixPath(path, this.prefix)
1611cb0ef41Sopenharmony_ci  }
1621cb0ef41Sopenharmony_ci
1631cb0ef41Sopenharmony_ci  [HEADER] () {
1641cb0ef41Sopenharmony_ci    if (this.type === 'Directory' && this.portable) {
1651cb0ef41Sopenharmony_ci      this.noMtime = true
1661cb0ef41Sopenharmony_ci    }
1671cb0ef41Sopenharmony_ci
1681cb0ef41Sopenharmony_ci    this.header = new Header({
1691cb0ef41Sopenharmony_ci      path: this[PREFIX](this.path),
1701cb0ef41Sopenharmony_ci      // only apply the prefix to hard links.
1711cb0ef41Sopenharmony_ci      linkpath: this.type === 'Link' ? this[PREFIX](this.linkpath)
1721cb0ef41Sopenharmony_ci      : this.linkpath,
1731cb0ef41Sopenharmony_ci      // only the permissions and setuid/setgid/sticky bitflags
1741cb0ef41Sopenharmony_ci      // not the higher-order bits that specify file type
1751cb0ef41Sopenharmony_ci      mode: this[MODE](this.stat.mode),
1761cb0ef41Sopenharmony_ci      uid: this.portable ? null : this.stat.uid,
1771cb0ef41Sopenharmony_ci      gid: this.portable ? null : this.stat.gid,
1781cb0ef41Sopenharmony_ci      size: this.stat.size,
1791cb0ef41Sopenharmony_ci      mtime: this.noMtime ? null : this.mtime || this.stat.mtime,
1801cb0ef41Sopenharmony_ci      type: this.type,
1811cb0ef41Sopenharmony_ci      uname: this.portable ? null :
1821cb0ef41Sopenharmony_ci      this.stat.uid === this.myuid ? this.myuser : '',
1831cb0ef41Sopenharmony_ci      atime: this.portable ? null : this.stat.atime,
1841cb0ef41Sopenharmony_ci      ctime: this.portable ? null : this.stat.ctime,
1851cb0ef41Sopenharmony_ci    })
1861cb0ef41Sopenharmony_ci
1871cb0ef41Sopenharmony_ci    if (this.header.encode() && !this.noPax) {
1881cb0ef41Sopenharmony_ci      super.write(new Pax({
1891cb0ef41Sopenharmony_ci        atime: this.portable ? null : this.header.atime,
1901cb0ef41Sopenharmony_ci        ctime: this.portable ? null : this.header.ctime,
1911cb0ef41Sopenharmony_ci        gid: this.portable ? null : this.header.gid,
1921cb0ef41Sopenharmony_ci        mtime: this.noMtime ? null : this.mtime || this.header.mtime,
1931cb0ef41Sopenharmony_ci        path: this[PREFIX](this.path),
1941cb0ef41Sopenharmony_ci        linkpath: this.type === 'Link' ? this[PREFIX](this.linkpath)
1951cb0ef41Sopenharmony_ci        : this.linkpath,
1961cb0ef41Sopenharmony_ci        size: this.header.size,
1971cb0ef41Sopenharmony_ci        uid: this.portable ? null : this.header.uid,
1981cb0ef41Sopenharmony_ci        uname: this.portable ? null : this.header.uname,
1991cb0ef41Sopenharmony_ci        dev: this.portable ? null : this.stat.dev,
2001cb0ef41Sopenharmony_ci        ino: this.portable ? null : this.stat.ino,
2011cb0ef41Sopenharmony_ci        nlink: this.portable ? null : this.stat.nlink,
2021cb0ef41Sopenharmony_ci      }).encode())
2031cb0ef41Sopenharmony_ci    }
2041cb0ef41Sopenharmony_ci    super.write(this.header.block)
2051cb0ef41Sopenharmony_ci  }
2061cb0ef41Sopenharmony_ci
2071cb0ef41Sopenharmony_ci  [DIRECTORY] () {
2081cb0ef41Sopenharmony_ci    if (this.path.slice(-1) !== '/') {
2091cb0ef41Sopenharmony_ci      this.path += '/'
2101cb0ef41Sopenharmony_ci    }
2111cb0ef41Sopenharmony_ci    this.stat.size = 0
2121cb0ef41Sopenharmony_ci    this[HEADER]()
2131cb0ef41Sopenharmony_ci    this.end()
2141cb0ef41Sopenharmony_ci  }
2151cb0ef41Sopenharmony_ci
2161cb0ef41Sopenharmony_ci  [SYMLINK] () {
2171cb0ef41Sopenharmony_ci    fs.readlink(this.absolute, (er, linkpath) => {
2181cb0ef41Sopenharmony_ci      if (er) {
2191cb0ef41Sopenharmony_ci        return this.emit('error', er)
2201cb0ef41Sopenharmony_ci      }
2211cb0ef41Sopenharmony_ci      this[ONREADLINK](linkpath)
2221cb0ef41Sopenharmony_ci    })
2231cb0ef41Sopenharmony_ci  }
2241cb0ef41Sopenharmony_ci
2251cb0ef41Sopenharmony_ci  [ONREADLINK] (linkpath) {
2261cb0ef41Sopenharmony_ci    this.linkpath = normPath(linkpath)
2271cb0ef41Sopenharmony_ci    this[HEADER]()
2281cb0ef41Sopenharmony_ci    this.end()
2291cb0ef41Sopenharmony_ci  }
2301cb0ef41Sopenharmony_ci
2311cb0ef41Sopenharmony_ci  [HARDLINK] (linkpath) {
2321cb0ef41Sopenharmony_ci    this.type = 'Link'
2331cb0ef41Sopenharmony_ci    this.linkpath = normPath(path.relative(this.cwd, linkpath))
2341cb0ef41Sopenharmony_ci    this.stat.size = 0
2351cb0ef41Sopenharmony_ci    this[HEADER]()
2361cb0ef41Sopenharmony_ci    this.end()
2371cb0ef41Sopenharmony_ci  }
2381cb0ef41Sopenharmony_ci
2391cb0ef41Sopenharmony_ci  [FILE] () {
2401cb0ef41Sopenharmony_ci    if (this.stat.nlink > 1) {
2411cb0ef41Sopenharmony_ci      const linkKey = this.stat.dev + ':' + this.stat.ino
2421cb0ef41Sopenharmony_ci      if (this.linkCache.has(linkKey)) {
2431cb0ef41Sopenharmony_ci        const linkpath = this.linkCache.get(linkKey)
2441cb0ef41Sopenharmony_ci        if (linkpath.indexOf(this.cwd) === 0) {
2451cb0ef41Sopenharmony_ci          return this[HARDLINK](linkpath)
2461cb0ef41Sopenharmony_ci        }
2471cb0ef41Sopenharmony_ci      }
2481cb0ef41Sopenharmony_ci      this.linkCache.set(linkKey, this.absolute)
2491cb0ef41Sopenharmony_ci    }
2501cb0ef41Sopenharmony_ci
2511cb0ef41Sopenharmony_ci    this[HEADER]()
2521cb0ef41Sopenharmony_ci    if (this.stat.size === 0) {
2531cb0ef41Sopenharmony_ci      return this.end()
2541cb0ef41Sopenharmony_ci    }
2551cb0ef41Sopenharmony_ci
2561cb0ef41Sopenharmony_ci    this[OPENFILE]()
2571cb0ef41Sopenharmony_ci  }
2581cb0ef41Sopenharmony_ci
2591cb0ef41Sopenharmony_ci  [OPENFILE] () {
2601cb0ef41Sopenharmony_ci    fs.open(this.absolute, 'r', (er, fd) => {
2611cb0ef41Sopenharmony_ci      if (er) {
2621cb0ef41Sopenharmony_ci        return this.emit('error', er)
2631cb0ef41Sopenharmony_ci      }
2641cb0ef41Sopenharmony_ci      this[ONOPENFILE](fd)
2651cb0ef41Sopenharmony_ci    })
2661cb0ef41Sopenharmony_ci  }
2671cb0ef41Sopenharmony_ci
2681cb0ef41Sopenharmony_ci  [ONOPENFILE] (fd) {
2691cb0ef41Sopenharmony_ci    this.fd = fd
2701cb0ef41Sopenharmony_ci    if (this[HAD_ERROR]) {
2711cb0ef41Sopenharmony_ci      return this[CLOSE]()
2721cb0ef41Sopenharmony_ci    }
2731cb0ef41Sopenharmony_ci
2741cb0ef41Sopenharmony_ci    this.blockLen = 512 * Math.ceil(this.stat.size / 512)
2751cb0ef41Sopenharmony_ci    this.blockRemain = this.blockLen
2761cb0ef41Sopenharmony_ci    const bufLen = Math.min(this.blockLen, this.maxReadSize)
2771cb0ef41Sopenharmony_ci    this.buf = Buffer.allocUnsafe(bufLen)
2781cb0ef41Sopenharmony_ci    this.offset = 0
2791cb0ef41Sopenharmony_ci    this.pos = 0
2801cb0ef41Sopenharmony_ci    this.remain = this.stat.size
2811cb0ef41Sopenharmony_ci    this.length = this.buf.length
2821cb0ef41Sopenharmony_ci    this[READ]()
2831cb0ef41Sopenharmony_ci  }
2841cb0ef41Sopenharmony_ci
2851cb0ef41Sopenharmony_ci  [READ] () {
2861cb0ef41Sopenharmony_ci    const { fd, buf, offset, length, pos } = this
2871cb0ef41Sopenharmony_ci    fs.read(fd, buf, offset, length, pos, (er, bytesRead) => {
2881cb0ef41Sopenharmony_ci      if (er) {
2891cb0ef41Sopenharmony_ci        // ignoring the error from close(2) is a bad practice, but at
2901cb0ef41Sopenharmony_ci        // this point we already have an error, don't need another one
2911cb0ef41Sopenharmony_ci        return this[CLOSE](() => this.emit('error', er))
2921cb0ef41Sopenharmony_ci      }
2931cb0ef41Sopenharmony_ci      this[ONREAD](bytesRead)
2941cb0ef41Sopenharmony_ci    })
2951cb0ef41Sopenharmony_ci  }
2961cb0ef41Sopenharmony_ci
2971cb0ef41Sopenharmony_ci  [CLOSE] (cb) {
2981cb0ef41Sopenharmony_ci    fs.close(this.fd, cb)
2991cb0ef41Sopenharmony_ci  }
3001cb0ef41Sopenharmony_ci
3011cb0ef41Sopenharmony_ci  [ONREAD] (bytesRead) {
3021cb0ef41Sopenharmony_ci    if (bytesRead <= 0 && this.remain > 0) {
3031cb0ef41Sopenharmony_ci      const er = new Error('encountered unexpected EOF')
3041cb0ef41Sopenharmony_ci      er.path = this.absolute
3051cb0ef41Sopenharmony_ci      er.syscall = 'read'
3061cb0ef41Sopenharmony_ci      er.code = 'EOF'
3071cb0ef41Sopenharmony_ci      return this[CLOSE](() => this.emit('error', er))
3081cb0ef41Sopenharmony_ci    }
3091cb0ef41Sopenharmony_ci
3101cb0ef41Sopenharmony_ci    if (bytesRead > this.remain) {
3111cb0ef41Sopenharmony_ci      const er = new Error('did not encounter expected EOF')
3121cb0ef41Sopenharmony_ci      er.path = this.absolute
3131cb0ef41Sopenharmony_ci      er.syscall = 'read'
3141cb0ef41Sopenharmony_ci      er.code = 'EOF'
3151cb0ef41Sopenharmony_ci      return this[CLOSE](() => this.emit('error', er))
3161cb0ef41Sopenharmony_ci    }
3171cb0ef41Sopenharmony_ci
3181cb0ef41Sopenharmony_ci    // null out the rest of the buffer, if we could fit the block padding
3191cb0ef41Sopenharmony_ci    // at the end of this loop, we've incremented bytesRead and this.remain
3201cb0ef41Sopenharmony_ci    // to be incremented up to the blockRemain level, as if we had expected
3211cb0ef41Sopenharmony_ci    // to get a null-padded file, and read it until the end.  then we will
3221cb0ef41Sopenharmony_ci    // decrement both remain and blockRemain by bytesRead, and know that we
3231cb0ef41Sopenharmony_ci    // reached the expected EOF, without any null buffer to append.
3241cb0ef41Sopenharmony_ci    if (bytesRead === this.remain) {
3251cb0ef41Sopenharmony_ci      for (let i = bytesRead; i < this.length && bytesRead < this.blockRemain; i++) {
3261cb0ef41Sopenharmony_ci        this.buf[i + this.offset] = 0
3271cb0ef41Sopenharmony_ci        bytesRead++
3281cb0ef41Sopenharmony_ci        this.remain++
3291cb0ef41Sopenharmony_ci      }
3301cb0ef41Sopenharmony_ci    }
3311cb0ef41Sopenharmony_ci
3321cb0ef41Sopenharmony_ci    const writeBuf = this.offset === 0 && bytesRead === this.buf.length ?
3331cb0ef41Sopenharmony_ci      this.buf : this.buf.slice(this.offset, this.offset + bytesRead)
3341cb0ef41Sopenharmony_ci
3351cb0ef41Sopenharmony_ci    const flushed = this.write(writeBuf)
3361cb0ef41Sopenharmony_ci    if (!flushed) {
3371cb0ef41Sopenharmony_ci      this[AWAITDRAIN](() => this[ONDRAIN]())
3381cb0ef41Sopenharmony_ci    } else {
3391cb0ef41Sopenharmony_ci      this[ONDRAIN]()
3401cb0ef41Sopenharmony_ci    }
3411cb0ef41Sopenharmony_ci  }
3421cb0ef41Sopenharmony_ci
3431cb0ef41Sopenharmony_ci  [AWAITDRAIN] (cb) {
3441cb0ef41Sopenharmony_ci    this.once('drain', cb)
3451cb0ef41Sopenharmony_ci  }
3461cb0ef41Sopenharmony_ci
3471cb0ef41Sopenharmony_ci  write (writeBuf) {
3481cb0ef41Sopenharmony_ci    if (this.blockRemain < writeBuf.length) {
3491cb0ef41Sopenharmony_ci      const er = new Error('writing more data than expected')
3501cb0ef41Sopenharmony_ci      er.path = this.absolute
3511cb0ef41Sopenharmony_ci      return this.emit('error', er)
3521cb0ef41Sopenharmony_ci    }
3531cb0ef41Sopenharmony_ci    this.remain -= writeBuf.length
3541cb0ef41Sopenharmony_ci    this.blockRemain -= writeBuf.length
3551cb0ef41Sopenharmony_ci    this.pos += writeBuf.length
3561cb0ef41Sopenharmony_ci    this.offset += writeBuf.length
3571cb0ef41Sopenharmony_ci    return super.write(writeBuf)
3581cb0ef41Sopenharmony_ci  }
3591cb0ef41Sopenharmony_ci
3601cb0ef41Sopenharmony_ci  [ONDRAIN] () {
3611cb0ef41Sopenharmony_ci    if (!this.remain) {
3621cb0ef41Sopenharmony_ci      if (this.blockRemain) {
3631cb0ef41Sopenharmony_ci        super.write(Buffer.alloc(this.blockRemain))
3641cb0ef41Sopenharmony_ci      }
3651cb0ef41Sopenharmony_ci      return this[CLOSE](er => er ? this.emit('error', er) : this.end())
3661cb0ef41Sopenharmony_ci    }
3671cb0ef41Sopenharmony_ci
3681cb0ef41Sopenharmony_ci    if (this.offset >= this.length) {
3691cb0ef41Sopenharmony_ci      // if we only have a smaller bit left to read, alloc a smaller buffer
3701cb0ef41Sopenharmony_ci      // otherwise, keep it the same length it was before.
3711cb0ef41Sopenharmony_ci      this.buf = Buffer.allocUnsafe(Math.min(this.blockRemain, this.buf.length))
3721cb0ef41Sopenharmony_ci      this.offset = 0
3731cb0ef41Sopenharmony_ci    }
3741cb0ef41Sopenharmony_ci    this.length = this.buf.length - this.offset
3751cb0ef41Sopenharmony_ci    this[READ]()
3761cb0ef41Sopenharmony_ci  }
3771cb0ef41Sopenharmony_ci})
3781cb0ef41Sopenharmony_ci
3791cb0ef41Sopenharmony_ciclass WriteEntrySync extends WriteEntry {
3801cb0ef41Sopenharmony_ci  [LSTAT] () {
3811cb0ef41Sopenharmony_ci    this[ONLSTAT](fs.lstatSync(this.absolute))
3821cb0ef41Sopenharmony_ci  }
3831cb0ef41Sopenharmony_ci
3841cb0ef41Sopenharmony_ci  [SYMLINK] () {
3851cb0ef41Sopenharmony_ci    this[ONREADLINK](fs.readlinkSync(this.absolute))
3861cb0ef41Sopenharmony_ci  }
3871cb0ef41Sopenharmony_ci
3881cb0ef41Sopenharmony_ci  [OPENFILE] () {
3891cb0ef41Sopenharmony_ci    this[ONOPENFILE](fs.openSync(this.absolute, 'r'))
3901cb0ef41Sopenharmony_ci  }
3911cb0ef41Sopenharmony_ci
3921cb0ef41Sopenharmony_ci  [READ] () {
3931cb0ef41Sopenharmony_ci    let threw = true
3941cb0ef41Sopenharmony_ci    try {
3951cb0ef41Sopenharmony_ci      const { fd, buf, offset, length, pos } = this
3961cb0ef41Sopenharmony_ci      const bytesRead = fs.readSync(fd, buf, offset, length, pos)
3971cb0ef41Sopenharmony_ci      this[ONREAD](bytesRead)
3981cb0ef41Sopenharmony_ci      threw = false
3991cb0ef41Sopenharmony_ci    } finally {
4001cb0ef41Sopenharmony_ci      // ignoring the error from close(2) is a bad practice, but at
4011cb0ef41Sopenharmony_ci      // this point we already have an error, don't need another one
4021cb0ef41Sopenharmony_ci      if (threw) {
4031cb0ef41Sopenharmony_ci        try {
4041cb0ef41Sopenharmony_ci          this[CLOSE](() => {})
4051cb0ef41Sopenharmony_ci        } catch (er) {}
4061cb0ef41Sopenharmony_ci      }
4071cb0ef41Sopenharmony_ci    }
4081cb0ef41Sopenharmony_ci  }
4091cb0ef41Sopenharmony_ci
4101cb0ef41Sopenharmony_ci  [AWAITDRAIN] (cb) {
4111cb0ef41Sopenharmony_ci    cb()
4121cb0ef41Sopenharmony_ci  }
4131cb0ef41Sopenharmony_ci
4141cb0ef41Sopenharmony_ci  [CLOSE] (cb) {
4151cb0ef41Sopenharmony_ci    fs.closeSync(this.fd)
4161cb0ef41Sopenharmony_ci    cb()
4171cb0ef41Sopenharmony_ci  }
4181cb0ef41Sopenharmony_ci}
4191cb0ef41Sopenharmony_ci
4201cb0ef41Sopenharmony_ciconst WriteEntryTar = warner(class WriteEntryTar extends Minipass {
4211cb0ef41Sopenharmony_ci  constructor (readEntry, opt) {
4221cb0ef41Sopenharmony_ci    opt = opt || {}
4231cb0ef41Sopenharmony_ci    super(opt)
4241cb0ef41Sopenharmony_ci    this.preservePaths = !!opt.preservePaths
4251cb0ef41Sopenharmony_ci    this.portable = !!opt.portable
4261cb0ef41Sopenharmony_ci    this.strict = !!opt.strict
4271cb0ef41Sopenharmony_ci    this.noPax = !!opt.noPax
4281cb0ef41Sopenharmony_ci    this.noMtime = !!opt.noMtime
4291cb0ef41Sopenharmony_ci
4301cb0ef41Sopenharmony_ci    this.readEntry = readEntry
4311cb0ef41Sopenharmony_ci    this.type = readEntry.type
4321cb0ef41Sopenharmony_ci    if (this.type === 'Directory' && this.portable) {
4331cb0ef41Sopenharmony_ci      this.noMtime = true
4341cb0ef41Sopenharmony_ci    }
4351cb0ef41Sopenharmony_ci
4361cb0ef41Sopenharmony_ci    this.prefix = opt.prefix || null
4371cb0ef41Sopenharmony_ci
4381cb0ef41Sopenharmony_ci    this.path = normPath(readEntry.path)
4391cb0ef41Sopenharmony_ci    this.mode = this[MODE](readEntry.mode)
4401cb0ef41Sopenharmony_ci    this.uid = this.portable ? null : readEntry.uid
4411cb0ef41Sopenharmony_ci    this.gid = this.portable ? null : readEntry.gid
4421cb0ef41Sopenharmony_ci    this.uname = this.portable ? null : readEntry.uname
4431cb0ef41Sopenharmony_ci    this.gname = this.portable ? null : readEntry.gname
4441cb0ef41Sopenharmony_ci    this.size = readEntry.size
4451cb0ef41Sopenharmony_ci    this.mtime = this.noMtime ? null : opt.mtime || readEntry.mtime
4461cb0ef41Sopenharmony_ci    this.atime = this.portable ? null : readEntry.atime
4471cb0ef41Sopenharmony_ci    this.ctime = this.portable ? null : readEntry.ctime
4481cb0ef41Sopenharmony_ci    this.linkpath = normPath(readEntry.linkpath)
4491cb0ef41Sopenharmony_ci
4501cb0ef41Sopenharmony_ci    if (typeof opt.onwarn === 'function') {
4511cb0ef41Sopenharmony_ci      this.on('warn', opt.onwarn)
4521cb0ef41Sopenharmony_ci    }
4531cb0ef41Sopenharmony_ci
4541cb0ef41Sopenharmony_ci    let pathWarn = false
4551cb0ef41Sopenharmony_ci    if (!this.preservePaths) {
4561cb0ef41Sopenharmony_ci      const [root, stripped] = stripAbsolutePath(this.path)
4571cb0ef41Sopenharmony_ci      if (root) {
4581cb0ef41Sopenharmony_ci        this.path = stripped
4591cb0ef41Sopenharmony_ci        pathWarn = root
4601cb0ef41Sopenharmony_ci      }
4611cb0ef41Sopenharmony_ci    }
4621cb0ef41Sopenharmony_ci
4631cb0ef41Sopenharmony_ci    this.remain = readEntry.size
4641cb0ef41Sopenharmony_ci    this.blockRemain = readEntry.startBlockSize
4651cb0ef41Sopenharmony_ci
4661cb0ef41Sopenharmony_ci    this.header = new Header({
4671cb0ef41Sopenharmony_ci      path: this[PREFIX](this.path),
4681cb0ef41Sopenharmony_ci      linkpath: this.type === 'Link' ? this[PREFIX](this.linkpath)
4691cb0ef41Sopenharmony_ci      : this.linkpath,
4701cb0ef41Sopenharmony_ci      // only the permissions and setuid/setgid/sticky bitflags
4711cb0ef41Sopenharmony_ci      // not the higher-order bits that specify file type
4721cb0ef41Sopenharmony_ci      mode: this.mode,
4731cb0ef41Sopenharmony_ci      uid: this.portable ? null : this.uid,
4741cb0ef41Sopenharmony_ci      gid: this.portable ? null : this.gid,
4751cb0ef41Sopenharmony_ci      size: this.size,
4761cb0ef41Sopenharmony_ci      mtime: this.noMtime ? null : this.mtime,
4771cb0ef41Sopenharmony_ci      type: this.type,
4781cb0ef41Sopenharmony_ci      uname: this.portable ? null : this.uname,
4791cb0ef41Sopenharmony_ci      atime: this.portable ? null : this.atime,
4801cb0ef41Sopenharmony_ci      ctime: this.portable ? null : this.ctime,
4811cb0ef41Sopenharmony_ci    })
4821cb0ef41Sopenharmony_ci
4831cb0ef41Sopenharmony_ci    if (pathWarn) {
4841cb0ef41Sopenharmony_ci      this.warn('TAR_ENTRY_INFO', `stripping ${pathWarn} from absolute path`, {
4851cb0ef41Sopenharmony_ci        entry: this,
4861cb0ef41Sopenharmony_ci        path: pathWarn + this.path,
4871cb0ef41Sopenharmony_ci      })
4881cb0ef41Sopenharmony_ci    }
4891cb0ef41Sopenharmony_ci
4901cb0ef41Sopenharmony_ci    if (this.header.encode() && !this.noPax) {
4911cb0ef41Sopenharmony_ci      super.write(new Pax({
4921cb0ef41Sopenharmony_ci        atime: this.portable ? null : this.atime,
4931cb0ef41Sopenharmony_ci        ctime: this.portable ? null : this.ctime,
4941cb0ef41Sopenharmony_ci        gid: this.portable ? null : this.gid,
4951cb0ef41Sopenharmony_ci        mtime: this.noMtime ? null : this.mtime,
4961cb0ef41Sopenharmony_ci        path: this[PREFIX](this.path),
4971cb0ef41Sopenharmony_ci        linkpath: this.type === 'Link' ? this[PREFIX](this.linkpath)
4981cb0ef41Sopenharmony_ci        : this.linkpath,
4991cb0ef41Sopenharmony_ci        size: this.size,
5001cb0ef41Sopenharmony_ci        uid: this.portable ? null : this.uid,
5011cb0ef41Sopenharmony_ci        uname: this.portable ? null : this.uname,
5021cb0ef41Sopenharmony_ci        dev: this.portable ? null : this.readEntry.dev,
5031cb0ef41Sopenharmony_ci        ino: this.portable ? null : this.readEntry.ino,
5041cb0ef41Sopenharmony_ci        nlink: this.portable ? null : this.readEntry.nlink,
5051cb0ef41Sopenharmony_ci      }).encode())
5061cb0ef41Sopenharmony_ci    }
5071cb0ef41Sopenharmony_ci
5081cb0ef41Sopenharmony_ci    super.write(this.header.block)
5091cb0ef41Sopenharmony_ci    readEntry.pipe(this)
5101cb0ef41Sopenharmony_ci  }
5111cb0ef41Sopenharmony_ci
5121cb0ef41Sopenharmony_ci  [PREFIX] (path) {
5131cb0ef41Sopenharmony_ci    return prefixPath(path, this.prefix)
5141cb0ef41Sopenharmony_ci  }
5151cb0ef41Sopenharmony_ci
5161cb0ef41Sopenharmony_ci  [MODE] (mode) {
5171cb0ef41Sopenharmony_ci    return modeFix(mode, this.type === 'Directory', this.portable)
5181cb0ef41Sopenharmony_ci  }
5191cb0ef41Sopenharmony_ci
5201cb0ef41Sopenharmony_ci  write (data) {
5211cb0ef41Sopenharmony_ci    const writeLen = data.length
5221cb0ef41Sopenharmony_ci    if (writeLen > this.blockRemain) {
5231cb0ef41Sopenharmony_ci      throw new Error('writing more to entry than is appropriate')
5241cb0ef41Sopenharmony_ci    }
5251cb0ef41Sopenharmony_ci    this.blockRemain -= writeLen
5261cb0ef41Sopenharmony_ci    return super.write(data)
5271cb0ef41Sopenharmony_ci  }
5281cb0ef41Sopenharmony_ci
5291cb0ef41Sopenharmony_ci  end () {
5301cb0ef41Sopenharmony_ci    if (this.blockRemain) {
5311cb0ef41Sopenharmony_ci      super.write(Buffer.alloc(this.blockRemain))
5321cb0ef41Sopenharmony_ci    }
5331cb0ef41Sopenharmony_ci    return super.end()
5341cb0ef41Sopenharmony_ci  }
5351cb0ef41Sopenharmony_ci})
5361cb0ef41Sopenharmony_ci
5371cb0ef41Sopenharmony_ciWriteEntry.Sync = WriteEntrySync
5381cb0ef41Sopenharmony_ciWriteEntry.Tar = WriteEntryTar
5391cb0ef41Sopenharmony_ci
5401cb0ef41Sopenharmony_ciconst getType = stat =>
5411cb0ef41Sopenharmony_ci  stat.isFile() ? 'File'
5421cb0ef41Sopenharmony_ci  : stat.isDirectory() ? 'Directory'
5431cb0ef41Sopenharmony_ci  : stat.isSymbolicLink() ? 'SymbolicLink'
5441cb0ef41Sopenharmony_ci  : 'Unsupported'
5451cb0ef41Sopenharmony_ci
5461cb0ef41Sopenharmony_cimodule.exports = WriteEntry
547