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