77 */
88namespace OC \Files ;
99
10- use OC \Files \Mount \MountPoint ;
1110use OC \Files \Storage \StorageFactory ;
1211use OC \User \NoUserException ;
13- use OCP \Cache \CappedMemoryCache ;
1412use OCP \EventDispatcher \IEventDispatcher ;
1513use OCP \Files \Events \Node \FilesystemTornDownEvent ;
1614use OCP \Files \Mount \IMountManager ;
@@ -28,8 +26,6 @@ class Filesystem {
2826
2927 private static ?View $ defaultInstance = null ;
3028
31- private static ?CappedMemoryCache $ normalizedPathCache = null ;
32-
3329 private static ?FilenameValidator $ validator = null ;
3430
3531 /**
@@ -603,46 +599,61 @@ public static function normalizePath($path, $stripTrailingSlash = true, $isAbsol
603599 */
604600 $ path = (string )$ path ;
605601
606- if ($ path === '' ) {
602+ if ($ path === '' || $ path === ' / ' ) {
607603 return '/ ' ;
608604 }
609605
610- if (is_null (self ::$ normalizedPathCache )) {
611- self ::$ normalizedPathCache = new CappedMemoryCache (2048 );
612- }
613-
614- $ cacheKey = json_encode ([$ path , $ stripTrailingSlash , $ isAbsolutePath , $ keepUnicode ]);
615-
616- if ($ cacheKey && isset (self ::$ normalizedPathCache [$ cacheKey ])) {
617- return self ::$ normalizedPathCache [$ cacheKey ];
618- }
619-
620606 //normalize unicode if possible
621607 if (!$ keepUnicode ) {
622608 $ path = \OC_Util::normalizeUnicode ($ path );
623609 }
624610
625- //add leading slash, if it is already there we strip it anyway
626- $ path = '/ ' . $ path ;
611+ $ len = strlen ($ path );
612+ $ out = [];
613+ $ outLen = 0 ;
614+
615+ // Force leading slash
616+ $ out [$ outLen ++] = '/ ' ;
617+
618+ $ prev = '/ ' ;
619+ $ i = 0 ;
627620
628- $ patterns = [
629- '# \\\\#s ' , // no windows style '\\' slashes
630- '#/\.(/\.)*/#s ' , // remove '/./'
631- '#\//+#s ' , // remove sequence of slashes
632- '#/\.$#s ' , // remove trailing '/.'
633- ];
621+ while ($ i < $ len ) {
622+ $ c = $ path [$ i ++];
634623
635- do {
636- $ count = 0 ;
637- $ path = preg_replace ($ patterns , '/ ' , $ path , -1 , $ count );
638- } while ($ count > 0 );
624+ // Normalize Windows slashes
625+ if ($ c === '\\' ) {
626+ $ c = '/ ' ;
627+ }
628+
629+ // Collapse multiple slashes
630+ if ($ c === '/ ' && $ prev === '/ ' ) {
631+ continue ;
632+ }
633+
634+ // Handle "/./" and trailing "/."
635+ if ($ c === '. ' && $ prev === '/ ' ) {
636+ $ next = $ i < $ len ? $ path [$ i ] : null ;
637+
638+ if ($ next === '/ ' || $ next === null ) {
639+ // Skip "./"
640+ if ($ next === '/ ' ) {
641+ $ i ++;
642+ }
643+ continue ;
644+ }
645+ }
646+
647+ $ out [$ outLen ++] = $ c ;
648+ $ prev = $ c ;
649+ }
639650
640- //remove trailing slash
641- if ($ stripTrailingSlash && strlen ( $ path ) > 1 ) {
642- $ path = rtrim ( $ path , ' / ' );
651+ // Remove trailing slash
652+ if ($ stripTrailingSlash && $ outLen > 1 && $ out [ $ outLen - 1 ] === ' / ' ) {
653+ array_pop ( $ out );
643654 }
644655
645- self :: $ normalizedPathCache [ $ cacheKey ] = $ path ;
656+ $ path = implode ( '' , $ out ) ;
646657
647658 return $ path ;
648659 }
0 commit comments