Skip to content

Commit fa28782

Browse files
authored
Merge pull request #26936 from nextcloud/external-storage-delete-clean
better cleanup of filecache when deleting an external storage
2 parents fd284f4 + ed2396b commit fa28782

File tree

5 files changed

+77
-48
lines changed

5 files changed

+77
-48
lines changed

apps/files_external/lib/Service/StoragesService.php

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -479,44 +479,7 @@ public function removeStorage($id) {
479479
$this->triggerHooks($deletedStorage, Filesystem::signal_delete_mount);
480480

481481
// delete oc_storages entries and oc_filecache
482-
try {
483-
$rustyStorageId = $this->getRustyStorageIdFromConfig($deletedStorage);
484-
\OC\Files\Cache\Storage::remove($rustyStorageId);
485-
} catch (\Exception $e) {
486-
// can happen either for invalid configs where the storage could not
487-
// be instantiated or whenever $user vars where used, in which case
488-
// the storage id could not be computed
489-
\OC::$server->getLogger()->logException($e, [
490-
'level' => ILogger::ERROR,
491-
'app' => 'files_external',
492-
]);
493-
}
494-
}
495-
496-
/**
497-
* Returns the rusty storage id from oc_storages from the given storage config.
498-
*
499-
* @param StorageConfig $storageConfig
500-
* @return string rusty storage id
501-
*/
502-
private function getRustyStorageIdFromConfig(StorageConfig $storageConfig) {
503-
// if any of the storage options contains $user, it is not possible
504-
// to compute the possible storage id as we don't know which users
505-
// mounted it already (and we certainly don't want to iterate over ALL users)
506-
foreach ($storageConfig->getBackendOptions() as $value) {
507-
if (strpos($value, '$user') !== false) {
508-
throw new \Exception('Cannot compute storage id for deletion due to $user vars in the configuration');
509-
}
510-
}
511-
512-
// note: similar to ConfigAdapter->prepateStorageConfig()
513-
$storageConfig->getAuthMechanism()->manipulateStorageConfig($storageConfig);
514-
$storageConfig->getBackend()->manipulateStorageConfig($storageConfig);
515-
516-
$class = $storageConfig->getBackend()->getStorageClass();
517-
$storageImpl = new $class($storageConfig->getBackendOptions());
518-
519-
return $storageImpl->getId();
482+
\OC\Files\Cache\Storage::cleanByMountId($id);
520483
}
521484

