Skip to content

Commit 1f036ca

Browse files
committed
fix: strip absolute paths more comprehensively
1 parent 1b94260 commit 1f036ca

6 files changed

+57
-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-5
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const path = require('path')
1414
const mkdir = require('./mkdir.js')
1515
const wc = require('./winchars.js')
1616
const pathReservations = require('./path-reservations.js')
17+
const stripAbsolutePath = require('./strip-absolute-path.js')
1718

1819
const ONENTRY = Symbol('onEntry')
1920
const CHECKFS = Symbol('checkFs')
@@ -224,11 +225,10 @@ class Unpack extends Parser {
224225

225226
// absolutes on posix are also absolutes on win32
226227
// so we only need to test this one to get both
227-
if (path.win32.isAbsolute(p)) {
228-
const parsed = path.win32.parse(p)
229-
entry.path = p.substr(parsed.root.length)
230-
const r = parsed.root
231-
this.warn('TAR_ENTRY_INFO', `stripping ${r} from absolute path`, {
228+
const [root, stripped] = stripAbsolutePath(p)
229+
if (root) {
230+
entry.path = stripped
231+
this.warn('TAR_ENTRY_INFO', `stripping ${root} from absolute path`, {
232232
entry,
233233
path: p,
234234
})

lib/write-entry.js

+13-10
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ const CLOSE = Symbol('close')
2323
const MODE = Symbol('mode')
2424
const warner = require('./warn-mixin.js')
2525
const winchars = require('./winchars.js')
26+
const stripAbsolutePath = require('./strip-absolute-path.js')
2627

2728
const modeFix = require('./mode-fix.js')
2829

@@ -52,12 +53,12 @@ const WriteEntry = warner(class WriteEntry extends MiniPass {
5253
this.on('warn', opt.onwarn)
5354

5455
let pathWarn = false
55-
if (!this.preservePaths && path.win32.isAbsolute(p)) {
56-
// absolutes on posix are also absolutes on win32
57-
// so we only need to test this one to get both
58-
const parsed = path.win32.parse(p)
59-
this.path = p.substr(parsed.root.length)
60-
pathWarn = parsed.root
56+
if (!this.preservePaths) {
57+
const [root, stripped] = stripAbsolutePath(this.path)
58+
if (root) {
59+
this.path = stripped
60+
pathWarn = root
61+
}
6162
}
6263

6364
this.win32 = !!opt.win32 || process.platform === 'win32'
@@ -351,10 +352,12 @@ const WriteEntryTar = warner(class WriteEntryTar extends MiniPass {
351352
this.on('warn', opt.onwarn)
352353

353354
let pathWarn = false
354-
if (path.isAbsolute(this.path) && !this.preservePaths) {
355-
const parsed = path.parse(this.path)
356-
pathWarn = parsed.root
357-
this.path = this.path.substr(parsed.root.length)
355+
if (!this.preservePaths) {
356+
const [root, stripped] = stripAbsolutePath(this.path)
357+
if (root) {
358+
this.path = stripped
359+
pathWarn = root
360+
}
358361
}
359362

360363
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/unpack.js

+5-2
Original file line numberDiff line numberDiff line change
@@ -776,14 +776,17 @@ t.test('absolute paths', t => {
776776
})
777777

778778
const absolute = path.resolve(dir, 'd/i/r/absolute')
779+
const root = path.parse(absolute).root
780+
const extraAbsolute = root + root + root + absolute
781+
t.ok(path.isAbsolute(extraAbsolute))
779782
t.ok(path.isAbsolute(absolute))
780783
const parsed = path.parse(absolute)
781784
const relative = absolute.substr(parsed.root.length)
782785
t.notOk(path.isAbsolute(relative))
783786

784787
const data = makeTar([
785788
{
786-
path: absolute,
789+
path: extraAbsolute,
787790
type: 'File',
788791
size: 1,
789792
atime: new Date('1979-07-01T19:10:00.000Z'),
@@ -798,7 +801,7 @@ t.test('absolute paths', t => {
798801
t.test('warn and correct', t => {
799802
const check = t => {
800803
t.match(warnings, [[
801-
'stripping / from absolute path',
804+
`stripping ${root}${root}${root}${root} from absolute path`,
802805
{ path: absolute, code: 'TAR_ENTRY_INFO' },
803806
]])
804807
t.ok(fs.lstatSync(path.resolve(dir, relative)).isFile(), 'is file')

test/write-entry.js

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

387387
t.test('absolute path', t => {
388-
const f = path.resolve(files, '512-bytes.txt')
388+
const absolute = path.resolve(files, '512-bytes.txt')
389+
const { root } = path.parse(absolute)
390+
const f = root + root + root + absolute
391+
const warn = root + root + root + root
389392
t.test('preservePaths=false strict=false', t => {
390393
const warnings = []
391394
const ws = new WriteEntry(f, {
@@ -398,13 +401,13 @@ t.test('absolute path', t => {
398401
out = Buffer.concat(out)
399402
t.equal(out.length, 1024)
400403
t.match(warnings, [[
401-
'TAR_ENTRY_INFO', /stripping .* from absolute path/, { path: f },
404+
'TAR_ENTRY_INFO', `stripping ${warn} from absolute path`, { path: f },
402405
]])
403406

404407
t.match(ws.header, {
405408
cksumValid: true,
406409
needPax: false,
407-
path: f.replace(/^(\/|[a-z]:\\\\)/, ''),
410+
path: f.replace(/^(\/|[a-z]:\\\\){4}/, ''),
408411
mode: 0o644,
409412
size: 512,
410413
linkpath: null,

0 commit comments

Comments
 (0)