diff --git a/lib/private/Files/Filesystem.php b/lib/private/Files/Filesystem.php
index 12e59e5ba2dc6ba04be04d4523f6d661e0cb606b..ba9c85deeee7bc285f19fea33ff4913d5212a2a8 100644
--- a/lib/private/Files/Filesystem.php
+++ b/lib/private/Files/Filesystem.php
@@ -812,7 +812,7 @@ class Filesystem {
 			return self::$normalizedPathCache[$cacheKey];
 		}
 
-		if ($path == '') {
+		if ($path === '') {
 			return '/';
 		}
 
@@ -821,38 +821,29 @@ class Filesystem {
 			$path = \OC_Util::normalizeUnicode($path);
 		}
 
-		//no windows style slashes
-		$path = str_replace('\\', '/', $path);
+		//add leading slash, if it is already there we strip it anyway
+		$path = '/' . $path;
 
-		//add leading slash
-		if ($path[0] !== '/') {
-			$path = '/' . $path;
-		}
+		$patterns = [
+			'/\\\\/s',          // no windows style slashes
+			'/\/\.(\/\.)?\//s', // remove '/./'
+			'/\/{2,}/s',        // remove squence of slashes
+			'/\/\.$/s',         // remove trailing /.
+		];
 
-		// 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);
+		do {
+			$count = 0;
+			$path = preg_replace($patterns, '/', $path, -1, $count);
+		} while ($count > 0);
 
 		//remove trailing slash
-		if ($stripTrailingSlash and strlen($path) > 1) {
+		if ($stripTrailingSlash && strlen($path) > 1) {
 			$path = rtrim($path, '/');
 		}
 
-		// remove trailing '/.'
-		if (substr($path, -2) == '/.') {
-			$path = substr($path, 0, -2);
-		}
-
-		$normalizedPath = $path;
-		self::$normalizedPathCache[$cacheKey] = $normalizedPath;
+		self::$normalizedPathCache[$cacheKey] = $path;
 
-		return $normalizedPath;
+		return $path;
 	}
 
 	/**
diff --git a/tests/lib/Files/FilesystemTest.php b/tests/lib/Files/FilesystemTest.php
index a98af220ba1772f1289b8eac0b3895d5193d8338..6fc6fbe9d7cae5e10b5f66b26dcefa6e15dd3123 100644
--- a/tests/lib/Files/FilesystemTest.php
+++ b/tests/lib/Files/FilesystemTest.php
@@ -115,73 +115,80 @@ class FilesystemTest extends \Test\TestCase {
 	}
 
 	public function normalizePathData() {
-		return array(
-			array('/', ''),
-			array('/', '/'),
-			array('/', '//'),
-			array('/', '/', false),
-			array('/', '//', false),
-
-			array('/path', '/path/'),
-			array('/path/', '/path/', false),
-			array('/path', 'path'),
-
-			array('/foo/bar', '/foo//bar/'),
-			array('/foo/bar/', '/foo//bar/', false),
-			array('/foo/bar', '/foo////bar'),
-			array('/foo/bar', '/foo/////bar'),
-			array('/foo/bar', '/foo/bar/.'),
-			array('/foo/bar', '/foo/bar/./'),
-			array('/foo/bar/', '/foo/bar/./', false),
-			array('/foo/bar', '/foo/bar/./.'),
-			array('/foo/bar', '/foo/bar/././'),
-			array('/foo/bar/', '/foo/bar/././', false),
-			array('/foo/bar', '/foo/./bar/'),
-			array('/foo/bar/', '/foo/./bar/', false),
-			array('/foo/.bar', '/foo/.bar/'),
-			array('/foo/.bar/', '/foo/.bar/', false),
-			array('/foo/.bar/tee', '/foo/.bar/tee'),
+		return [
+			['/', ''],
+			['/', '/'],
+			['/', '//'],
+			['/', '/', false],
+			['/', '//', false],
+
+			['/path', '/path/'],
+			['/path/', '/path/', false],
+			['/path', 'path'],
+
+			['/foo/bar', '/foo//bar/'],
+			['/foo/bar/', '/foo//bar/', false],
+			['/foo/bar', '/foo////bar'],
+			['/foo/bar', '/foo/////bar'],
+			['/foo/bar', '/foo/bar/.'],
+			['/foo/bar', '/foo/bar/./'],
+			['/foo/bar/', '/foo/bar/./', false],
+			['/foo/bar', '/foo/bar/./.'],
+			['/foo/bar', '/foo/bar/././'],
+			['/foo/bar/', '/foo/bar/././', false],
+			['/foo/bar', '/foo/./bar/'],
+			['/foo/bar/', '/foo/./bar/', false],
+			['/foo/.bar', '/foo/.bar/'],
+			['/foo/.bar/', '/foo/.bar/', false],
+			['/foo/.bar/tee', '/foo/.bar/tee'],
+
+			['/foo/bar', '/.///././//./foo/.///././//./bar/./././.'],
+			['/foo/bar/', '/.///././//./foo/.///././//./bar/./././.', false],
+			['/foo/bar', '/.///././//./foo/.///././//./bar/././././'],
+			['/foo/bar/', '/.///././//./foo/.///././//./bar/././././', false],
 
 			// Windows paths
-			array('/', ''),
-			array('/', '\\'),
-			array('/', '\\', false),
-			array('/', '\\\\'),
-			array('/', '\\\\', false),
-
-			array('/path', '\\path'),
-			array('/path', '\\path', false),
-			array('/path', '\\path\\'),
-			array('/path/', '\\path\\', false),
-
-			array('/foo/bar', '\\foo\\\\bar\\'),
-			array('/foo/bar/', '\\foo\\\\bar\\', false),
-			array('/foo/bar', '\\foo\\\\\\\\bar'),
-			array('/foo/bar', '\\foo\\\\\\\\\\bar'),
-			array('/foo/bar', '\\foo\\bar\\.'),
-			array('/foo/bar', '\\foo\\bar\\.\\'),
-			array('/foo/bar/', '\\foo\\bar\\.\\', false),
-			array('/foo/bar', '\\foo\\bar\\.\\.'),
-			array('/foo/bar', '\\foo\\bar\\.\\.\\'),
-			array('/foo/bar/', '\\foo\\bar\\.\\.\\', false),
-			array('/foo/bar', '\\foo\\.\\bar\\'),
-			array('/foo/bar/', '\\foo\\.\\bar\\', false),
-			array('/foo/.bar', '\\foo\\.bar\\'),
-			array('/foo/.bar/', '\\foo\\.bar\\', false),
-			array('/foo/.bar/tee', '\\foo\\.bar\\tee'),
+			['/', ''],
+			['/', '\\'],
+			['/', '\\', false],
+			['/', '\\\\'],
+			['/', '\\\\', false],
+
+			['/path', '\\path'],
+			['/path', '\\path', false],
+			['/path', '\\path\\'],
+			['/path/', '\\path\\', false],
+
+			['/foo/bar', '\\foo\\\\bar\\'],
+			['/foo/bar/', '\\foo\\\\bar\\', false],
+			['/foo/bar', '\\foo\\\\\\\\bar'],
+			['/foo/bar', '\\foo\\\\\\\\\\bar'],
+			['/foo/bar', '\\foo\\bar\\.'],
+			['/foo/bar', '\\foo\\bar\\.\\'],
+			['/foo/bar/', '\\foo\\bar\\.\\', false],
+			['/foo/bar', '\\foo\\bar\\.\\.'],
+			['/foo/bar', '\\foo\\bar\\.\\.\\'],
+			['/foo/bar/', '\\foo\\bar\\.\\.\\', false],
+			['/foo/bar', '\\foo\\.\\bar\\'],
+			['/foo/bar/', '\\foo\\.\\bar\\', false],
+			['/foo/.bar', '\\foo\\.bar\\'],
+			['/foo/.bar/', '\\foo\\.bar\\', false],
+			['/foo/.bar/tee', '\\foo\\.bar\\tee'],
 
 			// Absolute windows paths NOT marked as absolute
-			array('/C:', 'C:\\'),
-			array('/C:/', 'C:\\', false),
-			array('/C:/tests', 'C:\\tests'),
-			array('/C:/tests', 'C:\\tests', false),
-			array('/C:/tests', 'C:\\tests\\'),
-			array('/C:/tests/', 'C:\\tests\\', false),
+			['/C:', 'C:\\'],
+			['/C:/', 'C:\\', false],
+			['/C:/tests', 'C:\\tests'],
+			['/C:/tests', 'C:\\tests', false],
+			['/C:/tests', 'C:\\tests\\'],
+			['/C:/tests/', 'C:\\tests\\', false],
+			['/C:/tests/bar', 'C:\\tests\\.\\.\\bar'],
+			['/C:/tests/bar/', 'C:\\tests\\.\\.\\bar\\.\\', false],
 
 			// normalize does not resolve '..' (by design)
-			array('/foo/..', '/foo/../'),
-			array('/foo/..', '\\foo\\..\\'),
-		);
+			['/foo/..', '/foo/../'],
+			['/foo/..', '\\foo\\..\\'],
+		];
 	}
 
 	/**