Completed
Push — stable13 ( 74618d...d0f8a4 )
by Blizzz
235:34 queued 218:16
created
lib/private/Files/Config/UserMountCache.php 1 patch
Indentation   +346 added lines, -346 removed lines patch added patch discarded remove patch
@@ -43,350 +43,350 @@
 block discarded – undo
43 43
  * Cache mounts points per user in the cache so we can easilly look them up
44 44
  */
45 45
 class UserMountCache implements IUserMountCache {
46
-	/**
47
-	 * @var IDBConnection
48
-	 */
49
-	private $connection;
50
-
51
-	/**
52
-	 * @var IUserManager
53
-	 */
54
-	private $userManager;
55
-
56
-	/**
57
-	 * Cached mount info.
58
-	 * Map of $userId to ICachedMountInfo.
59
-	 *
60
-	 * @var ICache
61
-	 **/
62
-	private $mountsForUsers;
63
-
64
-	/**
65
-	 * @var ILogger
66
-	 */
67
-	private $logger;
68
-
69
-	/**
70
-	 * @var ICache
71
-	 */
72
-	private $cacheInfoCache;
73
-
74
-	/**
75
-	 * UserMountCache constructor.
76
-	 *
77
-	 * @param IDBConnection $connection
78
-	 * @param IUserManager $userManager
79
-	 * @param ILogger $logger
80
-	 */
81
-	public function __construct(IDBConnection $connection, IUserManager $userManager, ILogger $logger) {
82
-		$this->connection = $connection;
83
-		$this->userManager = $userManager;
84
-		$this->logger = $logger;
85
-		$this->cacheInfoCache = new CappedMemoryCache();
86
-		$this->mountsForUsers = new CappedMemoryCache();
87
-	}
88
-
89
-	public function registerMounts(IUser $user, array $mounts) {
90
-		// filter out non-proper storages coming from unit tests
91
-		$mounts = array_filter($mounts, function (IMountPoint $mount) {
92
-			return $mount instanceof SharedMount || $mount->getStorage() && $mount->getStorage()->getCache();
93
-		});
94
-		/** @var ICachedMountInfo[] $newMounts */
95
-		$newMounts = array_map(function (IMountPoint $mount) use ($user) {
96
-			// filter out any storages which aren't scanned yet since we aren't interested in files from those storages (yet)
97
-			if ($mount->getStorageRootId() === -1) {
98
-				return null;
99
-			} else {
100
-				return new LazyStorageMountInfo($user, $mount);
101
-			}
102
-		}, $mounts);
103
-		$newMounts = array_values(array_filter($newMounts));
104
-
105
-		$cachedMounts = $this->getMountsForUser($user);
106
-		$mountDiff = function (ICachedMountInfo $mount1, ICachedMountInfo $mount2) {
107
-			// since we are only looking for mounts for a specific user comparing on root id is enough
108
-			return $mount1->getRootId() - $mount2->getRootId();
109
-		};
110
-
111
-		/** @var ICachedMountInfo[] $addedMounts */
112
-		$addedMounts = array_udiff($newMounts, $cachedMounts, $mountDiff);
113
-		/** @var ICachedMountInfo[] $removedMounts */
114
-		$removedMounts = array_udiff($cachedMounts, $newMounts, $mountDiff);
115
-
116
-		$changedMounts = $this->findChangedMounts($newMounts, $cachedMounts);
117
-
118
-		foreach ($addedMounts as $mount) {
119
-			$this->addToCache($mount);
120
-			$this->mountsForUsers[$user->getUID()][] = $mount;
121
-		}
122
-		foreach ($removedMounts as $mount) {
123
-			$this->removeFromCache($mount);
124
-			$index = array_search($mount, $this->mountsForUsers[$user->getUID()]);
125
-			unset($this->mountsForUsers[$user->getUID()][$index]);
126
-		}
127
-		foreach ($changedMounts as $mount) {
128
-			$this->updateCachedMount($mount);
129
-		}
130
-	}
131
-
132
-	/**
133
-	 * @param ICachedMountInfo[] $newMounts
134
-	 * @param ICachedMountInfo[] $cachedMounts
135
-	 * @return ICachedMountInfo[]
136
-	 */
137
-	private function findChangedMounts(array $newMounts, array $cachedMounts) {
138
-		$changed = [];
139
-		foreach ($newMounts as $newMount) {
140
-			foreach ($cachedMounts as $cachedMount) {
141
-				if (
142
-					$newMount->getRootId() === $cachedMount->getRootId() &&
143
-					(
144
-						$newMount->getMountPoint() !== $cachedMount->getMountPoint() ||
145
-						$newMount->getStorageId() !== $cachedMount->getStorageId() ||
146
-						$newMount->getMountId() !== $cachedMount->getMountId()
147
-					)
148
-				) {
149
-					$changed[] = $newMount;
150
-				}
151
-			}
152
-		}
153
-		return $changed;
154
-	}
155
-
156
-	private function addToCache(ICachedMountInfo $mount) {
157
-		if ($mount->getStorageId() !== -1) {
158
-			$this->connection->insertIfNotExist('*PREFIX*mounts', [
159
-				'storage_id' => $mount->getStorageId(),
160
-				'root_id' => $mount->getRootId(),
161
-				'user_id' => $mount->getUser()->getUID(),
162
-				'mount_point' => $mount->getMountPoint(),
163
-				'mount_id' => $mount->getMountId()
164
-			], ['root_id', 'user_id']);
165
-		} else {
166
-			// in some cases this is legitimate, like orphaned shares
167
-			$this->logger->debug('Could not get storage info for mount at ' . $mount->getMountPoint());
168
-		}
169
-	}
170
-
171
-	private function updateCachedMount(ICachedMountInfo $mount) {
172
-		$builder = $this->connection->getQueryBuilder();
173
-
174
-		$query = $builder->update('mounts')
175
-			->set('storage_id', $builder->createNamedParameter($mount->getStorageId()))
176
-			->set('mount_point', $builder->createNamedParameter($mount->getMountPoint()))
177
-			->set('mount_id', $builder->createNamedParameter($mount->getMountId(), IQueryBuilder::PARAM_INT))
178
-			->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID())))
179
-			->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT)));
180
-
181
-		$query->execute();
182
-	}
183
-
184
-	private function removeFromCache(ICachedMountInfo $mount) {
185
-		$builder = $this->connection->getQueryBuilder();
186
-
187
-		$query = $builder->delete('mounts')
188
-			->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID())))
189
-			->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT)));
190
-		$query->execute();
191
-	}
192
-
193
-	private function dbRowToMountInfo(array $row) {
194
-		$user = $this->userManager->get($row['user_id']);
195
-		if (is_null($user)) {
196
-			return null;
197
-		}
198
-		$mount_id = $row['mount_id'];
199
-		if (!is_null($mount_id)) {
200
-			$mount_id = (int) $mount_id;
201
-		}
202
-		return new CachedMountInfo($user, (int)$row['storage_id'], (int)$row['root_id'], $row['mount_point'], $mount_id, isset($row['path']) ? $row['path'] : '');
203
-	}
204
-
205
-	/**
206
-	 * @param IUser $user
207
-	 * @return ICachedMountInfo[]
208
-	 */
209
-	public function getMountsForUser(IUser $user) {
210
-		if (!isset($this->mountsForUsers[$user->getUID()])) {
211
-			$builder = $this->connection->getQueryBuilder();
212
-			$query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path')
213
-				->from('mounts', 'm')
214
-				->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
215
-				->where($builder->expr()->eq('user_id', $builder->createPositionalParameter($user->getUID())));
216
-
217
-			$rows = $query->execute()->fetchAll();
218
-
219
-			$this->mountsForUsers[$user->getUID()] = array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
220
-		}
221
-		return $this->mountsForUsers[$user->getUID()];
222
-	}
223
-
224
-	/**
225
-	 * @param int $numericStorageId
226
-	 * @param string|null $user limit the results to a single user
227
-	 * @return CachedMountInfo[]
228
-	 */
229
-	public function getMountsForStorageId($numericStorageId, $user = null) {
230
-		$builder = $this->connection->getQueryBuilder();
231
-		$query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path')
232
-			->from('mounts', 'm')
233
-			->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
234
-			->where($builder->expr()->eq('storage_id', $builder->createPositionalParameter($numericStorageId, IQueryBuilder::PARAM_INT)));
235
-
236
-		if ($user) {
237
-			$query->andWhere($builder->expr()->eq('user_id', $builder->createPositionalParameter($user)));
238
-		}
239
-
240
-		$rows = $query->execute()->fetchAll();
241
-
242
-		return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
243
-	}
244
-
245
-	/**
246
-	 * @param int $rootFileId
247
-	 * @return CachedMountInfo[]
248
-	 */
249
-	public function getMountsForRootId($rootFileId) {
250
-		$builder = $this->connection->getQueryBuilder();
251
-		$query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path')
252
-			->from('mounts', 'm')
253
-			->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
254
-			->where($builder->expr()->eq('root_id', $builder->createPositionalParameter($rootFileId, IQueryBuilder::PARAM_INT)));
255
-
256
-		$rows = $query->execute()->fetchAll();
257
-
258
-		return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
259
-	}
260
-
261
-	/**
262
-	 * @param $fileId
263
-	 * @return array
264
-	 * @throws \OCP\Files\NotFoundException
265
-	 */
266
-	private function getCacheInfoFromFileId($fileId) {
267
-		if (!isset($this->cacheInfoCache[$fileId])) {
268
-			$builder = $this->connection->getQueryBuilder();
269
-			$query = $builder->select('storage', 'path', 'mimetype')
270
-				->from('filecache')
271
-				->where($builder->expr()->eq('fileid', $builder->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)));
272
-
273
-			$row = $query->execute()->fetch();
274
-			if (is_array($row)) {
275
-				$this->cacheInfoCache[$fileId] = [
276
-					(int)$row['storage'],
277
-					$row['path'],
278
-					(int)$row['mimetype']
279
-				];
280
-			} else {
281
-				throw new NotFoundException('File with id "' . $fileId . '" not found');
282
-			}
283
-		}
284
-		return $this->cacheInfoCache[$fileId];
285
-	}
286
-
287
-	/**
288
-	 * @param int $fileId
289
-	 * @param string|null $user optionally restrict the results to a single user
290
-	 * @return ICachedMountFileInfo[]
291
-	 * @since 9.0.0
292
-	 */
293
-	public function getMountsForFileId($fileId, $user = null) {
294
-		try {
295
-			list($storageId, $internalPath) = $this->getCacheInfoFromFileId($fileId);
296
-		} catch (NotFoundException $e) {
297
-			return [];
298
-		}
299
-		$mountsForStorage = $this->getMountsForStorageId($storageId, $user);
300
-
301
-		// filter mounts that are from the same storage but a different directory
302
-		$filteredMounts = array_filter($mountsForStorage, function (ICachedMountInfo $mount) use ($internalPath, $fileId) {
303
-			if ($fileId === $mount->getRootId()) {
304
-				return true;
305
-			}
306
-			$internalMountPath = $mount->getRootInternalPath();
307
-
308
-			return $internalMountPath === '' || substr($internalPath, 0, strlen($internalMountPath) + 1) === $internalMountPath . '/';
309
-		});
310
-
311
-		return array_map(function (ICachedMountInfo $mount) use ($internalPath) {
312
-			return new CachedMountFileInfo(
313
-				$mount->getUser(),
314
-				$mount->getStorageId(),
315
-				$mount->getRootId(),
316
-				$mount->getMountPoint(),
317
-				$mount->getMountId(),
318
-				$mount->getRootInternalPath(),
319
-				$internalPath
320
-			);
321
-		}, $filteredMounts);
322
-	}
323
-
324
-	/**
325
-	 * Remove all cached mounts for a user
326
-	 *
327
-	 * @param IUser $user
328
-	 */
329
-	public function removeUserMounts(IUser $user) {
330
-		$builder = $this->connection->getQueryBuilder();
331
-
332
-		$query = $builder->delete('mounts')
333
-			->where($builder->expr()->eq('user_id', $builder->createNamedParameter($user->getUID())));
334
-		$query->execute();
335
-	}
336
-
337
-	public function removeUserStorageMount($storageId, $userId) {
338
-		$builder = $this->connection->getQueryBuilder();
339
-
340
-		$query = $builder->delete('mounts')
341
-			->where($builder->expr()->eq('user_id', $builder->createNamedParameter($userId)))
342
-			->andWhere($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)));
343
-		$query->execute();
344
-	}
345
-
346
-	public function remoteStorageMounts($storageId) {
347
-		$builder = $this->connection->getQueryBuilder();
348
-
349
-		$query = $builder->delete('mounts')
350
-			->where($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)));
351
-		$query->execute();
352
-	}
353
-
354
-	/**
355
-	 * @param array $users
356
-	 * @return array
357
-	 * @suppress SqlInjectionChecker
358
-	 */
359
-	public function getUsedSpaceForUsers(array $users) {
360
-		$builder = $this->connection->getQueryBuilder();
361
-
362
-		$slash = $builder->createNamedParameter('/');
363
-
364
-		$mountPoint = $builder->func()->concat(
365
-			$builder->func()->concat($slash, 'user_id'),
366
-			$slash
367
-		);
368
-
369
-		$userIds = array_map(function (IUser $user) {
370
-			return $user->getUID();
371
-		}, $users);
372
-
373
-		$query = $builder->select('m.user_id', 'f.size')
374
-			->from('mounts', 'm')
375
-			->innerJoin('m', 'filecache', 'f',
376
-				$builder->expr()->andX(
377
-					$builder->expr()->eq('m.storage_id', 'f.storage'),
378
-					$builder->expr()->eq('f.path_hash', $builder->createNamedParameter(md5('files')))
379
-				))
380
-			->where($builder->expr()->eq('m.mount_point', $mountPoint))
381
-			->andWhere($builder->expr()->in('m.user_id', $builder->createNamedParameter($userIds, IQueryBuilder::PARAM_STR_ARRAY)));
382
-
383
-		$result = $query->execute();
384
-
385
-		$results = [];
386
-		while ($row = $result->fetch()) {
387
-			$results[$row['user_id']] = $row['size'];
388
-		}
389
-		$result->closeCursor();
390
-		return $results;
391
-	}
46
+    /**
47
+     * @var IDBConnection
48
+     */
49
+    private $connection;
50
+
51
+    /**
52
+     * @var IUserManager
53
+     */
54
+    private $userManager;
55
+
56
+    /**
57
+     * Cached mount info.
58
+     * Map of $userId to ICachedMountInfo.
59
+     *
60
+     * @var ICache
61
+     **/
62
+    private $mountsForUsers;
63
+
64
+    /**
65
+     * @var ILogger
66
+     */
67
+    private $logger;
68
+
69
+    /**
70
+     * @var ICache
71
+     */
72
+    private $cacheInfoCache;
73
+
74
+    /**
75
+     * UserMountCache constructor.
76
+     *
77
+     * @param IDBConnection $connection
78
+     * @param IUserManager $userManager
79
+     * @param ILogger $logger
80
+     */
81
+    public function __construct(IDBConnection $connection, IUserManager $userManager, ILogger $logger) {
82
+        $this->connection = $connection;
83
+        $this->userManager = $userManager;
84
+        $this->logger = $logger;
85
+        $this->cacheInfoCache = new CappedMemoryCache();
86
+        $this->mountsForUsers = new CappedMemoryCache();
87
+    }
88
+
89
+    public function registerMounts(IUser $user, array $mounts) {
90
+        // filter out non-proper storages coming from unit tests
91
+        $mounts = array_filter($mounts, function (IMountPoint $mount) {
92
+            return $mount instanceof SharedMount || $mount->getStorage() && $mount->getStorage()->getCache();
93
+        });
94
+        /** @var ICachedMountInfo[] $newMounts */
95
+        $newMounts = array_map(function (IMountPoint $mount) use ($user) {
96
+            // filter out any storages which aren't scanned yet since we aren't interested in files from those storages (yet)
97
+            if ($mount->getStorageRootId() === -1) {
98
+                return null;
99
+            } else {
100
+                return new LazyStorageMountInfo($user, $mount);
101
+            }
102
+        }, $mounts);
103
+        $newMounts = array_values(array_filter($newMounts));
104
+
105
+        $cachedMounts = $this->getMountsForUser($user);
106
+        $mountDiff = function (ICachedMountInfo $mount1, ICachedMountInfo $mount2) {
107
+            // since we are only looking for mounts for a specific user comparing on root id is enough
108
+            return $mount1->getRootId() - $mount2->getRootId();
109
+        };
110
+
111
+        /** @var ICachedMountInfo[] $addedMounts */
112
+        $addedMounts = array_udiff($newMounts, $cachedMounts, $mountDiff);
113
+        /** @var ICachedMountInfo[] $removedMounts */
114
+        $removedMounts = array_udiff($cachedMounts, $newMounts, $mountDiff);
115
+
116
+        $changedMounts = $this->findChangedMounts($newMounts, $cachedMounts);
117
+
118
+        foreach ($addedMounts as $mount) {
119
+            $this->addToCache($mount);
120
+            $this->mountsForUsers[$user->getUID()][] = $mount;
121
+        }
122
+        foreach ($removedMounts as $mount) {
123
+            $this->removeFromCache($mount);
124
+            $index = array_search($mount, $this->mountsForUsers[$user->getUID()]);
125
+            unset($this->mountsForUsers[$user->getUID()][$index]);
126
+        }
127
+        foreach ($changedMounts as $mount) {
128
+            $this->updateCachedMount($mount);
129
+        }
130
+    }
131
+
132
+    /**
133
+     * @param ICachedMountInfo[] $newMounts
134
+     * @param ICachedMountInfo[] $cachedMounts
135
+     * @return ICachedMountInfo[]
136
+     */
137
+    private function findChangedMounts(array $newMounts, array $cachedMounts) {
138
+        $changed = [];
139
+        foreach ($newMounts as $newMount) {
140
+            foreach ($cachedMounts as $cachedMount) {
141
+                if (
142
+                    $newMount->getRootId() === $cachedMount->getRootId() &&
143
+                    (
144
+                        $newMount->getMountPoint() !== $cachedMount->getMountPoint() ||
145
+                        $newMount->getStorageId() !== $cachedMount->getStorageId() ||
146
+                        $newMount->getMountId() !== $cachedMount->getMountId()
147
+                    )
148
+                ) {
149
+                    $changed[] = $newMount;
150
+                }
151
+            }
152
+        }
153
+        return $changed;
154
+    }
155
+
156
+    private function addToCache(ICachedMountInfo $mount) {
157
+        if ($mount->getStorageId() !== -1) {
158
+            $this->connection->insertIfNotExist('*PREFIX*mounts', [
159
+                'storage_id' => $mount->getStorageId(),
160
+                'root_id' => $mount->getRootId(),
161
+                'user_id' => $mount->getUser()->getUID(),
162
+                'mount_point' => $mount->getMountPoint(),
163
+                'mount_id' => $mount->getMountId()
164
+            ], ['root_id', 'user_id']);
165
+        } else {
166
+            // in some cases this is legitimate, like orphaned shares
167
+            $this->logger->debug('Could not get storage info for mount at ' . $mount->getMountPoint());
168
+        }
169
+    }
170
+
171
+    private function updateCachedMount(ICachedMountInfo $mount) {
172
+        $builder = $this->connection->getQueryBuilder();
173
+
174
+        $query = $builder->update('mounts')
175
+            ->set('storage_id', $builder->createNamedParameter($mount->getStorageId()))
176
+            ->set('mount_point', $builder->createNamedParameter($mount->getMountPoint()))
177
+            ->set('mount_id', $builder->createNamedParameter($mount->getMountId(), IQueryBuilder::PARAM_INT))
178
+            ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID())))
179
+            ->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT)));
180
+
181
+        $query->execute();
182
+    }
183
+
184
+    private function removeFromCache(ICachedMountInfo $mount) {
185
+        $builder = $this->connection->getQueryBuilder();
186
+
187
+        $query = $builder->delete('mounts')
188
+            ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($mount->getUser()->getUID())))
189
+            ->andWhere($builder->expr()->eq('root_id', $builder->createNamedParameter($mount->getRootId(), IQueryBuilder::PARAM_INT)));
190
+        $query->execute();
191
+    }
192
+
193
+    private function dbRowToMountInfo(array $row) {
194
+        $user = $this->userManager->get($row['user_id']);
195
+        if (is_null($user)) {
196
+            return null;
197
+        }
198
+        $mount_id = $row['mount_id'];
199
+        if (!is_null($mount_id)) {
200
+            $mount_id = (int) $mount_id;
201
+        }
202
+        return new CachedMountInfo($user, (int)$row['storage_id'], (int)$row['root_id'], $row['mount_point'], $mount_id, isset($row['path']) ? $row['path'] : '');
203
+    }
204
+
205
+    /**
206
+     * @param IUser $user
207
+     * @return ICachedMountInfo[]
208
+     */
209
+    public function getMountsForUser(IUser $user) {
210
+        if (!isset($this->mountsForUsers[$user->getUID()])) {
211
+            $builder = $this->connection->getQueryBuilder();
212
+            $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path')
213
+                ->from('mounts', 'm')
214
+                ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
215
+                ->where($builder->expr()->eq('user_id', $builder->createPositionalParameter($user->getUID())));
216
+
217
+            $rows = $query->execute()->fetchAll();
218
+
219
+            $this->mountsForUsers[$user->getUID()] = array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
220
+        }
221
+        return $this->mountsForUsers[$user->getUID()];
222
+    }
223
+
224
+    /**
225
+     * @param int $numericStorageId
226
+     * @param string|null $user limit the results to a single user
227
+     * @return CachedMountInfo[]
228
+     */
229
+    public function getMountsForStorageId($numericStorageId, $user = null) {
230
+        $builder = $this->connection->getQueryBuilder();
231
+        $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path')
232
+            ->from('mounts', 'm')
233
+            ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
234
+            ->where($builder->expr()->eq('storage_id', $builder->createPositionalParameter($numericStorageId, IQueryBuilder::PARAM_INT)));
235
+
236
+        if ($user) {
237
+            $query->andWhere($builder->expr()->eq('user_id', $builder->createPositionalParameter($user)));
238
+        }
239
+
240
+        $rows = $query->execute()->fetchAll();
241
+
242
+        return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
243
+    }
244
+
245
+    /**
246
+     * @param int $rootFileId
247
+     * @return CachedMountInfo[]
248
+     */
249
+    public function getMountsForRootId($rootFileId) {
250
+        $builder = $this->connection->getQueryBuilder();
251
+        $query = $builder->select('storage_id', 'root_id', 'user_id', 'mount_point', 'mount_id', 'f.path')
252
+            ->from('mounts', 'm')
253
+            ->innerJoin('m', 'filecache', 'f', $builder->expr()->eq('m.root_id', 'f.fileid'))
254
+            ->where($builder->expr()->eq('root_id', $builder->createPositionalParameter($rootFileId, IQueryBuilder::PARAM_INT)));
255
+
256
+        $rows = $query->execute()->fetchAll();
257
+
258
+        return array_filter(array_map([$this, 'dbRowToMountInfo'], $rows));
259
+    }
260
+
261
+    /**
262
+     * @param $fileId
263
+     * @return array
264
+     * @throws \OCP\Files\NotFoundException
265
+     */
266
+    private function getCacheInfoFromFileId($fileId) {
267
+        if (!isset($this->cacheInfoCache[$fileId])) {
268
+            $builder = $this->connection->getQueryBuilder();
269
+            $query = $builder->select('storage', 'path', 'mimetype')
270
+                ->from('filecache')
271
+                ->where($builder->expr()->eq('fileid', $builder->createNamedParameter($fileId, IQueryBuilder::PARAM_INT)));
272
+
273
+            $row = $query->execute()->fetch();
274
+            if (is_array($row)) {
275
+                $this->cacheInfoCache[$fileId] = [
276
+                    (int)$row['storage'],
277
+                    $row['path'],
278
+                    (int)$row['mimetype']
279
+                ];
280
+            } else {
281
+                throw new NotFoundException('File with id "' . $fileId . '" not found');
282
+            }
283
+        }
284
+        return $this->cacheInfoCache[$fileId];
285
+    }
286
+
287
+    /**
288
+     * @param int $fileId
289
+     * @param string|null $user optionally restrict the results to a single user
290
+     * @return ICachedMountFileInfo[]
291
+     * @since 9.0.0
292
+     */
293
+    public function getMountsForFileId($fileId, $user = null) {
294
+        try {
295
+            list($storageId, $internalPath) = $this->getCacheInfoFromFileId($fileId);
296
+        } catch (NotFoundException $e) {
297
+            return [];
298
+        }
299
+        $mountsForStorage = $this->getMountsForStorageId($storageId, $user);
300
+
301
+        // filter mounts that are from the same storage but a different directory
302
+        $filteredMounts = array_filter($mountsForStorage, function (ICachedMountInfo $mount) use ($internalPath, $fileId) {
303
+            if ($fileId === $mount->getRootId()) {
304
+                return true;
305
+            }
306
+            $internalMountPath = $mount->getRootInternalPath();
307
+
308
+            return $internalMountPath === '' || substr($internalPath, 0, strlen($internalMountPath) + 1) === $internalMountPath . '/';
309
+        });
310
+
311
+        return array_map(function (ICachedMountInfo $mount) use ($internalPath) {
312
+            return new CachedMountFileInfo(
313
+                $mount->getUser(),
314
+                $mount->getStorageId(),
315
+                $mount->getRootId(),
316
+                $mount->getMountPoint(),
317
+                $mount->getMountId(),
318
+                $mount->getRootInternalPath(),
319
+                $internalPath
320
+            );
321
+        }, $filteredMounts);
322
+    }
323
+
324
+    /**
325
+     * Remove all cached mounts for a user
326
+     *
327
+     * @param IUser $user
328
+     */
329
+    public function removeUserMounts(IUser $user) {
330
+        $builder = $this->connection->getQueryBuilder();
331
+
332
+        $query = $builder->delete('mounts')
333
+            ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($user->getUID())));
334
+        $query->execute();
335
+    }
336
+
337
+    public function removeUserStorageMount($storageId, $userId) {
338
+        $builder = $this->connection->getQueryBuilder();
339
+
340
+        $query = $builder->delete('mounts')
341
+            ->where($builder->expr()->eq('user_id', $builder->createNamedParameter($userId)))
342
+            ->andWhere($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)));
343
+        $query->execute();
344
+    }
345
+
346
+    public function remoteStorageMounts($storageId) {
347
+        $builder = $this->connection->getQueryBuilder();
348
+
349
+        $query = $builder->delete('mounts')
350
+            ->where($builder->expr()->eq('storage_id', $builder->createNamedParameter($storageId, IQueryBuilder::PARAM_INT)));
351
+        $query->execute();
352
+    }
353
+
354
+    /**
355
+     * @param array $users
356
+     * @return array
357
+     * @suppress SqlInjectionChecker
358
+     */
359
+    public function getUsedSpaceForUsers(array $users) {
360
+        $builder = $this->connection->getQueryBuilder();
361
+
362
+        $slash = $builder->createNamedParameter('/');
363
+
364
+        $mountPoint = $builder->func()->concat(
365
+            $builder->func()->concat($slash, 'user_id'),
366
+            $slash
367
+        );
368
+
369
+        $userIds = array_map(function (IUser $user) {
370
+            return $user->getUID();
371
+        }, $users);
372
+
373
+        $query = $builder->select('m.user_id', 'f.size')
374
+            ->from('mounts', 'm')
375
+            ->innerJoin('m', 'filecache', 'f',
376
+                $builder->expr()->andX(
377
+                    $builder->expr()->eq('m.storage_id', 'f.storage'),
378
+                    $builder->expr()->eq('f.path_hash', $builder->createNamedParameter(md5('files')))
379
+                ))
380
+            ->where($builder->expr()->eq('m.mount_point', $mountPoint))
381
+            ->andWhere($builder->expr()->in('m.user_id', $builder->createNamedParameter($userIds, IQueryBuilder::PARAM_STR_ARRAY)));
382
+
383
+        $result = $query->execute();
384
+
385
+        $results = [];
386
+        while ($row = $result->fetch()) {
387
+            $results[$row['user_id']] = $row['size'];
388
+        }
389
+        $result->closeCursor();
390
+        return $results;
391
+    }
392 392
 }
Please login to merge, or discard this patch.