From 2d89a4edc3dd76aef0bde3a9913cdb4f9c9d3b77 Mon Sep 17 00:00:00 2001 From: isaacs Date: Wed, 10 Apr 2024 10:59:50 -0700 Subject: [PATCH] Properly handle long linkpath in PaxHeader tar-stream creates some interesting tarballs, but they are technically allowed, and should be handled properly. Fix: #312 Also, this cleans up a flaky race condition in the unpack test. --- src/parse.ts | 1 + test/extract.js | 14 ++++++++++++++ test/fixtures/long-linkname.tar | Bin 0 -> 2560 bytes test/unpack.js | 8 ++++++-- 4 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 test/fixtures/long-linkname.tar diff --git a/src/parse.ts b/src/parse.ts index d0b0781e..0147f786 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -199,6 +199,7 @@ export class Parser extends EE implements Warner { }) } else if ( !/^(Symbolic)?Link$/.test(type) && + !/^(Global)?ExtendedHeader$/.test(type) && header.linkpath ) { this.warn('TAR_ENTRY_INVALID', 'linkpath forbidden', { diff --git a/test/extract.js b/test/extract.js index 8fe8eff1..ce2afeb7 100644 --- a/test/extract.js +++ b/test/extract.js @@ -415,3 +415,17 @@ t.test('brotli', async t => { t.end() }) }) + +t.test('verify long linkname is not a problem', async t => { + // See: https://github.com/isaacs/node-tar/issues/312 + const file = path.resolve(__dirname, 'fixtures/long-linkname.tar') + t.test('sync', t => { + x({ sync: true, strict: true, file, C: t.testdir({}) }) + t.ok(fs.lstatSync(t.testdirName + '/test').isSymbolicLink()) + t.end() + }) + t.test('async', async t => { + await x({ file, C: t.testdir({}), strict: true }) + t.ok(fs.lstatSync(t.testdirName + '/test').isSymbolicLink()) + }) +}) diff --git a/test/fixtures/long-linkname.tar b/test/fixtures/long-linkname.tar new file mode 100644 index 0000000000000000000000000000000000000000..34c0ea57d17b34911ef760553c67b7428d611138 GIT binary patch literal 2560 zcmWGYtnf%pOi3+bpdBzUFfcPQQD6YlK!8pg7#NuvD;S!X8JL=yn3R(TnHw1@ zFjNH4!EvRhemSotLq!yQO8Jb!sR?2=#j;MSp#qW2Neov`QOX{nE#FF;kXf=|3_A8ANB2M2#kgR HatHtb { if (!warned) { warned = true t.equal(er, poop) - t.end() } }, }) u.end(data) + t.equal(warned, true) + t.end() }) t.test('async', t => { @@ -1838,10 +1839,13 @@ t.test('set owner', t => { if (!warned) { warned = true t.equal(er, poop) - t.end() } }, }) + u.on('finish', () => { + t.equal(warned, true) + t.end() + }) u.end(data) })