diff --git a/src/Symfony/Component/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php index 02a90c9969..223e116090 100644 --- a/src/Symfony/Component/Filesystem/Filesystem.php +++ b/src/Symfony/Component/Filesystem/Filesystem.php @@ -368,25 +368,28 @@ class Filesystem $startPath = str_replace('\\', '/', $startPath); } + $stripDriveLetter = function ($path) { + if (strlen($path) > 2 && ':' === $path[1] && '/' === $path[2] && ctype_alpha($path[0])) { + return substr($path, 2); + } + + return $path; + }; + + $endPath = $stripDriveLetter($endPath); + $startPath = $stripDriveLetter($startPath); + // Split the paths into arrays $startPathArr = explode('/', trim($startPath, '/')); $endPathArr = explode('/', trim($endPath, '/')); - if ('/' !== $startPath[0]) { - array_shift($startPathArr); - } - - if ('/' !== $endPath[0]) { - array_shift($endPathArr); - } - - $normalizePathArray = function ($pathSegments) { + $normalizePathArray = function ($pathSegments, $absolute) { $result = array(); foreach ($pathSegments as $segment) { - if ('..' === $segment) { + if ('..' === $segment && ($absolute || count($result))) { array_pop($result); - } else { + } elseif ('.' !== $segment) { $result[] = $segment; } } @@ -394,8 +397,8 @@ class Filesystem return $result; }; - $startPathArr = $normalizePathArray($startPathArr); - $endPathArr = $normalizePathArray($endPathArr); + $startPathArr = $normalizePathArray($startPathArr, static::isAbsolutePath($startPath)); + $endPathArr = $normalizePathArray($endPathArr, static::isAbsolutePath($endPath)); // Find for which directory the common path stops $index = 0; @@ -410,13 +413,8 @@ class Filesystem $depth = count($startPathArr) - $index; } - // When we need to traverse from the start, and we are starting from a root path, don't add '../' - if ('/' === $startPath[0] && 0 === $index && 0 === $depth) { - $traverser = ''; - } else { - // Repeated "../" for each level need to reach the common path - $traverser = str_repeat('../', $depth); - } + // Repeated "../" for each level need to reach the common path + $traverser = str_repeat('../', $depth); $endPathRemainder = implode('/', array_slice($endPathArr, $index)); diff --git a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php index a4d111c218..1228b2d8e2 100644 --- a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php +++ b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php @@ -850,6 +850,7 @@ class FilesystemTest extends FilesystemTestCase array('/var/lib/symfony/src/Symfony', '/var/lib/symfony/src/Symfony/Component/', '../'), array('var/lib/symfony/', 'var/lib/symfony/src/Symfony/Component', '../../../'), array('/usr/lib/symfony/', '/var/lib/symfony/src/Symfony/Component', '../../../../../../usr/lib/symfony/'), + array('usr/lib/symfony/', 'var/lib/symfony/src/Symfony/Component', '../../../../../../usr/lib/symfony/'), array('/var/lib/symfony/src/Symfony/', '/var/lib/symfony/', 'src/Symfony/'), array('/aa/bb', '/aa/bb', './'), array('/aa/bb', '/aa/bb/', './'), @@ -881,6 +882,17 @@ class FilesystemTest extends FilesystemTestCase array('C:/aa/bb/../../cc', 'C:/aa/../dd/..', 'cc/'), array('C:/../aa/bb/cc', 'C:/aa/dd/..', 'bb/cc/'), array('C:/../../aa/../bb/cc', 'C:/aa/dd/..', '../bb/cc/'), + array('aa/bb', 'aa/cc', '../bb/'), + array('aa/cc', 'bb/cc', '../../aa/cc/'), + array('aa/bb', 'aa/./cc', '../bb/'), + array('aa/./bb', 'aa/cc', '../bb/'), + array('aa/./bb', 'aa/./cc', '../bb/'), + array('../../', '../../', './'), + array('../aa/bb/', 'aa/bb/', '../../../aa/bb/'), + array('../../../', '../../', '../'), + array('', '', './'), + array('', 'aa/', '../'), + array('aa/', '', 'aa/'), ); if ('\\' === DIRECTORY_SEPARATOR) {