aboutsummaryrefslogtreecommitdiffstats
path: root/lib/private
diff options
context:
space:
mode:
Diffstat (limited to 'lib/private')
-rw-r--r--lib/private/AppConfig.php50
-rw-r--r--lib/private/Avatar/AvatarManager.php3
-rw-r--r--lib/private/Cache/CappedMemoryCache.php28
-rw-r--r--lib/private/Files/Cache/Storage.php7
-rw-r--r--lib/private/Files/Config/CachedMountFileInfo.php3
-rw-r--r--lib/private/Files/Config/CachedMountInfo.php55
-rw-r--r--lib/private/Files/Config/LazyStorageMountInfo.php16
-rw-r--r--lib/private/Files/Config/MountProviderCollection.php16
-rw-r--r--lib/private/Files/Filesystem.php147
-rw-r--r--lib/private/Files/Mount/Manager.php62
-rw-r--r--lib/private/Files/Mount/RootMountProvider.php103
-rw-r--r--lib/private/Files/Node/Root.php60
-rw-r--r--lib/private/Files/SetupManager.php283
-rw-r--r--lib/private/Files/SetupManagerFactory.php66
-rw-r--r--lib/private/Files/SimpleFS/NewSimpleFile.php11
-rw-r--r--lib/private/Files/SimpleFS/SimpleFile.php7
-rw-r--r--lib/private/Files/View.php23
-rw-r--r--lib/private/Security/CSP/ContentSecurityPolicy.php7
-rw-r--r--lib/private/Server.php12
-rw-r--r--lib/private/Template/JSResourceLocator.php2
-rw-r--r--lib/private/legacy/OC_Util.php254
21 files changed, 700 insertions, 515 deletions
diff --git a/lib/private/AppConfig.php b/lib/private/AppConfig.php
index fc7c770fe08..1324d7f3056 100644
--- a/lib/private/AppConfig.php
+++ b/lib/private/AppConfig.php
@@ -55,6 +55,56 @@ class AppConfig implements IAppConfig {
'/^private_key$/',
'/^public_key$/',
],
+ 'integration_dropbox' => [
+ '/^client_id$/',
+ '/^client_secret$/',
+ ],
+ 'integration_github' => [
+ '/^client_id$/',
+ '/^client_secret$/',
+ ],
+ 'integration_gitlab' => [
+ '/^client_id$/',
+ '/^client_secret$/',
+ '/^oauth_instance_url$/',
+ ],
+ 'integration_google' => [
+ '/^client_id$/',
+ '/^client_secret$/',
+ ],
+ 'integration_jira' => [
+ '/^client_id$/',
+ '/^client_secret$/',
+ '/^forced_instance_url$/',
+ ],
+ 'integration_onedrive' => [
+ '/^client_id$/',
+ '/^client_secret$/',
+ ],
+ 'integration_openproject' => [
+ '/^client_id$/',
+ '/^client_secret$/',
+ '/^oauth_instance_url$/',
+ ],
+ 'integration_reddit' => [
+ '/^client_id$/',
+ '/^client_secret$/',
+ ],
+ 'integration_suitecrm' => [
+ '/^client_id$/',
+ '/^client_secret$/',
+ '/^oauth_instance_url$/',
+ ],
+ 'integration_twitter' => [
+ '/^consumer_key$/',
+ '/^consumer_secret$/',
+ '/^followed_user$/',
+ ],
+ 'integration_zammad' => [
+ '/^client_id$/',
+ '/^client_secret$/',
+ '/^oauth_instance_url$/',
+ ],
'notify_push' => [
'/^cookie$/',
],
diff --git a/lib/private/Avatar/AvatarManager.php b/lib/private/Avatar/AvatarManager.php
index c3afd8094c7..77138085dc9 100644
--- a/lib/private/Avatar/AvatarManager.php
+++ b/lib/private/Avatar/AvatarManager.php
@@ -43,6 +43,7 @@ use OCP\Accounts\PropertyDoesNotExistException;
use OCP\Files\IAppData;
use OCP\Files\NotFoundException;
use OCP\Files\NotPermittedException;
+use OCP\Files\StorageNotAvailableException;
use OCP\IAvatar;
use OCP\IAvatarManager;
use OCP\IConfig;
@@ -173,7 +174,7 @@ class AvatarManager implements IAvatarManager {
$folder->delete();
} catch (NotFoundException $e) {
$this->logger->debug("No cache for the user $userId. Ignoring avatar deletion");
- } catch (NotPermittedException $e) {
+ } catch (NotPermittedException | StorageNotAvailableException $e) {
$this->logger->error("Unable to delete user avatars for $userId. gnoring avatar deletion");
} catch (NoUserException $e) {
$this->logger->debug("User $userId not found. gnoring avatar deletion");
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/Cache/Storage.php b/lib/private/Files/Cache/Storage.php
index 33785607ef7..2de2c2f84d7 100644
--- a/lib/private/Files/Cache/Storage.php
+++ b/lib/private/Files/Cache/Storage.php
@@ -158,7 +158,7 @@ class Storage {
}
/**
- * @return array|null [ available, last_checked ]
+ * @return array [ available, last_checked ]
*/
public function getAvailability() {
if ($row = self::getStorageById($this->storageId)) {
@@ -167,7 +167,10 @@ class Storage {
'last_checked' => $row['last_checked']
];
} else {
- return null;
+ return [
+ 'available' => true,
+ 'last_checked' => time(),
+ ];
}
}
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/Mount/RootMountProvider.php b/lib/private/Files/Mount/RootMountProvider.php
new file mode 100644
index 00000000000..b301fc6dd14
--- /dev/null
+++ b/lib/private/Files/Mount/RootMountProvider.php
@@ -0,0 +1,103 @@
+<?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\Mount;
+
+use OC;
+use OC\Files\ObjectStore\ObjectStoreStorage;
+use OC\Files\Storage\LocalRootStorage;
+use OC_App;
+use OCP\Files\Config\IRootMountProvider;
+use OCP\Files\Storage\IStorageFactory;
+use OCP\IConfig;
+use Psr\Log\LoggerInterface;
+
+class RootMountProvider implements IRootMountProvider {
+ private IConfig $config;
+ private LoggerInterface $logger;
+
+ public function __construct(IConfig $config, LoggerInterface $logger) {
+ $this->config = $config;
+ $this->logger = $logger;
+ }
+
+ public function getRootMounts(IStorageFactory $loader): array {
+ $objectStore = $this->config->getSystemValue('objectstore', null);
+ $objectStoreMultiBucket = $this->config->getSystemValue('objectstore_multibucket', null);
+
+ if ($objectStoreMultiBucket) {
+ return [$this->getMultiBucketStoreRootMount($loader, $objectStoreMultiBucket)];
+ } elseif ($objectStore) {
+ return [$this->getObjectStoreRootMount($loader, $objectStore)];
+ } else {
+ return [$this->getLocalRootMount($loader)];
+ }
+ }
+
+ private function validateObjectStoreConfig(array &$config) {
+ if (empty($config['class'])) {
+ $this->logger->error('No class given for objectstore', ['app' => 'files']);
+ }
+ if (!isset($config['arguments'])) {
+ $config['arguments'] = [];
+ }
+
+ // instantiate object store implementation
+ $name = $config['class'];
+ if (strpos($name, 'OCA\\') === 0 && substr_count($name, '\\') >= 2) {
+ $segments = explode('\\', $name);
+ OC_App::loadApp(strtolower($segments[1]));
+ }
+ }
+
+ private function getLocalRootMount(IStorageFactory $loader): MountPoint {
+ $configDataDirectory = $this->config->getSystemValue("datadirectory", OC::$SERVERROOT . "/data");
+ return new MountPoint(LocalRootStorage::class, '/', ['datadir' => $configDataDirectory], $loader, null, null, self::class);
+ }
+
+ private function getObjectStoreRootMount(IStorageFactory $loader, array $config): MountPoint {
+ $this->validateObjectStoreConfig($config);
+
+ $config['arguments']['objectstore'] = new $config['class']($config['arguments']);
+ // mount with plain / root object store implementation
+ $config['class'] = ObjectStoreStorage::class;
+
+ return new MountPoint($config['class'], '/', $config['arguments'], $loader, null, null, self::class);
+ }
+
+ private function getMultiBucketStoreRootMount(IStorageFactory $loader, array $config): MountPoint {
+ $this->validateObjectStoreConfig($config);
+
+ if (!isset($config['arguments']['bucket'])) {
+ $config['arguments']['bucket'] = '';
+ }
+ // put the root FS always in first bucket for multibucket configuration
+ $config['arguments']['bucket'] .= '0';
+
+ $config['arguments']['objectstore'] = new $config['class']($config['arguments']);
+ // mount with plain / root object store implementation
+ $config['class'] = ObjectStoreStorage::class;
+
+ return new MountPoint($config['class'], '/', $config['arguments'], $loader, null, null, self::class);
+ }
+}
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/SimpleFS/NewSimpleFile.php b/lib/private/Files/SimpleFS/NewSimpleFile.php
index f805403fd87..76fc69ebbe7 100644
--- a/lib/private/Files/SimpleFS/NewSimpleFile.php
+++ b/lib/private/Files/SimpleFS/NewSimpleFile.php
@@ -191,6 +191,17 @@ class NewSimpleFile implements ISimpleFile {
}
/**
+ * {@inheritDoc}
+ */
+ public function getExtension(): string {
+ if ($this->file) {
+ return $this->file->getExtension();
+ } else {
+ return \pathinfo($this->name, PATHINFO_EXTENSION);
+ }
+ }
+
+ /**
* Open the file as stream for reading, resulting resource can be operated as stream like the result from php's own fopen
*
* @return resource
diff --git a/lib/private/Files/SimpleFS/SimpleFile.php b/lib/private/Files/SimpleFS/SimpleFile.php
index baf9b24e020..21a2fd92dcb 100644
--- a/lib/private/Files/SimpleFS/SimpleFile.php
+++ b/lib/private/Files/SimpleFS/SimpleFile.php
@@ -159,6 +159,13 @@ class SimpleFile implements ISimpleFile {
}
/**
+ * {@inheritDoc}
+ */
+ public function getExtension(): string {
+ return $this->file->getExtension();
+ }
+
+ /**
* Open the file as stream for reading, resulting resource can be operated as stream like the result from php's own fopen
*
* @return resource
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/Security/CSP/ContentSecurityPolicy.php b/lib/private/Security/CSP/ContentSecurityPolicy.php
index 78517f639a7..8a72934d4c9 100644
--- a/lib/private/Security/CSP/ContentSecurityPolicy.php
+++ b/lib/private/Security/CSP/ContentSecurityPolicy.php
@@ -244,4 +244,11 @@ class ContentSecurityPolicy extends \OCP\AppFramework\Http\ContentSecurityPolicy
public function setReportTo(array $reportTo) {
$this->reportTo = $reportTo;
}
+
+ /**
+ * @param boolean $strictDynamicAllowed
+ */
+ public function setStrictDynamicAllowed(bool $strictDynamicAllowed) {
+ $this->strictDynamicAllowed = $strictDynamicAllowed;
+ }
}
diff --git a/lib/private/Server.php b/lib/private/Server.php
index ec74857fd20..38720ab71c0 100644
--- a/lib/private/Server.php
+++ b/lib/private/Server.php
@@ -91,9 +91,11 @@ use OC\Files\Mount\CacheMountProvider;
use OC\Files\Mount\LocalHomeMountProvider;
use OC\Files\Mount\ObjectHomeMountProvider;
use OC\Files\Mount\ObjectStorePreviewCacheMountProvider;
+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;
@@ -215,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;
@@ -422,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(
@@ -947,6 +951,7 @@ class Server extends ServerContainer implements IServerContainer {
$manager->registerProvider(new CacheMountProvider($config));
$manager->registerHomeProvider(new LocalHomeMountProvider());
$manager->registerHomeProvider(new ObjectHomeMountProvider($config));
+ $manager->registerRootProvider(new RootMountProvider($config, $c->get(LoggerInterface::class)));
$manager->registerRootProvider(new ObjectStorePreviewCacheMountProvider($logger, $config));
return $manager;
@@ -1089,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/Template/JSResourceLocator.php b/lib/private/Template/JSResourceLocator.php
index 1421e28033a..bf84e1ae958 100644
--- a/lib/private/Template/JSResourceLocator.php
+++ b/lib/private/Template/JSResourceLocator.php
@@ -74,7 +74,7 @@ class JSResourceLocator extends ResourceLocator {
|| $this->cacheAndAppendCombineJsonIfExist($this->serverroot, $script.'.json')
|| $this->appendIfExist($this->serverroot, $theme_dir.'core/'.$script.'.js')
|| $this->appendIfExist($this->serverroot, 'core/'.$script.'.js')
- || $this->appendIfExist($this->serverroot, "dist/core-$scriptName.js")
+ || (strpos($scriptName, '/') === -1 && $this->appendIfExist($this->serverroot, "dist/core-$scriptName.js"))
|| $this->cacheAndAppendCombineJsonIfExist($this->serverroot, 'core/'.$script.'.json')
) {
return;
diff --git a/lib/private/legacy/OC_Util.php b/lib/private/legacy/OC_Util.php
index 9110678537f..ceed79bc9d5 100644
--- a/lib/private/legacy/OC_Util.php
+++ b/lib/private/legacy/OC_Util.php
@@ -66,11 +66,10 @@
use bantu\IniGetWrapper\IniGetWrapper;
use OC\AppFramework\Http\Request;
-use OC\Files\Storage\LocalRootStorage;
+use OC\Files\SetupManager;
use OCP\Files\Template\ITemplateManager;
use OCP\IConfig;
use OCP\IGroupManager;
-use OCP\ILogger;
use OCP\IURLGenerator;
use OCP\IUser;
use OCP\Share\IManager;
@@ -80,9 +79,6 @@ class OC_Util {
public static $scripts = [];
public static $styles = [];
public static $headers = [];
- private static $rootMounted = false;
- private static $rootFsSetup = false;
- private static $fsSetup = false;
/** @var array Local cache of version.php */
private static $versionCache = null;
@@ -91,222 +87,6 @@ class OC_Util {
return \OC::$server->getAppManager();
}
- private static function initLocalStorageRootFS() {
- // mount local file backend as root
- $configDataDirectory = \OC::$server->getSystemConfig()->getValue("datadirectory", OC::$SERVERROOT . "/data");
- //first set up the local "root" storage
- \OC\Files\Filesystem::initMountManager();
- if (!self::$rootMounted) {
- \OC\Files\Filesystem::mount(LocalRootStorage::class, ['datadir' => $configDataDirectory], '/');
- self::$rootMounted = true;
- }
- }
-
- /**
- * mounting an object storage as the root fs will in essence remove the
- * necessity of a data folder being present.
- * TODO make home storage aware of this and use the object storage instead of local disk access
- *
- * @param array $config containing 'class' and optional 'arguments'
- * @suppress PhanDeprecatedFunction
- */
- private static function initObjectStoreRootFS($config) {
- // check misconfiguration
- if (empty($config['class'])) {
- \OCP\Util::writeLog('files', 'No class given for objectstore', ILogger::ERROR);
- }
- if (!isset($config['arguments'])) {
- $config['arguments'] = [];
- }
-
- // instantiate object store implementation
- $name = $config['class'];
- if (strpos($name, 'OCA\\') === 0 && substr_count($name, '\\') >= 2) {
- $segments = explode('\\', $name);
- OC_App::loadApp(strtolower($segments[1]));
- }
- $config['arguments']['objectstore'] = new $config['class']($config['arguments']);
- // mount with plain / root object store implementation
- $config['class'] = '\OC\Files\ObjectStore\ObjectStoreStorage';
-
- // mount object storage as root
- \OC\Files\Filesystem::initMountManager();
- if (!self::$rootMounted) {
- \OC\Files\Filesystem::mount($config['class'], $config['arguments'], '/');
- self::$rootMounted = true;
- }
- }
-
- /**
- * mounting an object storage as the root fs will in essence remove the
- * necessity of a data folder being present.
- *
- * @param array $config containing 'class' and optional 'arguments'
- * @suppress PhanDeprecatedFunction
- */
- private static function initObjectStoreMultibucketRootFS($config) {
- // check misconfiguration
- if (empty($config['class'])) {
- \OCP\Util::writeLog('files', 'No class given for objectstore', ILogger::ERROR);
- }
- if (!isset($config['arguments'])) {
- $config['arguments'] = [];
- }
-
- // instantiate object store implementation
- $name = $config['class'];
- if (strpos($name, 'OCA\\') === 0 && substr_count($name, '\\') >= 2) {
- $segments = explode('\\', $name);
- OC_App::loadApp(strtolower($segments[1]));
- }
-
- if (!isset($config['arguments']['bucket'])) {
- $config['arguments']['bucket'] = '';
- }
- // put the root FS always in first bucket for multibucket configuration
- $config['arguments']['bucket'] .= '0';
-
- $config['arguments']['objectstore'] = new $config['class']($config['arguments']);
- // mount with plain / root object store implementation
- $config['class'] = '\OC\Files\ObjectStore\ObjectStoreStorage';
-
- // mount object storage as root
- \OC\Files\Filesystem::initMountManager();
- if (!self::$rootMounted) {
- \OC\Files\Filesystem::mount($config['class'], $config['arguments'], '/');
- self::$rootMounted = true;
- }
- }
-
- /**
- * 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);
-
- //check if we are using an object storage
- $objectStore = \OC::$server->getSystemConfig()->getValue('objectstore', null);
- $objectStoreMultibucket = \OC::$server->getSystemConfig()->getValue('objectstore_multibucket', null);
-
- // use the same order as in ObjectHomeMountProvider
- if (isset($objectStoreMultibucket)) {
- self::initObjectStoreMultibucketRootFS($objectStoreMultibucket);
- } elseif (isset($objectStore)) {
- self::initObjectStoreRootFS($objectStore);
- } else {
- self::initLocalStorageRootFS();
- }
-
- /** @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
*
@@ -317,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();
@@ -332,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;
}
@@ -497,11 +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;
- self::$rootMounted = false;
+ /** @var SetupManager $setupManager */
+ $setupManager = \OC::$server->get(SetupManager::class);
+ $setupManager->tearDown();
}
/**