From b20cf934acfdb9894207bfa31732ad6aae00f963 Mon Sep 17 00:00:00 2001 From: James Brotchie Date: Wed, 17 Feb 2016 12:34:42 +1000 Subject: [PATCH] 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. --- headers.js | 52 +++++++++++++++++++++++++---- test/extract.js | 13 ++++++++ test/fixtures/base-256-uid-gid.tar | Bin 0 -> 10240 bytes test/fixtures/index.js | 1 + 4 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 test/fixtures/base-256-uid-gid.tar diff --git a/headers.js b/headers.js index efee8f2..d4b00dd 100644 --- a/headers.js +++ b/headers.js @@ -95,13 +95,53 @@ var encodeOct = function (val, n) { 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) { - // Older versions of tar can prefix with spaces - while (offset < val.length && val[offset] === 32) offset++ - var end = clamp(indexOf(val, 32, offset, val.length), val.length, val.length) - while (offset < end && val[offset] === 0) offset++ - if (end === offset) return 0 - return parseInt(val.slice(offset, end).toString(), 8) + // 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 + while (offset < val.length && val[offset] === 32) offset++ + var end = clamp(indexOf(val, 32, offset, val.length), val.length, val.length) + while (offset < end && val[offset] === 0) offset++ + if (end === offset) return 0 + return parseInt(val.slice(offset, end).toString(), 8) + } } var decodeStr = function (val, offset, length) { diff --git a/test/extract.js b/test/extract.js index c78c3c4..9573c8d 100644 --- a/test/extract.js +++ b/test/extract.js @@ -451,3 +451,16 @@ test('gnu long path', function (t) { 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)) +}) diff --git a/test/fixtures/base-256-uid-gid.tar b/test/fixtures/base-256-uid-gid.tar new file mode 100644 index 0000000000000000000000000000000000000000..6e3d6e3a5f4224e7e01680b54b5c7ec0d2a5dd9b GIT binary patch literal 10240 zcmeH|&5qkP5P*H^VV^?Kxsom0>rDcrKz7#!0wh6@%`IpOni|XWN}|f2q;8R-kJD%9 zwU5vj=_6!@6eVTR1$tRD2kK&r^Z(5Z)iHj{D#(vowzCI%7Wiz|>)G$<|C@jQ_=|q! z-`SsZj?Zej+02UNX0+e`#-Em;xe}e}CC`IRa?K1&u4G*UC!zN02iZV}6GmPR z#&r70d|nB2u)CbgX1-?}c2eHXhuGP%w`A5Fq(VE&agyZ=faLO|Ffqy!1y@E(ol6hXy5ka0{zJMs84eM4w$h{T`*Zu(%I89B3wrd{FyR_d z3T;M4xUQZqrS97?hAd$(S`qql$FR)J#Je}0q-#JMVwuksXlWG(J#S?RKawEVhrp); zwI@B2B~#@cwERHn4LpwCW#2>}@in$VNp!AVgVQk>X-}o0QfxD&@V%&E`?G-jj<7EH6`lN%R#^c>~KM(~W2$;|JiLCs{8;B@L?t&#;4{ zt@`wq{oRCP&({dq^v!2*TJC~3NJ3(^$v^2W4td`Ed8xOs)LcO zYOz1jjYXW6Bsw1_AKD7*m`o3C3u%7$bdf*8#D;m>W1~sWPjgB;8_Mll7GB?MpIyJ) z=1mz6UOd0rzPj0l*VoV9ZeP8N%a-C0BCwcxnt z4%p?*b+*c`YG(2M?9