Completed
Push — master ( 0b2cf0...06ce2c )
by
unknown
29:25 queued 13s
created
lib/public/Files/Config/Event/UserMountAddedEvent.php 1 patch
Indentation   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -19,9 +19,9 @@
 block discarded – undo
19 19
  * @since 31.0.0
20 20
  */
21 21
 class UserMountAddedEvent extends Event {
22
-	public function __construct(
23
-		public readonly IMountPoint|ICachedMountInfo $mountPoint,
24
-	) {
25
-		parent::__construct();
26
-	}
22
+    public function __construct(
23
+        public readonly IMountPoint|ICachedMountInfo $mountPoint,
24
+    ) {
25
+        parent::__construct();
26
+    }
27 27
 }
Please login to merge, or discard this patch.
lib/public/Files/Config/Event/UserMountRemovedEvent.php 1 patch
Indentation   +5 added lines, -5 removed lines patch added patch discarded remove patch
@@ -19,9 +19,9 @@
 block discarded – undo
19 19
  * @since 31.0.0
20 20
  */
21 21
 class UserMountRemovedEvent extends Event {
22
-	public function __construct(
23
-		public readonly IMountPoint|ICachedMountInfo $mountPoint,
24
-	) {
25
-		parent::__construct();
26
-	}
22
+    public function __construct(
23
+        public readonly IMountPoint|ICachedMountInfo $mountPoint,
24
+    ) {
25
+        parent::__construct();
26
+    }
27 27
 }
Please login to merge, or discard this patch.
lib/public/Files/Config/Event/UserMountUpdatedEvent.php 1 patch
Indentation   +6 added lines, -6 removed lines patch added patch discarded remove patch
@@ -19,10 +19,10 @@
 block discarded – undo
19 19
  * @since 31.0.0
20 20
  */
21 21
 class UserMountUpdatedEvent extends Event {
22
-	public function __construct(
23
-		public readonly IMountPoint|ICachedMountInfo $oldMountPoint,
24
-		public readonly IMountPoint|ICachedMountInfo $newMountPoint,
25
-	) {
26
-		parent::__construct();
27
-	}
22
+    public function __construct(
23
+        public readonly IMountPoint|ICachedMountInfo $oldMountPoint,
24
+        public readonly IMountPoint|ICachedMountInfo $newMountPoint,
25
+    ) {
26
+        parent::__construct();
27
+    }
28 28
 }
Please login to merge, or discard this patch.
lib/private/Files/Config/UserMountCache.php 1 patch
Indentation   +470 added lines, -470 removed lines patch added patch discarded remove patch
@@ -29,474 +29,474 @@
 block discarded – undo
29 29
  */
