Skip to content

Commit d765ec6

Browse files
committed
fix: don't rely on share providers being avaiable in CleanupShareTarget
Signed-off-by: Robin Appelman <[email protected]>
1 parent ebe0600 commit d765ec6

File tree

2 files changed

+35
-22
lines changed

2 files changed

+35
-22
lines changed

apps/files_sharing/lib/Repair/CleanupShareTarget.php

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,17 @@
1111
use OC\Files\SetupManager;
1212
use OCA\Files_Sharing\ShareTargetValidator;
1313
use OCP\DB\QueryBuilder\IQueryBuilder;
14+
use OCP\Files\IRootFolder;
1415
use OCP\Files\Mount\IMountManager;
1516
use OCP\IDBConnection;
1617
use OCP\IUserManager;
1718
use OCP\Migration\IOutput;
1819
use OCP\Migration\IRepairStep;
19-
use OCP\Share\IManager;
20-
use OCP\Share\IProviderFactory;
2120
use OCP\Share\IShare;
2221

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

3436
public function __construct(
3537
private readonly IDBConnection $connection,
36-
private readonly IManager $shareManager,
37-
private readonly IProviderFactory $shareProviderFactory,
3838
private readonly ShareTargetValidator $shareTargetValidator,
3939
private readonly IUserManager $userManager,
4040
private readonly SetupManager $setupManager,
4141
private readonly IMountManager $mountManager,
42+
private readonly IRootFolder $rootFolder,
4243
) {
4344
}
4445

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

5859
$lastUser = '';
5960
$userMounts = [];
61+
$userFolder = null;
6062

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

6766
// since we ordered the share by user, we can reuse the last data until we get to the next user
6867
if ($lastUser !== $recipient->getUID()) {
@@ -71,19 +70,23 @@ public function run(IOutput $output) {
7170
$this->setupManager->tearDown();
7271
$this->setupManager->setupForUser($recipient);
7372
$userMounts = $this->mountManager->getAll();
73+
$userFolder = $this->rootFolder->getUserFolder($recipient->getUID());
7474
}
7575

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

81-
$this->shareTargetValidator->verifyMountPoint(
82-
$recipient,
83-
$share,
81+
$absoluteNewTarget = $this->shareTargetValidator->generateUniqueTarget(
82+
$shareInfo['file_source'],
83+
$absoluteNewTarget,
84+
$targetParentNode->getMountPoint(),
8485
$userMounts,
85-
[$share],
8686
);
87+
$newTarget = $userFolder->getRelativePath($absoluteNewTarget);
88+
89+
$this->moveShare((string)$shareInfo['id'], $newTarget);
8790

8891
$oldMountPoint = "/{$recipient->getUID()}/files$oldTarget/";
8992
$newMountPoint = "/{$recipient->getUID()}/files$newTarget/";
@@ -105,12 +108,22 @@ private function countProblemShares(): int {
105108
return (int)$query->executeQuery()->fetchOne();
106109
}
107110

111+
private function moveShare(string $id, string $target) {
112+
// since we only process user-specific shares, we can just move them
113+
// without having to check if we need to create a user-specific override
114+
$query = $this->connection->getQueryBuilder();
115+
$query->update('share')
116+
->set('file_target', $query->createNamedParameter($target))
117+
->where($query->expr()->eq('id', $query->createNamedParameter($id)))
118+
->executeStatement();
119+
}
120+
108121
/**
109-
* @return \Traversable<array{id: string, share_type: string, share_with: string}>
122+
* @return \Traversable<ShareInfo>
110123
*/
111124
private function getProblemShares(): \Traversable {
112125
$query = $this->connection->getQueryBuilder();
113-
$query->select('id', 'share_type', 'share_with')
126+
$query->select('id', 'share_type', 'share_with', 'file_source', 'file_target')
114127
->from('share')
115128
->where($query->expr()->like('file_target', $query->createNamedParameter('% (_) (_)%')))
116129
->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
@@ -84,7 +84,7 @@ public function verifyMountPoint(
8484
}
8585

8686
$newAbsoluteMountPoint = $this->generateUniqueTarget(
87-
$share,
87+
$share->getNodeId(),
8888
Filesystem::normalizePath($absoluteParent . '/' . $mountPoint),
8989
$parentMount,
9090
$allCachedMounts,
@@ -107,8 +107,8 @@ public function verifyMountPoint(
107107
/**
108108
* @param IMountPoint[] $allCachedMounts
109109
*/
110-
private function generateUniqueTarget(
111-
IShare $share,
110+
public function generateUniqueTarget(
111+
int $shareNodeId,
112112
string $absolutePath,
113113
IMountPoint $parentMount,
114114
array $allCachedMounts,
@@ -121,7 +121,7 @@ private function generateUniqueTarget(
121121
$i = 2;
122122
$parentCache = $parentMount->getStorage()->getCache();
123123
$internalPath = $parentMount->getInternalPath($absolutePath);
124-
while ($parentCache->inCache($internalPath) || $this->hasConflictingMount($share, $allCachedMounts, $absolutePath)) {
124+
while ($parentCache->inCache($internalPath) || $this->hasConflictingMount($shareNodeId, $allCachedMounts, $absolutePath)) {
125125
$absolutePath = Filesystem::normalizePath($dir . '/' . $name . ' (' . $i . ')' . $ext);
126126
$internalPath = $parentMount->getInternalPath($absolutePath);
127127
$i++;
@@ -133,13 +133,13 @@ private function generateUniqueTarget(
133133
/**
134134
* @param IMountPoint[] $allCachedMounts
135135
*/
136-
private function hasConflictingMount(IShare $share, array $allCachedMounts, string $absolutePath): bool {
136+
private function hasConflictingMount(int $shareNodeId, array $allCachedMounts, string $absolutePath): bool {
137137
if (!isset($allCachedMounts[$absolutePath . '/'])) {
138138
return false;
139139
}
140140

141141
$mount = $allCachedMounts[$absolutePath . '/'];
142-
if ($mount instanceof SharedMount && $mount->getShare()->getNodeId() === $share->getNodeId()) {
142+
if ($mount instanceof SharedMount && $mount->getShare()->getNodeId() === $shareNodeId) {
143143
// "conflicting" mount is a mount for the current share
144144
return false;
145145
}

0 commit comments

Comments
 (0)