Skip to content

Commit 3bcdd21

Browse files
committed
fix: don't rely on share providers being avaiable in CleanupShareTarget
Signed-off-by: Robin Appelman <robin@icewind.nl>
1 parent f61ef6d commit 3bcdd21

2 files changed

Lines changed: 35 additions & 22 deletions

File tree

apps/files_sharing/lib/Repair/CleanupShareTarget.php

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,16 @@
1313
use OCP\DB\QueryBuilder\IQueryBuilder;
1414
use OCP\Files\Config\ICachedMountInfo;
1515
use OCP\Files\Config\IUserMountCache;
16+
use OCP\Files\IRootFolder;
1617
use OCP\IDBConnection;
1718
use OCP\IUserManager;
1819
use OCP\Migration\IOutput;
1920
use OCP\Migration\IRepairStep;
20-
use OCP\Share\IManager;
21-
use OCP\Share\IProviderFactory;
2221
use OCP\Share\IShare;
2322

23+
/**
24+
* @psalm-type ShareInfo = array{id: string|int, share_type: string, share_with: string, file_source: string, file_target: string};
25+
*/
2426
class CleanupShareTarget implements IRepairStep {
2527
/** we only care about shares with a user target,
2628
* since the underling group/deck/talk share doesn't get moved
@@ -34,12 +36,11 @@ class CleanupShareTarget implements IRepairStep {
3436

3537
public function __construct(
3638
private readonly IDBConnection $connection,
37-
private readonly IManager $shareManager,
38-
private readonly IProviderFactory $shareProviderFactory,
3939
private readonly ShareTargetValidator $shareTargetValidator,
4040
private readonly IUserManager $userManager,
4141
private readonly SetupManager $setupManager,
4242
private readonly IUserMountCache $userMountCache,
43+
private readonly IRootFolder $rootFolder,
4344
) {
4445
}
4546

@@ -58,12 +59,10 @@ public function run(IOutput $output) {
5859

5960
$lastUser = '';
6061
$userMounts = [];
62+
$userFolder = null;
6163

6264
foreach ($this->getProblemShares() as $shareInfo) {
6365
$recipient = $this->userManager->getExistingUser($shareInfo['share_with']);
64-
$share = $this->shareProviderFactory
65-
->getProviderForType((int)$shareInfo['share_type'])
66-
->getShareById($shareInfo['id'], $recipient->getUID());
6766

6867
// since we ordered the share by user, we can reuse the last data until we get to the next user
6968
if ($lastUser !== $recipient->getUID()) {
@@ -74,19 +73,23 @@ public function run(IOutput $output) {
7473
$mounts = $this->userMountCache->getMountsForUser($recipient);
7574
$mountPoints = array_map(fn (ICachedMountInfo $mount) => $mount->getMountPoint(), $mounts);
7675
$userMounts = array_combine($mountPoints, $mounts);
76+
$userFolder = $this->rootFolder->getUserFolder($recipient->getUID());
7777
}
7878

79-
$oldTarget = $share->getTarget();
79+
$oldTarget = $shareInfo['file_target'];
8080
$newTarget = $this->cleanTarget($oldTarget);
81-
$share->setTarget($newTarget);
82-
$this->shareManager->moveShare($share, $recipient->getUID());
81+
$absoluteNewTarget = $userFolder->getFullPath($newTarget);
82+
$targetParentNode = $this->rootFolder->get(dirname($absoluteNewTarget));
8383

84-
$this->shareTargetValidator->verifyMountPoint(
85-
$recipient,
86-
$share,
84+
$absoluteNewTarget = $this->shareTargetValidator->generateUniqueTarget(
85+
$shareInfo['file_source'],
86+
$absoluteNewTarget,
87+
$targetParentNode->getMountPoint(),
8788
$userMounts,
88-
[$share],
8989
);
90+
$newTarget = $userFolder->getRelativePath($absoluteNewTarget);
91+
92+
$this->moveShare((string)$shareInfo['id'], $newTarget);
9093

9194
$oldMountPoint = "/{$recipient->getUID()}/files$oldTarget/";
9295
$newMountPoint = "/{$recipient->getUID()}/files$newTarget/";
@@ -108,12 +111,22 @@ private function countProblemShares(): int {
108111
return (int)$query->executeQuery()->fetchOne();
109112
}
110113

114+
private function moveShare(string $id, string $target) {
115+
// since we only process user-specific shares, we can just move them
116+
// without having to check if we need to create a user-specific override
117+
$query = $this->connection->getQueryBuilder();
118+
$query->update('share')
119+
->set('file_target', $query->createNamedParameter($target))
120+
->where($query->expr()->eq('id', $query->createNamedParameter($id)))
121+
->executeStatement();
122+
}
123+
111124
/**
112-
* @return \Traversable<array{id: string, share_type: string, share_with: string}>
125+
* @return \Traversable<ShareInfo>
113126
*/
114127
private function getProblemShares(): \Traversable {
115128
$query = $this->connection->getQueryBuilder();
116-
$query->select('id', 'share_type', 'share_with')
129+
$query->select('id', 'share_type', 'share_with', 'file_source', 'file_target')
117130
->from('share')
118131
->where($query->expr()->like('file_target', $query->createNamedParameter('% (_) (_)%')))
119132
->andWhere($query->expr()->in('share_type', $query->createNamedParameter(self::USER_SHARE_TYPES, IQueryBuilder::PARAM_INT_ARRAY), IQueryBuilder::PARAM_INT_ARRAY))

apps/files_sharing/lib/ShareTargetValidator.php

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public function verifyMountPoint(
8585
}
8686

8787
$newAbsoluteMountPoint = $this->generateUniqueTarget(
88-
$share,
88+
$share->getNodeId(),
8989
Filesystem::normalizePath($absoluteParent . '/' . $mountPoint),
9090
$parentMount,
9191
$allCachedMounts,
@@ -108,8 +108,8 @@ public function verifyMountPoint(
108108
/**
109109
* @param ICachedMountInfo[] $allCachedMounts
110110
*/
111-
private function generateUniqueTarget(
112-
IShare $share,
111+
public function generateUniqueTarget(
112+
int $shareNodeId,
113113
string $absolutePath,
114114
IMountPoint $parentMount,
115115
array $allCachedMounts,
@@ -122,7 +122,7 @@ private function generateUniqueTarget(
122122
$i = 2;
123123
$parentCache = $parentMount->getStorage()->getCache();
124124
$internalPath = $parentMount->getInternalPath($absolutePath);
125-
while ($parentCache->inCache($internalPath) || $this->hasConflictingMount($share, $allCachedMounts, $absolutePath)) {
125+
while ($parentCache->inCache($internalPath) || $this->hasConflictingMount($shareNodeId, $allCachedMounts, $absolutePath)) {
126126
$absolutePath = Filesystem::normalizePath($dir . '/' . $name . ' (' . $i . ')' . $ext);
127127
$internalPath = $parentMount->getInternalPath($absolutePath);
128128
$i++;
@@ -134,13 +134,13 @@ private function generateUniqueTarget(
134134
/**
135135
* @param ICachedMountInfo[] $allCachedMounts
136136
*/
137-
private function hasConflictingMount(IShare $share, array $allCachedMounts, string $absolutePath): bool {
137+
private function hasConflictingMount(int $shareNodeId, array $allCachedMounts, string $absolutePath): bool {
138138
if (!isset($allCachedMounts[$absolutePath . '/'])) {
139139
return false;
140140
}
141141

142142
$mount = $allCachedMounts[$absolutePath . '/'];
143-
if ($mount->getMountProvider() === MountProvider::class && $mount->getRootId() === $share->getNodeId()) {
143+
if ($mount->getMountProvider() === MountProvider::class && $mount->getRootId() === $shareNodeId) {
144144
// "conflicting" mount is a mount for the current share
145145
return false;
146146
}

0 commit comments

Comments
 (0)