Passed
Push — master ( 54f366...417f46 )
by Blizzz
15:08 queued 13s
created
lib/private/Files/SetupManager.php 2 patches
Indentation   +511 added lines, -511 removed lines patch added patch discarded remove patch
@@ -62,517 +62,517 @@
 block discarded – undo
62 62
 use Psr\Log\LoggerInterface;
63 63
 
64 64
 class SetupManager {
65
-	private bool $rootSetup = false;
66
-	private IEventLogger $eventLogger;
67
-	private MountProviderCollection $mountProviderCollection;
68
-	private IMountManager $mountManager;
69
-	private IUserManager $userManager;
70
-	// List of users for which at least one mount is setup
71
-	private array $setupUsers = [];
72
-	// List of users for which all mounts are setup
73
-	private array $setupUsersComplete = [];
74
-	/** @var array<string, string[]> */
75
-	private array $setupUserMountProviders = [];
76
-	private IEventDispatcher $eventDispatcher;
77
-	private IUserMountCache $userMountCache;
78
-	private ILockdownManager $lockdownManager;
79
-	private IUserSession $userSession;
80
-	private ICache $cache;
81
-	private LoggerInterface $logger;
82
-	private IConfig $config;
83
-	private bool $listeningForProviders;
84
-	private array $fullSetupRequired = [];
85
-	private bool $setupBuiltinWrappersDone = false;
86
-
87
-	public function __construct(
88
-		IEventLogger $eventLogger,
89
-		MountProviderCollection $mountProviderCollection,
90
-		IMountManager $mountManager,
91
-		IUserManager $userManager,
92
-		IEventDispatcher $eventDispatcher,
93
-		IUserMountCache $userMountCache,
94
-		ILockdownManager $lockdownManager,
95
-		IUserSession $userSession,
96
-		ICacheFactory $cacheFactory,
97
-		LoggerInterface $logger,
98
-		IConfig $config
99
-	) {
100
-		$this->eventLogger = $eventLogger;
101
-		$this->mountProviderCollection = $mountProviderCollection;
102
-		$this->mountManager = $mountManager;
103
-		$this->userManager = $userManager;
104
-		$this->eventDispatcher = $eventDispatcher;
105
-		$this->userMountCache = $userMountCache;
106
-		$this->lockdownManager = $lockdownManager;
107
-		$this->logger = $logger;
108
-		$this->userSession = $userSession;
109
-		$this->cache = $cacheFactory->createDistributed('setupmanager::');
110
-		$this->listeningForProviders = false;
111
-		$this->config = $config;
112
-
113
-		$this->setupListeners();
114
-	}
115
-
116
-	private function isSetupStarted(IUser $user): bool {
117
-		return in_array($user->getUID(), $this->setupUsers, true);
118
-	}
119
-
120
-	public function isSetupComplete(IUser $user): bool {
121
-		return in_array($user->getUID(), $this->setupUsersComplete, true);
122
-	}
123
-
124
-	private function setupBuiltinWrappers() {
125
-		if ($this->setupBuiltinWrappersDone) {
126
-			return;
127
-		}
128
-		$this->setupBuiltinWrappersDone = true;
129
-
130
-		// load all filesystem apps before, so no setup-hook gets lost
131
-		OC_App::loadApps(['filesystem']);
132
-		$prevLogging = Filesystem::logWarningWhenAddingStorageWrapper(false);
133
-
134
-		Filesystem::addStorageWrapper('mount_options', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
135
-			if ($storage->instanceOfStorage(Common::class)) {
136
-				$storage->setMountOptions($mount->getOptions());
137
-			}
138
-			return $storage;
139
-		});
140
-
141
-		Filesystem::addStorageWrapper('enable_sharing', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
142
-			if (!$mount->getOption('enable_sharing', true)) {
143
-				return new PermissionsMask([
144
-					'storage' => $storage,
145
-					'mask' => Constants::PERMISSION_ALL - Constants::PERMISSION_SHARE,
146
-				]);
147
-			}
148
-			return $storage;
149
-		});
150
-
151
-		// install storage availability wrapper, before most other wrappers
152
-		Filesystem::addStorageWrapper('oc_availability', function ($mountPoint, IStorage $storage) {
153
-			if (!$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage') && !$storage->isLocal()) {
154
-				return new Availability(['storage' => $storage]);
155
-			}
156
-			return $storage;
157
-		});
158
-
159
-		Filesystem::addStorageWrapper('oc_encoding', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
160
-			if ($mount->getOption('encoding_compatibility', false) && !$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) {
161
-				return new Encoding(['storage' => $storage]);
162
-			}
163
-			return $storage;
164
-		});
165
-
166
-		Filesystem::addStorageWrapper('oc_quota', function ($mountPoint, $storage) {
167
-			// set up quota for home storages, even for other users
168
-			// which can happen when using sharing
169
-
170
-			/**
171
-			 * @var Storage $storage
172
-			 */
173
-			if ($storage->instanceOfStorage(HomeObjectStoreStorage::class) || $storage->instanceOfStorage(Home::class)) {
174
-				if (is_object($storage->getUser())) {
175
-					$user = $storage->getUser();
176
-					return new Quota(['storage' => $storage, 'quotaCallback' => function () use ($user) {
177
-						return OC_Util::getUserQuota($user);
178
-					}, 'root' => 'files']);
179
-				}
180
-			}
181
-
182
-			return $storage;
183
-		});
184
-
185
-		Filesystem::addStorageWrapper('readonly', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
186
-			/*
65
+    private bool $rootSetup = false;
66
+    private IEventLogger $eventLogger;
67
+    private MountProviderCollection $mountProviderCollection;
68
+    private IMountManager $mountManager;
69
+    private IUserManager $userManager;
70
+    // List of users for which at least one mount is setup
71
+    private array $setupUsers = [];
72
+    // List of users for which all mounts are setup
73
+    private array $setupUsersComplete = [];
74
+    /** @var array<string, string[]> */
75
+    private array $setupUserMountProviders = [];
76
+    private IEventDispatcher $eventDispatcher;
77
+    private IUserMountCache $userMountCache;
78
+    private ILockdownManager $lockdownManager;
79
+    private IUserSession $userSession;
80
+    private ICache $cache;
81
+    private LoggerInterface $logger;
82
+    private IConfig $config;
83
+    private bool $listeningForProviders;
84
+    private array $fullSetupRequired = [];
85
+    private bool $setupBuiltinWrappersDone = false;
86
+
87
+    public function __construct(
88
+        IEventLogger $eventLogger,
89
+        MountProviderCollection $mountProviderCollection,
90
+        IMountManager $mountManager,
91
+        IUserManager $userManager,
92
+        IEventDispatcher $eventDispatcher,
93
+        IUserMountCache $userMountCache,
94
+        ILockdownManager $lockdownManager,
95
+        IUserSession $userSession,
96
+        ICacheFactory $cacheFactory,
97
+        LoggerInterface $logger,
98
+        IConfig $config
99
+    ) {
100
+        $this->eventLogger = $eventLogger;
101
+        $this->mountProviderCollection = $mountProviderCollection;
102
+        $this->mountManager = $mountManager;
103
+        $this->userManager = $userManager;
104
+        $this->eventDispatcher = $eventDispatcher;
105
+        $this->userMountCache = $userMountCache;
106
+        $this->lockdownManager = $lockdownManager;
107
+        $this->logger = $logger;
108
+        $this->userSession = $userSession;
109
+        $this->cache = $cacheFactory->createDistributed('setupmanager::');
110
+        $this->listeningForProviders = false;
111
+        $this->config = $config;
112
+
113
+        $this->setupListeners();
114
+    }
115
+
116
+    private function isSetupStarted(IUser $user): bool {
117
+        return in_array($user->getUID(), $this->setupUsers, true);
118
+    }
119
+
120
+    public function isSetupComplete(IUser $user): bool {
121
+        return in_array($user->getUID(), $this->setupUsersComplete, true);
122
+    }
123
+
124
+    private function setupBuiltinWrappers() {
125
+        if ($this->setupBuiltinWrappersDone) {
126
+            return;
127
+        }
128
+        $this->setupBuiltinWrappersDone = true;
129
+
130
+        // load all filesystem apps before, so no setup-hook gets lost
131
+        OC_App::loadApps(['filesystem']);
132
+        $prevLogging = Filesystem::logWarningWhenAddingStorageWrapper(false);
133
+
134
+        Filesystem::addStorageWrapper('mount_options', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
135
+            if ($storage->instanceOfStorage(Common::class)) {
136
+                $storage->setMountOptions($mount->getOptions());
137
+            }
138
+            return $storage;
139
+        });
140
+
141
+        Filesystem::addStorageWrapper('enable_sharing', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
142
+            if (!$mount->getOption('enable_sharing', true)) {
143
+                return new PermissionsMask([
144
+                    'storage' => $storage,
145
+                    'mask' => Constants::PERMISSION_ALL - Constants::PERMISSION_SHARE,
146
+                ]);
147
+            }
148
+            return $storage;
149
+        });
150
+
151
+        // install storage availability wrapper, before most other wrappers
152
+        Filesystem::addStorageWrapper('oc_availability', function ($mountPoint, IStorage $storage) {
153
+            if (!$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage') && !$storage->isLocal()) {
154
+                return new Availability(['storage' => $storage]);
155
+            }
156
+            return $storage;
157
+        });
158
+
159
+        Filesystem::addStorageWrapper('oc_encoding', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
160
+            if ($mount->getOption('encoding_compatibility', false) && !$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) {
161
+                return new Encoding(['storage' => $storage]);
162
+            }
163
+            return $storage;
164
+        });
165
+
166
+        Filesystem::addStorageWrapper('oc_quota', function ($mountPoint, $storage) {
167
+            // set up quota for home storages, even for other users
168
+            // which can happen when using sharing
169
+
170
+            /**
171
+             * @var Storage $storage
172
+             */
173
+            if ($storage->instanceOfStorage(HomeObjectStoreStorage::class) || $storage->instanceOfStorage(Home::class)) {
174
+                if (is_object($storage->getUser())) {
175
+                    $user = $storage->getUser();
176
+                    return new Quota(['storage' => $storage, 'quotaCallback' => function () use ($user) {
177
+                        return OC_Util::getUserQuota($user);
178
+                    }, 'root' => 'files']);
179
+                }
180
+            }
181
+
182
+            return $storage;
183
+        });
184
+
185
+        Filesystem::addStorageWrapper('readonly', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
186
+            /*
187 187
 			 * Do not allow any operations that modify the storage
188 188
 			 */
189
-			if ($mount->getOption('readonly', false)) {
190
-				return new PermissionsMask([
191
-					'storage' => $storage,
192
-					'mask' => Constants::PERMISSION_ALL & ~(
193
-							Constants::PERMISSION_UPDATE |
194
-							Constants::PERMISSION_CREATE |
195
-							Constants::PERMISSION_DELETE
196
-						),
197
-				]);
198
-			}
199
-			return $storage;
200
-		});
201
-
202
-		Filesystem::logWarningWhenAddingStorageWrapper($prevLogging);
203
-	}
204
-
205
-	/**
206
-	 * Setup the full filesystem for the specified user
207
-	 */
208
-	public function setupForUser(IUser $user): void {
209
-		if ($this->isSetupComplete($user)) {
210
-			return;
211
-		}
212
-		$this->setupUsersComplete[] = $user->getUID();
213
-
214
-		if (!isset($this->setupUserMountProviders[$user->getUID()])) {
215
-			$this->setupUserMountProviders[$user->getUID()] = [];
216
-		}
217
-
218
-		$previouslySetupProviders = $this->setupUserMountProviders[$user->getUID()];
219
-
220
-		$this->setupForUserWith($user, function () use ($user) {
221
-			$this->mountProviderCollection->addMountForUser($user, $this->mountManager, function (
222
-				IMountProvider $provider
223
-			) use ($user) {
224
-				return !in_array(get_class($provider), $this->setupUserMountProviders[$user->getUID()]);
225
-			});
226
-		});
227
-		$this->afterUserFullySetup($user, $previouslySetupProviders);
228
-	}
229
-
230
-	/**
231
-	 * part of the user setup that is run only once per user
232
-	 */
233
-	private function oneTimeUserSetup(IUser $user) {
234
-		if (in_array($user->getUID(), $this->setupUsers, true)) {
235
-			return;
236
-		}
237
-		$this->setupUsers[] = $user->getUID();
238
-
239
-		$this->setupBuiltinWrappers();
240
-
241
-		$prevLogging = Filesystem::logWarningWhenAddingStorageWrapper(false);
242
-
243
-		OC_Hook::emit('OC_Filesystem', 'preSetup', ['user' => $user->getUID()]);
244
-
245
-		Filesystem::logWarningWhenAddingStorageWrapper($prevLogging);
246
-
247
-		$userDir = '/' . $user->getUID() . '/files';
248
-
249
-		Filesystem::initInternal($userDir);
250
-
251
-		if ($this->lockdownManager->canAccessFilesystem()) {
252
-			// home mounts are handled separate since we need to ensure this is mounted before we call the other mount providers
253
-			$homeMount = $this->mountProviderCollection->getHomeMountForUser($user);
254
-			$this->mountManager->addMount($homeMount);
255
-
256
-			if ($homeMount->getStorageRootId() === -1) {
257
-				$homeMount->getStorage()->mkdir('');
258
-				$homeMount->getStorage()->getScanner()->scan('');
259
-			}
260
-		} else {
261
-			$this->mountManager->addMount(new MountPoint(
262
-				new NullStorage([]),
263
-				'/' . $user->getUID()
264
-			));
265
-			$this->mountManager->addMount(new MountPoint(
266
-				new NullStorage([]),
267
-				'/' . $user->getUID() . '/files'
268
-			));
269
-			$this->setupUsersComplete[] = $user->getUID();
270
-		}
271
-
272
-		$this->listenForNewMountProviders();
273
-	}
274
-
275
-	/**
276
-	 * Final housekeeping after a user has been fully setup
277
-	 */
278
-	private function afterUserFullySetup(IUser $user, array $previouslySetupProviders): void {
279
-		$userRoot = '/' . $user->getUID() . '/';
280
-		$mounts = $this->mountManager->getAll();
281
-		$mounts = array_filter($mounts, function (IMountPoint $mount) use ($userRoot) {
282
-			return strpos($mount->getMountPoint(), $userRoot) === 0;
283
-		});
284
-		$allProviders = array_map(function (IMountProvider $provider) {
285
-			return get_class($provider);
286
-		}, $this->mountProviderCollection->getProviders());
287
-		$newProviders = array_diff($allProviders, $previouslySetupProviders);
288
-		$mounts = array_filter($mounts, function (IMountPoint $mount) use ($previouslySetupProviders) {
289
-			return !in_array($mount->getMountProvider(), $previouslySetupProviders);
290
-		});
291
-		$this->userMountCache->registerMounts($user, $mounts, $newProviders);
292
-
293
-		$cacheDuration = $this->config->getSystemValueInt('fs_mount_cache_duration', 5 * 60);
294
-		if ($cacheDuration > 0) {
295
-			$this->cache->set($user->getUID(), true, $cacheDuration);
296
-			$this->fullSetupRequired[$user->getUID()] = false;
297
-		}
298
-	}
299
-
300
-	/**
301
-	 * @param IUser $user
302
-	 * @param IMountPoint $mounts
303
-	 * @return void
304
-	 * @throws \OCP\HintException
305
-	 * @throws \OC\ServerNotAvailableException
306
-	 */
307
-	private function setupForUserWith(IUser $user, callable $mountCallback): void {
308
-		$this->setupRoot();
309
-
310
-		if (!$this->isSetupStarted($user)) {
311
-			$this->oneTimeUserSetup($user);
312
-		}
313
-
314
-		$this->eventLogger->start('setup_fs', 'Setup filesystem');
315
-
316
-		if ($this->lockdownManager->canAccessFilesystem()) {
317
-			$mountCallback();
318
-		}
319
-		\OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', ['user' => $user->getUID()]);
320
-
321
-		$userDir = '/' . $user->getUID() . '/files';
322
-		OC_Hook::emit('OC_Filesystem', 'setup', ['user' => $user->getUID(), 'user_dir' => $userDir]);
323
-
324
-		$this->eventLogger->end('setup_fs');
325
-	}
326
-
327
-	/**
328
-	 * Set up the root filesystem
329
-	 */
330
-	public function setupRoot(): void {
331
-		//setting up the filesystem twice can only lead to trouble
332
-		if ($this->rootSetup) {
333
-			return;
334
-		}
335
-		$this->rootSetup = true;
336
-
337
-		$this->eventLogger->start('setup_root_fs', 'Setup root filesystem');
338
-
339
-		$this->setupBuiltinWrappers();
340
-
341
-		$rootMounts = $this->mountProviderCollection->getRootMounts();
342
-		foreach ($rootMounts as $rootMountProvider) {
343
-			$this->mountManager->addMount($rootMountProvider);
344
-		}
345
-
346
-		$this->eventLogger->end('setup_root_fs');
347
-	}
348
-
349
-	/**
350
-	 * Get the user to setup for a path or `null` if the root needs to be setup
351
-	 *
352
-	 * @param string $path
353
-	 * @return IUser|null
354
-	 */
355
-	private function getUserForPath(string $path) {
356
-		if (strpos($path, '/__groupfolders') === 0) {
357
-			return null;
358
-		} elseif (substr_count($path, '/') < 2) {
359
-			if ($user = $this->userSession->getUser()) {
360
-				return $user;
361
-			} else {
362
-				return null;
363
-			}
364
-		} elseif (strpos($path, '/appdata_' . \OC_Util::getInstanceId()) === 0 || strpos($path, '/files_external/') === 0) {
365
-			return null;
366
-		} else {
367
-			[, $userId] = explode('/', $path);
368
-		}
369
-
370
-		return $this->userManager->get($userId);
371
-	}
372
-
373
-	/**
374
-	 * Set up the filesystem for the specified path
375
-	 */
376
-	public function setupForPath(string $path, bool $includeChildren = false): void {
377
-		$user = $this->getUserForPath($path);
378
-		if (!$user) {
379
-			$this->setupRoot();
380
-			return;
381
-		}
382
-
383
-		if ($this->isSetupComplete($user)) {
384
-			return;
385
-		}
386
-
387
-		if ($this->fullSetupRequired($user)) {
388
-			$this->setupForUser($user);
389
-			return;
390
-		}
391
-
392
-		// for the user's home folder, and includes children we need everything always
393
-		if (rtrim($path) === "/" . $user->getUID() . "/files" && $includeChildren) {
394
-			$this->setupForUser($user);
395
-			return;
396
-		}
397
-
398
-		if (!isset($this->setupUserMountProviders[$user->getUID()])) {
399
-			$this->setupUserMountProviders[$user->getUID()] = [];
400
-		}
401
-		$setupProviders = &$this->setupUserMountProviders[$user->getUID()];
402
-		$currentProviders = [];
403
-
404
-		try {
405
-			$cachedMount = $this->userMountCache->getMountForPath($user, $path);
406
-		} catch (NotFoundException $e) {
407
-			$this->setupForUser($user);
408
-			return;
409
-		}
410
-
411
-		if (!$this->isSetupStarted($user)) {
412
-			$this->oneTimeUserSetup($user);
413
-		}
414
-
415
-		$mounts = [];
416
-		if (!in_array($cachedMount->getMountProvider(), $setupProviders)) {
417
-			$setupProviders[] = $cachedMount->getMountProvider();
418
-			$currentProviders[] = $cachedMount->getMountProvider();
419
-			if ($cachedMount->getMountProvider()) {
420
-				$mounts = $this->mountProviderCollection->getUserMountsForProviderClasses($user, [$cachedMount->getMountProvider()]);
421
-			} else {
422
-				$this->logger->debug("mount at " . $cachedMount->getMountPoint() . " has no provider set, performing full setup");
423
-				$this->setupForUser($user);
424
-				return;
425
-			}
426
-		}
427
-
428
-		if ($includeChildren) {
429
-			$subCachedMounts = $this->userMountCache->getMountsInPath($user, $path);
430
-			foreach ($subCachedMounts as $cachedMount) {
431
-				if (!in_array($cachedMount->getMountProvider(), $setupProviders)) {
432
-					$setupProviders[] = $cachedMount->getMountProvider();
433
-					$currentProviders[] = $cachedMount->getMountProvider();
434
-					if ($cachedMount->getMountProvider()) {
435
-						$mounts = array_merge($mounts, $this->mountProviderCollection->getUserMountsForProviderClasses($user, [$cachedMount->getMountProvider()]));
436
-					} else {
437
-						$this->logger->debug("mount at " . $cachedMount->getMountPoint() . " has no provider set, performing full setup");
438
-						$this->setupForUser($user);
439
-						return;
440
-					}
441
-				}
442
-			}
443
-		}
444
-
445
-		if (count($mounts)) {
446
-			$this->userMountCache->registerMounts($user, $mounts, $currentProviders);
447
-			$this->setupForUserWith($user, function () use ($mounts) {
448
-				array_walk($mounts, [$this->mountManager, 'addMount']);
449
-			});
450
-		} elseif (!$this->isSetupStarted($user)) {
451
-			$this->oneTimeUserSetup($user);
452
-		}
453
-	}
454
-
455
-	private function fullSetupRequired(IUser $user): bool {
456
-		// we perform a "cached" setup only after having done the full setup recently
457
-		// this is also used to trigger a full setup after handling events that are likely
458
-		// to change the available mounts
459
-		if (!isset($this->fullSetupRequired[$user->getUID()])) {
460
-			$this->fullSetupRequired[$user->getUID()] = !$this->cache->get($user->getUID());
461
-		}
462
-		return $this->fullSetupRequired[$user->getUID()];
463
-	}
464
-
465
-	/**
466
-	 * @param string $path
467
-	 * @param string[] $providers
468
-	 */
469
-	public function setupForProvider(string $path, array $providers): void {
470
-		$user = $this->getUserForPath($path);
471
-		if (!$user) {
472
-			$this->setupRoot();
473
-			return;
474
-		}
475
-
476
-		if ($this->isSetupComplete($user)) {
477
-			return;
478
-		}
479
-
480
-		if ($this->fullSetupRequired($user)) {
481
-			$this->setupForUser($user);
482
-			return;
483
-		}
484
-
485
-		// home providers are always used
486
-		$providers = array_filter($providers, function (string $provider) {
487
-			return !is_subclass_of($provider, IHomeMountProvider::class);
488
-		});
489
-
490
-		if (in_array('', $providers)) {
491
-			$this->setupForUser($user);
492
-			return;
493
-		}
494
-		$setupProviders = $this->setupUserMountProviders[$user->getUID()] ?? [];
495
-
496
-		$providers = array_diff($providers, $setupProviders);
497
-		if (count($providers) === 0) {
498
-			if (!$this->isSetupStarted($user)) {
499
-				$this->oneTimeUserSetup($user);
500
-			}
501
-			return;
502
-		} else {
503
-			$this->setupUserMountProviders[$user->getUID()] = array_merge($setupProviders, $providers);
504
-			$mounts = $this->mountProviderCollection->getUserMountsForProviderClasses($user, $providers);
505
-		}
506
-
507
-		$this->userMountCache->registerMounts($user, $mounts, $providers);
508
-		$this->setupForUserWith($user, function () use ($mounts) {
509
-			array_walk($mounts, [$this->mountManager, 'addMount']);
510
-		});
511
-	}
512
-
513
-	public function tearDown() {
514
-		$this->setupUsers = [];
515
-		$this->setupUsersComplete = [];
516
-		$this->setupUserMountProviders = [];
517
-		$this->fullSetupRequired = [];
518
-		$this->rootSetup = false;
519
-		$this->mountManager->clear();
520
-		$this->eventDispatcher->dispatchTyped(new FilesystemTornDownEvent());
521
-	}
522
-
523
-	/**
524
-	 * Get mounts from mount providers that are registered after setup
525
-	 */
526
-	private function listenForNewMountProviders() {
527
-		if (!$this->listeningForProviders) {
528
-			$this->listeningForProviders = true;
529
-			$this->mountProviderCollection->listen('\OC\Files\Config', 'registerMountProvider', function (
530
-				IMountProvider $provider
531
-			) {
532
-				foreach ($this->setupUsers as $userId) {
533
-					$user = $this->userManager->get($userId);
534
-					if ($user) {
535
-						$mounts = $provider->getMountsForUser($user, Filesystem::getLoader());
536
-						array_walk($mounts, [$this->mountManager, 'addMount']);
537
-					}
538
-				}
539
-			});
540
-		}
541
-	}
542
-
543
-	private function setupListeners() {
544
-		// note that this event handling is intentionally pessimistic
545
-		// clearing the cache to often is better than not enough
546
-
547
-		$this->eventDispatcher->addListener(UserAddedEvent::class, function (UserAddedEvent $event) {
548
-			$this->cache->remove($event->getUser()->getUID());
549
-		});
550
-		$this->eventDispatcher->addListener(UserRemovedEvent::class, function (UserRemovedEvent $event) {
551
-			$this->cache->remove($event->getUser()->getUID());
552
-		});
553
-		$this->eventDispatcher->addListener(ShareCreatedEvent::class, function (ShareCreatedEvent $event) {
554
-			$this->cache->remove($event->getShare()->getSharedWith());
555
-		});
556
-		$this->eventDispatcher->addListener(InvalidateMountCacheEvent::class, function (InvalidateMountCacheEvent $event
557
-		) {
558
-			if ($user = $event->getUser()) {
559
-				$this->cache->remove($user->getUID());
560
-			} else {
561
-				$this->cache->clear();
562
-			}
563
-		});
564
-
565
-		$genericEvents = [
566
-			'OCA\Circles\Events\CreatingCircleEvent',
567
-			'OCA\Circles\Events\DestroyingCircleEvent',
568
-			'OCA\Circles\Events\AddingCircleMemberEvent',
569
-			'OCA\Circles\Events\RemovingCircleMemberEvent',
570
-		];
571
-
572
-		foreach ($genericEvents as $genericEvent) {
573
-			$this->eventDispatcher->addListener($genericEvent, function ($event) {
574
-				$this->cache->clear();
575
-			});
576
-		}
577
-	}
189
+            if ($mount->getOption('readonly', false)) {
190
+                return new PermissionsMask([
191
+                    'storage' => $storage,
192
+                    'mask' => Constants::PERMISSION_ALL & ~(
193
+                            Constants::PERMISSION_UPDATE |
194
+                            Constants::PERMISSION_CREATE |
195
+                            Constants::PERMISSION_DELETE
196
+                        ),
197
+                ]);
198
+            }
199
+            return $storage;
200
+        });
201
+
202
+        Filesystem::logWarningWhenAddingStorageWrapper($prevLogging);
203
+    }
204
+
205
+    /**
206
+     * Setup the full filesystem for the specified user
207
+     */
208
+    public function setupForUser(IUser $user): void {
209
+        if ($this->isSetupComplete($user)) {
210
+            return;
211
+        }
212
+        $this->setupUsersComplete[] = $user->getUID();
213
+
214
+        if (!isset($this->setupUserMountProviders[$user->getUID()])) {
215
+            $this->setupUserMountProviders[$user->getUID()] = [];
216
+        }
217
+
218
+        $previouslySetupProviders = $this->setupUserMountProviders[$user->getUID()];
219
+
220
+        $this->setupForUserWith($user, function () use ($user) {
221
+            $this->mountProviderCollection->addMountForUser($user, $this->mountManager, function (
222
+                IMountProvider $provider
223
+            ) use ($user) {
224
+                return !in_array(get_class($provider), $this->setupUserMountProviders[$user->getUID()]);
225
+            });
226
+        });
227
+        $this->afterUserFullySetup($user, $previouslySetupProviders);
228
+    }
229
+
230
+    /**
231
+     * part of the user setup that is run only once per user
232
+     */
233
+    private function oneTimeUserSetup(IUser $user) {
234
+        if (in_array($user->getUID(), $this->setupUsers, true)) {
235
+            return;
236
+        }
237
+        $this->setupUsers[] = $user->getUID();
238
+
239
+        $this->setupBuiltinWrappers();
240
+
241
+        $prevLogging = Filesystem::logWarningWhenAddingStorageWrapper(false);
242
+
243
+        OC_Hook::emit('OC_Filesystem', 'preSetup', ['user' => $user->getUID()]);
244
+
245
+        Filesystem::logWarningWhenAddingStorageWrapper($prevLogging);
246
+
247
+        $userDir = '/' . $user->getUID() . '/files';
248
+
249
+        Filesystem::initInternal($userDir);
250
+
251
+        if ($this->lockdownManager->canAccessFilesystem()) {
252
+            // home mounts are handled separate since we need to ensure this is mounted before we call the other mount providers
253
+            $homeMount = $this->mountProviderCollection->getHomeMountForUser($user);
254
+            $this->mountManager->addMount($homeMount);
255
+
256
+            if ($homeMount->getStorageRootId() === -1) {
257
+                $homeMount->getStorage()->mkdir('');
258
+                $homeMount->getStorage()->getScanner()->scan('');
259
+            }
260
+        } else {
261
+            $this->mountManager->addMount(new MountPoint(
262
+                new NullStorage([]),
263
+                '/' . $user->getUID()
264
+            ));
265
+            $this->mountManager->addMount(new MountPoint(
266
+                new NullStorage([]),
267
+                '/' . $user->getUID() . '/files'
268
+            ));
269
+            $this->setupUsersComplete[] = $user->getUID();
270
+        }
271
+
272
+        $this->listenForNewMountProviders();
273
+    }
274
+
275
+    /**
276
+     * Final housekeeping after a user has been fully setup
277
+     */
278
+    private function afterUserFullySetup(IUser $user, array $previouslySetupProviders): void {
279
+        $userRoot = '/' . $user->getUID() . '/';
280
+        $mounts = $this->mountManager->getAll();
281
+        $mounts = array_filter($mounts, function (IMountPoint $mount) use ($userRoot) {
282
+            return strpos($mount->getMountPoint(), $userRoot) === 0;
283
+        });
284
+        $allProviders = array_map(function (IMountProvider $provider) {
285
+            return get_class($provider);
286
+        }, $this->mountProviderCollection->getProviders());
287
+        $newProviders = array_diff($allProviders, $previouslySetupProviders);
288
+        $mounts = array_filter($mounts, function (IMountPoint $mount) use ($previouslySetupProviders) {
289
+            return !in_array($mount->getMountProvider(), $previouslySetupProviders);
290
+        });
291
+        $this->userMountCache->registerMounts($user, $mounts, $newProviders);
292
+
293
+        $cacheDuration = $this->config->getSystemValueInt('fs_mount_cache_duration', 5 * 60);
294
+        if ($cacheDuration > 0) {
295
+            $this->cache->set($user->getUID(), true, $cacheDuration);
296
+            $this->fullSetupRequired[$user->getUID()] = false;
297
+        }
298
+    }
299
+
300
+    /**
301
+     * @param IUser $user
302
+     * @param IMountPoint $mounts
303
+     * @return void
304
+     * @throws \OCP\HintException
305
+     * @throws \OC\ServerNotAvailableException
306
+     */
307
+    private function setupForUserWith(IUser $user, callable $mountCallback): void {
308
+        $this->setupRoot();
309
+
310
+        if (!$this->isSetupStarted($user)) {
311
+            $this->oneTimeUserSetup($user);
312
+        }
313
+
314
+        $this->eventLogger->start('setup_fs', 'Setup filesystem');
315
+
316
+        if ($this->lockdownManager->canAccessFilesystem()) {
317
+            $mountCallback();
318
+        }
319
+        \OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', ['user' => $user->getUID()]);
320
+
321
+        $userDir = '/' . $user->getUID() . '/files';
322
+        OC_Hook::emit('OC_Filesystem', 'setup', ['user' => $user->getUID(), 'user_dir' => $userDir]);
323
+
324
+        $this->eventLogger->end('setup_fs');
325
+    }
326
+
327
+    /**
328
+     * Set up the root filesystem
329
+     */
330
+    public function setupRoot(): void {
331
+        //setting up the filesystem twice can only lead to trouble
332
+        if ($this->rootSetup) {
333
+            return;
334
+        }
335
+        $this->rootSetup = true;
336
+
337
+        $this->eventLogger->start('setup_root_fs', 'Setup root filesystem');
338
+
339
+        $this->setupBuiltinWrappers();
340
+
341
+        $rootMounts = $this->mountProviderCollection->getRootMounts();
342
+        foreach ($rootMounts as $rootMountProvider) {
343
+            $this->mountManager->addMount($rootMountProvider);
344
+        }
345
+
346
+        $this->eventLogger->end('setup_root_fs');
347
+    }
348
+
349
+    /**
350
+     * Get the user to setup for a path or `null` if the root needs to be setup
351
+     *
352
+     * @param string $path
353
+     * @return IUser|null
354
+     */
355
+    private function getUserForPath(string $path) {
356
+        if (strpos($path, '/__groupfolders') === 0) {
357
+            return null;
358
+        } elseif (substr_count($path, '/') < 2) {
359
+            if ($user = $this->userSession->getUser()) {
360
+                return $user;
361
+            } else {
362
+                return null;
363
+            }
364
+        } elseif (strpos($path, '/appdata_' . \OC_Util::getInstanceId()) === 0 || strpos($path, '/files_external/') === 0) {
365
+            return null;
366
+        } else {
367
+            [, $userId] = explode('/', $path);
368
+        }
369
+
370
+        return $this->userManager->get($userId);
371
+    }
372
+
373
+    /**
374
+     * Set up the filesystem for the specified path
375
+     */
376
+    public function setupForPath(string $path, bool $includeChildren = false): void {
377
+        $user = $this->getUserForPath($path);
378
+        if (!$user) {
379
+            $this->setupRoot();
380
+            return;
381
+        }
382
+
383
+        if ($this->isSetupComplete($user)) {
384
+            return;
385
+        }
386
+
387
+        if ($this->fullSetupRequired($user)) {
388
+            $this->setupForUser($user);
389
+            return;
390
+        }
391
+
392
+        // for the user's home folder, and includes children we need everything always
393
+        if (rtrim($path) === "/" . $user->getUID() . "/files" && $includeChildren) {
394
+            $this->setupForUser($user);
395
+            return;
396
+        }
397
+
398
+        if (!isset($this->setupUserMountProviders[$user->getUID()])) {
399
+            $this->setupUserMountProviders[$user->getUID()] = [];
400
+        }
401
+        $setupProviders = &$this->setupUserMountProviders[$user->getUID()];
402
+        $currentProviders = [];
403
+
404
+        try {
405
+            $cachedMount = $this->userMountCache->getMountForPath($user, $path);
406
+        } catch (NotFoundException $e) {
407
+            $this->setupForUser($user);
408
+            return;
409
+        }
410
+
411
+        if (!$this->isSetupStarted($user)) {
412
+            $this->oneTimeUserSetup($user);
413
+        }
414
+
415
+        $mounts = [];
416
+        if (!in_array($cachedMount->getMountProvider(), $setupProviders)) {
417
+            $setupProviders[] = $cachedMount->getMountProvider();
418
+            $currentProviders[] = $cachedMount->getMountProvider();
419
+            if ($cachedMount->getMountProvider()) {
420
+                $mounts = $this->mountProviderCollection->getUserMountsForProviderClasses($user, [$cachedMount->getMountProvider()]);
421
+            } else {
422
+                $this->logger->debug("mount at " . $cachedMount->getMountPoint() . " has no provider set, performing full setup");
423
+                $this->setupForUser($user);
424
+                return;
425
+            }
426
+        }
427
+
428
+        if ($includeChildren) {
429
+            $subCachedMounts = $this->userMountCache->getMountsInPath($user, $path);
430
+            foreach ($subCachedMounts as $cachedMount) {
431
+                if (!in_array($cachedMount->getMountProvider(), $setupProviders)) {
432
+                    $setupProviders[] = $cachedMount->getMountProvider();
433
+                    $currentProviders[] = $cachedMount->getMountProvider();
434
+                    if ($cachedMount->getMountProvider()) {
435
+                        $mounts = array_merge($mounts, $this->mountProviderCollection->getUserMountsForProviderClasses($user, [$cachedMount->getMountProvider()]));
436
+                    } else {
437
+                        $this->logger->debug("mount at " . $cachedMount->getMountPoint() . " has no provider set, performing full setup");
438
+                        $this->setupForUser($user);
439
+                        return;
440
+                    }
441
+                }
442
+            }
443
+        }
444
+
445
+        if (count($mounts)) {
446
+            $this->userMountCache->registerMounts($user, $mounts, $currentProviders);
447
+            $this->setupForUserWith($user, function () use ($mounts) {
448
+                array_walk($mounts, [$this->mountManager, 'addMount']);
449
+            });
450
+        } elseif (!$this->isSetupStarted($user)) {
451
+            $this->oneTimeUserSetup($user);
452
+        }
453
+    }
454
+
455
+    private function fullSetupRequired(IUser $user): bool {
456
+        // we perform a "cached" setup only after having done the full setup recently
457
+        // this is also used to trigger a full setup after handling events that are likely
458
+        // to change the available mounts
459
+        if (!isset($this->fullSetupRequired[$user->getUID()])) {
460
+            $this->fullSetupRequired[$user->getUID()] = !$this->cache->get($user->getUID());
461
+        }
462
+        return $this->fullSetupRequired[$user->getUID()];
463
+    }
464
+
465
+    /**
466
+     * @param string $path
467
+     * @param string[] $providers
468
+     */
469
+    public function setupForProvider(string $path, array $providers): void {
470
+        $user = $this->getUserForPath($path);
471
+        if (!$user) {
472
+            $this->setupRoot();
473
+            return;
474
+        }
475
+
476
+        if ($this->isSetupComplete($user)) {
477
+            return;
478
+        }
479
+
480
+        if ($this->fullSetupRequired($user)) {
481
+            $this->setupForUser($user);
482
+            return;
483
+        }
484
+
485
+        // home providers are always used
486
+        $providers = array_filter($providers, function (string $provider) {
487
+            return !is_subclass_of($provider, IHomeMountProvider::class);
488
+        });
489
+
490
+        if (in_array('', $providers)) {
491
+            $this->setupForUser($user);
492
+            return;
493
+        }
494
+        $setupProviders = $this->setupUserMountProviders[$user->getUID()] ?? [];
495
+
496
+        $providers = array_diff($providers, $setupProviders);
497
+        if (count($providers) === 0) {
498
+            if (!$this->isSetupStarted($user)) {
499
+                $this->oneTimeUserSetup($user);
500
+            }
501
+            return;
502
+        } else {
503
+            $this->setupUserMountProviders[$user->getUID()] = array_merge($setupProviders, $providers);
504
+            $mounts = $this->mountProviderCollection->getUserMountsForProviderClasses($user, $providers);
505
+        }
506
+
507
+        $this->userMountCache->registerMounts($user, $mounts, $providers);
508
+        $this->setupForUserWith($user, function () use ($mounts) {
509
+            array_walk($mounts, [$this->mountManager, 'addMount']);
510
+        });
511
+    }
512
+
513
+    public function tearDown() {
514
+        $this->setupUsers = [];
515
+        $this->setupUsersComplete = [];
516
+        $this->setupUserMountProviders = [];
517
+        $this->fullSetupRequired = [];
518
+        $this->rootSetup = false;
519
+        $this->mountManager->clear();
520
+        $this->eventDispatcher->dispatchTyped(new FilesystemTornDownEvent());
521
+    }
522
+
523
+    /**
524
+     * Get mounts from mount providers that are registered after setup
525
+     */
526
+    private function listenForNewMountProviders() {
527
+        if (!$this->listeningForProviders) {
528
+            $this->listeningForProviders = true;
529
+            $this->mountProviderCollection->listen('\OC\Files\Config', 'registerMountProvider', function (
530
+                IMountProvider $provider
531
+            ) {
532
+                foreach ($this->setupUsers as $userId) {
533
+                    $user = $this->userManager->get($userId);
534
+                    if ($user) {
535
+                        $mounts = $provider->getMountsForUser($user, Filesystem::getLoader());
536
+                        array_walk($mounts, [$this->mountManager, 'addMount']);
537
+                    }
538
+                }
539
+            });
540
+        }
541
+    }
542
+
543
+    private function setupListeners() {
544
+        // note that this event handling is intentionally pessimistic
545
+        // clearing the cache to often is better than not enough
546
+
547
+        $this->eventDispatcher->addListener(UserAddedEvent::class, function (UserAddedEvent $event) {
548
+            $this->cache->remove($event->getUser()->getUID());
549
+        });
550
+        $this->eventDispatcher->addListener(UserRemovedEvent::class, function (UserRemovedEvent $event) {
551
+            $this->cache->remove($event->getUser()->getUID());
552
+        });
553
+        $this->eventDispatcher->addListener(ShareCreatedEvent::class, function (ShareCreatedEvent $event) {
554
+            $this->cache->remove($event->getShare()->getSharedWith());
555
+        });
556
+        $this->eventDispatcher->addListener(InvalidateMountCacheEvent::class, function (InvalidateMountCacheEvent $event
557
+        ) {
558
+            if ($user = $event->getUser()) {
559
+                $this->cache->remove($user->getUID());
560
+            } else {
561
+                $this->cache->clear();
562
+            }
563
+        });
564
+
565
+        $genericEvents = [
566
+            'OCA\Circles\Events\CreatingCircleEvent',
567
+            'OCA\Circles\Events\DestroyingCircleEvent',
568
+            'OCA\Circles\Events\AddingCircleMemberEvent',
569
+            'OCA\Circles\Events\RemovingCircleMemberEvent',
570
+        ];
571
+
572
+        foreach ($genericEvents as $genericEvent) {
573
+            $this->eventDispatcher->addListener($genericEvent, function ($event) {
574
+                $this->cache->clear();
575
+            });
576
+        }
577
+    }
578 578
 }
