diff --git a/lib/unpack.js b/lib/unpack.js index edaf7833..6433bcb3 100644 --- a/lib/unpack.js +++ b/lib/unpack.js @@ -205,6 +205,8 @@ class Unpack extends Parser { if (parts.length < this.strip) return false entry.path = parts.slice(this.strip).join('/') + if (entry.path === '' && entry.type !== 'Directory' && entry.type !== 'GNUDumpDir') + return false if (entry.type === 'Link') { const linkparts = entry.linkpath.split(/\/|\\/) diff --git a/test/unpack.js b/test/unpack.js index db7c8f54..990f9242 100644 --- a/test/unpack.js +++ b/test/unpack.js @@ -2658,3 +2658,46 @@ t.test('drop entry from dirCache if no longer a directory', t => { check(t, path) }) }) + +t.test('using strip option when top level file exists', t => { + const dir = path.resolve(unpackdir, 'strip-with-top-file') + mkdirp.sync(dir + '/sync/y') + mkdirp.sync(dir + '/async/y') + const data = makeTar([ + { + path: 'top', + type: 'File', + size: 0, + }, + { + path: 'x', + type: 'Directory', + }, + { + path: 'x/a', + type: 'File', + size: 'a'.length, + }, + 'a', + '', + '', + ]) + t.plan(2) + const check = (t, path) => { + t.equal(fs.statSync(path).isDirectory(), true) + t.equal(fs.lstatSync(path + '/a').isFile(), true) + t.throws(() => fs.statSync(path + '/top'), { code: 'ENOENT' }) + t.end() + } + t.test('async', t => { + const path = dir + '/async' + new Unpack({ cwd: path, strip: 1 }) + .on('end', () => check(t, path)) + .end(data) + }) + t.test('sync', t => { + const path = dir + '/sync' + new UnpackSync({ cwd: path, strip: 1 }).end(data) + check(t, path) + }) +})