Completed
Push — master ( 8af5e0...ebf9cb )
by
unknown
43:55
created
lib/private/Files/Filesystem.php 1 patch
Indentation   +676 added lines, -676 removed lines patch added patch discarded remove patch
@@ -20,680 +20,680 @@
 block discarded – undo
20 20
 use Psr\Log\LoggerInterface;
21 21
 
22 22
 class Filesystem {
23
-	private static ?Mount\Manager $mounts = null;
24
-
25
-	public static bool $loaded = false;
26
-
27
-	private static ?View $defaultInstance = null;
28
-
29
-	private static ?FilenameValidator $validator = null;
30
-
31
-	/**
32
-	 * classname which used for hooks handling
33
-	 * used as signalclass in OC_Hooks::emit()
34
-	 */
35
-	public const CLASSNAME = 'OC_Filesystem';
36
-
37
-	/**
38
-	 * signalname emitted before file renaming
39
-	 *
40
-	 * @param string $oldpath
41
-	 * @param string $newpath
42
-	 */
43
-	public const signal_rename = 'rename';
44
-
45
-	/**
46
-	 * signal emitted after file renaming
47
-	 *
48
-	 * @param string $oldpath
49
-	 * @param string $newpath
50
-	 */
51
-	public const signal_post_rename = 'post_rename';
52
-
53
-	/**
54
-	 * signal emitted before file/dir creation
55
-	 *
56
-	 * @param string $path
57
-	 * @param bool $run changing this flag to false in hook handler will cancel event
58
-	 */
59
-	public const signal_create = 'create';
60
-
61
-	/**
62
-	 * signal emitted after file/dir creation
63
-	 *
64
-	 * @param string $path
65
-	 * @param bool $run changing this flag to false in hook handler will cancel event
66
-	 */
67
-	public const signal_post_create = 'post_create';
68
-
69
-	/**
70
-	 * signal emits before file/dir copy
71
-	 *
72
-	 * @param string $oldpath
73
-	 * @param string $newpath
74
-	 * @param bool $run changing this flag to false in hook handler will cancel event
75
-	 */
76
-	public const signal_copy = 'copy';
77
-
78
-	/**
79
-	 * signal emits after file/dir copy
80
-	 *
81
-	 * @param string $oldpath
82
-	 * @param string $newpath
83
-	 */
84
-	public const signal_post_copy = 'post_copy';
85
-
86
-	/**
87
-	 * signal emits before file/dir save
88
-	 *
89
-	 * @param string $path
90
-	 * @param bool $run changing this flag to false in hook handler will cancel event
91
-	 */
92
-	public const signal_write = 'write';
93
-
94
-	/**
95
-	 * signal emits after file/dir save
96
-	 *
97
-	 * @param string $path
98
-	 */
99
-	public const signal_post_write = 'post_write';
100
-
101
-	/**
102
-	 * signal emitted before file/dir update
103
-	 *
104
-	 * @param string $path
105
-	 * @param bool $run changing this flag to false in hook handler will cancel event
106
-	 */
107
-	public const signal_update = 'update';
108
-
109
-	/**
110
-	 * signal emitted after file/dir update
111
-	 *
112
-	 * @param string $path
113
-	 * @param bool $run changing this flag to false in hook handler will cancel event
114
-	 */
115
-	public const signal_post_update = 'post_update';
116
-
117
-	/**
118
-	 * signal emits when reading file/dir
119
-	 *
120
-	 * @param string $path
121
-	 */
122
-	public const signal_read = 'read';
123
-
124
-	/**
125
-	 * signal emits when removing file/dir
126
-	 *
127
-	 * @param string $path
128
-	 */
129
-	public const signal_delete = 'delete';
130
-
131
-	/**
132
-	 * parameters definitions for signals
133
-	 */
134
-	public const signal_param_path = 'path';
135
-	public const signal_param_oldpath = 'oldpath';
136
-	public const signal_param_newpath = 'newpath';
137
-
138
-	/**
139
-	 * run - changing this flag to false in hook handler will cancel event
140
-	 */
141
-	public const signal_param_run = 'run';
142
-
143
-	public const signal_create_mount = 'create_mount';
144
-	public const signal_delete_mount = 'delete_mount';
145
-	public const signal_param_mount_type = 'mounttype';
146
-	public const signal_param_users = 'users';
147
-
148
-	private static ?\OC\Files\Storage\StorageFactory $loader = null;
149
-
150
-	private static bool $logWarningWhenAddingStorageWrapper = true;
151
-
152
-	/**
153
-	 * @param bool $shouldLog
154
-	 * @return bool previous value
155
-	 * @internal
156
-	 */
157
-	public static function logWarningWhenAddingStorageWrapper(bool $shouldLog): bool {
158
-		$previousValue = self::$logWarningWhenAddingStorageWrapper;
159
-		self::$logWarningWhenAddingStorageWrapper = $shouldLog;
160
-		return $previousValue;
161
-	}
162
-
163
-	/**
164
-	 * @param string $wrapperName
165
-	 * @param callable $wrapper
166
-	 * @param int $priority
167
-	 */
168
-	public static function addStorageWrapper($wrapperName, $wrapper, $priority = 50) {
169
-		if (self::$logWarningWhenAddingStorageWrapper) {
170
-			\OCP\Server::get(LoggerInterface::class)->warning("Storage wrapper '{wrapper}' was not registered via the 'OC_Filesystem - preSetup' hook which could cause potential problems.", [
171
-				'wrapper' => $wrapperName,
172
-				'app' => 'filesystem',
173
-			]);
174
-		}
175
-
176
-		$mounts = self::getMountManager()->getAll();
177
-		/** @var StorageFactory $loader */
178
-		$loader = self::getLoader();
179
-		if (!$loader->addStorageWrapper($wrapperName, $wrapper, $priority, $mounts)) {
180
-			// do not re-wrap if storage with this name already existed
181
-			return;
182
-		}
183
-	}
184
-
185
-	/**
186
-	 * Returns the storage factory
187
-	 *
188
-	 * @return IStorageFactory
189
-	 */
190
-	public static function getLoader() {
191
-		if (!self::$loader) {
192
-			self::$loader = \OC::$server->get(IStorageFactory::class);
193
-		}
194
-		return self::$loader;
195
-	}
196
-
197
-	/**
198
-	 * Returns the mount manager
199
-	 */
200
-	public static function getMountManager(): Mount\Manager {
201
-		self::initMountManager();
202
-		assert(self::$mounts !== null);
203
-		return self::$mounts;
204
-	}
205
-
206
-	/**
207
-	 * get the mountpoint of the storage object for a path
208
-	 * ( note: because a storage is not always mounted inside the fakeroot, the
209
-	 * returned mountpoint is relative to the absolute root of the filesystem
210
-	 * and doesn't take the chroot into account )
211
-	 *
212
-	 * @param string $path
213
-	 * @return string
214
-	 */
215
-	public static function getMountPoint($path) {
216
-		if (!self::$mounts) {
217
-			\OC_Util::setupFS();
218
-		}
219
-		$mount = self::$mounts->find($path);
220
-		return $mount->getMountPoint();
221
-	}
222
-
223
-	/**
224
-	 * get a list of all mount points in a directory
225
-	 *
226
-	 * @param string $path
227
-	 * @return string[]
228
-	 */
229
-	public static function getMountPoints($path) {
230
-		if (!self::$mounts) {
231
-			\OC_Util::setupFS();
232
-		}
233
-		$result = [];
234
-		$mounts = self::$mounts->findIn($path);
235
-		foreach ($mounts as $mount) {
236
-			$result[] = $mount->getMountPoint();
237
-		}
238
-		return $result;
239
-	}
240
-
241
-	/**
242
-	 * get the storage mounted at $mountPoint
243
-	 *
244
-	 * @param string $mountPoint
245
-	 * @return \OC\Files\Storage\Storage|null
246
-	 */
247
-	public static function getStorage($mountPoint) {
248
-		$mount = self::getMountManager()->find($mountPoint);
249
-		return $mount->getStorage();
250
-	}
251
-
252
-	/**
253
-	 * @param string $id
254
-	 * @return Mount\MountPoint[]
255
-	 */
256
-	public static function getMountByStorageId($id) {
257
-		return self::getMountManager()->findByStorageId($id);
258
-	}
259
-
260
-	/**
261
-	 * @param int $id
262
-	 * @return Mount\MountPoint[]
263
-	 */
264
-	public static function getMountByNumericId($id) {
265
-		return self::getMountManager()->findByNumericId($id);
266
-	}
267
-
268
-	/**
269
-	 * resolve a path to a storage and internal path
270
-	 *
271
-	 * @param string $path
272
-	 * @return array{?\OCP\Files\Storage\IStorage, string} an array consisting of the storage and the internal path
273
-	 */
274
-	public static function resolvePath($path): array {
275
-		$mount = self::getMountManager()->find($path);
276
-		return [$mount->getStorage(), rtrim($mount->getInternalPath($path), '/')];
277
-	}
278
-
279
-	public static function init(string|IUser|null $user, string $root): bool {
280
-		if (self::$defaultInstance) {
281
-			return false;
282
-		}
283
-		self::initInternal($root);
284
-
285
-		//load custom mount config
286
-		self::initMountPoints($user);
287
-
288
-		return true;
289
-	}
290
-
291
-	public static function initInternal(string $root): bool {
292
-		if (self::$defaultInstance) {
293
-			return false;
294
-		}
295
-		self::getLoader();
296
-		self::$defaultInstance = new View($root);
297
-		/** @var IEventDispatcher $eventDispatcher */
298
-		$eventDispatcher = \OC::$server->get(IEventDispatcher::class);
299
-		$eventDispatcher->addListener(FilesystemTornDownEvent::class, function () {
300
-			self::$defaultInstance = null;
301
-			self::$loaded = false;
302
-		});
303
-
304
-		self::initMountManager();
305
-
306
-		self::$loaded = true;
307
-
308
-		return true;
309
-	}
310
-
311
-	public static function initMountManager(): void {
312
-		if (!self::$mounts) {
313
-			self::$mounts = \OC::$server->get(IMountManager::class);
314
-		}
315
-	}
316
-
317
-	/**
318
-	 * Initialize system and personal mount points for a user
319
-	 *
320
-	 * @throws \OC\User\NoUserException if the user is not available
321
-	 */
322
-	public static function initMountPoints(string|IUser|null $user = ''): void {
323
-		/** @var IUserManager $userManager */
324
-		$userManager = \OC::$server->get(IUserManager::class);
325
-
326
-		$userObject = ($user instanceof IUser) ? $user : $userManager->get($user);
327
-		if ($userObject) {
328
-			/** @var SetupManager $setupManager */
329
-			$setupManager = \OC::$server->get(SetupManager::class);
330
-			$setupManager->setupForUser($userObject);
331
-		} else {
332
-			throw new NoUserException();
333
-		}
334
-	}
335
-
336
-	/**
337
-	 * Get the default filesystem view
338
-	 */
339
-	public static function getView(): ?View {
340
-		if (!self::$defaultInstance) {
341
-			/** @var IUserSession $session */
342
-			$session = \OC::$server->get(IUserSession::class);
343
-			$user = $session->getUser();
344
-			if ($user) {
345
-				$userDir = '/' . $user->getUID() . '/files';
346
-				self::initInternal($userDir);
347
-			}
348
-		}
349
-		return self::$defaultInstance;
350
-	}
351
-
352
-	/**
353
-	 * tear down the filesystem, removing all storage providers
354
-	 */
355
-	public static function tearDown() {
356
-		\OC_Util::tearDownFS();
357
-	}
358
-
359
-	/**
360
-	 * get the relative path of the root data directory for the current user
361
-	 *
362
-	 * @return ?string
363
-	 *
364
-	 * Returns path like /admin/files
365
-	 */
366
-	public static function getRoot() {
367
-		if (!self::$defaultInstance) {
368
-			return null;
369
-		}
370
-		return self::$defaultInstance->getRoot();
371
-	}
372
-
373
-	/**
374
-	 * mount an \OC\Files\Storage\Storage in our virtual filesystem
375
-	 *
376
-	 * @param \OC\Files\Storage\Storage|string $class
377
-	 * @param array $arguments
378
-	 * @param string $mountpoint
379
-	 */
380
-	public static function mount($class, $arguments, $mountpoint) {
381
-		if (!self::$mounts) {
382
-			\OC_Util::setupFS();
383
-		}
384
-		$mount = new Mount\MountPoint($class, $mountpoint, $arguments, self::getLoader());
385
-		self::$mounts->addMount($mount);
386
-	}
387
-
388
-	/**
389
-	 * check if the requested path is valid
390
-	 *
391
-	 * @param string $path
392
-	 * @return bool
393
-	 */
394
-	public static function isValidPath($path) {
395
-		$path = self::normalizePath($path);
396
-		if (!$path || $path[0] !== '/') {
397
-			$path = '/' . $path;
398
-		}
399
-		if (str_contains($path, '/../') || strrchr($path, '/') === '/..') {
400
-			return false;
401
-		}
402
-		return true;
403
-	}
404
-
405
-	/**
406
-	 * @param string $filename
407
-	 * @return bool
408
-	 *
409
-	 * @deprecated 30.0.0 - use \OC\Files\FilenameValidator::isForbidden
410
-	 */
411
-	public static function isFileBlacklisted($filename) {
412
-		if (self::$validator === null) {
413
-			self::$validator = \OCP\Server::get(FilenameValidator::class);
414
-		}
415
-
416
-		$filename = self::normalizePath($filename);
417
-		return self::$validator->isForbidden($filename);
418
-	}
419
-
420
-	/**
421
-	 * check if the directory should be ignored when scanning
422
-	 * NOTE: the special directories . and .. would cause never ending recursion
423
-	 *
424
-	 * @param string $dir
425
-	 * @return boolean
426
-	 */
427
-	public static function isIgnoredDir($dir) {
428
-		if ($dir === '.' || $dir === '..') {
429
-			return true;
430
-		}
431
-		return false;
432
-	}
433
-
434
-	/**
435
-	 * following functions are equivalent to their php builtin equivalents for arguments/return values.
436
-	 */
437
-	public static function mkdir($path) {
438
-		return self::$defaultInstance->mkdir($path);
439
-	}
440
-
441
-	public static function rmdir($path) {
442
-		return self::$defaultInstance->rmdir($path);
443
-	}
444
-
445
-	public static function is_dir($path) {
446
-		return self::$defaultInstance->is_dir($path);
447
-	}
448
-
449
-	public static function is_file($path) {
450
-		return self::$defaultInstance->is_file($path);
451
-	}
452
-
453
-	public static function stat($path) {
454
-		return self::$defaultInstance->stat($path);
455
-	}
456
-
457
-	public static function filetype($path) {
458
-		return self::$defaultInstance->filetype($path);
459
-	}
460
-
461
-	public static function filesize($path) {
462
-		return self::$defaultInstance->filesize($path);
463
-	}
464
-
465
-	public static function readfile($path) {
466
-		return self::$defaultInstance->readfile($path);
467
-	}
468
-
469
-	public static function isCreatable($path) {
470
-		return self::$defaultInstance->isCreatable($path);
471
-	}
472
-
473
-	public static function isReadable($path) {
474
-		return self::$defaultInstance->isReadable($path);
475
-	}
476
-
477
-	public static function isUpdatable($path) {
478
-		return self::$defaultInstance->isUpdatable($path);
479
-	}
480
-
481
-	public static function isDeletable($path) {
482
-		return self::$defaultInstance->isDeletable($path);
483
-	}
484
-
485
-	public static function isSharable($path) {
486
-		return self::$defaultInstance->isSharable($path);
487
-	}
488
-
489
-	public static function file_exists($path) {
490
-		return self::$defaultInstance->file_exists($path);
491
-	}
492
-
493
-	public static function filemtime($path) {
494
-		return self::$defaultInstance->filemtime($path);
495
-	}
496
-
497
-	public static function touch($path, $mtime = null) {
498
-		return self::$defaultInstance->touch($path, $mtime);
499
-	}
500
-
501
-	/**
502
-	 * @return string|false
503
-	 */
504
-	public static function file_get_contents($path) {
505
-		return self::$defaultInstance->file_get_contents($path);
506
-	}
507
-
508
-	public static function file_put_contents($path, $data) {
509
-		return self::$defaultInstance->file_put_contents($path, $data);
510
-	}
511
-
512
-	public static function unlink($path) {
513
-		return self::$defaultInstance->unlink($path);
514
-	}
515
-
516
-	public static function rename($source, $target) {
517
-		return self::$defaultInstance->rename($source, $target);
518
-	}
519
-
520
-	public static function copy($source, $target) {
521
-		return self::$defaultInstance->copy($source, $target);
522
-	}
523
-
524
-	public static function fopen($path, $mode) {
525
-		return self::$defaultInstance->fopen($path, $mode);
526
-	}
527
-
528
-	/**
529
-	 * @param string $path
530
-	 * @throws \OCP\Files\InvalidPathException
531
-	 */
532
-	public static function toTmpFile($path): string|false {
533
-		return self::$defaultInstance->toTmpFile($path);
534
-	}
535
-
536
-	public static function fromTmpFile($tmpFile, $path) {
537
-		return self::$defaultInstance->fromTmpFile($tmpFile, $path);
538
-	}
539
-
540
-	public static function getMimeType($path) {
541
-		return self::$defaultInstance->getMimeType($path);
542
-	}
543
-
544
-	public static function hash($type, $path, $raw = false) {
545
-		return self::$defaultInstance->hash($type, $path, $raw);
546
-	}
547
-
548
-	public static function free_space($path = '/') {
549
-		return self::$defaultInstance->free_space($path);
550
-	}
551
-
552
-	public static function search($query) {
553
-		return self::$defaultInstance->search($query);
554
-	}
555
-
556
-	/**
557
-	 * @param string $query
558
-	 */
559
-	public static function searchByMime($query) {
560
-		return self::$defaultInstance->searchByMime($query);
561
-	}
562
-
563
-	/**
564
-	 * @param string|int $tag name or tag id
565
-	 * @param string $userId owner of the tags
566
-	 * @return FileInfo[] array or file info
567
-	 */
568
-	public static function searchByTag($tag, $userId) {
569
-		return self::$defaultInstance->searchByTag($tag, $userId);
570
-	}
571
-
572
-	/**
573
-	 * check if a file or folder has been updated since $time
574
-	 *
575
-	 * @param string $path
576
-	 * @param int $time
577
-	 * @return bool
578
-	 */
579
-	public static function hasUpdated($path, $time) {
580
-		return self::$defaultInstance->hasUpdated($path, $time);
581
-	}
582
-
583
-	/**
584
-	 * Fix common problems with a file path
585
-	 *
586
-	 * @param string $path
587
-	 * @param bool $stripTrailingSlash whether to strip the trailing slash
588
-	 * @param bool $isAbsolutePath whether the given path is absolute
589
-	 * @param bool $keepUnicode true to disable unicode normalization
590
-	 * @psalm-taint-escape file
591
-	 * @return string
592
-	 */
593
-	public static function normalizePath($path, $stripTrailingSlash = true, $isAbsolutePath = false, $keepUnicode = false) {
594
-		/**
595
-		 * FIXME: This is a workaround for existing classes and files which call
596
-		 *        this function with another type than a valid string. This
597
-		 *        conversion should get removed as soon as all existing
598
-		 *        function calls have been fixed.
599
-		 */
600
-		$path = (string)$path;
601
-
602
-		if ($path === '') {
603
-			return '/';
604
-		}
605
-
606
-		//normalize unicode if possible
607
-		if (!$keepUnicode) {
608
-			$path = \OC_Util::normalizeUnicode($path);
609
-		}
610
-
611
-		//add leading slash, if it is already there we strip it anyway
612
-		$path = '/' . $path;
613
-
614
-		$patterns = [
615
-			'#\\\\#s',       // no windows style '\\' slashes
616
-			'#/\.(/\.)*/#s', // remove '/./'
617
-			'#\//+#s',       // remove sequence of slashes
618
-			'#/\.$#s',       // remove trailing '/.'
619
-		];
620
-
621
-		do {
622
-			$count = 0;
623
-			$path = preg_replace($patterns, '/', $path, -1, $count);
624
-		} while ($count > 0);
625
-
626
-		//remove trailing slash
627
-		if ($stripTrailingSlash && strlen($path) > 1) {
628
-			$path = rtrim($path, '/');
629
-		}
630
-
631
-		return $path;
632
-	}
633
-
634
-	/**
635
-	 * get the filesystem info
636
-	 *
637
-	 * @param string $path
638
-	 * @param bool|string $includeMountPoints whether to add mountpoint sizes,
639
-	 *                                        defaults to true
640
-	 * @return \OC\Files\FileInfo|false False if file does not exist
641
-	 */
642
-	public static function getFileInfo($path, $includeMountPoints = true) {
643
-		return self::getView()->getFileInfo($path, $includeMountPoints);
644
-	}
645
-
646
-	/**
647
-	 * change file metadata
648
-	 *
649
-	 * @param string $path
650
-	 * @param array $data
651
-	 * @return int
652
-	 *
653
-	 * returns the fileid of the updated file
654
-	 */
655
-	public static function putFileInfo($path, $data) {
656
-		return self::$defaultInstance->putFileInfo($path, $data);
657
-	}
658
-
659
-	/**
660
-	 * get the content of a directory
661
-	 *
662
-	 * @param string $directory path under datadirectory
663
-	 * @param string $mimetype_filter limit returned content to this mimetype or mimepart
664
-	 * @return \OC\Files\FileInfo[]
665
-	 */
666
-	public static function getDirectoryContent($directory, $mimetype_filter = '') {
667
-		return self::$defaultInstance->getDirectoryContent($directory, $mimetype_filter);
668
-	}
669
-
670
-	/**
671
-	 * Get the path of a file by id
672
-	 *
673
-	 * Note that the resulting path is not guaranteed to be unique for the id, multiple paths can point to the same file
674
-	 *
675
-	 * @param int $id
676
-	 * @throws NotFoundException
677
-	 * @return string
678
-	 */
679
-	public static function getPath($id) {
680
-		return self::$defaultInstance->getPath($id);
681
-	}
682
-
683
-	/**
684
-	 * Get the owner for a file or folder
685
-	 *
686
-	 * @param string $path
687
-	 * @return string
688
-	 */
689
-	public static function getOwner($path) {
690
-		return self::$defaultInstance->getOwner($path);
691
-	}
692
-
693
-	/**
694
-	 * get the ETag for a file or folder
695
-	 */
696
-	public static function getETag(string $path): string|false {
697
-		return self::$defaultInstance->getETag($path);
698
-	}
23
+    private static ?Mount\Manager $mounts = null;
24
+
25
+    public static bool $loaded = false;
26
+
27
+    private static ?View $defaultInstance = null;
28
+
29
+    private static ?FilenameValidator $validator = null;
30
+
31
+    /**
32
+     * classname which used for hooks handling
33
+     * used as signalclass in OC_Hooks::emit()
34
+     */
35
+    public const CLASSNAME = 'OC_Filesystem';
36
+
37
+    /**
38
+     * signalname emitted before file renaming
39
+     *
40
+     * @param string $oldpath
41
+     * @param string $newpath
42
+     */
43
+    public const signal_rename = 'rename';
44
+
45
+    /**
46
+     * signal emitted after file renaming
47
+     *
48
+     * @param string $oldpath
49
+     * @param string $newpath
50
+     */
51
+    public const signal_post_rename = 'post_rename';
52
+
53
+    /**
54
+     * signal emitted before file/dir creation
55
+     *
56
+     * @param string $path
57
+     * @param bool $run changing this flag to false in hook handler will cancel event
58
+     */
59
+    public const signal_create = 'create';
60
+
61
+    /**
62
+     * signal emitted after file/dir creation
63
+     *
64
+     * @param string $path
65
+     * @param bool $run changing this flag to false in hook handler will cancel event
66
+     */
67
+    public const signal_post_create = 'post_create';
68
+
69
+    /**
70
+     * signal emits before file/dir copy
71
+     *
72
+     * @param string $oldpath
73
+     * @param string $newpath
74
+     * @param bool $run changing this flag to false in hook handler will cancel event
75
+     */
76
+    public const signal_copy = 'copy';
77
+
78
+    /**
79
+     * signal emits after file/dir copy
80
+     *
81
+     * @param string $oldpath
82
+     * @param string $newpath
83
+     */
84
+    public const signal_post_copy = 'post_copy';
85
+
86
+    /**
87
+     * signal emits before file/dir save
88
+     *
89
+     * @param string $path
90
+     * @param bool $run changing this flag to false in hook handler will cancel event
91
+     */
92
+    public const signal_write = 'write';
93
+
94
+    /**
95
+     * signal emits after file/dir save
96
+     *
97
+     * @param string $path
98
+     */
99
+    public const signal_post_write = 'post_write';
100
+
101
+    /**
102
+     * signal emitted before file/dir update
103
+     *
104
+     * @param string $path
105
+     * @param bool $run changing this flag to false in hook handler will cancel event
106
+     */
107
+    public const signal_update = 'update';
108
+
109
+    /**
110
+     * signal emitted after file/dir update
111
+     *
112
+     * @param string $path
113
+     * @param bool $run changing this flag to false in hook handler will cancel event
114
+     */
115
+    public const signal_post_update = 'post_update';
116
+
117
+    /**
118
+     * signal emits when reading file/dir
119
+     *
120
+     * @param string $path
121
+     */
122
+    public const signal_read = 'read';
123
+
124
+    /**
125
+     * signal emits when removing file/dir
126
+     *
127
+     * @param string $path
128
+     */
129
+    public const signal_delete = 'delete';
130
+
131
+    /**
132
+     * parameters definitions for signals
133
+     */
134
+    public const signal_param_path = 'path';
135
+    public const signal_param_oldpath = 'oldpath';
136
+    public const signal_param_newpath = 'newpath';
137
+
138
+    /**
139
+     * run - changing this flag to false in hook handler will cancel event
140
+     */
141
+    public const signal_param_run = 'run';
142
+
143
+    public const signal_create_mount = 'create_mount';
144
+    public const signal_delete_mount = 'delete_mount';
145
+    public const signal_param_mount_type = 'mounttype';
146
+    public const signal_param_users = 'users';
147
+
148
+    private static ?\OC\Files\Storage\StorageFactory $loader = null;
149
+
150
+    private static bool $logWarningWhenAddingStorageWrapper = true;
151
+
152
+    /**
153
+     * @param bool $shouldLog
154
+     * @return bool previous value
155
+     * @internal
156
+     */
157
+    public static function logWarningWhenAddingStorageWrapper(bool $shouldLog): bool {
158
+        $previousValue = self::$logWarningWhenAddingStorageWrapper;
159
+        self::$logWarningWhenAddingStorageWrapper = $shouldLog;
160
+        return $previousValue;
161
+    }
162
+
163
+    /**
164
+     * @param string $wrapperName
165
+     * @param callable $wrapper
166
+     * @param int $priority
167
+     */
168
+    public static function addStorageWrapper($wrapperName, $wrapper, $priority = 50) {
169
+        if (self::$logWarningWhenAddingStorageWrapper) {
170
+            \OCP\Server::get(LoggerInterface::class)->warning("Storage wrapper '{wrapper}' was not registered via the 'OC_Filesystem - preSetup' hook which could cause potential problems.", [
171
+                'wrapper' => $wrapperName,
172
+                'app' => 'filesystem',
173
+            ]);
174
+        }
175
+
176
+        $mounts = self::getMountManager()->getAll();
177
+        /** @var StorageFactory $loader */
178
+        $loader = self::getLoader();
179
+        if (!$loader->addStorageWrapper($wrapperName, $wrapper, $priority, $mounts)) {
180
+            // do not re-wrap if storage with this name already existed
181
+            return;
182
+        }
183
+    }
184
+
185
+    /**
186
+     * Returns the storage factory
187
+     *
188
+     * @return IStorageFactory
189
+     */
190
+    public static function getLoader() {
191
+        if (!self::$loader) {
192
+            self::$loader = \OC::$server->get(IStorageFactory::class);
193
+        }
194
+        return self::$loader;
195
+    }
196
+
197
+    /**
198
+     * Returns the mount manager
199
+     */
200
+    public static function getMountManager(): Mount\Manager {
201
+        self::initMountManager();
202
+        assert(self::$mounts !== null);
203
+        return self::$mounts;
204
+    }
205
+
206
+    /**
207
+     * get the mountpoint of the storage object for a path
208
+     * ( note: because a storage is not always mounted inside the fakeroot, the
209
+     * returned mountpoint is relative to the absolute root of the filesystem
210
+     * and doesn't take the chroot into account )
211
+     *
212
+     * @param string $path
213
+     * @return string
214
+     */
215
+    public static function getMountPoint($path) {
216
+        if (!self::$mounts) {
217
+            \OC_Util::setupFS();
218
+        }
219
+        $mount = self::$mounts->find($path);
220
+        return $mount->getMountPoint();
221
+    }
222
+
223
+    /**
224
+     * get a list of all mount points in a directory
225
+     *
226
+     * @param string $path
227
+     * @return string[]
228
+     */
229
+    public static function getMountPoints($path) {
230
+        if (!self::$mounts) {
231
+            \OC_Util::setupFS();
232
+        }
233
+        $result = [];
234
+        $mounts = self::$mounts->findIn($path);
235
+        foreach ($mounts as $mount) {
236
+            $result[] = $mount->getMountPoint();
237
+        }
238
+        return $result;
239
+    }
240
+
241
+    /**
242
+     * get the storage mounted at $mountPoint
243
+     *
244
+     * @param string $mountPoint
245
+     * @return \OC\Files\Storage\Storage|null
246
+     */
247
+    public static function getStorage($mountPoint) {
248
+        $mount = self::getMountManager()->find($mountPoint);
249
+        return $mount->getStorage();
250
+    }
251
+
252
+    /**
253
+     * @param string $id
254
+     * @return Mount\MountPoint[]
255
+     */
256
+    public static function getMountByStorageId($id) {
257
+        return self::getMountManager()->findByStorageId($id);
258
+    }
259
+
260
+    /**
261
+     * @param int $id
262
+     * @return Mount\MountPoint[]
263
+     */
264
+    public static function getMountByNumericId($id) {
265
+        return self::getMountManager()->findByNumericId($id);
266
+    }
267
+
268
+    /**
269
+     * resolve a path to a storage and internal path
270
+     *
271
+     * @param string $path
272
+     * @return array{?\OCP\Files\Storage\IStorage, string} an array consisting of the storage and the internal path
273
+     */
274
+    public static function resolvePath($path): array {
275
+        $mount = self::getMountManager()->find($path);
276
+        return [$mount->getStorage(), rtrim($mount->getInternalPath($path), '/')];
277
+    }
278
+
279
+    public static function init(string|IUser|null $user, string $root): bool {
280
+        if (self::$defaultInstance) {
281
+            return false;
282
+        }
283
+        self::initInternal($root);
284
+
285
+        //load custom mount config
286
+        self::initMountPoints($user);
287
+
288
+        return true;
289
+    }
290
+
291
+    public static function initInternal(string $root): bool {
292
+        if (self::$defaultInstance) {
293
+            return false;
294
+        }
295
+        self::getLoader();
296
+        self::$defaultInstance = new View($root);
297
+        /** @var IEventDispatcher $eventDispatcher */
298
+        $eventDispatcher = \OC::$server->get(IEventDispatcher::class);
299
+        $eventDispatcher->addListener(FilesystemTornDownEvent::class, function () {
300
+            self::$defaultInstance = null;
301
+            self::$loaded = false;
302
+        });
303
+
304
+        self::initMountManager();
305
+
306
+        self::$loaded = true;
307
+
308
+        return true;
309
+    }
310
+
311
+    public static function initMountManager(): void {
312
+        if (!self::$mounts) {
313
+            self::$mounts = \OC::$server->get(IMountManager::class);
314
+        }
315
+    }
316
+
317
+    /**
318
+     * Initialize system and personal mount points for a user
319
+     *
320
+     * @throws \OC\User\NoUserException if the user is not available
321
+     */
322
+    public static function initMountPoints(string|IUser|null $user = ''): void {
323
+        /** @var IUserManager $userManager */
324
+        $userManager = \OC::$server->get(IUserManager::class);
325
+
326
+        $userObject = ($user instanceof IUser) ? $user : $userManager->get($user);
327
+        if ($userObject) {
328
+            /** @var SetupManager $setupManager */
329
+            $setupManager = \OC::$server->get(SetupManager::class);
330
+            $setupManager->setupForUser($userObject);
331
+        } else {
332
+            throw new NoUserException();
333
+        }
334
+    }
335
+
336
+    /**
337
+     * Get the default filesystem view
338
+     */
339
+    public static function getView(): ?View {
340
+        if (!self::$defaultInstance) {
341
+            /** @var IUserSession $session */
342
+            $session = \OC::$server->get(IUserSession::class);
343
+            $user = $session->getUser();
344
+            if ($user) {
345
+                $userDir = '/' . $user->getUID() . '/files';
346
+                self::initInternal($userDir);
347
+            }
348
+        }
349
+        return self::$defaultInstance;
350
+    }
351
+
352
+    /**
353
+     * tear down the filesystem, removing all storage providers
354
+     */
355
+    public static function tearDown() {
356
+        \OC_Util::tearDownFS();
357
+    }
358
+
359
+    /**
360
+     * get the relative path of the root data directory for the current user
361
+     *
362
+     * @return ?string
363
+     *
364
+     * Returns path like /admin/files
365
+     */
366
+    public static function getRoot() {
367
+        if (!self::$defaultInstance) {
368
+            return null;
369
+        }
370
+        return self::$defaultInstance->getRoot();
371
+    }
372
+
373
+    /**
374
+     * mount an \OC\Files\Storage\Storage in our virtual filesystem
375
+     *
376
+     * @param \OC\Files\Storage\Storage|string $class
377
+     * @param array $arguments
378
+     * @param string $mountpoint
379
+     */
380
+    public static function mount($class, $arguments, $mountpoint) {
381
+        if (!self::$mounts) {
382
+            \OC_Util::setupFS();
383
+        }
384
+        $mount = new Mount\MountPoint($class, $mountpoint, $arguments, self::getLoader());
385
+        self::$mounts->addMount($mount);
386
+    }
387
+
388
+    /**
389
+     * check if the requested path is valid
390
+     *
391
+     * @param string $path
392
+     * @return bool
393
+     */
394
+    public static function isValidPath($path) {
395
+        $path = self::normalizePath($path);
396
+        if (!$path || $path[0] !== '/') {
397
+            $path = '/' . $path;
398
+        }
399
+        if (str_contains($path, '/../') || strrchr($path, '/') === '/..') {
400
+            return false;
401
+        }
402
+        return true;
403
+    }
404
+
405
+    /**
406
+     * @param string $filename
407
+     * @return bool
408
+     *
409
+     * @deprecated 30.0.0 - use \OC\Files\FilenameValidator::isForbidden
410
+     */
411
+    public static function isFileBlacklisted($filename) {
412
+        if (self::$validator === null) {
413
+            self::$validator = \OCP\Server::get(FilenameValidator::class);
414
+        }
415
+
416
+        $filename = self::normalizePath($filename);
417
+        return self::$validator->isForbidden($filename);
418
+    }
419
+
420
+    /**
421
+     * check if the directory should be ignored when scanning
422
+     * NOTE: the special directories . and .. would cause never ending recursion
423
+     *
424
+     * @param string $dir
425
+     * @return boolean
426
+     */
427
+    public static function isIgnoredDir($dir) {
428
+        if ($dir === '.' || $dir === '..') {
429
+            return true;
430
+        }
431
+        return false;
432
+    }
433
+
434
+    /**
435
+     * following functions are equivalent to their php builtin equivalents for arguments/return values.
436
+     */
437
+    public static function mkdir($path) {
438
+        return self::$defaultInstance->mkdir($path);
439
+    }
440
+
441
+    public static function rmdir($path) {
442
+        return self::$defaultInstance->rmdir($path);
443
+    }
444
+
445
+    public static function is_dir($path) {
446
+        return self::$defaultInstance->is_dir($path);
447
+    }
448
+
449
+    public static function is_file($path) {
450
+        return self::$defaultInstance->is_file($path);
451
+    }
452
+
453
+    public static function stat($path) {
454
+        return self::$defaultInstance->stat($path);
455
+    }
456
+
457
+    public static function filetype($path) {
458
+        return self::$defaultInstance->filetype($path);
459
+    }
460
+
461
+    public static function filesize($path) {
462
+        return self::$defaultInstance->filesize($path);
463
+    }
464
+
465
+    public static function readfile($path) {
466
+        return self::$defaultInstance->readfile($path);
467
+    }
468
+
469
+    public static function isCreatable($path) {
470
+        return self::$defaultInstance->isCreatable($path);
471
+    }
472
+
473
+    public static function isReadable($path) {
474
+        return self::$defaultInstance->isReadable($path);
475
+    }
476
+
477
+    public static function isUpdatable($path) {
478
+        return self::$defaultInstance->isUpdatable($path);
479
+    }
480
+
481
+    public static function isDeletable($path) {
482
+        return self::$defaultInstance->isDeletable($path);
483
+    }
484
+
485
+    public static function isSharable($path) {
486
+        return self::$defaultInstance->isSharable($path);
487
+    }
488
+
489
+    public static function file_exists($path) {
490
+        return self::$defaultInstance->file_exists($path);
491
+    }
492
+
493
+    public static function filemtime($path) {
494
+        return self::$defaultInstance->filemtime($path);
495
+    }
496
+
497
+    public static function touch($path, $mtime = null) {
498
+        return self::$defaultInstance->touch($path, $mtime);
499
+    }
500
+
501
+    /**
502
+     * @return string|false
503
+     */
504
+    public static function file_get_contents($path) {
505
+        return self::$defaultInstance->file_get_contents($path);
506
+    }
507
+
508
+    public static function file_put_contents($path, $data) {
509
+        return self::$defaultInstance->file_put_contents($path, $data);
510
+    }
511
+
512
+    public static function unlink($path) {
513
+        return self::$defaultInstance->unlink($path);
514
+    }
515
+
516
+    public static function rename($source, $target) {
517
+        return self::$defaultInstance->rename($source, $target);
518
+    }
519
+
520
+    public static function copy($source, $target) {
521
+        return self::$defaultInstance->copy($source, $target);
522
+    }
523
+
524
+    public static function fopen($path, $mode) {
525
+        return self::$defaultInstance->fopen($path, $mode);
526
+    }
527
+
528
+    /**
529
+     * @param string $path
530
+     * @throws \OCP\Files\InvalidPathException
531
+     */
532
+    public static function toTmpFile($path): string|false {
533
+        return self::$defaultInstance->toTmpFile($path);
534
+    }
535
+
536
+    public static function fromTmpFile($tmpFile, $path) {
537
+        return self::$defaultInstance->fromTmpFile($tmpFile, $path);
538
+    }
539
+
540
+    public static function getMimeType($path) {
541
+        return self::$defaultInstance->getMimeType($path);
542
+    }
543
+
544
+    public static function hash($type, $path, $raw = false) {
545
+        return self::$defaultInstance->hash($type, $path, $raw);
546
+    }
547
+
548
+    public static function free_space($path = '/') {
549
+        return self::$defaultInstance->free_space($path);
550
+    }
551
+
552
+    public static function search($query) {
553
+        return self::$defaultInstance->search($query);
554
+    }
555
+
556
+    /**
557
+     * @param string $query
558
+     */
559
+    public static function searchByMime($query) {
560
+        return self::$defaultInstance->searchByMime($query);
561
+    }
562
+
563
+    /**
564
+     * @param string|int $tag name or tag id
565
+     * @param string $userId owner of the tags
566
+     * @return FileInfo[] array or file info
567
+     */
568
+    public static function searchByTag($tag, $userId) {
569
+        return self::$defaultInstance->searchByTag($tag, $userId);
570
+    }
571
+
572
+    /**
573
+     * check if a file or folder has been updated since $time
574
+     *
575
+     * @param string $path
576
+     * @param int $time
577
+     * @return bool
578
+     */
579
+    public static function hasUpdated($path, $time) {
580
+        return self::$defaultInstance->hasUpdated($path, $time);
581
+    }
582
+
583
+    /**
584
+     * Fix common problems with a file path
585
+     *
586
+     * @param string $path
587
+     * @param bool $stripTrailingSlash whether to strip the trailing slash
588
+     * @param bool $isAbsolutePath whether the given path is absolute
589
+     * @param bool $keepUnicode true to disable unicode normalization
590
+     * @psalm-taint-escape file
591
+     * @return string
592
+     */
593
+    public static function normalizePath($path, $stripTrailingSlash = true, $isAbsolutePath = false, $keepUnicode = false) {
594
+        /**
595
+         * FIXME: This is a workaround for existing classes and files which call
596
+         *        this function with another type than a valid string. This
597
+         *        conversion should get removed as soon as all existing
598
+         *        function calls have been fixed.
599
+         */
600
+        $path = (string)$path;
601
+
602
+        if ($path === '') {
603
+            return '/';
604
+        }
605
+
606
+        //normalize unicode if possible
607
+        if (!$keepUnicode) {
608
+            $path = \OC_Util::normalizeUnicode($path);
609
+        }
610
+
611
+        //add leading slash, if it is already there we strip it anyway
612
+        $path = '/' . $path;
613
+
614
+        $patterns = [
615
+            '#\\\\#s',       // no windows style '\\' slashes
616
+            '#/\.(/\.)*/#s', // remove '/./'
617
+            '#\//+#s',       // remove sequence of slashes
618
+            '#/\.$#s',       // remove trailing '/.'
619
+        ];
620
+
621
+        do {
622
+            $count = 0;
623
+            $path = preg_replace($patterns, '/', $path, -1, $count);
624
+        } while ($count > 0);
625
+
626
+        //remove trailing slash
627
+        if ($stripTrailingSlash && strlen($path) > 1) {
628
+            $path = rtrim($path, '/');
629
+        }
630
+
631
+        return $path;
632
+    }
633
+
634
+    /**
635
+     * get the filesystem info
636
+     *
637
+     * @param string $path
638
+     * @param bool|string $includeMountPoints whether to add mountpoint sizes,
639
+     *                                        defaults to true
640
+     * @return \OC\Files\FileInfo|false False if file does not exist
641
+     */
642
+    public static function getFileInfo($path, $includeMountPoints = true) {
643
+        return self::getView()->getFileInfo($path, $includeMountPoints);
644
+    }
645
+
646
+    /**
647
+     * change file metadata
648
+     *
649
+     * @param string $path
650
+     * @param array $data
651
+     * @return int
652
+     *
653
+     * returns the fileid of the updated file
654
+     */
655
+    public static function putFileInfo($path, $data) {
656
+        return self::$defaultInstance->putFileInfo($path, $data);
657
+    }
658
+
659
+    /**
660
+     * get the content of a directory
661
+     *
662
+     * @param string $directory path under datadirectory
663
+     * @param string $mimetype_filter limit returned content to this mimetype or mimepart
664
+     * @return \OC\Files\FileInfo[]
665
+     */
666
+    public static function getDirectoryContent($directory, $mimetype_filter = '') {
667
+        return self::$defaultInstance->getDirectoryContent($directory, $mimetype_filter);
668
+    }
669
+
670
+    /**
671
+     * Get the path of a file by id
672
+     *
673
+     * Note that the resulting path is not guaranteed to be unique for the id, multiple paths can point to the same file
674
+     *
675
+     * @param int $id
676
+     * @throws NotFoundException
677
+     * @return string
678
+     */
679
+    public static function getPath($id) {
680
+        return self::$defaultInstance->getPath($id);
681
+    }
682
+
683
+    /**
684
+     * Get the owner for a file or folder
685
+     *
686
+     * @param string $path
687
+     * @return string
688
+     */
689
+    public static function getOwner($path) {
690
+        return self::$defaultInstance->getOwner($path);
691
+    }
692
+
693
+    /**
694
+     * get the ETag for a file or folder
695
+     */
696
+    public static function getETag(string $path): string|false {
697
+        return self::$defaultInstance->getETag($path);
698
+    }
699 699
 }
Please login to merge, or discard this patch.