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