522485
/**

apps/files_external/tests/Service/StoragesServiceTest.php

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,11 @@
4040
use OCA\Files_External\Service\DBConfigService;
4141
use OCA\Files_External\Service\StoragesService;
4242
use OCP\AppFramework\IAppContainer;
43+
use OCP\Files\Cache\ICache;
4344
use OCP\Files\Config\IUserMountCache;
45+
use OCP\Files\Mount\IMountPoint;
46+
use OCP\Files\Storage\IStorage;
47+
use OCP\IUser;
4448

4549
class CleaningDBConfig extends DBConfigService {
4650
private $mountIds = [];
@@ -279,27 +283,24 @@ public function deleteStorageDataProvider() {
279283
'password' => 'testPassword',
280284
'root' => 'someroot',
281285
],
282-
'webdav::[email protected]//someroot/',
283-
0
286+
'webdav::[email protected]//someroot/'
284287
],
285-
// special case with $user vars, cannot auto-remove the oc_storages entry
286288
[
287289
[
288290
'host' => 'example.com',
289291
'user' => '$user',
290292
'password' => 'testPassword',
291293
'root' => 'someroot',
292294
],
293-
'webdav::[email protected]//someroot/',
294-
1
295+
'webdav::[email protected]//someroot/'
295296
],
296297
];
297298
}
298299

299300
/**
300301
* @dataProvider deleteStorageDataProvider
301302
*/
302-
public function testDeleteStorage($backendOptions, $rustyStorageId, $expectedCountAfterDeletion) {
303+
public function testDeleteStorage($backendOptions, $rustyStorageId) {
303304
$backend = $this->backendService->getBackend('identifier:\OCA\Files_External\Lib\Backend\DAV');
304305
$authMechanism = $this->backendService->getAuthMechanism('identifier:\Auth\Mechanism');
305306
$storage = new StorageConfig(255);
@@ -315,6 +316,31 @@ public function testDeleteStorage($backendOptions, $rustyStorageId, $expectedCou
315316
// access, which isn't possible within this test
316317
$storageCache = new \OC\Files\Cache\Storage($rustyStorageId);
317318

319+
/** @var IUserMountCache $mountCache */
320+
$mountCache = \OC::$server->get(IUserMountCache::class);
321+
$mountCache->clear();
322+
$user = $this->createMock(IUser::class);
323+
$user->method('getUID')->willReturn('test');
324+
$cache = $this->createMock(ICache::class);
325+
$storage = $this->createMock(IStorage::class);
326+
$storage->method('getCache')->willReturn($cache);
327+
$mount = $this->createMock(IMountPoint::class);
328+
$mount->method('getStorage')
329+
->willReturn($storage);
330+
$mount->method('getStorageId')
331+
->willReturn($rustyStorageId);
332+
$mount->method('getNumericStorageId')
333+
->willReturn($storageCache->getNumericId());
334+
$mount->method('getStorageRootId')
335+
->willReturn(1);
336+
$mount->method('getMountPoint')
337+
->willReturn('dummy');
338+
$mount->method('getMountId')
339+
->willReturn($id);
340+
$mountCache->registerMounts($user, [
341+
$mount
342+
]);
343+
318344
// get numeric id for later check
319345
$numericId = $storageCache->getNumericId();
320346

@@ -338,7 +364,7 @@ public function testDeleteStorage($backendOptions, $rustyStorageId, $expectedCou
338364
$result = $storageCheckQuery->execute();
339365
$storages = $result->fetchAll();
340366
$result->closeCursor();
341-
$this->assertCount($expectedCountAfterDeletion, $storages, "expected $expectedCountAfterDeletion storages, got " . json_encode($storages));
367+
$this->assertCount(0, $storages, "expected 0 storages, got " . json_encode($storages));
342368
}
343369

344370
protected function actualDeletedUnexistingStorageTest() {

apps/files_external/tests/Service/UserGlobalStoragesServiceTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ public function testNonExistingStorage() {
204204
/**
205205
* @dataProvider deleteStorageDataProvider
206206
*/
207-
public function testDeleteStorage($backendOptions, $rustyStorageId, $expectedCountAfterDeletion) {
207+
public function testDeleteStorage($backendOptions, $rustyStorageId) {
208208
$this->expectException(\DomainException::class);
209209

210210
$backend = $this->backendService->getBackend('identifier:\OCA\Files_External\Lib\Backend\SMB');

apps/files_external/tests/Service/UserStoragesServiceTest.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,8 @@ public function testUpdateStorage() {
150150
/**
151151
* @dataProvider deleteStorageDataProvider
152152
*/
153-
public function testDeleteStorage($backendOptions, $rustyStorageId, $expectedCountAfterDeletion) {
154-
parent::testDeleteStorage($backendOptions, $rustyStorageId, $expectedCountAfterDeletion);
153+
public function testDeleteStorage($backendOptions, $rustyStorageId) {
154+
parent::testDeleteStorage($backendOptions, $rustyStorageId);
155155

156156
// hook called once for user (first one was during test creation)
157157
$this->assertHookCall(

lib/private/Files/Cache/Storage.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
namespace OC\Files\Cache;
3131

32+
use OCP\DB\QueryBuilder\IQueryBuilder;
3233
use OCP\Files\Storage\IStorage;
3334
use Psr\Log\LoggerInterface;
3435

@@ -219,4 +220,43 @@ public static function remove($storageId) {
219220
$query->execute();
220221
}
221222
}
223+
224+
/**
225+
* remove the entry for the storage by the mount id
226+
*
227+
* @param int $mountId
228+
*/
229+
public static function cleanByMountId(int $mountId) {
230+
$db = \OC::$server->getDatabaseConnection();
231+
232+
try {
233+
$db->beginTransaction();
234+
235+
$query = $db->getQueryBuilder();
236+
$query->select('storage_id')
237+
->from('mounts')
238+
->where($query->expr()->eq('mount_id', $query->createNamedParameter($mountId, IQueryBuilder::PARAM_INT)));
239+
$storageIds = $query->executeQuery()->fetchAll(\PDO::FETCH_COLUMN);
240+
241+
$query = $db->getQueryBuilder();
242+
$query->delete('filecache')
243+
->where($query->expr()->in('storage', $query->createNamedParameter($storageIds, IQueryBuilder::PARAM_INT_ARRAY)));
244+
$query->executeStatement();
245+
246+
$query = $db->getQueryBuilder();
247+
$query->delete('storages')
248+
->where($query->expr()->eq('numeric_id', $query->createNamedParameter($storageIds, IQueryBuilder::PARAM_INT_ARRAY)));
249+
$query->executeStatement();
250+
251+
$query = $db->getQueryBuilder();
252+
$query->delete('mounts')
253+
->where($query->expr()->eq('mount_id', $query->createNamedParameter($mountId, IQueryBuilder::PARAM_INT)));
254+
$query->executeStatement();
255+
256+
$db->commit();
257+
} catch (\Exception $e) {
258+
$db->rollBack();
259+
throw $e;
260+
}
261+
}
222262
}

0 commit comments

Comments
 (0)