Please login to merge, or discard this patch.
Spacing   +30 added lines, -30 removed lines patch added patch discarded remove patch
@@ -131,14 +131,14 @@  discard block
 block discarded – undo
131 131
 		OC_App::loadApps(['filesystem']);
132 132
 		$prevLogging = Filesystem::logWarningWhenAddingStorageWrapper(false);
133 133
 
134
-		Filesystem::addStorageWrapper('mount_options', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
134
+		Filesystem::addStorageWrapper('mount_options', function($mountPoint, IStorage $storage, IMountPoint $mount) {
135 135
 			if ($storage->instanceOfStorage(Common::class)) {
136 136
 				$storage->setMountOptions($mount->getOptions());
137 137
 			}
138 138
 			return $storage;
139 139
 		});
140 140
 
141
-		Filesystem::addStorageWrapper('enable_sharing', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
141
+		Filesystem::addStorageWrapper('enable_sharing', function($mountPoint, IStorage $storage, IMountPoint $mount) {
142 142
 			if (!$mount->getOption('enable_sharing', true)) {
143 143
 				return new PermissionsMask([
144 144
 					'storage' => $storage,
@@ -149,21 +149,21 @@  discard block
 block discarded – undo
149 149
 		});
150 150
 
151 151
 		// install storage availability wrapper, before most other wrappers
152
-		Filesystem::addStorageWrapper('oc_availability', function ($mountPoint, IStorage $storage) {
152
+		Filesystem::addStorageWrapper('oc_availability', function($mountPoint, IStorage $storage) {
153 153
 			if (!$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage') && !$storage->isLocal()) {
154 154
 				return new Availability(['storage' => $storage]);
155 155
 			}
156 156
 			return $storage;
157 157
 		});
158 158
 
159
-		Filesystem::addStorageWrapper('oc_encoding', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
159
+		Filesystem::addStorageWrapper('oc_encoding', function($mountPoint, IStorage $storage, IMountPoint $mount) {
160 160
 			if ($mount->getOption('encoding_compatibility', false) && !$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) {
161 161
 				return new Encoding(['storage' => $storage]);
162 162
 			}
163 163
 			return $storage;
164 164
 		});
165 165
 
166
-		Filesystem::addStorageWrapper('oc_quota', function ($mountPoint, $storage) {
166
+		Filesystem::addStorageWrapper('oc_quota', function($mountPoint, $storage) {
167 167
 			// set up quota for home storages, even for other users
168 168
 			// which can happen when using sharing
169 169
 
@@ -173,7 +173,7 @@  discard block
 block discarded – undo
173 173
 			if ($storage->instanceOfStorage(HomeObjectStoreStorage::class) || $storage->instanceOfStorage(Home::class)) {
174 174
 				if (is_object($storage->getUser())) {
175 175
 					$user = $storage->getUser();
176
-					return new Quota(['storage' => $storage, 'quotaCallback' => function () use ($user) {
176
+					return new Quota(['storage' => $storage, 'quotaCallback' => function() use ($user) {
177 177
 						return OC_Util::getUserQuota($user);
178 178
 					}, 'root' => 'files']);
179 179
 				}
@@ -182,7 +182,7 @@  discard block
 block discarded – undo
182 182
 			return $storage;
183 183
 		});
184 184
 
185
-		Filesystem::addStorageWrapper('readonly', function ($mountPoint, IStorage $storage, IMountPoint $mount) {
185
+		Filesystem::addStorageWrapper('readonly', function($mountPoint, IStorage $storage, IMountPoint $mount) {
186 186
 			/*
187 187
 			 * Do not allow any operations that modify the storage
188 188
 			 */
@@ -217,8 +217,8 @@  discard block
 block discarded – undo
217 217
 
218 218
 		$previouslySetupProviders = $this->setupUserMountProviders[$user->getUID()];
219 219
 
220
-		$this->setupForUserWith($user, function () use ($user) {
221
-			$this->mountProviderCollection->addMountForUser($user, $this->mountManager, function (
220
+		$this->setupForUserWith($user, function() use ($user) {
221
+			$this->mountProviderCollection->addMountForUser($user, $this->mountManager, function(
222 222
 				IMountProvider $provider
223 223
 			) use ($user) {
224 224
 				return !in_array(get_class($provider), $this->setupUserMountProviders[$user->getUID()]);
@@ -244,7 +244,7 @@  discard block
 block discarded – undo
244 244
 
245 245
 		Filesystem::logWarningWhenAddingStorageWrapper($prevLogging);
246 246
 
247
-		$userDir = '/' . $user->getUID() . '/files';
247
+		$userDir = '/'.$user->getUID().'/files';
248 248
 
249 249
 		Filesystem::initInternal($userDir);
250 250
 
@@ -260,11 +260,11 @@  discard block
 block discarded – undo
260 260
 		} else {
261 261
 			$this->mountManager->addMount(new MountPoint(
262 262
 				new NullStorage([]),
263
-				'/' . $user->getUID()
263
+				'/'.$user->getUID()
264 264
 			));
265 265
 			$this->mountManager->addMount(new MountPoint(
266 266
 				new NullStorage([]),
267
-				'/' . $user->getUID() . '/files'
267
+				'/'.$user->getUID().'/files'
268 268
 			));
269 269
 			$this->setupUsersComplete[] = $user->getUID();
270 270
 		}
@@ -276,16 +276,16 @@  discard block
 block discarded – undo
276 276
 	 * Final housekeeping after a user has been fully setup
277 277
 	 */
278 278
 	private function afterUserFullySetup(IUser $user, array $previouslySetupProviders): void {
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 strpos($mount->getMountPoint(), $userRoot) === 0;
283 283
 		});
284
-		$allProviders = array_map(function (IMountProvider $provider) {
284
+		$allProviders = array_map(function(IMountProvider $provider) {
285 285
 			return get_class($provider);
286 286
 		}, $this->mountProviderCollection->getProviders());
287 287
 		$newProviders = array_diff($allProviders, $previouslySetupProviders);
288
-		$mounts = array_filter($mounts, function (IMountPoint $mount) use ($previouslySetupProviders) {
288
+		$mounts = array_filter($mounts, function(IMountPoint $mount) use ($previouslySetupProviders) {
289 289
 			return !in_array($mount->getMountProvider(), $previouslySetupProviders);
290 290
 		});
291 291
 		$this->userMountCache->registerMounts($user, $mounts, $newProviders);
@@ -318,7 +318,7 @@  discard block
 block discarded – undo
318 318
 		}
319 319
 		\OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', ['user' => $user->getUID()]);
320 320
 
321
-		$userDir = '/' . $user->getUID() . '/files';
321
+		$userDir = '/'.$user->getUID().'/files';
322 322
 		OC_Hook::emit('OC_Filesystem', 'setup', ['user' => $user->getUID(), 'user_dir' => $userDir]);
323 323
 
324 324
 		$this->eventLogger->end('setup_fs');
@@ -361,7 +361,7 @@  discard block
 block discarded – undo
361 361
 			} else {
362 362
 				return null;
363 363
 			}
364
-		} elseif (strpos($path, '/appdata_' . \OC_Util::getInstanceId()) === 0 || strpos($path, '/files_external/') === 0) {
364
+		} elseif (strpos($path, '/appdata_'.\OC_Util::getInstanceId()) === 0 || strpos($path, '/files_external/') === 0) {
365 365
 			return null;
366 366
 		} else {
367 367
 			[, $userId] = explode('/', $path);
@@ -390,7 +390,7 @@  discard block
 block discarded – undo
390 390
 		}
391 391
 
392 392
 		// for the user's home folder, and includes children we need everything always
393
-		if (rtrim($path) === "/" . $user->getUID() . "/files" && $includeChildren) {
393
+		if (rtrim($path) === "/".$user->getUID()."/files" && $includeChildren) {
394 394
 			$this->setupForUser($user);
395 395
 			return;
396 396
 		}
@@ -419,7 +419,7 @@  discard block
 block discarded – undo
419 419
 			if ($cachedMount->getMountProvider()) {
420 420
 				$mounts = $this->mountProviderCollection->getUserMountsForProviderClasses($user, [$cachedMount->getMountProvider()]);
421 421
 			} else {
422
-				$this->logger->debug("mount at " . $cachedMount->getMountPoint() . " has no provider set, performing full setup");
422
+				$this->logger->debug("mount at ".$cachedMount->getMountPoint()." has no provider set, performing full setup");
423 423
 				$this->setupForUser($user);
424 424
 				return;
425 425
 			}
@@ -434,7 +434,7 @@  discard block
 block discarded – undo
434 434
 					if ($cachedMount->getMountProvider()) {
435 435
 						$mounts = array_merge($mounts, $this->mountProviderCollection->getUserMountsForProviderClasses($user, [$cachedMount->getMountProvider()]));
436 436
 					} else {
437
-						$this->logger->debug("mount at " . $cachedMount->getMountPoint() . " has no provider set, performing full setup");
437
+						$this->logger->debug("mount at ".$cachedMount->getMountPoint()." has no provider set, performing full setup");
438 438
 						$this->setupForUser($user);
439 439
 						return;
440 440
 					}
@@ -444,7 +444,7 @@  discard block
 block discarded – undo
444 444
 
445 445
 		if (count($mounts)) {
446 446
 			$this->userMountCache->registerMounts($user, $mounts, $currentProviders);
447
-			$this->setupForUserWith($user, function () use ($mounts) {
447
+			$this->setupForUserWith($user, function() use ($mounts) {
448 448
 				array_walk($mounts, [$this->mountManager, 'addMount']);
449 449
 			});
450 450
 		} elseif (!$this->isSetupStarted($user)) {
@@ -483,7 +483,7 @@  discard block
 block discarded – undo
483 483
 		}
484 484
 
485 485
 		// home providers are always used
486
-		$providers = array_filter($providers, function (string $provider) {
486
+		$providers = array_filter($providers, function(string $provider) {
487 487
 			return !is_subclass_of($provider, IHomeMountProvider::class);
488 488
 		});
489 489
 
@@ -505,7 +505,7 @@  discard block
 block discarded – undo
505 505
 		}
506 506
 
507 507
 		$this->userMountCache->registerMounts($user, $mounts, $providers);
508
-		$this->setupForUserWith($user, function () use ($mounts) {
508
+		$this->setupForUserWith($user, function() use ($mounts) {
509 509
 			array_walk($mounts, [$this->mountManager, 'addMount']);
510 510
 		});
511 511
 	}
@@ -526,7 +526,7 @@  discard block
 block discarded – undo
526 526
 	private function listenForNewMountProviders() {
527 527
 		if (!$this->listeningForProviders) {
528 528
 			$this->listeningForProviders = true;
529
-			$this->mountProviderCollection->listen('\OC\Files\Config', 'registerMountProvider', function (
529
+			$this->mountProviderCollection->listen('\OC\Files\Config', 'registerMountProvider', function(
530 530
 				IMountProvider $provider
531 531
 			) {
532 532
 				foreach ($this->setupUsers as $userId) {
@@ -544,16 +544,16 @@  discard block
 block discarded – undo
544 544
 		// note that this event handling is intentionally pessimistic
545 545
 		// clearing the cache to often is better than not enough
546 546
 
547
-		$this->eventDispatcher->addListener(UserAddedEvent::class, function (UserAddedEvent $event) {
547
+		$this->eventDispatcher->addListener(UserAddedEvent::class, function(UserAddedEvent $event) {
548 548
 			$this->cache->remove($event->getUser()->getUID());
549 549
 		});
550
-		$this->eventDispatcher->addListener(UserRemovedEvent::class, function (UserRemovedEvent $event) {
550
+		$this->eventDispatcher->addListener(UserRemovedEvent::class, function(UserRemovedEvent $event) {
551 551
 			$this->cache->remove($event->getUser()->getUID());
552 552
 		});
553
-		$this->eventDispatcher->addListener(ShareCreatedEvent::class, function (ShareCreatedEvent $event) {
553
+		$this->eventDispatcher->addListener(ShareCreatedEvent::class, function(ShareCreatedEvent $event) {
554 554
 			$this->cache->remove($event->getShare()->getSharedWith());
555 555
 		});
556
-		$this->eventDispatcher->addListener(InvalidateMountCacheEvent::class, function (InvalidateMountCacheEvent $event
556
+		$this->eventDispatcher->addListener(InvalidateMountCacheEvent::class, function(InvalidateMountCacheEvent $event
557 557
 		) {
558 558
 			if ($user = $event->getUser()) {
559 559
 				$this->cache->remove($user->getUID());
@@ -570,7 +570,7 @@  discard block
 block discarded – undo
570 570
 		];
571 571
 
572 572
 		foreach ($genericEvents as $genericEvent) {
573
-			$this->eventDispatcher->addListener($genericEvent, function ($event) {
573
+			$this->eventDispatcher->addListener($genericEvent, function($event) {
574 574
 				$this->cache->clear();
575 575
 			});
576 576
 		}
Please login to merge, or discard this patch.
lib/private/Files/Storage/Wrapper/Quota.php 1 patch
Indentation   +216 added lines, -216 removed lines patch added patch discarded remove patch
@@ -39,238 +39,238 @@
 block discarded – undo
39 39
 use OCP\Files\Storage\IStorage;
40 40
 
41 41
 class Quota extends Wrapper {
42
-	/** @var callable|null */
43
-	protected $quotaCallback;
44
-	protected ?int $quota;
45
-	protected string $sizeRoot;
46
-	private SystemConfig $config;
42
+    /** @var callable|null */
43
+    protected $quotaCallback;
44
+    protected ?int $quota;
45
+    protected string $sizeRoot;
46
+    private SystemConfig $config;
47 47
 
48
-	/**
49
-	 * @param array $parameters
50
-	 */
51
-	public function __construct($parameters) {
52
-		parent::__construct($parameters);
53
-		$this->quota = $parameters['quota'] ?? null;
54
-		$this->quotaCallback = $parameters['quotaCallback'] ?? null;
55
-		$this->sizeRoot = $parameters['root'] ?? '';
56
-		$this->config = \OC::$server->get(SystemConfig::class);
57
-	}
48
+    /**
49
+     * @param array $parameters
50
+     */
51
+    public function __construct($parameters) {
52
+        parent::__construct($parameters);
53
+        $this->quota = $parameters['quota'] ?? null;
54
+        $this->quotaCallback = $parameters['quotaCallback'] ?? null;
55
+        $this->sizeRoot = $parameters['root'] ?? '';
56
+        $this->config = \OC::$server->get(SystemConfig::class);
57
+    }
58 58
 
59
-	/**
60
-	 * @return int quota value
61
-	 */
62
-	public function getQuota(): int {
63
-		if ($this->quota === null) {
64
-			$quotaCallback = $this->quotaCallback;
65
-			if ($quotaCallback === null) {
66
-				throw new \Exception("No quota or quota callback provider");
67
-			}
68
-			$this->quota = $quotaCallback();
69
-		}
70
-		return $this->quota;
71
-	}
59
+    /**
60
+     * @return int quota value
61
+     */
62
+    public function getQuota(): int {
63
+        if ($this->quota === null) {
64
+            $quotaCallback = $this->quotaCallback;
65
+            if ($quotaCallback === null) {
66
+                throw new \Exception("No quota or quota callback provider");
67
+            }
68
+            $this->quota = $quotaCallback();
69
+        }
70
+        return $this->quota;
71
+    }
72 72
 
73
-	private function hasQuota(): bool {
74
-		return $this->getQuota() !== FileInfo::SPACE_UNLIMITED;
75
-	}
73
+    private function hasQuota(): bool {
74
+        return $this->getQuota() !== FileInfo::SPACE_UNLIMITED;
75
+    }
76 76
 
77
-	/**
78
-	 * @param string $path
79
-	 * @param \OC\Files\Storage\Storage $storage
80
-	 */
81
-	protected function getSize($path, $storage = null) {
82
-		if ($this->config->getValue('quota_include_external_storage', false)) {
83
-			$rootInfo = Filesystem::getFileInfo('', 'ext');
84
-			if ($rootInfo) {
85
-				return $rootInfo->getSize(true);
86
-			}
87
-			return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED;
88
-		} else {
89
-			if (is_null($storage)) {
90
-				$cache = $this->getCache();
91
-			} else {
92
-				$cache = $storage->getCache();
93
-			}
94
-			$data = $cache->get($path);
95
-			if ($data instanceof ICacheEntry and isset($data['size'])) {
96
-				return $data['size'];
97
-			} else {
98
-				return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED;
99
-			}
100
-		}
101
-	}
77
+    /**
78
+     * @param string $path
79
+     * @param \OC\Files\Storage\Storage $storage
80
+     */
81
+    protected function getSize($path, $storage = null) {
82
+        if ($this->config->getValue('quota_include_external_storage', false)) {
83
+            $rootInfo = Filesystem::getFileInfo('', 'ext');
84
+            if ($rootInfo) {
85
+                return $rootInfo->getSize(true);
86
+            }
87
+            return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED;
88
+        } else {
89
+            if (is_null($storage)) {
90
+                $cache = $this->getCache();
91
+            } else {
92
+                $cache = $storage->getCache();
93
+            }
94
+            $data = $cache->get($path);
95
+            if ($data instanceof ICacheEntry and isset($data['size'])) {
96
+                return $data['size'];
97
+            } else {
98
+                return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED;
99
+            }
100
+        }
101
+    }
102 102
 
103
-	/**
104
-	 * Get free space as limited by the quota
105
-	 *
106
-	 * @param string $path
107
-	 * @return int|bool
108
-	 */
109
-	public function free_space($path) {
110
-		if (!$this->hasQuota()) {
111
-			return $this->storage->free_space($path);
112
-		}
113
-		if ($this->getQuota() < 0 || strpos($path, 'cache') === 0 || strpos($path, 'uploads') === 0) {
114
-			return $this->storage->free_space($path);
115
-		} else {
116
-			$used = $this->getSize($this->sizeRoot);
117
-			if ($used < 0) {
118
-				return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED;
119
-			} else {
120
-				$free = $this->storage->free_space($path);
121
-				$quotaFree = max($this->getQuota() - $used, 0);
122
-				// if free space is known
123
-				if ($free >= 0) {
124
-					$free = min($free, $quotaFree);
125
-				} else {
126
-					$free = $quotaFree;
127
-				}
128
-				return $free;
129
-			}
130
-		}
131
-	}
103
+    /**
104
+     * Get free space as limited by the quota
105
+     *
106
+     * @param string $path
107
+     * @return int|bool
108
+     */
109
+    public function free_space($path) {
110
+        if (!$this->hasQuota()) {
111
+            return $this->storage->free_space($path);
112
+        }
113
+        if ($this->getQuota() < 0 || strpos($path, 'cache') === 0 || strpos($path, 'uploads') === 0) {
114
+            return $this->storage->free_space($path);
115
+        } else {
116
+            $used = $this->getSize($this->sizeRoot);
117
+            if ($used < 0) {
118
+                return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED;
119
+            } else {
120
+                $free = $this->storage->free_space($path);
121
+                $quotaFree = max($this->getQuota() - $used, 0);
122
+                // if free space is known
123
+                if ($free >= 0) {
124
+                    $free = min($free, $quotaFree);
125
+                } else {
126
+                    $free = $quotaFree;
127
+                }
128
+                return $free;
129
+            }
130
+        }
131
+    }
132 132
 
133
-	/**
134
-	 * see https://www.php.net/manual/en/function.file_put_contents.php
135
-	 *
136
-	 * @param string $path
137
-	 * @param mixed $data
138
-	 * @return int|false
139
-	 */
140
-	public function file_put_contents($path, $data) {
141
-		if (!$this->hasQuota()) {
142
-			return $this->storage->file_put_contents($path, $data);
143
-		}
144
-		$free = $this->free_space($path);
145
-		if ($free < 0 or strlen($data) < $free) {
146
-			return $this->storage->file_put_contents($path, $data);
147
-		} else {
148
-			return false;
149
-		}
150
-	}
133
+    /**
134
+     * see https://www.php.net/manual/en/function.file_put_contents.php
135
+     *
136
+     * @param string $path
137
+     * @param mixed $data
138
+     * @return int|false
139
+     */
140
+    public function file_put_contents($path, $data) {
141
+        if (!$this->hasQuota()) {
142
+            return $this->storage->file_put_contents($path, $data);
143
+        }
144
+        $free = $this->free_space($path);
145
+        if ($free < 0 or strlen($data) < $free) {
146
+            return $this->storage->file_put_contents($path, $data);
147
+        } else {
148
+            return false;
149
+        }
150
+    }
151 151
 
152
-	/**
153
-	 * see https://www.php.net/manual/en/function.copy.php
154
-	 *
155
-	 * @param string $source
156
-	 * @param string $target
157
-	 * @return bool
158
-	 */
159
-	public function copy($source, $target) {
160
-		if (!$this->hasQuota()) {
161
-			return $this->storage->copy($source, $target);
162
-		}
163
-		$free = $this->free_space($target);
164
-		if ($free < 0 or $this->getSize($source) < $free) {
165
-			return $this->storage->copy($source, $target);
166
-		} else {
167
-			return false;
168
-		}
169
-	}
152
+    /**
153
+     * see https://www.php.net/manual/en/function.copy.php
154
+     *
155
+     * @param string $source
156
+     * @param string $target
157
+     * @return bool
158
+     */
159
+    public function copy($source, $target) {
160
+        if (!$this->hasQuota()) {
161
+            return $this->storage->copy($source, $target);
162
+        }
163
+        $free = $this->free_space($target);
164
+        if ($free < 0 or $this->getSize($source) < $free) {
165
+            return $this->storage->copy($source, $target);
166
+        } else {
167
+            return false;
168
+        }
169
+    }
170 170
 
171
-	/**
172
-	 * see https://www.php.net/manual/en/function.fopen.php
173
-	 *
174
-	 * @param string $path
175
-	 * @param string $mode
176
-	 * @return resource|bool
177
-	 */
178
-	public function fopen($path, $mode) {
179
-		if (!$this->hasQuota()) {
180
-			return $this->storage->fopen($path, $mode);
181
-		}
182
-		$source = $this->storage->fopen($path, $mode);
171
+    /**
172
+     * see https://www.php.net/manual/en/function.fopen.php
173
+     *
174
+     * @param string $path
175
+     * @param string $mode
176
+     * @return resource|bool
177
+     */
178
+    public function fopen($path, $mode) {
179
+        if (!$this->hasQuota()) {
180
+            return $this->storage->fopen($path, $mode);
181
+        }
182
+        $source = $this->storage->fopen($path, $mode);
183 183
 
184
-		// don't apply quota for part files
185
-		if (!$this->isPartFile($path)) {
186
-			$free = $this->free_space($path);
187
-			if ($source && is_int($free) && $free >= 0 && $mode !== 'r' && $mode !== 'rb') {
188
-				// only apply quota for files, not metadata, trash or others
189
-				if ($this->shouldApplyQuota($path)) {
190
-					return \OC\Files\Stream\Quota::wrap($source, $free);
191
-				}
192
-			}
193
-		}
194
-		return $source;
195
-	}
184
+        // don't apply quota for part files
185
+        if (!$this->isPartFile($path)) {
186
+            $free = $this->free_space($path);
187
+            if ($source && is_int($free) && $free >= 0 && $mode !== 'r' && $mode !== 'rb') {
188
+                // only apply quota for files, not metadata, trash or others
189
+                if ($this->shouldApplyQuota($path)) {
190
+                    return \OC\Files\Stream\Quota::wrap($source, $free);
191
+                }
192
+            }
193
+        }
194
+        return $source;
195
+    }
196 196
 
197
-	/**
198
-	 * Checks whether the given path is a part file
199
-	 *
200
-	 * @param string $path Path that may identify a .part file
201
-	 * @return string File path without .part extension
202
-	 * @note this is needed for reusing keys
203
-	 */
204
-	private function isPartFile($path) {
205
-		$extension = pathinfo($path, PATHINFO_EXTENSION);
197
+    /**
198
+     * Checks whether the given path is a part file
199
+     *
200
+     * @param string $path Path that may identify a .part file
201
+     * @return string File path without .part extension
202
+     * @note this is needed for reusing keys
203
+     */
204
+    private function isPartFile($path) {
205
+        $extension = pathinfo($path, PATHINFO_EXTENSION);
206 206
 
207
-		return ($extension === 'part');
208
-	}
207
+        return ($extension === 'part');
208
+    }
209 209
 
210
-	/**
211
-	 * Only apply quota for files, not metadata, trash or others
212
-	 */
213
-	private function shouldApplyQuota(string $path): bool {
214
-		return strpos(ltrim($path, '/'), 'files/') === 0;
215
-	}
210
+    /**
211
+     * Only apply quota for files, not metadata, trash or others
212
+     */
213
+    private function shouldApplyQuota(string $path): bool {
214
+        return strpos(ltrim($path, '/'), 'files/') === 0;
215
+    }
216 216
 
217
-	/**
218
-	 * @param IStorage $sourceStorage
219
-	 * @param string $sourceInternalPath
220
-	 * @param string $targetInternalPath
221
-	 * @return bool
222
-	 */
223
-	public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
224
-		if (!$this->hasQuota()) {
225
-			return $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
226
-		}
227
-		$free = $this->free_space($targetInternalPath);
228
-		if ($free < 0 or $this->getSize($sourceInternalPath, $sourceStorage) < $free) {
229
-			return $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
230
-		} else {
231
-			return false;
232
-		}
233
-	}
217
+    /**
218
+     * @param IStorage $sourceStorage
219
+     * @param string $sourceInternalPath
220
+     * @param string $targetInternalPath
221
+     * @return bool
222
+     */
223
+    public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
224
+        if (!$this->hasQuota()) {
225
+            return $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
226
+        }
227
+        $free = $this->free_space($targetInternalPath);
228
+        if ($free < 0 or $this->getSize($sourceInternalPath, $sourceStorage) < $free) {
229
+            return $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
230
+        } else {
231
+            return false;
232
+        }
233
+    }
234 234
 
235
-	/**
236
-	 * @param IStorage $sourceStorage
237
-	 * @param string $sourceInternalPath
238
-	 * @param string $targetInternalPath
239
-	 * @return bool
240
-	 */
241
-	public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
242
-		if (!$this->hasQuota()) {
243
-			return $this->storage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
244
-		}
245
-		$free = $this->free_space($targetInternalPath);
246
-		if ($free < 0 or $this->getSize($sourceInternalPath, $sourceStorage) < $free) {
247
-			return $this->storage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
248
-		} else {
249
-			return false;
250
-		}
251
-	}
235
+    /**
236
+     * @param IStorage $sourceStorage
237
+     * @param string $sourceInternalPath
238
+     * @param string $targetInternalPath
239
+     * @return bool
240
+     */
241
+    public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) {
242
+        if (!$this->hasQuota()) {
243
+            return $this->storage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
244
+        }
245
+        $free = $this->free_space($targetInternalPath);
246
+        if ($free < 0 or $this->getSize($sourceInternalPath, $sourceStorage) < $free) {
247
+            return $this->storage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath);
248
+        } else {
249
+            return false;
250
+        }
251
+    }
252 252
 
253
-	public function mkdir($path) {
254
-		if (!$this->hasQuota()) {
255
-			return $this->storage->mkdir($path);
256
-		}
257
-		$free = $this->free_space($path);
258
-		if ($this->shouldApplyQuota($path) && $free == 0) {
259
-			return false;
260
-		}
253
+    public function mkdir($path) {
254
+        if (!$this->hasQuota()) {
255
+            return $this->storage->mkdir($path);
256
+        }
257
+        $free = $this->free_space($path);
258
+        if ($this->shouldApplyQuota($path) && $free == 0) {
259
+            return false;
260
+        }
261 261
 
262
-		return parent::mkdir($path);
263
-	}
262
+        return parent::mkdir($path);
263
+    }
264 264
 
265
-	public function touch($path, $mtime = null) {
266
-		if (!$this->hasQuota()) {
267
-			return $this->storage->touch($path, $mtime);
268
-		}
269
-		$free = $this->free_space($path);
270
-		if ($free == 0) {
271
-			return false;
272
-		}
265
+    public function touch($path, $mtime = null) {
266
+        if (!$this->hasQuota()) {
267
+            return $this->storage->touch($path, $mtime);
268
+        }
269
+        $free = $this->free_space($path);
270
+        if ($free == 0) {
271
+            return false;
272
+        }
273 273
 
274
-		return parent::touch($path, $mtime);
275
-	}
274
+        return parent::touch($path, $mtime);
275
+    }
276 276
 }
Please login to merge, or discard this patch.