Skip to content

Commit efc6bb0

Browse files
committed
fix: strip absolute paths more comprehensively
1 parent 65edb39 commit efc6bb0

5 files changed

+55
-20
lines changed

lib/strip-absolute-path.js

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// unix absolute paths are also absolute on win32, so we use this for both
2+
const { isAbsolute, parse } = require('path').win32
3+
4+
// returns [root, stripped]
5+
module.exports = path => {
6+
let r = ''
7+
while (isAbsolute(path)) {
8+
// windows will think that //x/y/z has a "root" of //x/y/
9+
const root = path.charAt(0) === '/' ? '/' : parse(path).root
10+
path = path.substr(root.length)
11+
r += root
12+
}
13+
return [r, path]
14+
}

lib/unpack.js

+5-4
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ const path = require('path')
99
const mkdir = require('./mkdir.js')
1010
const mkdirSync = mkdir.sync
1111
const wc = require('./winchars.js')
12+
const stripAbsolutePath = require('./strip-absolute-path.js')
1213

1314
const ONENTRY = Symbol('onEntry')
1415
const CHECKFS = Symbol('checkFs')
@@ -195,10 +196,10 @@ class Unpack extends Parser {
195196

196197
// absolutes on posix are also absolutes on win32
197198
// so we only need to test this one to get both
198-
if (path.win32.isAbsolute(p)) {
199-
const parsed = path.win32.parse(p)
200-
this.warn('stripping ' + parsed.root + ' from absolute path', p)
201-
entry.path = p.substr(parsed.root.length)
199+
const s = stripAbsolutePath(p)
200+
if (s[0]) {
201+
entry.path = s[1]
202+
this.warn(`stripping ${s[0]} from absolute path`, p)
202203
}
203204
}
204205

lib/write-entry.js

+16-13
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ const CLOSE = Symbol('close')
2626
const MODE = Symbol('mode')
2727
const warner = require('./warn-mixin.js')
2828
const winchars = require('./winchars.js')
29+
const stripAbsolutePath = require('./strip-absolute-path.js')
2930

3031
const modeFix = require('./mode-fix.js')
3132

@@ -54,12 +55,12 @@ const WriteEntry = warner(class WriteEntry extends MiniPass {
5455
if (typeof opt.onwarn === 'function')
5556
this.on('warn', opt.onwarn)
5657

57-
if (!this.preservePaths && path.win32.isAbsolute(p)) {
58-
// absolutes on posix are also absolutes on win32
59-
// so we only need to test this one to get both
60-
const parsed = path.win32.parse(p)
61-
this.warn('stripping ' + parsed.root + ' from absolute path', p)
62-
this.path = p.substr(parsed.root.length)
58+
if (!this.preservePaths) {
59+
const s = stripAbsolutePath(this.path)
60+
if (s[0]) {
61+
this.path = s[1]
62+
this.warn('stripping ' + s[0] + ' from absolute path', p)
63+
}
6364
}
6465

6566
this.win32 = !!opt.win32 || process.platform === 'win32'
@@ -343,13 +344,15 @@ const WriteEntryTar = warner(class WriteEntryTar extends MiniPass {
343344
if (typeof opt.onwarn === 'function')
344345
this.on('warn', opt.onwarn)
345346

346-
if (path.isAbsolute(this.path) && !this.preservePaths) {
347-
const parsed = path.parse(this.path)
348-
this.warn(
349-
'stripping ' + parsed.root + ' from absolute path',
350-
this.path
351-
)
352-
this.path = this.path.substr(parsed.root.length)
347+
if (!this.preservePaths) {
348+
const s = stripAbsolutePath(this.path)
349+
if (s[0]) {
350+
this.warn(
351+
'stripping ' + s[0] + ' from absolute path',
352+
this.path
353+
)
354+
this.path = s[1]
355+
}
353356
}
354357

355358
this.remain = readEntry.size

test/strip-absolute-path.js

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
const t = require('tap')
2+
const stripAbsolutePath = require('../lib/strip-absolute-path.js')
3+
4+
const cases = {
5+
'/': ['/', ''],
6+
'////': ['////', ''],
7+
'c:///a/b/c': ['c:///', 'a/b/c'],
8+
'\\\\foo\\bar\\baz': ['\\\\foo\\bar\\', 'baz'],
9+
'//foo//bar//baz': ['//', 'foo//bar//baz'],
10+
'c:\\c:\\c:\\c:\\\\d:\\e/f/g': ['c:\\c:\\c:\\c:\\\\d:\\', 'e/f/g'],
11+
}
12+
13+
for (const [input, [root, stripped]] of Object.entries(cases))
14+
t.strictSame(stripAbsolutePath(input), [root, stripped], input)

test/write-entry.js

+6-3
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,10 @@ t.test('nonexistent file', t => {
362362
})
363363

364364
t.test('absolute path', t => {
365-
const f = path.resolve(files, '512-bytes.txt')
365+
const absolute = path.resolve(files, '512-bytes.txt')
366+
const { root } = path.parse(absolute)
367+
const f = root + root + root + absolute
368+
const warn = root + root + root + root
366369
t.test('preservePaths=false strict=false', t => {
367370
const warnings = []
368371
const ws = new WriteEntry(f, {
@@ -375,13 +378,13 @@ t.test('absolute path', t => {
375378
out = Buffer.concat(out)
376379
t.equal(out.length, 1024)
377380
t.match(warnings, [[
378-
/stripping .* from absolute path/, f
381+
'stripping ' + warn + ' from absolute path', f
379382
]])
380383

381384
t.match(ws.header, {
382385
cksumValid: true,
383386
needPax: false,
384-
path: f.replace(/^(\/|[a-z]:\\\\)/, ''),
387+
path: f.replace(/^(\/|[a-z]:\\\\){4}/, ''),
385388
mode: 0o644,
386389
size: 512,
387390
linkpath: null,

0 commit comments

Comments
 (0)