Passed
Push — master ( 77a31b...df8576 )
by Joas
13:12 queued 10s
created
lib/private/Files/Filesystem.php 1 patch
Indentation   +848 added lines, -848 removed lines patch added patch discarded remove patch
@@ -71,852 +71,852 @@
 block discarded – undo
71 71
 
72 72
 class Filesystem {
73 73
 
74
-	/**
75
-	 * @var Mount\Manager $mounts
76
-	 */
77
-	private static $mounts;
78
-
79
-	public static $loaded = false;
80
-	/**
81
-	 * @var \OC\Files\View $defaultInstance
82
-	 */
83
-	private static $defaultInstance;
84
-
85
-	private static $usersSetup = [];
86
-
87
-	private static $normalizedPathCache = null;
88
-
89
-	private static $listeningForProviders = false;
90
-
91
-	/**
92
-	 * classname which used for hooks handling
93
-	 * used as signalclass in OC_Hooks::emit()
94
-	 */
95
-	public const CLASSNAME = 'OC_Filesystem';
96
-
97
-	/**
98
-	 * signalname emitted before file renaming
99
-	 *
100
-	 * @param string $oldpath
101
-	 * @param string $newpath
102
-	 */
103
-	public const signal_rename = 'rename';
104
-
105
-	/**
106
-	 * signal emitted after file renaming
107
-	 *
108
-	 * @param string $oldpath
109
-	 * @param string $newpath
110
-	 */
111
-	public const signal_post_rename = 'post_rename';
112
-
113
-	/**
114
-	 * signal emitted before file/dir creation
115
-	 *
116
-	 * @param string $path
117
-	 * @param bool $run changing this flag to false in hook handler will cancel event
118
-	 */
119
-	public const signal_create = 'create';
120
-
121
-	/**
122
-	 * signal emitted after file/dir creation
123
-	 *
124
-	 * @param string $path
125
-	 * @param bool $run changing this flag to false in hook handler will cancel event
126
-	 */
127
-	public const signal_post_create = 'post_create';
128
-
129
-	/**
130
-	 * signal emits before file/dir copy
131
-	 *
132
-	 * @param string $oldpath
133
-	 * @param string $newpath
134
-	 * @param bool $run changing this flag to false in hook handler will cancel event
135
-	 */
136
-	public const signal_copy = 'copy';
137
-
138
-	/**
139
-	 * signal emits after file/dir copy
140
-	 *
141
-	 * @param string $oldpath
142
-	 * @param string $newpath
143
-	 */
144
-	public const signal_post_copy = 'post_copy';
145
-
146
-	/**
147
-	 * signal emits before file/dir save
148
-	 *
149
-	 * @param string $path
150
-	 * @param bool $run changing this flag to false in hook handler will cancel event
151
-	 */
152
-	public const signal_write = 'write';
153
-
154
-	/**
155
-	 * signal emits after file/dir save
156
-	 *
157
-	 * @param string $path
158
-	 */
159
-	public const signal_post_write = 'post_write';
160
-
161
-	/**
162
-	 * signal emitted before file/dir update
163
-	 *
164
-	 * @param string $path
165
-	 * @param bool $run changing this flag to false in hook handler will cancel event
166
-	 */
167
-	public const signal_update = 'update';
168
-
169
-	/**
170
-	 * signal emitted after file/dir update
171
-	 *
172
-	 * @param string $path
173
-	 * @param bool $run changing this flag to false in hook handler will cancel event
174
-	 */
175
-	public const signal_post_update = 'post_update';
176
-
177
-	/**
178
-	 * signal emits when reading file/dir
179
-	 *
180
-	 * @param string $path
181
-	 */
182
-	public const signal_read = 'read';
183
-
184
-	/**
185
-	 * signal emits when removing file/dir
186
-	 *
187
-	 * @param string $path
188
-	 */
189
-	public const signal_delete = 'delete';
190
-
191
-	/**
192
-	 * parameters definitions for signals
193
-	 */
194
-	public const signal_param_path = 'path';
195
-	public const signal_param_oldpath = 'oldpath';
196
-	public const signal_param_newpath = 'newpath';
197
-
198
-	/**
199
-	 * run - changing this flag to false in hook handler will cancel event
200
-	 */
201
-	public const signal_param_run = 'run';
202
-
203
-	public const signal_create_mount = 'create_mount';
204
-	public const signal_delete_mount = 'delete_mount';
205
-	public const signal_param_mount_type = 'mounttype';
206
-	public const signal_param_users = 'users';
207
-
208
-	/**
209
-	 * @var \OC\Files\Storage\StorageFactory $loader
210
-	 */
211
-	private static $loader;
212
-
213
-	/** @var bool */
214
-	private static $logWarningWhenAddingStorageWrapper = true;
215
-
216
-	/**
217
-	 * @param bool $shouldLog
218
-	 * @return bool previous value
219
-	 * @internal
220
-	 */
221
-	public static function logWarningWhenAddingStorageWrapper($shouldLog) {
222
-		$previousValue = self::$logWarningWhenAddingStorageWrapper;
223
-		self::$logWarningWhenAddingStorageWrapper = (bool) $shouldLog;
224
-		return $previousValue;
225
-	}
226
-
227
-	/**
228
-	 * @param string $wrapperName
229
-	 * @param callable $wrapper
230
-	 * @param int $priority
231
-	 */
232
-	public static function addStorageWrapper($wrapperName, $wrapper, $priority = 50) {
233
-		if (self::$logWarningWhenAddingStorageWrapper) {
234
-			\OC::$server->getLogger()->warning("Storage wrapper '{wrapper}' was not registered via the 'OC_Filesystem - preSetup' hook which could cause potential problems.", [
235
-				'wrapper' => $wrapperName,
236
-				'app' => 'filesystem',
237
-			]);
238
-		}
239
-
240
-		$mounts = self::getMountManager()->getAll();
241
-		if (!self::getLoader()->addStorageWrapper($wrapperName, $wrapper, $priority, $mounts)) {
242
-			// do not re-wrap if storage with this name already existed
243
-			return;
244
-		}
245
-	}
246
-
247
-	/**
248
-	 * Returns the storage factory
249
-	 *
250
-	 * @return IStorageFactory
251
-	 */
252
-	public static function getLoader() {
253
-		if (!self::$loader) {
254
-			self::$loader = \OC::$server->query(IStorageFactory::class);
255
-		}
256
-		return self::$loader;
257
-	}
258
-
259
-	/**
260
-	 * Returns the mount manager
261
-	 *
262
-	 * @return \OC\Files\Mount\Manager
263
-	 */
264
-	public static function getMountManager($user = '') {
265
-		if (!self::$mounts) {
266
-			\OC_Util::setupFS($user);
267
-		}
268
-		return self::$mounts;
269
-	}
270
-
271
-	/**
272
-	 * get the mountpoint of the storage object for a path
273
-	 * ( note: because a storage is not always mounted inside the fakeroot, the
274
-	 * returned mountpoint is relative to the absolute root of the filesystem
275
-	 * and doesn't take the chroot into account )
276
-	 *
277
-	 * @param string $path
278
-	 * @return string
279
-	 */
280
-	public static function getMountPoint($path) {
281
-		if (!self::$mounts) {
282
-			\OC_Util::setupFS();
283
-		}
284
-		$mount = self::$mounts->find($path);
285
-		if ($mount) {
286
-			return $mount->getMountPoint();
287
-		} else {
288
-			return '';
289
-		}
290
-	}
291
-
292
-	/**
293
-	 * get a list of all mount points in a directory
294
-	 *
295
-	 * @param string $path
296
-	 * @return string[]
297
-	 */
298
-	public static function getMountPoints($path) {
299
-		if (!self::$mounts) {
300
-			\OC_Util::setupFS();
301
-		}
302
-		$result = [];
303
-		$mounts = self::$mounts->findIn($path);
304
-		foreach ($mounts as $mount) {
305
-			$result[] = $mount->getMountPoint();
306
-		}
307
-		return $result;
308
-	}
309
-
310
-	/**
311
-	 * get the storage mounted at $mountPoint
312
-	 *
313
-	 * @param string $mountPoint
314
-	 * @return \OC\Files\Storage\Storage
315
-	 */
316
-	public static function getStorage($mountPoint) {
317
-		if (!self::$mounts) {
318
-			\OC_Util::setupFS();
319
-		}
320
-		$mount = self::$mounts->find($mountPoint);
321
-		return $mount->getStorage();
322
-	}
323
-
324
-	/**
325
-	 * @param string $id
326
-	 * @return Mount\MountPoint[]
327
-	 */
328
-	public static function getMountByStorageId($id) {
329
-		if (!self::$mounts) {
330
-			\OC_Util::setupFS();
331
-		}
332
-		return self::$mounts->findByStorageId($id);
333
-	}
334
-
335
-	/**
336
-	 * @param int $id
337
-	 * @return Mount\MountPoint[]
338
-	 */
339
-	public static function getMountByNumericId($id) {
340
-		if (!self::$mounts) {
341
-			\OC_Util::setupFS();
342
-		}
343
-		return self::$mounts->findByNumericId($id);
344
-	}
345
-
346
-	/**
347
-	 * resolve a path to a storage and internal path
348
-	 *
349
-	 * @param string $path
350
-	 * @return array an array consisting of the storage and the internal path
351
-	 */
352
-	public static function resolvePath($path) {
353
-		if (!self::$mounts) {
354
-			\OC_Util::setupFS();
355
-		}
356
-		$mount = self::$mounts->find($path);
357
-		if ($mount) {
358
-			return [$mount->getStorage(), rtrim($mount->getInternalPath($path), '/')];
359
-		} else {
360
-			return [null, null];
361
-		}
362
-	}
363
-
364
-	public static function init($user, $root) {
365
-		if (self::$defaultInstance) {
366
-			return false;
367
-		}
368
-		self::getLoader();
369
-		self::$defaultInstance = new View($root);
370
-
371
-		if (!self::$mounts) {
372
-			self::$mounts = \OC::$server->getMountManager();
373
-		}
374
-
375
-		//load custom mount config
376
-		self::initMountPoints($user);
377
-
378
-		self::$loaded = true;
379
-
380
-		return true;
381
-	}
382
-
383
-	public static function initMountManager() {
384
-		if (!self::$mounts) {
385
-			self::$mounts = \OC::$server->getMountManager();
386
-		}
387
-	}
388
-
389
-	/**
390
-	 * Initialize system and personal mount points for a user
391
-	 *
392
-	 * @param string $user
393
-	 * @throws \OC\User\NoUserException if the user is not available
394
-	 */
395
-	public static function initMountPoints($user = '') {
396
-		if ($user == '') {
397
-			$user = \OC_User::getUser();
398
-		}
399
-		if ($user === null || $user === false || $user === '') {
400
-			throw new \OC\User\NoUserException('Attempted to initialize mount points for null user and no user in session');
401
-		}
402
-
403
-		if (isset(self::$usersSetup[$user])) {
404
-			return;
405
-		}
406
-
407
-		self::$usersSetup[$user] = true;
408
-
409
-		$userManager = \OC::$server->getUserManager();
410
-		$userObject = $userManager->get($user);
411
-
412
-		if (is_null($userObject)) {
413
-			\OCP\Util::writeLog('files', ' Backends provided no user object for ' . $user, ILogger::ERROR);
414
-			// reset flag, this will make it possible to rethrow the exception if called again
415
-			unset(self::$usersSetup[$user]);
416
-			throw new \OC\User\NoUserException('Backends provided no user object for ' . $user);
417
-		}
418
-
419
-		$realUid = $userObject->getUID();
420
-		// workaround in case of different casings
421
-		if ($user !== $realUid) {
422
-			$stack = json_encode(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 50));
423
-			\OCP\Util::writeLog('files', 'initMountPoints() called with wrong user casing. This could be a bug. Expected: "' . $realUid . '" got "' . $user . '". Stack: ' . $stack, ILogger::WARN);
424
-			$user = $realUid;
425
-
426
-			// again with the correct casing
427
-			if (isset(self::$usersSetup[$user])) {
428
-				return;
429
-			}
430
-
431
-			self::$usersSetup[$user] = true;
432
-		}
433
-
434
-		if (\OC::$server->getLockdownManager()->canAccessFilesystem()) {
435
-			/** @var \OC\Files\Config\MountProviderCollection $mountConfigManager */
436
-			$mountConfigManager = \OC::$server->getMountProviderCollection();
437
-
438
-			// home mounts are handled seperate since we need to ensure this is mounted before we call the other mount providers
439
-			$homeMount = $mountConfigManager->getHomeMountForUser($userObject);
440
-			self::getMountManager()->addMount($homeMount);
441
-
442
-			if ($homeMount->getStorageRootId() === -1) {
443
-				$homeMount->getStorage()->mkdir('');
444
-				$homeMount->getStorage()->getScanner()->scan('');
445
-			}
446
-
447
-			\OC\Files\Filesystem::getStorage($user);
448
-
449
-			// Chance to mount for other storages
450
-			if ($userObject) {
451
-				$mounts = $mountConfigManager->addMountForUser($userObject, self::getMountManager());
452
-				$mounts[] = $homeMount;
453
-				$mountConfigManager->registerMounts($userObject, $mounts);
454
-			}
455
-
456
-			self::listenForNewMountProviders($mountConfigManager, $userManager);
457
-		} else {
458
-			self::getMountManager()->addMount(new MountPoint(
459
-				new NullStorage([]),
460
-				'/' . $user
461
-			));
462
-			self::getMountManager()->addMount(new MountPoint(
463
-				new NullStorage([]),
464
-				'/' . $user . '/files'
465
-			));
466
-		}
467
-		\OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', ['user' => $user]);
468
-	}
469
-
470
-	/**
471
-	 * Get mounts from mount providers that are registered after setup
472
-	 *
473
-	 * @param MountProviderCollection $mountConfigManager
474
-	 * @param IUserManager $userManager
475
-	 */
476
-	private static function listenForNewMountProviders(MountProviderCollection $mountConfigManager, IUserManager $userManager) {
477
-		if (!self::$listeningForProviders) {
478
-			self::$listeningForProviders = true;
479
-			$mountConfigManager->listen('\OC\Files\Config', 'registerMountProvider', function (IMountProvider $provider) use ($userManager) {
480
-				foreach (Filesystem::$usersSetup as $user => $setup) {
481
-					$userObject = $userManager->get($user);
482
-					if ($userObject) {
483
-						$mounts = $provider->getMountsForUser($userObject, Filesystem::getLoader());
484
-						array_walk($mounts, [self::$mounts, 'addMount']);
485
-					}
486
-				}
487
-			});
488
-		}
489
-	}
490
-
491
-	/**
492
-	 * get the default filesystem view
493
-	 *
494
-	 * @return View
495
-	 */
496
-	public static function getView() {
497
-		return self::$defaultInstance;
498
-	}
499
-
500
-	/**
501
-	 * tear down the filesystem, removing all storage providers
502
-	 */
503
-	public static function tearDown() {
504
-		self::clearMounts();
505
-		self::$defaultInstance = null;
506
-	}
507
-
508
-	/**
509
-	 * get the relative path of the root data directory for the current user
510
-	 *
511
-	 * @return string
512
-	 *
513
-	 * Returns path like /admin/files
514
-	 */
515
-	public static function getRoot() {
516
-		if (!self::$defaultInstance) {
517
-			return null;
518
-		}
519
-		return self::$defaultInstance->getRoot();
520
-	}
521
-
522
-	/**
523
-	 * clear all mounts and storage backends
524
-	 */
525
-	public static function clearMounts() {
526
-		if (self::$mounts) {
527
-			self::$usersSetup = [];
528
-			self::$mounts->clear();
529
-		}
530
-	}
531
-
532
-	/**
533
-	 * mount an \OC\Files\Storage\Storage in our virtual filesystem
534
-	 *
535
-	 * @param \OC\Files\Storage\Storage|string $class
536
-	 * @param array $arguments
537
-	 * @param string $mountpoint
538
-	 */
539
-	public static function mount($class, $arguments, $mountpoint) {
540
-		if (!self::$mounts) {
541
-			\OC_Util::setupFS();
542
-		}
543
-		$mount = new Mount\MountPoint($class, $mountpoint, $arguments, self::getLoader());
544
-		self::$mounts->addMount($mount);
545
-	}
546
-
547
-	/**
548
-	 * return the path to a local version of the file
549
-	 * we need this because we can't know if a file is stored local or not from
550
-	 * outside the filestorage and for some purposes a local file is needed
551
-	 *
552
-	 * @param string $path
553
-	 * @return string
554
-	 */
555
-	public static function getLocalFile($path) {
556
-		return self::$defaultInstance->getLocalFile($path);
557
-	}
558
-
559
-	/**
560
-	 * @param string $path
561
-	 * @return string
562
-	 */
563
-	public static function getLocalFolder($path) {
564
-		return self::$defaultInstance->getLocalFolder($path);
565
-	}
566
-
567
-	/**
568
-	 * return path to file which reflects one visible in browser
569
-	 *
570
-	 * @param string $path
571
-	 * @return string
572
-	 */
573
-	public static function getLocalPath($path) {
574
-		$datadir = \OC_User::getHome(\OC_User::getUser()) . '/files';
575
-		$newpath = $path;
576
-		if (strncmp($newpath, $datadir, strlen($datadir)) == 0) {
577
-			$newpath = substr($path, strlen($datadir));
578
-		}
579
-		return $newpath;
580
-	}
581
-
582
-	/**
583
-	 * check if the requested path is valid
584
-	 *
585
-	 * @param string $path
586
-	 * @return bool
587
-	 */
588
-	public static function isValidPath($path) {
589
-		$path = self::normalizePath($path);
590
-		if (!$path || $path[0] !== '/') {
591
-			$path = '/' . $path;
592
-		}
593
-		if (strpos($path, '/../') !== false || strrchr($path, '/') === '/..') {
594
-			return false;
595
-		}
596
-		return true;
597
-	}
598
-
599
-	/**
600
-	 * checks if a file is blacklisted for storage in the filesystem
601
-	 * Listens to write and rename hooks
602
-	 *
603
-	 * @param array $data from hook
604
-	 */
605
-	public static function isBlacklisted($data) {
606
-		if (isset($data['path'])) {
607
-			$path = $data['path'];
608
-		} elseif (isset($data['newpath'])) {
609
-			$path = $data['newpath'];
610
-		}
611
-		if (isset($path)) {
612
-			if (self::isFileBlacklisted($path)) {
613
-				$data['run'] = false;
614
-			}
615
-		}
616
-	}
617
-
618
-	/**
619
-	 * @param string $filename
620
-	 * @return bool
621
-	 */
622
-	public static function isFileBlacklisted($filename) {
623
-		$filename = self::normalizePath($filename);
624
-
625
-		$blacklist = \OC::$server->getConfig()->getSystemValue('blacklisted_files', ['.htaccess']);
626
-		$filename = strtolower(basename($filename));
627
-		return in_array($filename, $blacklist);
628
-	}
629
-
630
-	/**
631
-	 * check if the directory should be ignored when scanning
632
-	 * NOTE: the special directories . and .. would cause never ending recursion
633
-	 *
634
-	 * @param string $dir
635
-	 * @return boolean
636
-	 */
637
-	public static function isIgnoredDir($dir) {
638
-		if ($dir === '.' || $dir === '..') {
639
-			return true;
640
-		}
641
-		return false;
642
-	}
643
-
644
-	/**
645
-	 * following functions are equivalent to their php builtin equivalents for arguments/return values.
646
-	 */
647
-	public static function mkdir($path) {
648
-		return self::$defaultInstance->mkdir($path);
649
-	}
650
-
651
-	public static function rmdir($path) {
652
-		return self::$defaultInstance->rmdir($path);
653
-	}
654
-
655
-	public static function is_dir($path) {
656
-		return self::$defaultInstance->is_dir($path);
657
-	}
658
-
659
-	public static function is_file($path) {
660
-		return self::$defaultInstance->is_file($path);
661
-	}
662
-
663
-	public static function stat($path) {
664
-		return self::$defaultInstance->stat($path);
665
-	}
666
-
667
-	public static function filetype($path) {
668
-		return self::$defaultInstance->filetype($path);
669
-	}
670
-
671
-	public static function filesize($path) {
672
-		return self::$defaultInstance->filesize($path);
673
-	}
674
-
675
-	public static function readfile($path) {
676
-		return self::$defaultInstance->readfile($path);
677
-	}
678
-
679
-	public static function isCreatable($path) {
680
-		return self::$defaultInstance->isCreatable($path);
681
-	}
682
-
683
-	public static function isReadable($path) {
684
-		return self::$defaultInstance->isReadable($path);
685
-	}
686
-
687
-	public static function isUpdatable($path) {
688
-		return self::$defaultInstance->isUpdatable($path);
689
-	}
690
-
691
-	public static function isDeletable($path) {
692
-		return self::$defaultInstance->isDeletable($path);
693
-	}
694
-
695
-	public static function isSharable($path) {
696
-		return self::$defaultInstance->isSharable($path);
697
-	}
698
-
699
-	public static function file_exists($path) {
700
-		return self::$defaultInstance->file_exists($path);
701
-	}
702
-
703
-	public static function filemtime($path) {
704
-		return self::$defaultInstance->filemtime($path);
705
-	}
706
-
707
-	public static function touch($path, $mtime = null) {
708
-		return self::$defaultInstance->touch($path, $mtime);
709
-	}
710
-
711
-	/**
712
-	 * @return string
713
-	 */
714
-	public static function file_get_contents($path) {
715
-		return self::$defaultInstance->file_get_contents($path);
716
-	}
717
-
718
-	public static function file_put_contents($path, $data) {
719
-		return self::$defaultInstance->file_put_contents($path, $data);
720
-	}
721
-
722
-	public static function unlink($path) {
723
-		return self::$defaultInstance->unlink($path);
724
-	}
725
-
726
-	public static function rename($path1, $path2) {
727
-		return self::$defaultInstance->rename($path1, $path2);
728
-	}
729
-
730
-	public static function copy($path1, $path2) {
731
-		return self::$defaultInstance->copy($path1, $path2);
732
-	}
733
-
734
-	public static function fopen($path, $mode) {
735
-		return self::$defaultInstance->fopen($path, $mode);
736
-	}
737
-
738
-	/**
739
-	 * @return string
740
-	 */
741
-	public static function toTmpFile($path) {
742
-		return self::$defaultInstance->toTmpFile($path);
743
-	}
744
-
745
-	public static function fromTmpFile($tmpFile, $path) {
746
-		return self::$defaultInstance->fromTmpFile($tmpFile, $path);
747
-	}
748
-
749
-	public static function getMimeType($path) {
750
-		return self::$defaultInstance->getMimeType($path);
751
-	}
752
-
753
-	public static function hash($type, $path, $raw = false) {
754
-		return self::$defaultInstance->hash($type, $path, $raw);
755
-	}
756
-
757
-	public static function free_space($path = '/') {
758
-		return self::$defaultInstance->free_space($path);
759
-	}
760
-
761
-	public static function search($query) {
762
-		return self::$defaultInstance->search($query);
763
-	}
764
-
765
-	/**
766
-	 * @param string $query
767
-	 */
768
-	public static function searchByMime($query) {
769
-		return self::$defaultInstance->searchByMime($query);
770
-	}
771
-
772
-	/**
773
-	 * @param string|int $tag name or tag id
774
-	 * @param string $userId owner of the tags
775
-	 * @return FileInfo[] array or file info
776
-	 */
777
-	public static function searchByTag($tag, $userId) {
778
-		return self::$defaultInstance->searchByTag($tag, $userId);
779
-	}
780
-
781
-	/**
782
-	 * check if a file or folder has been updated since $time
783
-	 *
784
-	 * @param string $path
785
-	 * @param int $time
786
-	 * @return bool
787
-	 */
788
-	public static function hasUpdated($path, $time) {
789
-		return self::$defaultInstance->hasUpdated($path, $time);
790
-	}
791
-
792
-	/**
793
-	 * Fix common problems with a file path
794
-	 *
795
-	 * @param string $path
796
-	 * @param bool $stripTrailingSlash whether to strip the trailing slash
797
-	 * @param bool $isAbsolutePath whether the given path is absolute
798
-	 * @param bool $keepUnicode true to disable unicode normalization
799
-	 * @return string
800
-	 */
801
-	public static function normalizePath($path, $stripTrailingSlash = true, $isAbsolutePath = false, $keepUnicode = false) {
802
-		if (is_null(self::$normalizedPathCache)) {
803
-			self::$normalizedPathCache = new CappedMemoryCache(2048);
804
-		}
805
-
806
-		/**
807
-		 * FIXME: This is a workaround for existing classes and files which call
808
-		 *        this function with another type than a valid string. This
809
-		 *        conversion should get removed as soon as all existing
810
-		 *        function calls have been fixed.
811
-		 */
812
-		$path = (string)$path;
813
-
814
-		$cacheKey = json_encode([$path, $stripTrailingSlash, $isAbsolutePath, $keepUnicode]);
815
-
816
-		if (isset(self::$normalizedPathCache[$cacheKey])) {
817
-			return self::$normalizedPathCache[$cacheKey];
818
-		}
819
-
820
-		if ($path === '') {
821
-			return '/';
822
-		}
823
-
824
-		//normalize unicode if possible
825
-		if (!$keepUnicode) {
826
-			$path = \OC_Util::normalizeUnicode($path);
827
-		}
828
-
829
-		//add leading slash, if it is already there we strip it anyway
830
-		$path = '/' . $path;
831
-
832
-		$patterns = [
833
-			'/\\\\/s',          // no windows style slashes
834
-			'/\/\.(\/\.)?\//s', // remove '/./'
835
-			'/\/{2,}/s',        // remove sequence of slashes
836
-			'/\/\.$/s',         // remove trailing /.
837
-		];
838
-
839
-		do {
840
-			$count = 0;
841
-			$path = preg_replace($patterns, '/', $path, -1, $count);
842
-		} while ($count > 0);
843
-
844
-		//remove trailing slash
845
-		if ($stripTrailingSlash && strlen($path) > 1) {
846
-			$path = rtrim($path, '/');
847
-		}
848
-
849
-		self::$normalizedPathCache[$cacheKey] = $path;
850
-
851
-		return $path;
852
-	}
853
-
854
-	/**
855
-	 * get the filesystem info
856
-	 *
857
-	 * @param string $path
858
-	 * @param boolean $includeMountPoints whether to add mountpoint sizes,
859
-	 * defaults to true
860
-	 * @return \OC\Files\FileInfo|bool False if file does not exist
861
-	 */
862
-	public static function getFileInfo($path, $includeMountPoints = true) {
863
-		return self::$defaultInstance->getFileInfo($path, $includeMountPoints);
864
-	}
865
-
866
-	/**
867
-	 * change file metadata
868
-	 *
869
-	 * @param string $path
870
-	 * @param array $data
871
-	 * @return int
872
-	 *
873
-	 * returns the fileid of the updated file
874
-	 */
875
-	public static function putFileInfo($path, $data) {
876
-		return self::$defaultInstance->putFileInfo($path, $data);
877
-	}
878
-
879
-	/**
880
-	 * get the content of a directory
881
-	 *
882
-	 * @param string $directory path under datadirectory
883
-	 * @param string $mimetype_filter limit returned content to this mimetype or mimepart
884
-	 * @return \OC\Files\FileInfo[]
885
-	 */
886
-	public static function getDirectoryContent($directory, $mimetype_filter = '') {
887
-		return self::$defaultInstance->getDirectoryContent($directory, $mimetype_filter);
888
-	}
889
-
890
-	/**
891
-	 * Get the path of a file by id
892
-	 *
893
-	 * Note that the resulting path is not guaranteed to be unique for the id, multiple paths can point to the same file
894
-	 *
895
-	 * @param int $id
896
-	 * @throws NotFoundException
897
-	 * @return string
898
-	 */
899
-	public static function getPath($id) {
900
-		return self::$defaultInstance->getPath($id);
901
-	}
902
-
903
-	/**
904
-	 * Get the owner for a file or folder
905
-	 *
906
-	 * @param string $path
907
-	 * @return string
908
-	 */
909
-	public static function getOwner($path) {
910
-		return self::$defaultInstance->getOwner($path);
911
-	}
912
-
913
-	/**
914
-	 * get the ETag for a file or folder
915
-	 *
916
-	 * @param string $path
917
-	 * @return string
918
-	 */
919
-	public static function getETag($path) {
920
-		return self::$defaultInstance->getETag($path);
921
-	}
74
+    /**
75
+     * @var Mount\Manager $mounts
76
+     */
77
+    private static $mounts;
78
+
79
+    public static $loaded = false;
80
+    /**
81
+     * @var \OC\Files\View $defaultInstance
82
+     */
83
+    private static $defaultInstance;
84
+
85
+    private static $usersSetup = [];
86
+
87
+    private static $normalizedPathCache = null;
88
+
89
+    private static $listeningForProviders = false;
90
+
91
+    /**
92
+     * classname which used for hooks handling
93
+     * used as signalclass in OC_Hooks::emit()
94
+     */
95
+    public const CLASSNAME = 'OC_Filesystem';
96
+
97
+    /**
98
+     * signalname emitted before file renaming
99
+     *
100
+     * @param string $oldpath
101
+     * @param string $newpath
102
+     */
103
+    public const signal_rename = 'rename';
104
+
105
+    /**
106
+     * signal emitted after file renaming
107
+     *
108
+     * @param string $oldpath
109
+     * @param string $newpath
110
+     */
111
+    public const signal_post_rename = 'post_rename';
112
+
113
+    /**
114
+     * signal emitted before file/dir creation
115
+     *
116
+     * @param string $path
117
+     * @param bool $run changing this flag to false in hook handler will cancel event
118
+     */
119
+    public const signal_create = 'create';
120
+
121
+    /**
122
+     * signal emitted after file/dir creation
123
+     *
124
+     * @param string $path
125
+     * @param bool $run changing this flag to false in hook handler will cancel event
126
+     */
127
+    public const signal_post_create = 'post_create';
128
+
129
+    /**
130
+     * signal emits before file/dir copy
131
+     *
132
+     * @param string $oldpath
133
+     * @param string $newpath
134
+     * @param bool $run changing this flag to false in hook handler will cancel event
135
+     */
136
+    public const signal_copy = 'copy';
137
+
138
+    /**
139
+     * signal emits after file/dir copy
140
+     *
141
+     * @param string $oldpath
142
+     * @param string $newpath
143
+     */
144
+    public const signal_post_copy = 'post_copy';
145
+
146
+    /**
147
+     * signal emits before file/dir save
148
+     *
149
+     * @param string $path
150
+     * @param bool $run changing this flag to false in hook handler will cancel event
151
+     */
152
+    public const signal_write = 'write';
153
+
154
+    /**
155
+     * signal emits after file/dir save
156
+     *
157
+     * @param string $path
158
+     */
159
+    public const signal_post_write = 'post_write';
160
+
161
+    /**
162
+     * signal emitted before file/dir update
163
+     *
164
+     * @param string $path
165
+     * @param bool $run changing this flag to false in hook handler will cancel event
166
+     */
167
+    public const signal_update = 'update';
168
+
169
+    /**
170
+     * signal emitted after file/dir update
171
+     *
172
+     * @param string $path
173
+     * @param bool $run changing this flag to false in hook handler will cancel event
174
+     */
175
+    public const signal_post_update = 'post_update';
176
+
177
+    /**
178
+     * signal emits when reading file/dir
179
+     *
180
+     * @param string $path
181
+     */
182
+    public const signal_read = 'read';
183
+
184
+    /**
185
+     * signal emits when removing file/dir
186
+     *
187
+     * @param string $path
188
+     */
189
+    public const signal_delete = 'delete';
190
+
191
+    /**
192
+     * parameters definitions for signals
193
+     */
194
+    public const signal_param_path = 'path';
195
+    public const signal_param_oldpath = 'oldpath';
196
+    public const signal_param_newpath = 'newpath';
197
+
198
+    /**
199
+     * run - changing this flag to false in hook handler will cancel event
200
+     */
201
+    public const signal_param_run = 'run';
202
+
203
+    public const signal_create_mount = 'create_mount';
204
+    public const signal_delete_mount = 'delete_mount';
205
+    public const signal_param_mount_type = 'mounttype';
206
+    public const signal_param_users = 'users';
207
+
208
+    /**
209
+     * @var \OC\Files\Storage\StorageFactory $loader
210
+     */
211
+    private static $loader;
212
+
213
+    /** @var bool */
214
+    private static $logWarningWhenAddingStorageWrapper = true;
215
+
216
+    /**
217
+     * @param bool $shouldLog
218
+     * @return bool previous value
219
+     * @internal
220
+     */
221
+    public static function logWarningWhenAddingStorageWrapper($shouldLog) {
222
+        $previousValue = self::$logWarningWhenAddingStorageWrapper;
223
+        self::$logWarningWhenAddingStorageWrapper = (bool) $shouldLog;
224
+        return $previousValue;
225
+    }
226
+
227
+    /**
228
+     * @param string $wrapperName
229
+     * @param callable $wrapper
230
+     * @param int $priority
231
+     */
232
+    public static function addStorageWrapper($wrapperName, $wrapper, $priority = 50) {
233
+        if (self::$logWarningWhenAddingStorageWrapper) {
234
+            \OC::$server->getLogger()->warning("Storage wrapper '{wrapper}' was not registered via the 'OC_Filesystem - preSetup' hook which could cause potential problems.", [
235
+                'wrapper' => $wrapperName,
236
+                'app' => 'filesystem',
237
+            ]);
238
+        }
239
+
240
+        $mounts = self::getMountManager()->getAll();
241
+        if (!self::getLoader()->addStorageWrapper($wrapperName, $wrapper, $priority, $mounts)) {
242
+            // do not re-wrap if storage with this name already existed
243
+            return;
244
+        }
245
+    }
246
+
247
+    /**
248
+     * Returns the storage factory
249
+     *
250
+     * @return IStorageFactory
251
+     */
252
+    public static function getLoader() {
253
+        if (!self::$loader) {
254
+            self::$loader = \OC::$server->query(IStorageFactory::class);
255
+        }
256
+        return self::$loader;
257
+    }
258
+
259
+    /**
260
+     * Returns the mount manager
261
+     *
262
+     * @return \OC\Files\Mount\Manager
263
+     */
264
+    public static function getMountManager($user = '') {
265
+        if (!self::$mounts) {
266
+            \OC_Util::setupFS($user);
267
+        }
268
+        return self::$mounts;
269
+    }
270
+
271
+    /**
272
+     * get the mountpoint of the storage object for a path
273
+     * ( note: because a storage is not always mounted inside the fakeroot, the
274
+     * returned mountpoint is relative to the absolute root of the filesystem
275
+     * and doesn't take the chroot into account )
276
+     *
277
+     * @param string $path
278
+     * @return string
279
+     */
280
+    public static function getMountPoint($path) {
281
+        if (!self::$mounts) {
282
+            \OC_Util::setupFS();
283
+        }
284
+        $mount = self::$mounts->find($path);
285
+        if ($mount) {
286
+            return $mount->getMountPoint();
287
+        } else {
288
+            return '';
289
+        }
290
+    }
291
+
292
+    /**
293
+     * get a list of all mount points in a directory
294
+     *
295
+     * @param string $path
296
+     * @return string[]
297
+     */
298
+    public static function getMountPoints($path) {
299
+        if (!self::$mounts) {
300
+            \OC_Util::setupFS();
301
+        }
302
+        $result = [];
303
+        $mounts = self::$mounts->findIn($path);
304
+        foreach ($mounts as $mount) {
305
+            $result[] = $mount->getMountPoint();
306
+        }
307
+        return $result;
308
+    }
309
+
310
+    /**
311
+     * get the storage mounted at $mountPoint
312
+     *
313
+     * @param string $mountPoint
314
+     * @return \OC\Files\Storage\Storage
315
+     */
316
+    public static function getStorage($mountPoint) {
317
+        if (!self::$mounts) {
318
+            \OC_Util::setupFS();
319
+        }
320
+        $mount = self::$mounts->find($mountPoint);
321
+        return $mount->getStorage();
322
+    }
323
+
324
+    /**
325
+     * @param string $id
326
+     * @return Mount\MountPoint[]
327
+     */
328
+    public static function getMountByStorageId($id) {
329
+        if (!self::$mounts) {
330
+            \OC_Util::setupFS();
331
+        }
332
+        return self::$mounts->findByStorageId($id);
333
+    }
334
+
335
+    /**
336
+     * @param int $id
337
+     * @return Mount\MountPoint[]
338
+     */
339
+    public static function getMountByNumericId($id) {
340
+        if (!self::$mounts) {
341
+            \OC_Util::setupFS();
342
+        }
343
+        return self::$mounts->findByNumericId($id);
344
+    }
345
+
346
+    /**
347
+     * resolve a path to a storage and internal path
348
+     *
349
+     * @param string $path
350
+     * @return array an array consisting of the storage and the internal path
351
+     */
352
+    public static function resolvePath($path) {
353
+        if (!self::$mounts) {
354
+            \OC_Util::setupFS();
355
+        }
356
+        $mount = self::$mounts->find($path);
357
+        if ($mount) {
358
+            return [$mount->getStorage(), rtrim($mount->getInternalPath($path), '/')];
359
+        } else {
360
+            return [null, null];
361
+        }
362
+    }
363
+
364
+    public static function init($user, $root) {
365
+        if (self::$defaultInstance) {
366
+            return false;
367
+        }
368
+        self::getLoader();
369
+        self::$defaultInstance = new View($root);
370
+
371
+        if (!self::$mounts) {
372
+            self::$mounts = \OC::$server->getMountManager();
373
+        }
374
+
375
+        //load custom mount config
376
+        self::initMountPoints($user);
377
+
378
+        self::$loaded = true;
379
+
380
+        return true;
381
+    }
382
+
383
+    public static function initMountManager() {
384
+        if (!self::$mounts) {
385
+            self::$mounts = \OC::$server->getMountManager();
386
+        }
387
+    }
388
+
389
+    /**
390
+     * Initialize system and personal mount points for a user
391
+     *
392
+     * @param string $user
393
+     * @throws \OC\User\NoUserException if the user is not available
394
+     */
395
+    public static function initMountPoints($user = '') {
396
+        if ($user == '') {
397
+            $user = \OC_User::getUser();
398
+        }
399
+        if ($user === null || $user === false || $user === '') {
400
+            throw new \OC\User\NoUserException('Attempted to initialize mount points for null user and no user in session');
401
+        }
402
+
403
+        if (isset(self::$usersSetup[$user])) {
404
+            return;
405
+        }
406
+
407
+        self::$usersSetup[$user] = true;
408
+
409
+        $userManager = \OC::$server->getUserManager();
410
+        $userObject = $userManager->get($user);
411
+
412
+        if (is_null($userObject)) {
413
+            \OCP\Util::writeLog('files', ' Backends provided no user object for ' . $user, ILogger::ERROR);
414
+            // reset flag, this will make it possible to rethrow the exception if called again
415
+            unset(self::$usersSetup[$user]);
416
+            throw new \OC\User\NoUserException('Backends provided no user object for ' . $user);
417
+        }
418
+
419
+        $realUid = $userObject->getUID();
420
+        // workaround in case of different casings
421
+        if ($user !== $realUid) {
422
+            $stack = json_encode(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 50));
423
+            \OCP\Util::writeLog('files', 'initMountPoints() called with wrong user casing. This could be a bug. Expected: "' . $realUid . '" got "' . $user . '". Stack: ' . $stack, ILogger::WARN);
424
+            $user = $realUid;
425
+
426
+            // again with the correct casing
427
+            if (isset(self::$usersSetup[$user])) {
428
+                return;
429
+            }
430
+
431
+            self::$usersSetup[$user] = true;
432
+        }
433
+
434
+        if (\OC::$server->getLockdownManager()->canAccessFilesystem()) {
435
+            /** @var \OC\Files\Config\MountProviderCollection $mountConfigManager */
436
+            $mountConfigManager = \OC::$server->getMountProviderCollection();
437
+
438
+            // home mounts are handled seperate since we need to ensure this is mounted before we call the other mount providers
439
+            $homeMount = $mountConfigManager->getHomeMountForUser($userObject);
440
+            self::getMountManager()->addMount($homeMount);
441
+
442
+            if ($homeMount->getStorageRootId() === -1) {
443
+                $homeMount->getStorage()->mkdir('');
444
+                $homeMount->getStorage()->getScanner()->scan('');
445
+            }
446
+
447
+            \OC\Files\Filesystem::getStorage($user);
448
+
449
+            // Chance to mount for other storages
450
+            if ($userObject) {
451
+                $mounts = $mountConfigManager->addMountForUser($userObject, self::getMountManager());
452
+                $mounts[] = $homeMount;
453
+                $mountConfigManager->registerMounts($userObject, $mounts);
454
+            }
455
+
456
+            self::listenForNewMountProviders($mountConfigManager, $userManager);
457
+        } else {
458
+            self::getMountManager()->addMount(new MountPoint(
459
+                new NullStorage([]),
460
+                '/' . $user
461
+            ));
462
+            self::getMountManager()->addMount(new MountPoint(
463
+                new NullStorage([]),
464
+                '/' . $user . '/files'
465
+            ));
466
+        }
467
+        \OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', ['user' => $user]);
468
+    }
469
+
470
+    /**
471
+     * Get mounts from mount providers that are registered after setup
472
+     *
473
+     * @param MountProviderCollection $mountConfigManager
474
+     * @param IUserManager $userManager
475
+     */
476
+    private static function listenForNewMountProviders(MountProviderCollection $mountConfigManager, IUserManager $userManager) {
477
+        if (!self::$listeningForProviders) {
478
+            self::$listeningForProviders = true;
479
+            $mountConfigManager->listen('\OC\Files\Config', 'registerMountProvider', function (IMountProvider $provider) use ($userManager) {
480
+                foreach (Filesystem::$usersSetup as $user => $setup) {
481
+                    $userObject = $userManager->get($user);
482
+                    if ($userObject) {
483
+                        $mounts = $provider->getMountsForUser($userObject, Filesystem::getLoader());
484
+                        array_walk($mounts, [self::$mounts, 'addMount']);
485
+                    }
486
+                }
487
+            });
488
+        }
489
+    }
490
+
491
+    /**
492
+     * get the default filesystem view
493
+     *
494
+     * @return View
495
+     */
496
+    public static function getView() {
497
+        return self::$defaultInstance;
498
+    }
499
+
500
+    /**
501
+     * tear down the filesystem, removing all storage providers
502
+     */
503
+    public static function tearDown() {
504
+        self::clearMounts();
505
+        self::$defaultInstance = null;
506
+    }
507
+
508
+    /**
509
+     * get the relative path of the root data directory for the current user
510
+     *
511
+     * @return string
512
+     *
513
+     * Returns path like /admin/files
514
+     */
515
+    public static function getRoot() {
516
+        if (!self::$defaultInstance) {
517
+            return null;
518
+        }
519
+        return self::$defaultInstance->getRoot();
520
+    }
521
+
522
+    /**
523
+     * clear all mounts and storage backends
524
+     */
525
+    public static function clearMounts() {
526
+        if (self::$mounts) {
527
+            self::$usersSetup = [];
528
+            self::$mounts->clear();
529
+        }
530
+    }
531
+
532
+    /**
533
+     * mount an \OC\Files\Storage\Storage in our virtual filesystem
534
+     *
535
+     * @param \OC\Files\Storage\Storage|string $class
536
+     * @param array $arguments
537
+     * @param string $mountpoint
538
+     */
539
+    public static function mount($class, $arguments, $mountpoint) {
540
+        if (!self::$mounts) {
541
+            \OC_Util::setupFS();
542
+        }
543
+        $mount = new Mount\MountPoint($class, $mountpoint, $arguments, self::getLoader());
544
+        self::$mounts->addMount($mount);
545
+    }
546
+
547
+    /**
548
+     * return the path to a local version of the file
549
+     * we need this because we can't know if a file is stored local or not from
550
+     * outside the filestorage and for some purposes a local file is needed
551
+     *
552
+     * @param string $path
553
+     * @return string
554
+     */
555
+    public static function getLocalFile($path) {
556
+        return self::$defaultInstance->getLocalFile($path);
557
+    }
558
+
559
+    /**
560
+     * @param string $path
561
+     * @return string
562
+     */
563
+    public static function getLocalFolder($path) {
564
+        return self::$defaultInstance->getLocalFolder($path);
565
+    }
566
+
567
+    /**
568
+     * return path to file which reflects one visible in browser
569
+     *
570
+     * @param string $path
571
+     * @return string
572
+     */
573
+    public static function getLocalPath($path) {
574
+        $datadir = \OC_User::getHome(\OC_User::getUser()) . '/files';
575
+        $newpath = $path;
576
+        if (strncmp($newpath, $datadir, strlen($datadir)) == 0) {
577
+            $newpath = substr($path, strlen($datadir));
578
+        }
579
+        return $newpath;
580
+    }
581
+
582
+    /**
583
+     * check if the requested path is valid
584
+     *
585
+     * @param string $path
586
+     * @return bool
587
+     */
588
+    public static function isValidPath($path) {
589
+        $path = self::normalizePath($path);
590
+        if (!$path || $path[0] !== '/') {
591
+            $path = '/' . $path;
592
+        }
593
+        if (strpos($path, '/../') !== false || strrchr($path, '/') === '/..') {
594
+            return false;
595
+        }
596
+        return true;
597
+    }
598
+
599
+    /**
600
+     * checks if a file is blacklisted for storage in the filesystem
601
+     * Listens to write and rename hooks
602
+     *
603
+     * @param array $data from hook
604
+     */
605
+    public static function isBlacklisted($data) {
606
+        if (isset($data['path'])) {
607
+            $path = $data['path'];
608
+        } elseif (isset($data['newpath'])) {
609
+            $path = $data['newpath'];
610
+        }
611
+        if (isset($path)) {
612
+            if (self::isFileBlacklisted($path)) {
613
+                $data['run'] = false;
614
+            }
615
+        }
616
+    }
617
+
618
+    /**
619
+     * @param string $filename
620
+     * @return bool
621
+     */
622
+    public static function isFileBlacklisted($filename) {
623
+        $filename = self::normalizePath($filename);
624
+
625
+        $blacklist = \OC::$server->getConfig()->getSystemValue('blacklisted_files', ['.htaccess']);
626
+        $filename = strtolower(basename($filename));
627
+        return in_array($filename, $blacklist);
628
+    }
629
+
630
+    /**
631
+     * check if the directory should be ignored when scanning
632
+     * NOTE: the special directories . and .. would cause never ending recursion
633
+     *
634
+     * @param string $dir
635
+     * @return boolean
636
+     */
637
+    public static function isIgnoredDir($dir) {
638
+        if ($dir === '.' || $dir === '..') {
639
+            return true;
640
+        }
641
+        return false;
642
+    }
643
+
644
+    /**
645
+     * following functions are equivalent to their php builtin equivalents for arguments/return values.
646
+     */
647
+    public static function mkdir($path) {
648
+        return self::$defaultInstance->mkdir($path);
649
+    }
650
+
651
+    public static function rmdir($path) {
652
+        return self::$defaultInstance->rmdir($path);
653
+    }
654
+
655
+    public static function is_dir($path) {
656
+        return self::$defaultInstance->is_dir($path);
657
+    }
658
+
659
+    public static function is_file($path) {
660
+        return self::$defaultInstance->is_file($path);
661
+    }
662
+
663
+    public static function stat($path) {
664
+        return self::$defaultInstance->stat($path);
665
+    }
666
+
667
+    public static function filetype($path) {
668
+        return self::$defaultInstance->filetype($path);
669
+    }
670
+
671
+    public static function filesize($path) {
672
+        return self::$defaultInstance->filesize($path);
673
+    }
674
+
675
+    public static function readfile($path) {
676
+        return self::$defaultInstance->readfile($path);
677
+    }
678
+
679
+    public static function isCreatable($path) {
680
+        return self::$defaultInstance->isCreatable($path);
681
+    }
682
+
683
+    public static function isReadable($path) {
684
+        return self::$defaultInstance->isReadable($path);
685
+    }
686
+
687
+    public static function isUpdatable($path) {
688
+        return self::$defaultInstance->isUpdatable($path);
689
+    }
690
+
691
+    public static function isDeletable($path) {
692
+        return self::$defaultInstance->isDeletable($path);
693
+    }
694
+
695
+    public static function isSharable($path) {
696
+        return self::$defaultInstance->isSharable($path);
697
+    }
698
+
699
+    public static function file_exists($path) {
700
+        return self::$defaultInstance->file_exists($path);
701
+    }
702
+
703
+    public static function filemtime($path) {
704
+        return self::$defaultInstance->filemtime($path);
705
+    }
706
+
707
+    public static function touch($path, $mtime = null) {
708
+        return self::$defaultInstance->touch($path, $mtime);
709
+    }
710
+
711
+    /**
712
+     * @return string
713
+     */
714
+    public static function file_get_contents($path) {
715
+        return self::$defaultInstance->file_get_contents($path);
716
+    }
717
+
718
+    public static function file_put_contents($path, $data) {
719
+        return self::$defaultInstance->file_put_contents($path, $data);
720
+    }
721
+
722
+    public static function unlink($path) {
723
+        return self::$defaultInstance->unlink($path);
724
+    }
725
+
726
+    public static function rename($path1, $path2) {
727
+        return self::$defaultInstance->rename($path1, $path2);
728
+    }
729
+
730
+    public static function copy($path1, $path2) {
731
+        return self::$defaultInstance->copy($path1, $path2);
732
+    }
733
+
734
+    public static function fopen($path, $mode) {
735
+        return self::$defaultInstance->fopen($path, $mode);
736
+    }
737
+
738
+    /**
739
+     * @return string
740
+     */
741
+    public static function toTmpFile($path) {
742
+        return self::$defaultInstance->toTmpFile($path);
743
+    }
744
+
745
+    public static function fromTmpFile($tmpFile, $path) {
746
+        return self::$defaultInstance->fromTmpFile($tmpFile, $path);
747
+    }
748
+
749
+    public static function getMimeType($path) {
750
+        return self::$defaultInstance->getMimeType($path);
751
+    }
752
+
753
+    public static function hash($type, $path, $raw = false) {
754
+        return self::$defaultInstance->hash($type, $path, $raw);
755
+    }
756
+
757
+    public static function free_space($path = '/') {
758
+        return self::$defaultInstance->free_space($path);
759
+    }
760
+
761
+    public static function search($query) {
762
+        return self::$defaultInstance->search($query);
763
+    }
764
+
765
+    /**
766
+     * @param string $query
767
+     */
768
+    public static function searchByMime($query) {
769
+        return self::$defaultInstance->searchByMime($query);
770
+    }
771
+
772
+    /**
773
+     * @param string|int $tag name or tag id
774
+     * @param string $userId owner of the tags
775
+     * @return FileInfo[] array or file info
776
+     */
777
+    public static function searchByTag($tag, $userId) {
778
+        return self::$defaultInstance->searchByTag($tag, $userId);
779
+    }
780
+
781
+    /**
782
+     * check if a file or folder has been updated since $time
783
+     *
784
+     * @param string $path
785
+     * @param int $time
786
+     * @return bool
787
+     */
788
+    public static function hasUpdated($path, $time) {
789
+        return self::$defaultInstance->hasUpdated($path, $time);
790
+    }
791
+
792
+    /**
793
+     * Fix common problems with a file path
794
+     *
795
+     * @param string $path
796
+     * @param bool $stripTrailingSlash whether to strip the trailing slash
797
+     * @param bool $isAbsolutePath whether the given path is absolute
798
+     * @param bool $keepUnicode true to disable unicode normalization
799
+     * @return string
800
+     */
801
+    public static function normalizePath($path, $stripTrailingSlash = true, $isAbsolutePath = false, $keepUnicode = false) {
802
+        if (is_null(self::$normalizedPathCache)) {
803
+            self::$normalizedPathCache = new CappedMemoryCache(2048);
804
+        }
805
+
806
+        /**
807
+         * FIXME: This is a workaround for existing classes and files which call
808
+         *        this function with another type than a valid string. This
809
+         *        conversion should get removed as soon as all existing
810
+         *        function calls have been fixed.
811
+         */
812
+        $path = (string)$path;
813
+
814
+        $cacheKey = json_encode([$path, $stripTrailingSlash, $isAbsolutePath, $keepUnicode]);
815
+
816
+        if (isset(self::$normalizedPathCache[$cacheKey])) {
817
+            return self::$normalizedPathCache[$cacheKey];
818
+        }
819
+
820
+        if ($path === '') {
821
+            return '/';
822
+        }
823
+
824
+        //normalize unicode if possible
825
+        if (!$keepUnicode) {
826
+            $path = \OC_Util::normalizeUnicode($path);
827
+        }
828
+
829
+        //add leading slash, if it is already there we strip it anyway
830
+        $path = '/' . $path;
831
+
832
+        $patterns = [
833
+            '/\\\\/s',          // no windows style slashes
834
+            '/\/\.(\/\.)?\//s', // remove '/./'
835
+            '/\/{2,}/s',        // remove sequence of slashes
836
+            '/\/\.$/s',         // remove trailing /.
837
+        ];
838
+
839
+        do {
840
+            $count = 0;
841
+            $path = preg_replace($patterns, '/', $path, -1, $count);
842
+        } while ($count > 0);
843
+
844
+        //remove trailing slash
845
+        if ($stripTrailingSlash && strlen($path) > 1) {
846
+            $path = rtrim($path, '/');
847
+        }
848
+
849
+        self::$normalizedPathCache[$cacheKey] = $path;
850
+
851
+        return $path;
852
+    }
853
+
854
+    /**
855
+     * get the filesystem info
856
+     *
857
+     * @param string $path
858
+     * @param boolean $includeMountPoints whether to add mountpoint sizes,
859
+     * defaults to true
860
+     * @return \OC\Files\FileInfo|bool False if file does not exist
861
+     */
862
+    public static function getFileInfo($path, $includeMountPoints = true) {
863
+        return self::$defaultInstance->getFileInfo($path, $includeMountPoints);
864
+    }
865
+
866
+    /**
867
+     * change file metadata
868
+     *
869
+     * @param string $path
870
+     * @param array $data
871
+     * @return int
872
+     *
873
+     * returns the fileid of the updated file
874
+     */
875
+    public static function putFileInfo($path, $data) {
876
+        return self::$defaultInstance->putFileInfo($path, $data);
877
+    }
878
+
879
+    /**
880
+     * get the content of a directory
881
+     *
882
+     * @param string $directory path under datadirectory
883
+     * @param string $mimetype_filter limit returned content to this mimetype or mimepart
884
+     * @return \OC\Files\FileInfo[]
885
+     */
886
+    public static function getDirectoryContent($directory, $mimetype_filter = '') {
887
+        return self::$defaultInstance->getDirectoryContent($directory, $mimetype_filter);
888
+    }
889
+
890
+    /**
891
+     * Get the path of a file by id
892
+     *
893
+     * Note that the resulting path is not guaranteed to be unique for the id, multiple paths can point to the same file
894
+     *
895
+     * @param int $id
896
+     * @throws NotFoundException
897
+     * @return string
898
+     */
899
+    public static function getPath($id) {
900
+        return self::$defaultInstance->getPath($id);
901
+    }
902
+
903
+    /**
904
+     * Get the owner for a file or folder
905
+     *
906
+     * @param string $path
907
+     * @return string
908
+     */
909
+    public static function getOwner($path) {
910
+        return self::$defaultInstance->getOwner($path);
911
+    }
912
+
913
+    /**
914
+     * get the ETag for a file or folder
915
+     *
916
+     * @param string $path
917
+     * @return string
918
+     */
919
+    public static function getETag($path) {
920
+        return self::$defaultInstance->getETag($path);
921
+    }
922 922
 }
Please login to merge, or discard this patch.