diff --git a/apps/files_sharing/lib/Listener/SharesUpdatedListener.php b/apps/files_sharing/lib/Listener/SharesUpdatedListener.php index 7d70d89affb..ccef71bad5c 100644 --- a/apps/files_sharing/lib/Listener/SharesUpdatedListener.php +++ b/apps/files_sharing/lib/Listener/SharesUpdatedListener.php @@ -15,6 +15,7 @@ use OCP\EventDispatcher\Event; 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 @@ class SharesUpdatedListener implements IEventListener { 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 790ea11db29..68202483dbc 100644 --- a/apps/files_sharing/lib/MountProvider.php +++ b/apps/files_sharing/lib/MountProvider.php @@ -12,6 +12,7 @@ use InvalidArgumentException; 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; @@ -27,7 +28,7 @@ use Psr\Log\LoggerInterface; use function count; -class MountProvider implements IMountProvider, IPartialMountProvider { +class MountProvider implements IMountProvider, IAuthoritativeMountProvider, IPartialMountProvider { /** * @param IConfig $config @@ -58,9 +59,10 @@ class MountProvider implements IMountProvider, IPartialMountProvider { /** * @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), @@ -70,7 +72,8 @@ class MountProvider implements IMountProvider, IPartialMountProvider { $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); } @@ -292,12 +295,6 @@ class MountProvider implements IMountProvider, IPartialMountProvider { } $shareId = (int)$parentShare->getId(); - $absMountPoint = '/' . $user->getUID() . '/files/' . trim($parentShare->getTarget(), '/') . '/'; - - // after the mountpoint is verified for the first time, only new mountpoints (e.g. groupfolders can overwrite the target) - if ($shareId > $maxValidatedShare || isset($allMounts[$absMountPoint])) { - $this->shareTargetValidator->verifyMountPoint($user, $parentShare, $allMounts, $groupedShares); - } $mount = new SharedMount( '\OCA\Files_Sharing\SharedStorage', @@ -347,14 +344,16 @@ class MountProvider implements IMountProvider, IPartialMountProvider { * 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; } diff --git a/apps/files_sharing/lib/Repair/CleanupShareTarget.php b/apps/files_sharing/lib/Repair/CleanupShareTarget.php index d32d5dc21d2..845e24e0367 100644 --- a/apps/files_sharing/lib/Repair/CleanupShareTarget.php +++ b/apps/files_sharing/lib/Repair/CleanupShareTarget.php @@ -11,8 +11,9 @@ namespace OCA\Files_Sharing\Repair; use OC\Files\SetupManager; use OCA\Files_Sharing\ShareTargetValidator; use OCP\DB\QueryBuilder\IQueryBuilder; +use OCP\Files\Config\ICachedMountInfo; +use OCP\Files\Config\IUserMountCache; use OCP\Files\IRootFolder; -use OCP\Files\Mount\IMountManager; use OCP\Files\NotFoundException; use OCP\ICacheFactory; use OCP\IDBConnection; @@ -42,7 +43,7 @@ class CleanupShareTarget implements IRepairStep { private readonly ShareTargetValidator $shareTargetValidator, private readonly IUserManager $userManager, private readonly SetupManager $setupManager, - private readonly IMountManager $mountManager, + private readonly IUserMountCache $userMountCache, private readonly IRootFolder $rootFolder, private readonly LoggerInterface $logger, private readonly ICacheFactory $cacheFactory, @@ -85,7 +86,9 @@ class CleanupShareTarget implements IRepairStep { $this->setupManager->tearDown(); $this->setupManager->setupForUser($recipient); - $userMounts = $this->mountManager->getAll(); + $mounts = $this->userMountCache->getMountsForUser($recipient); + $mountPoints = array_map(fn (ICachedMountInfo $mount) => $mount->getMountPoint(), $mounts); + $userMounts = array_combine($mountPoints, $mounts); $userFolder = $this->rootFolder->getUserFolder($recipient->getUID()); }