diff --git a/lib/path.js b/lib/path.js index 3fab7f79d746ec..56a7c4f36e35ca 100644 --- a/lib/path.js +++ b/lib/path.js @@ -35,6 +35,7 @@ function normalizeStringWin32(path, allowAboveRoot) { var lastSlash = -1; var dots = 0; var code; + var isAboveRoot = false; for (var i = 0; i <= path.length; ++i) { if (i < path.length) code = path.charCodeAt(i); @@ -46,7 +47,7 @@ function normalizeStringWin32(path, allowAboveRoot) { if (lastSlash === i - 1 || dots === 1) { // NOOP } else if (lastSlash !== i - 1 && dots === 2) { - if (res.length < 2 || + if (res.length < 2 || !isAboveRoot || res.charCodeAt(res.length - 1) !== 46/*.*/ || res.charCodeAt(res.length - 2) !== 46/*.*/) { if (res.length > 2) { @@ -63,12 +64,14 @@ function normalizeStringWin32(path, allowAboveRoot) { res = res.slice(0, j); lastSlash = i; dots = 0; + isAboveRoot = false; continue; } } else if (res.length === 2 || res.length === 1) { res = ''; lastSlash = i; dots = 0; + isAboveRoot = false; continue; } } @@ -77,12 +80,14 @@ function normalizeStringWin32(path, allowAboveRoot) { res += '\\..'; else res = '..'; + isAboveRoot = true; } } else { if (res.length > 0) res += '\\' + path.slice(lastSlash + 1, i); else res = path.slice(lastSlash + 1, i); + isAboveRoot = false; } lastSlash = i; dots = 0; @@ -101,6 +106,7 @@ function normalizeStringPosix(path, allowAboveRoot) { var lastSlash = -1; var dots = 0; var code; + var isAboveRoot = false; for (var i = 0; i <= path.length; ++i) { if (i < path.length) code = path.charCodeAt(i); @@ -112,7 +118,7 @@ function normalizeStringPosix(path, allowAboveRoot) { if (lastSlash === i - 1 || dots === 1) { // NOOP } else if (lastSlash !== i - 1 && dots === 2) { - if (res.length < 2 || + if (res.length < 2 || !isAboveRoot || res.charCodeAt(res.length - 1) !== 46/*.*/ || res.charCodeAt(res.length - 2) !== 46/*.*/) { if (res.length > 2) { @@ -129,12 +135,14 @@ function normalizeStringPosix(path, allowAboveRoot) { res = res.slice(0, j); lastSlash = i; dots = 0; + isAboveRoot = false; continue; } } else if (res.length === 2 || res.length === 1) { res = ''; lastSlash = i; dots = 0; + isAboveRoot = false; continue; } } @@ -143,12 +151,14 @@ function normalizeStringPosix(path, allowAboveRoot) { res += '/..'; else res = '..'; + isAboveRoot = true; } } else { if (res.length > 0) res += '/' + path.slice(lastSlash + 1, i); else res = path.slice(lastSlash + 1, i); + isAboveRoot = false; } lastSlash = i; dots = 0; diff --git a/test/parallel/test-path.js b/test/parallel/test-path.js index 3e4f2b43e4c21e..8b9f1600202d4c 100644 --- a/test/parallel/test-path.js +++ b/test/parallel/test-path.js @@ -432,6 +432,11 @@ assert.strictEqual(path.win32.normalize('C:..\\..\\abc\\..\\def'), 'C:..\\..\\def'); assert.strictEqual(path.win32.normalize('C:\\.'), 'C:\\'); assert.strictEqual(path.win32.normalize('file:stream'), 'file:stream'); +assert.strictEqual(path.win32.normalize('bar\\foo..\\..\\'), 'bar\\'); +assert.strictEqual(path.win32.normalize('bar\\foo..\\..'), 'bar'); +assert.strictEqual(path.win32.normalize('bar\\foo..\\..\\baz'), 'bar\\baz'); +assert.strictEqual(path.win32.normalize('bar\\foo..\\'), 'bar\\foo..\\'); +assert.strictEqual(path.win32.normalize('bar\\foo..'), 'bar\\foo..'); assert.strictEqual(path.posix.normalize('./fixtures///b/../b/c.js'), 'fixtures/b/c.js'); @@ -441,6 +446,11 @@ assert.strictEqual(path.posix.normalize('a//b//./c'), 'a/b/c'); assert.strictEqual(path.posix.normalize('a//b//.'), 'a/b'); assert.strictEqual(path.posix.normalize('/a/b/c/../../../x/y/z'), '/x/y/z'); assert.strictEqual(path.posix.normalize('///..//./foo/.//bar'), '/foo/bar'); +assert.strictEqual(path.posix.normalize('bar/foo../../'), 'bar/'); +assert.strictEqual(path.posix.normalize('bar/foo../..'), 'bar'); +assert.strictEqual(path.posix.normalize('bar/foo../../baz'), 'bar/baz'); +assert.strictEqual(path.posix.normalize('bar/foo../'), 'bar/foo../'); +assert.strictEqual(path.posix.normalize('bar/foo..'), 'bar/foo..'); // path.resolve tests