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