Completed
Push — master ( 95b961...08b9ec )
by
unknown
56:44 queued 27:41
created
lib/private/Files/SetupManager.php 2 patches
Indentation   +542 added lines, -542 removed lines patch added patch discarded remove patch
@@ -56,548 +56,548 @@
 block discarded – undo
56 56
 use Psr\Log\LoggerInterface;
57 57
 
58 58
 class SetupManager {
59
-	private bool $rootSetup = false;
60
-	// List of users for which at least one mount is setup
61
-	private array $setupUsers = [];
62
-	// List of users for which all mounts are setup
63
-	private array $setupUsersComplete = [];
64
-	/** @var array<string, string[]> */
65
-	private array $setupUserMountProviders = [];
66
-	private ICache $cache;
67
-	private bool $listeningForProviders;
68
-	private array $fullSetupRequired = [];
69
-	private bool $setupBuiltinWrappersDone = false;
70
-	private bool $forceFullSetup = false;
71
-
72
-	public function __construct(
73
-		private IEventLogger $eventLogger,
74
-		private MountProviderCollection $mountProviderCollection,
75
-		private IMountManager $mountManager,
76
-		private IUserManager $userManager,
77
-		private IEventDispatcher $eventDispatcher,
78
-		private IUserMountCache $userMountCache,
79
-		private ILockdownManager $lockdownManager,
80
-		private IUserSession $userSession,
81
-		ICacheFactory $cacheFactory,
82
-		private LoggerInterface $logger,
83
-		private IConfig $config,
84
-		private ShareDisableChecker $shareDisableChecker,
85
-	) {
86
-		$this->cache = $cacheFactory->createDistributed('setupmanager::');
87
-		$this->listeningForProviders = false;
88
-		$this->forceFullSetup = $this->config->getSystemValueBool('debug.force-full-fs-setup');
89
-
90
-		$this->setupListeners();
91
-	}
92
-
93
-	private function isSetupStarted(IUser $user): bool {
94
-		return in_array($user->getUID(), $this->setupUsers, true);
95
-	}
96
-
97
-	public function isSetupComplete(IUser $user): bool {
98
-		return in_array($user->getUID(), $this->setupUsersComplete, true);
99
-	}
100
-
101
-	private function setupBuiltinWrappers() {
102
-		if ($this->setupBuiltinWrappersDone) {
103
-			return;
104
-		}
105
-		$this->setupBuiltinWrappersDone = true;
106
-
107
-		// load all filesystem apps before, so no setup-hook gets lost
108
-		OC_App::loadApps(['filesystem']);
109
-		$prevLogging = Filesystem::logWarningWhenAddingStorageWrapper(false);
110
-
111
-		Filesystem::addStorageWrapper('mount_options', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
112
-			if ($storage->instanceOfStorage(Common::class)) {
113
-				$options = array_merge($mount->getOptions(), ['mount_point' => $mountPoint]);
114
-				$storage->setMountOptions($options);
115
-			}
116
-			return $storage;
117
-		});
118
-
119
-		$reSharingEnabled = Share::isResharingAllowed();
120
-		$user = $this->userSession->getUser();
121
-		$sharingEnabledForUser = $user ? !$this->shareDisableChecker->sharingDisabledForUser($user->getUID()) : true;
122
-		Filesystem::addStorageWrapper(
123
-			'sharing_mask',
124
-			function ($mountPoint, IStorage $storage, IMountPoint $mount) use ($reSharingEnabled, $sharingEnabledForUser) {
125
-				$sharingEnabledForMount = $mount->getOption('enable_sharing', true);
126
-				$isShared = $mount instanceof ISharedMountPoint;
127
-				if (!$sharingEnabledForMount || !$sharingEnabledForUser || (!$reSharingEnabled && $isShared)) {
128
-					return new PermissionsMask([
129
-						'storage' => $storage,
130
-						'mask' => Constants::PERMISSION_ALL - Constants::PERMISSION_SHARE,
131
-					]);
132
-				}
133
-				return $storage;
134
-			}
135
-		);
136
-
137
-		// install storage availability wrapper, before most other wrappers
138
-		Filesystem::addStorageWrapper('oc_availability', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
139
-			$externalMount = $mount instanceof ExternalMountPoint || $mount instanceof Mount;
140
-			if ($externalMount && !$storage->isLocal()) {
141
-				return new Availability(['storage' => $storage]);
142
-			}
143
-			return $storage;
144
-		});
145
-
146
-		Filesystem::addStorageWrapper('oc_encoding', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
147
-			if ($mount->getOption('encoding_compatibility', false) && !$mount instanceof SharedMount) {
148
-				return new Encoding(['storage' => $storage]);
149
-			}
150
-			return $storage;
151
-		});
152
-
153
-		$quotaIncludeExternal = $this->config->getSystemValue('quota_include_external_storage', false);
154
-		Filesystem::addStorageWrapper('oc_quota', function ($mountPoint, $storage, IMountPoint $mount) use ($quotaIncludeExternal) {
155
-			// set up quota for home storages, even for other users
156
-			// which can happen when using sharing
157
-			if ($mount instanceof HomeMountPoint) {
158
-				$user = $mount->getUser();
159
-				return new Quota(['storage' => $storage, 'quotaCallback' => function () use ($user) {
160
-					return OC_Util::getUserQuota($user);
161
-				}, 'root' => 'files', 'include_external_storage' => $quotaIncludeExternal]);
162
-			}
163
-
164
-			return $storage;
165
-		});
166
-
167
-		Filesystem::addStorageWrapper('readonly', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
168
-			/*
59
+    private bool $rootSetup = false;
60
+    // List of users for which at least one mount is setup
61
+    private array $setupUsers = [];
62
+    // List of users for which all mounts are setup
63
+    private array $setupUsersComplete = [];
64
+    /** @var array<string, string[]> */
65
+    private array $setupUserMountProviders = [];
66
+    private ICache $cache;
67
+    private bool $listeningForProviders;
68
+    private array $fullSetupRequired = [];
69
+    private bool $setupBuiltinWrappersDone = false;
70
+    private bool $forceFullSetup = false;
71
+
72
+    public function __construct(
73
+        private IEventLogger $eventLogger,
74
+        private MountProviderCollection $mountProviderCollection,
75
+        private IMountManager $mountManager,
76
+        private IUserManager $userManager,
77
+        private IEventDispatcher $eventDispatcher,
78
+        private IUserMountCache $userMountCache,
79
+        private ILockdownManager $lockdownManager,
80
+        private IUserSession $userSession,
81
+        ICacheFactory $cacheFactory,
82
+        private LoggerInterface $logger,
83
+        private IConfig $config,
84
+        private ShareDisableChecker $shareDisableChecker,
85
+    ) {
86
+        $this->cache = $cacheFactory->createDistributed('setupmanager::');
87
+        $this->listeningForProviders = false;
88
+        $this->forceFullSetup = $this->config->getSystemValueBool('debug.force-full-fs-setup');
89
+
90
+        $this->setupListeners();
91
+    }
92
+
93
+    private function isSetupStarted(IUser $user): bool {
94
+        return in_array($user->getUID(), $this->setupUsers, true);
95
+    }
96
+
97
+    public function isSetupComplete(IUser $user): bool {
98
+        return in_array($user->getUID(), $this->setupUsersComplete, true);
99
+    }
100
+
101
+    private function setupBuiltinWrappers() {
102
+        if ($this->setupBuiltinWrappersDone) {
103
+            return;
104
+        }
105
+        $this->setupBuiltinWrappersDone = true;
106
+
107
+        // load all filesystem apps before, so no setup-hook gets lost
108
+        OC_App::loadApps(['filesystem']);
109
+        $prevLogging = Filesystem::logWarningWhenAddingStorageWrapper(false);
110
+
111
+        Filesystem::addStorageWrapper('mount_options', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
112
+            if ($storage->instanceOfStorage(Common::class)) {
113
+                $options = array_merge($mount->getOptions(), ['mount_point' => $mountPoint]);
114
+                $storage->setMountOptions($options);
115
+            }
116
+            return $storage;
117
+        });
118
+
119
+        $reSharingEnabled = Share::isResharingAllowed();
120
+        $user = $this->userSession->getUser();
121
+        $sharingEnabledForUser = $user ? !$this->shareDisableChecker->sharingDisabledForUser($user->getUID()) : true;
122
+        Filesystem::addStorageWrapper(
123
+            'sharing_mask',
124
+            function ($mountPoint, IStorage $storage, IMountPoint $mount) use ($reSharingEnabled, $sharingEnabledForUser) {
125
+                $sharingEnabledForMount = $mount->getOption('enable_sharing', true);
126
+                $isShared = $mount instanceof ISharedMountPoint;
127
+                if (!$sharingEnabledForMount || !$sharingEnabledForUser || (!$reSharingEnabled && $isShared)) {
128
+                    return new PermissionsMask([
129
+                        'storage' => $storage,
130
+                        'mask' => Constants::PERMISSION_ALL - Constants::PERMISSION_SHARE,
131
+                    ]);
132
+                }
133
+                return $storage;
134
+            }
135
+        );
136
+
137
+        // install storage availability wrapper, before most other wrappers
138
+        Filesystem::addStorageWrapper('oc_availability', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
139
+            $externalMount = $mount instanceof ExternalMountPoint || $mount instanceof Mount;
140
+            if ($externalMount && !$storage->isLocal()) {
141
+                return new Availability(['storage' => $storage]);
142
+            }
143
+            return $storage;
144
+        });
145
+
146
+        Filesystem::addStorageWrapper('oc_encoding', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
147
+            if ($mount->getOption('encoding_compatibility', false) && !$mount instanceof SharedMount) {
148
+                return new Encoding(['storage' => $storage]);
149
+            }
150
+            return $storage;
151
+        });
152
+
153
+        $quotaIncludeExternal = $this->config->getSystemValue('quota_include_external_storage', false);
154
+        Filesystem::addStorageWrapper('oc_quota', function ($mountPoint, $storage, IMountPoint $mount) use ($quotaIncludeExternal) {
155
+            // set up quota for home storages, even for other users
156
+            // which can happen when using sharing
157
+            if ($mount instanceof HomeMountPoint) {
158
+                $user = $mount->getUser();
159
+                return new Quota(['storage' => $storage, 'quotaCallback' => function () use ($user) {
160
+                    return OC_Util::getUserQuota($user);
161
+                }, 'root' => 'files', 'include_external_storage' => $quotaIncludeExternal]);
162
+            }
163
+
164
+            return $storage;
165
+        });
166
+
167
+        Filesystem::addStorageWrapper('readonly', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
168
+            /*
169 169
 			 * Do not allow any operations that modify the storage
170 170
 			 */
171
-			if ($mount->getOption('readonly', false)) {
172
-				return new PermissionsMask([
173
-					'storage' => $storage,
174
-					'mask' => Constants::PERMISSION_ALL & ~(
175
-						Constants::PERMISSION_UPDATE |
176
-						Constants::PERMISSION_CREATE |
177
-						Constants::PERMISSION_DELETE
178
-					),
179
-				]);
180
-			}
181
-			return $storage;
182
-		});
183
-
184
-		Filesystem::logWarningWhenAddingStorageWrapper($prevLogging);
185
-	}
186
-
187
-	/**
188
-	 * Setup the full filesystem for the specified user
189
-	 */
190
-	public function setupForUser(IUser $user): void {
191
-		if ($this->isSetupComplete($user)) {
192
-			return;
193
-		}
194
-		$this->setupUsersComplete[] = $user->getUID();
195
-
196
-		$this->eventLogger->start('fs:setup:user:full', 'Setup full filesystem for user');
197
-
198
-		if (!isset($this->setupUserMountProviders[$user->getUID()])) {
199
-			$this->setupUserMountProviders[$user->getUID()] = [];
200
-		}
201
-
202
-		$previouslySetupProviders = $this->setupUserMountProviders[$user->getUID()];
203
-
204
-		$this->setupForUserWith($user, function () use ($user) {
205
-			$this->mountProviderCollection->addMountForUser($user, $this->mountManager, function (
206
-				IMountProvider $provider,
207
-			) use ($user) {
208
-				return !in_array(get_class($provider), $this->setupUserMountProviders[$user->getUID()]);
209
-			});
210
-		});
211
-		$this->afterUserFullySetup($user, $previouslySetupProviders);
212
-		$this->eventLogger->end('fs:setup:user:full');
213
-	}
214
-
215
-	/**
216
-	 * part of the user setup that is run only once per user
217
-	 */
218
-	private function oneTimeUserSetup(IUser $user) {
219
-		if ($this->isSetupStarted($user)) {
220
-			return;
221
-		}
222
-		$this->setupUsers[] = $user->getUID();
223
-
224
-		$this->setupRoot();
225
-
226
-		$this->eventLogger->start('fs:setup:user:onetime', 'Onetime filesystem for user');
227
-
228
-		$this->setupBuiltinWrappers();
229
-
230
-		$prevLogging = Filesystem::logWarningWhenAddingStorageWrapper(false);
231
-
232
-		// TODO remove hook
233
-		OC_Hook::emit('OC_Filesystem', 'preSetup', ['user' => $user->getUID()]);
234
-
235
-		$event = new BeforeFileSystemSetupEvent($user);
236
-		$this->eventDispatcher->dispatchTyped($event);
237
-
238
-		Filesystem::logWarningWhenAddingStorageWrapper($prevLogging);
239
-
240
-		$userDir = '/' . $user->getUID() . '/files';
241
-
242
-		Filesystem::initInternal($userDir);
243
-
244
-		if ($this->lockdownManager->canAccessFilesystem()) {
245
-			$this->eventLogger->start('fs:setup:user:home', 'Setup home filesystem for user');
246
-			// home mounts are handled separate since we need to ensure this is mounted before we call the other mount providers
247
-			$homeMount = $this->mountProviderCollection->getHomeMountForUser($user);
248
-			$this->mountManager->addMount($homeMount);
249
-
250
-			if ($homeMount->getStorageRootId() === -1) {
251
-				$this->eventLogger->start('fs:setup:user:home:scan', 'Scan home filesystem for user');
252
-				$homeMount->getStorage()->mkdir('');
253
-				$homeMount->getStorage()->getScanner()->scan('');
254
-				$this->eventLogger->end('fs:setup:user:home:scan');
255
-			}
256
-			$this->eventLogger->end('fs:setup:user:home');
257
-		} else {
258
-			$this->mountManager->addMount(new MountPoint(
259
-				new NullStorage([]),
260
-				'/' . $user->getUID()
261
-			));
262
-			$this->mountManager->addMount(new MountPoint(
263
-				new NullStorage([]),
264
-				'/' . $user->getUID() . '/files'
265
-			));
266
-			$this->setupUsersComplete[] = $user->getUID();
267
-		}
268
-
269
-		$this->listenForNewMountProviders();
270
-
271
-		$this->eventLogger->end('fs:setup:user:onetime');
272
-	}
273
-
274
-	/**
275
-	 * Final housekeeping after a user has been fully setup
276
-	 */
277
-	private function afterUserFullySetup(IUser $user, array $previouslySetupProviders): void {
278
-		$this->eventLogger->start('fs:setup:user:full:post', 'Housekeeping after user is setup');
279
-		$userRoot = '/' . $user->getUID() . '/';
280
-		$mounts = $this->mountManager->getAll();
281
-		$mounts = array_filter($mounts, function (IMountPoint $mount) use ($userRoot) {
282
-			return str_starts_with($mount->getMountPoint(), $userRoot);
283
-		});
284
-		$allProviders = array_map(function (IMountProvider|IHomeMountProvider|IRootMountProvider $provider) {
285
-			return get_class($provider);
286
-		}, array_merge(
287
-			$this->mountProviderCollection->getProviders(),
288
-			$this->mountProviderCollection->getHomeProviders(),
289
-			$this->mountProviderCollection->getRootProviders(),
290
-		));
291
-		$newProviders = array_diff($allProviders, $previouslySetupProviders);
292
-		$mounts = array_filter($mounts, function (IMountPoint $mount) use ($previouslySetupProviders) {
293
-			return !in_array($mount->getMountProvider(), $previouslySetupProviders);
294
-		});
295
-		$this->userMountCache->registerMounts($user, $mounts, $newProviders);
296
-
297
-		$cacheDuration = $this->config->getSystemValueInt('fs_mount_cache_duration', 5 * 60);
298
-		if ($cacheDuration > 0) {
299
-			$this->cache->set($user->getUID(), true, $cacheDuration);
300
-			$this->fullSetupRequired[$user->getUID()] = false;
301
-		}
302
-		$this->eventLogger->end('fs:setup:user:full:post');
303
-	}
304
-
305
-	/**
306
-	 * @param IUser $user
307
-	 * @param IMountPoint $mounts
308
-	 * @return void
309
-	 * @throws \OCP\HintException
310
-	 * @throws \OC\ServerNotAvailableException
311
-	 */
312
-	private function setupForUserWith(IUser $user, callable $mountCallback): void {
313
-		$this->oneTimeUserSetup($user);
314
-
315
-		if ($this->lockdownManager->canAccessFilesystem()) {
316
-			$mountCallback();
317
-		}
318
-		$this->eventLogger->start('fs:setup:user:post-init-mountpoint', 'post_initMountPoints legacy hook');
319
-		\OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', ['user' => $user->getUID()]);
320
-		$this->eventLogger->end('fs:setup:user:post-init-mountpoint');
321
-
322
-		$userDir = '/' . $user->getUID() . '/files';
323
-		$this->eventLogger->start('fs:setup:user:setup-hook', 'setup legacy hook');
324
-		OC_Hook::emit('OC_Filesystem', 'setup', ['user' => $user->getUID(), 'user_dir' => $userDir]);
325
-		$this->eventLogger->end('fs:setup:user:setup-hook');
326
-	}
327
-
328
-	/**
329
-	 * Set up the root filesystem
330
-	 */
331
-	public function setupRoot(): void {
332
-		//setting up the filesystem twice can only lead to trouble
333
-		if ($this->rootSetup) {
334
-			return;
335
-		}
336
-
337
-		$this->setupBuiltinWrappers();
338
-
339
-		$this->rootSetup = true;
340
-
341
-		$this->eventLogger->start('fs:setup:root', 'Setup root filesystem');
342
-
343
-		$rootMounts = $this->mountProviderCollection->getRootMounts();
344
-		foreach ($rootMounts as $rootMountProvider) {
345
-			$this->mountManager->addMount($rootMountProvider);
346
-		}
347
-
348
-		$this->eventLogger->end('fs:setup:root');
349
-	}
350
-
351
-	/**
352
-	 * Get the user to setup for a path or `null` if the root needs to be setup
353
-	 *
354
-	 * @param string $path
355
-	 * @return IUser|null
356
-	 */
357
-	private function getUserForPath(string $path) {
358
-		if (str_starts_with($path, '/__groupfolders')) {
359
-			return null;
360
-		} elseif (substr_count($path, '/') < 2) {
361
-			if ($user = $this->userSession->getUser()) {
362
-				return $user;
363
-			} else {
364
-				return null;
365
-			}
366
-		} elseif (str_starts_with($path, '/appdata_' . \OC_Util::getInstanceId()) || str_starts_with($path, '/files_external/')) {
367
-			return null;
368
-		} else {
369
-			[, $userId] = explode('/', $path);
370
-		}
371
-
372
-		return $this->userManager->get($userId);
373
-	}
374
-
375
-	/**
376
-	 * Set up the filesystem for the specified path
377
-	 */
378
-	public function setupForPath(string $path, bool $includeChildren = false): void {
379
-		$user = $this->getUserForPath($path);
380
-		if (!$user) {
381
-			$this->setupRoot();
382
-			return;
383
-		}
384
-
385
-		if ($this->isSetupComplete($user)) {
386
-			return;
387
-		}
388
-
389
-		if ($this->fullSetupRequired($user)) {
390
-			$this->setupForUser($user);
391
-			return;
392
-		}
393
-
394
-		// for the user's home folder, and includes children we need everything always
395
-		if (rtrim($path) === '/' . $user->getUID() . '/files' && $includeChildren) {
396
-			$this->setupForUser($user);
397
-			return;
398
-		}
399
-
400
-		if (!isset($this->setupUserMountProviders[$user->getUID()])) {
401
-			$this->setupUserMountProviders[$user->getUID()] = [];
402
-		}
403
-		$setupProviders = &$this->setupUserMountProviders[$user->getUID()];
404
-		$currentProviders = [];
405
-
406
-		try {
407
-			$cachedMount = $this->userMountCache->getMountForPath($user, $path);
408
-		} catch (NotFoundException $e) {
409
-			$this->setupForUser($user);
410
-			return;
411
-		}
412
-
413
-		$this->oneTimeUserSetup($user);
414
-
415
-		$this->eventLogger->start('fs:setup:user:path', "Setup $path filesystem for user");
416
-		$this->eventLogger->start('fs:setup:user:path:find', "Find mountpoint for $path");
417
-
418
-		$mounts = [];
419
-		if (!in_array($cachedMount->getMountProvider(), $setupProviders)) {
420
-			$currentProviders[] = $cachedMount->getMountProvider();
421
-			if ($cachedMount->getMountProvider()) {
422
-				$setupProviders[] = $cachedMount->getMountProvider();
423
-				$mounts = $this->mountProviderCollection->getUserMountsForProviderClasses($user, [$cachedMount->getMountProvider()]);
424
-			} else {
425
-				$this->logger->debug('mount at ' . $cachedMount->getMountPoint() . ' has no provider set, performing full setup');
426
-				$this->eventLogger->end('fs:setup:user:path:find');
427
-				$this->setupForUser($user);
428
-				$this->eventLogger->end('fs:setup:user:path');
429
-				return;
430
-			}
431
-		}
432
-
433
-		if ($includeChildren) {
434
-			$subCachedMounts = $this->userMountCache->getMountsInPath($user, $path);
435
-			$this->eventLogger->end('fs:setup:user:path:find');
436
-
437
-			$needsFullSetup = array_reduce($subCachedMounts, function (bool $needsFullSetup, ICachedMountInfo $cachedMountInfo) {
438
-				return $needsFullSetup || $cachedMountInfo->getMountProvider() === '';
439
-			}, false);
440
-
441
-			if ($needsFullSetup) {
442
-				$this->logger->debug('mount has no provider set, performing full setup');
443
-				$this->setupForUser($user);
444
-				$this->eventLogger->end('fs:setup:user:path');
445
-				return;
446
-			} else {
447
-				foreach ($subCachedMounts as $cachedMount) {
448
-					if (!in_array($cachedMount->getMountProvider(), $setupProviders)) {
449
-						$currentProviders[] = $cachedMount->getMountProvider();
450
-						$setupProviders[] = $cachedMount->getMountProvider();
451
-						$mounts = array_merge($mounts, $this->mountProviderCollection->getUserMountsForProviderClasses($user, [$cachedMount->getMountProvider()]));
452
-					}
453
-				}
454
-			}
455
-		} else {
456
-			$this->eventLogger->end('fs:setup:user:path:find');
457
-		}
458
-
459
-		if (count($mounts)) {
460
-			$this->userMountCache->registerMounts($user, $mounts, $currentProviders);
461
-			$this->setupForUserWith($user, function () use ($mounts) {
462
-				array_walk($mounts, [$this->mountManager, 'addMount']);
463
-			});
464
-		} elseif (!$this->isSetupStarted($user)) {
465
-			$this->oneTimeUserSetup($user);
466
-		}
467
-		$this->eventLogger->end('fs:setup:user:path');
468
-	}
469
-
470
-	private function fullSetupRequired(IUser $user): bool {
471
-		if ($this->forceFullSetup) {
472
-			return true;
473
-		}
474
-
475
-		// we perform a "cached" setup only after having done the full setup recently
476
-		// this is also used to trigger a full setup after handling events that are likely
477
-		// to change the available mounts
478
-		if (!isset($this->fullSetupRequired[$user->getUID()])) {
479
-			$this->fullSetupRequired[$user->getUID()] = !$this->cache->get($user->getUID());
480
-		}
481
-		return $this->fullSetupRequired[$user->getUID()];
482
-	}
483
-
484
-	/**
485
-	 * @param string $path
486
-	 * @param string[] $providers
487
-	 */
488
-	public function setupForProvider(string $path, array $providers): void {
489
-		$user = $this->getUserForPath($path);
490
-		if (!$user) {
491
-			$this->setupRoot();
492
-			return;
493
-		}
494
-
495
-		if ($this->isSetupComplete($user)) {
496
-			return;
497
-		}
498
-
499
-		if ($this->fullSetupRequired($user)) {
500
-			$this->setupForUser($user);
501
-			return;
502
-		}
503
-
504
-		$this->eventLogger->start('fs:setup:user:providers', 'Setup filesystem for ' . implode(', ', $providers));
505
-
506
-		$this->oneTimeUserSetup($user);
507
-
508
-		// home providers are always used
509
-		$providers = array_filter($providers, function (string $provider) {
510
-			return !is_subclass_of($provider, IHomeMountProvider::class);
511
-		});
512
-
513
-		if (in_array('', $providers)) {
514
-			$this->setupForUser($user);
515
-			return;
516
-		}
517
-		$setupProviders = $this->setupUserMountProviders[$user->getUID()] ?? [];
518
-
519
-		$providers = array_diff($providers, $setupProviders);
520
-		if (count($providers) === 0) {
521
-			if (!$this->isSetupStarted($user)) {
522
-				$this->oneTimeUserSetup($user);
523
-			}
524
-			$this->eventLogger->end('fs:setup:user:providers');
525
-			return;
526
-		} else {
527
-			$this->setupUserMountProviders[$user->getUID()] = array_merge($setupProviders, $providers);
528
-			$mounts = $this->mountProviderCollection->getUserMountsForProviderClasses($user, $providers);
529
-		}
530
-
531
-		$this->userMountCache->registerMounts($user, $mounts, $providers);
532
-		$this->setupForUserWith($user, function () use ($mounts) {
533
-			array_walk($mounts, [$this->mountManager, 'addMount']);
534
-		});
535
-		$this->eventLogger->end('fs:setup:user:providers');
536
-	}
537
-
538
-	public function tearDown() {
539
-		$this->setupUsers = [];
540
-		$this->setupUsersComplete = [];
541
-		$this->setupUserMountProviders = [];
542
-		$this->fullSetupRequired = [];
543
-		$this->rootSetup = false;
544
-		$this->mountManager->clear();
545
-		$this->eventDispatcher->dispatchTyped(new FilesystemTornDownEvent());
546
-	}
547
-
548
-	/**
549
-	 * Get mounts from mount providers that are registered after setup
550
-	 */
551
-	private function listenForNewMountProviders() {
552
-		if (!$this->listeningForProviders) {
553
-			$this->listeningForProviders = true;
554
-			$this->mountProviderCollection->listen('\OC\Files\Config', 'registerMountProvider', function (
555
-				IMountProvider $provider,
556
-			) {
557
-				foreach ($this->setupUsers as $userId) {
558
-					$user = $this->userManager->get($userId);
559
-					if ($user) {
560
-						$mounts = $provider->getMountsForUser($user, Filesystem::getLoader());
561
-						array_walk($mounts, [$this->mountManager, 'addMount']);
562
-					}
563
-				}
564
-			});
565
-		}
566
-	}
567
-
568
-	private function setupListeners() {
569
-		// note that this event handling is intentionally pessimistic
570
-		// clearing the cache to often is better than not enough
571
-
572
-		$this->eventDispatcher->addListener(UserAddedEvent::class, function (UserAddedEvent $event) {
573
-			$this->cache->remove($event->getUser()->getUID());
574
-		});
575
-		$this->eventDispatcher->addListener(UserRemovedEvent::class, function (UserRemovedEvent $event) {
576
-			$this->cache->remove($event->getUser()->getUID());
577
-		});
578
-		$this->eventDispatcher->addListener(ShareCreatedEvent::class, function (ShareCreatedEvent $event) {
579
-			$this->cache->remove($event->getShare()->getSharedWith());
580
-		});
581
-		$this->eventDispatcher->addListener(InvalidateMountCacheEvent::class, function (InvalidateMountCacheEvent $event,
582
-		) {
583
-			if ($user = $event->getUser()) {
584
-				$this->cache->remove($user->getUID());
585
-			} else {
586
-				$this->cache->clear();
587
-			}
588
-		});
589
-
590
-		$genericEvents = [
591
-			'OCA\Circles\Events\CreatingCircleEvent',
592
-			'OCA\Circles\Events\DestroyingCircleEvent',
593
-			'OCA\Circles\Events\AddingCircleMemberEvent',
594
-			'OCA\Circles\Events\RemovingCircleMemberEvent',
595
-		];
596
-
597
-		foreach ($genericEvents as $genericEvent) {
598
-			$this->eventDispatcher->addListener($genericEvent, function ($event) {
599
-				$this->cache->clear();
600
-			});
601
-		}
602
-	}
171
+            if ($mount->getOption('readonly', false)) {
172
+                return new PermissionsMask([
173
+                    'storage' => $storage,
174
+                    'mask' => Constants::PERMISSION_ALL & ~(
175
+                        Constants::PERMISSION_UPDATE |
176
+                        Constants::PERMISSION_CREATE |
177
+                        Constants::PERMISSION_DELETE
178
+                    ),
179
+                ]);
180
+            }
181
+            return $storage;
182
+        });
183
+
184
+        Filesystem::logWarningWhenAddingStorageWrapper($prevLogging);
185
+    }
186
+
187
+    /**
188
+     * Setup the full filesystem for the specified user
189
+     */
190
+    public function setupForUser(IUser $user): void {
191
+        if ($this->isSetupComplete($user)) {
192
+            return;
193
+        }
194
+        $this->setupUsersComplete[] = $user->getUID();
195
+
196
+        $this->eventLogger->start('fs:setup:user:full', 'Setup full filesystem for user');
197
+
198
+        if (!isset($this->setupUserMountProviders[$user->getUID()])) {
199
+            $this->setupUserMountProviders[$user->getUID()] = [];
200
+        }
201
+
202
+        $previouslySetupProviders = $this->setupUserMountProviders[$user->getUID()];
203
+
204
+        $this->setupForUserWith($user, function () use ($user) {
205
+            $this->mountProviderCollection->addMountForUser($user, $this->mountManager, function (
206
+                IMountProvider $provider,
207
+            ) use ($user) {
208
+                return !in_array(get_class($provider), $this->setupUserMountProviders[$user->getUID()]);
209
+            });
210
+        });
211
+        $this->afterUserFullySetup($user, $previouslySetupProviders);
212
+        $this->eventLogger->end('fs:setup:user:full');
213
+    }
214
+
215
+    /**
216
+     * part of the user setup that is run only once per user
217
+     */
218
+    private function oneTimeUserSetup(IUser $user) {
219
+        if ($this->isSetupStarted($user)) {
220
+            return;
221
+        }
222
+        $this->setupUsers[] = $user->getUID();
223
+
224
+        $this->setupRoot();
225
+
226
+        $this->eventLogger->start('fs:setup:user:onetime', 'Onetime filesystem for user');
227
+
228
+        $this->setupBuiltinWrappers();
229
+
230
+        $prevLogging = Filesystem::logWarningWhenAddingStorageWrapper(false);
231
+
232
+        // TODO remove hook
233
+        OC_Hook::emit('OC_Filesystem', 'preSetup', ['user' => $user->getUID()]);
234
+
235
+        $event = new BeforeFileSystemSetupEvent($user);
236
+        $this->eventDispatcher->dispatchTyped($event);
237
+
238
+        Filesystem::logWarningWhenAddingStorageWrapper($prevLogging);
239
+
240
+        $userDir = '/' . $user->getUID() . '/files';
241
+
242
+        Filesystem::initInternal($userDir);
243
+
244
+        if ($this->lockdownManager->canAccessFilesystem()) {
245
+            $this->eventLogger->start('fs:setup:user:home', 'Setup home filesystem for user');
246
+            // home mounts are handled separate since we need to ensure this is mounted before we call the other mount providers
247
+            $homeMount = $this->mountProviderCollection->getHomeMountForUser($user);
248
+            $this->mountManager->addMount($homeMount);
249
+
250
+            if ($homeMount->getStorageRootId() === -1) {
251
+                $this->eventLogger->start('fs:setup:user:home:scan', 'Scan home filesystem for user');
252
+                $homeMount->getStorage()->mkdir('');
253
+                $homeMount->getStorage()->getScanner()->scan('');
254
+                $this->eventLogger->end('fs:setup:user:home:scan');
255
+            }
256
+            $this->eventLogger->end('fs:setup:user:home');
257
+        } else {
258
+            $this->mountManager->addMount(new MountPoint(
259
+                new NullStorage([]),
260
+                '/' . $user->getUID()
261
+            ));
262
+            $this->mountManager->addMount(new MountPoint(
263
+                new NullStorage([]),
264
+                '/' . $user->getUID() . '/files'
265
+            ));
266
+            $this->setupUsersComplete[] = $user->getUID();
267
+        }
268
+
269
+        $this->listenForNewMountProviders();
270
+
271
+        $this->eventLogger->end('fs:setup:user:onetime');
272
+    }
273
+
274
+    /**
275
+     * Final housekeeping after a user has been fully setup
276
+     */
277
+    private function afterUserFullySetup(IUser $user, array $previouslySetupProviders): void {
278
+        $this->eventLogger->start('fs:setup:user:full:post', 'Housekeeping after user is setup');
279
+        $userRoot = '/' . $user->getUID() . '/';
280
+        $mounts = $this->mountManager->getAll();
281
+        $mounts = array_filter($mounts, function (IMountPoint $mount) use ($userRoot) {
282
+            return str_starts_with($mount->getMountPoint(), $userRoot);
283
+        });
284
+        $allProviders = array_map(function (IMountProvider|IHomeMountProvider|IRootMountProvider $provider) {
285
+            return get_class($provider);
286
+        }, array_merge(
287
+            $this->mountProviderCollection->getProviders(),
288
+            $this->mountProviderCollection->getHomeProviders(),
289
+            $this->mountProviderCollection->getRootProviders(),
290
+        ));
291
+        $newProviders = array_diff($allProviders, $previouslySetupProviders);
292
+        $mounts = array_filter($mounts, function (IMountPoint $mount) use ($previouslySetupProviders) {
293
+            return !in_array($mount->getMountProvider(), $previouslySetupProviders);
294
+        });
295
+        $this->userMountCache->registerMounts($user, $mounts, $newProviders);
296
+
297
+        $cacheDuration = $this->config->getSystemValueInt('fs_mount_cache_duration', 5 * 60);
298
+        if ($cacheDuration > 0) {
299
+            $this->cache->set($user->getUID(), true, $cacheDuration);
300
+            $this->fullSetupRequired[$user->getUID()] = false;
301
+        }
302
+        $this->eventLogger->end('fs:setup:user:full:post');
303
+    }
304
+
305
+    /**
306
+     * @param IUser $user
307
+     * @param IMountPoint $mounts
308
+     * @return void
309
+     * @throws \OCP\HintException
310
+     * @throws \OC\ServerNotAvailableException
311
+     */
312
+    private function setupForUserWith(IUser $user, callable $mountCallback): void {
313
+        $this->oneTimeUserSetup($user);
314
+
315
+        if ($this->lockdownManager->canAccessFilesystem()) {
316
+            $mountCallback();
317
+        }
318
+        $this->eventLogger->start('fs:setup:user:post-init-mountpoint', 'post_initMountPoints legacy hook');
319
+        \OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', ['user' => $user->getUID()]);
320
+        $this->eventLogger->end('fs:setup:user:post-init-mountpoint');
321
+
322
+        $userDir = '/' . $user->getUID() . '/files';
323
+        $this->eventLogger->start('fs:setup:user:setup-hook', 'setup legacy hook');
324
+        OC_Hook::emit('OC_Filesystem', 'setup', ['user' => $user->getUID(), 'user_dir' => $userDir]);
325
+        $this->eventLogger->end('fs:setup:user:setup-hook');
326
+    }
327
+
328
+    /**
329
+     * Set up the root filesystem
330
+     */
331
+    public function setupRoot(): void {
332
+        //setting up the filesystem twice can only lead to trouble
333
+        if ($this->rootSetup) {
334
+            return;
335
+        }
336
+
337
+        $this->setupBuiltinWrappers();
338
+
339
+        $this->rootSetup = true;
340
+
341
+        $this->eventLogger->start('fs:setup:root', 'Setup root filesystem');
342
+
343
+        $rootMounts = $this->mountProviderCollection->getRootMounts();
344
+        foreach ($rootMounts as $rootMountProvider) {
345
+            $this->mountManager->addMount($rootMountProvider);
346
+        }
347
+
348
+        $this->eventLogger->end('fs:setup:root');
349
+    }
350
+
351
+    /**
352
+     * Get the user to setup for a path or `null` if the root needs to be setup
353
+     *
354
+     * @param string $path
355
+     * @return IUser|null
356
+     */
357
+    private function getUserForPath(string $path) {
358
+        if (str_starts_with($path, '/__groupfolders')) {
359
+            return null;
360
+        } elseif (substr_count($path, '/') < 2) {
361
+            if ($user = $this->userSession->getUser()) {
362
+                return $user;
363
+            } else {
364
+                return null;
365
+            }
366
+        } elseif (str_starts_with($path, '/appdata_' . \OC_Util::getInstanceId()) || str_starts_with($path, '/files_external/')) {
367
+            return null;
368
+        } else {
369
+            [, $userId] = explode('/', $path);
370
+        }
371
+
372
+        return $this->userManager->get($userId);
373
+    }
374
+
375
+    /**
376
+     * Set up the filesystem for the specified path
377
+     */
378
+    public function setupForPath(string $path, bool $includeChildren = false): void {
379
+        $user = $this->getUserForPath($path);
380
+        if (!$user) {
381
+            $this->setupRoot();
382
+            return;
383
+        }
384
+
385
+        if ($this->isSetupComplete($user)) {
386
+            return;
387
+        }
388
+
389
+        if ($this->fullSetupRequired($user)) {
390
+            $this->setupForUser($user);
391
+            return;
392
+        }
393
+
394
+        // for the user's home folder, and includes children we need everything always
395
+        if (rtrim($path) === '/' . $user->getUID() . '/files' && $includeChildren) {
396
+            $this->setupForUser($user);
397
+            return;
398
+        }
399
+
400
+        if (!isset($this->setupUserMountProviders[$user->getUID()])) {
401
+            $this->setupUserMountProviders[$user->getUID()] = [];
402
+        }
403
+        $setupProviders = &$this->setupUserMountProviders[$user->getUID()];
404
+        $currentProviders = [];
405
+
406
+        try {
407
+            $cachedMount = $this->userMountCache->getMountForPath($user, $path);
408
+        } catch (NotFoundException $e) {
409
+            $this->setupForUser($user);
410
+            return;
411
+        }
412
+
413
+        $this->oneTimeUserSetup($user);
414
+
415
+        $this->eventLogger->start('fs:setup:user:path', "Setup $path filesystem for user");
416
+        $this->eventLogger->start('fs:setup:user:path:find', "Find mountpoint for $path");
417
+
418
+        $mounts = [];
419
+        if (!in_array($cachedMount->getMountProvider(), $setupProviders)) {
420
+            $currentProviders[] = $cachedMount->getMountProvider();
421
+            if ($cachedMount->getMountProvider()) {
422
+                $setupProviders[] = $cachedMount->getMountProvider();
423
+                $mounts = $this->mountProviderCollection->getUserMountsForProviderClasses($user, [$cachedMount->getMountProvider()]);
424
+            } else {
425
+                $this->logger->debug('mount at ' . $cachedMount->getMountPoint() . ' has no provider set, performing full setup');
426
+                $this->eventLogger->end('fs:setup:user:path:find');
427
+                $this->setupForUser($user);
428
+                $this->eventLogger->end('fs:setup:user:path');
429
+                return;
430
+            }
431
+        }
432
+
433
+        if ($includeChildren) {
434
+            $subCachedMounts = $this->userMountCache->getMountsInPath($user, $path);
435
+            $this->eventLogger->end('fs:setup:user:path:find');
436
+
437
+            $needsFullSetup = array_reduce($subCachedMounts, function (bool $needsFullSetup, ICachedMountInfo $cachedMountInfo) {
438
+                return $needsFullSetup || $cachedMountInfo->getMountProvider() === '';
439
+            }, false);
440
+
441
+            if ($needsFullSetup) {
442
+                $this->logger->debug('mount has no provider set, performing full setup');
443
+                $this->setupForUser($user);
444
+                $this->eventLogger->end('fs:setup:user:path');
445
+                return;
446
+            } else {
447
+                foreach ($subCachedMounts as $cachedMount) {
448
+                    if (!in_array($cachedMount->getMountProvider(), $setupProviders)) {
449
+                        $currentProviders[] = $cachedMount->getMountProvider();
450
+                        $setupProviders[] = $cachedMount->getMountProvider();
451
+                        $mounts = array_merge($mounts, $this->mountProviderCollection->getUserMountsForProviderClasses($user, [$cachedMount->getMountProvider()]));
452
+                    }
453
+                }
454
+            }
455
+        } else {
456
+            $this->eventLogger->end('fs:setup:user:path:find');
457
+        }
458
+
459
+        if (count($mounts)) {
460
+            $this->userMountCache->registerMounts($user, $mounts, $currentProviders);
461
+            $this->setupForUserWith($user, function () use ($mounts) {
462
+                array_walk($mounts, [$this->mountManager, 'addMount']);
463
+            });
464
+        } elseif (!$this->isSetupStarted($user)) {
465
+            $this->oneTimeUserSetup($user);
466
+        }
467
+        $this->eventLogger->end('fs:setup:user:path');
468
+    }
469
+
470
+    private function fullSetupRequired(IUser $user): bool {
471
+        if ($this->forceFullSetup) {
472
+            return true;
473
+        }
474
+
475
+        // we perform a "cached" setup only after having done the full setup recently
476
+        // this is also used to trigger a full setup after handling events that are likely
477
+        // to change the available mounts
478
+        if (!isset($this->fullSetupRequired[$user->getUID()])) {
479
+            $this->fullSetupRequired[$user->getUID()] = !$this->cache->get($user->getUID());
480
+        }
481
+        return $this->fullSetupRequired[$user->getUID()];
482
+    }
483
+
484
+    /**
485
+     * @param string $path
486
+     * @param string[] $providers
487
+     */
488
+    public function setupForProvider(string $path, array $providers): void {
489
+        $user = $this->getUserForPath($path);
490
+        if (!$user) {
491
+            $this->setupRoot();
492
+            return;
493
+        }
494
+
495
+        if ($this->isSetupComplete($user)) {
496
+            return;
497
+        }
498
+
499
+        if ($this->fullSetupRequired($user)) {
500
+            $this->setupForUser($user);
501
+            return;
502
+        }
503
+
504
+        $this->eventLogger->start('fs:setup:user:providers', 'Setup filesystem for ' . implode(', ', $providers));
505
+
506
+        $this->oneTimeUserSetup($user);
507
+
508
+        // home providers are always used
509
+        $providers = array_filter($providers, function (string $provider) {
510
+            return !is_subclass_of($provider, IHomeMountProvider::class);
511
+        });
512
+
513
+        if (in_array('', $providers)) {
514
+            $this->setupForUser($user);
515
+            return;
516
+        }
517
+        $setupProviders = $this->setupUserMountProviders[$user->getUID()] ?? [];
518
+
519
+        $providers = array_diff($providers, $setupProviders);
520
+        if (count($providers) === 0) {
521
+            if (!$this->isSetupStarted($user)) {
522
+                $this->oneTimeUserSetup($user);
523
+            }
524
+            $this->eventLogger->end('fs:setup:user:providers');
525
+            return;
526
+        } else {
527
+            $this->setupUserMountProviders[$user->getUID()] = array_merge($setupProviders, $providers);
528
+            $mounts = $this->mountProviderCollection->getUserMountsForProviderClasses($user, $providers);
529
+        }
530
+
531
+        $this->userMountCache->registerMounts($user, $mounts, $providers);
532
+        $this->setupForUserWith($user, function () use ($mounts) {
533
+            array_walk($mounts, [$this->mountManager, 'addMount']);
534
+        });
535
+        $this->eventLogger->end('fs:setup:user:providers');
536
+    }
537
+
538
+    public function tearDown() {
539
+        $this->setupUsers = [];
540
+        $this->setupUsersComplete = [];
541
+        $this->setupUserMountProviders = [];
542
+        $this->fullSetupRequired = [];
543
+        $this->rootSetup = false;
544
+        $this->mountManager->clear();
545
+        $this->eventDispatcher->dispatchTyped(new FilesystemTornDownEvent());
546
+    }
547
+
548
+    /**
549
+     * Get mounts from mount providers that are registered after setup
550
+     */
551
+    private function listenForNewMountProviders() {
552
+        if (!$this->listeningForProviders) {
553
+            $this->listeningForProviders = true;
554
+            $this->mountProviderCollection->listen('\OC\Files\Config', 'registerMountProvider', function (
555
+                IMountProvider $provider,
556
+            ) {
557
+                foreach ($this->setupUsers as $userId) {
558
+                    $user = $this->userManager->get($userId);
559
+                    if ($user) {
560
+                        $mounts = $provider->getMountsForUser($user, Filesystem::getLoader());
561
+                        array_walk($mounts, [$this->mountManager, 'addMount']);
562
+                    }
563
+                }
564
+            });
565
+        }
566
+    }
567
+
568
+    private function setupListeners() {
569
+        // note that this event handling is intentionally pessimistic
570
+        // clearing the cache to often is better than not enough
571
+
572
+        $this->eventDispatcher->addListener(UserAddedEvent::class, function (UserAddedEvent $event) {
573
+            $this->cache->remove($event->getUser()->getUID());
574
+        });
575
+        $this->eventDispatcher->addListener(UserRemovedEvent::class, function (UserRemovedEvent $event) {
576
+            $this->cache->remove($event->getUser()->getUID());
577
+        });
578
+        $this->eventDispatcher->addListener(ShareCreatedEvent::class, function (ShareCreatedEvent $event) {
579
+            $this->cache->remove($event->getShare()->getSharedWith());
580
+        });
581
+        $this->eventDispatcher->addListener(InvalidateMountCacheEvent::class, function (InvalidateMountCacheEvent $event,
582
+        ) {
583
+            if ($user = $event->getUser()) {
584
+                $this->cache->remove($user->getUID());
585
+            } else {
586
+                $this->cache->clear();
587
+            }
588
+        });
589
+
590
+        $genericEvents = [
591
+            'OCA\Circles\Events\CreatingCircleEvent',
592
+            'OCA\Circles\Events\DestroyingCircleEvent',
593
+            'OCA\Circles\Events\AddingCircleMemberEvent',
594
+            'OCA\Circles\Events\RemovingCircleMemberEvent',
595
+        ];
596
+
597
+        foreach ($genericEvents as $genericEvent) {
598
+            $this->eventDispatcher->addListener($genericEvent, function ($event) {
599
+                $this->cache->clear();
600
+            });
601
+        }
602
+    }
603 603
 }
