From ec680da68da1b41c05ef48b68b6221c1afd86ccc Mon Sep 17 00:00:00 2001 From: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com> Date: Mon, 29 Dec 2025 15:06:24 +0100 Subject: [PATCH 1/7] feat(files_sharing): implement partial mount providers Signed-off-by: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com> --- .../lib/External/MountProvider.php | 77 ++++++++++- apps/files_sharing/lib/MountProvider.php | 122 +++++++++++++++--- .../files_sharing/tests/MountProviderTest.php | 93 ++++++++++++- 3 files changed, 269 insertions(+), 23 deletions(-) diff --git a/apps/files_sharing/lib/External/MountProvider.php b/apps/files_sharing/lib/External/MountProvider.php index 5e132c22903ce..549d4f3e79858 100644 --- a/apps/files_sharing/lib/External/MountProvider.php +++ b/apps/files_sharing/lib/External/MountProvider.php @@ -13,6 +13,8 @@ use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\Federation\ICloudIdManager; use OCP\Files\Config\IMountProvider; +use OCP\Files\Config\IMountProviderArgs; +use OCP\Files\Config\IPartialMountProvider; use OCP\Files\Storage\IStorageFactory; use OCP\Http\Client\IClientService; use OCP\ICertificateManager; @@ -21,7 +23,7 @@ use OCP\Server; use OCP\Share\IShare; -class MountProvider implements IMountProvider { +class MountProvider implements IMountProvider, IPartialMountProvider { public const STORAGE = ExternalShareStorage::class; /** @@ -69,4 +71,77 @@ public function getMountsForUser(IUser $user, IStorageFactory $loader): array { $result->closeCursor(); return $mounts; } + + /** + * @inheritDoc + */ + public function getMountsForPath( + string $path, + bool $forChildren, + array $mountProviderArgs, + IStorageFactory $loader, + ): array { + if (empty($mountProviderArgs)) { + return []; + } + + $userId = null; + $user = null; + foreach ($mountProviderArgs as $mountProviderArg) { + if ($userId === null) { + $user = $mountProviderArg->mountInfo->getUser(); + $userId = $user->getUID(); + } elseif ($userId !== $mountProviderArg->mountInfo->getUser()->getUID()) { + throw new \LogicException('Mounts must belong to the same user!'); + } + } + + if (!$forChildren) { + // override path with mount point when fetching without children + $path = $mountProviderArgs[0]->mountInfo->getMountPoint(); + } + + // remove /uid/files as the target is stored without + $path = \substr($path, \strlen('/' . $userId . '/files')); + // remove trailing slash + $path = \rtrim($path, '/'); + + // make sure trailing slash is present when loading children + if ($forChildren || $path === '') { + $path .= '/'; + } + + $qb = $this->connection->getQueryBuilder(); + $qb->select('id', 'remote', 'share_token', 'password', 'mountpoint', 'owner') + ->from('share_external') + ->where($qb->expr()->eq('user', $qb->createNamedParameter($user->getUID()))) + ->andWhere($qb->expr()->eq('accepted', $qb->createNamedParameter(IShare::STATUS_ACCEPTED, IQueryBuilder::PARAM_INT))); + + if ($forChildren) { + $qb->andWhere($qb->expr()->like('mountpoint', $qb->createNamedParameter($this->connection->escapeLikeParameter($path) . '_%'))); + } else { + $qb->andWhere($qb->expr()->eq('mountpoint', $qb->createNamedParameter($path))); + } + + $result = $qb->executeQuery(); + + $mounts = []; + while ($row = $result->fetchAssociative()) { + $row['manager'] = $this; + $row['token'] = $row['share_token']; + $mount = $this->getMount($user, $row, $loader); + + $isRequestedMount = array_any($mountProviderArgs, function (IMountProviderArgs $arg) use ($mount) { + return $arg->mountInfo->getMountPoint() === $mount->getMountPoint(); + }); + if (!$isRequestedMount) { + continue; + } + + $mounts[$mount->getMountPoint()] = $mount; + } + $result->closeCursor(); + + return $mounts; + } } diff --git a/apps/files_sharing/lib/MountProvider.php b/apps/files_sharing/lib/MountProvider.php index 1d9e16db5ef84..5496506ad6eb5 100644 --- a/apps/files_sharing/lib/MountProvider.php +++ b/apps/files_sharing/lib/MountProvider.php @@ -14,6 +14,8 @@ use OCP\Cache\CappedMemoryCache; use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Config\IMountProvider; +use OCP\Files\Config\IMountProviderArgs; +use OCP\Files\Config\IPartialMountProvider; use OCP\Files\Mount\IMountManager; use OCP\Files\Mount\IMountPoint; use OCP\Files\Storage\IStorageFactory; @@ -26,7 +28,7 @@ use Psr\Log\LoggerInterface; use function count; -class MountProvider implements IMountProvider { +class MountProvider implements IMountProvider, IPartialMountProvider { /** * @param IConfig $config * @param IManager $shareManager @@ -51,7 +53,7 @@ public function __construct( */ public function getMountsForUser(IUser $user, IStorageFactory $loader) { $userId = $user->getUID(); - $shares = array_merge( + $shares = $this->mergeIterables( $this->shareManager->getSharedWith($userId, IShare::TYPE_USER, null, -1), $this->shareManager->getSharedWith($userId, IShare::TYPE_GROUP, null, -1), $this->shareManager->getSharedWith($userId, IShare::TYPE_CIRCLE, null, -1), @@ -62,17 +64,19 @@ public function getMountsForUser(IUser $user, IStorageFactory $loader) { $shares = $this->filterShares($shares, $userId); $superShares = $this->buildSuperShares($shares, $user); - return $this->getMountsFromSuperShares($userId, $superShares, $loader, $user); + return array_values($this->getMountsFromSuperShares($userId, + $superShares, + $loader, $user)); } /** * Groups shares by path (nodeId) and target path * - * @param IShare[] $shares + * @param iterable $shares * @return IShare[][] array of grouped shares, each element in the * array is a group which itself is an array of shares */ - private function groupShares(array $shares) { + private function groupShares(iterable $shares): array { $tmp = []; foreach ($shares as $share) { @@ -108,11 +112,11 @@ private function groupShares(array $shares) { * the shares in the group, forming the most permissive combination * possible. * - * @param IShare[] $allShares + * @param iterable $allShares * @param IUser $user user * @return list}> Tuple of [superShare, groupedShares] */ - private function buildSuperShares(array $allShares, IUser $user) { + private function buildSuperShares(iterable $allShares, IUser $user): array { $result = []; $groupedShares = $this->groupShares($allShares); @@ -248,7 +252,7 @@ private function adjustTarget( * @param array $superShares * @param IStorageFactory $loader * @param IUser $user - * @return array + * @return array IMountPoint indexed by mount point * @throws Exception */ private function getMountsFromSuperShares( @@ -333,24 +337,106 @@ private function getMountsFromSuperShares( $validShareCache->set($userId, $newMaxValidatedShare, 24 * 60 * 60); // array_filter removes the null values from the array - return array_values(array_filter($mounts)); + return array_filter($mounts); } /** * Filters out shares owned or shared by the user and ones for which the * user has no permissions. * - * @param IShare[] $shares - * @return IShare[] + * @param iterable $shares + * @return iterable */ - private function filterShares(array $shares, string $userId): array { - return array_filter( - $shares, - static function (IShare $share) use ($userId) { - return $share->getPermissions() > 0 - && $share->getShareOwner() !== $userId - && $share->getSharedBy() !== $userId; + private function filterShares(iterable $shares, string $userId): iterable { + foreach ($shares as $share) { + if ($share->getPermissions() > 0 && $share->getShareOwner() + !== $userId && $share->getSharedBy() !== $userId) { + yield $share; } + } + } + + /** + * @inheritdoc + */ + public function getMountsForPath( + string $path, + bool $forChildren, + array $mountProviderArgs, + IStorageFactory $loader, + ): array { + if (empty($mountProviderArgs)) { + return []; + } + + $limit = -1; + $userId = null; + $user = null; + foreach ($mountProviderArgs as $mountProviderArg) { + if ($userId === null) { + $user = $mountProviderArg->mountInfo->getUser(); + $userId = $user->getUID(); + } elseif ($userId !== $mountProviderArg->mountInfo->getUser()->getUID()) { + throw new \LogicException('Mounts must belong to the same user!'); + } + } + + if (!$forChildren) { + // override path with mount point when fetching without children + $path = $mountProviderArgs[0]->mountInfo->getMountPoint(); + } + + // remove /uid/files as the target is stored without + $path = \substr($path, \strlen('/' . $userId . '/files')); + // remove trailing slash + $path = \rtrim($path, '/'); + + // make sure trailing slash is present when loading children + if ($forChildren || $path === '') { + $path .= '/'; + } + + $shares = $this->mergeIterables( + $this->shareManager->getSharedWithByPath($userId, + IShare::TYPE_USER, $path, $forChildren, $limit), + $this->shareManager->getSharedWithByPath($userId, + IShare::TYPE_GROUP, $path, $forChildren, $limit), + $this->shareManager->getSharedWithByPath($userId, + IShare::TYPE_CIRCLE, $path, $forChildren, $limit), + $this->shareManager->getSharedWithByPath($userId, + IShare::TYPE_ROOM, $path, $forChildren, $limit), + $this->shareManager->getSharedWithByPath($userId, + IShare::TYPE_DECK, $path, $forChildren, $limit), ); + + $shares = $this->filterShares($shares, $userId); + $superShares = $this->buildSuperShares($shares, $user); + + // remove unrequested shares + $superShares = \array_filter($superShares, function (array $shares) use ($mountProviderArgs) { + $superShare = $shares[0]; + + return array_any($mountProviderArgs, + function (IMountProviderArgs $mountProviderArg) use ($superShare) { + return $superShare->getNodeId() === $mountProviderArg->mountInfo->getRootId(); + }); + }); + + return $this->getMountsFromSuperShares($userId, + $superShares, + $loader, + $user); + } + + /** + * @param iterable ...$iterables + * @return iterable + */ + private function mergeIterables(...$iterables): iterable { + foreach ($iterables as $iterable) { + foreach ($iterable as $value) { + yield $value; + } + } } } diff --git a/apps/files_sharing/tests/MountProviderTest.php b/apps/files_sharing/tests/MountProviderTest.php index 20db33d62e8f7..4cc8856d06407 100644 --- a/apps/files_sharing/tests/MountProviderTest.php +++ b/apps/files_sharing/tests/MountProviderTest.php @@ -7,14 +7,17 @@ */ namespace OCA\Files_Sharing\Tests; -use OC\Memcache\NullCache; use OC\Share20\Share; use OCA\Files_Sharing\MountProvider; use OCA\Files_Sharing\SharedMount; use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\Cache\ICacheEntry; +use OCP\Files\Config\ICachedMountInfo; +use OCP\Files\Config\IMountProviderArgs; use OCP\Files\IRootFolder; use OCP\Files\Mount\IMountManager; use OCP\Files\Storage\IStorageFactory; +use OCP\ICache; use OCP\ICacheFactory; use OCP\IConfig; use OCP\IUser; @@ -35,6 +38,7 @@ class MountProviderTest extends \Test\TestCase { protected IManager&MockObject $shareManager; protected IStorageFactory&MockObject $loader; protected LoggerInterface&MockObject $logger; + private ICache&MockObject $cache; protected function setUp(): void { parent::setUp(); @@ -45,9 +49,10 @@ protected function setUp(): void { $this->shareManager = $this->getMockBuilder(IManager::class)->getMock(); $this->logger = $this->getMockBuilder(LoggerInterface::class)->getMock(); $eventDispatcher = $this->createMock(IEventDispatcher::class); + $this->cache = $this->createMock(ICache::class); + $this->cache->method('get')->willReturn(true); $cacheFactory = $this->createMock(ICacheFactory::class); - $cacheFactory->method('createLocal') - ->willReturn(new NullCache()); + $cacheFactory->method('createLocal')->willReturn($this->cache); $mountManager = $this->createMock(IMountManager::class); $this->provider = new MountProvider($this->config, $this->shareManager, $this->logger, $eventDispatcher, $cacheFactory, $mountManager); @@ -355,7 +360,6 @@ public function testMergeShares(array $userShares, array $groupShares, array $ex $circleShares = []; $roomShares = []; $deckShares = []; - $scienceMeshShares = []; $this->shareManager->expects($this->exactly(5)) ->method('getSharedWith') ->willReturnMap([ @@ -402,4 +406,85 @@ public function testMergeShares(array $userShares, array $groupShares, array $ex } } } + + #[\PHPUnit\Framework\Attributes\DataProvider(methodName: 'mergeSharesDataProvider')] + public function testMergeSharesInGetMountsForPath(array $userShares, array $groupShares, array $expectedShares, bool $moveFails = false): void { + $rootFolder = $this->createMock(IRootFolder::class); + $userManager = $this->createMock(IUserManager::class); + + $userShares = array_map(function ($shareSpec) { + return $this->makeMockShare($shareSpec[0], $shareSpec[1], $shareSpec[2], $shareSpec[3], $shareSpec[4], $shareSpec[5]); + }, $userShares); + $groupShares = array_map(function ($shareSpec) { + return $this->makeMockShare($shareSpec[0], $shareSpec[1], $shareSpec[2], $shareSpec[3], $shareSpec[4], $shareSpec[5]); + }, $groupShares); + + $this->user->expects($this->any()) + ->method('getUID') + ->willReturn('user1'); + + // tests regarding circles are made in the app itself. + $circleShares = []; + $roomShares = []; + $deckShares = []; + $path = '/'; + + // no expected shares? then no calls are performed to providers + $expectedProviderCalls = \count($expectedShares) ? 5 : 0; + $this->shareManager->expects($this->exactly($expectedProviderCalls)) + ->method('getSharedWithByPath') + ->willReturnMap([ + ['user1', IShare::TYPE_USER, $path, true, -1, 0, $userShares], + ['user1', IShare::TYPE_GROUP, $path, true, -1, 0, $groupShares], + ['user1', IShare::TYPE_CIRCLE, $path, true, -1, 0, $circleShares], + ['user1', IShare::TYPE_ROOM, $path, true, -1, 0, $roomShares], + ['user1', IShare::TYPE_DECK, $path, true, -1, 0, $deckShares], + ]); + + $this->shareManager->expects($this->any()) + ->method('newShare') + ->willReturnCallback(function () use ($rootFolder, $userManager) { + return new Share($rootFolder, $userManager); + }); + + if ($moveFails) { + $this->shareManager->expects($this->any()) + ->method('moveShare') + ->willThrowException(new \InvalidArgumentException()); + } + + $mountArgs = []; + foreach ($expectedShares as $share) { + $mountInfo = $this->createMock(ICachedMountInfo::class); + $mountInfo->method('getUser')->willReturn($this->user); + $mountInfo->method('getRootId')->willReturn($share[1]); + $rootCacheEntry = $this->createMock(ICacheEntry::class); + $mountArg = new IMountProviderArgs($mountInfo, $rootCacheEntry); + $mountArgs[] = $mountArg; + } + + $mounts = $this->provider->getMountsForPath('/', true, $mountArgs, $this->loader); + + $this->assertCount(\count($expectedShares), $mounts); + + foreach (array_values($mounts) as $index => $mount) { + $expectedShare = $expectedShares[$index]; + $this->assertInstanceOf('OCA\Files_Sharing\SharedMount', $mount); + + // supershare + /** @var SharedMount $mount */ + $share = $mount->getShare(); + + $this->assertEquals($expectedShare[0], $share->getId()); + $this->assertEquals($expectedShare[1], $share->getNodeId()); + $this->assertEquals($expectedShare[2], $share->getShareOwner()); + $this->assertEquals($expectedShare[3], $share->getTarget()); + $this->assertEquals($expectedShare[4], $share->getPermissions()); + if ($expectedShare[5] === null) { + $this->assertNull($share->getAttributes()); + } else { + $this->assertEquals($expectedShare[5], $share->getAttributes()->toArray()); + } + } + } } From 94597b8757077192bbf4a028bfe738a3d3548edc Mon Sep 17 00:00:00 2001 From: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com> Date: Wed, 31 Dec 2025 12:37:09 +0100 Subject: [PATCH 2/7] feat: add indexes for target on share and share_external Signed-off-by: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com> --- .../Migration/Version11300Date20201120141438.php | 1 + core/Listener/AddMissingIndicesListener.php | 16 ++++++++++++++++ .../Version13000Date20170718121200.php | 2 +- 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/apps/files_sharing/lib/Migration/Version11300Date20201120141438.php b/apps/files_sharing/lib/Migration/Version11300Date20201120141438.php index 5530a3ad8ab08..e97f198a19322 100644 --- a/apps/files_sharing/lib/Migration/Version11300Date20201120141438.php +++ b/apps/files_sharing/lib/Migration/Version11300Date20201120141438.php @@ -85,6 +85,7 @@ public function changeSchema(IOutput $output, Closure $schemaClosure, array $opt ]); $table->setPrimaryKey(['id']); $table->addUniqueIndex(['user', 'mountpoint_hash'], 'sh_external_mp'); + $table->addIndex(['user', 'mountpoint'], 'user_mountpoint_index', [], ['lengths' => [null, 128]]); } else { $table = $schema->getTable('share_external'); $remoteIdColumn = $table->getColumn('remote_id'); diff --git a/core/Listener/AddMissingIndicesListener.php b/core/Listener/AddMissingIndicesListener.php index 1130165d870d7..98fc643bc0c3a 100644 --- a/core/Listener/AddMissingIndicesListener.php +++ b/core/Listener/AddMissingIndicesListener.php @@ -210,5 +210,21 @@ public function handle(Event $event): void { 'unique_category_per_user', ['uid', 'type', 'category'] ); + + $event->replaceIndex( + 'share', + ['share_with_index'], + 'share_with_file_target_index', + ['share_with', 'file_target'], + false, + ['lengths' => [null, 128]] + ); + + $event->addMissingIndex( + 'share_external', + 'user_mountpoint_index', + ['user', 'mountpoint'], + ['lengths' => [null, 128]] + ); } } diff --git a/core/Migrations/Version13000Date20170718121200.php b/core/Migrations/Version13000Date20170718121200.php index 9c58ba18b5174..c4f57980ad1eb 100644 --- a/core/Migrations/Version13000Date20170718121200.php +++ b/core/Migrations/Version13000Date20170718121200.php @@ -453,7 +453,7 @@ public function changeSchema(IOutput $output, \Closure $schemaClosure, array $op $table->addIndex(['item_type', 'share_type'], 'item_share_type_index'); $table->addIndex(['file_source'], 'file_source_index'); $table->addIndex(['token'], 'token_index'); - $table->addIndex(['share_with'], 'share_with_index'); + $table->addIndex(['share_with', 'file_target'], 'share_with_file_target_index', [], ['lengths' => [null, 128]]); $table->addIndex(['parent'], 'parent_index'); $table->addIndex(['uid_owner'], 'owner_index'); $table->addIndex(['uid_initiator'], 'initiator_index'); From efcdd85df0ecb5157c585475d6a24474c0aaf631 Mon Sep 17 00:00:00 2001 From: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com> Date: Fri, 2 Jan 2026 11:51:16 +0100 Subject: [PATCH 3/7] fix: make sure that ShareManager uses iterators Signed-off-by: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com> --- lib/private/Share20/Manager.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php index 466401d14377f..4a808c9923949 100644 --- a/lib/private/Share20/Manager.php +++ b/lib/private/Share20/Manager.php @@ -1309,6 +1309,8 @@ public function getSharedWithByPath(string $userId, int $shareType, string $path if (\is_array($shares)) { $shares = new ArrayIterator($shares); + } elseif (!$shares instanceof \Iterator) { + $shares = new \IteratorIterator($shares); } return new \CallbackFilterIterator($shares, function (IShare $share) { From 22e3437aae5fdbee1f1d4d87eb52b055942bf63c Mon Sep 17 00:00:00 2001 From: Louis Chmn Date: Thu, 8 Jan 2026 18:34:49 +0100 Subject: [PATCH 4/7] fixup! feat(files_sharing): implement partial mount providers Signed-off-by: Louis Chmn --- .../lib/External/MountProvider.php | 3 --- apps/files_sharing/lib/MountProvider.php | 18 +++++------------- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/apps/files_sharing/lib/External/MountProvider.php b/apps/files_sharing/lib/External/MountProvider.php index 549d4f3e79858..5fb8d653c2613 100644 --- a/apps/files_sharing/lib/External/MountProvider.php +++ b/apps/files_sharing/lib/External/MountProvider.php @@ -72,9 +72,6 @@ public function getMountsForUser(IUser $user, IStorageFactory $loader): array { return $mounts; } - /** - * @inheritDoc - */ public function getMountsForPath( string $path, bool $forChildren, diff --git a/apps/files_sharing/lib/MountProvider.php b/apps/files_sharing/lib/MountProvider.php index 5496506ad6eb5..7a512aec26f3c 100644 --- a/apps/files_sharing/lib/MountProvider.php +++ b/apps/files_sharing/lib/MountProvider.php @@ -356,9 +356,6 @@ private function filterShares(iterable $shares, string $userId): iterable { } } - /** - * @inheritdoc - */ public function getMountsForPath( string $path, bool $forChildren, @@ -397,16 +394,11 @@ public function getMountsForPath( } $shares = $this->mergeIterables( - $this->shareManager->getSharedWithByPath($userId, - IShare::TYPE_USER, $path, $forChildren, $limit), - $this->shareManager->getSharedWithByPath($userId, - IShare::TYPE_GROUP, $path, $forChildren, $limit), - $this->shareManager->getSharedWithByPath($userId, - IShare::TYPE_CIRCLE, $path, $forChildren, $limit), - $this->shareManager->getSharedWithByPath($userId, - IShare::TYPE_ROOM, $path, $forChildren, $limit), - $this->shareManager->getSharedWithByPath($userId, - IShare::TYPE_DECK, $path, $forChildren, $limit), + $this->shareManager->getSharedWithByPath($userId, IShare::TYPE_USER, $path, $forChildren, $limit), + $this->shareManager->getSharedWithByPath($userId, IShare::TYPE_GROUP, $path, $forChildren, $limit), + $this->shareManager->getSharedWithByPath($userId, IShare::TYPE_CIRCLE, $path, $forChildren, $limit), + $this->shareManager->getSharedWithByPath($userId, IShare::TYPE_ROOM, $path, $forChildren, $limit), + $this->shareManager->getSharedWithByPath($userId, IShare::TYPE_DECK, $path, $forChildren, $limit), ); $shares = $this->filterShares($shares, $userId); From 307976bebcda23302b9be374c863f34738c8060f Mon Sep 17 00:00:00 2001 From: Louis Chmn Date: Thu, 8 Jan 2026 18:36:27 +0100 Subject: [PATCH 5/7] chore(files_sharing): Minor syntax cleanups Signed-off-by: Louis Chmn --- apps/files_sharing/lib/MountProvider.php | 34 +++++++++++++----------- lib/private/Files/SetupManager.php | 3 +-- lib/private/Share20/Manager.php | 5 ++-- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/apps/files_sharing/lib/MountProvider.php b/apps/files_sharing/lib/MountProvider.php index 7a512aec26f3c..ed3f8925ec20f 100644 --- a/apps/files_sharing/lib/MountProvider.php +++ b/apps/files_sharing/lib/MountProvider.php @@ -64,9 +64,14 @@ public function getMountsForUser(IUser $user, IStorageFactory $loader) { $shares = $this->filterShares($shares, $userId); $superShares = $this->buildSuperShares($shares, $user); - return array_values($this->getMountsFromSuperShares($userId, - $superShares, - $loader, $user)); + return array_values( + $this->getMountsFromSuperShares( + $userId, + $superShares, + $loader, + $user + ), + ); } /** @@ -241,8 +246,7 @@ private function adjustTarget( // null groups which usually appear with group backend // caching inconsistencies $this->logger->debug( - 'Could not adjust share target for share ' . $share->getId( - ) . ' to make it consistent: ' . $e->getMessage(), + 'Could not adjust share target for share ' . $share->getId() . ' to make it consistent: ' . $e->getMessage(), ['app' => 'files_sharing'] ); } @@ -265,13 +269,11 @@ private function getMountsFromSuperShares( $mounts = []; $view = new View('/' . $userId . '/files'); $ownerViews = []; - $sharingDisabledForUser - = $this->shareManager->sharingDisabledForUser($userId); + $sharingDisabledForUser = $this->shareManager->sharingDisabledForUser($userId); /** @var CappedMemoryCache $folderExistCache */ $foldersExistCache = new CappedMemoryCache(); - $validShareCache - = $this->cacheFactory->createLocal('share-valid-mountpoint-max'); + $validShareCache = $this->cacheFactory->createLocal('share-valid-mountpoint-max'); $maxValidatedShare = $validShareCache->get($userId) ?? 0; $newMaxValidatedShare = $maxValidatedShare; @@ -316,12 +318,10 @@ private function getMountsFromSuperShares( $event = new ShareMountedEvent($mount); $this->eventDispatcher->dispatchTyped($event); - $mounts[$mount->getMountPoint()] - = $allMounts[$mount->getMountPoint()] = $mount; + $mounts[$mount->getMountPoint()] = $allMounts[$mount->getMountPoint()] = $mount; foreach ($event->getAdditionalMounts() as $additionalMount) { - $allMounts[$additionalMount->getMountPoint()] - = $mounts[$additionalMount->getMountPoint()] - = $additionalMount; + $mounts[$additionalMount->getMountPoint()] = $additionalMount; + $allMounts[$additionalMount->getMountPoint()] = $additionalMount; } } catch (Exception $e) { $this->logger->error( @@ -349,8 +349,10 @@ private function getMountsFromSuperShares( */ private function filterShares(iterable $shares, string $userId): iterable { foreach ($shares as $share) { - if ($share->getPermissions() > 0 && $share->getShareOwner() - !== $userId && $share->getSharedBy() !== $userId) { + if ( + $share->getPermissions() > 0 + && $share->getShareOwner() !== $userId && $share->getSharedBy() !== $userId + ) { yield $share; } } diff --git a/lib/private/Files/SetupManager.php b/lib/private/Files/SetupManager.php index 7f8bc2ed5485b..1537c327d6bb3 100644 --- a/lib/private/Files/SetupManager.php +++ b/lib/private/Files/SetupManager.php @@ -468,8 +468,7 @@ public function setupForPath(string $path, bool $includeChildren = false): void $mountProvider = $cachedMount->getMountProvider(); $mountPoint = $cachedMount->getMountPoint(); $isMountProviderSetup = in_array($mountProvider, $setupProviders); - $isPathSetupAsAuthoritative - = $this->isPathSetup($mountPoint); + $isPathSetupAsAuthoritative = $this->isPathSetup($mountPoint); if (!$isMountProviderSetup && !$isPathSetupAsAuthoritative) { if ($mountProvider === '') { $this->logger->debug('mount at ' . $cachedMount->getMountPoint() . ' has no provider set, performing full setup'); diff --git a/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php index 4a808c9923949..51aa9559d5a22 100644 --- a/lib/private/Share20/Manager.php +++ b/lib/private/Share20/Manager.php @@ -1299,12 +1299,13 @@ public function getSharedWithByPath(string $userId, int $shareType, string $path throw new \RuntimeException(\get_class($provider) . ' must implement IPartialShareProvider'); } - $shares = $provider->getSharedWithByPath($userId, + $shares = $provider->getSharedWithByPath( + $userId, $shareType, $path, $forChildren, $limit, - $offset + $offset, ); if (\is_array($shares)) { From 948431e1077ada6b9bb0e59b1db1619ad51fe887 Mon Sep 17 00:00:00 2001 From: Louis Chmn Date: Thu, 8 Jan 2026 18:36:43 +0100 Subject: [PATCH 6/7] CHECK TODOS Signed-off-by: Louis Chmn --- apps/files_sharing/lib/External/MountProvider.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/files_sharing/lib/External/MountProvider.php b/apps/files_sharing/lib/External/MountProvider.php index 5fb8d653c2613..5f86649f34015 100644 --- a/apps/files_sharing/lib/External/MountProvider.php +++ b/apps/files_sharing/lib/External/MountProvider.php @@ -95,7 +95,7 @@ public function getMountsForPath( if (!$forChildren) { // override path with mount point when fetching without children - $path = $mountProviderArgs[0]->mountInfo->getMountPoint(); + $path = $mountProviderArgs[0]->mountInfo->getMountPoint(); // TODO: not sure what this is doing, is this getting the parent path? } // remove /uid/files as the target is stored without @@ -132,7 +132,7 @@ public function getMountsForPath( return $arg->mountInfo->getMountPoint() === $mount->getMountPoint(); }); if (!$isRequestedMount) { - continue; + continue; // TODO: does it means something is off? because we have it in oc_share_external but not in oc_mounts } $mounts[$mount->getMountPoint()] = $mount; From e9711fb417b2d370708d5cffa7088656c481df93 Mon Sep 17 00:00:00 2001 From: Louis Chmn Date: Fri, 9 Jan 2026 13:48:06 +0100 Subject: [PATCH 7/7] fixup! chore(files_sharing): Minor syntax cleanups --- lib/private/Files/SetupManager.php | 34 +++++++++++++----------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/lib/private/Files/SetupManager.php b/lib/private/Files/SetupManager.php index 1537c327d6bb3..9910782f5ee25 100644 --- a/lib/private/Files/SetupManager.php +++ b/lib/private/Files/SetupManager.php @@ -495,8 +495,7 @@ public function setupForPath(string $path, bool $includeChildren = false): void } else { $currentProviders[] = $mountProvider; $setupProviders[] = $mountProvider; - $fullProviderMounts[] - = $this->mountProviderCollection->getUserMountsForProviderClasses($user, [$mountProvider]); + $fullProviderMounts[] = $this->mountProviderCollection->getUserMountsForProviderClasses($user, [$mountProvider]); } } @@ -504,11 +503,10 @@ public function setupForPath(string $path, bool $includeChildren = false): void $subCachedMounts = $this->userMountCache->getMountsInPath($user, $path); $this->eventLogger->end('fs:setup:user:path:find'); - $needsFullSetup - = array_any( - $subCachedMounts, - fn (ICachedMountInfo $info) => $info->getMountProvider() === '' - ); + $needsFullSetup = array_any( + $subCachedMounts, + fn (ICachedMountInfo $info) => $info->getMountProvider() === '' + ); if ($needsFullSetup) { $this->logger->debug('mount has no provider set, performing full setup'); @@ -541,11 +539,10 @@ public function setupForPath(string $path, bool $includeChildren = false): void $currentProviders[] = $mountProvider; $setupProviders[] = $mountProvider; - $fullProviderMounts[] - = $this->mountProviderCollection->getUserMountsForProviderClasses( - $user, - [$mountProvider] - ); + $fullProviderMounts[] = $this->mountProviderCollection->getUserMountsForProviderClasses( + $user, + [$mountProvider] + ); } if (!empty($authoritativeCachedMounts)) { @@ -572,13 +569,12 @@ static function (ICachedMountInfo $info) use ($rootsMetadata) { }, $cachedMounts )); - $authoritativeMounts[] - = $this->mountProviderCollection->getUserMountsFromProviderByPath( - $providerClass, - $path, - true, - $providerArgs, - ); + $authoritativeMounts[] = $this->mountProviderCollection->getUserMountsFromProviderByPath( + $providerClass, + $path, + true, + $providerArgs, + ); } } } else {