Skip to content

Commit 147e078

Browse files
committedJul 23, 2021
fix: strip absolute paths more comprehensively
1 parent 1dea1df commit 147e078

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
@@ -8,6 +8,7 @@ const path = require('path')
88
const mkdir = require('./mkdir.js')
99
const mkdirSync = mkdir.sync
1010
const wc = require('./winchars.js')
11+
const stripAbsolutePath = require('./strip-absolute-path.js')
1112

1213
const ONENTRY = Symbol('onEntry')
1314
const CHECKFS = Symbol('checkFs')
@@ -136,10 +137,10 @@ class Unpack extends Parser {
136137

137138
// absolutes on posix are also absolutes on win32
138139
// so we only need to test this one to get both
139-
if (path.win32.isAbsolute(p)) {
140-
const parsed = path.win32.parse(p)
141-
this.warn('stripping ' + parsed.root + ' from absolute path', p)
142-
entry.path = p.substr(parsed.root.length)
140+
const s = stripAbsolutePath(p)
141+
if (s[0]) {
142+
entry.path = s[1]
143+
this.warn(`stripping ${s[0]} from absolute path`, p)
143144
}
144145
}
145146

‎lib/write-entry.js

+16-13
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const ONOPENFILE = Symbol('onopenfile')
2424
const CLOSE = Symbol('close')
2525
const warner = require('./warn-mixin.js')
2626
const winchars = require('./winchars.js')
27+
const stripAbsolutePath = require('./strip-absolute-path.js')
2728

2829
const WriteEntry = warner(class WriteEntry extends MiniPass {
2930
constructor (p, opt) {
@@ -47,12 +48,12 @@ const WriteEntry = warner(class WriteEntry extends MiniPass {
4748
if (typeof opt.onwarn === 'function')
4849
this.on('warn', opt.onwarn)
4950

50-
if (!this.preservePaths && path.win32.isAbsolute(p)) {
51-
// absolutes on posix are also absolutes on win32
52-
// so we only need to test this one to get both
53-
const parsed = path.win32.parse(p)
54-
this.warn('stripping ' + parsed.root + ' from absolute path', p)
55-
this.path = p.substr(parsed.root.length)
51+
if (!this.preservePaths) {
52+
const s = stripAbsolutePath(this.path)
53+
if (s[0]) {
54+
this.path = s[1]
55+
this.warn('stripping ' + s[0] + ' from absolute path', p)
56+
}
5657
}
5758

5859
this.win32 = !!opt.win32 || process.platform === 'win32'
@@ -320,13 +321,15 @@ const WriteEntryTar = warner(class WriteEntryTar extends MiniPass {
320321
if (typeof opt.onwarn === 'function')
321322
this.on('warn', opt.onwarn)
322323

323-
if (path.isAbsolute(this.path) && !this.preservePaths) {
324-
const parsed = path.parse(this.path)
325-
this.warn(
326-
'stripping ' + parsed.root + ' from absolute path',
327-
this.path
328-
)
329-
this.path = this.path.substr(parsed.root.length)
324+
if (!this.preservePaths) {
325+
const s = stripAbsolutePath(this.path)
326+
if (s[0]) {
327+
this.warn(
328+
'stripping ' + s[0] + ' from absolute path',
329+
this.path
330+
)
331+
this.path = s[1]
332+
}
330333
}
331334

332335
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)
Please sign in to comment.