diff options
author | Robin Appelman <robin@icewind.nl> | 2022-03-08 14:50:25 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-03-08 14:50:25 +0000 |
commit | e8872f01ae850bcbf66220beba44463f68e3d673 (patch) | |
tree | 9b2b1d01992d26368ff456af0440d0a2965308a6 /lib | |
parent | 23e8ae15aaea30359a927492155de13c97b311ce (diff) | |
parent | 917c74e214094e321ff96e1aa067ae60d22e2c58 (diff) | |
download | nextcloud-server-e8872f01ae850bcbf66220beba44463f68e3d673.tar.gz nextcloud-server-e8872f01ae850bcbf66220beba44463f68e3d673.zip |
Merge pull request #31431 from nextcloud/fs-setup-manager
Unify/cleanup filesystem setup
Diffstat (limited to 'lib')
19 files changed, 569 insertions, 424 deletions
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 6fd3d9207db..86efab3ad52 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -271,6 +271,7 @@ return array( 'OCP\\Files\\Events\\Node\\BeforeNodeRenamedEvent' => $baseDir . '/lib/public/Files/Events/Node/BeforeNodeRenamedEvent.php', 'OCP\\Files\\Events\\Node\\BeforeNodeTouchedEvent' => $baseDir . '/lib/public/Files/Events/Node/BeforeNodeTouchedEvent.php', 'OCP\\Files\\Events\\Node\\BeforeNodeWrittenEvent' => $baseDir . '/lib/public/Files/Events/Node/BeforeNodeWrittenEvent.php', + 'OCP\\Files\\Events\\Node\\FilesystemTornDownEvent' => $baseDir . '/lib/public/Files/Events/Node/FilesystemTornDownEvent.php', 'OCP\\Files\\Events\\Node\\NodeCopiedEvent' => $baseDir . '/lib/public/Files/Events/Node/NodeCopiedEvent.php', 'OCP\\Files\\Events\\Node\\NodeCreatedEvent' => $baseDir . '/lib/public/Files/Events/Node/NodeCreatedEvent.php', 'OCP\\Files\\Events\\Node\\NodeDeletedEvent' => $baseDir . '/lib/public/Files/Events/Node/NodeDeletedEvent.php', @@ -1162,6 +1163,8 @@ return array( 'OC\\Files\\Search\\SearchComparison' => $baseDir . '/lib/private/Files/Search/SearchComparison.php', 'OC\\Files\\Search\\SearchOrder' => $baseDir . '/lib/private/Files/Search/SearchOrder.php', 'OC\\Files\\Search\\SearchQuery' => $baseDir . '/lib/private/Files/Search/SearchQuery.php', + 'OC\\Files\\SetupManager' => $baseDir . '/lib/private/Files/SetupManager.php', + 'OC\\Files\\SetupManagerFactory' => $baseDir . '/lib/private/Files/SetupManagerFactory.php', 'OC\\Files\\SimpleFS\\NewSimpleFile' => $baseDir . '/lib/private/Files/SimpleFS/NewSimpleFile.php', 'OC\\Files\\SimpleFS\\SimpleFile' => $baseDir . '/lib/private/Files/SimpleFS/SimpleFile.php', 'OC\\Files\\SimpleFS\\SimpleFolder' => $baseDir . '/lib/private/Files/SimpleFS/SimpleFolder.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index c8c0e7df381..ea37771d63c 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -300,6 +300,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OCP\\Files\\Events\\Node\\BeforeNodeRenamedEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Events/Node/BeforeNodeRenamedEvent.php', 'OCP\\Files\\Events\\Node\\BeforeNodeTouchedEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Events/Node/BeforeNodeTouchedEvent.php', 'OCP\\Files\\Events\\Node\\BeforeNodeWrittenEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Events/Node/BeforeNodeWrittenEvent.php', + 'OCP\\Files\\Events\\Node\\FilesystemTornDownEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Events/Node/FilesystemTornDownEvent.php', 'OCP\\Files\\Events\\Node\\NodeCopiedEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Events/Node/NodeCopiedEvent.php', 'OCP\\Files\\Events\\Node\\NodeCreatedEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Events/Node/NodeCreatedEvent.php', 'OCP\\Files\\Events\\Node\\NodeDeletedEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Events/Node/NodeDeletedEvent.php', @@ -1191,6 +1192,8 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OC\\Files\\Search\\SearchComparison' => __DIR__ . '/../../..' . '/lib/private/Files/Search/SearchComparison.php', 'OC\\Files\\Search\\SearchOrder' => __DIR__ . '/../../..' . '/lib/private/Files/Search/SearchOrder.php', 'OC\\Files\\Search\\SearchQuery' => __DIR__ . '/../../..' . '/lib/private/Files/Search/SearchQuery.php', + 'OC\\Files\\SetupManager' => __DIR__ . '/../../..' . '/lib/private/Files/SetupManager.php', + 'OC\\Files\\SetupManagerFactory' => __DIR__ . '/../../..' . '/lib/private/Files/SetupManagerFactory.php', 'OC\\Files\\SimpleFS\\NewSimpleFile' => __DIR__ . '/../../..' . '/lib/private/Files/SimpleFS/NewSimpleFile.php', 'OC\\Files\\SimpleFS\\SimpleFile' => __DIR__ . '/../../..' . '/lib/private/Files/SimpleFS/SimpleFile.php', 'OC\\Files\\SimpleFS\\SimpleFolder' => __DIR__ . '/../../..' . '/lib/private/Files/SimpleFS/SimpleFolder.php', diff --git a/lib/private/Cache/CappedMemoryCache.php b/lib/private/Cache/CappedMemoryCache.php index 584a53f0ff2..9260bf1f6b3 100644 --- a/lib/private/Cache/CappedMemoryCache.php +++ b/lib/private/Cache/CappedMemoryCache.php @@ -27,30 +27,42 @@ use OCP\ICache; * In-memory cache with a capacity limit to keep memory usage in check * * Uses a simple FIFO expiry mechanism + * @template T */ class CappedMemoryCache implements ICache, \ArrayAccess { private $capacity; + /** @var T[] */ private $cache = []; public function __construct($capacity = 512) { $this->capacity = $capacity; } - public function hasKey($key) { + public function hasKey($key): bool { return isset($this->cache[$key]); } + /** + * @return ?T + */ public function get($key) { - return isset($this->cache[$key]) ? $this->cache[$key] : null; + return $this->cache[$key] ?? null; } - public function set($key, $value, $ttl = 0) { + /** + * @param string $key + * @param T $value + * @param int $ttl + * @return bool + */ + public function set($key, $value, $ttl = 0): bool { if (is_null($key)) { $this->cache[] = $value; } else { $this->cache[$key] = $value; } $this->garbageCollect(); + return true; } public function remove($key) { @@ -68,13 +80,18 @@ class CappedMemoryCache implements ICache, \ArrayAccess { } /** - * @return mixed + * @return T */ #[\ReturnTypeWillChange] public function &offsetGet($offset) { return $this->cache[$offset]; } + /** + * @param string $key + * @param T $value + * @return void + */ public function offsetSet($offset, $value): void { $this->set($offset, $value); } @@ -83,6 +100,9 @@ class CappedMemoryCache implements ICache, \ArrayAccess { $this->remove($offset); } + /** + * @return T[] + */ public function getData() { return $this->cache; } diff --git a/lib/private/Files/Config/CachedMountFileInfo.php b/lib/private/Files/Config/CachedMountFileInfo.php index 71a6ddb9ea9..11a9a505808 100644 --- a/lib/private/Files/Config/CachedMountFileInfo.php +++ b/lib/private/Files/Config/CachedMountFileInfo.php @@ -27,8 +27,7 @@ use OCP\Files\Config\ICachedMountFileInfo; use OCP\IUser; class CachedMountFileInfo extends CachedMountInfo implements ICachedMountFileInfo { - /** @var string */ - private $internalPath; + private string $internalPath; public function __construct( IUser $user, diff --git a/lib/private/Files/Config/CachedMountInfo.php b/lib/private/Files/Config/CachedMountInfo.php index c70dba100a4..43c9fae63ec 100644 --- a/lib/private/Files/Config/CachedMountInfo.php +++ b/lib/private/Files/Config/CachedMountInfo.php @@ -28,38 +28,13 @@ use OCP\Files\Node; use OCP\IUser; class CachedMountInfo implements ICachedMountInfo { - /** - * @var IUser - */ - protected $user; - - /** - * @var int - */ - protected $storageId; - - /** - * @var int - */ - protected $rootId; - - /** - * @var string - */ - protected $mountPoint; - - /** - * @var int|null - */ - protected $mountId; - - /** - * @var string - */ - protected $rootInternalPath; - - /** @var string */ - protected $mountProvider; + protected IUser $user; + protected int $storageId; + protected int $rootId; + protected string $mountPoint; + protected ?int $mountId; + protected string $rootInternalPath; + protected string $mountProvider; /** * CachedMountInfo constructor. @@ -95,28 +70,28 @@ class CachedMountInfo implements ICachedMountInfo { /** * @return IUser */ - public function getUser() { + public function getUser(): IUser { return $this->user; } /** * @return int the numeric storage id of the mount */ - public function getStorageId() { + public function getStorageId(): int { return $this->storageId; } /** * @return int the fileid of the root of the mount */ - public function getRootId() { + public function getRootId(): int { return $this->rootId; } /** - * @return Node the root node of the mount + * @return Node|null the root node of the mount */ - public function getMountPointNode() { + public function getMountPointNode(): ?Node { // TODO injection etc Filesystem::initMountPoints($this->getUser()->getUID()); $userNode = \OC::$server->getUserFolder($this->getUser()->getUID()); @@ -131,7 +106,7 @@ class CachedMountInfo implements ICachedMountInfo { /** * @return string the mount point of the mount for the user */ - public function getMountPoint() { + public function getMountPoint(): string { return $this->mountPoint; } @@ -141,7 +116,7 @@ class CachedMountInfo implements ICachedMountInfo { * @return int|null mount id or null if not applicable * @since 9.1.0 */ - public function getMountId() { + public function getMountId(): ?int { return $this->mountId; } @@ -150,7 +125,7 @@ class CachedMountInfo implements ICachedMountInfo { * * @return string */ - public function getRootInternalPath() { + public function getRootInternalPath(): string { return $this->rootInternalPath; } diff --git a/lib/private/Files/Config/LazyStorageMountInfo.php b/lib/private/Files/Config/LazyStorageMountInfo.php index fd3bbcbe0fb..78055a2cdb8 100644 --- a/lib/private/Files/Config/LazyStorageMountInfo.php +++ b/lib/private/Files/Config/LazyStorageMountInfo.php @@ -25,8 +25,7 @@ use OCP\Files\Mount\IMountPoint; use OCP\IUser; class LazyStorageMountInfo extends CachedMountInfo { - /** @var IMountPoint */ - private $mount; + private IMountPoint $mount; /** * CachedMountInfo constructor. @@ -37,12 +36,15 @@ class LazyStorageMountInfo extends CachedMountInfo { public function __construct(IUser $user, IMountPoint $mount) { $this->user = $user; $this->mount = $mount; + $this->rootId = 0; + $this->storageId = 0; + $this->mountPoint = ''; } /** * @return int the numeric storage id of the mount */ - public function getStorageId() { + public function getStorageId(): int { if (!$this->storageId) { $this->storageId = $this->mount->getNumericStorageId(); } @@ -52,7 +54,7 @@ class LazyStorageMountInfo extends CachedMountInfo { /** * @return int the fileid of the root of the mount */ - public function getRootId() { + public function getRootId(): int { if (!$this->rootId) { $this->rootId = $this->mount->getStorageRootId(); } @@ -62,14 +64,14 @@ class LazyStorageMountInfo extends CachedMountInfo { /** * @return string the mount point of the mount for the user */ - public function getMountPoint() { + public function getMountPoint(): string { if (!$this->mountPoint) { $this->mountPoint = $this->mount->getMountPoint(); } return parent::getMountPoint(); } - public function getMountId() { + public function getMountId(): ?int { return $this->mount->getMountId(); } @@ -78,7 +80,7 @@ class LazyStorageMountInfo extends CachedMountInfo { * * @return string */ - public function getRootInternalPath() { + public function getRootInternalPath(): string { return $this->mount->getInternalPath($this->mount->getMountPoint()); } diff --git a/lib/private/Files/Config/MountProviderCollection.php b/lib/private/Files/Config/MountProviderCollection.php index ba70e29ab8d..cd8a2a2e29f 100644 --- a/lib/private/Files/Config/MountProviderCollection.php +++ b/lib/private/Files/Config/MountProviderCollection.php @@ -184,16 +184,6 @@ class MountProviderCollection implements IMountProviderCollection, Emitter { } /** - * Cache mounts for user - * - * @param IUser $user - * @param IMountPoint[] $mountPoints - */ - public function registerMounts(IUser $user, array $mountPoints) { - $this->mountCache->registerMounts($user, $mountPoints); - } - - /** * Get the mount cache which can be used to search for mounts without setting up the filesystem * * @return IUserMountCache @@ -222,4 +212,10 @@ class MountProviderCollection implements IMountProviderCollection, Emitter { }, []); return $mounts; } + + public function clearProviders() { + $this->providers = []; + $this->homeProviders = []; + $this->rootProviders = []; + } } diff --git a/lib/private/Files/Filesystem.php b/lib/private/Files/Filesystem.php index e439b746bf6..1aedad93aa1 100644 --- a/lib/private/Files/Filesystem.php +++ b/lib/private/Files/Filesystem.php @@ -38,13 +38,12 @@ namespace OC\Files; use OC\Cache\CappedMemoryCache; -use OC\Files\Config\MountProviderCollection; use OC\Files\Mount\MountPoint; -use OC\Lockdown\Filesystem\NullStorage; -use OCP\Files\Config\IMountProvider; +use OC\User\NoUserException; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\Events\Node\FilesystemTornDownEvent; use OCP\Files\NotFoundException; use OCP\Files\Storage\IStorageFactory; -use OCP\ILogger; use OCP\IUser; use OCP\IUserManager; @@ -259,11 +258,7 @@ class Filesystem { \OC_Util::setupFS(); } $mount = self::$mounts->find($path); - if ($mount) { - return $mount->getMountPoint(); - } else { - return ''; - } + return $mount->getMountPoint(); } /** @@ -319,11 +314,7 @@ class Filesystem { */ public static function resolvePath($path) { $mount = self::getMountManager()->find($path); - if ($mount) { - return [$mount->getStorage(), rtrim($mount->getInternalPath($path), '/')]; - } else { - return [null, null]; - } + return [$mount->getStorage(), rtrim($mount->getInternalPath($path), '/')]; } public static function init($user, $root) { @@ -332,6 +323,13 @@ class Filesystem { } self::getLoader(); self::$defaultInstance = new View($root); + /** @var IEventDispatcher $eventDispatcher */ + $eventDispatcher = \OC::$server->get(IEventDispatcher::class); + $eventDispatcher->addListener(FilesystemTornDownEvent::class, function () { + self::$defaultInstance = null; + self::$usersSetup = []; + self::$loaded = false; + }); if (!self::$mounts) { self::$mounts = \OC::$server->getMountManager(); @@ -358,106 +356,16 @@ class Filesystem { * @throws \OC\User\NoUserException if the user is not available */ public static function initMountPoints($user = '') { - $userManager = \OC::$server->getUserManager(); - if (is_string($user)) { - if ($user === '') { - $user = \OC_User::getUser(); - } - - $userObject = $userManager->get($user); - } elseif ($user instanceof IUser) { - $userObject = $user; - $user = $userObject->getUID(); - } else { - $userObject = null; - } - - if ($userObject === null || $user === false || $user === '') { - throw new \OC\User\NoUserException('Attempted to initialize mount points for null user and no user in session'); - } - - if (isset(self::$usersSetup[$user])) { - return; - } - - self::$usersSetup[$user] = true; - - if (is_null($userObject)) { - \OCP\Util::writeLog('files', ' Backends provided no user object for ' . $user, ILogger::ERROR); - // reset flag, this will make it possible to rethrow the exception if called again - unset(self::$usersSetup[$user]); - throw new \OC\User\NoUserException('Backends provided no user object for ' . $user); - } - - $realUid = $userObject->getUID(); - // workaround in case of different casings - if ($user !== $realUid) { - $stack = json_encode(debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 50)); - \OCP\Util::writeLog('files', 'initMountPoints() called with wrong user casing. This could be a bug. Expected: "' . $realUid . '" got "' . $user . '". Stack: ' . $stack, ILogger::WARN); - $user = $realUid; - - // again with the correct casing - if (isset(self::$usersSetup[$user])) { - return; - } - - self::$usersSetup[$user] = true; - } - - if (\OC::$server->getLockdownManager()->canAccessFilesystem()) { - /** @var \OC\Files\Config\MountProviderCollection $mountConfigManager */ - $mountConfigManager = \OC::$server->getMountProviderCollection(); - - // home mounts are handled seperate since we need to ensure this is mounted before we call the other mount providers - $homeMount = $mountConfigManager->getHomeMountForUser($userObject); - self::getMountManager()->addMount($homeMount); - - if ($homeMount->getStorageRootId() === -1) { - $homeMount->getStorage()->mkdir(''); - $homeMount->getStorage()->getScanner()->scan(''); - } - - \OC\Files\Filesystem::getStorage($user); - - // Chance to mount for other storages - if ($userObject) { - $mounts = $mountConfigManager->addMountForUser($userObject, self::getMountManager()); - $mounts[] = $homeMount; - $mountConfigManager->registerMounts($userObject, $mounts); - } - - self::listenForNewMountProviders($mountConfigManager, $userManager); + /** @var IUserManager $userManager */ + $userManager = \OC::$server->get(IUserManager::class); + + $userObject = ($user instanceof IUser) ? $user : $userManager->get($user); + if ($userObject) { + /** @var SetupManager $setupManager */ + $setupManager = \OC::$server->get(SetupManager::class); + $setupManager->setupForUser($userObject); } else { - self::getMountManager()->addMount(new MountPoint( - new NullStorage([]), - '/' . $user - )); - self::getMountManager()->addMount(new MountPoint( - new NullStorage([]), - '/' . $user . '/files' - )); - } - \OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', ['user' => $user]); - } - - /** - * Get mounts from mount providers that are registered after setup - * - * @param MountProviderCollection $mountConfigManager - * @param IUserManager $userManager - */ - private static function listenForNewMountProviders(MountProviderCollection $mountConfigManager, IUserManager $userManager) { - if (!self::$listeningForProviders) { - self::$listeningForProviders = true; - $mountConfigManager->listen('\OC\Files\Config', 'registerMountProvider', function (IMountProvider $provider) use ($userManager) { - foreach (Filesystem::$usersSetup as $user => $setup) { - $userObject = $userManager->get($user); - if ($userObject) { - $mounts = $provider->getMountsForUser($userObject, Filesystem::getLoader()); - array_walk($mounts, [self::$mounts, 'addMount']); - } - } - }); + throw new NoUserException(); } } @@ -474,8 +382,7 @@ class Filesystem { * tear down the filesystem, removing all storage providers */ public static function tearDown() { - self::clearMounts(); - self::$defaultInstance = null; + \OC_Util::tearDownFS(); } /** @@ -493,16 +400,6 @@ class Filesystem { } /** - * clear all mounts and storage backends - */ - public static function clearMounts() { - if (self::$mounts) { - self::$usersSetup = []; - self::$mounts->clear(); - } - } - - /** * mount an \OC\Files\Storage\Storage in our virtual filesystem * * @param \OC\Files\Storage\Storage|string $class diff --git a/lib/private/Files/Mount/Manager.php b/lib/private/Files/Mount/Manager.php index 22b05b1f384..66832690363 100644 --- a/lib/private/Files/Mount/Manager.php +++ b/lib/private/Files/Mount/Manager.php @@ -26,26 +26,30 @@ declare(strict_types=1); * along with this program. If not, see <http://www.gnu.org/licenses/> * */ + namespace OC\Files\Mount; use OC\Cache\CappedMemoryCache; use OC\Files\Filesystem; +use OC\Files\SetupManager; +use OC\Files\SetupManagerFactory; use OCP\Files\Mount\IMountManager; use OCP\Files\Mount\IMountPoint; +use OCP\Files\NotFoundException; class Manager implements IMountManager { /** @var MountPoint[] */ - private $mounts = []; - - /** @var CappedMemoryCache */ - private $pathCache; - - /** @var CappedMemoryCache */ - private $inPathCache; - - public function __construct() { + private array $mounts = []; + /** @var CappedMemoryCache<IMountPoint> */ + private CappedMemoryCache $pathCache; + /** @var CappedMemoryCache<IMountPoint[]> */ + private CappedMemoryCache $inPathCache; + private SetupManager $setupManager; + + public function __construct(SetupManagerFactory $setupManagerFactory) { $this->pathCache = new CappedMemoryCache(); $this->inPathCache = new CappedMemoryCache(); + $this->setupManager = $setupManagerFactory->create($this); } /** @@ -81,26 +85,14 @@ class Manager implements IMountManager { $this->inPathCache->clear(); } - private function setupForFind(string $path) { - if (strpos($path, '/appdata_' . \OC_Util::getInstanceId()) === 0) { - // for appdata, we only setup the root bits, not the user bits - \OC_Util::setupRootFS(); - } elseif (strpos($path, '/files_external/uploads/') === 0) { - // for OC\Security\CertificateManager, we only setup the root bits, not the user bits - \OC_Util::setupRootFS(); - } else { - \OC_Util::setupFS(); - } - } - /** * Find the mount for $path * * @param string $path - * @return MountPoint|null + * @return IMountPoint */ - public function find(string $path) { - $this->setupForFind($path); + public function find(string $path): IMountPoint { + $this->setupManager->setupForPath($path); $path = Filesystem::normalizePath($path); if (isset($this->pathCache[$path])) { @@ -113,10 +105,8 @@ class Manager implements IMountManager { if (isset($this->mounts[$mountPoint])) { $this->pathCache[$path] = $this->mounts[$mountPoint]; return $this->mounts[$mountPoint]; - } - - if ($current === '') { - return null; + } elseif ($current === '') { + break; } $current = dirname($current); @@ -124,16 +114,18 @@ class Manager implements IMountManager { $current = ''; } } + + throw new NotFoundException("No mount for path " . $path . " existing mounts: " . implode(",", array_keys($this->mounts))); } /** * Find all mounts in $path * * @param string $path - * @return MountPoint[] + * @return IMountPoint[] */ public function findIn(string $path): array { - $this->setupForFind($path); + $this->setupManager->setupForPath($path); $path = $this->formatPath($path); if (isset($this->inPathCache[$path])) { @@ -163,7 +155,7 @@ class Manager implements IMountManager { * Find mounts by storage id * * @param string $id - * @return MountPoint[] + * @return IMountPoint[] */ public function findByStorageId(string $id): array { \OC_Util::setupFS(); @@ -180,7 +172,7 @@ class Manager implements IMountManager { } /** - * @return MountPoint[] + * @return IMountPoint[] */ public function getAll(): array { return $this->mounts; @@ -190,7 +182,7 @@ class Manager implements IMountManager { * Find mounts by numeric storage id * * @param int $id - * @return MountPoint[] + * @return IMountPoint[] */ public function findByNumericId(int $id): array { $storageId = \OC\Files\Cache\Storage::getStorageId($id); @@ -208,4 +200,8 @@ class Manager implements IMountManager { } return $path; } + + public function getSetupManager(): SetupManager { + return $this->setupManager; + } } diff --git a/lib/private/Files/Node/Root.php b/lib/private/Files/Node/Root.php index b5707c87543..88ac4a31d34 100644 --- a/lib/private/Files/Node/Root.php +++ b/lib/private/Files/Node/Root.php @@ -35,13 +35,17 @@ namespace OC\Files\Node; use OC\Cache\CappedMemoryCache; use OC\Files\Mount\Manager; use OC\Files\Mount\MountPoint; +use OC\Files\View; use OC\Hooks\PublicEmitter; use OC\User\NoUserException; +use OCP\EventDispatcher\IEventDispatcher; use OCP\Files\Config\IUserMountCache; +use OCP\Files\Events\Node\FilesystemTornDownEvent; use OCP\Files\IRootFolder; use OCP\Files\NotFoundException; use OCP\Files\NotPermittedException; use OCP\ILogger; +use OCP\IUser; use OCP\IUserManager; /** @@ -64,35 +68,32 @@ use OCP\IUserManager; * @package OC\Files\Node */ class Root extends Folder implements IRootFolder { - /** @var Manager */ - private $mountManager; - /** @var PublicEmitter */ - private $emitter; - /** @var null|\OC\User\User */ - private $user; - /** @var CappedMemoryCache */ - private $userFolderCache; - /** @var IUserMountCache */ - private $userMountCache; - /** @var ILogger */ - private $logger; - /** @var IUserManager */ - private $userManager; + private Manager $mountManager; + private PublicEmitter $emitter; + private ?IUser $user; + private CappedMemoryCache $userFolderCache; + private IUserMountCache $userMountCache; + private ILogger $logger; + private IUserManager $userManager; + private IEventDispatcher $eventDispatcher; /** - * @param \OC\Files\Mount\Manager $manager - * @param \OC\Files\View $view - * @param \OC\User\User|null $user + * @param Manager $manager + * @param View $view + * @param IUser|null $user * @param IUserMountCache $userMountCache * @param ILogger $logger * @param IUserManager $userManager */ - public function __construct($manager, + public function __construct( + $manager, $view, $user, - IUserMountCache $userMountCache, - ILogger $logger, - IUserManager $userManager) { + IUserMountCache $userMountCache, + ILogger $logger, + IUserManager $userManager, + IEventDispatcher $eventDispatcher + ) { parent::__construct($this, $view, ''); $this->mountManager = $manager; $this->user = $user; @@ -101,6 +102,9 @@ class Root extends Folder implements IRootFolder { $this->userMountCache = $userMountCache; $this->logger = $logger; $this->userManager = $userManager; + $eventDispatcher->addListener(FilesystemTornDownEvent::class, function () { + $this->userFolderCache = new CappedMemoryCache(); + }); } /** @@ -267,21 +271,21 @@ class Root extends Folder implements IRootFolder { * @return int */ public function getId() { - return null; + return 0; } /** * @return array */ public function stat() { - return null; + return []; } /** * @return int */ public function getMTime() { - return null; + return 0; } /** @@ -289,14 +293,14 @@ class Root extends Folder implements IRootFolder { * @return int */ public function getSize($includeMounts = true) { - return null; + return 0; } /** * @return string */ public function getEtag() { - return null; + return ''; } /** @@ -393,10 +397,6 @@ class Root extends Folder implements IRootFolder { return $this->userFolderCache->get($userId); } - public function clearCache() { - $this->userFolderCache = new CappedMemoryCache(); - } - public function getUserMountCache() { return $this->userMountCache; } diff --git a/lib/private/Files/SetupManager.php b/lib/private/Files/SetupManager.php new file mode 100644 index 00000000000..f9276ef4171 --- /dev/null +++ b/lib/private/Files/SetupManager.php @@ -0,0 +1,283 @@ +<?php + +declare(strict_types=1); +/** + * @copyright Copyright (c) 2022 Robin Appelman <robin@icewind.nl> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\Files; + +use OC\Files\Config\MountProviderCollection; +use OC\Files\Mount\MountPoint; +use OC\Files\ObjectStore\HomeObjectStoreStorage; +use OC\Files\Storage\Common; +use OC\Files\Storage\Home; +use OC\Files\Storage\Storage; +use OC\Files\Storage\Wrapper\Availability; +use OC\Files\Storage\Wrapper\Encoding; +use OC\Files\Storage\Wrapper\PermissionsMask; +use OC\Files\Storage\Wrapper\Quota; +use OC\Lockdown\Filesystem\NullStorage; +use OC_App; +use OC_Hook; +use OC_Util; +use OCP\Constants; +use OCP\Diagnostics\IEventLogger; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\Config\IMountProvider; +use OCP\Files\Config\IUserMountCache; +use OCP\Files\Events\Node\FilesystemTornDownEvent; +use OCP\Files\Mount\IMountManager; +use OCP\Files\Mount\IMountPoint; +use OCP\Files\Storage\IStorage; +use OCP\IUser; +use OCP\IUserManager; +use OCP\Lockdown\ILockdownManager; + +class SetupManager { + private bool $rootSetup = false; + private IEventLogger $eventLogger; + private MountProviderCollection $mountProviderCollection; + private IMountManager $mountManager; + private IUserManager $userManager; + private array $setupUsers = []; + private IEventDispatcher $eventDispatcher; + private IUserMountCache $userMountCache; + private ILockdownManager $lockdownManager; + private bool $listeningForProviders; + + public function __construct( + IEventLogger $eventLogger, + MountProviderCollection $mountProviderCollection, + IMountManager $mountManager, + IUserManager $userManager, + IEventDispatcher $eventDispatcher, + IUserMountCache $userMountCache, + ILockdownManager $lockdownManager + ) { + $this->eventLogger = $eventLogger; + $this->mountProviderCollection = $mountProviderCollection; + $this->mountManager = $mountManager; + $this->userManager = $userManager; + $this->eventDispatcher = $eventDispatcher; + $this->userMountCache = $userMountCache; + $this->lockdownManager = $lockdownManager; + $this->listeningForProviders = false; + } + + private function setupBuiltinWrappers() { + Filesystem::addStorageWrapper('mount_options', function ($mountPoint, IStorage $storage, IMountPoint $mount) { + if ($storage->instanceOfStorage(Common::class)) { + $storage->setMountOptions($mount->getOptions()); + } + return $storage; + }); + + Filesystem::addStorageWrapper('enable_sharing', function ($mountPoint, IStorage $storage, IMountPoint $mount) { + if (!$mount->getOption('enable_sharing', true)) { + return new PermissionsMask([ + 'storage' => $storage, + 'mask' => Constants::PERMISSION_ALL - Constants::PERMISSION_SHARE, + ]); + } + return $storage; + }); + + // install storage availability wrapper, before most other wrappers + Filesystem::addStorageWrapper('oc_availability', function ($mountPoint, IStorage $storage) { + if (!$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage') && !$storage->isLocal()) { + return new Availability(['storage' => $storage]); + } + return $storage; + }); + + Filesystem::addStorageWrapper('oc_encoding', function ($mountPoint, IStorage $storage, IMountPoint $mount) { + if ($mount->getOption('encoding_compatibility', false) && !$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage') && !$storage->isLocal()) { + return new Encoding(['storage' => $storage]); + } + return $storage; + }); + + Filesystem::addStorageWrapper('oc_quota', function ($mountPoint, $storage) { + // set up quota for home storages, even for other users + // which can happen when using sharing + + /** + * @var Storage $storage + */ + if ($storage->instanceOfStorage(HomeObjectStoreStorage::class) || $storage->instanceOfStorage(Home::class)) { + if (is_object($storage->getUser())) { + $quota = OC_Util::getUserQuota($storage->getUser()); + if ($quota !== \OCP\Files\FileInfo::SPACE_UNLIMITED) { + return new Quota(['storage' => $storage, 'quota' => $quota, 'root' => 'files']); + } + } + } + + return $storage; + }); + + Filesystem::addStorageWrapper('readonly', function ($mountPoint, IStorage $storage, IMountPoint $mount) { + /* + * Do not allow any operations that modify the storage + */ + if ($mount->getOption('readonly', false)) { + return new PermissionsMask([ + 'storage' => $storage, + 'mask' => Constants::PERMISSION_ALL & ~( + Constants::PERMISSION_UPDATE | + Constants::PERMISSION_CREATE | + Constants::PERMISSION_DELETE + ), + ]); + } + return $storage; + }); + } + + /** + * Setup the full filesystem for the specified user + */ + public function setupForUser(IUser $user): void { + $this->setupRoot(); + + if (in_array($user->getUID(), $this->setupUsers, true)) { + return; + } + $this->setupUsers[] = $user->getUID(); + + $this->eventLogger->start('setup_fs', 'Setup filesystem'); + + $prevLogging = Filesystem::logWarningWhenAddingStorageWrapper(false); + + OC_Hook::emit('OC_Filesystem', 'preSetup', ['user' => $user->getUID()]); + + Filesystem::logWarningWhenAddingStorageWrapper($prevLogging); + + $userDir = '/' . $user->getUID() . '/files'; + + Filesystem::init($user, $userDir); + + if ($this->lockdownManager->canAccessFilesystem()) { + // home mounts are handled separate since we need to ensure this is mounted before we call the other mount providers + $homeMount = $this->mountProviderCollection->getHomeMountForUser($user); + $this->mountManager->addMount($homeMount); + + if ($homeMount->getStorageRootId() === -1) { + $homeMount->getStorage()->mkdir(''); + $homeMount->getStorage()->getScanner()->scan(''); + } + + // Chance to mount for other storages + $mounts = $this->mountProviderCollection->addMountForUser($user, $this->mountManager); + $mounts[] = $homeMount; + $this->userMountCache->registerMounts($user, $mounts); + + $this->listenForNewMountProviders(); + } else { + $this->mountManager->addMount(new MountPoint( + new NullStorage([]), + '/' . $user->getUID() + )); + $this->mountManager->addMount(new MountPoint( + new NullStorage([]), + '/' . $user->getUID() . '/files' + )); + } + \OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', ['user' => $user->getUID()]); + + OC_Hook::emit('OC_Filesystem', 'setup', ['user' => $user->getUID(), 'user_dir' => $userDir]); + + $this->eventLogger->end('setup_fs'); + } + + /** + * Set up the root filesystem + */ + public function setupRoot(): void { + //setting up the filesystem twice can only lead to trouble + if ($this->rootSetup) { + return; + } + $this->rootSetup = true; + + $this->eventLogger->start('setup_root_fs', 'Setup root filesystem'); + + // load all filesystem apps before, so no setup-hook gets lost + OC_App::loadApps(['filesystem']); + $prevLogging = Filesystem::logWarningWhenAddingStorageWrapper(false); + + $this->setupBuiltinWrappers(); + + Filesystem::logWarningWhenAddingStorageWrapper($prevLogging); + + $rootMounts = $this->mountProviderCollection->getRootMounts(); + foreach ($rootMounts as $rootMountProvider) { + $this->mountManager->addMount($rootMountProvider); + } + + $this->eventLogger->end('setup_root_fs'); + } + + /** + * Set up the filesystem for the specified path + */ + public function setupForPath(string $path): void { + if (substr_count($path, '/') < 2 || strpos($path, '/appdata_' . \OC_Util::getInstanceId()) === 0 || strpos($path, '/files_external/') === 0) { + $this->setupRoot(); + return; + } else { + [, $userId] = explode('/', $path); + } + + $user = $this->userManager->get($userId); + + if (!$user) { + $this->setupRoot(); + return; + } + + $this->setupForUser($user); + } + + public function tearDown() { + $this->setupUsers = []; + $this->rootSetup = false; + $this->mountManager->clear(); + $this->eventDispatcher->dispatchTyped(new FilesystemTornDownEvent()); + } + + /** + * Get mounts from mount providers that are registered after setup + */ + private function listenForNewMountProviders() { + if (!$this->listeningForProviders) { + $this->listeningForProviders = true; + $this->mountProviderCollection->listen('\OC\Files\Config', 'registerMountProvider', function (IMountProvider $provider) { + foreach ($this->setupUsers as $userId) { + $user = $this->userManager->get($userId); + if ($user) { + $mounts = $provider->getMountsForUser($user, Filesystem::getLoader()); + array_walk($mounts, [$this->mountManager, 'addMount']); + } + } + }); + } + } +} diff --git a/lib/private/Files/SetupManagerFactory.php b/lib/private/Files/SetupManagerFactory.php new file mode 100644 index 00000000000..5dd1601570d --- /dev/null +++ b/lib/private/Files/SetupManagerFactory.php @@ -0,0 +1,66 @@ +<?php + +declare(strict_types=1); +/** + * @copyright Copyright (c) 2022 Robin Appelman <robin@icewind.nl> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OC\Files; + +use OCP\Diagnostics\IEventLogger; +use OCP\EventDispatcher\IEventDispatcher; +use OCP\Files\Config\IMountProviderCollection; +use OCP\Files\Config\IUserMountCache; +use OCP\Files\Mount\IMountManager; +use OCP\IUserManager; +use OCP\Lockdown\ILockdownManager; + +class SetupManagerFactory { + private IEventLogger $eventLogger; + private IMountProviderCollection $mountProviderCollection; + private IUserManager $userManager; + private IEventDispatcher $eventDispatcher; + private IUserMountCache $userMountCache; + private ILockdownManager $lockdownManager; + private ?SetupManager $setupManager; + + public function __construct( + IEventLogger $eventLogger, + IMountProviderCollection $mountProviderCollection, + IUserManager $userManager, + IEventDispatcher $eventDispatcher, + IUserMountCache $userMountCache, + ILockdownManager $lockdownManager + ) { + $this->eventLogger = $eventLogger; + $this->mountProviderCollection = $mountProviderCollection; + $this->userManager = $userManager; + $this->eventDispatcher = $eventDispatcher; + $this->userMountCache = $userMountCache; + $this->lockdownManager = $lockdownManager; + $this->setupManager = null; + } + + public function create(IMountManager $mountManager): SetupManager { + if (!$this->setupManager) { + $this->setupManager = new SetupManager($this->eventLogger, $this->mountProviderCollection, $mountManager, $this->userManager, $this->eventDispatcher, $this->userMountCache, $this->lockdownManager); + } + return $this->setupManager; + } +} diff --git a/lib/private/Files/View.php b/lib/private/Files/View.php index 3cdc6166840..779e0611591 100644 --- a/lib/private/Files/View.php +++ b/lib/private/Files/View.php @@ -274,7 +274,7 @@ class View { /** * remove mount point * - * @param \OC\Files\Mount\MoveableMount $mount + * @param IMountPoint $mount * @param string $path relative to data/ * @return boolean */ @@ -719,7 +719,7 @@ class View { $postFix = (substr($path, -1) === '/') ? '/' : ''; $absolutePath = Filesystem::normalizePath($this->getAbsolutePath($path)); $mount = Filesystem::getMountManager()->find($absolutePath . $postFix); - if ($mount and $mount->getInternalPath($absolutePath) === '') { + if ($mount->getInternalPath($absolutePath) === '') { return $this->removeMount($mount, $absolutePath); } if ($this->is_dir($path)) { @@ -1383,10 +1383,6 @@ class View { $path = Filesystem::normalizePath($this->fakeRoot . '/' . $path); $mount = Filesystem::getMountManager()->find($path); - if (!$mount) { - \OC::$server->getLogger()->warning('Mountpoint not found for path: ' . $path); - return false; - } $storage = $mount->getStorage(); $internalPath = $mount->getInternalPath($path); if ($storage) { @@ -1488,7 +1484,7 @@ class View { $rootEntry = $subCache->get(''); if (!$rootEntry) { - $subScanner = $subStorage->getScanner(''); + $subScanner = $subStorage->getScanner(); try { $subScanner->scanFile(''); } catch (\OCP\Files\StorageNotAvailableException $e) { @@ -1739,12 +1735,13 @@ class View { $manager = Filesystem::getMountManager(); $mounts = $manager->findIn($this->fakeRoot); $mounts[] = $manager->find($this->fakeRoot); - // reverse the array so we start with the storage this view is in + $mounts = array_filter($mounts); + // reverse the array, so we start with the storage this view is in // which is the most likely to contain the file we're looking for $mounts = array_reverse($mounts); - // put non shared mounts in front of the shared mount - // this prevent unneeded recursion into shares + // put non-shared mounts in front of the shared mount + // this prevents unneeded recursion into shares usort($mounts, function (IMountPoint $a, IMountPoint $b) { return $a instanceof SharedMount && (!$b instanceof SharedMount) ? 1 : -1; }); @@ -1915,14 +1912,10 @@ class View { * @param string $absolutePath absolute path * @param bool $useParentMount true to return parent mount instead of whatever * is mounted directly on the given path, false otherwise - * @return \OC\Files\Mount\MountPoint mount point for which to apply locks + * @return IMountPoint mount point for which to apply locks */ private function getMountForLock($absolutePath, $useParentMount = false) { - $results = []; $mount = Filesystem::getMountManager()->find($absolutePath); - if (!$mount) { - return $results; - } if ($useParentMount) { // find out if something is mounted directly on the path diff --git a/lib/private/Server.php b/lib/private/Server.php index 8d1f377251c..38720ab71c0 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -95,6 +95,7 @@ use OC\Files\Mount\RootMountProvider; use OC\Files\Node\HookConnector; use OC\Files\Node\LazyRoot; use OC\Files\Node\Root; +use OC\Files\SetupManager; use OC\Files\Storage\StorageFactory; use OC\Files\Template\TemplateManager; use OC\Files\Type\Loader; @@ -216,6 +217,7 @@ use OCP\L10N\IFactory; use OCP\LDAP\ILDAPProvider; use OCP\LDAP\ILDAPProviderFactory; use OCP\Lock\ILockingProvider; +use OCP\Lockdown\ILockdownManager; use OCP\Log\ILogFactory; use OCP\Mail\IMailer; use OCP\Remote\Api\IApiFactory; @@ -423,7 +425,8 @@ class Server extends ServerContainer implements IServerContainer { null, $c->get(IUserMountCache::class), $this->get(ILogger::class), - $this->get(IUserManager::class) + $this->get(IUserManager::class), + $this->get(IEventDispatcher::class), ); $previewConnector = new \OC\Preview\WatcherConnector( @@ -1091,6 +1094,11 @@ class Server extends ServerContainer implements IServerContainer { /** @deprecated 19.0.0 */ $this->registerDeprecatedAlias('LockingProvider', ILockingProvider::class); + $this->registerAlias(ILockdownManager::class, 'LockdownManager'); + $this->registerService(SetupManager::class, function ($c) { + // create the setupmanager through the mount manager to resolve the cyclic dependency + return $c->get(\OC\Files\Mount\Manager::class)->getSetupManager(); + }); $this->registerAlias(IMountManager::class, \OC\Files\Mount\Manager::class); /** @deprecated 19.0.0 */ $this->registerDeprecatedAlias('MountManager', IMountManager::class); diff --git a/lib/private/legacy/OC_Util.php b/lib/private/legacy/OC_Util.php index 40dcbb13b93..ceed79bc9d5 100644 --- a/lib/private/legacy/OC_Util.php +++ b/lib/private/legacy/OC_Util.php @@ -66,6 +66,7 @@ use bantu\IniGetWrapper\IniGetWrapper; use OC\AppFramework\Http\Request; +use OC\Files\SetupManager; use OCP\Files\Template\ITemplateManager; use OCP\IConfig; use OCP\IGroupManager; @@ -78,8 +79,6 @@ class OC_Util { public static $scripts = []; public static $styles = []; public static $headers = []; - private static $rootFsSetup = false; - private static $fsSetup = false; /** @var array Local cache of version.php */ private static $versionCache = null; @@ -89,122 +88,6 @@ class OC_Util { } /** - * Can be set up - * - * @param string $user - * @return boolean - * @description configure the initial filesystem based on the configuration - * @suppress PhanDeprecatedFunction - * @suppress PhanAccessMethodInternal - */ - public static function setupRootFS(string $user = '') { - //setting up the filesystem twice can only lead to trouble - if (self::$rootFsSetup) { - return false; - } - - \OC::$server->getEventLogger()->start('setup_root_fs', 'Setup root filesystem'); - - // load all filesystem apps before, so no setup-hook gets lost - OC_App::loadApps(['filesystem']); - - self::$rootFsSetup = true; - - \OC\Files\Filesystem::initMountManager(); - - $prevLogging = \OC\Files\Filesystem::logWarningWhenAddingStorageWrapper(false); - \OC\Files\Filesystem::addStorageWrapper('mount_options', function ($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) { - if ($storage->instanceOfStorage('\OC\Files\Storage\Common')) { - /** @var \OC\Files\Storage\Common $storage */ - $storage->setMountOptions($mount->getOptions()); - } - return $storage; - }); - - \OC\Files\Filesystem::addStorageWrapper('enable_sharing', function ($mountPoint, \OCP\Files\Storage\IStorage $storage, \OCP\Files\Mount\IMountPoint $mount) { - if (!$mount->getOption('enable_sharing', true)) { - return new \OC\Files\Storage\Wrapper\PermissionsMask([ - 'storage' => $storage, - 'mask' => \OCP\Constants::PERMISSION_ALL - \OCP\Constants::PERMISSION_SHARE - ]); - } - return $storage; - }); - - // install storage availability wrapper, before most other wrappers - \OC\Files\Filesystem::addStorageWrapper('oc_availability', function ($mountPoint, \OCP\Files\Storage\IStorage $storage) { - if (!$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage') && !$storage->isLocal()) { - return new \OC\Files\Storage\Wrapper\Availability(['storage' => $storage]); - } - return $storage; - }); - - \OC\Files\Filesystem::addStorageWrapper('oc_encoding', function ($mountPoint, \OCP\Files\Storage $storage, \OCP\Files\Mount\IMountPoint $mount) { - if ($mount->getOption('encoding_compatibility', false) && !$storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage') && !$storage->isLocal()) { - return new \OC\Files\Storage\Wrapper\Encoding(['storage' => $storage]); - } - return $storage; - }); - - \OC\Files\Filesystem::addStorageWrapper('oc_quota', function ($mountPoint, $storage) { - // set up quota for home storages, even for other users - // which can happen when using sharing - - /** - * @var \OC\Files\Storage\Storage $storage - */ - if ($storage->instanceOfStorage('\OC\Files\Storage\Home') - || $storage->instanceOfStorage('\OC\Files\ObjectStore\HomeObjectStoreStorage') - ) { - /** @var \OC\Files\Storage\Home $storage */ - if (is_object($storage->getUser())) { - $quota = OC_Util::getUserQuota($storage->getUser()); - if ($quota !== \OCP\Files\FileInfo::SPACE_UNLIMITED) { - return new \OC\Files\Storage\Wrapper\Quota(['storage' => $storage, 'quota' => $quota, 'root' => 'files']); - } - } - } - - return $storage; - }); - - \OC\Files\Filesystem::addStorageWrapper('readonly', function ($mountPoint, \OCP\Files\Storage\IStorage $storage, \OCP\Files\Mount\IMountPoint $mount) { - /* - * Do not allow any operations that modify the storage - */ - if ($mount->getOption('readonly', false)) { - return new \OC\Files\Storage\Wrapper\PermissionsMask([ - 'storage' => $storage, - 'mask' => \OCP\Constants::PERMISSION_ALL & ~( - \OCP\Constants::PERMISSION_UPDATE | - \OCP\Constants::PERMISSION_CREATE | - \OCP\Constants::PERMISSION_DELETE - ), - ]); - } - return $storage; - }); - - OC_Hook::emit('OC_Filesystem', 'preSetup', ['user' => $user]); - - \OC\Files\Filesystem::logWarningWhenAddingStorageWrapper($prevLogging); - - /** @var \OCP\Files\Config\IMountProviderCollection $mountProviderCollection */ - $mountProviderCollection = \OC::$server->query(\OCP\Files\Config\IMountProviderCollection::class); - $rootMountProviders = $mountProviderCollection->getRootMounts(); - - /** @var \OC\Files\Mount\Manager $mountManager */ - $mountManager = \OC\Files\Filesystem::getMountManager(); - foreach ($rootMountProviders as $rootMountProvider) { - $mountManager->addMount($rootMountProvider); - } - - \OC::$server->getEventLogger()->end('setup_root_fs'); - - return true; - } - - /** * Setup the file system * * @param string|null $user @@ -214,14 +97,6 @@ class OC_Util { * @suppress PhanAccessMethodInternal */ public static function setupFS(?string $user = '') { - self::setupRootFS($user ?? ''); - - if (self::$fsSetup) { - return false; - } - - \OC::$server->getEventLogger()->start('setup_fs', 'Setup filesystem'); - // If we are not forced to load a specific user we load the one that is logged in if ($user === '') { $userObject = \OC::$server->get(\OCP\IUserSession::class)->getUser(); @@ -229,18 +104,14 @@ class OC_Util { $userObject = \OC::$server->get(\OCP\IUserManager::class)->get($user); } - //if we aren't logged in, or the user doesn't exist, there is no use to set up the filesystem - if ($userObject) { - self::$fsSetup = true; - - $userDir = '/' . $userObject->getUID() . '/files'; - - //jail the user into his "home" directory - \OC\Files\Filesystem::init($userObject, $userDir); + /** @var SetupManager $setupManager */ + $setupManager = \OC::$server->get(SetupManager::class); - OC_Hook::emit('OC_Filesystem', 'setup', ['user' => $userObject->getUID(), 'user_dir' => $userDir]); + if ($userObject) { + $setupManager->setupForUser($userObject); + } else { + $setupManager->setupRoot(); } - \OC::$server->getEventLogger()->end('setup_fs'); return true; } @@ -394,10 +265,9 @@ class OC_Util { * @suppress PhanUndeclaredMethod */ public static function tearDownFS() { - \OC\Files\Filesystem::tearDown(); - \OC::$server->getRootFolder()->clearCache(); - self::$fsSetup = false; - self::$rootFsSetup = false; + /** @var SetupManager $setupManager */ + $setupManager = \OC::$server->get(SetupManager::class); + $setupManager->tearDown(); } /** diff --git a/lib/public/Files/Config/ICachedMountFileInfo.php b/lib/public/Files/Config/ICachedMountFileInfo.php index 4de0a1218b4..e6aa2ec38c8 100644 --- a/lib/public/Files/Config/ICachedMountFileInfo.php +++ b/lib/public/Files/Config/ICachedMountFileInfo.php @@ -34,11 +34,11 @@ interface ICachedMountFileInfo extends ICachedMountInfo { * @return string * @since 13.0.0 */ - public function getInternalPath(); + public function getInternalPath(): string; /** * @return string * @since 13.0.0 */ - public function getPath(); + public function getPath(): string; } diff --git a/lib/public/Files/Config/ICachedMountInfo.php b/lib/public/Files/Config/ICachedMountInfo.php index 812e79cdbc8..dafd2423fdc 100644 --- a/lib/public/Files/Config/ICachedMountInfo.php +++ b/lib/public/Files/Config/ICachedMountInfo.php @@ -35,31 +35,31 @@ interface ICachedMountInfo { * @return IUser * @since 9.0.0 */ - public function getUser(); + public function getUser(): IUser; /** * @return int the numeric storage id of the mount * @since 9.0.0 */ - public function getStorageId(); + public function getStorageId(): int; /** * @return int the fileid of the root of the mount * @since 9.0.0 */ - public function getRootId(); + public function getRootId(): int; /** - * @return Node the root node of the mount + * @return Node|null the root node of the mount * @since 9.0.0 */ - public function getMountPointNode(); + public function getMountPointNode(): ?Node; /** * @return string the mount point of the mount for the user * @since 9.0.0 */ - public function getMountPoint(); + public function getMountPoint(): string; /** * Get the id of the configured mount @@ -67,7 +67,7 @@ interface ICachedMountInfo { * @return int|null mount id or null if not applicable * @since 9.1.0 */ - public function getMountId(); + public function getMountId(): ?int; /** * Get the internal path (within the storage) of the root of the mount @@ -75,7 +75,7 @@ interface ICachedMountInfo { * @return string * @since 11.0.0 */ - public function getRootInternalPath(); + public function getRootInternalPath(): string; /** * Get the class of the mount provider that this mount originates from diff --git a/lib/public/Files/Events/Node/FilesystemTornDownEvent.php b/lib/public/Files/Events/Node/FilesystemTornDownEvent.php new file mode 100644 index 00000000000..3e7780c827e --- /dev/null +++ b/lib/public/Files/Events/Node/FilesystemTornDownEvent.php @@ -0,0 +1,34 @@ +<?php + +declare(strict_types=1); +/** + * @copyright Copyright (c) 2022 Robin Appelman <robin@icewind.nl> + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + * + */ + +namespace OCP\Files\Events\Node; + +use OCP\EventDispatcher\Event; + +/** + * Event fired after the filesystem has been torn down + * + * @since 24.0.0 + */ +class FilesystemTornDownEvent extends Event { +} diff --git a/lib/public/Files/Mount/IMountManager.php b/lib/public/Files/Mount/IMountManager.php index 1e8c674f8f5..aa760f53e96 100644 --- a/lib/public/Files/Mount/IMountManager.php +++ b/lib/public/Files/Mount/IMountManager.php @@ -37,7 +37,7 @@ interface IMountManager { /** * Add a new mount * - * @param \OCP\Files\Mount\IMountPoint $mount + * @param IMountPoint $mount * @since 8.2.0 */ public function addMount(IMountPoint $mount); @@ -63,16 +63,16 @@ interface IMountManager { * Find the mount for $path * * @param string $path - * @return \OCP\Files\Mount\IMountPoint|null + * @return IMountPoint * @since 8.2.0 */ - public function find(string $path); + public function find(string $path): ?IMountPoint; /** * Find all mounts in $path * * @param string $path - * @return \OCP\Files\Mount\IMountPoint[] + * @return IMountPoint[] * @since 8.2.0 */ public function findIn(string $path): array; @@ -88,13 +88,13 @@ interface IMountManager { * Find mounts by storage id * * @param string $id - * @return \OCP\Files\Mount\IMountPoint[] + * @return IMountPoint[] * @since 8.2.0 */ public function findByStorageId(string $id): array; /** - * @return \OCP\Files\Mount\IMountPoint[] + * @return IMountPoint[] * @since 8.2.0 */ public function getAll(): array; @@ -103,7 +103,7 @@ interface IMountManager { * Find mounts by numeric storage id * * @param int $id - * @return \OCP\Files\Mount\IMountPoint[] + * @return IMountPoint[] * @since 8.2.0 */ public function findByNumericId(int $id): array; |