Correctly parse large base-256 values in tar header.
In the tar header, large integers are stored in a two's-complement base-256 notation. Add support to tar-stream for parsing this format, fixing the bug of reading gid and uid as NaN values.
This commit is contained in:
parent
8e3b1749a3
commit
b20cf934ac
4 changed files with 60 additions and 6 deletions
40
headers.js
40
headers.js
|
@ -95,13 +95,53 @@ var encodeOct = function (val, n) {
|
||||||
return ZEROS.slice(0, n - val.length) + val + ' '
|
return ZEROS.slice(0, n - val.length) + val + ' '
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Copied from the node-tar repo and modified to meet
|
||||||
|
* tar-stream coding standard.
|
||||||
|
*
|
||||||
|
* Source: https://github.com/npm/node-tar/blob/51b6627a1f357d2eb433e7378e5f05e83b7aa6cd/lib/header.js#L349
|
||||||
|
*/
|
||||||
|
function parse256 (buf) {
|
||||||
|
// first byte MUST be either 80 or FF
|
||||||
|
// 80 for positive, FF for 2's comp
|
||||||
|
var positive
|
||||||
|
if (buf[0] === 0x80) positive = true
|
||||||
|
else if (buf[0] === 0xFF) positive = false
|
||||||
|
else return null
|
||||||
|
|
||||||
|
// build up a base-256 tuple from the least sig to the highest
|
||||||
|
var zero = false
|
||||||
|
var tuple = []
|
||||||
|
for (var i = buf.length - 1; i > 0; i--) {
|
||||||
|
var byte = buf[i]
|
||||||
|
if (positive) tuple.push(byte)
|
||||||
|
else if (zero && byte === 0) tuple.push(0)
|
||||||
|
else if (zero) {
|
||||||
|
zero = false
|
||||||
|
tuple.push(0x100 - byte)
|
||||||
|
} else tuple.push(0xFF - byte)
|
||||||
|
}
|
||||||
|
|
||||||
|
var sum = 0
|
||||||
|
var l = tuple.length
|
||||||
|
for (i = 0; i < l; i++) {
|
||||||
|
sum += tuple[i] * Math.pow(256, i)
|
||||||
|
}
|
||||||
|
|
||||||
|
return positive ? sum : -1 * sum
|
||||||
|
}
|
||||||
|
|
||||||
var decodeOct = function (val, offset) {
|
var decodeOct = function (val, offset) {
|
||||||
|
// If prefixed with 0x80 then parse as a base-256 integer
|
||||||
|
if (val[offset] & 0x80) {
|
||||||
|
return parse256(val.slice(offset, offset + 8))
|
||||||
|
} else {
|
||||||
// Older versions of tar can prefix with spaces
|
// Older versions of tar can prefix with spaces
|
||||||
while (offset < val.length && val[offset] === 32) offset++
|
while (offset < val.length && val[offset] === 32) offset++
|
||||||
var end = clamp(indexOf(val, 32, offset, val.length), val.length, val.length)
|
var end = clamp(indexOf(val, 32, offset, val.length), val.length, val.length)
|
||||||
while (offset < end && val[offset] === 0) offset++
|
while (offset < end && val[offset] === 0) offset++
|
||||||
if (end === offset) return 0
|
if (end === offset) return 0
|
||||||
return parseInt(val.slice(offset, end).toString(), 8)
|
return parseInt(val.slice(offset, end).toString(), 8)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var decodeStr = function (val, offset, length) {
|
var decodeStr = function (val, offset, length) {
|
||||||
|
|
|
@ -451,3 +451,16 @@ test('gnu long path', function (t) {
|
||||||
|
|
||||||
extract.end(fs.readFileSync(fixtures.GNU_LONG_PATH))
|
extract.end(fs.readFileSync(fixtures.GNU_LONG_PATH))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('base 256 uid and gid', function (t) {
|
||||||
|
t.plan(2)
|
||||||
|
var extract = tar.extract()
|
||||||
|
|
||||||
|
extract.on('entry', function (header, stream, callback) {
|
||||||
|
t.ok(header.uid === 116435139)
|
||||||
|
t.ok(header.gid === 1876110778)
|
||||||
|
callback()
|
||||||
|
})
|
||||||
|
|
||||||
|
extract.end(fs.readFileSync(fixtures.BASE_256_UID_GID))
|
||||||
|
})
|
||||||
|
|
BIN
test/fixtures/base-256-uid-gid.tar
vendored
Normal file
BIN
test/fixtures/base-256-uid-gid.tar
vendored
Normal file
Binary file not shown.
1
test/fixtures/index.js
vendored
1
test/fixtures/index.js
vendored
|
@ -10,3 +10,4 @@ exports.NAME_IS_100_TAR = path.join(__dirname, 'name-is-100.tar')
|
||||||
exports.INVALID_TGZ = path.join(__dirname, 'invalid.tgz')
|
exports.INVALID_TGZ = path.join(__dirname, 'invalid.tgz')
|
||||||
exports.SPACE_TAR_GZ = path.join(__dirname, 'space.tar')
|
exports.SPACE_TAR_GZ = path.join(__dirname, 'space.tar')
|
||||||
exports.GNU_LONG_PATH = path.join(__dirname, 'gnu-long-path.tar')
|
exports.GNU_LONG_PATH = path.join(__dirname, 'gnu-long-path.tar')
|
||||||
|
exports.BASE_256_UID_GID = path.join(__dirname, 'base-256-uid-gid.tar')
|
||||||
|
|
Loading…
Reference in a new issue