30 30
 class UserMountCache implements IUserMountCache {
31 31
 
32
-	/**
33
-	 * Cached mount info.
34
-	 * @var CappedMemoryCache<ICachedMountInfo[]>
35
-	 **/
36
-	private CappedMemoryCache $mountsForUsers;
37
-	/**
38
-	 * fileid => internal path mapping for cached mount info.
39
-	 * @var CappedMemoryCache<string>
40
-	 **/
41
-	private CappedMemoryCache $internalPathCache;
42
-	/** @var CappedMemoryCache<array> */
43
-	private CappedMemoryCache $cacheInfoCache;
44
-
45
-	/**
46
-	 * UserMountCache constructor.
47
-	 */
48
-	public function __construct(
49
-		private IDBConnection $connection,
50
-		private IUserManager $userManager,
51
-		private LoggerInterface $logger,
52
-		private IEventLogger $eventLogger,
53
-		private IEventDispatcher $eventDispatcher,
54
-	) {
55
-		$this->cacheInfoCache = new CappedMemoryCache();
56
-		$this->internalPathCache = new CappedMemoryCache();
57
-		$this->mountsForUsers = new CappedMemoryCache();
58
-	}
59
-
60
-	public function registerMounts(IUser $user, array $mounts, ?array $mountProviderClasses = null) {
61
-		$this->eventLogger->start('fs:setup:user:register', 'Registering mounts for user');
62
-		/** @var array<string, ICachedMountInfo> $newMounts */
63
-		$newMounts = [];
64
-		foreach ($mounts as $mount) {
65
-			// filter out any storages which aren't scanned yet since we aren't interested in files from those storages (yet)
66
-			if ($mount->getStorageRootId() !== -1) {
67
-				$mountInfo = new LazyStorageMountInfo($user, $mount);
68
-				$newMounts[$mountInfo->getKey()] = $mountInfo;
69
-			}
70
-		}
71
-
72
-		$cachedMounts = $this->getMountsForUser($user);
73
-		if (is_array($mountProviderClasses)) {
74
-			$cachedMounts = array_filter($cachedMounts, function (ICachedMountInfo $mountInfo) use ($mountProviderClasses, $newMounts) {
75
-				// for existing mounts that didn't have a mount provider set
76
-				// we still want the ones that map to new mounts
77
-				if ($mountInfo->getMountProvider() === '' && isset($newMounts[$mountInfo->getKey()])) {
78
-					return true;
79
-				}
80
-				return in_array($mountInfo->getMountProvider(), $mountProviderClasses);
81
-			});
82
-		}
83
-
84
-		$addedMounts = [];
85
-		$removedMounts = [];
86
-
87
-		foreach ($newMounts as $mountKey => $newMount) {
88
-			if (!isset($cachedMounts[$mountKey])) {
89
-				$addedMounts[] = $newMount;
90
-			}
91
-		}
92
-
93
-		foreach ($cachedMounts as $mountKey => $cachedMount) {
94
-			if (!isset($newMounts[$mountKey])) {
95
-				$removedMounts[] = $cachedMount;
96
-			}
97
-		}
98
-
99
-		$changedMounts = $this->findChangedMounts($newMounts, $cachedMounts);
100
-
101
-		if ($addedMounts || $removedMounts || $changedMounts) {
102
-			$this->connection->beginTransaction();
103
-			$userUID = $user->getUID();
104
-			try {
105
-				foreach ($addedMounts as $mount) {
106
-					$this->logger->debug("Adding mount '{$mount->getKey()}' for user '$userUID'", ['app' => 'files', 'mount_provider' => $mount->getMountProvider()]);
107
-					$this->addToCache($mount);
108
-					/** @psalm-suppress InvalidArgument */
109
-					$this->mountsForUsers[$userUID][$mount->getKey()] = $mount;
110
-				}
111
-				foreach ($removedMounts as $mount) {
112
-					$this->logger->debug("Removing mount '{$mount->getKey()}' for user '$userUID'", ['app' => 'files', 'mount_provider' => $mount->getMountProvider()]);
113
-					$this->removeFromCache($mount);
114
-					unset($this->mountsForUsers[$userUID][$mount->getKey()]);
115
-				}
116
-				foreach ($changedMounts as $mountPair) {
117
-					$newMount = $mountPair[1];
118
-					$this->logger->debug("Updating mount '{$newMount->getKey()}' for user '$userUID'", ['app' => 'files', 'mount_provider' => $newMount->getMountProvider()]);
119
-					$this->updateCachedMount($newMount);
120
-					/** @psalm-suppress InvalidArgument */
121
-					$this->mountsForUsers[$userUID][$newMount->getKey()] = $newMount;
122
-				}
123
-				$this->connection->commit();
124
-			} catch (\Throwable $e) {
125
-				$this->connection->rollBack();
126
-				throw $e;
127
-			}
128
-
129
-			// Only fire events after all mounts have already been adjusted in the database.
130
-			foreach ($addedMounts as $mount) {
131
-				$this->eventDispatcher->dispatchTyped(new UserMountAddedEvent($mount));
132
-			}
133
-			foreach ($removedMounts as $mount) {
134
-				$this->eventDispatcher->dispatchTyped(new UserMountRemovedEvent($mount));
135
-			}
136
-			foreach ($changedMounts as $mountPair) {
137
-				$this->eventDispatcher->dispatchTyped(new UserMountUpdatedEvent($mountPair[0], $mountPair[1]));
138
-			}
139
-		}
140
-		$this->eventLogger->end('fs:setup:user:register');
141
-	}
142
-
143
-	/**
144
-	 * @param array<string, ICachedMountInfo> $newMounts
145
-	 * @param array<string, ICachedMountInfo> $cachedMounts
146
-	 * @return list<list{0: ICachedMountInfo, 1: ICachedMountInfo}> Pairs of old and new mounts
147
-	 */
148
-	private function findChangedMounts(array $newMounts, array $cachedMounts): array {
149
-		$changed = [];
150
-		foreach ($cachedMounts as $key => $cachedMount) {
151
-			if (isset($newMounts[$key])) {
152
-				$newMount = $newMounts[$key];
153
-				if (
154
-					$newMount->getStorageId() !== $cachedMount->getStorageId() ||
155
-					$newMount->getMountId() !== $cachedMount->getMountId() ||
156
-					$newMount->getMountProvider() !== $cachedMount->getMountProvider()
157
-				) {
158
-					$changed[] = [$cachedMount, $newMount];
159
-				}
160
-			}
161
-		}
162
-		return $changed;
163
-	}
164
-
165
-	private function addToCache(ICachedMountInfo $mount) {
166
-		if ($mount->getStorageId() !== -1) {
167
-			$this->connection->insertIfNotExist('*PREFIX*mounts', [
168
-				'storage_id' => $mount->getStorageId(),
169
-				'root_id' => $mount->getRootId(),
170
-				'user_id' => $mount->getUser()->getUID(),
171
-				'mount_point' => $mount->getMountPoint(),
172
-				'mount_id' => $mount->getMountId(),
173
-				'mount_provider_class' => $mount->getMountProvider(),
174
-			], ['root_id', 'user_id', 'mount_point']);
175
-		} else {
176
-			// in some cases this is legitimate, like orphaned shares
177
-			$this->logger->debug('Could not get storage info for mount at ' . $mount->getMountPoint());
178
-		}
179
-	}
180
-
181
-	private function updateCachedMount(ICachedMountInfo $mount) {
182
-		$builder = $this->connection->getQueryBuilder();
183
-
184
-		$query = $builder->update('mounts')
185
-			->set('storage_id', $builder->createNamedParameter($mount->getStorageId()))
186
-			->set('mount_point', $builder->createNamedParameter($mount->getMountPoint()))
187
-			->set('mount_id', $builder->createNamedParameter($mount->getMountId(), IQueryBuilder::PARAM_INT))
188
-			->set('mount_provider_class', $builder->createNamedParameter($mount->getMountProvider()))
189
-			->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID())))
190
-			->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT)));
191
-
192
-		$query->executeStatement();
193
-	}
194
-
195
-	private function removeFromCache(ICachedMountInfo $mount) {
196
-		$builder = $this->connection->getQueryBuilder();
197
-
198
-		$query = $builder->delete('mounts')
199
-			->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID())))
200
-			->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT)))
201
-			->andWhere($builder->expr()->eq('mount_point', $builder->createNamedParameter($mount->getMountPoint())));
202
-		$query->executeStatement();
203
-	}
204
-
205
-	/**
206
-	 * @param array $row
207
-	 * @param (callable(CachedMountInfo): string)|null $pathCallback
208
-	 * @return CachedMountInfo
209
-	 */
210
-	private function dbRowToMountInfo(array $row, ?callable $pathCallback = null): ICachedMountInfo {
211
-		$user = new LazyUser($row['user_id'], $this->userManager);
212
-		$mount_id = $row['mount_id'];
213
-		if (!is_null($mount_id)) {
214
-			$mount_id = (int)$mount_id;
215
-		}
216
-		if ($pathCallback) {
217
-			return new LazyPathCachedMountInfo(
218
-				$user,
219
-				(int)$row['storage_id'],
220
-				(int)$row['root_id'],
221
-				$row['mount_point'],
222
-				$row['mount_provider_class'] ?? '',
223
-				$mount_id,
224
-				$pathCallback,
225
-			);
226
-		} else {
227
-			return new CachedMountInfo(
228
-				$user,
229
-				(int)$row['storage_id'],
230
-				(int)$row['root_id'],
231
-				$row['mount_point'],
232
-				$row['mount_provider_class'] ?? '',
233
-				$mount_id,
234
-				$row['path'] ?? '',
235
-			);
236
-		}
237
-	}
238
-
239
-	/**
240
-	 * @param IUser $user
241
-	 * @return ICachedMountInfo[]
242
-	 */
243
-	public function getMountsForUser(IUser $user) {
244
-		$userUID = $user->getUID();
245
-		if (!$this->userManager->userExists($userUID)) {
246
-			return [];
247
-		}
248
-		if (!isset($this->mountsForUsers[$userUID])) {
249
-			$builder = $this->connection->getQueryBuilder();
250
-			$query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'mount_provider_class')
251
-				->from('mounts', 'm')
252
-				->where($builder->expr()->eq('user_id', $builder->createNamedParameter($userUID)));
253
-
254
-			$result = $query->executeQuery();
255
-			$rows = $result->fetchAll();
256
-			$result->closeCursor();
257
-
258
-			/** @var array<string, ICachedMountInfo> $mounts */
259
-			$mounts = [];
260
-			foreach ($rows as $row) {
261
-				$mount = $this->dbRowToMountInfo($row, [$this, 'getInternalPathForMountInfo']);
262
-				if ($mount !== null) {
263
-					$mounts[$mount->getKey()] = $mount;
264
-				}
265
-			}
266
-			$this->mountsForUsers[$userUID] = $mounts;
267
-		}
268
-		return $this->mountsForUsers[$userUID];
269
-	}
270
-
271
-	public function getInternalPathForMountInfo(CachedMountInfo $info): string {
272
-		$cached = $this->internalPathCache->get($info->getRootId());
273
-		if ($cached !== null) {
274
-			return $cached;
275
-		}
276
-		$builder = $this->connection->getQueryBuilder();
277
-		$query = $builder->select('path')
278
-			->from('filecache')
279
-			->where($builder->expr()->eq('fileid', $builder->createNamedParameter($info->getRootId())));
280
-		return $query->executeQuery()->fetchOne() ?: '';
281
-	}
282
-
283
-	/**
284
-	 * @param int $numericStorageId
285
-	 * @param string|null $user limit the results to a single user
286
-	 * @return CachedMountInfo[]
287
-	 */
288
-	public function getMountsForStorageId($numericStorageId, $user = null) {
289
-		$builder = $this->connection->getQueryBuilder();
290
-		$query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path', 'mount_provider_class')
291
-			->from('mounts', 'm')
292
-			->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
293
-			->where($builder->expr()->eq('storage_id', $builder->createNamedParameter($numericStorageId, IQueryBuilder::PARAM_INT)));
294
-
295
-		if ($user) {
296
-			$query->andWhere($builder->expr()->eq('user_id', $builder->createNamedParameter($user)));
297
-		}
298
-
299
-		$result = $query->executeQuery();
300
-		$rows = $result->fetchAll();
301
-		$result->closeCursor();
302
-
303
-		return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
304
-	}
305
-
306
-	/**
307
-	 * @param int $rootFileId
308
-	 * @return CachedMountInfo[]
309
-	 */
310
-	public function getMountsForRootId($rootFileId) {
311
-		$builder = $this->connection->getQueryBuilder();
312
-		$query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path', 'mount_provider_class')
313
-			->from('mounts', 'm')
314
-			->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
315
-			->where($builder->expr()->eq('root_id', $builder->createNamedParameter($rootFileId, IQueryBuilder::PARAM_INT)));
316
-
317
-		$result = $query->executeQuery();
318
-		$rows = $result->fetchAll();
319
-		$result->closeCursor();
320
-
321
-		return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
322
-	}
323
-
324
-	/**
325
-	 * @param $fileId
326
-	 * @return array{int, string, int}
327
-	 * @throws \OCP\Files\NotFoundException
328
-	 */
329
-	private function getCacheInfoFromFileId($fileId): array {
330
-		if (!isset($this->cacheInfoCache[$fileId])) {
331
-			$builder = $this->connection->getQueryBuilder();
332
-			$query = $builder->select('storage', 'path', 'mimetype')
333
-				->from('filecache')
334
-				->where($builder->expr()->eq('fileid', $builder->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)));
335
-
336
-			$result = $query->executeQuery();
337
-			$row = $result->fetch();
338
-			$result->closeCursor();
339
-
340
-			if (is_array($row)) {
341
-				$this->cacheInfoCache[$fileId] = [
342
-					(int)$row['storage'],
343
-					(string)$row['path'],
344
-					(int)$row['mimetype']
345
-				];
346
-			} else {
347
-				throw new NotFoundException('File with id "' . $fileId . '" not found');
348
-			}
349
-		}
350
-		return $this->cacheInfoCache[$fileId];
351
-	}
352
-
353
-	/**
354
-	 * @param int $fileId
355
-	 * @param string|null $user optionally restrict the results to a single user
356
-	 * @return ICachedMountFileInfo[]
357
-	 * @since 9.0.0
358
-	 */
359
-	public function getMountsForFileId($fileId, $user = null) {
360
-		try {
361
-			[$storageId, $internalPath] = $this->getCacheInfoFromFileId($fileId);
362
-		} catch (NotFoundException $e) {
363
-			return [];
364
-		}
365
-		$mountsForStorage = $this->getMountsForStorageId($storageId, $user);
366
-
367
-		// filter mounts that are from the same storage but not a parent of the file we care about
368
-		$filteredMounts = array_filter($mountsForStorage, function (ICachedMountInfo $mount) use ($internalPath, $fileId) {
369
-			if ($fileId === $mount->getRootId()) {
370
-				return true;
371
-			}
372
-			$internalMountPath = $mount->getRootInternalPath();
373
-
374
-			return $internalMountPath === '' || str_starts_with($internalPath, $internalMountPath . '/');
375
-		});
376
-
377
-		$filteredMounts = array_values(array_filter($filteredMounts, function (ICachedMountInfo $mount) {
378
-			return $this->userManager->userExists($mount->getUser()->getUID());
379
-		}));
380
-
381
-		return array_map(function (ICachedMountInfo $mount) use ($internalPath) {
382
-			return new CachedMountFileInfo(
383
-				$mount->getUser(),
384
-				$mount->getStorageId(),
385
-				$mount->getRootId(),
386
-				$mount->getMountPoint(),
387
-				$mount->getMountId(),
388
-				$mount->getMountProvider(),
389
-				$mount->getRootInternalPath(),
390
-				$internalPath
391
-			);
392
-		}, $filteredMounts);
393
-	}
394
-
395
-	/**
396
-	 * Remove all cached mounts for a user
397
-	 *
398
-	 * @param IUser $user
399
-	 */
400
-	public function removeUserMounts(IUser $user) {
401
-		$builder = $this->connection->getQueryBuilder();
402
-
403
-		$query = $builder->delete('mounts')
404
-			->where($builder->expr()->eq('user_id', $builder->createNamedParameter($user->getUID())));
405
-		$query->executeStatement();
406
-	}
407
-
408
-	public function removeUserStorageMount($storageId, $userId) {
409
-		$builder = $this->connection->getQueryBuilder();
410
-
411
-		$query = $builder->delete('mounts')
412
-			->where($builder->expr()->eq('user_id', $builder->createNamedParameter($userId)))
413
-			->andWhere($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)));
414
-		$query->executeStatement();
415
-	}
416
-
417
-	public function remoteStorageMounts($storageId) {
418
-		$builder = $this->connection->getQueryBuilder();
419
-
420
-		$query = $builder->delete('mounts')
421
-			->where($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)));
422
-		$query->executeStatement();
423
-	}
424
-
425
-	/**
426
-	 * @param array $users
427
-	 * @return array
428
-	 */
429
-	public function getUsedSpaceForUsers(array $users) {
430
-		$builder = $this->connection->getQueryBuilder();
431
-
432
-		$slash = $builder->createNamedParameter('/');
433
-
434
-		$mountPoint = $builder->func()->concat(
435
-			$builder->func()->concat($slash, 'user_id'),
436
-			$slash
437
-		);
438
-
439
-		$userIds = array_map(function (IUser $user) {
440
-			return $user->getUID();
441
-		}, $users);
442
-
443
-		$query = $builder->select('m.user_id', 'f.size')
444
-			->from('mounts', 'm')
445
-			->innerJoin('m', 'filecache', 'f',
446
-				$builder->expr()->andX(
447
-					$builder->expr()->eq('m.storage_id', 'f.storage'),
448
-					$builder->expr()->eq('f.path_hash', $builder->createNamedParameter(md5('files')))
449
-				))
450
-			->where($builder->expr()->eq('m.mount_point', $mountPoint))
451
-			->andWhere($builder->expr()->in('m.user_id', $builder->createNamedParameter($userIds, IQueryBuilder::PARAM_STR_ARRAY)));
452
-
453
-		$result = $query->executeQuery();
454
-
455
-		$results = [];
456
-		while ($row = $result->fetch()) {
457
-			$results[$row['user_id']] = $row['size'];
458
-		}
459
-		$result->closeCursor();
460
-		return $results;
461
-	}
462
-
463
-	public function clear(): void {
464
-		$this->cacheInfoCache = new CappedMemoryCache();
465
-		$this->mountsForUsers = new CappedMemoryCache();
466
-	}
467
-
468
-	public function getMountForPath(IUser $user, string $path): ICachedMountInfo {
469
-		$mounts = $this->getMountsForUser($user);
470
-		$mountPoints = array_map(function (ICachedMountInfo $mount) {
471
-			return $mount->getMountPoint();
472
-		}, $mounts);
473
-		$mounts = array_combine($mountPoints, $mounts);
474
-
475
-		$current = rtrim($path, '/');
476
-		// walk up the directory tree until we find a path that has a mountpoint set
477
-		// the loop will return if a mountpoint is found or break if none are found
478
-		while (true) {
479
-			$mountPoint = $current . '/';
480
-			if (isset($mounts[$mountPoint])) {
481
-				return $mounts[$mountPoint];
482
-			} elseif ($current === '') {
483
-				break;
484
-			}
485
-
486
-			$current = dirname($current);
487
-			if ($current === '.' || $current === '/') {
488
-				$current = '';
489
-			}
490
-		}
491
-
492
-		throw new NotFoundException('No cached mount for path ' . $path);
493
-	}
494
-
495
-	public function getMountsInPath(IUser $user, string $path): array {
496
-		$path = rtrim($path, '/') . '/';
497
-		$mounts = $this->getMountsForUser($user);
498
-		return array_filter($mounts, function (ICachedMountInfo $mount) use ($path) {
499
-			return $mount->getMountPoint() !== $path && str_starts_with($mount->getMountPoint(), $path);
500
-		});
501
-	}
32
+    /**
33
+     * Cached mount info.
34
+     * @var CappedMemoryCache<ICachedMountInfo[]>
35
+     **/
36
+    private CappedMemoryCache $mountsForUsers;
37
+    /**
38
+     * fileid => internal path mapping for cached mount info.
39
+     * @var CappedMemoryCache<string>
40
+     **/
41
+    private CappedMemoryCache $internalPathCache;
42
+    /** @var CappedMemoryCache<array> */
43
+    private CappedMemoryCache $cacheInfoCache;
44
+
45
+    /**
46
+     * UserMountCache constructor.
47
+     */
48
+    public function __construct(
49
+        private IDBConnection $connection,
50
+        private IUserManager $userManager,
51
+        private LoggerInterface $logger,
52
+        private IEventLogger $eventLogger,
53
+        private IEventDispatcher $eventDispatcher,
54
+    ) {
55
+        $this->cacheInfoCache = new CappedMemoryCache();
56
+        $this->internalPathCache = new CappedMemoryCache();
57
+        $this->mountsForUsers = new CappedMemoryCache();
58
+    }
59
+
60
+    public function registerMounts(IUser $user, array $mounts, ?array $mountProviderClasses = null) {
61
+        $this->eventLogger->start('fs:setup:user:register', 'Registering mounts for user');
62
+        /** @var array<string, ICachedMountInfo> $newMounts */
63
+        $newMounts = [];
64
+        foreach ($mounts as $mount) {
65
+            // filter out any storages which aren't scanned yet since we aren't interested in files from those storages (yet)
66
+            if ($mount->getStorageRootId() !== -1) {
67
+                $mountInfo = new LazyStorageMountInfo($user, $mount);
68
+                $newMounts[$mountInfo->getKey()] = $mountInfo;
69
+            }
70
+        }
71
+
72
+        $cachedMounts = $this->getMountsForUser($user);
73
+        if (is_array($mountProviderClasses)) {
74
+            $cachedMounts = array_filter($cachedMounts, function (ICachedMountInfo $mountInfo) use ($mountProviderClasses, $newMounts) {
75
+                // for existing mounts that didn't have a mount provider set
76
+                // we still want the ones that map to new mounts
77
+                if ($mountInfo->getMountProvider() === '' && isset($newMounts[$mountInfo->getKey()])) {
78
+                    return true;
79
+                }
80
+                return in_array($mountInfo->getMountProvider(), $mountProviderClasses);
81
+            });
82
+        }
83
+
84
+        $addedMounts = [];
85
+        $removedMounts = [];
86
+
87
+        foreach ($newMounts as $mountKey => $newMount) {
88
+            if (!isset($cachedMounts[$mountKey])) {
89
+                $addedMounts[] = $newMount;
90
+            }
91
+        }
92
+
93
+        foreach ($cachedMounts as $mountKey => $cachedMount) {
94
+            if (!isset($newMounts[$mountKey])) {
95
+                $removedMounts[] = $cachedMount;
96
+            }
97
+        }
98
+
99
+        $changedMounts = $this->findChangedMounts($newMounts, $cachedMounts);
100
+
101
+        if ($addedMounts || $removedMounts || $changedMounts) {
102
+            $this->connection->beginTransaction();
103
+            $userUID = $user->getUID();
104
+            try {
105
+                foreach ($addedMounts as $mount) {
106
+                    $this->logger->debug("Adding mount '{$mount->getKey()}' for user '$userUID'", ['app' => 'files', 'mount_provider' => $mount->getMountProvider()]);
107
+                    $this->addToCache($mount);
108
+                    /** @psalm-suppress InvalidArgument */
109
+                    $this->mountsForUsers[$userUID][$mount->getKey()] = $mount;
110
+                }
111
+                foreach ($removedMounts as $mount) {
112
+                    $this->logger->debug("Removing mount '{$mount->getKey()}' for user '$userUID'", ['app' => 'files', 'mount_provider' => $mount->getMountProvider()]);
113
+                    $this->removeFromCache($mount);
114
+                    unset($this->mountsForUsers[$userUID][$mount->getKey()]);
115
+                }
116
+                foreach ($changedMounts as $mountPair) {
117
+                    $newMount = $mountPair[1];
118
+                    $this->logger->debug("Updating mount '{$newMount->getKey()}' for user '$userUID'", ['app' => 'files', 'mount_provider' => $newMount->getMountProvider()]);
119
+                    $this->updateCachedMount($newMount);
120
+                    /** @psalm-suppress InvalidArgument */
121
+                    $this->mountsForUsers[$userUID][$newMount->getKey()] = $newMount;
122
+                }
123
+                $this->connection->commit();
124
+            } catch (\Throwable $e) {
125
+                $this->connection->rollBack();
126
+                throw $e;
127
+            }
128
+
129
+            // Only fire events after all mounts have already been adjusted in the database.
130
+            foreach ($addedMounts as $mount) {
131
+                $this->eventDispatcher->dispatchTyped(new UserMountAddedEvent($mount));
132
+            }
133
+            foreach ($removedMounts as $mount) {
134
+                $this->eventDispatcher->dispatchTyped(new UserMountRemovedEvent($mount));
135
+            }
136
+            foreach ($changedMounts as $mountPair) {
137
+                $this->eventDispatcher->dispatchTyped(new UserMountUpdatedEvent($mountPair[0], $mountPair[1]));
138
+            }
139
+        }
140
+        $this->eventLogger->end('fs:setup:user:register');
141
+    }
142
+
143
+    /**
144
+     * @param array<string, ICachedMountInfo> $newMounts
145
+     * @param array<string, ICachedMountInfo> $cachedMounts
146
+     * @return list<list{0: ICachedMountInfo, 1: ICachedMountInfo}> Pairs of old and new mounts
147
+     */
148
+    private function findChangedMounts(array $newMounts, array $cachedMounts): array {
149
+        $changed = [];
150
+        foreach ($cachedMounts as $key => $cachedMount) {
151
+            if (isset($newMounts[$key])) {
152
+                $newMount = $newMounts[$key];
153
+                if (
154
+                    $newMount->getStorageId() !== $cachedMount->getStorageId() ||
155
+                    $newMount->getMountId() !== $cachedMount->getMountId() ||
156
+                    $newMount->getMountProvider() !== $cachedMount->getMountProvider()
157
+                ) {
158
+                    $changed[] = [$cachedMount, $newMount];
159
+                }
160
+            }
161
+        }
162
+        return $changed;
163
+    }
164
+
165
+    private function addToCache(ICachedMountInfo $mount) {
166
+        if ($mount->getStorageId() !== -1) {
167
+            $this->connection->insertIfNotExist('*PREFIX*mounts', [
168
+                'storage_id' => $mount->getStorageId(),
169
+                'root_id' => $mount->getRootId(),
170
+                'user_id' => $mount->getUser()->getUID(),
171
+                'mount_point' => $mount->getMountPoint(),
172
+                'mount_id' => $mount->getMountId(),
173
+                'mount_provider_class' => $mount->getMountProvider(),
174
+            ], ['root_id', 'user_id', 'mount_point']);
175
+        } else {
176
+            // in some cases this is legitimate, like orphaned shares
177
+            $this->logger->debug('Could not get storage info for mount at ' . $mount->getMountPoint());
178
+        }
179
+    }
180
+
181
+    private function updateCachedMount(ICachedMountInfo $mount) {
182
+        $builder = $this->connection->getQueryBuilder();
183
+
184
+        $query = $builder->update('mounts')
185
+            ->set('storage_id', $builder->createNamedParameter($mount->getStorageId()))
186
+            ->set('mount_point', $builder->createNamedParameter($mount->getMountPoint()))
187
+            ->set('mount_id', $builder->createNamedParameter($mount->getMountId(), IQueryBuilder::PARAM_INT))
188
+            ->set('mount_provider_class', $builder->createNamedParameter($mount->getMountProvider()))
189
+            ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID())))
190
+            ->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT)));
191
+
192
+        $query->executeStatement();
193
+    }
194
+
195
+    private function removeFromCache(ICachedMountInfo $mount) {
196
+        $builder = $this->connection->getQueryBuilder();
197
+
198
+        $query = $builder->delete('mounts')
199
+            ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID())))
200
+            ->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT)))
201
+            ->andWhere($builder->expr()->eq('mount_point', $builder->createNamedParameter($mount->getMountPoint())));
202
+        $query->executeStatement();
203
+    }
204
+
205
+    /**
206
+     * @param array $row
207
+     * @param (callable(CachedMountInfo): string)|null $pathCallback
208
+     * @return CachedMountInfo
209
+     */
210
+    private function dbRowToMountInfo(array $row, ?callable $pathCallback = null): ICachedMountInfo {
211
+        $user = new LazyUser($row['user_id'], $this->userManager);
212
+        $mount_id = $row['mount_id'];
213
+        if (!is_null($mount_id)) {
214
+            $mount_id = (int)$mount_id;
215
+        }
216
+        if ($pathCallback) {
217
+            return new LazyPathCachedMountInfo(
218
+                $user,
219
+                (int)$row['storage_id'],
220
+                (int)$row['root_id'],
221
+                $row['mount_point'],
222
+                $row['mount_provider_class'] ?? '',
223
+                $mount_id,
224
+                $pathCallback,
225
+            );
226
+        } else {
227
+            return new CachedMountInfo(
228
+                $user,
229
+                (int)$row['storage_id'],
230
+                (int)$row['root_id'],
231
+                $row['mount_point'],
232
+                $row['mount_provider_class'] ?? '',
233
+                $mount_id,
234
+                $row['path'] ?? '',
235
+            );
236
+        }
237
+    }
238
+
239
+    /**
240
+     * @param IUser $user
241
+     * @return ICachedMountInfo[]
242
+     */
243
+    public function getMountsForUser(IUser $user) {
244
+        $userUID = $user->getUID();
245
+        if (!$this->userManager->userExists($userUID)) {
246
+            return [];
247
+        }
248
+        if (!isset($this->mountsForUsers[$userUID])) {
249
+            $builder = $this->connection->getQueryBuilder();
250
+            $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'mount_provider_class')
251
+                ->from('mounts', 'm')
252
+                ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($userUID)));
253
+
254
+            $result = $query->executeQuery();
255
+            $rows = $result->fetchAll();
256
+            $result->closeCursor();
257
+
258
+            /** @var array<string, ICachedMountInfo> $mounts */
259
+            $mounts = [];
260
+            foreach ($rows as $row) {
261
+                $mount = $this->dbRowToMountInfo($row, [$this, 'getInternalPathForMountInfo']);
262
+                if ($mount !== null) {
263
+                    $mounts[$mount->getKey()] = $mount;
264
+                }
265
+            }
266
+            $this->mountsForUsers[$userUID] = $mounts;
267
+        }
268
+        return $this->mountsForUsers[$userUID];
269
+    }
270
+
271
+    public function getInternalPathForMountInfo(CachedMountInfo $info): string {
272
+        $cached = $this->internalPathCache->get($info->getRootId());
273
+        if ($cached !== null) {
274
+            return $cached;
275
+        }
276
+        $builder = $this->connection->getQueryBuilder();
277
+        $query = $builder->select('path')
278
+            ->from('filecache')
279
+            ->where($builder->expr()->eq('fileid', $builder->createNamedParameter($info->getRootId())));
280
+        return $query->executeQuery()->fetchOne() ?: '';
281
+    }
282
+
283
+    /**
284
+     * @param int $numericStorageId
285
+     * @param string|null $user limit the results to a single user
286
+     * @return CachedMountInfo[]
287
+     */
288
+    public function getMountsForStorageId($numericStorageId, $user = null) {
289
+        $builder = $this->connection->getQueryBuilder();
290
+        $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path', 'mount_provider_class')
291
+            ->from('mounts', 'm')
292
+            ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
293
+            ->where($builder->expr()->eq('storage_id', $builder->createNamedParameter($numericStorageId, IQueryBuilder::PARAM_INT)));
294
+
295
+        if ($user) {
296
+            $query->andWhere($builder->expr()->eq('user_id', $builder->createNamedParameter($user)));
297
+        }
298
+
299
+        $result = $query->executeQuery();
300
+        $rows = $result->fetchAll();
301
+        $result->closeCursor();
302
+
303
+        return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
304
+    }
305
+
306
+    /**
307
+     * @param int $rootFileId
308
+     * @return CachedMountInfo[]
309
+     */
310
+    public function getMountsForRootId($rootFileId) {
311
+        $builder = $this->connection->getQueryBuilder();
312
+        $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path', 'mount_provider_class')
313
+            ->from('mounts', 'm')
314
+            ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
315
+            ->where($builder->expr()->eq('root_id', $builder->createNamedParameter($rootFileId, IQueryBuilder::PARAM_INT)));
316
+
317
+        $result = $query->executeQuery();
318
+        $rows = $result->fetchAll();
319
+        $result->closeCursor();
320
+
321
+        return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
322
+    }
323
+
324
+    /**
325
+     * @param $fileId
326
+     * @return array{int, string, int}
327
+     * @throws \OCP\Files\NotFoundException
328
+     */
329
+    private function getCacheInfoFromFileId($fileId): array {
330
+        if (!isset($this->cacheInfoCache[$fileId])) {
331
+            $builder = $this->connection->getQueryBuilder();
332
+            $query = $builder->select('storage', 'path', 'mimetype')
333
+                ->from('filecache')
334
+                ->where($builder->expr()->eq('fileid', $builder->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)));
335
+
336
+            $result = $query->executeQuery();
337
+            $row = $result->fetch();
338
+            $result->closeCursor();
339
+
340
+            if (is_array($row)) {
341
+                $this->cacheInfoCache[$fileId] = [
342
+                    (int)$row['storage'],
343
+                    (string)$row['path'],
344
+                    (int)$row['mimetype']
345
+                ];
346
+            } else {
347
+                throw new NotFoundException('File with id "' . $fileId . '" not found');
348
+            }
349
+        }
350
+        return $this->cacheInfoCache[$fileId];
351
+    }
352
+
353
+    /**
354
+     * @param int $fileId
355
+     * @param string|null $user optionally restrict the results to a single user
356
+     * @return ICachedMountFileInfo[]
357
+     * @since 9.0.0
358
+     */
359
+    public function getMountsForFileId($fileId, $user = null) {
360
+        try {
361
+            [$storageId, $internalPath] = $this->getCacheInfoFromFileId($fileId);
362
+        } catch (NotFoundException $e) {
363
+            return [];
364
+        }
365
+        $mountsForStorage = $this->getMountsForStorageId($storageId, $user);
366
+
367
+        // filter mounts that are from the same storage but not a parent of the file we care about
368
+        $filteredMounts = array_filter($mountsForStorage, function (ICachedMountInfo $mount) use ($internalPath, $fileId) {
369
+            if ($fileId === $mount->getRootId()) {
370
+                return true;
371
+            }
372
+            $internalMountPath = $mount->getRootInternalPath();
373
+
374
+            return $internalMountPath === '' || str_starts_with($internalPath, $internalMountPath . '/');
375
+        });
376
+
377
+        $filteredMounts = array_values(array_filter($filteredMounts, function (ICachedMountInfo $mount) {
378
+            return $this->userManager->userExists($mount->getUser()->getUID());
379
+        }));
380
+
381
+        return array_map(function (ICachedMountInfo $mount) use ($internalPath) {
382
+            return new CachedMountFileInfo(
383
+                $mount->getUser(),
384
+                $mount->getStorageId(),
385
+                $mount->getRootId(),
386
+                $mount->getMountPoint(),
387
+                $mount->getMountId(),
388
+                $mount->getMountProvider(),
389
+                $mount->getRootInternalPath(),
390
+                $internalPath
391
+            );
392
+        }, $filteredMounts);
393
+    }
394
+
395
+    /**
396
+     * Remove all cached mounts for a user
397
+     *
398
+     * @param IUser $user
399
+     */
400
+    public function removeUserMounts(IUser $user) {
401
+        $builder = $this->connection->getQueryBuilder();
402
+
403
+        $query = $builder->delete('mounts')
404
+            ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($user->getUID())));
405
+        $query->executeStatement();
406
+    }
407
+
408
+    public function removeUserStorageMount($storageId, $userId) {
409
+        $builder = $this->connection->getQueryBuilder();
410
+
411
+        $query = $builder->delete('mounts')
412
+            ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($userId)))
413
+            ->andWhere($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)));
414
+        $query->executeStatement();
415
+    }
416
+
417
+    public function remoteStorageMounts($storageId) {
418
+        $builder = $this->connection->getQueryBuilder();
419
+
420
+        $query = $builder->delete('mounts')
421
+            ->where($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)));
422
+        $query->executeStatement();
423
+    }
424
+
425
+    /**
426
+     * @param array $users
427
+     * @return array
428
+     */
429
+    public function getUsedSpaceForUsers(array $users) {
430
+        $builder = $this->connection->getQueryBuilder();
431
+
432
+        $slash = $builder->createNamedParameter('/');
433
+
434
+        $mountPoint = $builder->func()->concat(
435
+            $builder->func()->concat($slash, 'user_id'),
436
+            $slash
437
+        );
438
+
439
+        $userIds = array_map(function (IUser $user) {
440
+            return $user->getUID();
441
+        }, $users);
442
+
443
+        $query = $builder->select('m.user_id', 'f.size')
444
+            ->from('mounts', 'm')
445
+            ->innerJoin('m', 'filecache', 'f',
446
+                $builder->expr()->andX(
447
+                    $builder->expr()->eq('m.storage_id', 'f.storage'),
448
+                    $builder->expr()->eq('f.path_hash', $builder->createNamedParameter(md5('files')))
449
+                ))
450
+            ->where($builder->expr()->eq('m.mount_point', $mountPoint))
451
+            ->andWhere($builder->expr()->in('m.user_id', $builder->createNamedParameter($userIds, IQueryBuilder::PARAM_STR_ARRAY)));
452
+
453
+        $result = $query->executeQuery();
454
+
455
+        $results = [];
456
+        while ($row = $result->fetch()) {
457
+            $results[$row['user_id']] = $row['size'];
458
+        }
459
+        $result->closeCursor();
460
+        return $results;
461
+    }
462
+
463
+    public function clear(): void {
464
+        $this->cacheInfoCache = new CappedMemoryCache();
465
+        $this->mountsForUsers = new CappedMemoryCache();
466
+    }
467
+
468
+    public function getMountForPath(IUser $user, string $path): ICachedMountInfo {
469
+        $mounts = $this->getMountsForUser($user);
470
+        $mountPoints = array_map(function (ICachedMountInfo $mount) {
471
+            return $mount->getMountPoint();
472
+        }, $mounts);
473
+        $mounts = array_combine($mountPoints, $mounts);
474
+
475
+        $current = rtrim($path, '/');
476
+        // walk up the directory tree until we find a path that has a mountpoint set
477
+        // the loop will return if a mountpoint is found or break if none are found
478
+        while (true) {
479
+            $mountPoint = $current . '/';
480
+            if (isset($mounts[$mountPoint])) {
481
+                return $mounts[$mountPoint];
482
+            } elseif ($current === '') {
483
+                break;
484
+            }
485
+
486
+            $current = dirname($current);
487
+            if ($current === '.' || $current === '/') {
488
+                $current = '';
489
+            }
490
+        }
491
+
492
+        throw new NotFoundException('No cached mount for path ' . $path);
493
+    }
494
+
495
+    public function getMountsInPath(IUser $user, string $path): array {
496
+        $path = rtrim($path, '/') . '/';
497
+        $mounts = $this->getMountsForUser($user);
498
+        return array_filter($mounts, function (ICachedMountInfo $mount) use ($path) {
499
+            return $mount->getMountPoint() !== $path && str_starts_with($mount->getMountPoint(), $path);
500
+        });
501
+    }
502 502
 }
