Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nodejs/node.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'deps/npm/node_modules/tar/lib/write-entry.js')
-rw-r--r--deps/npm/node_modules/tar/lib/write-entry.js203
1 files changed, 145 insertions, 58 deletions
diff --git a/deps/npm/node_modules/tar/lib/write-entry.js b/deps/npm/node_modules/tar/lib/write-entry.js
index 0301759ad38..3702f2ae519 100644
--- a/deps/npm/node_modules/tar/lib/write-entry.js
+++ b/deps/npm/node_modules/tar/lib/write-entry.js
@@ -4,6 +4,15 @@ 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')
@@ -21,6 +30,10 @@ 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')
@@ -33,21 +46,31 @@ const WriteEntry = warner(class WriteEntry extends MiniPass {
super(opt)
if (typeof p !== 'string')
throw new TypeError('path is required')
- this.path = p
+ 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()
+ 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 = opt.cwd || process.cwd()
+ 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)
@@ -63,11 +86,13 @@ const WriteEntry = warner(class WriteEntry extends MiniPass {
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 = opt.absolute || path.resolve(this.cwd, p)
+ this.absolute = normPath(opt.absolute || path.resolve(this.cwd, p))
if (this.path === '')
this.path = './'
@@ -85,6 +110,12 @@ const WriteEntry = warner(class WriteEntry extends MiniPass {
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)
@@ -117,13 +148,19 @@ const WriteEntry = warner(class WriteEntry extends MiniPass {
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.path,
- linkpath: this.linkpath,
+ 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),
@@ -139,13 +176,14 @@ const WriteEntry = warner(class WriteEntry extends MiniPass {
})
if (this.header.encode() && !this.noPax) {
- this.write(new Pax({
+ 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.path,
- linkpath: this.linkpath,
+ 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,
@@ -154,7 +192,7 @@ const WriteEntry = warner(class WriteEntry extends MiniPass {
nlink: this.portable ? null : this.stat.nlink,
}).encode())
}
- this.write(this.header.block)
+ super.write(this.header.block)
}
[DIRECTORY] () {
@@ -174,14 +212,14 @@ const WriteEntry = warner(class WriteEntry extends MiniPass {
}
[ONREADLINK] (linkpath) {
- this.linkpath = linkpath.replace(/\\/g, '/')
+ this.linkpath = normPath(linkpath)
this[HEADER]()
this.end()
}
[HARDLINK] (linkpath) {
this.type = 'Link'
- this.linkpath = path.relative(this.cwd, linkpath).replace(/\\/g, '/')
+ this.linkpath = normPath(path.relative(this.cwd, linkpath))
this.stat.size = 0
this[HEADER]()
this.end()
@@ -214,74 +252,110 @@ const WriteEntry = warner(class WriteEntry extends MiniPass {
}
[ONOPENFILE] (fd) {
- const blockLen = 512 * Math.ceil(this.stat.size / 512)
- const bufLen = Math.min(blockLen, this.maxReadSize)
- const buf = Buffer.allocUnsafe(bufLen)
- this[READ](fd, buf, 0, buf.length, 0, this.stat.size, blockLen)
+ 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] (fd, buf, offset, length, pos, remain, blockRemain) {
+ [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](fd, () => this.emit('error', er))
+ return this[CLOSE](() => this.emit('error', er))
}
- this[ONREAD](fd, buf, offset, length, pos, remain, blockRemain, bytesRead)
+ this[ONREAD](bytesRead)
})
}
- [CLOSE] (fd, cb) {
- fs.close(fd, cb)
+ [CLOSE] (cb) {
+ fs.close(this.fd, cb)
}
- [ONREAD] (fd, buf, offset, length, pos, remain, blockRemain, bytesRead) {
- if (bytesRead <= 0 && remain > 0) {
+ [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](fd, () => this.emit('error', er))
+ return this[CLOSE](() => this.emit('error', er))
}
- if (bytesRead > remain) {
+ 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](fd, () => this.emit('error', er))
+ return this[CLOSE](() => this.emit('error', er))
}
// null out the rest of the buffer, if we could fit the block padding
- if (bytesRead === remain) {
- for (let i = bytesRead; i < length && bytesRead < blockRemain; i++) {
- buf[i + offset] = 0
+ // 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++
- remain++
+ this.remain++
}
}
- const writeBuf = offset === 0 && bytesRead === buf.length ?
- buf : buf.slice(offset, offset + bytesRead)
- remain -= bytesRead
- blockRemain -= bytesRead
- pos += bytesRead
- offset += bytesRead
+ 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)
+ }
- this.write(writeBuf)
+ 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)
+ }
- if (!remain) {
- if (blockRemain)
- this.write(Buffer.alloc(blockRemain))
- return this[CLOSE](fd, er => er ? this.emit('error', er) : this.end())
+ [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 (offset >= length) {
- buf = Buffer.allocUnsafe(length)
- offset = 0
+ 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
}
- length = buf.length - offset
- this[READ](fd, buf, offset, length, pos, remain, blockRemain)
+ this.length = this.buf.length - this.offset
+ this[READ]()
}
})
@@ -298,25 +372,30 @@ class WriteEntrySync extends WriteEntry {
this[ONOPENFILE](fs.openSync(this.absolute, 'r'))
}
- [READ] (fd, buf, offset, length, pos, remain, blockRemain) {
+ [READ] () {
let threw = true
try {
+ const { fd, buf, offset, length, pos } = this
const bytesRead = fs.readSync(fd, buf, offset, length, pos)
- this[ONREAD](fd, buf, offset, length, pos, remain, blockRemain, bytesRead)
+ 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](fd, () => {})
+ this[CLOSE](() => {})
} catch (er) {}
}
}
}
- [CLOSE] (fd, cb) {
- fs.closeSync(fd)
+ [AWAITDRAIN] (cb) {
+ cb()
+ }
+
+ [CLOSE] (cb) {
+ fs.closeSync(this.fd)
cb()
}
}
@@ -336,7 +415,9 @@ const WriteEntryTar = warner(class WriteEntryTar extends MiniPass {
if (this.type === 'Directory' && this.portable)
this.noMtime = true
- this.path = readEntry.path
+ 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
@@ -346,7 +427,7 @@ const WriteEntryTar = warner(class WriteEntryTar extends MiniPass {
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 = readEntry.linkpath
+ this.linkpath = normPath(readEntry.linkpath)
if (typeof opt.onwarn === 'function')
this.on('warn', opt.onwarn)
@@ -364,8 +445,9 @@ const WriteEntryTar = warner(class WriteEntryTar extends MiniPass {
this.blockRemain = readEntry.startBlockSize
this.header = new Header({
- path: this.path,
- linkpath: this.linkpath,
+ 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,
@@ -392,8 +474,9 @@ const WriteEntryTar = warner(class WriteEntryTar extends MiniPass {
ctime: this.portable ? null : this.ctime,
gid: this.portable ? null : this.gid,
mtime: this.noMtime ? null : this.mtime,
- path: this.path,
- linkpath: this.linkpath,
+ 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,
@@ -407,6 +490,10 @@ const WriteEntryTar = warner(class WriteEntryTar extends MiniPass {
readEntry.pipe(this)
}
+ [PREFIX] (path) {
+ return prefixPath(path, this.prefix)
+ }
+
[MODE] (mode) {
return modeFix(mode, this.type === 'Directory', this.portable)
}
@@ -421,7 +508,7 @@ const WriteEntryTar = warner(class WriteEntryTar extends MiniPass {
end () {
if (this.blockRemain)
- this.write(Buffer.alloc(this.blockRemain))
+ super.write(Buffer.alloc(this.blockRemain))
return super.end()
}
})