diff --git a/src/Composer/Util/Filesystem.php b/src/Composer/Util/Filesystem.php index 110aeb847..6e80dce2a 100644 --- a/src/Composer/Util/Filesystem.php +++ b/src/Composer/Util/Filesystem.php @@ -318,10 +318,12 @@ class Filesystem $path = substr($path, strlen($prefix)); } + $appended = false; foreach (explode('/', $path) as $chunk) { - if ('..' === $chunk) { + if ('..' === $chunk && $appended) { array_pop($parts); } elseif ('.' !== $chunk && '' !== $chunk) { + $appended = true; $parts[] = $chunk; } } diff --git a/tests/Composer/Test/Util/FilesystemTest.php b/tests/Composer/Test/Util/FilesystemTest.php index 479fad56d..65fa83fe2 100644 --- a/tests/Composer/Test/Util/FilesystemTest.php +++ b/tests/Composer/Test/Util/FilesystemTest.php @@ -139,4 +139,27 @@ class FilesystemTest extends TestCase $fs = new Filesystem; $this->assertGreaterThanOrEqual(10, $fs->size("$tmp/composer_testdir")); } + + /** + * @dataProvider provideNormalizedPaths + */ + public function testNormalizePath($expected, $actual) + { + $fs = new Filesystem; + $this->assertEquals($expected, $fs->normalizePath($actual)); + } + + public function provideNormalizedPaths() + { + return array( + array('../foo', '../foo'), + array('c:/foo/bar', 'c:/foo//bar'), + array('C:/foo/bar', 'C:/foo/./bar'), + array('C:/bar', 'C:/foo/../bar'), + array('/bar', '/foo/../bar/'), + array('phar://c:/Foo', 'phar://c:/Foo/Bar/..'), + array('phar://c:/', 'phar://c:/Foo/Bar/../../../..'), + array('/', '/Foo/Bar/../../../..'), + ); + } }