From b1773aba10d9969c6bf34627bb6cef3953cfe5e6 Mon Sep 17 00:00:00 2001 From: Maxence Lange Date: Wed, 23 Sep 2026 11:59:55 -0100 Subject: [PATCH] fix(federation): fix shares and mount rename Signed-off-by: Maxence Lange --- lib/MountManager/CircleMountProvider.php | 87 +++++++++--------------- 1 file changed, 33 insertions(+), 54 deletions(-) diff --git a/lib/MountManager/CircleMountProvider.php b/lib/MountManager/CircleMountProvider.php index 980a26d6a..7f8ab2ca4 100644 --- a/lib/MountManager/CircleMountProvider.php +++ b/lib/MountManager/CircleMountProvider.php @@ -18,7 +18,6 @@ use OCA\Circles\Exceptions\MountPointConstructionException; use OCA\Circles\Exceptions\RequestBuilderException; use OCA\Circles\Exceptions\SingleCircleNotFoundException; -use OCA\Circles\IFederatedUser; use OCA\Circles\Model\Member; use OCA\Circles\Model\Mount; use OCA\Circles\Model\Mountpoint; @@ -29,10 +28,8 @@ use OCP\DB\Exception; use OCP\Federation\ICloudIdManager; use OCP\Files\Config\IMountProvider; -use OCP\Files\Folder; use OCP\Files\IRootFolder; use OCP\Files\Mount\IMountPoint; -use OCP\Files\NotFoundException; use OCP\Files\Storage\IStorageFactory; use OCP\Http\Client\IClientService; use OCP\IUser; @@ -42,6 +39,7 @@ class CircleMountProvider implements IMountProvider { use TArrayTools; public const EXTERNAL_STORAGE = ExternalStorage::class; + public array $mountedPoint = []; public function __construct( private IClientService $clientService, @@ -188,63 +186,44 @@ private function fixDuplicateFile(string $userId, Mount $mount): void { return; } - $fs = $this->rootFolder->getUserFolder($userId); - - try { - $fs->get($mount->getMountPoint()); - } catch (NotFoundException) { - // in case no alternate mountpoint, we generate one in database (easier to catch duplicate mountpoint) - if ($mount->getAlternateMountPoint() !== null) { - return; - } - - $federatedUser = $this->federatedUserService->getLocalFederatedUser($userId); - $mountPoint = new Mountpoint($mount->getMountId(), $federatedUser->getSingleId(), $mount->getOriginalMountPoint()); - try { - $this->mountPointRequest->insert($mountPoint); - return; - } catch (Exception $e) { - // meaning a duplicate mountpoint already exists, we need to set a new filename - if ($e->getReason() !== Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) { - throw $e; - } - } + // we will be using cache version of the filesystem, to not cycle while operating it + $mountId = $mount->getId(); + $baseFile = $mountPoint = '/files' . $mount->getMountPoint(); + $parentMount = $this->rootFolder->getUserFolder($userId)->getMountPoint(); + $parentCache = $parentMount->getStorage()->getCache(); + + // splitting extension to have a nice /file (1).ext + $ext = pathinfo($mountPoint, PATHINFO_EXTENSION); + if ($ext !== '') { + $baseFile = substr($mountPoint, 0, -(strlen($ext) + 1)); + $ext = '.' . $ext; } - $federatedUser = $this->federatedUserService->getLocalFederatedUser($userId); - $this->generateIncrementedMountpoint($fs, $mount, $federatedUser); - } + // based on cached content, improving naming + $n = 1; + while ($parentCache->inCache($mountPoint) + || ($this->mountedPoint[$mountPoint] ?? $mountId) !== $mountId) { + $mountPoint = $baseFile . ' (' . $n++ . ')' . $ext; + } - private function generateIncrementedMountpoint(Folder $fs, Mount $mount, IFederatedUser $federatedUser): void { - $info = pathinfo($mount->getMountPoint()); - $filename = rtrim($this->get('dirname', $info), '/') . '/' . $this->get('filename', $info); - $extension = $this->get('extension', $info); - $extension = ($extension === '') ? '' : '.' . $extension; + // we keep trace as this won't be available in cache + $this->mountedPoint[$mountPoint] = $mount->getId(); - $n = 2; - while (true) { - $path = $filename . " ($n)" . $extension; + $federatedUser = $this->federatedUserService->getLocalFederatedUser($userId); + $mountPoint = new Mountpoint($mount->getMountId(), $federatedUser->getSingleId(), substr($mountPoint, 6)); + try { try { - $fs->get($path); - } catch (NotFoundException) { - $mountPoint = new Mountpoint($mount->getMountId(), $federatedUser->getSingleId(), $path); - $mount->setAlternateMountPoint($mountPoint); - try { - try { - $this->mountPointRequest->update($mountPoint); - } catch (MountNotFoundException) { - $this->mountPointRequest->insert($mountPoint); - } - return; - } catch (Exception $e) { - // meaning path is already used by another share for this user, we keep incrementing - if ($e->getReason() !== Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) { - throw $e; - } - } + $this->mountPointRequest->update($mountPoint); + } catch (MountNotFoundException) { + $this->mountPointRequest->insert($mountPoint); + } + return; + } catch (Exception $e) { + $this->logger->error('issue while creating alternate mount point', ['exception' => $e]); + // while there should be no reason for a unique constraint violation, we just log and ignore it + if ($e->getReason() !== Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) { + throw $e; } - - $n++; } } }