diff --git a/apps/files/ajax/list.php b/apps/files/ajax/list.php index 350fc7fa5f6..0be38c3b96f 100644 --- a/apps/files/ajax/list.php +++ b/apps/files/ajax/list.php @@ -10,7 +10,7 @@ OCP\JSON::checkLoggedIn(); // Load the files $dir = isset( $_GET['dir'] ) ? $_GET['dir'] : ''; - +$dir = \OC\Files\Filesystem::normalizePath($dir); if (!\OC\Files\Filesystem::is_dir($dir . '/')) { header("HTTP/1.0 404 Not Found"); exit(); diff --git a/apps/files/index.php b/apps/files/index.php index f0f95b3bac8..9ae378d7a1d 100644 --- a/apps/files/index.php +++ b/apps/files/index.php @@ -36,6 +36,7 @@ OCP\Util::addscript('files', 'filelist'); OCP\App::setActiveNavigationEntry('files_index'); // Load the files $dir = isset($_GET['dir']) ? stripslashes($_GET['dir']) : ''; +$dir = \OC\Files\Filesystem::normalizePath($dir); // Redirect if directory does not exist if (!\OC\Files\Filesystem::is_dir($dir . '/')) { header('Location: ' . OCP\Util::getScriptName() . ''); @@ -128,7 +129,7 @@ if ($needUpgrade) { $tmpl = new OCP\Template('files', 'index', 'user'); $tmpl->assign('fileList', $list->fetchPage()); $tmpl->assign('breadcrumb', $breadcrumbNav->fetchPage()); - $tmpl->assign('dir', \OC\Files\Filesystem::normalizePath($dir)); + $tmpl->assign('dir', $dir); $tmpl->assign('isCreatable', $isCreatable); $tmpl->assign('permissions', $permissions); $tmpl->assign('files', $files); diff --git a/lib/private/files/filesystem.php b/lib/private/files/filesystem.php index 899666f3e1a..8500b3c581b 100644 --- a/lib/private/files/filesystem.php +++ b/lib/private/files/filesystem.php @@ -689,18 +689,32 @@ class Filesystem { } //no windows style slashes $path = str_replace('\\', '/', $path); + //add leading slash if ($path[0] !== '/') { $path = '/' . $path; } - //remove duplicate slashes - while (strpos($path, '//') !== false) { - $path = str_replace('//', '/', $path); + + // remove '/./' + // ugly, but str_replace() can't replace them all in one go + // as the replacement itself is part of the search string + // which will only be found during the next iteration + while (strpos($path, '/./') !== false) { + $path = str_replace('/./', '/', $path); } + // remove sequences of slashes + $path = preg_replace('#/{2,}#', '/', $path); + //remove trailing slash if ($stripTrailingSlash and strlen($path) > 1 and substr($path, -1, 1) === '/') { $path = substr($path, 0, -1); } + + // remove trailing '/.' + if (substr($path, -2) == '/.') { + $path = substr($path, 0, -2); + } + //normalize unicode if possible $path = \OC_Util::normalizeUnicode($path); diff --git a/tests/lib/files/filesystem.php b/tests/lib/files/filesystem.php index 990e95ca595..7cb57bf95ad 100644 --- a/tests/lib/files/filesystem.php +++ b/tests/lib/files/filesystem.php @@ -69,17 +69,72 @@ class Filesystem extends \PHPUnit_Framework_TestCase { } public function testNormalize() { + $this->assertEquals('/', \OC\Files\Filesystem::normalizePath('')); + $this->assertEquals('/', \OC\Files\Filesystem::normalizePath('/')); + $this->assertEquals('/', \OC\Files\Filesystem::normalizePath('/', false)); + $this->assertEquals('/', \OC\Files\Filesystem::normalizePath('//')); + $this->assertEquals('/', \OC\Files\Filesystem::normalizePath('//', false)); $this->assertEquals('/path', \OC\Files\Filesystem::normalizePath('/path/')); $this->assertEquals('/path/', \OC\Files\Filesystem::normalizePath('/path/', false)); $this->assertEquals('/path', \OC\Files\Filesystem::normalizePath('path')); - $this->assertEquals('/path', \OC\Files\Filesystem::normalizePath('\path')); $this->assertEquals('/foo/bar', \OC\Files\Filesystem::normalizePath('/foo//bar/')); + $this->assertEquals('/foo/bar/', \OC\Files\Filesystem::normalizePath('/foo//bar/', false)); $this->assertEquals('/foo/bar', \OC\Files\Filesystem::normalizePath('/foo////bar')); + $this->assertEquals('/foo/bar', \OC\Files\Filesystem::normalizePath('/foo/////bar')); + $this->assertEquals('/foo/bar', \OC\Files\Filesystem::normalizePath('/foo/bar/.')); + $this->assertEquals('/foo/bar', \OC\Files\Filesystem::normalizePath('/foo/bar/./')); + $this->assertEquals('/foo/bar/', \OC\Files\Filesystem::normalizePath('/foo/bar/./', false)); + $this->assertEquals('/foo/bar', \OC\Files\Filesystem::normalizePath('/foo/bar/./.')); + $this->assertEquals('/foo/bar', \OC\Files\Filesystem::normalizePath('/foo/bar/././')); + $this->assertEquals('/foo/bar/', \OC\Files\Filesystem::normalizePath('/foo/bar/././', false)); + $this->assertEquals('/foo/bar', \OC\Files\Filesystem::normalizePath('/foo/./bar/')); + $this->assertEquals('/foo/bar/', \OC\Files\Filesystem::normalizePath('/foo/./bar/', false)); + $this->assertEquals('/foo/.bar', \OC\Files\Filesystem::normalizePath('/foo/.bar/')); + $this->assertEquals('/foo/.bar/', \OC\Files\Filesystem::normalizePath('/foo/.bar/', false)); + $this->assertEquals('/foo/.bar/tee', \OC\Files\Filesystem::normalizePath('/foo/.bar/tee')); + + // normalize does not resolve '..' (by design) + $this->assertEquals('/foo/..', \OC\Files\Filesystem::normalizePath('/foo/../')); + if (class_exists('Patchwork\PHP\Shim\Normalizer')) { $this->assertEquals("/foo/bar\xC3\xBC", \OC\Files\Filesystem::normalizePath("/foo/baru\xCC\x88")); } } + public function testNormalizeWindowsPaths() { + $this->assertEquals('/', \OC\Files\Filesystem::normalizePath('')); + $this->assertEquals('/', \OC\Files\Filesystem::normalizePath('\\')); + $this->assertEquals('/', \OC\Files\Filesystem::normalizePath('\\', false)); + $this->assertEquals('/', \OC\Files\Filesystem::normalizePath('\\\\')); + $this->assertEquals('/', \OC\Files\Filesystem::normalizePath('\\\\', false)); + $this->assertEquals('/path', \OC\Files\Filesystem::normalizePath('\\path')); + $this->assertEquals('/path', \OC\Files\Filesystem::normalizePath('\\path', false)); + $this->assertEquals('/path', \OC\Files\Filesystem::normalizePath('\\path\\')); + $this->assertEquals('/path/', \OC\Files\Filesystem::normalizePath('\\path\\', false)); + $this->assertEquals('/foo/bar', \OC\Files\Filesystem::normalizePath('\\foo\\\\bar\\')); + $this->assertEquals('/foo/bar/', \OC\Files\Filesystem::normalizePath('\\foo\\\\bar\\', false)); + $this->assertEquals('/foo/bar', \OC\Files\Filesystem::normalizePath('\\foo\\\\\\\\bar')); + $this->assertEquals('/foo/bar', \OC\Files\Filesystem::normalizePath('\\foo\\\\\\\\\\bar')); + $this->assertEquals('/foo/bar', \OC\Files\Filesystem::normalizePath('\\foo\\bar\\.')); + $this->assertEquals('/foo/bar', \OC\Files\Filesystem::normalizePath('\\foo\\bar\\.\\')); + $this->assertEquals('/foo/bar/', \OC\Files\Filesystem::normalizePath('\\foo\\bar\\.\\', false)); + $this->assertEquals('/foo/bar', \OC\Files\Filesystem::normalizePath('\\foo\\bar\\.\\.')); + $this->assertEquals('/foo/bar', \OC\Files\Filesystem::normalizePath('\\foo\\bar\\.\\.\\')); + $this->assertEquals('/foo/bar/', \OC\Files\Filesystem::normalizePath('\\foo\\bar\\.\\.\\', false)); + $this->assertEquals('/foo/bar', \OC\Files\Filesystem::normalizePath('\\foo\\.\\bar\\')); + $this->assertEquals('/foo/bar/', \OC\Files\Filesystem::normalizePath('\\foo\\.\\bar\\', false)); + $this->assertEquals('/foo/.bar', \OC\Files\Filesystem::normalizePath('\\foo\\.bar\\')); + $this->assertEquals('/foo/.bar/', \OC\Files\Filesystem::normalizePath('\\foo\\.bar\\', false)); + $this->assertEquals('/foo/.bar/tee', \OC\Files\Filesystem::normalizePath('\\foo\\.bar\\tee')); + + // normalize does not resolve '..' (by design) + $this->assertEquals('/foo/..', \OC\Files\Filesystem::normalizePath('\\foo\\..\\')); + + if (class_exists('Patchwork\PHP\Shim\Normalizer')) { + $this->assertEquals("/foo/bar\xC3\xBC", \OC\Files\Filesystem::normalizePath("\\foo\\baru\xCC\x88")); + } + } + public function testHooks() { if(\OC\Files\Filesystem::getView()){ $user = \OC_User::getUser();