Please login to merge, or discard this patch.
Spacing   +31 added lines, -31 removed lines patch added patch discarded remove patch
@@ -108,7 +108,7 @@  discard block
 block discarded – undo
108 108
 		OC_App::loadApps(['filesystem']);
109 109
 		$prevLogging = Filesystem::logWarningWhenAddingStorageWrapper(false);
110 110
 
111
-		Filesystem::addStorageWrapper('mount_options', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
111
+		Filesystem::addStorageWrapper('mount_options', function($mountPoint, IStorage $storage, IMountPoint $mount) {
112 112
 			if ($storage->instanceOfStorage(Common::class)) {
113 113
 				$options = array_merge($mount->getOptions(), ['mount_point' => $mountPoint]);
114 114
 				$storage->setMountOptions($options);
@@ -121,7 +121,7 @@  discard block
 block discarded – undo
121 121
 		$sharingEnabledForUser = $user ? !$this->shareDisableChecker->sharingDisabledForUser($user->getUID()) : true;
122 122
 		Filesystem::addStorageWrapper(
123 123
 			'sharing_mask',
124
-			function ($mountPoint, IStorage $storage, IMountPoint $mount) use ($reSharingEnabled, $sharingEnabledForUser) {
124
+			function($mountPoint, IStorage $storage, IMountPoint $mount) use ($reSharingEnabled, $sharingEnabledForUser) {
125 125
 				$sharingEnabledForMount = $mount->getOption('enable_sharing', true);
126 126
 				$isShared = $mount instanceof ISharedMountPoint;
127 127
 				if (!$sharingEnabledForMount || !$sharingEnabledForUser || (!$reSharingEnabled && $isShared)) {
@@ -135,7 +135,7 @@  discard block
 block discarded – undo
135 135
 		);
136 136
 
137 137
 		// install storage availability wrapper, before most other wrappers
138
-		Filesystem::addStorageWrapper('oc_availability', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
138
+		Filesystem::addStorageWrapper('oc_availability', function($mountPoint, IStorage $storage, IMountPoint $mount) {
139 139
 			$externalMount = $mount instanceof ExternalMountPoint || $mount instanceof Mount;
140 140
 			if ($externalMount && !$storage->isLocal()) {
141 141
 				return new Availability(['storage' => $storage]);
@@ -143,7 +143,7 @@  discard block
 block discarded – undo
143 143
 			return $storage;
144 144
 		});
145 145
 
146
-		Filesystem::addStorageWrapper('oc_encoding', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
146
+		Filesystem::addStorageWrapper('oc_encoding', function($mountPoint, IStorage $storage, IMountPoint $mount) {
147 147
 			if ($mount->getOption('encoding_compatibility', false) && !$mount instanceof SharedMount) {
148 148
 				return new Encoding(['storage' => $storage]);
149 149
 			}
@@ -151,12 +151,12 @@  discard block
 block discarded – undo
151 151
 		});
152 152
 
153 153
 		$quotaIncludeExternal = $this->config->getSystemValue('quota_include_external_storage', false);
154
-		Filesystem::addStorageWrapper('oc_quota', function ($mountPoint, $storage, IMountPoint $mount) use ($quotaIncludeExternal) {
154
+		Filesystem::addStorageWrapper('oc_quota', function($mountPoint, $storage, IMountPoint $mount) use ($quotaIncludeExternal) {
155 155
 			// set up quota for home storages, even for other users
156 156
 			// which can happen when using sharing
157 157
 			if ($mount instanceof HomeMountPoint) {
158 158
 				$user = $mount->getUser();
159
-				return new Quota(['storage' => $storage, 'quotaCallback' => function () use ($user) {
159
+				return new Quota(['storage' => $storage, 'quotaCallback' => function() use ($user) {
160 160
 					return OC_Util::getUserQuota($user);
161 161
 				}, 'root' => 'files', 'include_external_storage' => $quotaIncludeExternal]);
162 162
 			}
@@ -164,7 +164,7 @@  discard block
 block discarded – undo
164 164
 			return $storage;
165 165
 		});
166 166
 
167
-		Filesystem::addStorageWrapper('readonly', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
167
+		Filesystem::addStorageWrapper('readonly', function($mountPoint, IStorage $storage, IMountPoint $mount) {
168 168
 			/*
169 169
 			 * Do not allow any operations that modify the storage
170 170
 			 */
@@ -201,8 +201,8 @@  discard block
 block discarded – undo
201 201
 
202 202
 		$previouslySetupProviders = $this->setupUserMountProviders[$user->getUID()];
203 203
 
204
-		$this->setupForUserWith($user, function () use ($user) {
205
-			$this->mountProviderCollection->addMountForUser($user, $this->mountManager, function (
204
+		$this->setupForUserWith($user, function() use ($user) {
205
+			$this->mountProviderCollection->addMountForUser($user, $this->mountManager, function(
206 206
 				IMountProvider $provider,
207 207
 			) use ($user) {
208 208
 				return !in_array(get_class($provider), $this->setupUserMountProviders[$user->getUID()]);
@@ -237,7 +237,7 @@  discard block
 block discarded – undo
237 237
 
238 238
 		Filesystem::logWarningWhenAddingStorageWrapper($prevLogging);
239 239
 
240
-		$userDir = '/' . $user->getUID() . '/files';
240
+		$userDir = '/'.$user->getUID().'/files';
241 241
 
242 242
 		Filesystem::initInternal($userDir);
243 243
 
@@ -257,11 +257,11 @@  discard block
 block discarded – undo
257 257
 		} else {
258 258
 			$this->mountManager->addMount(new MountPoint(
259 259
 				new NullStorage([]),
260
-				'/' . $user->getUID()
260
+				'/'.$user->getUID()
261 261
 			));
262 262
 			$this->mountManager->addMount(new MountPoint(
263 263
 				new NullStorage([]),
264
-				'/' . $user->getUID() . '/files'
264
+				'/'.$user->getUID().'/files'
265 265
 			));
266 266
 			$this->setupUsersComplete[] = $user->getUID();
267 267
 		}
@@ -276,12 +276,12 @@  discard block
 block discarded – undo
276 276
 	 */
277 277
 	private function afterUserFullySetup(IUser $user, array $previouslySetupProviders): void {
278 278
 		$this->eventLogger->start('fs:setup:user:full:post', 'Housekeeping after user is setup');
279
-		$userRoot = '/' . $user->getUID() . '/';
279
+		$userRoot = '/'.$user->getUID().'/';
280 280
 		$mounts = $this->mountManager->getAll();
281
-		$mounts = array_filter($mounts, function (IMountPoint $mount) use ($userRoot) {
281
+		$mounts = array_filter($mounts, function(IMountPoint $mount) use ($userRoot) {
282 282
 			return str_starts_with($mount->getMountPoint(), $userRoot);
283 283
 		});
284
-		$allProviders = array_map(function (IMountProvider|IHomeMountProvider|IRootMountProvider $provider) {
284
+		$allProviders = array_map(function(IMountProvider | IHomeMountProvider | IRootMountProvider $provider) {
285 285
 			return get_class($provider);
286 286
 		}, array_merge(
287 287
 			$this->mountProviderCollection->getProviders(),
@@ -289,7 +289,7 @@  discard block
 block discarded – undo
289 289
 			$this->mountProviderCollection->getRootProviders(),
290 290
 		));
291 291
 		$newProviders = array_diff($allProviders, $previouslySetupProviders);
292
-		$mounts = array_filter($mounts, function (IMountPoint $mount) use ($previouslySetupProviders) {
292
+		$mounts = array_filter($mounts, function(IMountPoint $mount) use ($previouslySetupProviders) {
293 293
 			return !in_array($mount->getMountProvider(), $previouslySetupProviders);
294 294
 		});
295 295
 		$this->userMountCache->registerMounts($user, $mounts, $newProviders);
@@ -319,7 +319,7 @@  discard block
 block discarded – undo
319 319
 		\OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', ['user' => $user->getUID()]);
320 320
 		$this->eventLogger->end('fs:setup:user:post-init-mountpoint');
321 321
 
322
-		$userDir = '/' . $user->getUID() . '/files';
322
+		$userDir = '/'.$user->getUID().'/files';
323 323
 		$this->eventLogger->start('fs:setup:user:setup-hook', 'setup legacy hook');
324 324
 		OC_Hook::emit('OC_Filesystem', 'setup', ['user' => $user->getUID(), 'user_dir' => $userDir]);
325 325
 		$this->eventLogger->end('fs:setup:user:setup-hook');
@@ -363,7 +363,7 @@  discard block
 block discarded – undo
363 363
 			} else {
364 364
 				return null;
365 365
 			}
366
-		} elseif (str_starts_with($path, '/appdata_' . \OC_Util::getInstanceId()) || str_starts_with($path, '/files_external/')) {
366
+		} elseif (str_starts_with($path, '/appdata_'.\OC_Util::getInstanceId()) || str_starts_with($path, '/files_external/')) {
367 367
 			return null;
368 368
 		} else {
369 369
 			[, $userId] = explode('/', $path);
@@ -392,7 +392,7 @@  discard block
 block discarded – undo
392 392
 		}
393 393
 
394 394
 		// for the user's home folder, and includes children we need everything always
395
-		if (rtrim($path) === '/' . $user->getUID() . '/files' && $includeChildren) {
395
+		if (rtrim($path) === '/'.$user->getUID().'/files' && $includeChildren) {
396 396
 			$this->setupForUser($user);
397 397
 			return;
398 398
 		}
@@ -422,7 +422,7 @@  discard block
 block discarded – undo
422 422
 				$setupProviders[] = $cachedMount->getMountProvider();
423 423
 				$mounts = $this->mountProviderCollection->getUserMountsForProviderClasses($user, [$cachedMount->getMountProvider()]);
424 424
 			} else {
425
-				$this->logger->debug('mount at ' . $cachedMount->getMountPoint() . ' has no provider set, performing full setup');
425
+				$this->logger->debug('mount at '.$cachedMount->getMountPoint().' has no provider set, performing full setup');
426 426
 				$this->eventLogger->end('fs:setup:user:path:find');
427 427
 				$this->setupForUser($user);
428 428
 				$this->eventLogger->end('fs:setup:user:path');
@@ -434,7 +434,7 @@  discard block
 block discarded – undo
434 434
 			$subCachedMounts = $this->userMountCache->getMountsInPath($user, $path);
435 435
 			$this->eventLogger->end('fs:setup:user:path:find');
436 436
 
437
-			$needsFullSetup = array_reduce($subCachedMounts, function (bool $needsFullSetup, ICachedMountInfo $cachedMountInfo) {
437
+			$needsFullSetup = array_reduce($subCachedMounts, function(bool $needsFullSetup, ICachedMountInfo $cachedMountInfo) {
438 438
 				return $needsFullSetup || $cachedMountInfo->getMountProvider() === '';
439 439
 			}, false);
440 440
 
@@ -458,7 +458,7 @@  discard block
 block discarded – undo
458 458
 
459 459
 		if (count($mounts)) {
460 460
 			$this->userMountCache->registerMounts($user, $mounts, $currentProviders);
461
-			$this->setupForUserWith($user, function () use ($mounts) {
461
+			$this->setupForUserWith($user, function() use ($mounts) {
462 462
 				array_walk($mounts, [$this->mountManager, 'addMount']);
463 463
 			});
464 464
 		} elseif (!$this->isSetupStarted($user)) {
@@ -501,12 +501,12 @@  discard block
 block discarded – undo
501 501
 			return;
502 502
 		}
503 503
 
504
-		$this->eventLogger->start('fs:setup:user:providers', 'Setup filesystem for ' . implode(', ', $providers));
504
+		$this->eventLogger->start('fs:setup:user:providers', 'Setup filesystem for '.implode(', ', $providers));
505 505
 
506 506
 		$this->oneTimeUserSetup($user);
507 507
 
508 508
 		// home providers are always used
509
-		$providers = array_filter($providers, function (string $provider) {
509
+		$providers = array_filter($providers, function(string $provider) {
510 510
 			return !is_subclass_of($provider, IHomeMountProvider::class);
511 511
 		});
512 512
 
@@ -529,7 +529,7 @@  discard block
 block discarded – undo
529 529
 		}
530 530
 
531 531
 		$this->userMountCache->registerMounts($user, $mounts, $providers);
532
-		$this->setupForUserWith($user, function () use ($mounts) {
532
+		$this->setupForUserWith($user, function() use ($mounts) {
533 533
 			array_walk($mounts, [$this->mountManager, 'addMount']);
534 534
 		});
535 535
 		$this->eventLogger->end('fs:setup:user:providers');
@@ -551,7 +551,7 @@  discard block
 block discarded – undo
551 551
 	private function listenForNewMountProviders() {
552 552
 		if (!$this->listeningForProviders) {
553 553
 			$this->listeningForProviders = true;
554
-			$this->mountProviderCollection->listen('\OC\Files\Config', 'registerMountProvider', function (
554
+			$this->mountProviderCollection->listen('\OC\Files\Config', 'registerMountProvider', function(
555 555
 				IMountProvider $provider,
556 556
 			) {
557 557
 				foreach ($this->setupUsers as $userId) {
@@ -569,16 +569,16 @@  discard block
 block discarded – undo
569 569
 		// note that this event handling is intentionally pessimistic
570 570
 		// clearing the cache to often is better than not enough
571 571
 
572
-		$this->eventDispatcher->addListener(UserAddedEvent::class, function (UserAddedEvent $event) {
572
+		$this->eventDispatcher->addListener(UserAddedEvent::class, function(UserAddedEvent $event) {
573 573
 			$this->cache->remove($event->getUser()->getUID());
574 574
 		});
575
-		$this->eventDispatcher->addListener(UserRemovedEvent::class, function (UserRemovedEvent $event) {
575
+		$this->eventDispatcher->addListener(UserRemovedEvent::class, function(UserRemovedEvent $event) {
576 576
 			$this->cache->remove($event->getUser()->getUID());
577 577
 		});
578
-		$this->eventDispatcher->addListener(ShareCreatedEvent::class, function (ShareCreatedEvent $event) {
578
+		$this->eventDispatcher->addListener(ShareCreatedEvent::class, function(ShareCreatedEvent $event) {
579 579
 			$this->cache->remove($event->getShare()->getSharedWith());
580 580
 		});
581
-		$this->eventDispatcher->addListener(InvalidateMountCacheEvent::class, function (InvalidateMountCacheEvent $event,
581
+		$this->eventDispatcher->addListener(InvalidateMountCacheEvent::class, function(InvalidateMountCacheEvent $event,
582 582
 		) {
583 583
 			if ($user = $event->getUser()) {
584 584
 				$this->cache->remove($user->getUID());
@@ -595,7 +595,7 @@  discard block
 block discarded – undo
595 595
 		];
596 596
 
597 597
 		foreach ($genericEvents as $genericEvent) {
598
-			$this->eventDispatcher->addListener($genericEvent, function ($event) {
598
+			$this->eventDispatcher->addListener($genericEvent, function($event) {
599 599
 				$this->cache->clear();
600 600
 			});
601 601
 		}
Please login to merge, or discard this patch.
lib/private/Files/Config/MountProviderCollection.php 2 patches
Indentation   +223 added lines, -223 removed lines patch added patch discarded remove patch
@@ -21,227 +21,227 @@
 block discarded – undo
21 21
 use OCP\IUser;
22 22
 
23 23
 class MountProviderCollection implements IMountProviderCollection, Emitter {
24
-	use EmitterTrait;
25
-
26
-	/**
27
-	 * @var list<IHomeMountProvider>
28
-	 */
29
-	private array $homeProviders = [];
30
-
31
-	/**
32
-	 * @var list<IMountProvider>
33
-	 */
34
-	private array $providers = [];
35
-
36
-	/** @var list<IRootMountProvider> */
37
-	private array $rootProviders = [];
38
-
39
-	/** @var list<callable> */
40
-	private array $mountFilters = [];
41
-
42
-	public function __construct(
43
-		private IStorageFactory $loader,
44
-		private IUserMountCache $mountCache,
45
-		private IEventLogger $eventLogger,
46
-	) {
47
-	}
48
-
49
-	/**
50
-	 * @return list<IMountPoint>
51
-	 */
52
-	private function getMountsFromProvider(IMountProvider $provider, IUser $user, IStorageFactory $loader): array {
53
-		$class = str_replace('\\', '_', get_class($provider));
54
-		$uid = $user->getUID();
55
-		$this->eventLogger->start('fs:setup:provider:' . $class, "Getting mounts from $class for $uid");
56
-		$mounts = $provider->getMountsForUser($user, $loader) ?? [];
57
-		$this->eventLogger->end('fs:setup:provider:' . $class);
58
-		return array_values($mounts);
59
-	}
60
-
61
-	/**
62
-	 * @param list<IMountProvider> $providers
63
-	 * @return list<IMountPoint>
64
-	 */
65
-	private function getUserMountsForProviders(IUser $user, array $providers): array {
66
-		$loader = $this->loader;
67
-		$mounts = array_map(function (IMountProvider $provider) use ($user, $loader) {
68
-			return $this->getMountsFromProvider($provider, $user, $loader);
69
-		}, $providers);
70
-		$mounts = array_reduce($mounts, function (array $mounts, array $providerMounts) {
71
-			return array_merge($mounts, $providerMounts);
72
-		}, []);
73
-		return $this->filterMounts($user, $mounts);
74
-	}
75
-
76
-	/**
77
-	 * @return list<IMountPoint>
78
-	 */
79
-	public function getMountsForUser(IUser $user): array {
80
-		return $this->getUserMountsForProviders($user, $this->providers);
81
-	}
82
-
83
-	/**
84
-	 * @return list<IMountPoint>
85
-	 */
86
-	public function getUserMountsForProviderClasses(IUser $user, array $mountProviderClasses): array {
87
-		$providers = array_filter(
88
-			$this->providers,
89
-			fn (IMountProvider $mountProvider) => (in_array(get_class($mountProvider), $mountProviderClasses))
90
-		);
91
-		return $this->getUserMountsForProviders($user, $providers);
92
-	}
93
-
94
-	/**
95
-	 * @return list<IMountPoint>
96
-	 */
97
-	public function addMountForUser(IUser $user, IMountManager $mountManager, ?callable $providerFilter = null): array {
98
-		// shared mount provider gets to go last since it needs to know existing files
99
-		// to check for name collisions
100
-		$firstMounts = [];
101
-		if ($providerFilter) {
102
-			$providers = array_filter($this->providers, $providerFilter);
103
-		} else {
104
-			$providers = $this->providers;
105
-		}
106
-		$firstProviders = array_filter($providers, function (IMountProvider $provider) {
107
-			return (get_class($provider) !== 'OCA\Files_Sharing\MountProvider');
108
-		});
109
-		$lastProviders = array_filter($providers, function (IMountProvider $provider) {
110
-			return (get_class($provider) === 'OCA\Files_Sharing\MountProvider');
111
-		});
112
-		foreach ($firstProviders as $provider) {
113
-			$mounts = $this->getMountsFromProvider($provider, $user, $this->loader);
114
-			$firstMounts = array_merge($firstMounts, $mounts);
115
-		}
116
-		$firstMounts = $this->filterMounts($user, $firstMounts);
117
-		array_walk($firstMounts, [$mountManager, 'addMount']);
118
-
119
-		$lateMounts = [];
120
-		foreach ($lastProviders as $provider) {
121
-			$mounts = $this->getMountsFromProvider($provider, $user, $this->loader);
122
-			$lateMounts = array_merge($lateMounts, $mounts);
123
-		}
124
-
125
-		$lateMounts = $this->filterMounts($user, $lateMounts);
126
-		$this->eventLogger->start('fs:setup:add-mounts', 'Add mounts to the filesystem');
127
-		array_walk($lateMounts, [$mountManager, 'addMount']);
128
-		$this->eventLogger->end('fs:setup:add-mounts');
129
-
130
-		return array_values(array_merge($lateMounts, $firstMounts));
131
-	}
132
-
133
-	/**
134
-	 * Get the configured home mount for this user
135
-	 *
136
-	 * @since 9.1.0
137
-	 */
138
-	public function getHomeMountForUser(IUser $user): IMountPoint {
139
-		$providers = array_reverse($this->homeProviders); // call the latest registered provider first to give apps an opportunity to overwrite builtin
140
-		foreach ($providers as $homeProvider) {
141
-			if ($mount = $homeProvider->getHomeMountForUser($user, $this->loader)) {
142
-				$mount->setMountPoint('/' . $user->getUID()); //make sure the mountpoint is what we expect
143
-				return $mount;
144
-			}
145
-		}
146
-		throw new \Exception('No home storage configured for user ' . $user);
147
-	}
148
-
149
-	/**
150
-	 * Add a provider for mount points
151
-	 */
152
-	public function registerProvider(IMountProvider $provider): void {
153
-		$this->providers[] = $provider;
154
-
155
-		$this->emit('\OC\Files\Config', 'registerMountProvider', [$provider]);
156
-	}
157
-
158
-	public function registerMountFilter(callable $filter): void {
159
-		$this->mountFilters[] = $filter;
160
-	}
161
-
162
-	/**
163
-	 * @param list<IMountPoint> $mountPoints
164
-	 * @return list<IMountPoint>
165
-	 */
166
-	private function filterMounts(IUser $user, array $mountPoints): array {
167
-		return array_values(array_filter($mountPoints, function (IMountPoint $mountPoint) use ($user) {
168
-			foreach ($this->mountFilters as $filter) {
169
-				if ($filter($mountPoint, $user) === false) {
170
-					return false;
171
-				}
172
-			}
173
-			return true;
174
-		}));
175
-	}
176
-
177
-	/**
178
-	 * Add a provider for home mount points
179
-	 *
180
-	 * @param IHomeMountProvider $provider
181
-	 * @since 9.1.0
182
-	 */
183
-	public function registerHomeProvider(IHomeMountProvider $provider) {
184
-		$this->homeProviders[] = $provider;
185
-		$this->emit('\OC\Files\Config', 'registerHomeMountProvider', [$provider]);
186
-	}
187
-
188
-	/**
189
-	 * Get the mount cache which can be used to search for mounts without setting up the filesystem
190
-	 */
191
-	public function getMountCache(): IUserMountCache {
192
-		return $this->mountCache;
193
-	}
194
-
195
-	public function registerRootProvider(IRootMountProvider $provider): void {
196
-		$this->rootProviders[] = $provider;
197
-	}
198
-
199
-	/**
200
-	 * Get all root mountpoints
201
-	 *
202
-	 * @return list<IMountPoint>
203
-	 * @since 20.0.0
204
-	 */
205
-	public function getRootMounts(): array {
206
-		$loader = $this->loader;
207
-		$mounts = array_map(function (IRootMountProvider $provider) use ($loader) {
208
-			return $provider->getRootMounts($loader);
209
-		}, $this->rootProviders);
210
-		$mounts = array_reduce($mounts, function (array $mounts, array $providerMounts) {
211
-			return array_merge($mounts, $providerMounts);
212
-		}, []);
213
-
214
-		if (count($mounts) === 0) {
215
-			throw new \Exception('No root mounts provided by any provider');
216
-		}
217
-
218
-		return array_values($mounts);
219
-	}
220
-
221
-	public function clearProviders(): void {
222
-		$this->providers = [];
223
-		$this->homeProviders = [];
224
-		$this->rootProviders = [];
225
-	}
226
-
227
-	/**
228
-	 * @return list<IMountProvider>
229
-	 */
230
-	public function getProviders(): array {
231
-		return $this->providers;
232
-	}
233
-
234
-	/**
235
-	 * @return list<IHomeMountProvider>
236
-	 */
237
-	public function getHomeProviders(): array {
238
-		return $this->homeProviders;
239
-	}
240
-
241
-	/**
242
-	 * @return list<IRootMountProvider>
243
-	 */
244
-	public function getRootProviders(): array {
245
-		return $this->rootProviders;
246
-	}
24
+    use EmitterTrait;
25
+
26
+    /**
27
+     * @var list<IHomeMountProvider>
28
+     */
29
+    private array $homeProviders = [];
30
+
31
+    /**
32
+     * @var list<IMountProvider>
33
+     */
34
+    private array $providers = [];
35
+
36
+    /** @var list<IRootMountProvider> */
37
+    private array $rootProviders = [];
38
+
39
+    /** @var list<callable> */
40
+    private array $mountFilters = [];
41
+
42
+    public function __construct(
43
+        private IStorageFactory $loader,
44
+        private IUserMountCache $mountCache,
45
+        private IEventLogger $eventLogger,
46
+    ) {
47
+    }
48
+
49
+    /**
50
+     * @return list<IMountPoint>
51
+     */
52
+    private function getMountsFromProvider(IMountProvider $provider, IUser $user, IStorageFactory $loader): array {
53
+        $class = str_replace('\\', '_', get_class($provider));
54
+        $uid = $user->getUID();
55
+        $this->eventLogger->start('fs:setup:provider:' . $class, "Getting mounts from $class for $uid");
56
+        $mounts = $provider->getMountsForUser($user, $loader) ?? [];
57
+        $this->eventLogger->end('fs:setup:provider:' . $class);
58
+        return array_values($mounts);
59
+    }
60
+
61
+    /**
62
+     * @param list<IMountProvider> $providers
63
+     * @return list<IMountPoint>
64
+     */
65
+    private function getUserMountsForProviders(IUser $user, array $providers): array {
66
+        $loader = $this->loader;
67
+        $mounts = array_map(function (IMountProvider $provider) use ($user, $loader) {
68
+            return $this->getMountsFromProvider($provider, $user, $loader);
69
+        }, $providers);
70
+        $mounts = array_reduce($mounts, function (array $mounts, array $providerMounts) {
71
+            return array_merge($mounts, $providerMounts);
72
+        }, []);
73
+        return $this->filterMounts($user, $mounts);
74
+    }
75
+
76
+    /**
77
+     * @return list<IMountPoint>
78
+     */
79
+    public function getMountsForUser(IUser $user): array {
80
+        return $this->getUserMountsForProviders($user, $this->providers);
81
+    }
82
+
83
+    /**
84
+     * @return list<IMountPoint>
85
+     */
86
+    public function getUserMountsForProviderClasses(IUser $user, array $mountProviderClasses): array {
87
+        $providers = array_filter(
88
+            $this->providers,
89
+            fn (IMountProvider $mountProvider) => (in_array(get_class($mountProvider), $mountProviderClasses))
90
+        );
91
+        return $this->getUserMountsForProviders($user, $providers);
92
+    }
93
+
94
+    /**
95
+     * @return list<IMountPoint>
96
+     */
97
+    public function addMountForUser(IUser $user, IMountManager $mountManager, ?callable $providerFilter = null): array {
98
+        // shared mount provider gets to go last since it needs to know existing files
99
+        // to check for name collisions
100
+        $firstMounts = [];
101
+        if ($providerFilter) {
102
+            $providers = array_filter($this->providers, $providerFilter);
103
+        } else {
104
+            $providers = $this->providers;
105
+        }
106
+        $firstProviders = array_filter($providers, function (IMountProvider $provider) {
107
+            return (get_class($provider) !== 'OCA\Files_Sharing\MountProvider');
108
+        });
109
+        $lastProviders = array_filter($providers, function (IMountProvider $provider) {
110
+            return (get_class($provider) === 'OCA\Files_Sharing\MountProvider');
111
+        });
112
+        foreach ($firstProviders as $provider) {
113
+            $mounts = $this->getMountsFromProvider($provider, $user, $this->loader);
114
+            $firstMounts = array_merge($firstMounts, $mounts);
115
+        }
116
+        $firstMounts = $this->filterMounts($user, $firstMounts);
117
+        array_walk($firstMounts, [$mountManager, 'addMount']);
118
+
119
+        $lateMounts = [];
120
+        foreach ($lastProviders as $provider) {
121
+            $mounts = $this->getMountsFromProvider($provider, $user, $this->loader);
122
+            $lateMounts = array_merge($lateMounts, $mounts);
123
+        }
124
+
125
+        $lateMounts = $this->filterMounts($user, $lateMounts);
126
+        $this->eventLogger->start('fs:setup:add-mounts', 'Add mounts to the filesystem');
127
+        array_walk($lateMounts, [$mountManager, 'addMount']);
128
+        $this->eventLogger->end('fs:setup:add-mounts');
129
+
130
+        return array_values(array_merge($lateMounts, $firstMounts));
131
+    }
132
+
133
+    /**
134
+     * Get the configured home mount for this user
135
+     *
136
+     * @since 9.1.0
137
+     */
138
+    public function getHomeMountForUser(IUser $user): IMountPoint {
139
+        $providers = array_reverse($this->homeProviders); // call the latest registered provider first to give apps an opportunity to overwrite builtin
140
+        foreach ($providers as $homeProvider) {
141
+            if ($mount = $homeProvider->getHomeMountForUser($user, $this->loader)) {
142
+                $mount->setMountPoint('/' . $user->getUID()); //make sure the mountpoint is what we expect
143
+                return $mount;
144
+            }
145
+        }
146
+        throw new \Exception('No home storage configured for user ' . $user);
147
+    }
148
+
149
+    /**
150
+     * Add a provider for mount points
151
+     */
152
+    public function registerProvider(IMountProvider $provider): void {
153
+        $this->providers[] = $provider;
154
+
155
+        $this->emit('\OC\Files\Config', 'registerMountProvider', [$provider]);
156
+    }
157
+
158
+    public function registerMountFilter(callable $filter): void {
159
+        $this->mountFilters[] = $filter;
160
+    }
161
+
162
+    /**
163
+     * @param list<IMountPoint> $mountPoints
164
+     * @return list<IMountPoint>
165
+     */
166
+    private function filterMounts(IUser $user, array $mountPoints): array {
167
+        return array_values(array_filter($mountPoints, function (IMountPoint $mountPoint) use ($user) {
168
+            foreach ($this->mountFilters as $filter) {
169
+                if ($filter($mountPoint, $user) === false) {
170
+                    return false;
171
+                }
172
+            }
173
+            return true;
174
+        }));
175
+    }
176
+
177
+    /**
178
+     * Add a provider for home mount points
179
+     *
180
+     * @param IHomeMountProvider $provider
181
+     * @since 9.1.0
182
+     */
183
+    public function registerHomeProvider(IHomeMountProvider $provider) {
184
+        $this->homeProviders[] = $provider;
185
+        $this->emit('\OC\Files\Config', 'registerHomeMountProvider', [$provider]);
186
+    }
187
+
188
+    /**
189
+     * Get the mount cache which can be used to search for mounts without setting up the filesystem
190
+     */
191
+    public function getMountCache(): IUserMountCache {
192
+        return $this->mountCache;
193
+    }
194
+
195
+    public function registerRootProvider(IRootMountProvider $provider): void {
196
+        $this->rootProviders[] = $provider;
197
+    }
198
+
199
+    /**
200
+     * Get all root mountpoints
201
+     *
202
+     * @return list<IMountPoint>
203
+     * @since 20.0.0
204
+     */
205
+    public function getRootMounts(): array {
206
+        $loader = $this->loader;
207
+        $mounts = array_map(function (IRootMountProvider $provider) use ($loader) {
208
+            return $provider->getRootMounts($loader);
209
+        }, $this->rootProviders);
210
+        $mounts = array_reduce($mounts, function (array $mounts, array $providerMounts) {
211
+            return array_merge($mounts, $providerMounts);
212
+        }, []);
213
+
214
+        if (count($mounts) === 0) {
215
+            throw new \Exception('No root mounts provided by any provider');
216
+        }
217
+
218
+        return array_values($mounts);
219
+    }
220
+
221
+    public function clearProviders(): void {
222
+        $this->providers = [];
223
+        $this->homeProviders = [];
224
+        $this->rootProviders = [];
225
+    }
226
+
227
+    /**
228
+     * @return list<IMountProvider>
229
+     */
230
+    public function getProviders(): array {
231
+        return $this->providers;
232
+    }
233
+
234
+    /**
235
+     * @return list<IHomeMountProvider>
236
+     */
237
+    public function getHomeProviders(): array {
238
+        return $this->homeProviders;
239
+    }
240
+
241
+    /**
242
+     * @return list<IRootMountProvider>
243
+     */
244
+    public function getRootProviders(): array {
245
+        return $this->rootProviders;
246
+    }
247 247
 }
Please login to merge, or discard this patch.
Spacing   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -52,9 +52,9 @@  discard block
 block discarded – undo
52 52
 	private function getMountsFromProvider(IMountProvider $provider, IUser $user, IStorageFactory $loader): array {
53 53
 		$class = str_replace('\\', '_', get_class($provider));
54 54
 		$uid = $user->getUID();
55
-		$this->eventLogger->start('fs:setup:provider:' . $class, "Getting mounts from $class for $uid");
55
+		$this->eventLogger->start('fs:setup:provider:'.$class, "Getting mounts from $class for $uid");
56 56
 		$mounts = $provider->getMountsForUser($user, $loader) ?? [];
57
-		$this->eventLogger->end('fs:setup:provider:' . $class);
57
+		$this->eventLogger->end('fs:setup:provider:'.$class);
58 58
 		return array_values($mounts);
59 59
 	}
60 60
 
@@ -64,10 +64,10 @@  discard block
 block discarded – undo
64 64
 	 */
65 65
 	private function getUserMountsForProviders(IUser $user, array $providers): array {
66 66
 		$loader = $this->loader;
67
-		$mounts = array_map(function (IMountProvider $provider) use ($user, $loader) {
67
+		$mounts = array_map(function(IMountProvider $provider) use ($user, $loader) {
68 68
 			return $this->getMountsFromProvider($provider, $user, $loader);
69 69
 		}, $providers);
70
-		$mounts = array_reduce($mounts, function (array $mounts, array $providerMounts) {
70
+		$mounts = array_reduce($mounts, function(array $mounts, array $providerMounts) {
71 71
 			return array_merge($mounts, $providerMounts);
72 72
 		}, []);
73 73
 		return $this->filterMounts($user, $mounts);
@@ -103,10 +103,10 @@  discard block
 block discarded – undo
103 103
 		} else {
104 104
 			$providers = $this->providers;
105 105
 		}
106
-		$firstProviders = array_filter($providers, function (IMountProvider $provider) {
106
+		$firstProviders = array_filter($providers, function(IMountProvider $provider) {
107 107
 			return (get_class($provider) !== 'OCA\Files_Sharing\MountProvider');
108 108
 		});
109
-		$lastProviders = array_filter($providers, function (IMountProvider $provider) {
109
+		$lastProviders = array_filter($providers, function(IMountProvider $provider) {
110 110
 			return (get_class($provider) === 'OCA\Files_Sharing\MountProvider');
111 111
 		});
112 112
 		foreach ($firstProviders as $provider) {
@@ -139,11 +139,11 @@  discard block
 block discarded – undo
139 139
 		$providers = array_reverse($this->homeProviders); // call the latest registered provider first to give apps an opportunity to overwrite builtin
140 140
 		foreach ($providers as $homeProvider) {
141 141
 			if ($mount = $homeProvider->getHomeMountForUser($user, $this->loader)) {
142
-				$mount->setMountPoint('/' . $user->getUID()); //make sure the mountpoint is what we expect
142
+				$mount->setMountPoint('/'.$user->getUID()); //make sure the mountpoint is what we expect
143 143
 				return $mount;
144 144
 			}
145 145
 		}
146
-		throw new \Exception('No home storage configured for user ' . $user);
146
+		throw new \Exception('No home storage configured for user '.$user);
147 147
 	}
148 148
 
149 149
 	/**
@@ -164,7 +164,7 @@  discard block
 block discarded – undo
164 164
 	 * @return list<IMountPoint>
165 165
 	 */
166 166
 	private function filterMounts(IUser $user, array $mountPoints): array {
167
-		return array_values(array_filter($mountPoints, function (IMountPoint $mountPoint) use ($user) {
167
+		return array_values(array_filter($mountPoints, function(IMountPoint $mountPoint) use ($user) {
168 168
 			foreach ($this->mountFilters as $filter) {
169 169
 				if ($filter($mountPoint, $user) === false) {
170 170
 					return false;
@@ -204,10 +204,10 @@  discard block
 block discarded – undo
204 204
 	 */
205 205
 	public function getRootMounts(): array {
206 206
 		$loader = $this->loader;
207
-		$mounts = array_map(function (IRootMountProvider $provider) use ($loader) {
207
+		$mounts = array_map(function(IRootMountProvider $provider) use ($loader) {
208 208
 			return $provider->getRootMounts($loader);
209 209
 		}, $this->rootProviders);
210
-		$mounts = array_reduce($mounts, function (array $mounts, array $providerMounts) {
210
+		$mounts = array_reduce($mounts, function(array $mounts, array $providerMounts) {
211 211
 			return array_merge($mounts, $providerMounts);
212 212
 		}, []);
213 213
 
Please login to merge, or discard this patch.