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:
James Brotchie 2016-02-17 12:34:42 +10:00
parent 8e3b1749a3
commit b20cf934ac
4 changed files with 60 additions and 6 deletions

View file

@ -95,7 +95,46 @@ 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)
@ -103,6 +142,7 @@ var decodeOct = function (val, 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) {
return val.slice(offset, indexOf(val, 0, offset, offset + length)).toString() return val.slice(offset, indexOf(val, 0, offset, offset + length)).toString()

View file

@ -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

Binary file not shown.

View file

@ -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')