From eb6f78e26d4a02c452ad38614f68e6fe01c31ec6 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Tue, 13 Jan 2026 15:14:36 +0100 Subject: [PATCH] feat: implement authoritative mount provider for share provider Signed-off-by: Robin Appelman --- .../lib/Listener/SharesUpdatedListener.php | 31 ++++++++++++++----- apps/files_sharing/lib/MountProvider.php | 13 +++++--- 2 files changed, 32 insertions(+), 12 deletions(-) diff --git a/apps/files_sharing/lib/Listener/SharesUpdatedListener.php b/apps/files_sharing/lib/Listener/SharesUpdatedListener.php index 7d70d89affb82..ccef71bad5c87 100644 --- a/apps/files_sharing/lib/Listener/SharesUpdatedListener.php +++ b/apps/files_sharing/lib/Listener/SharesUpdatedListener.php @@ -15,6 +15,7 @@ use OCP\EventDispatcher\IEventListener; use OCP\Files\Config\ICachedMountInfo; use OCP\Files\Config\IUserMountCache; +use OCP\Files\Storage\IStorageFactory; use OCP\Group\Events\UserAddedEvent; use OCP\Group\Events\UserRemovedEvent; use OCP\IUser; @@ -36,50 +37,64 @@ public function __construct( private readonly IUserMountCache $userMountCache, private readonly MountProvider $shareMountProvider, private readonly ShareTargetValidator $shareTargetValidator, + private readonly IStorageFactory $storageFactory, ) { } public function handle(Event $event): void { if ($event instanceof UserShareAccessUpdatedEvent) { foreach ($event->getUsers() as $user) { - $this->updateForUser($user); + $this->updateForUser($user, true); } } if ($event instanceof UserAddedEvent || $event instanceof UserRemovedEvent) { - $this->updateForUser($event->getUser()); + $this->updateForUser($event->getUser(), true); } if ( $event instanceof ShareCreatedEvent - || $event instanceof BeforeShareDeletedEvent || $event instanceof ShareTransferredEvent ) { foreach ($this->shareManager->getUsersForShare($event->getShare()) as $user) { - $this->updateForUser($user); + $this->updateForUser($user, true); + } + } + if ($event instanceof BeforeShareDeletedEvent) { + foreach ($this->shareManager->getUsersForShare($event->getShare()) as $user) { + $this->updateForUser($user, false, [$event->getShare()]); } } } - private function updateForUser(IUser $user): void { + private function updateForUser(IUser $user, bool $verifyMountPoints, array $ignoreShares = []): void { // prevent recursion if (isset($this->inUpdate[$user->getUID()])) { return; } $this->inUpdate[$user->getUID()] = true; - $cachedMounts = $this->userMountCache->getMountsForUser($user); + $shareMounts = array_filter($cachedMounts, fn (ICachedMountInfo $mount) => $mount->getMountProvider() === MountProvider::class); $mountPoints = array_map(fn (ICachedMountInfo $mount) => $mount->getMountPoint(), $cachedMounts); $mountsByPath = array_combine($mountPoints, $cachedMounts); - $shares = $this->shareMountProvider->getSuperSharesForUser($user); + $shares = $this->shareMountProvider->getSuperSharesForUser($user, $ignoreShares); + $mountsChanged = count($shares) !== count($shareMounts); foreach ($shares as &$share) { [$parentShare, $groupedShares] = $share; $mountPoint = '/' . $user->getUID() . '/files/' . trim($parentShare->getTarget(), '/') . '/'; $mountKey = $parentShare->getNodeId() . '::' . $mountPoint; if (!isset($cachedMounts[$mountKey])) { - $this->shareTargetValidator->verifyMountPoint($user, $parentShare, $mountsByPath, $groupedShares); + $mountsChanged = true; + if ($verifyMountPoints) { + $this->shareTargetValidator->verifyMountPoint($user, $parentShare, $mountsByPath, $groupedShares); + } } } + if ($mountsChanged) { + $newMounts = $this->shareMountProvider->getMountsFromSuperShares($user, $shares, $this->storageFactory); + $this->userMountCache->registerMounts($user, $newMounts, [MountProvider::class]); + } + unset($this->inUpdate[$user->getUID()]); } } diff --git a/apps/files_sharing/lib/MountProvider.php b/apps/files_sharing/lib/MountProvider.php index d397f8ee7058b..8047a0934a709 100644 --- a/apps/files_sharing/lib/MountProvider.php +++ b/apps/files_sharing/lib/MountProvider.php @@ -12,6 +12,7 @@ use OC\Files\View; use OCA\Files_Sharing\Event\ShareMountedEvent; use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\Config\IAuthoritativeMountProvider; use OCP\Files\Config\IMountProvider; use OCP\Files\Config\IPartialMountProvider; use OCP\Files\Mount\IMountManager; @@ -28,7 +29,7 @@ use function count; -class MountProvider implements IMountProvider, IPartialMountProvider { +class MountProvider implements IMountProvider, IAuthoritativeMountProvider, IPartialMountProvider { public function __construct( protected readonly IConfig $config, protected readonly IManager $shareManager, @@ -46,9 +47,10 @@ public function getMountsForUser(IUser $user, IStorageFactory $loader): array { /** * @param IUser $user + * @param list $excludeShares * @return list}> Tuple of [superShare, groupedShares] */ - public function getSuperSharesForUser(IUser $user): array { + public function getSuperSharesForUser(IUser $user, array $excludeShares = []): array { $userId = $user->getUID(); $shares = $this->mergeIterables( $this->shareManager->getSharedWith($userId, IShare::TYPE_USER, null, -1), @@ -58,7 +60,8 @@ public function getSuperSharesForUser(IUser $user): array { $this->shareManager->getSharedWith($userId, IShare::TYPE_DECK, null, -1), ); - $shares = $this->filterShares($shares, $userId); + $excludeShareIds = array_map(fn (IShare $share) => $share->getFullId(), $excludeShares); + $shares = $this->filterShares($shares, $userId, $excludeShareIds); return $this->buildSuperShares($shares, $user); } @@ -318,14 +321,16 @@ public function getMountsFromSuperShares( * user has no permissions. * * @param iterable $shares + * @param list $excludeShareIds * @return iterable */ - private function filterShares(iterable $shares, string $userId): iterable { + private function filterShares(iterable $shares, string $userId, array $excludeShareIds = []): iterable { foreach ($shares as $share) { if ( $share->getPermissions() > 0 && $share->getShareOwner() !== $userId && $share->getSharedBy() !== $userId + && !in_array($share->getFullId(), $excludeShareIds) ) { yield $share; }