From f47a586cdd9090d3212ebbcc0746bd53e9a8b35c Mon Sep 17 00:00:00 2001 From: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com> Date: Mon, 24 Nov 2025 17:06:59 +0100 Subject: [PATCH 1/4] docs: update comments Signed-off-by: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com> --- .../Files/Config/MountProviderCollection.php | 3 +++ lib/private/Files/SetupManager.php | 13 +++++++++++-- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/lib/private/Files/Config/MountProviderCollection.php b/lib/private/Files/Config/MountProviderCollection.php index 9d63184e05fd4..a6e05eb1f8cb1 100644 --- a/lib/private/Files/Config/MountProviderCollection.php +++ b/lib/private/Files/Config/MountProviderCollection.php @@ -81,6 +81,9 @@ public function getMountsForUser(IUser $user): array { } /** + * Returns the mounts for the user from the specified provider classes. + * Providers not registered in the MountProviderCollection will be skipped. + * * @return list */ public function getUserMountsForProviderClasses(IUser $user, array $mountProviderClasses): array { diff --git a/lib/private/Files/SetupManager.php b/lib/private/Files/SetupManager.php index b92c608a81d25..e646dacf0bce9 100644 --- a/lib/private/Files/SetupManager.php +++ b/lib/private/Files/SetupManager.php @@ -60,7 +60,11 @@ class SetupManager { private array $setupUsers = []; // List of users for which all mounts are setup private array $setupUsersComplete = []; - /** @var array */ + /** + * An array of provider classes that have been set up, indexed by UserUID. + * + * @var array[]> + */ private array $setupUserMountProviders = []; private ICache $cache; private bool $listeningForProviders; @@ -213,7 +217,7 @@ public function setupForUser(IUser $user): void { } /** - * part of the user setup that is run only once per user + * Part of the user setup that is run only once per user. */ private function oneTimeUserSetup(IUser $user) { if ($this->isSetupStarted($user)) { @@ -303,11 +307,16 @@ private function afterUserFullySetup(IUser $user, array $previouslySetupProvider } /** + * Executes the one-time user setup and, if the user can access the + * filesystem, executes $mountCallback. + * * @param IUser $user * @param IMountPoint $mounts * @return void * @throws \OCP\HintException * @throws \OC\ServerNotAvailableException + * @see self::oneTimeUserSetup() + * */ private function setupForUserWith(IUser $user, callable $mountCallback): void { $this->oneTimeUserSetup($user); From 9b519b46796f0d481326ab8f9b616d52a9aa833a Mon Sep 17 00:00:00 2001 From: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com> Date: Thu, 4 Sep 2025 12:22:04 +0200 Subject: [PATCH 2/4] refactor: simplify code replace array_reduce + array_merge with array_merge(...) replace conditional assignment with ??= Signed-off-by: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com> --- lib/private/Files/Config/MountProviderCollection.php | 4 +--- lib/private/Files/SetupManager.php | 5 +---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/lib/private/Files/Config/MountProviderCollection.php b/lib/private/Files/Config/MountProviderCollection.php index a6e05eb1f8cb1..aa445a0879e6f 100644 --- a/lib/private/Files/Config/MountProviderCollection.php +++ b/lib/private/Files/Config/MountProviderCollection.php @@ -67,9 +67,7 @@ private function getUserMountsForProviders(IUser $user, array $providers): array $mounts = array_map(function (IMountProvider $provider) use ($user, $loader) { return $this->getMountsFromProvider($provider, $user, $loader); }, $providers); - $mounts = array_reduce($mounts, function (array $mounts, array $providerMounts) { - return array_merge($mounts, $providerMounts); - }, []); + $mounts = array_merge(...array_values($mounts)); return $this->filterMounts($user, $mounts); } diff --git a/lib/private/Files/SetupManager.php b/lib/private/Files/SetupManager.php index e646dacf0bce9..1911316ad3656 100644 --- a/lib/private/Files/SetupManager.php +++ b/lib/private/Files/SetupManager.php @@ -199,10 +199,7 @@ public function setupForUser(IUser $user): void { $this->eventLogger->start('fs:setup:user:full', 'Setup full filesystem for user'); - if (!isset($this->setupUserMountProviders[$user->getUID()])) { - $this->setupUserMountProviders[$user->getUID()] = []; - } - + $this->setupUserMountProviders[$user->getUID()] ??= []; $previouslySetupProviders = $this->setupUserMountProviders[$user->getUID()]; $this->setupForUserWith($user, function () use ($user) { From fcdb28e4a3de00221633bbb474ebb222d5371f6d Mon Sep 17 00:00:00 2001 From: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com> Date: Thu, 4 Sep 2025 16:25:37 +0200 Subject: [PATCH 3/4] feat: add IPartialMountProvider to support authoritative mounts IMountProviders implementing this interface will be able to take advantage of authoritative mounts. The function `getMountsFromMountPoints` will receive the path that the provider is asked to set-up and an array of IMountProviderArgs providing information regarding the stored mount points and the file cache data for the related root. The mount provider should verify the validity of the mounts and return IMountPoints related to them. Signed-off-by: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com> --- lib/composer/composer/autoload_classmap.php | 2 + lib/composer/composer/autoload_static.php | 2 + .../Files/Config/IMountProviderArgs.php | 24 +++++++++++ .../Files/Config/IPartialMountProvider.php | 43 +++++++++++++++++++ 4 files changed, 71 insertions(+) create mode 100644 lib/public/Files/Config/IMountProviderArgs.php create mode 100644 lib/public/Files/Config/IPartialMountProvider.php diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index f076862bfb081..98f4d5a9dcf15 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -420,7 +420,9 @@ 'OCP\\Files\\Config\\ICachedMountInfo' => $baseDir . '/lib/public/Files/Config/ICachedMountInfo.php', 'OCP\\Files\\Config\\IHomeMountProvider' => $baseDir . '/lib/public/Files/Config/IHomeMountProvider.php', 'OCP\\Files\\Config\\IMountProvider' => $baseDir . '/lib/public/Files/Config/IMountProvider.php', + 'OCP\\Files\\Config\\IMountProviderArgs' => $baseDir . '/lib/public/Files/Config/IMountProviderArgs.php', 'OCP\\Files\\Config\\IMountProviderCollection' => $baseDir . '/lib/public/Files/Config/IMountProviderCollection.php', + 'OCP\\Files\\Config\\IPartialMountProvider' => $baseDir . '/lib/public/Files/Config/IPartialMountProvider.php', 'OCP\\Files\\Config\\IRootMountProvider' => $baseDir . '/lib/public/Files/Config/IRootMountProvider.php', 'OCP\\Files\\Config\\IUserMountCache' => $baseDir . '/lib/public/Files/Config/IUserMountCache.php', 'OCP\\Files\\ConnectionLostException' => $baseDir . '/lib/public/Files/ConnectionLostException.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 9cfc877e3c29f..c463a93e9a3a3 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -461,7 +461,9 @@ class ComposerStaticInit749170dad3f5e7f9ca158f5a9f04f6a2 'OCP\\Files\\Config\\ICachedMountInfo' => __DIR__ . '/../../..' . '/lib/public/Files/Config/ICachedMountInfo.php', 'OCP\\Files\\Config\\IHomeMountProvider' => __DIR__ . '/../../..' . '/lib/public/Files/Config/IHomeMountProvider.php', 'OCP\\Files\\Config\\IMountProvider' => __DIR__ . '/../../..' . '/lib/public/Files/Config/IMountProvider.php', + 'OCP\\Files\\Config\\IMountProviderArgs' => __DIR__ . '/../../..' . '/lib/public/Files/Config/IMountProviderArgs.php', 'OCP\\Files\\Config\\IMountProviderCollection' => __DIR__ . '/../../..' . '/lib/public/Files/Config/IMountProviderCollection.php', + 'OCP\\Files\\Config\\IPartialMountProvider' => __DIR__ . '/../../..' . '/lib/public/Files/Config/IPartialMountProvider.php', 'OCP\\Files\\Config\\IRootMountProvider' => __DIR__ . '/../../..' . '/lib/public/Files/Config/IRootMountProvider.php', 'OCP\\Files\\Config\\IUserMountCache' => __DIR__ . '/../../..' . '/lib/public/Files/Config/IUserMountCache.php', 'OCP\\Files\\ConnectionLostException' => __DIR__ . '/../../..' . '/lib/public/Files/ConnectionLostException.php', diff --git a/lib/public/Files/Config/IMountProviderArgs.php b/lib/public/Files/Config/IMountProviderArgs.php new file mode 100644 index 0000000000000..b4c848f5f38ec --- /dev/null +++ b/lib/public/Files/Config/IMountProviderArgs.php @@ -0,0 +1,24 @@ + IMountPoint instances, indexed by + * mount-point + */ + public function getMountsForPath( + string $path, + array $mountProviderArgs, + IStorageFactory $loader, + ): array; +} From d14a03222044078f639cef8f59a526f8c7dffda1 Mon Sep 17 00:00:00 2001 From: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com> Date: Fri, 5 Sep 2025 13:28:27 +0200 Subject: [PATCH 4/4] feat: implement support for authoritative mount providers Signed-off-by: Salvatore Martire <4652631+salmart-dev@users.noreply.github.com> --- build/psalm-baseline.xml | 6 - build/stubs/php-polyfill.php | 3 + .../Files/Config/MountProviderCollection.php | 70 +++++-- lib/private/Files/SetupManager.php | 175 +++++++++++++++--- lib/private/Files/SetupManagerFactory.php | 3 + 5 files changed, 214 insertions(+), 43 deletions(-) diff --git a/build/psalm-baseline.xml b/build/psalm-baseline.xml index 75beecd1639ed..712dc3bc3bbb3 100644 --- a/build/psalm-baseline.xml +++ b/build/psalm-baseline.xml @@ -3641,12 +3641,6 @@ - - - - - - diff --git a/build/stubs/php-polyfill.php b/build/stubs/php-polyfill.php index 606a21f8dfeb3..2f85987b06c5c 100644 --- a/build/stubs/php-polyfill.php +++ b/build/stubs/php-polyfill.php @@ -7,3 +7,6 @@ // PHP 8.4 function array_find(array $array, callable $callback) {} +// PHP 8.5 +function array_any(array $array, callable $callback): bool {} + diff --git a/lib/private/Files/Config/MountProviderCollection.php b/lib/private/Files/Config/MountProviderCollection.php index aa445a0879e6f..24d2bf54a0960 100644 --- a/lib/private/Files/Config/MountProviderCollection.php +++ b/lib/private/Files/Config/MountProviderCollection.php @@ -9,16 +9,21 @@ use OC\Hooks\Emitter; use OC\Hooks\EmitterTrait; +use OCA\Files_Sharing\MountProvider; use OCP\Diagnostics\IEventLogger; use OCP\Files\Config\IHomeMountProvider; use OCP\Files\Config\IMountProvider; +use OCP\Files\Config\IMountProviderArgs; use OCP\Files\Config\IMountProviderCollection; +use OCP\Files\Config\IPartialMountProvider; use OCP\Files\Config\IRootMountProvider; use OCP\Files\Config\IUserMountCache; use OCP\Files\Mount\IMountManager; use OCP\Files\Mount\IMountPoint; use OCP\Files\Storage\IStorageFactory; use OCP\IUser; +use function get_class; +use function in_array; class MountProviderCollection implements IMountProviderCollection, Emitter { use EmitterTrait; @@ -29,7 +34,7 @@ class MountProviderCollection implements IMountProviderCollection, Emitter { private array $homeProviders = []; /** - * @var list + * @var array, IMountProvider> */ private array $providers = []; @@ -67,7 +72,7 @@ private function getUserMountsForProviders(IUser $user, array $providers): array $mounts = array_map(function (IMountProvider $provider) use ($user, $loader) { return $this->getMountsFromProvider($provider, $user, $loader); }, $providers); - $mounts = array_merge(...array_values($mounts)); + $mounts = array_merge(...$mounts); return $this->filterMounts($user, $mounts); } @@ -75,21 +80,53 @@ private function getUserMountsForProviders(IUser $user, array $providers): array * @return list */ public function getMountsForUser(IUser $user): array { - return $this->getUserMountsForProviders($user, $this->providers); + return $this->getUserMountsForProviders($user, array_values($this->providers)); + } + + /** + * @param IMountProviderArgs[] $mountProviderArgs + * @return array IMountPoint array indexed by mount + * point. + */ + public function getUserMountsFromProviderByPath( + string $providerClass, + string $path, + array $mountProviderArgs, + ): array { + $provider = $this->providers[$providerClass] ?? null; + if ($provider === null) { + return []; + } + + if (!is_a($providerClass, IPartialMountProvider::class, true)) { + throw new \LogicException( + 'Mount provider does not support partial mounts' + ); + } + + /** @var IPartialMountProvider $provider */ + return $provider->getMountsForPath( + $path, + $mountProviderArgs, + $this->loader, + ); } /** * Returns the mounts for the user from the specified provider classes. * Providers not registered in the MountProviderCollection will be skipped. * + * @inheritdoc + * * @return list */ public function getUserMountsForProviderClasses(IUser $user, array $mountProviderClasses): array { $providers = array_filter( $this->providers, - fn (IMountProvider $mountProvider) => (in_array(get_class($mountProvider), $mountProviderClasses)) + fn (string $providerClass) => in_array($providerClass, $mountProviderClasses), + ARRAY_FILTER_USE_KEY ); - return $this->getUserMountsForProviders($user, $providers); + return $this->getUserMountsForProviders($user, array_values($providers)); } /** @@ -100,16 +137,21 @@ public function addMountForUser(IUser $user, IMountManager $mountManager, ?calla // to check for name collisions $firstMounts = []; if ($providerFilter) { - $providers = array_filter($this->providers, $providerFilter); + $providers = array_filter($this->providers, $providerFilter, ARRAY_FILTER_USE_KEY); } else { $providers = $this->providers; } - $firstProviders = array_filter($providers, function (IMountProvider $provider) { - return (get_class($provider) !== 'OCA\Files_Sharing\MountProvider'); - }); - $lastProviders = array_filter($providers, function (IMountProvider $provider) { - return (get_class($provider) === 'OCA\Files_Sharing\MountProvider'); - }); + $firstProviders + = array_filter( + $providers, + fn (string $providerClass) => ($providerClass !== MountProvider::class), + ARRAY_FILTER_USE_KEY + ); + $lastProviders = array_filter( + $providers, + fn (string $providerClass) => $providerClass === MountProvider::class, + ARRAY_FILTER_USE_KEY + ); foreach ($firstProviders as $provider) { $mounts = $this->getMountsFromProvider($provider, $user, $this->loader); $firstMounts = array_merge($firstMounts, $mounts); @@ -151,7 +193,7 @@ public function getHomeMountForUser(IUser $user): IMountPoint { * Add a provider for mount points */ public function registerProvider(IMountProvider $provider): void { - $this->providers[] = $provider; + $this->providers[get_class($provider)] = $provider; $this->emit('\OC\Files\Config', 'registerMountProvider', [$provider]); } @@ -229,7 +271,7 @@ public function clearProviders(): void { * @return list */ public function getProviders(): array { - return $this->providers; + return array_values($this->providers); } /** diff --git a/lib/private/Files/SetupManager.php b/lib/private/Files/SetupManager.php index 1911316ad3656..3c0cdfe21236c 100644 --- a/lib/private/Files/SetupManager.php +++ b/lib/private/Files/SetupManager.php @@ -8,6 +8,7 @@ namespace OC\Files; +use OC\Files\Cache\FileAccess; use OC\Files\Config\MountProviderCollection; use OC\Files\Mount\HomeMountPoint; use OC\Files\Mount\MountPoint; @@ -33,6 +34,8 @@ use OCP\Files\Config\ICachedMountInfo; use OCP\Files\Config\IHomeMountProvider; use OCP\Files\Config\IMountProvider; +use OCP\Files\Config\IMountProviderArgs; +use OCP\Files\Config\IPartialMountProvider; use OCP\Files\Config\IRootMountProvider; use OCP\Files\Config\IUserMountCache; use OCP\Files\Events\BeforeFileSystemSetupEvent; @@ -53,6 +56,10 @@ use OCP\Lockdown\ILockdownManager; use OCP\Share\Events\ShareCreatedEvent; use Psr\Log\LoggerInterface; +use function array_key_exists; +use function count; +use function dirname; +use function in_array; class SetupManager { private bool $rootSetup = false; @@ -66,11 +73,19 @@ class SetupManager { * @var array[]> */ private array $setupUserMountProviders = []; + /** + * An array of paths that have already been set up + * + * @var array + */ + private array $setupMountProviderPaths = []; private ICache $cache; private bool $listeningForProviders; private array $fullSetupRequired = []; private bool $setupBuiltinWrappersDone = false; private bool $forceFullSetup = false; + private const SETUP_WITH_CHILDREN = 1; + private const SETUP_WITHOUT_CHILDREN = 0; public function __construct( private IEventLogger $eventLogger, @@ -86,6 +101,7 @@ public function __construct( private IConfig $config, private ShareDisableChecker $shareDisableChecker, private IAppManager $appManager, + private FileAccess $fileAccess, ) { $this->cache = $cacheFactory->createDistributed('setupmanager::'); $this->listeningForProviders = false; @@ -102,6 +118,27 @@ public function isSetupComplete(IUser $user): bool { return in_array($user->getUID(), $this->setupUsersComplete, true); } + /** + * Checks if a path has been cached either directly or through a full setup + * of one of its parents. + */ + private function isPathSetup(string $path): bool { + // if the exact path was already setup with or without children + if (array_key_exists($path, $this->setupMountProviderPaths)) { + return true; + } + + // or if any of the ancestors was fully setup + while (($path = dirname($path)) !== '/') { + $setupPath = $this->setupMountProviderPaths[$path] ?? null; + if ($setupPath === self::SETUP_WITH_CHILDREN) { + return true; + } + } + + return false; + } + private function setupBuiltinWrappers() { if ($this->setupBuiltinWrappersDone) { return; @@ -204,9 +241,9 @@ public function setupForUser(IUser $user): void { $this->setupForUserWith($user, function () use ($user) { $this->mountProviderCollection->addMountForUser($user, $this->mountManager, function ( - IMountProvider $provider, + string $providerClass, ) use ($user) { - return !in_array(get_class($provider), $this->setupUserMountProviders[$user->getUID()]); + return !in_array($providerClass, $this->setupUserMountProviders[$user->getUID()]); }); }); $this->afterUserFullySetup($user, $previouslySetupProviders); @@ -379,7 +416,8 @@ private function getUserForPath(string $path) { } /** - * Set up the filesystem for the specified path + * Set up the filesystem for the specified path, optionally including all + * children mounts. */ public function setupForPath(string $path, bool $includeChildren = false): void { $user = $this->getUserForPath($path); @@ -421,51 +459,141 @@ public function setupForPath(string $path, bool $includeChildren = false): void $this->eventLogger->start('fs:setup:user:path', "Setup $path filesystem for user"); $this->eventLogger->start('fs:setup:user:path:find', "Find mountpoint for $path"); - $mounts = []; - if (!in_array($cachedMount->getMountProvider(), $setupProviders)) { - $currentProviders[] = $cachedMount->getMountProvider(); - if ($cachedMount->getMountProvider()) { - $setupProviders[] = $cachedMount->getMountProvider(); - $mounts = $this->mountProviderCollection->getUserMountsForProviderClasses($user, [$cachedMount->getMountProvider()]); - } else { + $fullProviderMounts = []; + $authoritativeMounts = []; + + $mountProvider = $cachedMount->getMountProvider(); + $mountPoint = $cachedMount->getMountPoint(); + $isMountProviderSetup = in_array($mountProvider, $setupProviders); + $isPathSetupAsAuthoritative + = $this->isPathSetup($mountPoint); + if (!$isMountProviderSetup && !$isPathSetupAsAuthoritative) { + if ($mountProvider === '') { $this->logger->debug('mount at ' . $cachedMount->getMountPoint() . ' has no provider set, performing full setup'); $this->eventLogger->end('fs:setup:user:path:find'); $this->setupForUser($user); $this->eventLogger->end('fs:setup:user:path'); return; } + + if (is_a($mountProvider, IPartialMountProvider::class, true)) { + $rootId = $cachedMount->getRootId(); + $rootMetadata = $this->fileAccess->getByFileId($rootId); + $providerArgs = new IMountProviderArgs($cachedMount, $rootMetadata); + // mark the path as cached (without children for now...) + $cacheKey = rtrim($mountPoint, '/'); + $this->setupMountProviderPaths[$cacheKey] = self::SETUP_WITHOUT_CHILDREN; + $authoritativeMounts[] = array_values( + $this->mountProviderCollection->getUserMountsFromProviderByPath( + $mountProvider, + $path, + [$providerArgs] + ) + ); + } else { + $currentProviders[] = $mountProvider; + $setupProviders[] = $mountProvider; + $fullProviderMounts[] + = $this->mountProviderCollection->getUserMountsForProviderClasses($user, [$mountProvider]); + } } if ($includeChildren) { $subCachedMounts = $this->userMountCache->getMountsInPath($user, $path); $this->eventLogger->end('fs:setup:user:path:find'); - $needsFullSetup = array_reduce($subCachedMounts, function (bool $needsFullSetup, ICachedMountInfo $cachedMountInfo) { - return $needsFullSetup || $cachedMountInfo->getMountProvider() === ''; - }, false); + $needsFullSetup + = array_any( + $subCachedMounts, + fn (ICachedMountInfo $info) => $info->getMountProvider() === '' + ); if ($needsFullSetup) { $this->logger->debug('mount has no provider set, performing full setup'); $this->setupForUser($user); $this->eventLogger->end('fs:setup:user:path'); return; - } else { - foreach ($subCachedMounts as $cachedMount) { - if (!in_array($cachedMount->getMountProvider(), $setupProviders)) { - $currentProviders[] = $cachedMount->getMountProvider(); - $setupProviders[] = $cachedMount->getMountProvider(); - $mounts = array_merge($mounts, $this->mountProviderCollection->getUserMountsForProviderClasses($user, [$cachedMount->getMountProvider()])); + } + + /** @var array, ICachedMountInfo[]> $authoritativeCachedMounts */ + $authoritativeCachedMounts = []; + foreach ($subCachedMounts as $cachedMount) { + /** @var class-string $mountProvider */ + $mountProvider = $cachedMount->getMountProvider(); + + // skip setup for already set up providers + if (in_array($mountProvider, $setupProviders)) { + continue; + } + + if (is_a($mountProvider, IPartialMountProvider::class, true)) { + // skip setup if path was set up as authoritative before + if ($this->isPathSetup($cachedMount->getMountPoint())) { + continue; } + // collect cached mount points for authoritative providers + $authoritativeCachedMounts[$mountProvider] ??= []; + $authoritativeCachedMounts[$mountProvider][] = $cachedMount; + continue; + } + + $currentProviders[] = $mountProvider; + $setupProviders[] = $mountProvider; + $fullProviderMounts[] + = $this->mountProviderCollection->getUserMountsForProviderClasses( + $user, + [$mountProvider] + ); + } + + if (!empty($authoritativeCachedMounts)) { + $rootIds = array_map( + fn (ICachedMountInfo $mount) => $mount->getRootId(), + array_merge(...array_values($authoritativeCachedMounts)), + ); + + $rootsMetadata = []; + foreach (array_chunk($rootIds, 1000) as $chunk) { + foreach ($this->fileAccess->getByFileIds($chunk) as $id => $fileMetadata) { + $rootsMetadata[$id] = $fileMetadata; + } + } + $cacheKey = rtrim($mountPoint, '/'); + $this->setupMountProviderPaths[$cacheKey] = self::SETUP_WITH_CHILDREN; + foreach ($authoritativeCachedMounts as $providerClass => $cachedMounts) { + $providerArgs = array_filter(array_map( + static function (ICachedMountInfo $info) use ($rootsMetadata) { + $rootMetadata = $rootsMetadata[$info->getRootId()] ?? null; + + return $rootMetadata + ? new IMountProviderArgs($info, $rootMetadata) + : null; + }, + $cachedMounts + )); + $authoritativeMounts[] + = $this->mountProviderCollection->getUserMountsFromProviderByPath( + $providerClass, + $path, + $providerArgs, + ); } } } else { $this->eventLogger->end('fs:setup:user:path:find'); } - if (count($mounts)) { - $this->registerMounts($user, $mounts, $currentProviders); - $this->setupForUserWith($user, function () use ($mounts) { - array_walk($mounts, [$this->mountManager, 'addMount']); + $fullProviderMounts = array_merge(...$fullProviderMounts); + $authoritativeMounts = array_merge(...$authoritativeMounts); + + if (count($fullProviderMounts) || count($authoritativeMounts)) { + if (count($fullProviderMounts)) { + $this->registerMounts($user, $fullProviderMounts, $currentProviders); + } + + $this->setupForUserWith($user, function () use ($fullProviderMounts, $authoritativeMounts) { + $allMounts = [...$fullProviderMounts, ...$authoritativeMounts]; + array_walk($allMounts, $this->mountManager->addMount(...)); }); } elseif (!$this->isSetupStarted($user)) { $this->oneTimeUserSetup($user); @@ -545,6 +673,7 @@ public function tearDown() { $this->setupUsers = []; $this->setupUsersComplete = []; $this->setupUserMountProviders = []; + $this->setupMountProviderPaths = []; $this->fullSetupRequired = []; $this->rootSetup = false; $this->mountManager->clear(); diff --git a/lib/private/Files/SetupManagerFactory.php b/lib/private/Files/SetupManagerFactory.php index d2fe978fa9e63..369e3089017f0 100644 --- a/lib/private/Files/SetupManagerFactory.php +++ b/lib/private/Files/SetupManagerFactory.php @@ -8,6 +8,7 @@ namespace OC\Files; +use OC\Files\Cache\FileAccess; use OC\Share20\ShareDisableChecker; use OCP\App\IAppManager; use OCP\Diagnostics\IEventLogger; @@ -38,6 +39,7 @@ public function __construct( private IConfig $config, private ShareDisableChecker $shareDisableChecker, private IAppManager $appManager, + private FileAccess $fileAccess, ) { $this->setupManager = null; } @@ -58,6 +60,7 @@ public function create(IMountManager $mountManager): SetupManager { $this->config, $this->shareDisableChecker, $this->appManager, + $this->fileAccess, ); } return $this->setupManager;