Please login to merge, or discard this patch.
tests/lib/Files/Config/UserMountCacheTest.php 1 patch
Indentation   +457 added lines, -457 removed lines patch added patch discarded remove patch
@@ -34,566 +34,566 @@
 block discarded – undo
34 34
  * @group DB
35 35
  */
36 36
 class UserMountCacheTest extends TestCase {
37
-	private IDBConnection $connection;
38
-	private IUserManager $userManager;
39
-	private IEventDispatcher $eventDispatcher;
40
-	private UserMountCache $cache;
41
-	private array $fileIds = [];
42
-
43
-	protected function setUp(): void {
44
-		parent::setUp();
45
-
46
-		$this->fileIds = [];
47
-
48
-		$this->connection = \OC::$server->getDatabaseConnection();
49
-
50
-		$config = $this->getMockBuilder(IConfig::class)
51
-			->disableOriginalConstructor()
52
-			->getMock();
53
-		$config
54
-			->expects($this->any())
55
-			->method('getUserValue')
56
-			->willReturnArgument(3);
57
-		$config
58
-			->expects($this->any())
59
-			->method('getAppValue')
60
-			->willReturnArgument(2);
61
-
62
-		$this->userManager = new Manager($config, $this->createMock(ICacheFactory::class), $this->createMock(IEventDispatcher::class), $this->createMock(LoggerInterface::class));
63
-		$userBackend = new Dummy();
64
-		$userBackend->createUser('u1', '');
65
-		$userBackend->createUser('u2', '');
66
-		$userBackend->createUser('u3', '');
67
-		$this->userManager->registerBackend($userBackend);
68
-
69
-		$this->eventDispatcher = $this->createMock(IEventDispatcher::class);
37
+    private IDBConnection $connection;
38
+    private IUserManager $userManager;
39
+    private IEventDispatcher $eventDispatcher;
40
+    private UserMountCache $cache;
41
+    private array $fileIds = [];
42
+
43
+    protected function setUp(): void {
44
+        parent::setUp();
45
+
46
+        $this->fileIds = [];
47
+
48
+        $this->connection = \OC::$server->getDatabaseConnection();
49
+
50
+        $config = $this->getMockBuilder(IConfig::class)
51
+            ->disableOriginalConstructor()
52
+            ->getMock();
53
+        $config
54
+            ->expects($this->any())
55
+            ->method('getUserValue')
56
+            ->willReturnArgument(3);
57
+        $config
58
+            ->expects($this->any())
59
+            ->method('getAppValue')
60
+            ->willReturnArgument(2);
61
+
62
+        $this->userManager = new Manager($config, $this->createMock(ICacheFactory::class), $this->createMock(IEventDispatcher::class), $this->createMock(LoggerInterface::class));
63
+        $userBackend = new Dummy();
64
+        $userBackend->createUser('u1', '');
65
+        $userBackend->createUser('u2', '');
66
+        $userBackend->createUser('u3', '');
67
+        $this->userManager->registerBackend($userBackend);
68
+
69
+        $this->eventDispatcher = $this->createMock(IEventDispatcher::class);
70 70
 
71
-		$this->cache = new UserMountCache($this->connection,
72
-			$this->userManager,
73
-			$this->createMock(LoggerInterface::class),
74
-			$this->createMock(IEventLogger::class),
75
-			$this->eventDispatcher,
76
-		);
77
-	}
78
-
79
-	protected function tearDown(): void {
80
-		$builder = $this->connection->getQueryBuilder();
81
-
82
-		$builder->delete('mounts')->execute();
83
-
84
-		$builder = $this->connection->getQueryBuilder();
85
-
86
-		foreach ($this->fileIds as $fileId) {
87
-			$builder->delete('filecache')
88
-				->where($builder->expr()->eq('fileid', new Literal($fileId)))
89
-				->execute();
90
-		}
91
-	}
92
-
93
-	private function getStorage($storageId, $rootInternalPath = '') {
94
-		$rootId = $this->createCacheEntry($rootInternalPath, $storageId);
95
-
96
-		$storageCache = $this->createMock(\OC\Files\Cache\Storage::class);
97
-		$storageCache->expects($this->any())
98
-			->method('getNumericId')
99
-			->willReturn($storageId);
100
-
101
-		$cache = $this->createMock(Cache::class);
102
-		$cache->expects($this->any())
103
-			->method('getId')
104
-			->willReturn($rootId);
105
-		$cache->method('getNumericStorageId')
106
-			->willReturn($storageId);
71
+        $this->cache = new UserMountCache($this->connection,
72
+            $this->userManager,
73
+            $this->createMock(LoggerInterface::class),
74
+            $this->createMock(IEventLogger::class),
75
+            $this->eventDispatcher,
76
+        );
77
+    }
78
+
79
+    protected function tearDown(): void {
80
+        $builder = $this->connection->getQueryBuilder();
81
+
82
+        $builder->delete('mounts')->execute();
83
+
84
+        $builder = $this->connection->getQueryBuilder();
85
+
86
+        foreach ($this->fileIds as $fileId) {
87
+            $builder->delete('filecache')
88
+                ->where($builder->expr()->eq('fileid', new Literal($fileId)))
89
+                ->execute();
90
+        }
91
+    }
92
+
93
+    private function getStorage($storageId, $rootInternalPath = '') {
94
+        $rootId = $this->createCacheEntry($rootInternalPath, $storageId);
95
+
96
+        $storageCache = $this->createMock(\OC\Files\Cache\Storage::class);
97
+        $storageCache->expects($this->any())
98
+            ->method('getNumericId')
99
+            ->willReturn($storageId);
100
+
101
+        $cache = $this->createMock(Cache::class);
102
+        $cache->expects($this->any())
103
+            ->method('getId')
104
+            ->willReturn($rootId);
105
+        $cache->method('getNumericStorageId')
106
+            ->willReturn($storageId);
107 107
 
108
-		$storage = $this->createMock(Storage::class);
109
-		$storage->expects($this->any())
110
-			->method('getStorageCache')
111
-			->willReturn($storageCache);
112
-		$storage->expects($this->any())
113
-			->method('getCache')
114
-			->willReturn($cache);
108
+        $storage = $this->createMock(Storage::class);
109
+        $storage->expects($this->any())
110
+            ->method('getStorageCache')
111
+            ->willReturn($storageCache);
112
+        $storage->expects($this->any())
113
+            ->method('getCache')
114
+            ->willReturn($cache);
115 115
 
116
-		return [$storage, $rootId];
117
-	}
118
-
119
-	private function clearCache() {
120
-		$this->invokePrivate($this->cache, 'mountsForUsers', [new CappedMemoryCache()]);
121
-	}
122
-
123
-	private function keyForMount(MountPoint $mount): string {
124
-		return $mount->getStorageRootId() . '::' . $mount->getMountPoint();
125
-	}
126
-
127
-	public function testNewMounts(): void {
128
-		$this->eventDispatcher
129
-			->expects($this->once())
130
-			->method('dispatchTyped')
131
-			->with($this->callback(fn (UserMountAddedEvent $event) => $event->mountPoint->getMountPoint() === '/asd/'));
132
-
133
-		$user = $this->userManager->get('u1');
116
+        return [$storage, $rootId];
117
+    }
118
+
119
+    private function clearCache() {
120
+        $this->invokePrivate($this->cache, 'mountsForUsers', [new CappedMemoryCache()]);
121
+    }
122
+
123
+    private function keyForMount(MountPoint $mount): string {
124
+        return $mount->getStorageRootId() . '::' . $mount->getMountPoint();
125
+    }
126
+
127
+    public function testNewMounts(): void {
128
+        $this->eventDispatcher
129
+            ->expects($this->once())
130
+            ->method('dispatchTyped')
131
+            ->with($this->callback(fn (UserMountAddedEvent $event) => $event->mountPoint->getMountPoint() === '/asd/'));
132
+
133
+        $user = $this->userManager->get('u1');
134 134
 
135
-		[$storage] = $this->getStorage(10);
136
-		$mount = new MountPoint($storage, '/asd/');
135
+        [$storage] = $this->getStorage(10);
136
+        $mount = new MountPoint($storage, '/asd/');
137 137
 
138
-		$this->cache->registerMounts($user, [$mount]);
138
+        $this->cache->registerMounts($user, [$mount]);
139 139
 
140
-		$this->clearCache();
140
+        $this->clearCache();
141 141
 
142
-		$cachedMounts = $this->cache->getMountsForUser($user);
142
+        $cachedMounts = $this->cache->getMountsForUser($user);
143 143
 
144
-		$this->assertCount(1, $cachedMounts);
145
-		$cachedMount = $cachedMounts[$this->keyForMount($mount)];
146
-		$this->assertEquals('/asd/', $cachedMount->getMountPoint());
147
-		$this->assertEquals($user->getUID(), $cachedMount->getUser()->getUID());
148
-		$this->assertEquals($storage->getCache()->getId(''), $cachedMount->getRootId());
149
-		$this->assertEquals($storage->getStorageCache()->getNumericId(), $cachedMount->getStorageId());
150
-	}
144
+        $this->assertCount(1, $cachedMounts);
145
+        $cachedMount = $cachedMounts[$this->keyForMount($mount)];
146
+        $this->assertEquals('/asd/', $cachedMount->getMountPoint());
147
+        $this->assertEquals($user->getUID(), $cachedMount->getUser()->getUID());
148
+        $this->assertEquals($storage->getCache()->getId(''), $cachedMount->getRootId());
149
+        $this->assertEquals($storage->getStorageCache()->getNumericId(), $cachedMount->getStorageId());
150
+    }
151 151
 
152
-	public function testSameMounts(): void {
153
-		$this->eventDispatcher
154
-			->expects($this->once())
155
-			->method('dispatchTyped')
156
-			->with($this->callback(fn (UserMountAddedEvent $event) => $event->mountPoint->getMountPoint() === '/asd/'));
152
+    public function testSameMounts(): void {
153
+        $this->eventDispatcher
154
+            ->expects($this->once())
155
+            ->method('dispatchTyped')
156
+            ->with($this->callback(fn (UserMountAddedEvent $event) => $event->mountPoint->getMountPoint() === '/asd/'));
157 157
 
158
-		$user = $this->userManager->get('u1');
158
+        $user = $this->userManager->get('u1');
159 159
 
160
-		[$storage] = $this->getStorage(10);
161
-		$mount = new MountPoint($storage, '/asd/');
160
+        [$storage] = $this->getStorage(10);
161
+        $mount = new MountPoint($storage, '/asd/');
162 162
 
163
-		$this->cache->registerMounts($user, [$mount]);
163
+        $this->cache->registerMounts($user, [$mount]);
164 164
 
165
-		$this->clearCache();
165
+        $this->clearCache();
166 166
 
167
-		$this->cache->registerMounts($user, [$mount]);
167
+        $this->cache->registerMounts($user, [$mount]);
168 168
 
169
-		$this->clearCache();
169
+        $this->clearCache();
170 170
 
171
-		$cachedMounts = $this->cache->getMountsForUser($user);
171
+        $cachedMounts = $this->cache->getMountsForUser($user);
172 172
 
173
-		$this->assertCount(1, $cachedMounts);
174
-		$cachedMount = $cachedMounts[$this->keyForMount($mount)];
175
-		$this->assertEquals('/asd/', $cachedMount->getMountPoint());
176
-		$this->assertEquals($user->getUID(), $cachedMount->getUser()->getUID());
177
-		$this->assertEquals($storage->getCache()->getId(''), $cachedMount->getRootId());
178
-		$this->assertEquals($storage->getStorageCache()->getNumericId(), $cachedMount->getStorageId());
179
-	}
173
+        $this->assertCount(1, $cachedMounts);
174
+        $cachedMount = $cachedMounts[$this->keyForMount($mount)];
175
+        $this->assertEquals('/asd/', $cachedMount->getMountPoint());
176
+        $this->assertEquals($user->getUID(), $cachedMount->getUser()->getUID());
177
+        $this->assertEquals($storage->getCache()->getId(''), $cachedMount->getRootId());
178
+        $this->assertEquals($storage->getStorageCache()->getNumericId(), $cachedMount->getStorageId());
179
+    }
180 180
 
181
-	public function testRemoveMounts(): void {
182
-		$operation = 0;
183
-		$this->eventDispatcher
184
-			->expects($this->exactly(2))
185
-			->method('dispatchTyped')
186
-			->with($this->callback(function (UserMountAddedEvent|UserMountRemovedEvent $event) use (&$operation) {
187
-				return match(++$operation) {
188
-					1 => $event instanceof UserMountAddedEvent && $event->mountPoint->getMountPoint() === '/asd/',
189
-					2 => $event instanceof UserMountRemovedEvent && $event->mountPoint->getMountPoint() === '/asd/',
190
-					default => false,
191
-				};
192
-			}));
181
+    public function testRemoveMounts(): void {
182
+        $operation = 0;
183
+        $this->eventDispatcher
184
+            ->expects($this->exactly(2))
185
+            ->method('dispatchTyped')
186
+            ->with($this->callback(function (UserMountAddedEvent|UserMountRemovedEvent $event) use (&$operation) {
187
+                return match(++$operation) {
188
+                    1 => $event instanceof UserMountAddedEvent && $event->mountPoint->getMountPoint() === '/asd/',
189
+                    2 => $event instanceof UserMountRemovedEvent && $event->mountPoint->getMountPoint() === '/asd/',
190
+                    default => false,
191
+                };
192
+            }));
193 193
 
194
-		$user = $this->userManager->get('u1');
194
+        $user = $this->userManager->get('u1');
195 195
 
196
-		[$storage] = $this->getStorage(10);
197
-		$mount = new MountPoint($storage, '/asd/');
196
+        [$storage] = $this->getStorage(10);
197
+        $mount = new MountPoint($storage, '/asd/');
198 198
 
199
-		$this->cache->registerMounts($user, [$mount]);
199
+        $this->cache->registerMounts($user, [$mount]);
200 200
 
201
-		$this->clearCache();
201
+        $this->clearCache();
202 202
 
203
-		$this->cache->registerMounts($user, []);
203
+        $this->cache->registerMounts($user, []);
204 204
 
205
-		$this->clearCache();
205
+        $this->clearCache();
206 206
 
207
-		$cachedMounts = $this->cache->getMountsForUser($user);
207
+        $cachedMounts = $this->cache->getMountsForUser($user);
208 208
 
209
-		$this->assertCount(0, $cachedMounts);
210
-	}
209
+        $this->assertCount(0, $cachedMounts);
210
+    }
211 211
 
212
-	public function testChangeMounts(): void {
213
-		$operation = 0;
214
-		$this->eventDispatcher
215
-			->expects($this->exactly(3))
216
-			->method('dispatchTyped')
217
-			->with($this->callback(function (UserMountAddedEvent|UserMountRemovedEvent $event) use (&$operation) {
218
-				return match(++$operation) {
219
-					1 => $event instanceof UserMountAddedEvent && $event->mountPoint->getMountPoint() === '/bar/',
220
-					2 => $event instanceof UserMountAddedEvent && $event->mountPoint->getMountPoint() === '/foo/',
221
-					3 => $event instanceof UserMountRemovedEvent && $event->mountPoint->getMountPoint() === '/bar/',
222
-					default => false,
223
-				};
224
-			}));
212
+    public function testChangeMounts(): void {
213
+        $operation = 0;
214
+        $this->eventDispatcher
215
+            ->expects($this->exactly(3))
216
+            ->method('dispatchTyped')
217
+            ->with($this->callback(function (UserMountAddedEvent|UserMountRemovedEvent $event) use (&$operation) {
218
+                return match(++$operation) {
219
+                    1 => $event instanceof UserMountAddedEvent && $event->mountPoint->getMountPoint() === '/bar/',
220
+                    2 => $event instanceof UserMountAddedEvent && $event->mountPoint->getMountPoint() === '/foo/',
221
+                    3 => $event instanceof UserMountRemovedEvent && $event->mountPoint->getMountPoint() === '/bar/',
222
+                    default => false,
223
+                };
224
+            }));
225 225
 
226
-		$user = $this->userManager->get('u1');
226
+        $user = $this->userManager->get('u1');
227 227
 
228
-		[$storage] = $this->getStorage(10);
229
-		$mount = new MountPoint($storage, '/bar/');
228
+        [$storage] = $this->getStorage(10);
229
+        $mount = new MountPoint($storage, '/bar/');
230 230
 
231
-		$this->cache->registerMounts($user, [$mount]);
231
+        $this->cache->registerMounts($user, [$mount]);
232 232
 
233
-		$this->clearCache();
233
+        $this->clearCache();
234 234
 
235
-		$mount = new MountPoint($storage, '/foo/');
235
+        $mount = new MountPoint($storage, '/foo/');
236 236
 
237
-		$this->cache->registerMounts($user, [$mount]);
237
+        $this->cache->registerMounts($user, [$mount]);
238 238
 
239
-		$this->clearCache();
239
+        $this->clearCache();
240 240
 
241
-		$cachedMounts = $this->cache->getMountsForUser($user);
241
+        $cachedMounts = $this->cache->getMountsForUser($user);
242 242
 
243
-		$this->assertCount(1, $cachedMounts);
244
-		$cachedMount = $cachedMounts[$this->keyForMount($mount)];
245
-		$this->assertEquals('/foo/', $cachedMount->getMountPoint());
246
-	}
243
+        $this->assertCount(1, $cachedMounts);
244
+        $cachedMount = $cachedMounts[$this->keyForMount($mount)];
245
+        $this->assertEquals('/foo/', $cachedMount->getMountPoint());
246
+    }
247 247
 
248
-	public function testChangeMountId(): void {
249
-		$operation = 0;
250
-		$this->eventDispatcher
251
-			->expects($this->exactly(2))
252
-			->method('dispatchTyped')
253
-			->with($this->callback(function (UserMountAddedEvent|UserMountUpdatedEvent $event) use (&$operation) {
254
-				return match(++$operation) {
255
-					1 => $event instanceof UserMountAddedEvent && $event->mountPoint->getMountPoint() === '/foo/',
256
-					2 => $event instanceof UserMountUpdatedEvent && $event->oldMountPoint->getMountId() === null && $event->newMountPoint->getMountId() === 1,
257
-					default => false,
258
-				};
259
-			}));
248
+    public function testChangeMountId(): void {
249
+        $operation = 0;
250
+        $this->eventDispatcher
251
+            ->expects($this->exactly(2))
252
+            ->method('dispatchTyped')
253
+            ->with($this->callback(function (UserMountAddedEvent|UserMountUpdatedEvent $event) use (&$operation) {
254
+                return match(++$operation) {
255
+                    1 => $event instanceof UserMountAddedEvent && $event->mountPoint->getMountPoint() === '/foo/',
256
+                    2 => $event instanceof UserMountUpdatedEvent && $event->oldMountPoint->getMountId() === null && $event->newMountPoint->getMountId() === 1,
257
+                    default => false,
258
+                };
259
+            }));
260 260
 
261
-		$user = $this->userManager->get('u1');
261
+        $user = $this->userManager->get('u1');
262 262
 
263
-		[$storage] = $this->getStorage(10);
264
-		$mount = new MountPoint($storage, '/foo/', null, null, null, null);
263
+        [$storage] = $this->getStorage(10);
264
+        $mount = new MountPoint($storage, '/foo/', null, null, null, null);
265 265
 
266
-		$this->cache->registerMounts($user, [$mount]);
266
+        $this->cache->registerMounts($user, [$mount]);
267 267
 
268
-		$this->clearCache();
268
+        $this->clearCache();
269 269
 
270
-		$mount = new MountPoint($storage, '/foo/', null, null, null, 1);
270
+        $mount = new MountPoint($storage, '/foo/', null, null, null, 1);
271 271
 
272
-		$this->cache->registerMounts($user, [$mount]);
272
+        $this->cache->registerMounts($user, [$mount]);
273 273
 
274
-		$this->clearCache();
274
+        $this->clearCache();
275 275
 
276
-		$cachedMounts = $this->cache->getMountsForUser($user);
276
+        $cachedMounts = $this->cache->getMountsForUser($user);
277 277
 
278
-		$this->assertCount(1, $cachedMounts);
279
-		$cachedMount = $cachedMounts[$this->keyForMount($mount)];
280
-		$this->assertEquals(1, $cachedMount->getMountId());
281
-	}
278
+        $this->assertCount(1, $cachedMounts);
279
+        $cachedMount = $cachedMounts[$this->keyForMount($mount)];
280
+        $this->assertEquals(1, $cachedMount->getMountId());
281
+    }
282 282
 
283
-	public function testGetMountsForUser(): void {
284
-		$user1 = $this->userManager->get('u1');
285
-		$user2 = $this->userManager->get('u2');
286
-		$user3 = $this->userManager->get('u3');
283
+    public function testGetMountsForUser(): void {
284
+        $user1 = $this->userManager->get('u1');
285
+        $user2 = $this->userManager->get('u2');
286
+        $user3 = $this->userManager->get('u3');
287 287
 
288
-		[$storage1, $id1] = $this->getStorage(1);
289
-		[$storage2, $id2] = $this->getStorage(2, 'foo/bar');
290
-		$mount1 = new MountPoint($storage1, '/foo/');
291
-		$mount2 = new MountPoint($storage2, '/bar/');
288
+        [$storage1, $id1] = $this->getStorage(1);
289
+        [$storage2, $id2] = $this->getStorage(2, 'foo/bar');
290
+        $mount1 = new MountPoint($storage1, '/foo/');
291
+        $mount2 = new MountPoint($storage2, '/bar/');
292 292
 
293
-		$this->cache->registerMounts($user1, [$mount1, $mount2]);
294
-		$this->cache->registerMounts($user2, [$mount2]);
295
-		$this->cache->registerMounts($user3, [$mount2]);
293
+        $this->cache->registerMounts($user1, [$mount1, $mount2]);
294
+        $this->cache->registerMounts($user2, [$mount2]);
295
+        $this->cache->registerMounts($user3, [$mount2]);
296 296
 
297
-		$this->clearCache();
297
+        $this->clearCache();
298 298
 
299
-		$user3->delete();
299
+        $user3->delete();
300 300
 
301
-		$cachedMounts = $this->cache->getMountsForUser($user1);
301
+        $cachedMounts = $this->cache->getMountsForUser($user1);
302 302
 
303
-		$this->assertCount(2, $cachedMounts);
304
-		$this->assertEquals('/foo/', $cachedMounts[$this->keyForMount($mount1)]->getMountPoint());
305
-		$this->assertEquals($user1->getUID(), $cachedMounts[$this->keyForMount($mount1)]->getUser()->getUID());
306
-		$this->assertEquals($id1, $cachedMounts[$this->keyForMount($mount1)]->getRootId());
307
-		$this->assertEquals(1, $cachedMounts[$this->keyForMount($mount1)]->getStorageId());
308
-		$this->assertEquals('', $cachedMounts[$this->keyForMount($mount1)]->getRootInternalPath());
309
-
310
-		$this->assertEquals('/bar/', $cachedMounts[$this->keyForMount($mount2)]->getMountPoint());
311
-		$this->assertEquals($user1->getUID(), $cachedMounts[$this->keyForMount($mount2)]->getUser()->getUID());
312
-		$this->assertEquals($id2, $cachedMounts[$this->keyForMount($mount2)]->getRootId());
313
-		$this->assertEquals(2, $cachedMounts[$this->keyForMount($mount2)]->getStorageId());
314
-		$this->assertEquals('foo/bar', $cachedMounts[$this->keyForMount($mount2)]->getRootInternalPath());
315
-
316
-		$cachedMounts = $this->cache->getMountsForUser($user3);
317
-		$this->assertEmpty($cachedMounts);
318
-	}
319
-
320
-	public function testGetMountsByStorageId(): void {
321
-		$user1 = $this->userManager->get('u1');
322
-		$user2 = $this->userManager->get('u2');
323
-
324
-		[$storage1, $id1] = $this->getStorage(1);
325
-		[$storage2, $id2] = $this->getStorage(2);
326
-		$mount1 = new MountPoint($storage1, '/foo/');
327
-		$mount2 = new MountPoint($storage2, '/bar/');
328
-
329
-		$this->cache->registerMounts($user1, [$mount1, $mount2]);
330
-		$this->cache->registerMounts($user2, [$mount2]);
331
-
332
-		$this->clearCache();
333
-
334
-		$cachedMounts = $this->cache->getMountsForStorageId(2);
335
-		$this->sortMounts($cachedMounts);
336
-
337
-		$this->assertCount(2, $cachedMounts);
338
-
339
-		$this->assertEquals('/bar/', $cachedMounts[0]->getMountPoint());
340
-		$this->assertEquals($user1->getUID(), $cachedMounts[0]->getUser()->getUID());
341
-		$this->assertEquals($id2, $cachedMounts[0]->getRootId());
342
-		$this->assertEquals(2, $cachedMounts[0]->getStorageId());
343
-
344
-		$this->assertEquals('/bar/', $cachedMounts[1]->getMountPoint());
345
-		$this->assertEquals($user2->getUID(), $cachedMounts[1]->getUser()->getUID());
346
-		$this->assertEquals($id2, $cachedMounts[1]->getRootId());
347
-		$this->assertEquals(2, $cachedMounts[1]->getStorageId());
348
-	}
349
-
350
-	public function testGetMountsByRootId(): void {
351
-		$user1 = $this->userManager->get('u1');
352
-		$user2 = $this->userManager->get('u2');
353
-
354
-		[$storage1, $id1] = $this->getStorage(1);
355
-		[$storage2, $id2] = $this->getStorage(2);
356
-		$mount1 = new MountPoint($storage1, '/foo/');
357
-		$mount2 = new MountPoint($storage2, '/bar/');
303
+        $this->assertCount(2, $cachedMounts);
304
+        $this->assertEquals('/foo/', $cachedMounts[$this->keyForMount($mount1)]->getMountPoint());
305
+        $this->assertEquals($user1->getUID(), $cachedMounts[$this->keyForMount($mount1)]->getUser()->getUID());
306
+        $this->assertEquals($id1, $cachedMounts[$this->keyForMount($mount1)]->getRootId());
307
+        $this->assertEquals(1, $cachedMounts[$this->keyForMount($mount1)]->getStorageId());
308
+        $this->assertEquals('', $cachedMounts[$this->keyForMount($mount1)]->getRootInternalPath());
309
+
310
+        $this->assertEquals('/bar/', $cachedMounts[$this->keyForMount($mount2)]->getMountPoint());
311
+        $this->assertEquals($user1->getUID(), $cachedMounts[$this->keyForMount($mount2)]->getUser()->getUID());
312
+        $this->assertEquals($id2, $cachedMounts[$this->keyForMount($mount2)]->getRootId());
313
+        $this->assertEquals(2, $cachedMounts[$this->keyForMount($mount2)]->getStorageId());
314
+        $this->assertEquals('foo/bar', $cachedMounts[$this->keyForMount($mount2)]->getRootInternalPath());
315
+
316
+        $cachedMounts = $this->cache->getMountsForUser($user3);
317
+        $this->assertEmpty($cachedMounts);
318
+    }
319
+
320
+    public function testGetMountsByStorageId(): void {
321
+        $user1 = $this->userManager->get('u1');
322
+        $user2 = $this->userManager->get('u2');
323
+
324
+        [$storage1, $id1] = $this->getStorage(1);
325
+        [$storage2, $id2] = $this->getStorage(2);
326
+        $mount1 = new MountPoint($storage1, '/foo/');
327
+        $mount2 = new MountPoint($storage2, '/bar/');
328
+
329
+        $this->cache->registerMounts($user1, [$mount1, $mount2]);
330
+        $this->cache->registerMounts($user2, [$mount2]);
331
+
332
+        $this->clearCache();
333
+
334
+        $cachedMounts = $this->cache->getMountsForStorageId(2);
335
+        $this->sortMounts($cachedMounts);
336
+
337
+        $this->assertCount(2, $cachedMounts);
338
+
339
+        $this->assertEquals('/bar/', $cachedMounts[0]->getMountPoint());
340
+        $this->assertEquals($user1->getUID(), $cachedMounts[0]->getUser()->getUID());
341
+        $this->assertEquals($id2, $cachedMounts[0]->getRootId());
342
+        $this->assertEquals(2, $cachedMounts[0]->getStorageId());
343
+
344
+        $this->assertEquals('/bar/', $cachedMounts[1]->getMountPoint());
345
+        $this->assertEquals($user2->getUID(), $cachedMounts[1]->getUser()->getUID());
346
+        $this->assertEquals($id2, $cachedMounts[1]->getRootId());
347
+        $this->assertEquals(2, $cachedMounts[1]->getStorageId());
348
+    }
349
+
350
+    public function testGetMountsByRootId(): void {
351
+        $user1 = $this->userManager->get('u1');
352
+        $user2 = $this->userManager->get('u2');
353
+
354
+        [$storage1, $id1] = $this->getStorage(1);
355
+        [$storage2, $id2] = $this->getStorage(2);
356
+        $mount1 = new MountPoint($storage1, '/foo/');
357
+        $mount2 = new MountPoint($storage2, '/bar/');
358 358
 
359
-		$this->cache->registerMounts($user1, [$mount1, $mount2]);
360
-		$this->cache->registerMounts($user2, [$mount2]);
359
+        $this->cache->registerMounts($user1, [$mount1, $mount2]);
360
+        $this->cache->registerMounts($user2, [$mount2]);
361 361
 
362
-		$this->clearCache();
363
-
364
-		$cachedMounts = $this->cache->getMountsForRootId($id2);
365
-		$this->sortMounts($cachedMounts);
366
-
367
-		$this->assertCount(2, $cachedMounts);
368
-
369
-		$this->assertEquals('/bar/', $cachedMounts[0]->getMountPoint());
370
-		$this->assertEquals($user1->getUID(), $cachedMounts[0]->getUser()->getUID());
371
-		$this->assertEquals($id2, $cachedMounts[0]->getRootId());
372
-		$this->assertEquals(2, $cachedMounts[0]->getStorageId());
373
-
374
-		$this->assertEquals('/bar/', $cachedMounts[1]->getMountPoint());
375
-		$this->assertEquals($user2->getUID(), $cachedMounts[1]->getUser()->getUID());
376
-		$this->assertEquals($id2, $cachedMounts[1]->getRootId());
377
-		$this->assertEquals(2, $cachedMounts[1]->getStorageId());
378
-	}
379
-
380
-	private function sortMounts(&$mounts) {
381
-		usort($mounts, function (ICachedMountInfo $a, ICachedMountInfo $b) {
382
-			return strcmp($a->getUser()->getUID(), $b->getUser()->getUID());
383
-		});
384
-	}
385
-
386
-	private function createCacheEntry($internalPath, $storageId, $size = 0) {
387
-		$internalPath = trim($internalPath, '/');
388
-		try {
389
-			$query = $this->connection->getQueryBuilder();
390
-			$query->insert('filecache')
391
-				->values([
392
-					'storage' => $query->createNamedParameter($storageId),
393
-					'path' => $query->createNamedParameter($internalPath),
394
-					'path_hash' => $query->createNamedParameter(md5($internalPath)),
395
-					'parent' => $query->createNamedParameter(-1, IQueryBuilder::PARAM_INT),
396
-					'name' => $query->createNamedParameter(basename($internalPath)),
397
-					'mimetype' => $query->createNamedParameter(0, IQueryBuilder::PARAM_INT),
398
-					'mimepart' => $query->createNamedParameter(0, IQueryBuilder::PARAM_INT),
399
-					'size' => $query->createNamedParameter($size),
400
-					'storage_mtime' => $query->createNamedParameter(0, IQueryBuilder::PARAM_INT),
401
-					'encrypted' => $query->createNamedParameter(0, IQueryBuilder::PARAM_INT),
402
-					'unencrypted_size' => $query->createNamedParameter(0, IQueryBuilder::PARAM_INT),
403
-					'etag' => $query->createNamedParameter(''),
404
-					'permissions' => $query->createNamedParameter(31, IQueryBuilder::PARAM_INT),
405
-				]);
406
-			$query->executeStatement();
407
-			$id = $query->getLastInsertId();
408
-			$this->fileIds[] = $id;
409
-		} catch (DbalException $e) {
410
-			if ($e->getReason() === DbalException::REASON_UNIQUE_CONSTRAINT_VIOLATION) {
411
-				$query = $this->connection->getQueryBuilder();
412
-				$query->select('fileid')
413
-					->from('filecache')
414
-					->where($query->expr()->eq('storage', $query->createNamedParameter($storageId)))
415
-					->andWhere($query->expr()->eq('path_hash', $query->createNamedParameter(md5($internalPath))));
416
-				$id = (int)$query->execute()->fetchColumn();
417
-			} else {
418
-				throw $e;
419
-			}
420
-		}
421
-		return $id;
422
-	}
362
+        $this->clearCache();
363
+
364
+        $cachedMounts = $this->cache->getMountsForRootId($id2);
365
+        $this->sortMounts($cachedMounts);
366
+
367
+        $this->assertCount(2, $cachedMounts);
368
+
369
+        $this->assertEquals('/bar/', $cachedMounts[0]->getMountPoint());
370
+        $this->assertEquals($user1->getUID(), $cachedMounts[0]->getUser()->getUID());
371
+        $this->assertEquals($id2, $cachedMounts[0]->getRootId());
372
+        $this->assertEquals(2, $cachedMounts[0]->getStorageId());
373
+
374
+        $this->assertEquals('/bar/', $cachedMounts[1]->getMountPoint());
375
+        $this->assertEquals($user2->getUID(), $cachedMounts[1]->getUser()->getUID());
376
+        $this->assertEquals($id2, $cachedMounts[1]->getRootId());
377
+        $this->assertEquals(2, $cachedMounts[1]->getStorageId());
378
+    }
379
+
380
+    private function sortMounts(&$mounts) {
381
+        usort($mounts, function (ICachedMountInfo $a, ICachedMountInfo $b) {
382
+            return strcmp($a->getUser()->getUID(), $b->getUser()->getUID());
383
+        });
384
+    }
385
+
386
+    private function createCacheEntry($internalPath, $storageId, $size = 0) {
387
+        $internalPath = trim($internalPath, '/');
388
+        try {
389
+            $query = $this->connection->getQueryBuilder();
390
+            $query->insert('filecache')
391
+                ->values([
392
+                    'storage' => $query->createNamedParameter($storageId),
393
+                    'path' => $query->createNamedParameter($internalPath),
394
+                    'path_hash' => $query->createNamedParameter(md5($internalPath)),
395
+                    'parent' => $query->createNamedParameter(-1, IQueryBuilder::PARAM_INT),
396
+                    'name' => $query->createNamedParameter(basename($internalPath)),
397
+                    'mimetype' => $query->createNamedParameter(0, IQueryBuilder::PARAM_INT),
398
+                    'mimepart' => $query->createNamedParameter(0, IQueryBuilder::PARAM_INT),
399
+                    'size' => $query->createNamedParameter($size),
400
+                    'storage_mtime' => $query->createNamedParameter(0, IQueryBuilder::PARAM_INT),
401
+                    'encrypted' => $query->createNamedParameter(0, IQueryBuilder::PARAM_INT),
402
+                    'unencrypted_size' => $query->createNamedParameter(0, IQueryBuilder::PARAM_INT),
403
+                    'etag' => $query->createNamedParameter(''),
404
+                    'permissions' => $query->createNamedParameter(31, IQueryBuilder::PARAM_INT),
405
+                ]);
406
+            $query->executeStatement();
407
+            $id = $query->getLastInsertId();
408
+            $this->fileIds[] = $id;
409
+        } catch (DbalException $e) {
410
+            if ($e->getReason() === DbalException::REASON_UNIQUE_CONSTRAINT_VIOLATION) {
411
+                $query = $this->connection->getQueryBuilder();
412
+                $query->select('fileid')
413
+                    ->from('filecache')
414
+                    ->where($query->expr()->eq('storage', $query->createNamedParameter($storageId)))
415
+                    ->andWhere($query->expr()->eq('path_hash', $query->createNamedParameter(md5($internalPath))));
416
+                $id = (int)$query->execute()->fetchColumn();
417
+            } else {
418
+                throw $e;
419
+            }
420
+        }
421
+        return $id;
422
+    }
423 423
 
424
-	public function testGetMountsForFileIdRootId(): void {
425
-		$user1 = $this->userManager->get('u1');
424
+    public function testGetMountsForFileIdRootId(): void {
425
+        $user1 = $this->userManager->get('u1');
426 426
 
427
-		[$storage1, $rootId] = $this->getStorage(2);
428
-		$mount1 = new MountPoint($storage1, '/foo/');
427
+        [$storage1, $rootId] = $this->getStorage(2);
428
+        $mount1 = new MountPoint($storage1, '/foo/');
429 429
 
430
-		$this->cache->registerMounts($user1, [$mount1]);
430
+        $this->cache->registerMounts($user1, [$mount1]);
431 431
 
432
-		$this->clearCache();
432
+        $this->clearCache();
433 433
 
434
-		$cachedMounts = $this->cache->getMountsForFileId($rootId);
434
+        $cachedMounts = $this->cache->getMountsForFileId($rootId);
435 435
 
436
-		$this->assertCount(1, $cachedMounts);
436
+        $this->assertCount(1, $cachedMounts);
437 437
 
438
-		$this->assertEquals('/foo/', $cachedMounts[0]->getMountPoint());
439
-		$this->assertEquals($user1->getUID(), $cachedMounts[0]->getUser()->getUID());
440
-		$this->assertEquals($rootId, $cachedMounts[0]->getRootId());
441
-		$this->assertEquals(2, $cachedMounts[0]->getStorageId());
442
-	}
438
+        $this->assertEquals('/foo/', $cachedMounts[0]->getMountPoint());
439
+        $this->assertEquals($user1->getUID(), $cachedMounts[0]->getUser()->getUID());
440
+        $this->assertEquals($rootId, $cachedMounts[0]->getRootId());
441
+        $this->assertEquals(2, $cachedMounts[0]->getStorageId());
442
+    }
443 443
 
444
-	public function testGetMountsForFileIdSubFolder(): void {
445
-		$user1 = $this->userManager->get('u1');
444
+    public function testGetMountsForFileIdSubFolder(): void {
445
+        $user1 = $this->userManager->get('u1');
446 446
 
447
-		$fileId = $this->createCacheEntry('/foo/bar', 2);
447
+        $fileId = $this->createCacheEntry('/foo/bar', 2);
448 448
 
449
-		[$storage1, $rootId] = $this->getStorage(2);
450
-		$mount1 = new MountPoint($storage1, '/foo/');
449
+        [$storage1, $rootId] = $this->getStorage(2);
450
+        $mount1 = new MountPoint($storage1, '/foo/');
451 451
 
452
-		$this->cache->registerMounts($user1, [$mount1]);
452
+        $this->cache->registerMounts($user1, [$mount1]);
453 453
 
454
-		$this->clearCache();
454
+        $this->clearCache();
455 455
 
456
-		$cachedMounts = $this->cache->getMountsForFileId($fileId);
457
-
458
-		$this->assertCount(1, $cachedMounts);
459
-
460
-		$this->assertEquals('/foo/', $cachedMounts[0]->getMountPoint());
461
-		$this->assertEquals($user1->getUID(), $cachedMounts[0]->getUser()->getUID());
462
-		$this->assertEquals($rootId, $cachedMounts[0]->getRootId());
463
-		$this->assertEquals(2, $cachedMounts[0]->getStorageId());
464
-		$this->assertEquals('foo/bar', $cachedMounts[0]->getInternalPath());
465
-		$this->assertEquals('/foo/foo/bar', $cachedMounts[0]->getPath());
466
-	}
467
-
468
-	public function testGetMountsForFileIdSubFolderMount(): void {
469
-		$user1 = $this->userManager->get('u1');
470
-
471
-		[$storage1, $rootId] = $this->getStorage(2);
472
-		$folderId = $this->createCacheEntry('/foo', 2);
473
-		$fileId = $this->createCacheEntry('/foo/bar', 2);
456
+        $cachedMounts = $this->cache->getMountsForFileId($fileId);
457
+
458
+        $this->assertCount(1, $cachedMounts);
459
+
460
+        $this->assertEquals('/foo/', $cachedMounts[0]->getMountPoint());
461
+        $this->assertEquals($user1->getUID(), $cachedMounts[0]->getUser()->getUID());
462
+        $this->assertEquals($rootId, $cachedMounts[0]->getRootId());
463
+        $this->assertEquals(2, $cachedMounts[0]->getStorageId());
464
+        $this->assertEquals('foo/bar', $cachedMounts[0]->getInternalPath());
465
+        $this->assertEquals('/foo/foo/bar', $cachedMounts[0]->getPath());
466
+    }
467
+
468
+    public function testGetMountsForFileIdSubFolderMount(): void {
469
+        $user1 = $this->userManager->get('u1');
470
+
471
+        [$storage1, $rootId] = $this->getStorage(2);
472
+        $folderId = $this->createCacheEntry('/foo', 2);
473
+        $fileId = $this->createCacheEntry('/foo/bar', 2);
474 474
 
475 475
 
476
-		$mount1 = $this->getMockBuilder(MountPoint::class)
477
-			->setConstructorArgs([$storage1, '/'])
478
-			->onlyMethods(['getStorageRootId'])
479
-			->getMock();
476
+        $mount1 = $this->getMockBuilder(MountPoint::class)
477
+            ->setConstructorArgs([$storage1, '/'])
478
+            ->onlyMethods(['getStorageRootId'])
479
+            ->getMock();
480 480
 
481
-		$mount1->expects($this->any())
482
-			->method('getStorageRootId')
483
-			->willReturn($folderId);
481
+        $mount1->expects($this->any())
482
+            ->method('getStorageRootId')
483
+            ->willReturn($folderId);
484 484
 
485
-		$this->cache->registerMounts($user1, [$mount1]);
485
+        $this->cache->registerMounts($user1, [$mount1]);
486 486
 
487
-		$this->clearCache();
487
+        $this->clearCache();
488 488
 
489
-		$cachedMounts = $this->cache->getMountsForFileId($fileId);
489
+        $cachedMounts = $this->cache->getMountsForFileId($fileId);
490 490
 
491
-		$this->assertCount(1, $cachedMounts);
491
+        $this->assertCount(1, $cachedMounts);
492 492
 
493
-		$this->assertEquals('/', $cachedMounts[0]->getMountPoint());
494
-		$this->assertEquals($user1->getUID(), $cachedMounts[0]->getUser()->getUID());
495
-		$this->assertEquals($folderId, $cachedMounts[0]->getRootId());
496
-		$this->assertEquals(2, $cachedMounts[0]->getStorageId());
497
-		$this->assertEquals('foo', $cachedMounts[0]->getRootInternalPath());
498
-		$this->assertEquals('bar', $cachedMounts[0]->getInternalPath());
499
-		$this->assertEquals('/bar', $cachedMounts[0]->getPath());
500
-	}
493
+        $this->assertEquals('/', $cachedMounts[0]->getMountPoint());
494
+        $this->assertEquals($user1->getUID(), $cachedMounts[0]->getUser()->getUID());
495
+        $this->assertEquals($folderId, $cachedMounts[0]->getRootId());
496
+        $this->assertEquals(2, $cachedMounts[0]->getStorageId());
497
+        $this->assertEquals('foo', $cachedMounts[0]->getRootInternalPath());
498
+        $this->assertEquals('bar', $cachedMounts[0]->getInternalPath());
499
+        $this->assertEquals('/bar', $cachedMounts[0]->getPath());
500
+    }
501 501
 
502
-	public function testGetMountsForFileIdSubFolderMountOutside(): void {
503
-		$user1 = $this->userManager->get('u1');
502
+    public function testGetMountsForFileIdSubFolderMountOutside(): void {
503
+        $user1 = $this->userManager->get('u1');
504 504
 
505
-		[$storage1, $rootId] = $this->getStorage(2);
506
-		$folderId = $this->createCacheEntry('/foo', 2);
507
-		$fileId = $this->createCacheEntry('/bar/asd', 2);
505
+        [$storage1, $rootId] = $this->getStorage(2);
506
+        $folderId = $this->createCacheEntry('/foo', 2);
507
+        $fileId = $this->createCacheEntry('/bar/asd', 2);
508 508
 
509
-		$mount1 = $this->getMockBuilder(MountPoint::class)
510
-			->setConstructorArgs([$storage1, '/foo/'])
511
-			->onlyMethods(['getStorageRootId'])
512
-			->getMock();
509
+        $mount1 = $this->getMockBuilder(MountPoint::class)
510
+            ->setConstructorArgs([$storage1, '/foo/'])
511
+            ->onlyMethods(['getStorageRootId'])
512
+            ->getMock();
513 513
 
514
-		$mount1->expects($this->any())
515
-			->method('getStorageRootId')
516
-			->willReturn($folderId);
514
+        $mount1->expects($this->any())
515
+            ->method('getStorageRootId')
516
+            ->willReturn($folderId);
517 517
 
518
-		$this->cache->registerMounts($user1, [$mount1]);
518
+        $this->cache->registerMounts($user1, [$mount1]);
519 519
 
520
-		$this->cache->registerMounts($user1, [$mount1]);
520
+        $this->cache->registerMounts($user1, [$mount1]);
521 521
 
522
-		$this->clearCache();
522
+        $this->clearCache();
523 523
 
524
-		$cachedMounts = $this->cache->getMountsForFileId($fileId);
524
+        $cachedMounts = $this->cache->getMountsForFileId($fileId);
525 525
 
526
-		$this->assertCount(0, $cachedMounts);
527
-	}
526
+        $this->assertCount(0, $cachedMounts);
527
+    }
528 528
 
529 529
 
530
-	public function testGetMountsForFileIdDeletedUser(): void {
531
-		$user1 = $this->userManager->get('u1');
530
+    public function testGetMountsForFileIdDeletedUser(): void {
531
+        $user1 = $this->userManager->get('u1');
532 532
 
533
-		[$storage1, $rootId] = $this->getStorage(2);
534
-		$rootId = $this->createCacheEntry('', 2);
535
-		$mount1 = new MountPoint($storage1, '/foo/');
536
-		$this->cache->registerMounts($user1, [$mount1]);
533
+        [$storage1, $rootId] = $this->getStorage(2);
534
+        $rootId = $this->createCacheEntry('', 2);
535
+        $mount1 = new MountPoint($storage1, '/foo/');
536
+        $this->cache->registerMounts($user1, [$mount1]);
537 537
 
538
-		$user1->delete();
539
-		$this->clearCache();
538
+        $user1->delete();
539
+        $this->clearCache();
540 540
 
541
-		$cachedMounts = $this->cache->getMountsForFileId($rootId);
542
-		$this->assertEmpty($cachedMounts);
543
-	}
541
+        $cachedMounts = $this->cache->getMountsForFileId($rootId);
542
+        $this->assertEmpty($cachedMounts);
543
+    }
544 544
 
545
-	public function testGetUsedSpaceForUsers(): void {
546
-		$user1 = $this->userManager->get('u1');
547
-		$user2 = $this->userManager->get('u2');
545
+    public function testGetUsedSpaceForUsers(): void {
546
+        $user1 = $this->userManager->get('u1');
547
+        $user2 = $this->userManager->get('u2');
548 548
 
549
-		/** @var Storage $storage1 */
550
-		[$storage1, $rootId] = $this->getStorage(2);
551
-		$folderId = $this->createCacheEntry('files', 2, 100);
552
-		$fileId = $this->createCacheEntry('files/foo', 2, 7);
553
-		$storage1->getCache()->put($folderId, ['size' => 100]);
554
-		$storage1->getCache()->update($fileId, ['size' => 70]);
549
+        /** @var Storage $storage1 */
550
+        [$storage1, $rootId] = $this->getStorage(2);
551
+        $folderId = $this->createCacheEntry('files', 2, 100);
552
+        $fileId = $this->createCacheEntry('files/foo', 2, 7);
553
+        $storage1->getCache()->put($folderId, ['size' => 100]);
554
+        $storage1->getCache()->update($fileId, ['size' => 70]);
555 555
 
556
-		$mount1 = $this->getMockBuilder(MountPoint::class)
557
-			->setConstructorArgs([$storage1, '/u1/'])
558
-			->onlyMethods(['getStorageRootId', 'getNumericStorageId'])
559
-			->getMock();
556
+        $mount1 = $this->getMockBuilder(MountPoint::class)
557
+            ->setConstructorArgs([$storage1, '/u1/'])
558
+            ->onlyMethods(['getStorageRootId', 'getNumericStorageId'])
559
+            ->getMock();
560 560
 
561
-		$mount1->expects($this->any())
562
-			->method('getStorageRootId')
563
-			->willReturn($rootId);
561
+        $mount1->expects($this->any())
562
+            ->method('getStorageRootId')
563
+            ->willReturn($rootId);
564 564
 
565
-		$mount1->expects($this->any())
566
-			->method('getNumericStorageId')
567
-			->willReturn(2);
565
+        $mount1->expects($this->any())
566
+            ->method('getNumericStorageId')
567
+            ->willReturn(2);
568 568
 
569
-		$this->cache->registerMounts($user1, [$mount1]);
569
+        $this->cache->registerMounts($user1, [$mount1]);
570 570
 
571
-		$result = $this->cache->getUsedSpaceForUsers([$user1, $user2]);
572
-		$this->assertEquals(['u1' => 100], $result);
573
-	}
571
+        $result = $this->cache->getUsedSpaceForUsers([$user1, $user2]);
572
+        $this->assertEquals(['u1' => 100], $result);
573
+    }
574 574
 
575 575
 
576
-	public function testMigrateMountProvider(): void {
577
-		$user1 = $this->userManager->get('u1');
576
+    public function testMigrateMountProvider(): void {
577
+        $user1 = $this->userManager->get('u1');
578 578
 
579
-		[$storage1, $rootId] = $this->getStorage(2);
580
-		$rootId = $this->createCacheEntry('', 2);
581
-		$mount1 = new MountPoint($storage1, '/foo/');
582
-		$this->cache->registerMounts($user1, [$mount1]);
579
+        [$storage1, $rootId] = $this->getStorage(2);
580
+        $rootId = $this->createCacheEntry('', 2);
581
+        $mount1 = new MountPoint($storage1, '/foo/');
582
+        $this->cache->registerMounts($user1, [$mount1]);
583 583
 
584
-		$this->clearCache();
584
+        $this->clearCache();
585 585
 
586
-		$cachedMounts = $this->cache->getMountsForUser($user1);
587
-		$this->assertCount(1, $cachedMounts);
588
-		$this->assertEquals('', $cachedMounts[$this->keyForMount($mount1)]->getMountProvider());
586
+        $cachedMounts = $this->cache->getMountsForUser($user1);
587
+        $this->assertCount(1, $cachedMounts);
588
+        $this->assertEquals('', $cachedMounts[$this->keyForMount($mount1)]->getMountProvider());
589 589
 
590
-		$mount1 = new MountPoint($storage1, '/foo/', null, null, null, null, 'dummy');
591
-		$this->cache->registerMounts($user1, [$mount1], ['dummy']);
590
+        $mount1 = new MountPoint($storage1, '/foo/', null, null, null, null, 'dummy');
591
+        $this->cache->registerMounts($user1, [$mount1], ['dummy']);
592 592
 
593
-		$this->clearCache();
593
+        $this->clearCache();
594 594
 
595
-		$cachedMounts = $this->cache->getMountsForUser($user1);
596
-		$this->assertCount(1, $cachedMounts);
597
-		$this->assertEquals('dummy', $cachedMounts[$this->keyForMount($mount1)]->getMountProvider());
598
-	}
595
+        $cachedMounts = $this->cache->getMountsForUser($user1);
596
+        $this->assertCount(1, $cachedMounts);
597
+        $this->assertEquals('dummy', $cachedMounts[$this->keyForMount($mount1)]->getMountProvider());
598
+    }
599 599
 }
Please login to merge, or discard this patch.