summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/autoloader.php5
-rw-r--r--lib/base.php7
-rw-r--r--lib/composer/composer/autoload_classmap.php21
-rw-r--r--lib/composer/composer/autoload_namespaces.php2
-rw-r--r--lib/composer/composer/autoload_psr4.php2
-rw-r--r--lib/composer/composer/autoload_real.php25
-rw-r--r--lib/composer/composer/autoload_static.php19
-rw-r--r--lib/l10n/ar.js3
-rw-r--r--lib/l10n/ar.json3
-rw-r--r--lib/l10n/sv.js20
-rw-r--r--lib/l10n/sv.json20
-rw-r--r--lib/private/Accounts/AccountManager.php11
-rw-r--r--lib/private/AppFramework/App.php33
-rw-r--r--lib/private/AppFramework/Http/Request.php25
-rw-r--r--lib/private/AppFramework/Http/RequestId.php52
-rw-r--r--lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php3
-rw-r--r--lib/private/AppFramework/Utility/SimpleContainer.php8
-rw-r--r--lib/private/Authentication/Token/IProvider.php2
-rw-r--r--lib/private/Authentication/Token/Manager.php6
-rw-r--r--lib/private/Authentication/Token/PublicKeyTokenProvider.php4
-rw-r--r--lib/private/Cache/CappedMemoryCache.php4
-rw-r--r--lib/private/Cache/File.php4
-rw-r--r--lib/private/Comments/EmojiHelper.php101
-rw-r--r--lib/private/Comments/Manager.php10
-rw-r--r--lib/private/Contacts/ContactsMenu/ContactsStore.php4
-rw-r--r--lib/private/Contacts/ContactsMenu/Manager.php4
-rw-r--r--lib/private/DB/Connection.php94
-rw-r--r--lib/private/DB/DbDataCollector.php154
-rw-r--r--lib/private/DB/MigrationService.php11
-rw-r--r--lib/private/DB/ObjectParameter.php71
-rw-r--r--lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php12
-rw-r--r--lib/private/DB/QueryBuilder/FunctionBuilder/OCIFunctionBuilder.php12
-rw-r--r--lib/private/DB/QueryBuilder/FunctionBuilder/SqliteFunctionBuilder.php12
-rw-r--r--lib/private/DB/QueryBuilder/QueryBuilder.php26
-rw-r--r--lib/private/Diagnostics/EventLogger.php3
-rw-r--r--lib/private/Encryption/EncryptionWrapper.php12
-rw-r--r--lib/private/Encryption/Manager.php15
-rw-r--r--lib/private/EventDispatcher/GenericEventWrapper.php8
-rw-r--r--lib/private/EventDispatcher/SymfonyAdapter.php11
-rw-r--r--lib/private/Federation/CloudFederationProviderManager.php12
-rw-r--r--lib/private/Files/Cache/Cache.php5
-rw-r--r--lib/private/Files/Cache/CacheQueryBuilder.php4
-rw-r--r--lib/private/Files/Cache/QuerySearchHelper.php7
-rw-r--r--lib/private/Files/Cache/Storage.php17
-rw-r--r--lib/private/Files/Cache/StorageGlobal.php32
-rw-r--r--lib/private/Files/Config/MountProviderCollection.php34
-rw-r--r--lib/private/Files/Config/UserMountCache.php55
-rw-r--r--lib/private/Files/Filesystem.php27
-rw-r--r--lib/private/Files/Mount/Manager.php21
-rw-r--r--lib/private/Files/Mount/ObjectStorePreviewCacheMountProvider.php7
-rw-r--r--lib/private/Files/Node/Folder.php78
-rw-r--r--lib/private/Files/Node/LazyFolder.php37
-rw-r--r--lib/private/Files/Node/LazyRoot.php4
-rw-r--r--lib/private/Files/Node/LazyUserFolder.php66
-rw-r--r--lib/private/Files/Node/Node.php40
-rw-r--r--lib/private/Files/Node/Root.php115
-rw-r--r--lib/private/Files/ObjectStore/Swift.php3
-rw-r--r--lib/private/Files/ObjectStore/SwiftFactory.php10
-rw-r--r--lib/private/Files/SetupManager.php293
-rw-r--r--lib/private/Files/SetupManagerFactory.php17
-rw-r--r--lib/private/Files/Storage/DAV.php9
-rw-r--r--lib/private/Files/Storage/Wrapper/Encryption.php24
-rw-r--r--lib/private/Files/Type/Detection.php13
-rw-r--r--lib/private/Files/Utils/PathHelper.php71
-rw-r--r--lib/private/Files/Utils/Scanner.php11
-rw-r--r--lib/private/Files/View.php193
-rw-r--r--lib/private/Group/Group.php3
-rw-r--r--lib/private/Group/Manager.php12
-rw-r--r--lib/private/Http/Client/Client.php5
-rw-r--r--lib/private/Http/Client/ClientService.php6
-rw-r--r--lib/private/Http/Client/LocalAddressChecker.php7
-rw-r--r--lib/private/Lock/DBLockingProvider.php13
-rw-r--r--lib/private/Mail/Mailer.php15
-rw-r--r--lib/private/Memcache/APCu.php5
-rw-r--r--lib/private/Memcache/ArrayCache.php2
-rw-r--r--lib/private/Memcache/Factory.php85
-rw-r--r--lib/private/Memcache/LoggerWrapperCache.php177
-rw-r--r--lib/private/Memcache/Memcached.php2
-rw-r--r--lib/private/Memcache/NullCache.php2
-rw-r--r--lib/private/Memcache/ProfilerWrapperCache.php220
-rw-r--r--lib/private/Memcache/Redis.php124
-rw-r--r--lib/private/Migration/SimpleOutput.php8
-rw-r--r--lib/private/Preview/Imaginary.php24
-rw-r--r--lib/private/Profiler/FileProfilerStorage.php286
-rw-r--r--lib/private/Profiler/Profile.php168
-rw-r--r--lib/private/Profiler/Profiler.php105
-rw-r--r--lib/private/Profiler/RoutingDataCollector.php55
-rw-r--r--lib/private/Repair.php11
-rw-r--r--lib/private/Repair/Collation.php19
-rw-r--r--lib/private/Repair/NC16/CleanupCardDAVPhotoCache.php11
-rw-r--r--lib/private/Repair/Owncloud/CleanPreviewsBackgroundJob.php13
-rw-r--r--lib/private/Repair/Owncloud/MigrateOauthTables.php124
-rw-r--r--lib/private/Route/CachingRouter.php5
-rw-r--r--lib/private/Route/Router.php12
-rw-r--r--lib/private/Search/SearchComposer.php14
-rw-r--r--lib/private/Security/Bruteforce/Throttler.php13
-rw-r--r--lib/private/Security/CertificateManager.php40
-rw-r--r--lib/private/Security/IdentityProof/Manager.php7
-rw-r--r--lib/private/Server.php69
-rw-r--r--lib/private/Share20/Manager.php9
-rw-r--r--lib/private/Template/CSSResourceLocator.php5
-rw-r--r--lib/private/Template/IconsCacher.php12
-rw-r--r--lib/private/Template/JSCombiner.php14
-rw-r--r--lib/private/Template/JSResourceLocator.php4
-rwxr-xr-xlib/private/Template/ResourceLocator.php8
-rw-r--r--lib/private/Template/SCSSCacher.php22
-rw-r--r--lib/private/TemplateLayout.php5
-rw-r--r--lib/private/Updater/ChangesCheck.php7
-rw-r--r--lib/private/User/Session.php24
-rw-r--r--lib/private/legacy/OC_Helper.php4
-rw-r--r--lib/private/legacy/OC_Response.php1
-rw-r--r--lib/public/DB/QueryBuilder/IFunctionBuilder.php18
-rw-r--r--lib/public/DataCollector/AbstractDataCollector.php87
-rw-r--r--lib/public/DataCollector/IDataCollector.php55
-rw-r--r--lib/public/Files/Config/IMountProviderCollection.php10
-rw-r--r--lib/public/Files/Config/IUserMountCache.php26
-rw-r--r--lib/public/Files/Events/InvalidateMountCacheEvent.php55
-rw-r--r--lib/public/Files/IRootFolder.php13
-rw-r--r--lib/public/ICache.php6
-rw-r--r--lib/public/IRequestId.php39
-rw-r--r--lib/public/Profiler/IProfile.php168
-rw-r--r--lib/public/Profiler/IProfiler.php101
122 files changed, 3490 insertions, 909 deletions
diff --git a/lib/autoloader.php b/lib/autoloader.php
index c8eebee3e0c..a29b9aece79 100644
--- a/lib/autoloader.php
+++ b/lib/autoloader.php
@@ -38,6 +38,7 @@ namespace OC;
use \OCP\AutoloadNotAllowedException;
use OCP\ILogger;
+use OCP\ICache;
class Autoloader {
/** @var bool */
@@ -182,9 +183,9 @@ class Autoloader {
/**
* Sets the optional low-latency cache for class to path mapping.
*
- * @param \OC\Memcache\Cache $memoryCache Instance of memory cache.
+ * @param ICache $memoryCache Instance of memory cache.
*/
- public function setMemoryCache(\OC\Memcache\Cache $memoryCache = null): void {
+ public function setMemoryCache(ICache $memoryCache = null): void {
$this->memoryCache = $memoryCache;
}
}
diff --git a/lib/base.php b/lib/base.php
index 2dd878fdbbc..21889272dd7 100644
--- a/lib/base.php
+++ b/lib/base.php
@@ -161,7 +161,11 @@ class OC {
'SCRIPT_FILENAME' => $_SERVER['SCRIPT_FILENAME'],
],
];
- $fakeRequest = new \OC\AppFramework\Http\Request($params, new \OC\Security\SecureRandom(), new \OC\AllConfig(new \OC\SystemConfig(self::$config)));
+ $fakeRequest = new \OC\AppFramework\Http\Request(
+ $params,
+ new \OC\AppFramework\Http\RequestId($_SERVER['UNIQUE_ID'] ?? '', new \OC\Security\SecureRandom()),
+ new \OC\AllConfig(new \OC\SystemConfig(self::$config))
+ );
$scriptName = $fakeRequest->getScriptName();
if (substr($scriptName, -1) == '/') {
$scriptName .= 'index.php';
@@ -604,6 +608,7 @@ class OC {
$eventLogger->end('request');
});
$eventLogger->start('boot', 'Initialize');
+ $eventLogger->start('runtime', 'Runtime (total - autoloader)');
// Override php.ini and log everything if we're troubleshooting
if (self::$config->getValue('loglevel') === ILogger::DEBUG) {
diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php
index b6af8b8cef4..c821786b74b 100644
--- a/lib/composer/composer/autoload_classmap.php
+++ b/lib/composer/composer/autoload_classmap.php
@@ -2,7 +2,7 @@
// autoload_classmap.php @generated by Composer
-$vendorDir = dirname(dirname(__FILE__));
+$vendorDir = dirname(__DIR__);
$baseDir = dirname(dirname($vendorDir));
return array(
@@ -196,6 +196,8 @@ return array(
'OCP\\Dashboard\\RegisterWidgetEvent' => $baseDir . '/lib/public/Dashboard/RegisterWidgetEvent.php',
'OCP\\Dashboard\\Service\\IEventsService' => $baseDir . '/lib/public/Dashboard/Service/IEventsService.php',
'OCP\\Dashboard\\Service\\IWidgetsService' => $baseDir . '/lib/public/Dashboard/Service/IWidgetsService.php',
+ 'OCP\\DataCollector\\AbstractDataCollector' => $baseDir . '/lib/public/DataCollector/AbstractDataCollector.php',
+ 'OCP\\DataCollector\\IDataCollector' => $baseDir . '/lib/public/DataCollector/IDataCollector.php',
'OCP\\Defaults' => $baseDir . '/lib/public/Defaults.php',
'OCP\\Diagnostics\\IEvent' => $baseDir . '/lib/public/Diagnostics/IEvent.php',
'OCP\\Diagnostics\\IEventLogger' => $baseDir . '/lib/public/Diagnostics/IEventLogger.php',
@@ -260,6 +262,7 @@ return array(
'OCP\\Files\\Events\\FileCacheUpdated' => $baseDir . '/lib/public/Files/Events/FileCacheUpdated.php',
'OCP\\Files\\Events\\FileScannedEvent' => $baseDir . '/lib/public/Files/Events/FileScannedEvent.php',
'OCP\\Files\\Events\\FolderScannedEvent' => $baseDir . '/lib/public/Files/Events/FolderScannedEvent.php',
+ 'OCP\\Files\\Events\\InvalidateMountCacheEvent' => $baseDir . '/lib/public/Files/Events/InvalidateMountCacheEvent.php',
'OCP\\Files\\Events\\NodeAddedToCache' => $baseDir . '/lib/public/Files/Events/NodeAddedToCache.php',
'OCP\\Files\\Events\\NodeRemovedFromCache' => $baseDir . '/lib/public/Files/Events/NodeRemovedFromCache.php',
'OCP\\Files\\Events\\Node\\AbstractNodeEvent' => $baseDir . '/lib/public/Files/Events/Node/AbstractNodeEvent.php',
@@ -412,6 +415,7 @@ return array(
'OCP\\INavigationManager' => $baseDir . '/lib/public/INavigationManager.php',
'OCP\\IPreview' => $baseDir . '/lib/public/IPreview.php',
'OCP\\IRequest' => $baseDir . '/lib/public/IRequest.php',
+ 'OCP\\IRequestId' => $baseDir . '/lib/public/IRequestId.php',
'OCP\\ISearch' => $baseDir . '/lib/public/ISearch.php',
'OCP\\IServerContainer' => $baseDir . '/lib/public/IServerContainer.php',
'OCP\\ISession' => $baseDir . '/lib/public/ISession.php',
@@ -465,6 +469,8 @@ return array(
'OCP\\Preview\\IVersionedPreviewFile' => $baseDir . '/lib/public/Preview/IVersionedPreviewFile.php',
'OCP\\Profile\\ILinkAction' => $baseDir . '/lib/public/Profile/ILinkAction.php',
'OCP\\Profile\\ParameterDoesNotExistException' => $baseDir . '/lib/public/Profile/ParameterDoesNotExistException.php',
+ 'OCP\\Profiler\\IProfile' => $baseDir . '/lib/public/Profiler/IProfile.php',
+ 'OCP\\Profiler\\IProfiler' => $baseDir . '/lib/public/Profiler/IProfiler.php',
'OCP\\Remote\\Api\\IApiCollection' => $baseDir . '/lib/public/Remote/Api/IApiCollection.php',
'OCP\\Remote\\Api\\IApiFactory' => $baseDir . '/lib/public/Remote/Api/IApiFactory.php',
'OCP\\Remote\\Api\\ICapabilitiesApi' => $baseDir . '/lib/public/Remote/Api/ICapabilitiesApi.php',
@@ -635,6 +641,7 @@ return array(
'OC\\AppFramework\\Http\\Dispatcher' => $baseDir . '/lib/private/AppFramework/Http/Dispatcher.php',
'OC\\AppFramework\\Http\\Output' => $baseDir . '/lib/private/AppFramework/Http/Output.php',
'OC\\AppFramework\\Http\\Request' => $baseDir . '/lib/private/AppFramework/Http/Request.php',
+ 'OC\\AppFramework\\Http\\RequestId' => $baseDir . '/lib/private/AppFramework/Http/RequestId.php',
'OC\\AppFramework\\Logger' => $baseDir . '/lib/private/AppFramework/Logger.php',
'OC\\AppFramework\\Middleware\\AdditionalScriptsMiddleware' => $baseDir . '/lib/private/AppFramework/Middleware/AdditionalScriptsMiddleware.php',
'OC\\AppFramework\\Middleware\\CompressionMiddleware' => $baseDir . '/lib/private/AppFramework/Middleware/CompressionMiddleware.php',
@@ -806,6 +813,7 @@ return array(
'OC\\Command\\FileAccess' => $baseDir . '/lib/private/Command/FileAccess.php',
'OC\\Command\\QueueBus' => $baseDir . '/lib/private/Command/QueueBus.php',
'OC\\Comments\\Comment' => $baseDir . '/lib/private/Comments/Comment.php',
+ 'OC\\Comments\\EmojiHelper' => $baseDir . '/lib/private/Comments/EmojiHelper.php',
'OC\\Comments\\Manager' => $baseDir . '/lib/private/Comments/Manager.php',
'OC\\Comments\\ManagerFactory' => $baseDir . '/lib/private/Comments/ManagerFactory.php',
'OC\\Config' => $baseDir . '/lib/private/Config.php',
@@ -1021,6 +1029,7 @@ return array(
'OC\\DB\\Connection' => $baseDir . '/lib/private/DB/Connection.php',
'OC\\DB\\ConnectionAdapter' => $baseDir . '/lib/private/DB/ConnectionAdapter.php',
'OC\\DB\\ConnectionFactory' => $baseDir . '/lib/private/DB/ConnectionFactory.php',
+ 'OC\\DB\\DbDataCollector' => $baseDir . '/lib/private/DB/DbDataCollector.php',
'OC\\DB\\Exceptions\\DbalException' => $baseDir . '/lib/private/DB/Exceptions/DbalException.php',
'OC\\DB\\MigrationException' => $baseDir . '/lib/private/DB/MigrationException.php',
'OC\\DB\\MigrationService' => $baseDir . '/lib/private/DB/MigrationService.php',
@@ -1031,6 +1040,7 @@ return array(
'OC\\DB\\MySQLMigrator' => $baseDir . '/lib/private/DB/MySQLMigrator.php',
'OC\\DB\\MySqlTools' => $baseDir . '/lib/private/DB/MySqlTools.php',
'OC\\DB\\OCSqlitePlatform' => $baseDir . '/lib/private/DB/OCSqlitePlatform.php',
+ 'OC\\DB\\ObjectParameter' => $baseDir . '/lib/private/DB/ObjectParameter.php',
'OC\\DB\\OracleConnection' => $baseDir . '/lib/private/DB/OracleConnection.php',
'OC\\DB\\OracleMigrator' => $baseDir . '/lib/private/DB/OracleMigrator.php',
'OC\\DB\\PgSqlTools' => $baseDir . '/lib/private/DB/PgSqlTools.php',
@@ -1138,6 +1148,7 @@ return array(
'OC\\Files\\Node\\HookConnector' => $baseDir . '/lib/private/Files/Node/HookConnector.php',
'OC\\Files\\Node\\LazyFolder' => $baseDir . '/lib/private/Files/Node/LazyFolder.php',
'OC\\Files\\Node\\LazyRoot' => $baseDir . '/lib/private/Files/Node/LazyRoot.php',
+ 'OC\\Files\\Node\\LazyUserFolder' => $baseDir . '/lib/private/Files/Node/LazyUserFolder.php',
'OC\\Files\\Node\\Node' => $baseDir . '/lib/private/Files/Node/Node.php',
'OC\\Files\\Node\\NonExistingFile' => $baseDir . '/lib/private/Files/Node/NonExistingFile.php',
'OC\\Files\\Node\\NonExistingFolder' => $baseDir . '/lib/private/Files/Node/NonExistingFolder.php',
@@ -1198,6 +1209,7 @@ return array(
'OC\\Files\\Type\\Detection' => $baseDir . '/lib/private/Files/Type/Detection.php',
'OC\\Files\\Type\\Loader' => $baseDir . '/lib/private/Files/Type/Loader.php',
'OC\\Files\\Type\\TemplateManager' => $baseDir . '/lib/private/Files/Type/TemplateManager.php',
+ 'OC\\Files\\Utils\\PathHelper' => $baseDir . '/lib/private/Files/Utils/PathHelper.php',
'OC\\Files\\Utils\\Scanner' => $baseDir . '/lib/private/Files/Utils/Scanner.php',
'OC\\Files\\View' => $baseDir . '/lib/private/Files/View.php',
'OC\\ForbiddenException' => $baseDir . '/lib/private/ForbiddenException.php',
@@ -1274,8 +1286,10 @@ return array(
'OC\\Memcache\\CASTrait' => $baseDir . '/lib/private/Memcache/CASTrait.php',
'OC\\Memcache\\Cache' => $baseDir . '/lib/private/Memcache/Cache.php',
'OC\\Memcache\\Factory' => $baseDir . '/lib/private/Memcache/Factory.php',
+ 'OC\\Memcache\\LoggerWrapperCache' => $baseDir . '/lib/private/Memcache/LoggerWrapperCache.php',
'OC\\Memcache\\Memcached' => $baseDir . '/lib/private/Memcache/Memcached.php',
'OC\\Memcache\\NullCache' => $baseDir . '/lib/private/Memcache/NullCache.php',
+ 'OC\\Memcache\\ProfilerWrapperCache' => $baseDir . '/lib/private/Memcache/ProfilerWrapperCache.php',
'OC\\Memcache\\Redis' => $baseDir . '/lib/private/Memcache/Redis.php',
'OC\\MemoryInfo' => $baseDir . '/lib/private/MemoryInfo.php',
'OC\\Migration\\BackgroundRepair' => $baseDir . '/lib/private/Migration/BackgroundRepair.php',
@@ -1342,6 +1356,10 @@ return array(
'OC\\Profile\\Actions\\WebsiteAction' => $baseDir . '/lib/private/Profile/Actions/WebsiteAction.php',
'OC\\Profile\\ProfileManager' => $baseDir . '/lib/private/Profile/ProfileManager.php',
'OC\\Profile\\TProfileHelper' => $baseDir . '/lib/private/Profile/TProfileHelper.php',
+ 'OC\\Profiler\\FileProfilerStorage' => $baseDir . '/lib/private/Profiler/FileProfilerStorage.php',
+ 'OC\\Profiler\\Profile' => $baseDir . '/lib/private/Profiler/Profile.php',
+ 'OC\\Profiler\\Profiler' => $baseDir . '/lib/private/Profiler/Profiler.php',
+ 'OC\\Profiler\\RoutingDataCollector' => $baseDir . '/lib/private/Profiler/RoutingDataCollector.php',
'OC\\RedisFactory' => $baseDir . '/lib/private/RedisFactory.php',
'OC\\Remote\\Api\\ApiBase' => $baseDir . '/lib/private/Remote/Api/ApiBase.php',
'OC\\Remote\\Api\\ApiCollection' => $baseDir . '/lib/private/Remote/Api/ApiCollection.php',
@@ -1379,6 +1397,7 @@ return array(
'OC\\Repair\\Owncloud\\CleanPreviewsBackgroundJob' => $baseDir . '/lib/private/Repair/Owncloud/CleanPreviewsBackgroundJob.php',
'OC\\Repair\\Owncloud\\DropAccountTermsTable' => $baseDir . '/lib/private/Repair/Owncloud/DropAccountTermsTable.php',
'OC\\Repair\\Owncloud\\InstallCoreBundle' => $baseDir . '/lib/private/Repair/Owncloud/InstallCoreBundle.php',
+ 'OC\\Repair\\Owncloud\\MigrateOauthTables' => $baseDir . '/lib/private/Repair/Owncloud/MigrateOauthTables.php',
'OC\\Repair\\Owncloud\\MoveAvatars' => $baseDir . '/lib/private/Repair/Owncloud/MoveAvatars.php',
'OC\\Repair\\Owncloud\\MoveAvatarsBackgroundJob' => $baseDir . '/lib/private/Repair/Owncloud/MoveAvatarsBackgroundJob.php',
'OC\\Repair\\Owncloud\\SaveAccountsTableData' => $baseDir . '/lib/private/Repair/Owncloud/SaveAccountsTableData.php',
diff --git a/lib/composer/composer/autoload_namespaces.php b/lib/composer/composer/autoload_namespaces.php
index 4a9c20beed0..f1ae7a0ffec 100644
--- a/lib/composer/composer/autoload_namespaces.php
+++ b/lib/composer/composer/autoload_namespaces.php
@@ -2,7 +2,7 @@
// autoload_namespaces.php @generated by Composer
-$vendorDir = dirname(dirname(__FILE__));
+$vendorDir = dirname(__DIR__);
$baseDir = dirname(dirname($vendorDir));
return array(
diff --git a/lib/composer/composer/autoload_psr4.php b/lib/composer/composer/autoload_psr4.php
index b641d9c6a03..74e48cf69ae 100644
--- a/lib/composer/composer/autoload_psr4.php
+++ b/lib/composer/composer/autoload_psr4.php
@@ -2,7 +2,7 @@
// autoload_psr4.php @generated by Composer
-$vendorDir = dirname(dirname(__FILE__));
+$vendorDir = dirname(__DIR__);
$baseDir = dirname(dirname($vendorDir));
return array(
diff --git a/lib/composer/composer/autoload_real.php b/lib/composer/composer/autoload_real.php
index a5748c7a891..4b1ab7678ec 100644
--- a/lib/composer/composer/autoload_real.php
+++ b/lib/composer/composer/autoload_real.php
@@ -23,30 +23,11 @@ class ComposerAutoloaderInit53792487c5a8370acc0b06b1a864ff4c
}
spl_autoload_register(array('ComposerAutoloaderInit53792487c5a8370acc0b06b1a864ff4c', 'loadClassLoader'), true, true);
- self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(\dirname(__FILE__)));
+ self::$loader = $loader = new \Composer\Autoload\ClassLoader(\dirname(__DIR__));
spl_autoload_unregister(array('ComposerAutoloaderInit53792487c5a8370acc0b06b1a864ff4c', 'loadClassLoader'));
- $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
- if ($useStaticLoader) {
- require __DIR__ . '/autoload_static.php';
-
- call_user_func(\Composer\Autoload\ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c::getInitializer($loader));
- } else {
- $map = require __DIR__ . '/autoload_namespaces.php';
- foreach ($map as $namespace => $path) {
- $loader->set($namespace, $path);
- }
-
- $map = require __DIR__ . '/autoload_psr4.php';
- foreach ($map as $namespace => $path) {
- $loader->setPsr4($namespace, $path);
- }
-
- $classMap = require __DIR__ . '/autoload_classmap.php';
- if ($classMap) {
- $loader->addClassMap($classMap);
- }
- }
+ require __DIR__ . '/autoload_static.php';
+ \Composer\Autoload\ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c::getInitializer($loader)();
$loader->register(true);
diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php
index b1e9912f506..1d414814fc4 100644
--- a/lib/composer/composer/autoload_static.php
+++ b/lib/composer/composer/autoload_static.php
@@ -225,6 +225,8 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OCP\\Dashboard\\RegisterWidgetEvent' => __DIR__ . '/../../..' . '/lib/public/Dashboard/RegisterWidgetEvent.php',
'OCP\\Dashboard\\Service\\IEventsService' => __DIR__ . '/../../..' . '/lib/public/Dashboard/Service/IEventsService.php',
'OCP\\Dashboard\\Service\\IWidgetsService' => __DIR__ . '/../../..' . '/lib/public/Dashboard/Service/IWidgetsService.php',
+ 'OCP\\DataCollector\\AbstractDataCollector' => __DIR__ . '/../../..' . '/lib/public/DataCollector/AbstractDataCollector.php',
+ 'OCP\\DataCollector\\IDataCollector' => __DIR__ . '/../../..' . '/lib/public/DataCollector/IDataCollector.php',
'OCP\\Defaults' => __DIR__ . '/../../..' . '/lib/public/Defaults.php',
'OCP\\Diagnostics\\IEvent' => __DIR__ . '/../../..' . '/lib/public/Diagnostics/IEvent.php',
'OCP\\Diagnostics\\IEventLogger' => __DIR__ . '/../../..' . '/lib/public/Diagnostics/IEventLogger.php',
@@ -289,6 +291,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OCP\\Files\\Events\\FileCacheUpdated' => __DIR__ . '/../../..' . '/lib/public/Files/Events/FileCacheUpdated.php',
'OCP\\Files\\Events\\FileScannedEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Events/FileScannedEvent.php',
'OCP\\Files\\Events\\FolderScannedEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Events/FolderScannedEvent.php',
+ 'OCP\\Files\\Events\\InvalidateMountCacheEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Events/InvalidateMountCacheEvent.php',
'OCP\\Files\\Events\\NodeAddedToCache' => __DIR__ . '/../../..' . '/lib/public/Files/Events/NodeAddedToCache.php',
'OCP\\Files\\Events\\NodeRemovedFromCache' => __DIR__ . '/../../..' . '/lib/public/Files/Events/NodeRemovedFromCache.php',
'OCP\\Files\\Events\\Node\\AbstractNodeEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Events/Node/AbstractNodeEvent.php',
@@ -441,6 +444,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OCP\\INavigationManager' => __DIR__ . '/../../..' . '/lib/public/INavigationManager.php',
'OCP\\IPreview' => __DIR__ . '/../../..' . '/lib/public/IPreview.php',
'OCP\\IRequest' => __DIR__ . '/../../..' . '/lib/public/IRequest.php',
+ 'OCP\\IRequestId' => __DIR__ . '/../../..' . '/lib/public/IRequestId.php',
'OCP\\ISearch' => __DIR__ . '/../../..' . '/lib/public/ISearch.php',
'OCP\\IServerContainer' => __DIR__ . '/../../..' . '/lib/public/IServerContainer.php',
'OCP\\ISession' => __DIR__ . '/../../..' . '/lib/public/ISession.php',
@@ -494,6 +498,8 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OCP\\Preview\\IVersionedPreviewFile' => __DIR__ . '/../../..' . '/lib/public/Preview/IVersionedPreviewFile.php',
'OCP\\Profile\\ILinkAction' => __DIR__ . '/../../..' . '/lib/public/Profile/ILinkAction.php',
'OCP\\Profile\\ParameterDoesNotExistException' => __DIR__ . '/../../..' . '/lib/public/Profile/ParameterDoesNotExistException.php',
+ 'OCP\\Profiler\\IProfile' => __DIR__ . '/../../..' . '/lib/public/Profiler/IProfile.php',
+ 'OCP\\Profiler\\IProfiler' => __DIR__ . '/../../..' . '/lib/public/Profiler/IProfiler.php',
'OCP\\Remote\\Api\\IApiCollection' => __DIR__ . '/../../..' . '/lib/public/Remote/Api/IApiCollection.php',
'OCP\\Remote\\Api\\IApiFactory' => __DIR__ . '/../../..' . '/lib/public/Remote/Api/IApiFactory.php',
'OCP\\Remote\\Api\\ICapabilitiesApi' => __DIR__ . '/../../..' . '/lib/public/Remote/Api/ICapabilitiesApi.php',
@@ -664,6 +670,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\AppFramework\\Http\\Dispatcher' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Http/Dispatcher.php',
'OC\\AppFramework\\Http\\Output' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Http/Output.php',
'OC\\AppFramework\\Http\\Request' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Http/Request.php',
+ 'OC\\AppFramework\\Http\\RequestId' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Http/RequestId.php',
'OC\\AppFramework\\Logger' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Logger.php',
'OC\\AppFramework\\Middleware\\AdditionalScriptsMiddleware' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Middleware/AdditionalScriptsMiddleware.php',
'OC\\AppFramework\\Middleware\\CompressionMiddleware' => __DIR__ . '/../../..' . '/lib/private/AppFramework/Middleware/CompressionMiddleware.php',
@@ -835,6 +842,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\Command\\FileAccess' => __DIR__ . '/../../..' . '/lib/private/Command/FileAccess.php',
'OC\\Command\\QueueBus' => __DIR__ . '/../../..' . '/lib/private/Command/QueueBus.php',
'OC\\Comments\\Comment' => __DIR__ . '/../../..' . '/lib/private/Comments/Comment.php',
+ 'OC\\Comments\\EmojiHelper' => __DIR__ . '/../../..' . '/lib/private/Comments/EmojiHelper.php',
'OC\\Comments\\Manager' => __DIR__ . '/../../..' . '/lib/private/Comments/Manager.php',
'OC\\Comments\\ManagerFactory' => __DIR__ . '/../../..' . '/lib/private/Comments/ManagerFactory.php',
'OC\\Config' => __DIR__ . '/../../..' . '/lib/private/Config.php',
@@ -1050,6 +1058,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\DB\\Connection' => __DIR__ . '/../../..' . '/lib/private/DB/Connection.php',
'OC\\DB\\ConnectionAdapter' => __DIR__ . '/../../..' . '/lib/private/DB/ConnectionAdapter.php',
'OC\\DB\\ConnectionFactory' => __DIR__ . '/../../..' . '/lib/private/DB/ConnectionFactory.php',
+ 'OC\\DB\\DbDataCollector' => __DIR__ . '/../../..' . '/lib/private/DB/DbDataCollector.php',
'OC\\DB\\Exceptions\\DbalException' => __DIR__ . '/../../..' . '/lib/private/DB/Exceptions/DbalException.php',
'OC\\DB\\MigrationException' => __DIR__ . '/../../..' . '/lib/private/DB/MigrationException.php',
'OC\\DB\\MigrationService' => __DIR__ . '/../../..' . '/lib/private/DB/MigrationService.php',
@@ -1060,6 +1069,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\DB\\MySQLMigrator' => __DIR__ . '/../../..' . '/lib/private/DB/MySQLMigrator.php',
'OC\\DB\\MySqlTools' => __DIR__ . '/../../..' . '/lib/private/DB/MySqlTools.php',
'OC\\DB\\OCSqlitePlatform' => __DIR__ . '/../../..' . '/lib/private/DB/OCSqlitePlatform.php',
+ 'OC\\DB\\ObjectParameter' => __DIR__ . '/../../..' . '/lib/private/DB/ObjectParameter.php',
'OC\\DB\\OracleConnection' => __DIR__ . '/../../..' . '/lib/private/DB/OracleConnection.php',
'OC\\DB\\OracleMigrator' => __DIR__ . '/../../..' . '/lib/private/DB/OracleMigrator.php',
'OC\\DB\\PgSqlTools' => __DIR__ . '/../../..' . '/lib/private/DB/PgSqlTools.php',
@@ -1167,6 +1177,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\Files\\Node\\HookConnector' => __DIR__ . '/../../..' . '/lib/private/Files/Node/HookConnector.php',
'OC\\Files\\Node\\LazyFolder' => __DIR__ . '/../../..' . '/lib/private/Files/Node/LazyFolder.php',
'OC\\Files\\Node\\LazyRoot' => __DIR__ . '/../../..' . '/lib/private/Files/Node/LazyRoot.php',
+ 'OC\\Files\\Node\\LazyUserFolder' => __DIR__ . '/../../..' . '/lib/private/Files/Node/LazyUserFolder.php',
'OC\\Files\\Node\\Node' => __DIR__ . '/../../..' . '/lib/private/Files/Node/Node.php',
'OC\\Files\\Node\\NonExistingFile' => __DIR__ . '/../../..' . '/lib/private/Files/Node/NonExistingFile.php',
'OC\\Files\\Node\\NonExistingFolder' => __DIR__ . '/../../..' . '/lib/private/Files/Node/NonExistingFolder.php',
@@ -1227,6 +1238,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\Files\\Type\\Detection' => __DIR__ . '/../../..' . '/lib/private/Files/Type/Detection.php',
'OC\\Files\\Type\\Loader' => __DIR__ . '/../../..' . '/lib/private/Files/Type/Loader.php',
'OC\\Files\\Type\\TemplateManager' => __DIR__ . '/../../..' . '/lib/private/Files/Type/TemplateManager.php',
+ 'OC\\Files\\Utils\\PathHelper' => __DIR__ . '/../../..' . '/lib/private/Files/Utils/PathHelper.php',
'OC\\Files\\Utils\\Scanner' => __DIR__ . '/../../..' . '/lib/private/Files/Utils/Scanner.php',
'OC\\Files\\View' => __DIR__ . '/../../..' . '/lib/private/Files/View.php',
'OC\\ForbiddenException' => __DIR__ . '/../../..' . '/lib/private/ForbiddenException.php',
@@ -1303,8 +1315,10 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\Memcache\\CASTrait' => __DIR__ . '/../../..' . '/lib/private/Memcache/CASTrait.php',
'OC\\Memcache\\Cache' => __DIR__ . '/../../..' . '/lib/private/Memcache/Cache.php',
'OC\\Memcache\\Factory' => __DIR__ . '/../../..' . '/lib/private/Memcache/Factory.php',
+ 'OC\\Memcache\\LoggerWrapperCache' => __DIR__ . '/../../..' . '/lib/private/Memcache/LoggerWrapperCache.php',
'OC\\Memcache\\Memcached' => __DIR__ . '/../../..' . '/lib/private/Memcache/Memcached.php',
'OC\\Memcache\\NullCache' => __DIR__ . '/../../..' . '/lib/private/Memcache/NullCache.php',
+ 'OC\\Memcache\\ProfilerWrapperCache' => __DIR__ . '/../../..' . '/lib/private/Memcache/ProfilerWrapperCache.php',
'OC\\Memcache\\Redis' => __DIR__ . '/../../..' . '/lib/private/Memcache/Redis.php',
'OC\\MemoryInfo' => __DIR__ . '/../../..' . '/lib/private/MemoryInfo.php',
'OC\\Migration\\BackgroundRepair' => __DIR__ . '/../../..' . '/lib/private/Migration/BackgroundRepair.php',
@@ -1371,6 +1385,10 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\Profile\\Actions\\WebsiteAction' => __DIR__ . '/../../..' . '/lib/private/Profile/Actions/WebsiteAction.php',
'OC\\Profile\\ProfileManager' => __DIR__ . '/../../..' . '/lib/private/Profile/ProfileManager.php',
'OC\\Profile\\TProfileHelper' => __DIR__ . '/../../..' . '/lib/private/Profile/TProfileHelper.php',
+ 'OC\\Profiler\\FileProfilerStorage' => __DIR__ . '/../../..' . '/lib/private/Profiler/FileProfilerStorage.php',
+ 'OC\\Profiler\\Profile' => __DIR__ . '/../../..' . '/lib/private/Profiler/Profile.php',
+ 'OC\\Profiler\\Profiler' => __DIR__ . '/../../..' . '/lib/private/Profiler/Profiler.php',
+ 'OC\\Profiler\\RoutingDataCollector' => __DIR__ . '/../../..' . '/lib/private/Profiler/RoutingDataCollector.php',
'OC\\RedisFactory' => __DIR__ . '/../../..' . '/lib/private/RedisFactory.php',
'OC\\Remote\\Api\\ApiBase' => __DIR__ . '/../../..' . '/lib/private/Remote/Api/ApiBase.php',
'OC\\Remote\\Api\\ApiCollection' => __DIR__ . '/../../..' . '/lib/private/Remote/Api/ApiCollection.php',
@@ -1408,6 +1426,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c
'OC\\Repair\\Owncloud\\CleanPreviewsBackgroundJob' => __DIR__ . '/../../..' . '/lib/private/Repair/Owncloud/CleanPreviewsBackgroundJob.php',
'OC\\Repair\\Owncloud\\DropAccountTermsTable' => __DIR__ . '/../../..' . '/lib/private/Repair/Owncloud/DropAccountTermsTable.php',
'OC\\Repair\\Owncloud\\InstallCoreBundle' => __DIR__ . '/../../..' . '/lib/private/Repair/Owncloud/InstallCoreBundle.php',
+ 'OC\\Repair\\Owncloud\\MigrateOauthTables' => __DIR__ . '/../../..' . '/lib/private/Repair/Owncloud/MigrateOauthTables.php',
'OC\\Repair\\Owncloud\\MoveAvatars' => __DIR__ . '/../../..' . '/lib/private/Repair/Owncloud/MoveAvatars.php',
'OC\\Repair\\Owncloud\\MoveAvatarsBackgroundJob' => __DIR__ . '/../../..' . '/lib/private/Repair/Owncloud/MoveAvatarsBackgroundJob.php',
'OC\\Repair\\Owncloud\\SaveAccountsTableData' => __DIR__ . '/../../..' . '/lib/private/Repair/Owncloud/SaveAccountsTableData.php',
diff --git a/lib/l10n/ar.js b/lib/l10n/ar.js
index 8a986850199..853182c5df0 100644
--- a/lib/l10n/ar.js
+++ b/lib/l10n/ar.js
@@ -118,6 +118,7 @@ OC.L10N.register(
"This can usually be fixed by giving the webserver write access to the config directory" : "يمكن حل هذا عادة بإعطاء خادم الوب صلاحية الكتابة في مجلد config",
"Can't create or write into the data directory %s" : "لا يمكن الإنشاء أو الكتابة في مجلد البيانات %s",
"Can't read file" : "لا يمكن قراءة الملف",
- "This can usually be fixed by giving the webserver write access to the config directory. See %s" : "يمكن إصلاح هذا الخطا بإعطاء مخدّم الموقع صلاحيات التعديل على مجلد الإعدادات. أنظر %s"
+ "This can usually be fixed by giving the webserver write access to the config directory. See %s" : "يمكن إصلاح هذا الخطا بإعطاء مخدّم الموقع صلاحيات التعديل على مجلد الإعدادات. أنظر %s",
+ "Please upgrade your database version" : "فضلًا قم بتحديث إصدار قاعدة بياناتك"
},
"nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;");
diff --git a/lib/l10n/ar.json b/lib/l10n/ar.json
index 2b4bdc5bd6b..ce726d3b323 100644
--- a/lib/l10n/ar.json
+++ b/lib/l10n/ar.json
@@ -116,6 +116,7 @@
"This can usually be fixed by giving the webserver write access to the config directory" : "يمكن حل هذا عادة بإعطاء خادم الوب صلاحية الكتابة في مجلد config",
"Can't create or write into the data directory %s" : "لا يمكن الإنشاء أو الكتابة في مجلد البيانات %s",
"Can't read file" : "لا يمكن قراءة الملف",
- "This can usually be fixed by giving the webserver write access to the config directory. See %s" : "يمكن إصلاح هذا الخطا بإعطاء مخدّم الموقع صلاحيات التعديل على مجلد الإعدادات. أنظر %s"
+ "This can usually be fixed by giving the webserver write access to the config directory. See %s" : "يمكن إصلاح هذا الخطا بإعطاء مخدّم الموقع صلاحيات التعديل على مجلد الإعدادات. أنظر %s",
+ "Please upgrade your database version" : "فضلًا قم بتحديث إصدار قاعدة بياناتك"
},"pluralForm" :"nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;"
} \ No newline at end of file
diff --git a/lib/l10n/sv.js b/lib/l10n/sv.js
index ef690b97a68..d698b06e082 100644
--- a/lib/l10n/sv.js
+++ b/lib/l10n/sv.js
@@ -6,7 +6,7 @@ OC.L10N.register(
"See %s" : "Se %s",
"The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Filerna i appen %1$s ersattes inte korrekt. Kontrollera att det är en version som är kompatibel med servern.",
"Sample configuration detected" : "Exempel-konfiguration detekterad",
- "It has been detected that the sample configuration has been copied. This can break your installation and is unsupported. Please read the documentation before performing changes on config.php" : "Det har upptäckts att provkonfigurationen har kopierats. Detta kan bryta din installation och stöds inte. Vänligen läs dokumentationen innan du utför ändringar på config.php",
+ "It has been detected that the sample configuration has been copied. This can break your installation and is unsupported. Please read the documentation before performing changes on config.php" : "Det har upptäckts att provkonfigurationen har kopierats. Detta kan bryta din installation och stöds inte. Läs dokumentationen innan du utför ändringar på config.php",
"%s email verification" : "%s e-postverifikation",
"Email verification" : "E-postverifikation",
"Click the following button to confirm your email." : "Klicka på följande knapp för att verifiera din e-postadress.",
@@ -120,9 +120,9 @@ OC.L10N.register(
"Oracle username and/or password not valid" : "Oracle-användarnamnet och/eller lösenordet är felaktigt",
"PostgreSQL username and/or password not valid" : "PostgreSQL-användarnamnet och/eller lösenordet är felaktigt",
"Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X stöds inte och %s kommer inte att fungera korrekt på denna plattform. Använd på egen risk!",
- "For the best results, please consider using a GNU/Linux server instead." : "För bästa resultat, vänligen överväg att använda en GNU/Linux-server istället.",
+ "For the best results, please consider using a GNU/Linux server instead." : "För bästa resultat, överväg att använda en GNU/Linux-server istället.",
"It seems that this %s instance is running on a 32-bit PHP environment and the open_basedir has been configured in php.ini. This will lead to problems with files over 4 GB and is highly discouraged." : "Det verkar som om denna %s instans körs på en 32-bitars PHP miljö och open_basedir har konfigurerats i php.ini. Detta kommer att leda till problem med filer över 4 GB och är verkligen inte rekommenderat!",
- "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Vänligen ta bort open_basedir-inställningen i din php.ini eller växla till 64-bitars PHP.",
+ "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Ta bort open_basedir-inställningen i din php.ini eller växla till 64-bitars PHP.",
"Set an admin username." : "Ange ett användarnamn för administratören.",
"Set an admin password." : "Ange ett administratörslösenord.",
"Cannot create or write into the data directory %s" : "Kan inte skapa eller skriva till data-katalogen %s",
@@ -205,15 +205,15 @@ OC.L10N.register(
"Login canceled by app" : "Inloggningen avbruten av appen",
"App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Appen \"%1$s\" kan inte installeras eftersom följande beroenden inte är uppfyllda: %2$s",
"a safe home for all your data" : "ett säkert hem för all din data",
- "File is currently busy, please try again later" : "Filen är för tillfället upptagen, vänligen försök igen senare",
+ "File is currently busy, please try again later" : "Filen är för tillfället upptagen, försök igen senare",
"Cannot read file" : "Kan inte läsa fil",
"Application is not enabled" : "Applikationen är inte aktiverad",
"Authentication error" : "Fel vid autentisering",
- "Token expired. Please reload page." : "Token har löpt ut. Vänligen uppdatera sidan.",
+ "Token expired. Please reload page." : "Token har löpt ut. Uppdatera sidan.",
"No database drivers (sqlite, mysql, or postgresql) installed." : "Inga databasdrivrutiner (sqlite, mysql, eller postgresql) installerade.",
"Or, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it. See %s" : "Eller, om du föredrar att behålla config.php skrivskyddad, sätt alternativet \"config_is_read_only\" till true i den. Se %s",
"PHP module %s not installed." : "PHP-modulen %s är inte installerad.",
- "Please ask your server administrator to install the module." : "Vänligen be serveradministratören att installera modulen.",
+ "Please ask your server administrator to install the module." : "Be serveradministratören att installera modulen.",
"PHP setting \"%s\" is not set to \"%s\"." : "PHP-inställning \"%s\" är inte inställd på \"%s\".",
"Adjusting this setting in php.ini will make Nextcloud run again" : "Att ändra denna inställning i php.ini kommer göra så att Nextcloud fungerar igen",
"libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 2.7.0 är det minsta som krävs. För närvarande är %s installerat.",
@@ -221,8 +221,8 @@ OC.L10N.register(
"PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "PHP är tydligen inställt för att tömma \"inline doc blocks\". Detta kommer att göra flera kärnprogram otillgängliga.",
"This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Detta orsakas troligtvis av en cache/accelerator som t ex Zend OPchache eller eAccelerator.",
"PHP modules have been installed, but they are still listed as missing?" : "PHP-moduler har installerats, men de listas fortfarande som saknade?",
- "Please ask your server administrator to restart the web server." : "Vänligen be din serveradministratör att starta om webbservern.",
- "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Vänligen ändra behörigheterna till 0770 så att katalogen inte kan listas av andra användare.",
+ "Please ask your server administrator to restart the web server." : "Be din serveradministratör att starta om webbservern.",
+ "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Ändra behörigheterna till 0770 så att katalogen inte kan listas av andra användare.",
"Ensure there is a file called \".ocdata\" in the root of the data directory." : "Säkerställ att du har filen \".ocdata\" i huvudkatalogen för din data.",
"Action \"%s\" not supported or implemented." : "Åtgärd \"%s\" stöds inte eller är inte implementerad.",
"Authentication failed, wrong token or provider ID given" : "Autentisering misslyckades, felaktig token eller leverantörs-ID",
@@ -252,11 +252,11 @@ OC.L10N.register(
"This can usually be fixed by giving the webserver write access to the root directory. See %s" : "Detta kan vanligtvis åtgärda genom att ge webbservern skrivåtkomst till rotkatalogen. Se %s",
"Permissions can usually be fixed by giving the webserver write access to the root directory. See %s." : "Rättigheter kan vanligtvis fixas genom att ge webbservern skrivåtkomst till rotkatalogen. Se %s.",
"Setting locale to %s failed" : "Sätta locale till %s misslyckades",
- "Please install one of these locales on your system and restart your webserver." : "Vänligen Installera en av dessa språk på ditt system och starta om webbservern.",
+ "Please install one of these locales on your system and restart your webserver." : "Installera en av dessa språk på ditt system och starta om webbservern.",
"mbstring.func_overload is set to \"%s\" instead of the expected value \"0\"" : "mbstring.func_overload är satt till \"%s\" istället för det förväntade värdet \"0\"",
"To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini" : "För att åtgärda detta problem sätt värdet <code> mbstring.func_overload till </ code> <code> 0 </ code> i din php.ini",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 krävs",
- "Please upgrade your database version" : "Vänligen uppgradera din databasversion",
+ "Please upgrade your database version" : "Uppgradera din databasversion",
"Your data directory is readable by other users" : "Din datamapp är läsbar av andra användare",
"Your data directory must be an absolute path" : "Du måste specificera en korrekt sökväg till datamappen",
"Check the value of \"datadirectory\" in your configuration" : "Kontrollera värdet av \"datakatalog\" i din konfiguration",
diff --git a/lib/l10n/sv.json b/lib/l10n/sv.json
index 444d8d908bb..74526fac761 100644
--- a/lib/l10n/sv.json
+++ b/lib/l10n/sv.json
@@ -4,7 +4,7 @@
"See %s" : "Se %s",
"The files of the app %1$s were not replaced correctly. Make sure it is a version compatible with the server." : "Filerna i appen %1$s ersattes inte korrekt. Kontrollera att det är en version som är kompatibel med servern.",
"Sample configuration detected" : "Exempel-konfiguration detekterad",
- "It has been detected that the sample configuration has been copied. This can break your installation and is unsupported. Please read the documentation before performing changes on config.php" : "Det har upptäckts att provkonfigurationen har kopierats. Detta kan bryta din installation och stöds inte. Vänligen läs dokumentationen innan du utför ändringar på config.php",
+ "It has been detected that the sample configuration has been copied. This can break your installation and is unsupported. Please read the documentation before performing changes on config.php" : "Det har upptäckts att provkonfigurationen har kopierats. Detta kan bryta din installation och stöds inte. Läs dokumentationen innan du utför ändringar på config.php",
"%s email verification" : "%s e-postverifikation",
"Email verification" : "E-postverifikation",
"Click the following button to confirm your email." : "Klicka på följande knapp för att verifiera din e-postadress.",
@@ -118,9 +118,9 @@
"Oracle username and/or password not valid" : "Oracle-användarnamnet och/eller lösenordet är felaktigt",
"PostgreSQL username and/or password not valid" : "PostgreSQL-användarnamnet och/eller lösenordet är felaktigt",
"Mac OS X is not supported and %s will not work properly on this platform. Use it at your own risk! " : "Mac OS X stöds inte och %s kommer inte att fungera korrekt på denna plattform. Använd på egen risk!",
- "For the best results, please consider using a GNU/Linux server instead." : "För bästa resultat, vänligen överväg att använda en GNU/Linux-server istället.",
+ "For the best results, please consider using a GNU/Linux server instead." : "För bästa resultat, överväg att använda en GNU/Linux-server istället.",
"It seems that this %s instance is running on a 32-bit PHP environment and the open_basedir has been configured in php.ini. This will lead to problems with files over 4 GB and is highly discouraged." : "Det verkar som om denna %s instans körs på en 32-bitars PHP miljö och open_basedir har konfigurerats i php.ini. Detta kommer att leda till problem med filer över 4 GB och är verkligen inte rekommenderat!",
- "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Vänligen ta bort open_basedir-inställningen i din php.ini eller växla till 64-bitars PHP.",
+ "Please remove the open_basedir setting within your php.ini or switch to 64-bit PHP." : "Ta bort open_basedir-inställningen i din php.ini eller växla till 64-bitars PHP.",
"Set an admin username." : "Ange ett användarnamn för administratören.",
"Set an admin password." : "Ange ett administratörslösenord.",
"Cannot create or write into the data directory %s" : "Kan inte skapa eller skriva till data-katalogen %s",
@@ -203,15 +203,15 @@
"Login canceled by app" : "Inloggningen avbruten av appen",
"App \"%1$s\" cannot be installed because the following dependencies are not fulfilled: %2$s" : "Appen \"%1$s\" kan inte installeras eftersom följande beroenden inte är uppfyllda: %2$s",
"a safe home for all your data" : "ett säkert hem för all din data",
- "File is currently busy, please try again later" : "Filen är för tillfället upptagen, vänligen försök igen senare",
+ "File is currently busy, please try again later" : "Filen är för tillfället upptagen, försök igen senare",
"Cannot read file" : "Kan inte läsa fil",
"Application is not enabled" : "Applikationen är inte aktiverad",
"Authentication error" : "Fel vid autentisering",
- "Token expired. Please reload page." : "Token har löpt ut. Vänligen uppdatera sidan.",
+ "Token expired. Please reload page." : "Token har löpt ut. Uppdatera sidan.",
"No database drivers (sqlite, mysql, or postgresql) installed." : "Inga databasdrivrutiner (sqlite, mysql, eller postgresql) installerade.",
"Or, if you prefer to keep config.php file read only, set the option \"config_is_read_only\" to true in it. See %s" : "Eller, om du föredrar att behålla config.php skrivskyddad, sätt alternativet \"config_is_read_only\" till true i den. Se %s",
"PHP module %s not installed." : "PHP-modulen %s är inte installerad.",
- "Please ask your server administrator to install the module." : "Vänligen be serveradministratören att installera modulen.",
+ "Please ask your server administrator to install the module." : "Be serveradministratören att installera modulen.",
"PHP setting \"%s\" is not set to \"%s\"." : "PHP-inställning \"%s\" är inte inställd på \"%s\".",
"Adjusting this setting in php.ini will make Nextcloud run again" : "Att ändra denna inställning i php.ini kommer göra så att Nextcloud fungerar igen",
"libxml2 2.7.0 is at least required. Currently %s is installed." : "libxml2 2.7.0 är det minsta som krävs. För närvarande är %s installerat.",
@@ -219,8 +219,8 @@
"PHP is apparently set up to strip inline doc blocks. This will make several core apps inaccessible." : "PHP är tydligen inställt för att tömma \"inline doc blocks\". Detta kommer att göra flera kärnprogram otillgängliga.",
"This is probably caused by a cache/accelerator such as Zend OPcache or eAccelerator." : "Detta orsakas troligtvis av en cache/accelerator som t ex Zend OPchache eller eAccelerator.",
"PHP modules have been installed, but they are still listed as missing?" : "PHP-moduler har installerats, men de listas fortfarande som saknade?",
- "Please ask your server administrator to restart the web server." : "Vänligen be din serveradministratör att starta om webbservern.",
- "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Vänligen ändra behörigheterna till 0770 så att katalogen inte kan listas av andra användare.",
+ "Please ask your server administrator to restart the web server." : "Be din serveradministratör att starta om webbservern.",
+ "Please change the permissions to 0770 so that the directory cannot be listed by other users." : "Ändra behörigheterna till 0770 så att katalogen inte kan listas av andra användare.",
"Ensure there is a file called \".ocdata\" in the root of the data directory." : "Säkerställ att du har filen \".ocdata\" i huvudkatalogen för din data.",
"Action \"%s\" not supported or implemented." : "Åtgärd \"%s\" stöds inte eller är inte implementerad.",
"Authentication failed, wrong token or provider ID given" : "Autentisering misslyckades, felaktig token eller leverantörs-ID",
@@ -250,11 +250,11 @@
"This can usually be fixed by giving the webserver write access to the root directory. See %s" : "Detta kan vanligtvis åtgärda genom att ge webbservern skrivåtkomst till rotkatalogen. Se %s",
"Permissions can usually be fixed by giving the webserver write access to the root directory. See %s." : "Rättigheter kan vanligtvis fixas genom att ge webbservern skrivåtkomst till rotkatalogen. Se %s.",
"Setting locale to %s failed" : "Sätta locale till %s misslyckades",
- "Please install one of these locales on your system and restart your webserver." : "Vänligen Installera en av dessa språk på ditt system och starta om webbservern.",
+ "Please install one of these locales on your system and restart your webserver." : "Installera en av dessa språk på ditt system och starta om webbservern.",
"mbstring.func_overload is set to \"%s\" instead of the expected value \"0\"" : "mbstring.func_overload är satt till \"%s\" istället för det förväntade värdet \"0\"",
"To fix this issue set <code>mbstring.func_overload</code> to <code>0</code> in your php.ini" : "För att åtgärda detta problem sätt värdet <code> mbstring.func_overload till </ code> <code> 0 </ code> i din php.ini",
"PostgreSQL >= 9 required" : "PostgreSQL >= 9 krävs",
- "Please upgrade your database version" : "Vänligen uppgradera din databasversion",
+ "Please upgrade your database version" : "Uppgradera din databasversion",
"Your data directory is readable by other users" : "Din datamapp är läsbar av andra användare",
"Your data directory must be an absolute path" : "Du måste specificera en korrekt sökväg till datamappen",
"Check the value of \"datadirectory\" in your configuration" : "Kontrollera värdet av \"datakatalog\" i din konfiguration",
diff --git a/lib/private/Accounts/AccountManager.php b/lib/private/Accounts/AccountManager.php
index 127adc9ef38..5792ba1dc5d 100644
--- a/lib/private/Accounts/AccountManager.php
+++ b/lib/private/Accounts/AccountManager.php
@@ -41,6 +41,7 @@ use libphonenumber\PhoneNumber;
use libphonenumber\PhoneNumberFormat;
use libphonenumber\PhoneNumberUtil;
use OC\Profile\TProfileHelper;
+use OC\Cache\CappedMemoryCache;
use OCA\Settings\BackgroundJobs\VerifyUserData;
use OCP\Accounts\IAccount;
use OCP\Accounts\IAccountManager;
@@ -116,6 +117,7 @@ class AccountManager implements IAccountManager {
private $crypto;
/** @var IFactory */
private $l10nfactory;
+ private CappedMemoryCache $internalCache;
public function __construct(
IDBConnection $connection,
@@ -142,6 +144,7 @@ class AccountManager implements IAccountManager {
$this->crypto = $crypto;
// DIing IL10N results in a dependency loop
$this->l10nfactory = $factory;
+ $this->internalCache = new CappedMemoryCache();
}
/**
@@ -763,7 +766,12 @@ class AccountManager implements IAccountManager {
}
public function getAccount(IUser $user): IAccount {
- return $this->parseAccountData($user, $this->getUser($user));
+ if ($this->internalCache->hasKey($user->getUID())) {
+ return $this->internalCache->get($user->getUID());
+ }
+ $account = $this->parseAccountData($user, $this->getUser($user));
+ $this->internalCache->set($user->getUID(), $account);
+ return $account;
}
public function updateAccount(IAccount $account): void {
@@ -813,5 +821,6 @@ class AccountManager implements IAccountManager {
}
$this->updateUser($account->getUser(), $data, true);
+ $this->internalCache->set($account->getUser()->getUID(), $account);
}
}
diff --git a/lib/private/AppFramework/App.php b/lib/private/AppFramework/App.php
index 6c2f905afa5..feebb32d5bc 100644
--- a/lib/private/AppFramework/App.php
+++ b/lib/private/AppFramework/App.php
@@ -34,11 +34,16 @@ namespace OC\AppFramework;
use OC\AppFramework\DependencyInjection\DIContainer;
use OC\AppFramework\Http\Dispatcher;
use OC\AppFramework\Http\Request;
+use OC\Diagnostics\EventLogger;
+use OCP\Profiler\IProfiler;
+use OC\Profiler\RoutingDataCollector;
+use OCP\AppFramework\QueryException;
use OCP\AppFramework\Http;
use OCP\AppFramework\Http\ICallbackResponse;
use OCP\AppFramework\Http\IOutput;
-use OCP\AppFramework\QueryException;
+use OCP\Diagnostics\IEventLogger;
use OCP\HintException;
+use OCP\IConfig;
use OCP\IRequest;
/**
@@ -114,20 +119,30 @@ class App {
* @throws HintException
*/
public static function main(string $controllerName, string $methodName, DIContainer $container, array $urlParams = null) {
+ /** @var IProfiler $profiler */
+ $profiler = $container->get(IProfiler::class);
+ $config = $container->get(IConfig::class);
+ // Disable profiler on the profiler UI
+ $profiler->setEnabled($profiler->isEnabled() && !is_null($urlParams) && isset($urlParams['_route']) && !str_starts_with($urlParams['_route'], 'profiler.'));
+ if ($profiler->isEnabled()) {
+ \OC::$server->get(IEventLogger::class)->activate();
+ $profiler->add(new RoutingDataCollector($container['AppName'], $controllerName, $methodName));
+ }
+
if (!is_null($urlParams)) {
/** @var Request $request */
- $request = $container->query(IRequest::class);
+ $request = $container->get(IRequest::class);
$request->setUrlParameters($urlParams);
} elseif (isset($container['urlParams']) && !is_null($container['urlParams'])) {
/** @var Request $request */
- $request = $container->query(IRequest::class);
+ $request = $container->get(IRequest::class);
$request->setUrlParameters($container['urlParams']);
}
$appName = $container['AppName'];
// first try $controllerName then go for \OCA\AppName\Controller\$controllerName
try {
- $controller = $container->query($controllerName);
+ $controller = $container->get($controllerName);
} catch (QueryException $e) {
if (strpos($controllerName, '\\Controller\\') !== false) {
// This is from a global registered app route that is not enabled.
@@ -158,6 +173,16 @@ class App {
$io = $container[IOutput::class];
+ if ($profiler->isEnabled()) {
+ /** @var EventLogger $eventLogger */
+ $eventLogger = $container->get(IEventLogger::class);
+ $eventLogger->end('runtime');
+ $profile = $profiler->collect($container->get(IRequest::class), $response);
+ $profiler->saveProfile($profile);
+ $io->setHeader('X-Debug-Token:' . $profile->getToken());
+ $io->setHeader('Server-Timing: token;desc="' . $profile->getToken() . '"');
+ }
+
if (!is_null($httpHeaders)) {
$io->setHeader($httpHeaders);
}
diff --git a/lib/private/AppFramework/Http/Request.php b/lib/private/AppFramework/Http/Request.php
index 21af2bc46f4..f896b825f2d 100644
--- a/lib/private/AppFramework/Http/Request.php
+++ b/lib/private/AppFramework/Http/Request.php
@@ -48,8 +48,8 @@ use OC\Security\CSRF\CsrfTokenManager;
use OC\Security\TrustedDomainHelper;
use OCP\IConfig;
use OCP\IRequest;
+use OCP\IRequestId;
use OCP\Security\ICrypto;
-use OCP\Security\ISecureRandom;
/**
* Class for accessing variables in the request.
@@ -92,12 +92,10 @@ class Request implements \ArrayAccess, \Countable, IRequest {
'method',
'requesttoken',
];
- /** @var ISecureRandom */
- protected $secureRandom;
+ /** @var RequestId */
+ protected $requestId;
/** @var IConfig */
protected $config;
- /** @var string */
- protected $requestId = '';
/** @var ICrypto */
protected $crypto;
/** @var CsrfTokenManager|null */
@@ -117,20 +115,20 @@ class Request implements \ArrayAccess, \Countable, IRequest {
* - array 'cookies' the $_COOKIE array
* - string 'method' the request method (GET, POST etc)
* - string|false 'requesttoken' the requesttoken or false when not available
- * @param ISecureRandom $secureRandom
+ * @param IRequestId $requestId
* @param IConfig $config
* @param CsrfTokenManager|null $csrfTokenManager
* @param string $stream
* @see https://www.php.net/manual/en/reserved.variables.php
*/
public function __construct(array $vars,
- ISecureRandom $secureRandom,
+ IRequestId $requestId,
IConfig $config,
CsrfTokenManager $csrfTokenManager = null,
string $stream = 'php://input') {
$this->inputStream = $stream;
$this->items['params'] = [];
- $this->secureRandom = $secureRandom;
+ $this->requestId = $requestId;
$this->config = $config;
$this->csrfTokenManager = $csrfTokenManager;
@@ -571,16 +569,7 @@ class Request implements \ArrayAccess, \Countable, IRequest {
* @return string
*/
public function getId(): string {
- if (isset($this->server['UNIQUE_ID'])) {
- return $this->server['UNIQUE_ID'];
- }
-
- if (empty($this->requestId)) {
- $validChars = ISecureRandom::CHAR_ALPHANUMERIC;
- $this->requestId = $this->secureRandom->generate(20, $validChars);
- }
-
- return $this->requestId;
+ return $this->requestId->getId();
}
/**
diff --git a/lib/private/AppFramework/Http/RequestId.php b/lib/private/AppFramework/Http/RequestId.php
new file mode 100644
index 00000000000..70032873a75
--- /dev/null
+++ b/lib/private/AppFramework/Http/RequestId.php
@@ -0,0 +1,52 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2022, Joas Schilling <coding@schilljs.com>
+ *
+ * @author Joas Schilling <coding@schilljs.com>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * 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, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+namespace OC\AppFramework\Http;
+
+use OCP\IRequestId;
+use OCP\Security\ISecureRandom;
+
+class RequestId implements IRequestId {
+ protected ISecureRandom $secureRandom;
+ protected string $requestId;
+
+ public function __construct(string $uniqueId,
+ ISecureRandom $secureRandom) {
+ $this->requestId = $uniqueId;
+ $this->secureRandom = $secureRandom;
+ }
+
+ /**
+ * Returns an ID for the request, value is not guaranteed to be unique and is mostly meant for logging
+ * If `mod_unique_id` is installed this value will be taken.
+ * @return string
+ */
+ public function getId(): string {
+ if (empty($this->requestId)) {
+ $validChars = ISecureRandom::CHAR_ALPHANUMERIC;
+ $this->requestId = $this->secureRandom->generate(20, $validChars);
+ }
+
+ return $this->requestId;
+ }
+}
diff --git a/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php b/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php
index fffeffd4feb..e0f36231b68 100644
--- a/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php
+++ b/lib/private/AppFramework/Middleware/Security/SecurityMiddleware.php
@@ -264,6 +264,9 @@ class SecurityMiddleware extends Middleware {
if ($usernamePrefill !== '') {
$params['user'] = $usernamePrefill;
}
+ if ($this->request->getParam('direct')) {
+ $params['direct'] = 1;
+ }
$url = $this->urlGenerator->linkToRoute('core.login.showLoginForm', $params);
$response = new RedirectResponse($url);
} else {
diff --git a/lib/private/AppFramework/Utility/SimpleContainer.php b/lib/private/AppFramework/Utility/SimpleContainer.php
index 598c66b6aba..429382aa223 100644
--- a/lib/private/AppFramework/Utility/SimpleContainer.php
+++ b/lib/private/AppFramework/Utility/SimpleContainer.php
@@ -38,6 +38,7 @@ use Psr\Container\ContainerInterface;
use ReflectionClass;
use ReflectionException;
use ReflectionParameter;
+use ReflectionNamedType;
use function class_exists;
/**
@@ -78,12 +79,13 @@ class SimpleContainer implements ArrayAccess, ContainerInterface, IContainer {
$resolveName = $parameter->getName();
// try to find out if it is a class or a simple parameter
- if ($parameterType !== null && !$parameterType->isBuiltin()) {
+ if ($parameterType !== null && ($parameterType instanceof ReflectionNamedType) && !$parameterType->isBuiltin()) {
$resolveName = $parameterType->getName();
}
try {
- $builtIn = $parameter->hasType() && $parameter->getType()->isBuiltin();
+ $builtIn = $parameter->hasType() && ($parameter->getType() instanceof ReflectionNamedType)
+ && $parameter->getType()->isBuiltin();
return $this->query($resolveName, !$builtIn);
} catch (QueryException $e) {
// Service not found, use the default value when available
@@ -91,7 +93,7 @@ class SimpleContainer implements ArrayAccess, ContainerInterface, IContainer {
return $parameter->getDefaultValue();
}
- if ($parameterType !== null && !$parameterType->isBuiltin()) {
+ if ($parameterType !== null && ($parameterType instanceof ReflectionNamedType) && !$parameterType->isBuiltin()) {
$resolveName = $parameter->getName();
try {
return $this->query($resolveName);
diff --git a/lib/private/Authentication/Token/IProvider.php b/lib/private/Authentication/Token/IProvider.php
index e604ac715c2..0a145bfd7e6 100644
--- a/lib/private/Authentication/Token/IProvider.php
+++ b/lib/private/Authentication/Token/IProvider.php
@@ -44,7 +44,7 @@ interface IProvider {
* @param string $uid
* @param string $loginName
* @param string|null $password
- * @param string $name
+ * @param string $name Name will be trimmed to 120 chars when longer
* @param int $type token type
* @param int $remember whether the session token should be used for remember-me
* @return IToken
diff --git a/lib/private/Authentication/Token/Manager.php b/lib/private/Authentication/Token/Manager.php
index 0a7a821e23e..f8a0fb11c52 100644
--- a/lib/private/Authentication/Token/Manager.php
+++ b/lib/private/Authentication/Token/Manager.php
@@ -49,7 +49,7 @@ class Manager implements IProvider {
* @param string $uid
* @param string $loginName
* @param string|null $password
- * @param string $name
+ * @param string $name Name will be trimmed to 120 chars when longer
* @param int $type token type
* @param int $remember whether the session token should be used for remember-me
* @return IToken
@@ -61,6 +61,10 @@ class Manager implements IProvider {
string $name,
int $type = IToken::TEMPORARY_TOKEN,
int $remember = IToken::DO_NOT_REMEMBER): IToken {
+ if (mb_strlen($name) > 128) {
+ $name = mb_substr($name, 0, 120) . '…';
+ }
+
try {
return $this->publicKeyTokenProvider->generateToken(
$token,
diff --git a/lib/private/Authentication/Token/PublicKeyTokenProvider.php b/lib/private/Authentication/Token/PublicKeyTokenProvider.php
index d2ee47cf380..26337029d77 100644
--- a/lib/private/Authentication/Token/PublicKeyTokenProvider.php
+++ b/lib/private/Authentication/Token/PublicKeyTokenProvider.php
@@ -84,6 +84,10 @@ class PublicKeyTokenProvider implements IProvider {
string $name,
int $type = IToken::TEMPORARY_TOKEN,
int $remember = IToken::DO_NOT_REMEMBER): IToken {
+ if (mb_strlen($name) > 128) {
+ throw new InvalidTokenException('The given name is too long');
+ }
+
$dbToken = $this->newToken($token, $uid, $loginName, $password, $name, $type, $remember);
$this->mapper->insert($dbToken);
diff --git a/lib/private/Cache/CappedMemoryCache.php b/lib/private/Cache/CappedMemoryCache.php
index 9260bf1f6b3..0a3300435eb 100644
--- a/lib/private/Cache/CappedMemoryCache.php
+++ b/lib/private/Cache/CappedMemoryCache.php
@@ -115,4 +115,8 @@ class CappedMemoryCache implements ICache, \ArrayAccess {
$this->remove($key);
}
}
+
+ public static function isAvailable(): bool {
+ return true;
+ }
}
diff --git a/lib/private/Cache/File.php b/lib/private/Cache/File.php
index 0ecd894d2d2..a96a7cd9c0b 100644
--- a/lib/private/Cache/File.php
+++ b/lib/private/Cache/File.php
@@ -203,4 +203,8 @@ class File implements ICache {
}
}
}
+
+ public static function isAvailable(): bool {
+ return true;
+ }
}
diff --git a/lib/private/Comments/EmojiHelper.php b/lib/private/Comments/EmojiHelper.php
new file mode 100644
index 00000000000..a75919edbc9
--- /dev/null
+++ b/lib/private/Comments/EmojiHelper.php
@@ -0,0 +1,101 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright Copyright (c) 2020, Georg Ehrke
+ *
+ * @author Georg Ehrke <oc.list@georgehrke.com>
+ * @author Joas Schilling <coding@schilljs.com>
+ *
+ * @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\Comments;
+
+use OCP\IDBConnection;
+
+/**
+ * Copied OCA\UserStatus\Service\EmojiService
+ * Needs to be unified later
+ */
+class EmojiHelper {
+
+ /** @var IDBConnection */
+ private $db;
+
+ /**
+ * EmojiService constructor.
+ *
+ * @param IDBConnection $db
+ */
+ public function __construct(IDBConnection $db) {
+ $this->db = $db;
+ }
+
+ /**
+ * @return bool
+ */
+ public function doesPlatformSupportEmoji(): bool {
+ return $this->db->supports4ByteText() &&
+ \class_exists(\IntlBreakIterator::class);
+ }
+
+ /**
+ * @param string $emoji
+ * @return bool
+ */
+ public function isValidEmoji(string $emoji): bool {
+ $intlBreakIterator = \IntlBreakIterator::createCharacterInstance();
+ $intlBreakIterator->setText($emoji);
+
+ $characterCount = 0;
+ while ($intlBreakIterator->next() !== \IntlBreakIterator::DONE) {
+ $characterCount++;
+ }
+
+ if ($characterCount !== 1) {
+ return false;
+ }
+
+ $codePointIterator = \IntlBreakIterator::createCodePointInstance();
+ $codePointIterator->setText($emoji);
+
+ foreach ($codePointIterator->getPartsIterator() as $codePoint) {
+ $codePointType = \IntlChar::charType($codePoint);
+
+ // If the current code-point is an emoji or a modifier (like a skin-tone)
+ // just continue and check the next character
+ if ($codePointType === \IntlChar::CHAR_CATEGORY_MODIFIER_SYMBOL ||
+ $codePointType === \IntlChar::CHAR_CATEGORY_MODIFIER_LETTER ||
+ $codePointType === \IntlChar::CHAR_CATEGORY_OTHER_SYMBOL ||
+ $codePointType === \IntlChar::CHAR_CATEGORY_GENERAL_OTHER_TYPES) {
+ continue;
+ }
+
+ // If it's neither a modifier nor an emoji, we only allow
+ // a zero-width-joiner or a variation selector 16
+ $codePointValue = \IntlChar::ord($codePoint);
+ if ($codePointValue === 8205 || $codePointValue === 65039) {
+ continue;
+ }
+
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/lib/private/Comments/Manager.php b/lib/private/Comments/Manager.php
index 384187accf3..123e4f6988d 100644
--- a/lib/private/Comments/Manager.php
+++ b/lib/private/Comments/Manager.php
@@ -59,6 +59,9 @@ class Manager implements ICommentsManager {
/** @var ITimeFactory */
protected $timeFactory;
+ /** @var EmojiHelper */
+ protected $emojiHelper;
+
/** @var IInitialStateService */
protected $initialStateService;
@@ -78,11 +81,13 @@ class Manager implements ICommentsManager {
LoggerInterface $logger,
IConfig $config,
ITimeFactory $timeFactory,
+ EmojiHelper $emojiHelper,
IInitialStateService $initialStateService) {
$this->dbConn = $dbConn;
$this->logger = $logger;
$this->config = $config;
$this->timeFactory = $timeFactory;
+ $this->emojiHelper = $emojiHelper;
$this->initialStateService = $initialStateService;
}
@@ -148,8 +153,9 @@ class Manager implements ICommentsManager {
throw new \UnexpectedValueException('Actor, Object and Verb information must be provided for saving');
}
- if ($comment->getVerb() === 'reaction' && mb_strlen($comment->getMessage()) > 2) {
- throw new \UnexpectedValueException('Reactions cannot be longer than 2 chars (emoji with skin tone have two chars)');
+ if ($comment->getVerb() === 'reaction' && !$this->emojiHelper->isValidEmoji($comment->getMessage())) {
+ // 4 characters: laptop + person + gender + skin color => "🧑🏽‍💻" is a single emoji from the picker
+ throw new \UnexpectedValueException('Reactions can only be a single emoji');
}
if ($comment->getId() === '') {
diff --git a/lib/private/Contacts/ContactsMenu/ContactsStore.php b/lib/private/Contacts/ContactsMenu/ContactsStore.php
index 5b7a942a244..0ac388ce00a 100644
--- a/lib/private/Contacts/ContactsMenu/ContactsStore.php
+++ b/lib/private/Contacts/ContactsMenu/ContactsStore.php
@@ -107,7 +107,7 @@ class ContactsStore implements IContactsStore {
}
$allContacts = $this->contactsManager->search(
- $filter ?: '',
+ $filter ?? '',
[
'FN',
'EMAIL'
@@ -146,7 +146,7 @@ class ContactsStore implements IContactsStore {
*
* @param IUser $self
* @param Entry[] $entries
- * @param string $filter
+ * @param string|null $filter
* @return Entry[] the filtered contacts
*/
private function filterContacts(
diff --git a/lib/private/Contacts/ContactsMenu/Manager.php b/lib/private/Contacts/ContactsMenu/Manager.php
index cea67735da5..73a5a475d85 100644
--- a/lib/private/Contacts/ContactsMenu/Manager.php
+++ b/lib/private/Contacts/ContactsMenu/Manager.php
@@ -59,14 +59,14 @@ class Manager {
/**
* @param IUser $user
- * @param string $filter
+ * @param string|null $filter
* @return array
*/
public function getEntries(IUser $user, $filter) {
$maxAutocompleteResults = max(0, $this->config->getSystemValueInt('sharing.maxAutocompleteResults', Constants::SHARING_MAX_AUTOCOMPLETE_RESULTS_DEFAULT));
$minSearchStringLength = $this->config->getSystemValueInt('sharing.minSearchStringLength', 0);
$topEntries = [];
- if (strlen($filter) >= $minSearchStringLength) {
+ if (strlen($filter ?? '') >= $minSearchStringLength) {
$entries = $this->store->getContacts($user, $filter, $maxAutocompleteResults);
$sortedEntries = $this->sortEntries($entries);
diff --git a/lib/private/DB/Connection.php b/lib/private/DB/Connection.php
index e32c530c19e..2e38b1ddf5e 100644
--- a/lib/private/DB/Connection.php
+++ b/lib/private/DB/Connection.php
@@ -42,6 +42,7 @@ use Doctrine\DBAL\Driver;
use Doctrine\DBAL\Exception;
use Doctrine\DBAL\Exception\ConstraintViolationException;
use Doctrine\DBAL\Exception\NotNullConstraintViolationException;
+use Doctrine\DBAL\Logging\DebugStack;
use Doctrine\DBAL\Platforms\MySQLPlatform;
use Doctrine\DBAL\Platforms\OraclePlatform;
use Doctrine\DBAL\Platforms\PostgreSQL94Platform;
@@ -49,11 +50,13 @@ use Doctrine\DBAL\Platforms\SqlitePlatform;
use Doctrine\DBAL\Result;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Statement;
-use OC\DB\QueryBuilder\QueryBuilder;
-use OC\SystemConfig;
use OCP\DB\QueryBuilder\IQueryBuilder;
-use OCP\ILogger;
+use OCP\IRequestId;
use OCP\PreConditionNotMetException;
+use OC\DB\QueryBuilder\QueryBuilder;
+use OC\SystemConfig;
+use Psr\Log\LoggerInterface;
+use OCP\Profiler\IProfiler;
class Connection extends \Doctrine\DBAL\Connection {
/** @var string */
@@ -65,8 +68,7 @@ class Connection extends \Doctrine\DBAL\Connection {
/** @var SystemConfig */
private $systemConfig;
- /** @var ILogger */
- private $logger;
+ private LoggerInterface $logger;
protected $lockedTable = null;
@@ -76,6 +78,47 @@ class Connection extends \Doctrine\DBAL\Connection {
/** @var int */
protected $queriesExecuted = 0;
+ /** @var DbDataCollector|null */
+ protected $dbDataCollector = null;
+
+ /**
+ * Initializes a new instance of the Connection class.
+ *
+ * @throws \Exception
+ */
+ public function __construct(
+ array $params,
+ Driver $driver,
+ ?Configuration $config = null,
+ ?EventManager $eventManager = null
+ ) {
+ if (!isset($params['adapter'])) {
+ throw new \Exception('adapter not set');
+ }
+ if (!isset($params['tablePrefix'])) {
+ throw new \Exception('tablePrefix not set');
+ }
+ /**
+ * @psalm-suppress InternalMethod
+ */
+ parent::__construct($params, $driver, $config, $eventManager);
+ $this->adapter = new $params['adapter']($this);
+ $this->tablePrefix = $params['tablePrefix'];
+
+ $this->systemConfig = \OC::$server->getSystemConfig();
+ $this->logger = \OC::$server->get(LoggerInterface::class);
+
+ /** @var \OCP\Profiler\IProfiler */
+ $profiler = \OC::$server->get(IProfiler::class);
+ if ($profiler->isEnabled()) {
+ $this->dbDataCollector = new DbDataCollector($this);
+ $profiler->add($this->dbDataCollector);
+ $debugStack = new DebugStack();
+ $this->dbDataCollector->setDebugStack($debugStack);
+ $this->_config->setSQLLogger($debugStack);
+ }
+ }
+
/**
* @throws Exception
*/
@@ -125,7 +168,7 @@ class Connection extends \Doctrine\DBAL\Connection {
*/
public function createQueryBuilder() {
$backtrace = $this->getCallerBacktrace();
- \OC::$server->getLogger()->debug('Doctrine QueryBuilder retrieved in {backtrace}', ['app' => 'core', 'backtrace' => $backtrace]);
+ $this->logger->debug('Doctrine QueryBuilder retrieved in {backtrace}', ['app' => 'core', 'backtrace' => $backtrace]);
$this->queriesBuilt++;
return parent::createQueryBuilder();
}
@@ -138,7 +181,7 @@ class Connection extends \Doctrine\DBAL\Connection {
*/
public function getExpressionBuilder() {
$backtrace = $this->getCallerBacktrace();
- \OC::$server->getLogger()->debug('Doctrine ExpressionBuilder retrieved in {backtrace}', ['app' => 'core', 'backtrace' => $backtrace]);
+ $this->logger->debug('Doctrine ExpressionBuilder retrieved in {backtrace}', ['app' => 'core', 'backtrace' => $backtrace]);
$this->queriesBuilt++;
return parent::getExpressionBuilder();
}
@@ -168,34 +211,6 @@ class Connection extends \Doctrine\DBAL\Connection {
}
/**
- * Initializes a new instance of the Connection class.
- *
- * @param array $params The connection parameters.
- * @param \Doctrine\DBAL\Driver $driver
- * @param \Doctrine\DBAL\Configuration $config
- * @param \Doctrine\Common\EventManager $eventManager
- * @throws \Exception
- */
- public function __construct(array $params, Driver $driver, Configuration $config = null,
- EventManager $eventManager = null) {
- if (!isset($params['adapter'])) {
- throw new \Exception('adapter not set');
- }
- if (!isset($params['tablePrefix'])) {
- throw new \Exception('tablePrefix not set');
- }
- /**
- * @psalm-suppress InternalMethod
- */
- parent::__construct($params, $driver, $config, $eventManager);
- $this->adapter = new $params['adapter']($this);
- $this->tablePrefix = $params['tablePrefix'];
-
- $this->systemConfig = \OC::$server->getSystemConfig();
- $this->logger = \OC::$server->getLogger();
- }
-
- /**
* Prepares an SQL statement.
*
* @param string $statement The SQL statement to prepare.
@@ -281,11 +296,16 @@ class Connection extends \Doctrine\DBAL\Connection {
}
protected function logQueryToFile(string $sql): void {
- $logFile = $this->systemConfig->getValue('query_log_file', '');
+ $logFile = $this->systemConfig->getValue('query_log_file');
if ($logFile !== '' && is_writable(dirname($logFile)) && (!file_exists($logFile) || is_writable($logFile))) {
+ $prefix = '';
+ if ($this->systemConfig->getValue('query_log_file_requestid') === 'yes') {
+ $prefix .= \OC::$server->get(IRequestId::class)->getId() . "\t";
+ }
+
file_put_contents(
$this->systemConfig->getValue('query_log_file', ''),
- $sql . "\n",
+ $prefix . $sql . "\n",
FILE_APPEND
);
}
diff --git a/lib/private/DB/DbDataCollector.php b/lib/private/DB/DbDataCollector.php
new file mode 100644
index 00000000000..d708955b10e
--- /dev/null
+++ b/lib/private/DB/DbDataCollector.php
@@ -0,0 +1,154 @@
+<?php
+
+declare(strict_types = 1);
+/**
+ * @copyright 2022 Carl Schwan <carl@carlschwan.eu>
+ *
+ * @author Carl Schwan <carl@carlschwan.eu>
+ *
+ * @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\DB;
+
+use Doctrine\DBAL\Logging\DebugStack;
+use Doctrine\DBAL\Types\ConversionException;
+use Doctrine\DBAL\Types\Type;
+use OC\AppFramework\Http\Request;
+use OCP\AppFramework\Http\Response;
+
+class DbDataCollector extends \OCP\DataCollector\AbstractDataCollector {
+ protected ?DebugStack $debugStack = null;
+ private Connection $connection;
+
+ /**
+ * DbDataCollector constructor.
+ */
+ public function __construct(Connection $connection) {
+ $this->connection = $connection;
+ }
+
+ public function setDebugStack(DebugStack $debugStack, $name = 'default'): void {
+ $this->debugStack = $debugStack;
+ }
+
+ /**
+ * @inheritDoc
+ */
+ public function collect(Request $request, Response $response, \Throwable $exception = null): void {
+ $queries = $this->sanitizeQueries($this->debugStack->queries);
+
+ $this->data = [
+ 'queries' => $queries,
+ ];
+ }
+
+ public function getName(): string {
+ return 'db';
+ }
+
+ public function getQueries(): array {
+ return $this->data['queries'];
+ }
+
+ private function sanitizeQueries(array $queries): array {
+ foreach ($queries as $i => $query) {
+ $queries[$i] = $this->sanitizeQuery($query);
+ }
+
+ return $queries;
+ }
+
+ private function sanitizeQuery(array $query): array {
+ $query['explainable'] = true;
+ $query['runnable'] = true;
+ if (null === $query['params']) {
+ $query['params'] = [];
+ }
+ if (!\is_array($query['params'])) {
+ $query['params'] = [$query['params']];
+ }
+ if (!\is_array($query['types'])) {
+ $query['types'] = [];
+ }
+ foreach ($query['params'] as $j => $param) {
+ $e = null;
+ if (isset($query['types'][$j])) {
+ // Transform the param according to the type
+ $type = $query['types'][$j];
+ if (\is_string($type)) {
+ $type = Type::getType($type);
+ }
+ if ($type instanceof Type) {
+ $query['types'][$j] = $type->getBindingType();
+ try {
+ $param = $type->convertToDatabaseValue($param, $this->connection->getDatabasePlatform());
+ } catch (\TypeError $e) {
+ } catch (ConversionException $e) {
+ }
+ }
+ }
+
+ [$query['params'][$j], $explainable, $runnable] = $this->sanitizeParam($param, $e);
+ if (!$explainable) {
+ $query['explainable'] = false;
+ }
+
+ if (!$runnable) {
+ $query['runnable'] = false;
+ }
+ }
+
+ return $query;
+ }
+
+ /**
+ * Sanitizes a param.
+ *
+ * The return value is an array with the sanitized value and a boolean
+ * indicating if the original value was kept (allowing to use the sanitized
+ * value to explain the query).
+ */
+ private function sanitizeParam($var, ?\Throwable $error): array {
+ if (\is_object($var)) {
+ return [$o = new ObjectParameter($var, $error), false, $o->isStringable() && !$error];
+ }
+
+ if ($error) {
+ return ['⚠ '.$error->getMessage(), false, false];
+ }
+
+ if (\is_array($var)) {
+ $a = [];
+ $explainable = $runnable = true;
+ foreach ($var as $k => $v) {
+ [$value, $e, $r] = $this->sanitizeParam($v, null);
+ $explainable = $explainable && $e;
+ $runnable = $runnable && $r;
+ $a[$k] = $value;
+ }
+
+ return [$a, $explainable, $runnable];
+ }
+
+ if (\is_resource($var)) {
+ return [sprintf('/* Resource(%s) */', get_resource_type($var)), false, false];
+ }
+
+ return [$var, true, true];
+ }
+}
diff --git a/lib/private/DB/MigrationService.php b/lib/private/DB/MigrationService.php
index e7361cb4cab..046e3a4924b 100644
--- a/lib/private/DB/MigrationService.php
+++ b/lib/private/DB/MigrationService.php
@@ -43,6 +43,7 @@ use OCP\AppFramework\App;
use OCP\AppFramework\QueryException;
use OCP\Migration\IMigrationStep;
use OCP\Migration\IOutput;
+use Psr\Log\LoggerInterface;
class MigrationService {
@@ -73,7 +74,7 @@ class MigrationService {
$this->connection = $connection;
$this->output = $output;
if (null === $this->output) {
- $this->output = new SimpleOutput(\OC::$server->getLogger(), $appName);
+ $this->output = new SimpleOutput(\OC::$server->get(LoggerInterface::class), $appName);
}
if ($appName === 'core') {
@@ -594,6 +595,10 @@ class MigrationService {
if ((!$sourceTable instanceof Table || !$sourceTable->hasColumn($thing->getName())) && $thing->getNotnull() && $thing->getType()->getName() === Types::BOOLEAN) {
throw new \InvalidArgumentException('Column "' . $table->getName() . '"."' . $thing->getName() . '" is type Bool and also NotNull, so it can not store "false".');
}
+
+ if ($thing->getLength() > 4000 && $thing->getType()->getName() === Types::STRING) {
+ throw new \InvalidArgumentException('Column "' . $table->getName() . '"."' . $thing->getName() . '" is type String, but exceeding the 4.000 length limit.');
+ }
}
foreach ($table->getIndexes() as $thing) {
@@ -634,8 +639,8 @@ class MigrationService {
if ($isUsingDefaultName && \strlen($table->getName()) - $prefixLength >= 23) {
throw new \InvalidArgumentException('Primary index name on "' . $table->getName() . '" is too long.');
}
- } elseif (!$primaryKey instanceof Index) {
- throw new \InvalidArgumentException('Table "' . $table->getName() . '" has no primary key and therefor will not behave sane in clustered setups.');
+ // } elseif (!$primaryKey instanceof Index && !$sourceTable instanceof Table) {
+ // throw new \InvalidArgumentException('Table "' . $table->getName() . '" has no primary key and therefor will not behave sane in clustered setups.');
}
}
diff --git a/lib/private/DB/ObjectParameter.php b/lib/private/DB/ObjectParameter.php
new file mode 100644
index 00000000000..61ac16018d8
--- /dev/null
+++ b/lib/private/DB/ObjectParameter.php
@@ -0,0 +1,71 @@
+<?php
+
+declare(strict_types = 1);
+
+/*
+ * This file is part of the Symfony package.
+ *
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+/**
+ * @copyright 2022 Carl Schwan <carl@carlschwan.eu>
+ *
+ * @author Carl Schwan <carl@carlschwan.eu>
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @license AGPL-3.0-or-later AND MIT
+ *
+ * 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\DB;
+
+final class ObjectParameter {
+ private $object;
+ private $error;
+ private $stringable;
+ private $class;
+
+ /**
+ * @param object $object
+ */
+ public function __construct($object, ?\Throwable $error) {
+ $this->object = $object;
+ $this->error = $error;
+ $this->stringable = \is_callable([$object, '__toString']);
+ $this->class = \get_class($object);
+ }
+
+ /**
+ * @return object
+ */
+ public function getObject() {
+ return $this->object;
+ }
+
+ public function getError(): ?\Throwable {
+ return $this->error;
+ }
+
+ public function isStringable(): bool {
+ return $this->stringable;
+ }
+
+ public function getClass(): string {
+ return $this->class;
+ }
+}
diff --git a/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php b/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php
index 03630ea14a3..e0a7549a0ad 100644
--- a/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php
+++ b/lib/private/DB/QueryBuilder/FunctionBuilder/FunctionBuilder.php
@@ -94,6 +94,18 @@ class FunctionBuilder implements IFunctionBuilder {
return new QueryFunction('COUNT(' . $quotedName . ')' . $alias);
}
+ public function octetLength($field, $alias = ''): IQueryFunction {
+ $alias = $alias ? (' AS ' . $this->helper->quoteColumnName($alias)) : '';
+ $quotedName = $this->helper->quoteColumnName($field);
+ return new QueryFunction('OCTET_LENGTH(' . $quotedName . ')' . $alias);
+ }
+
+ public function charLength($field, $alias = ''): IQueryFunction {
+ $alias = $alias ? (' AS ' . $this->helper->quoteColumnName($alias)) : '';
+ $quotedName = $this->helper->quoteColumnName($field);
+ return new QueryFunction('CHAR_LENGTH(' . $quotedName . ')' . $alias);
+ }
+
public function max($field): IQueryFunction {
return new QueryFunction('MAX(' . $this->helper->quoteColumnName($field) . ')');
}
diff --git a/lib/private/DB/QueryBuilder/FunctionBuilder/OCIFunctionBuilder.php b/lib/private/DB/QueryBuilder/FunctionBuilder/OCIFunctionBuilder.php
index 43ecf599eba..a9844ec3373 100644
--- a/lib/private/DB/QueryBuilder/FunctionBuilder/OCIFunctionBuilder.php
+++ b/lib/private/DB/QueryBuilder/FunctionBuilder/OCIFunctionBuilder.php
@@ -91,4 +91,16 @@ class OCIFunctionBuilder extends FunctionBuilder {
$separator = $this->connection->quote($separator);
return new QueryFunction('LISTAGG(' . $this->helper->quoteColumnName($expr) . ', ' . $separator . ')' . $orderByClause);
}
+
+ public function octetLength($field, $alias = ''): IQueryFunction {
+ $alias = $alias ? (' AS ' . $this->helper->quoteColumnName($alias)) : '';
+ $quotedName = $this->helper->quoteColumnName($field);
+ return new QueryFunction('LENGTHB(' . $quotedName . ')' . $alias);
+ }
+
+ public function charLength($field, $alias = ''): IQueryFunction {
+ $alias = $alias ? (' AS ' . $this->helper->quoteColumnName($alias)) : '';
+ $quotedName = $this->helper->quoteColumnName($field);
+ return new QueryFunction('LENGTH(' . $quotedName . ')' . $alias);
+ }
}
diff --git a/lib/private/DB/QueryBuilder/FunctionBuilder/SqliteFunctionBuilder.php b/lib/private/DB/QueryBuilder/FunctionBuilder/SqliteFunctionBuilder.php
index fe700075a82..bb97d2e29f9 100644
--- a/lib/private/DB/QueryBuilder/FunctionBuilder/SqliteFunctionBuilder.php
+++ b/lib/private/DB/QueryBuilder/FunctionBuilder/SqliteFunctionBuilder.php
@@ -48,4 +48,16 @@ class SqliteFunctionBuilder extends FunctionBuilder {
public function least($x, $y): IQueryFunction {
return new QueryFunction('MIN(' . $this->helper->quoteColumnName($x) . ', ' . $this->helper->quoteColumnName($y) . ')');
}
+
+ public function octetLength($field, $alias = ''): IQueryFunction {
+ $alias = $alias ? (' AS ' . $this->helper->quoteColumnName($alias)) : '';
+ $quotedName = $this->helper->quoteColumnName($field);
+ return new QueryFunction('LENGTH(CAST(' . $quotedName . ' as BLOB))' . $alias);
+ }
+
+ public function charLength($field, $alias = ''): IQueryFunction {
+ $alias = $alias ? (' AS ' . $this->helper->quoteColumnName($alias)) : '';
+ $quotedName = $this->helper->quoteColumnName($field);
+ return new QueryFunction('LENGTH(' . $quotedName . ')' . $alias);
+ }
}
diff --git a/lib/private/DB/QueryBuilder/QueryBuilder.php b/lib/private/DB/QueryBuilder/QueryBuilder.php
index de326a2a317..4ecfd773492 100644
--- a/lib/private/DB/QueryBuilder/QueryBuilder.php
+++ b/lib/private/DB/QueryBuilder/QueryBuilder.php
@@ -53,7 +53,7 @@ use OCP\DB\QueryBuilder\ILiteral;
use OCP\DB\QueryBuilder\IParameter;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\DB\QueryBuilder\IQueryFunction;
-use OCP\ILogger;
+use Psr\Log\LoggerInterface;
class QueryBuilder implements IQueryBuilder {
@@ -63,8 +63,7 @@ class QueryBuilder implements IQueryBuilder {
/** @var SystemConfig */
private $systemConfig;
- /** @var ILogger */
- private $logger;
+ private LoggerInterface $logger;
/** @var \Doctrine\DBAL\Query\QueryBuilder */
private $queryBuilder;
@@ -83,9 +82,8 @@ class QueryBuilder implements IQueryBuilder {
*
* @param ConnectionAdapter $connection
* @param SystemConfig $systemConfig
- * @param ILogger $logger
*/
- public function __construct(ConnectionAdapter $connection, SystemConfig $systemConfig, ILogger $logger) {
+ public function __construct(ConnectionAdapter $connection, SystemConfig $systemConfig, LoggerInterface $logger) {
$this->connection = $connection;
$this->systemConfig = $systemConfig;
$this->logger = $logger;
@@ -229,8 +227,7 @@ class QueryBuilder implements IQueryBuilder {
}
} catch (\Error $e) {
// likely an error during conversion of $value to string
- $this->logger->debug('DB QueryBuilder: error trying to log SQL query');
- $this->logger->logException($e);
+ $this->logger->error('DB QueryBuilder: error trying to log SQL query', ['exception' => $e]);
}
}
@@ -245,11 +242,10 @@ class QueryBuilder implements IQueryBuilder {
if (empty($hasSelectAll) === empty($hasSelectSpecific)) {
$exception = new QueryException('Query is selecting * and specific values in the same query. This is not supported in Oracle.');
- $this->logger->logException($exception, [
- 'message' => 'Query is selecting * and specific values in the same query. This is not supported in Oracle.',
+ $this->logger->error($exception->getMessage(), [
'query' => $this->getSQL(),
- 'level' => ILogger::ERROR,
'app' => 'core',
+ 'exception' => $exception,
]);
}
}
@@ -266,21 +262,19 @@ class QueryBuilder implements IQueryBuilder {
if ($hasTooLargeArrayParameter) {
$exception = new QueryException('More than 1000 expressions in a list are not allowed on Oracle.');
- $this->logger->logException($exception, [
- 'message' => 'More than 1000 expressions in a list are not allowed on Oracle.',
+ $this->logger->error($exception->getMessage(), [
'query' => $this->getSQL(),
- 'level' => ILogger::ERROR,
'app' => 'core',
+ 'exception' => $exception,
]);
}
if ($numberOfParameters > 65535) {
$exception = new QueryException('The number of parameters must not exceed 65535. Restriction by PostgreSQL.');
- $this->logger->logException($exception, [
- 'message' => 'The number of parameters must not exceed 65535. Restriction by PostgreSQL.',
+ $this->logger->error($exception->getMessage(), [
'query' => $this->getSQL(),
- 'level' => ILogger::ERROR,
'app' => 'core',
+ 'exception' => $exception,
]);
}
diff --git a/lib/private/Diagnostics/EventLogger.php b/lib/private/Diagnostics/EventLogger.php
index 35cef0be3f5..c7b89002ea9 100644
--- a/lib/private/Diagnostics/EventLogger.php
+++ b/lib/private/Diagnostics/EventLogger.php
@@ -60,7 +60,8 @@ class EventLogger implements IEventLogger {
}
public function isLoggingActivated(): bool {
- $systemValue = (bool)$this->config->getValue('diagnostics.logging', false);
+ $systemValue = (bool)$this->config->getValue('diagnostics.logging', false)
+ || (bool)$this->config->getValue('profiler', false);
if ($systemValue && $this->config->getValue('debug', false)) {
return true;
diff --git a/lib/private/Encryption/EncryptionWrapper.php b/lib/private/Encryption/EncryptionWrapper.php
index e3dc539dd00..f2803fa5ff8 100644
--- a/lib/private/Encryption/EncryptionWrapper.php
+++ b/lib/private/Encryption/EncryptionWrapper.php
@@ -30,7 +30,6 @@ use OC\Files\View;
use OC\Memcache\ArrayCache;
use OCP\Files\Mount\IMountPoint;
use OCP\Files\Storage;
-use OCP\ILogger;
use Psr\Log\LoggerInterface;
/**
@@ -48,19 +47,14 @@ class EncryptionWrapper {
/** @var Manager */
private $manager;
- /** @var ILogger */
- private $logger;
+ private LoggerInterface $logger;
/**
* EncryptionWrapper constructor.
- *
- * @param ArrayCache $arrayCache
- * @param Manager $manager
- * @param ILogger $logger
*/
public function __construct(ArrayCache $arrayCache,
Manager $manager,
- ILogger $logger
+ LoggerInterface $logger
) {
$this->arrayCache = $arrayCache;
$this->manager = $manager;
@@ -101,7 +95,7 @@ class EncryptionWrapper {
Filesystem::getMountManager(),
$this->manager,
$fileHelper,
- \OC::$server->get(LoggerInterface::class),
+ $this->logger,
$uid
);
return new Encryption(
diff --git a/lib/private/Encryption/Manager.php b/lib/private/Encryption/Manager.php
index 55578ee25f4..5788da990d5 100644
--- a/lib/private/Encryption/Manager.php
+++ b/lib/private/Encryption/Manager.php
@@ -34,7 +34,7 @@ use OCP\Encryption\IEncryptionModule;
use OCP\Encryption\IManager;
use OCP\IConfig;
use OCP\IL10N;
-use OCP\ILogger;
+use Psr\Log\LoggerInterface;
class Manager implements IManager {
@@ -44,8 +44,7 @@ class Manager implements IManager {
/** @var IConfig */
protected $config;
- /** @var ILogger */
- protected $logger;
+ protected LoggerInterface $logger;
/** @var Il10n */
protected $l;
@@ -59,15 +58,7 @@ class Manager implements IManager {
/** @var ArrayCache */
protected $arrayCache;
- /**
- * @param IConfig $config
- * @param ILogger $logger
- * @param IL10N $l10n
- * @param View $rootView
- * @param Util $util
- * @param ArrayCache $arrayCache
- */
- public function __construct(IConfig $config, ILogger $logger, IL10N $l10n, View $rootView, Util $util, ArrayCache $arrayCache) {
+ public function __construct(IConfig $config, LoggerInterface $logger, IL10N $l10n, View $rootView, Util $util, ArrayCache $arrayCache) {
$this->encryptionModules = [];
$this->config = $config;
$this->logger = $logger;
diff --git a/lib/private/EventDispatcher/GenericEventWrapper.php b/lib/private/EventDispatcher/GenericEventWrapper.php
index 3574bc8bb83..b4d851d700f 100644
--- a/lib/private/EventDispatcher/GenericEventWrapper.php
+++ b/lib/private/EventDispatcher/GenericEventWrapper.php
@@ -26,13 +26,11 @@ declare(strict_types=1);
*/
namespace OC\EventDispatcher;
-use OCP\ILogger;
+use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\GenericEvent;
class GenericEventWrapper extends GenericEvent {
-
- /** @var ILogger */
- private $logger;
+ private LoggerInterface $logger;
/** @var GenericEvent */
private $event;
@@ -43,7 +41,7 @@ class GenericEventWrapper extends GenericEvent {
/** @var bool */
private $deprecationNoticeLogged = false;
- public function __construct(ILogger $logger, string $eventName, ?GenericEvent $event) {
+ public function __construct(LoggerInterface $logger, string $eventName, ?GenericEvent $event) {
parent::__construct($eventName);
$this->logger = $logger;
$this->event = $event;
diff --git a/lib/private/EventDispatcher/SymfonyAdapter.php b/lib/private/EventDispatcher/SymfonyAdapter.php
index 6cd636afc55..a12e932e380 100644
--- a/lib/private/EventDispatcher/SymfonyAdapter.php
+++ b/lib/private/EventDispatcher/SymfonyAdapter.php
@@ -27,12 +27,12 @@ declare(strict_types=1);
*/
namespace OC\EventDispatcher;
-use Symfony\Component\EventDispatcher\GenericEvent;
-use function is_callable;
use OCP\EventDispatcher\Event;
-use OCP\ILogger;
+use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\EventDispatcher\GenericEvent;
+use function is_callable;
use function is_object;
use function is_string;
@@ -43,13 +43,12 @@ class SymfonyAdapter implements EventDispatcherInterface {
/** @var EventDispatcher */
private $eventDispatcher;
- /** @var ILogger */
- private $logger;
+ private LoggerInterface $logger;
/**
* @deprecated 20.0.0
*/
- public function __construct(EventDispatcher $eventDispatcher, ILogger $logger) {
+ public function __construct(EventDispatcher $eventDispatcher, LoggerInterface $logger) {
$this->eventDispatcher = $eventDispatcher;
$this->logger = $logger;
}
diff --git a/lib/private/Federation/CloudFederationProviderManager.php b/lib/private/Federation/CloudFederationProviderManager.php
index c19ca8429ca..c25d4a40363 100644
--- a/lib/private/Federation/CloudFederationProviderManager.php
+++ b/lib/private/Federation/CloudFederationProviderManager.php
@@ -32,7 +32,7 @@ use OCP\Federation\ICloudFederationProviderManager;
use OCP\Federation\ICloudFederationShare;
use OCP\Federation\ICloudIdManager;
use OCP\Http\Client\IClientService;
-use OCP\ILogger;
+use Psr\Log\LoggerInterface;
/**
* Class Manager
@@ -55,8 +55,7 @@ class CloudFederationProviderManager implements ICloudFederationProviderManager
/** @var ICloudIdManager */
private $cloudIdManager;
- /** @var ILogger */
- private $logger;
+ private LoggerInterface $logger;
/** @var array cache OCM end-points */
private $ocmEndPoints = [];
@@ -69,12 +68,11 @@ class CloudFederationProviderManager implements ICloudFederationProviderManager
* @param IAppManager $appManager
* @param IClientService $httpClientService
* @param ICloudIdManager $cloudIdManager
- * @param ILogger $logger
*/
public function __construct(IAppManager $appManager,
IClientService $httpClientService,
ICloudIdManager $cloudIdManager,
- ILogger $logger) {
+ LoggerInterface $logger) {
$this->cloudFederationProvider = [];
$this->appManager = $appManager;
$this->httpClientService = $httpClientService;
@@ -156,7 +154,7 @@ class CloudFederationProviderManager implements ICloudFederationProviderManager
// we re-throw the exception and fall back to the old behaviour.
// (flat re-shares has been introduced in Nextcloud 9.1)
if ($e->getCode() === Http::STATUS_INTERNAL_SERVER_ERROR) {
- $this->logger->debug($e->getMessage());
+ $this->logger->debug($e->getMessage(), ['exception' => $e]);
throw $e;
}
}
@@ -190,7 +188,7 @@ class CloudFederationProviderManager implements ICloudFederationProviderManager
}
} catch (\Exception $e) {
// log the error and return false
- $this->logger->error('error while sending notification for federated share: ' . $e->getMessage());
+ $this->logger->error('error while sending notification for federated share: ' . $e->getMessage(), ['exception' => $e]);
}
return false;
diff --git a/lib/private/Files/Cache/Cache.php b/lib/private/Files/Cache/Cache.php
index 7c2e635549a..949079dfa22 100644
--- a/lib/private/Files/Cache/Cache.php
+++ b/lib/private/Files/Cache/Cache.php
@@ -58,6 +58,7 @@ use OCP\Files\Search\ISearchOperator;
use OCP\Files\Search\ISearchQuery;
use OCP\Files\Storage\IStorage;
use OCP\IDBConnection;
+use Psr\Log\LoggerInterface;
/**
* Metadata cache for a storage
@@ -128,7 +129,7 @@ class Cache implements ICache {
return new CacheQueryBuilder(
$this->connection,
\OC::$server->getSystemConfig(),
- \OC::$server->getLogger()
+ \OC::$server->get(LoggerInterface::class)
);
}
@@ -590,7 +591,7 @@ class Cache implements ICache {
$query = $this->getQueryBuilder();
$query->delete('filecache_extended')
->where($query->expr()->in('fileid', $query->createParameter('childIds')));
-
+
foreach (array_chunk($childIds, 1000) as $childIdChunk) {
$query->setParameter('childIds', $childIdChunk, IQueryBuilder::PARAM_INT_ARRAY);
$query->execute();
diff --git a/lib/private/Files/Cache/CacheQueryBuilder.php b/lib/private/Files/Cache/CacheQueryBuilder.php
index 87a1f940f20..b5a9101877c 100644
--- a/lib/private/Files/Cache/CacheQueryBuilder.php
+++ b/lib/private/Files/Cache/CacheQueryBuilder.php
@@ -29,7 +29,7 @@ use OC\DB\QueryBuilder\QueryBuilder;
use OC\SystemConfig;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
-use OCP\ILogger;
+use Psr\Log\LoggerInterface;
/**
* Query builder with commonly used helpers for filecache queries
@@ -37,7 +37,7 @@ use OCP\ILogger;
class CacheQueryBuilder extends QueryBuilder {
private $alias = null;
- public function __construct(IDBConnection $connection, SystemConfig $systemConfig, ILogger $logger) {
+ public function __construct(IDBConnection $connection, SystemConfig $systemConfig, LoggerInterface $logger) {
parent::__construct($connection, $systemConfig, $logger);
}
diff --git a/lib/private/Files/Cache/QuerySearchHelper.php b/lib/private/Files/Cache/QuerySearchHelper.php
index e065e95e4fd..3bf9abf3524 100644
--- a/lib/private/Files/Cache/QuerySearchHelper.php
+++ b/lib/private/Files/Cache/QuerySearchHelper.php
@@ -34,7 +34,7 @@ use OCP\Files\IMimeTypeLoader;
use OCP\Files\Search\ISearchBinaryOperator;
use OCP\Files\Search\ISearchQuery;
use OCP\IDBConnection;
-use OCP\ILogger;
+use Psr\Log\LoggerInterface;
class QuerySearchHelper {
@@ -44,8 +44,7 @@ class QuerySearchHelper {
private $connection;
/** @var SystemConfig */
private $systemConfig;
- /** @var ILogger */
- private $logger;
+ private LoggerInterface $logger;
/** @var SearchBuilder */
private $searchBuilder;
/** @var QueryOptimizer */
@@ -55,7 +54,7 @@ class QuerySearchHelper {
IMimeTypeLoader $mimetypeLoader,
IDBConnection $connection,
SystemConfig $systemConfig,
- ILogger $logger,
+ LoggerInterface $logger,
SearchBuilder $searchBuilder,
QueryOptimizer $queryOptimizer
) {
diff --git a/lib/private/Files/Cache/Storage.php b/lib/private/Files/Cache/Storage.php
index 2de2c2f84d7..fb9e5500658 100644
--- a/lib/private/Files/Cache/Storage.php
+++ b/lib/private/Files/Cache/Storage.php
@@ -126,19 +126,9 @@ class Storage {
* @param int $numericId
* @return string|null either the storage id string or null if the numeric id is not known
*/
- public static function getStorageId($numericId) {
- $query = \OC::$server->getDatabaseConnection()->getQueryBuilder();
- $query->select('id')
- ->from('storages')
- ->where($query->expr()->eq('numeric_id', $query->createNamedParameter($numericId)));
- $result = $query->execute();
- $row = $result->fetch();
- $result->closeCursor();
- if ($row) {
- return $row['id'];
- } else {
- return null;
- }
+ public static function getStorageId(int $numericId): ?string {
+ $storage = self::getGlobalCache()->getStorageInfoByNumericId($numericId);
+ return $storage['id'] ?? null;
}
/**
@@ -240,6 +230,7 @@ class Storage {
->from('mounts')
->where($query->expr()->eq('mount_id', $query->createNamedParameter($mountId, IQueryBuilder::PARAM_INT)));
$storageIds = $query->executeQuery()->fetchAll(\PDO::FETCH_COLUMN);
+ $storageIds = array_unique($storageIds);
$query = $db->getQueryBuilder();
$query->delete('filecache')
diff --git a/lib/private/Files/Cache/StorageGlobal.php b/lib/private/Files/Cache/StorageGlobal.php
index 7162f8e4908..a898c435415 100644
--- a/lib/private/Files/Cache/StorageGlobal.php
+++ b/lib/private/Files/Cache/StorageGlobal.php
@@ -41,8 +41,10 @@ class StorageGlobal {
/** @var IDBConnection */
private $connection;
- /** @var array[] */
+ /** @var array<string, array> */
private $cache = [];
+ /** @var array<int, array> */
+ private $numericIdCache = [];
public function __construct(IDBConnection $connection) {
$this->connection = $connection;
@@ -68,7 +70,7 @@ class StorageGlobal {
* @param string $storageId
* @return array|null
*/
- public function getStorageInfo($storageId) {
+ public function getStorageInfo(string $storageId): ?array {
if (!isset($this->cache[$storageId])) {
$builder = $this->connection->getQueryBuilder();
$query = $builder->select(['id', 'numeric_id', 'available', 'last_checked'])
@@ -81,9 +83,33 @@ class StorageGlobal {
if ($row) {
$this->cache[$storageId] = $row;
+ $this->numericIdCache[(int)$row['numeric_id']] = $row;
}
}
- return isset($this->cache[$storageId]) ? $this->cache[$storageId] : null;
+ return $this->cache[$storageId] ?? null;
+ }
+
+ /**
+ * @param int $numericId
+ * @return array|null
+ */
+ public function getStorageInfoByNumericId(int $numericId): ?array {
+ if (!isset($this->numericIdCache[$numericId])) {
+ $builder = $this->connection->getQueryBuilder();
+ $query = $builder->select(['id', 'numeric_id', 'available', 'last_checked'])
+ ->from('storages')
+ ->where($builder->expr()->eq('numeric_id', $builder->createNamedParameter($numericId)));
+
+ $result = $query->execute();
+ $row = $result->fetch();
+ $result->closeCursor();
+
+ if ($row) {
+ $this->numericIdCache[$numericId] = $row;
+ $this->cache[$row['id']] = $row;
+ }
+ }
+ return $this->numericIdCache[$numericId] ?? null;
}
public function clearCache() {
diff --git a/lib/private/Files/Config/MountProviderCollection.php b/lib/private/Files/Config/MountProviderCollection.php
index cd8a2a2e29f..334fce15d9e 100644
--- a/lib/private/Files/Config/MountProviderCollection.php
+++ b/lib/private/Files/Config/MountProviderCollection.php
@@ -75,16 +75,15 @@ class MountProviderCollection implements IMountProviderCollection, Emitter {
}
/**
- * Get all configured mount points for the user
- *
- * @param \OCP\IUser $user
- * @return \OCP\Files\Mount\IMountPoint[]
+ * @param IUser $user
+ * @param IMountProvider[] $providers
+ * @return IMountPoint[]
*/
- public function getMountsForUser(IUser $user) {
+ private function getUserMountsForProviders(IUser $user, array $providers): array {
$loader = $this->loader;
$mounts = array_map(function (IMountProvider $provider) use ($user, $loader) {
return $provider->getMountsForUser($user, $loader);
- }, $this->providers);
+ }, $providers);
$mounts = array_filter($mounts, function ($result) {
return is_array($result);
});
@@ -94,14 +93,31 @@ class MountProviderCollection implements IMountProviderCollection, Emitter {
return $this->filterMounts($user, $mounts);
}
- public function addMountForUser(IUser $user, IMountManager $mountManager) {
+ public function getMountsForUser(IUser $user): array {
+ return $this->getUserMountsForProviders($user, $this->providers);
+ }
+
+ public function getUserMountsForProviderClasses(IUser $user, array $mountProviderClasses): array {
+ $providers = array_filter(
+ $this->providers,
+ fn (IMountProvider $mountProvider) => (in_array(get_class($mountProvider), $mountProviderClasses))
+ );
+ return $this->getUserMountsForProviders($user, $providers);
+ }
+
+ public function addMountForUser(IUser $user, IMountManager $mountManager, callable $providerFilter = null) {
// shared mount provider gets to go last since it needs to know existing files
// to check for name collisions
$firstMounts = [];
- $firstProviders = array_filter($this->providers, function (IMountProvider $provider) {
+ if ($providerFilter) {
+ $providers = array_filter($this->providers, $providerFilter);
+ } else {
+ $providers = $this->providers;
+ }
+ $firstProviders = array_filter($providers, function (IMountProvider $provider) {
return (get_class($provider) !== 'OCA\Files_Sharing\MountProvider');
});
- $lastProviders = array_filter($this->providers, function (IMountProvider $provider) {
+ $lastProviders = array_filter($providers, function (IMountProvider $provider) {
return (get_class($provider) === 'OCA\Files_Sharing\MountProvider');
});
foreach ($firstProviders as $provider) {
diff --git a/lib/private/Files/Config/UserMountCache.php b/lib/private/Files/Config/UserMountCache.php
index dc2640361e7..666ba9b065b 100644
--- a/lib/private/Files/Config/UserMountCache.php
+++ b/lib/private/Files/Config/UserMountCache.php
@@ -38,9 +38,9 @@ use OCP\Files\Mount\IMountPoint;
use OCP\Files\NotFoundException;
use OCP\ICache;
use OCP\IDBConnection;
-use OCP\ILogger;
use OCP\IUser;
use OCP\IUserManager;
+use Psr\Log\LoggerInterface;
/**
* Cache mounts points per user in the cache so we can easilly look them up
@@ -64,10 +64,7 @@ class UserMountCache implements IUserMountCache {
**/
private $mountsForUsers;
- /**
- * @var ILogger
- */
- private $logger;
+ private LoggerInterface $logger;
/**
* @var ICache
@@ -76,12 +73,8 @@ class UserMountCache implements IUserMountCache {
/**
* UserMountCache constructor.
- *
- * @param IDBConnection $connection
- * @param IUserManager $userManager
- * @param ILogger $logger
*/
- public function __construct(IDBConnection $connection, IUserManager $userManager, ILogger $logger) {
+ public function __construct(IDBConnection $connection, IUserManager $userManager, LoggerInterface $logger) {
$this->connection = $connection;
$this->userManager = $userManager;
$this->logger = $logger;
@@ -89,7 +82,7 @@ class UserMountCache implements IUserMountCache {
$this->mountsForUsers = new CappedMemoryCache();
}
- public function registerMounts(IUser $user, array $mounts) {
+ public function registerMounts(IUser $user, array $mounts, array $mountProviderClasses = null) {
// filter out non-proper storages coming from unit tests
$mounts = array_filter($mounts, function (IMountPoint $mount) {
return $mount instanceof SharedMount || $mount->getStorage() && $mount->getStorage()->getCache();
@@ -110,6 +103,11 @@ class UserMountCache implements IUserMountCache {
$newMounts = array_combine($newMountRootIds, $newMounts);
$cachedMounts = $this->getMountsForUser($user);
+ if (is_array($mountProviderClasses)) {
+ $cachedMounts = array_filter($cachedMounts, function (ICachedMountInfo $mountInfo) use ($mountProviderClasses) {
+ return in_array($mountInfo->getMountProvider(), $mountProviderClasses);
+ });
+ }
$cachedMountRootIds = array_map(function (ICachedMountInfo $mount) {
return $mount->getRootId();
}, $cachedMounts);
@@ -446,4 +444,39 @@ class UserMountCache implements IUserMountCache {
$this->cacheInfoCache = new CappedMemoryCache();
$this->mountsForUsers = new CappedMemoryCache();
}
+
+ public function getMountForPath(IUser $user, string $path): ICachedMountInfo {
+ $mounts = $this->getMountsForUser($user);
+ $mountPoints = array_map(function (ICachedMountInfo $mount) {
+ return $mount->getMountPoint();
+ }, $mounts);
+ $mounts = array_combine($mountPoints, $mounts);
+
+ $current = $path;
+ // walk up the directory tree until we find a path that has a mountpoint set
+ // the loop will return if a mountpoint is found or break if none are found
+ while (true) {
+ $mountPoint = $current . '/';
+ if (isset($mounts[$mountPoint])) {
+ return $mounts[$mountPoint];
+ } elseif ($current === '') {
+ break;
+ }
+
+ $current = dirname($current);
+ if ($current === '.' || $current === '/') {
+ $current = '';
+ }
+ }
+
+ throw new NotFoundException("No cached mount for path " . $path);
+ }
+
+ public function getMountsInPath(IUser $user, string $path): array {
+ $path = rtrim($path, '/') . '/';
+ $mounts = $this->getMountsForUser($user);
+ return array_filter($mounts, function (ICachedMountInfo $mount) use ($path) {
+ return $mount->getMountPoint() !== $path && strpos($mount->getMountPoint(), $path) === 0;
+ });
+ }
}
diff --git a/lib/private/Files/Filesystem.php b/lib/private/Files/Filesystem.php
index 9db9252037f..20b44e2736a 100644
--- a/lib/private/Files/Filesystem.php
+++ b/lib/private/Files/Filesystem.php
@@ -46,6 +46,7 @@ use OCP\Files\NotFoundException;
use OCP\Files\Storage\IStorageFactory;
use OCP\IUser;
use OCP\IUserManager;
+use OCP\IUserSession;
class Filesystem {
@@ -324,6 +325,18 @@ class Filesystem {
if (self::$defaultInstance) {
return false;
}
+ self::initInternal($root);
+
+ //load custom mount config
+ self::initMountPoints($user);
+
+ return true;
+ }
+
+ public static function initInternal($root) {
+ if (self::$defaultInstance) {
+ return false;
+ }
self::getLoader();
self::$defaultInstance = new View($root);
/** @var IEventDispatcher $eventDispatcher */
@@ -338,9 +351,6 @@ class Filesystem {
self::$mounts = \OC::$server->getMountManager();
}
- //load custom mount config
- self::initMountPoints($user);
-
self::$loaded = true;
return true;
@@ -378,6 +388,15 @@ class Filesystem {
* @return View
*/
public static function getView() {
+ if (!self::$defaultInstance) {
+ /** @var IUserSession $session */
+ $session = \OC::$server->get(IUserSession::class);
+ $user = $session->getUser();
+ if ($user) {
+ $userDir = '/' . $user->getUID() . '/files';
+ self::initInternal($userDir);
+ }
+ }
return self::$defaultInstance;
}
@@ -736,7 +755,7 @@ class Filesystem {
* @return \OC\Files\FileInfo|false False if file does not exist
*/
public static function getFileInfo($path, $includeMountPoints = true) {
- return self::$defaultInstance->getFileInfo($path, $includeMountPoints);
+ return self::getView()->getFileInfo($path, $includeMountPoints);
}
/**
diff --git a/lib/private/Files/Mount/Manager.php b/lib/private/Files/Mount/Manager.php
index 66832690363..69285018d17 100644
--- a/lib/private/Files/Mount/Manager.php
+++ b/lib/private/Files/Mount/Manager.php
@@ -125,7 +125,7 @@ class Manager implements IMountManager {
* @return IMountPoint[]
*/
public function findIn(string $path): array {
- $this->setupManager->setupForPath($path);
+ $this->setupManager->setupForPath($path, true);
$path = $this->formatPath($path);
if (isset($this->inPathCache[$path])) {
@@ -158,7 +158,6 @@ class Manager implements IMountManager {
* @return IMountPoint[]
*/
public function findByStorageId(string $id): array {
- \OC_Util::setupFS();
if (\strlen($id) > 64) {
$id = md5($id);
}
@@ -204,4 +203,22 @@ class Manager implements IMountManager {
public function getSetupManager(): SetupManager {
return $this->setupManager;
}
+
+ /**
+ * Return all mounts in a path from a specific mount provider
+ *
+ * @param string $path
+ * @param string[] $mountProviders
+ * @return MountPoint[]
+ */
+ public function getMountsByMountProvider(string $path, array $mountProviders) {
+ $this->getSetupManager()->setupForProvider($path, $mountProviders);
+ if (in_array('', $mountProviders)) {
+ return $this->mounts;
+ } else {
+ return array_filter($this->mounts, function ($mount) use ($mountProviders) {
+ return in_array($mount->getMountProvider(), $mountProviders);
+ });
+ }
+ }
}
diff --git a/lib/private/Files/Mount/ObjectStorePreviewCacheMountProvider.php b/lib/private/Files/Mount/ObjectStorePreviewCacheMountProvider.php
index 0043503f2cd..3a20afba5a5 100644
--- a/lib/private/Files/Mount/ObjectStorePreviewCacheMountProvider.php
+++ b/lib/private/Files/Mount/ObjectStorePreviewCacheMountProvider.php
@@ -31,18 +31,17 @@ use OC\Files\Storage\Wrapper\Jail;
use OCP\Files\Config\IRootMountProvider;
use OCP\Files\Storage\IStorageFactory;
use OCP\IConfig;
-use OCP\ILogger;
+use Psr\Log\LoggerInterface;
/**
* Mount provider for object store app data folder for previews
*/
class ObjectStorePreviewCacheMountProvider implements IRootMountProvider {
- /** @var ILogger */
- private $logger;
+ private LoggerInterface $logger;
/** @var IConfig */
private $config;
- public function __construct(ILogger $logger, IConfig $config) {
+ public function __construct(LoggerInterface $logger, IConfig $config) {
$this->logger = $logger;
$this->config = $config;
}
diff --git a/lib/private/Files/Node/Folder.php b/lib/private/Files/Node/Folder.php
index 400fd6bedcc..d058805b20e 100644
--- a/lib/private/Files/Node/Folder.php
+++ b/lib/private/Files/Node/Folder.php
@@ -36,6 +36,7 @@ use OC\Files\Cache\Wrapper\CacheJail;
use OC\Files\Search\SearchComparison;
use OC\Files\Search\SearchOrder;
use OC\Files\Search\SearchQuery;
+use OC\Files\Utils\PathHelper;
use OCP\Files\Cache\ICacheEntry;
use OCP\Files\FileInfo;
use OCP\Files\Mount\IMountPoint;
@@ -76,17 +77,7 @@ class Folder extends Node implements \OCP\Files\Folder {
* @return string|null
*/
public function getRelativePath($path) {
- if ($this->path === '' or $this->path === '/') {
- return $this->normalizePath($path);
- }
- if ($path === $this->path) {
- return '/';
- } elseif (strpos($path, $this->path . '/') !== 0) {
- return null;
- } else {
- $path = substr($path, strlen($this->path));
- return $this->normalizePath($path);
- }
+ return PathHelper::getRelativePath($this->getPath(), $path);
}
/**
@@ -342,70 +333,7 @@ class Folder extends Node implements \OCP\Files\Folder {
* @return \OC\Files\Node\Node[]
*/
public function getById($id) {
- $mountCache = $this->root->getUserMountCache();
- if (strpos($this->getPath(), '/', 1) > 0) {
- [, $user] = explode('/', $this->getPath());
- } else {
- $user = null;
- }
- $mountsContainingFile = $mountCache->getMountsForFileId((int)$id, $user);
-
- // when a user has access trough the same storage trough multiple paths
- // (such as an external storage that is both mounted for a user and shared to the user)
- // the mount cache will only hold a single entry for the storage
- // this can lead to issues as the different ways the user has access to a storage can have different permissions
- //
- // so instead of using the cached entries directly, we instead filter the current mounts by the rootid of the cache entry
-
- $mountRootIds = array_map(function ($mount) {
- return $mount->getRootId();
- }, $mountsContainingFile);
- $mountRootPaths = array_map(function ($mount) {
- return $mount->getRootInternalPath();
- }, $mountsContainingFile);
- $mountRoots = array_combine($mountRootIds, $mountRootPaths);
-
- $mounts = $this->root->getMountsIn($this->path);
- $mounts[] = $this->root->getMount($this->path);
-
- $mountsContainingFile = array_filter($mounts, function ($mount) use ($mountRoots) {
- return isset($mountRoots[$mount->getStorageRootId()]);
- });
-
- if (count($mountsContainingFile) === 0) {
- if ($user === $this->getAppDataDirectoryName()) {
- return $this->getByIdInRootMount((int)$id);
- }
- return [];
- }
-
- $nodes = array_map(function (IMountPoint $mount) use ($id, $mountRoots) {
- $rootInternalPath = $mountRoots[$mount->getStorageRootId()];
- $cacheEntry = $mount->getStorage()->getCache()->get((int)$id);
- if (!$cacheEntry) {
- return null;
- }
-
- // cache jails will hide the "true" internal path
- $internalPath = ltrim($rootInternalPath . '/' . $cacheEntry->getPath(), '/');
- $pathRelativeToMount = substr($internalPath, strlen($rootInternalPath));
- $pathRelativeToMount = ltrim($pathRelativeToMount, '/');
- $absolutePath = rtrim($mount->getMountPoint() . $pathRelativeToMount, '/');
- return $this->root->createNode($absolutePath, new \OC\Files\FileInfo(
- $absolutePath, $mount->getStorage(), $cacheEntry->getPath(), $cacheEntry, $mount,
- \OC::$server->getUserManager()->get($mount->getStorage()->getOwner($pathRelativeToMount))
- ));
- }, $mountsContainingFile);
-
- $nodes = array_filter($nodes);
-
- $folders = array_filter($nodes, function (Node $node) {
- return $this->getRelativePath($node->getPath());
- });
- usort($folders, function ($a, $b) {
- return $b->getPath() <=> $a->getPath();
- });
- return $folders;
+ return $this->root->getByIdInPath((int)$id, $this->getPath());
}
protected function getAppDataDirectoryName(): string {
diff --git a/lib/private/Files/Node/LazyFolder.php b/lib/private/Files/Node/LazyFolder.php
index bfdaeeccff7..7d5038e85a2 100644
--- a/lib/private/Files/Node/LazyFolder.php
+++ b/lib/private/Files/Node/LazyFolder.php
@@ -25,6 +25,9 @@ declare(strict_types=1);
*/
namespace OC\Files\Node;
+use OC\Files\Utils\PathHelper;
+use OCP\Constants;
+
/**
* Class LazyFolder
*
@@ -40,13 +43,16 @@ class LazyFolder implements \OCP\Files\Folder {
/** @var LazyFolder | null */
protected $folder = null;
+ protected array $data;
+
/**
* LazyFolder constructor.
*
* @param \Closure $folderClosure
*/
- public function __construct(\Closure $folderClosure) {
+ public function __construct(\Closure $folderClosure, array $data = []) {
$this->folderClosure = $folderClosure;
+ $this->data = $data;
}
/**
@@ -181,6 +187,9 @@ class LazyFolder implements \OCP\Files\Folder {
* @inheritDoc
*/
public function getPath() {
+ if (isset($this->data['path'])) {
+ return $this->data['path'];
+ }
return $this->__call(__FUNCTION__, func_get_args());
}
@@ -230,6 +239,9 @@ class LazyFolder implements \OCP\Files\Folder {
* @inheritDoc
*/
public function getPermissions() {
+ if (isset($this->data['permissions'])) {
+ return $this->data['permissions'];
+ }
return $this->__call(__FUNCTION__, func_get_args());
}
@@ -237,6 +249,9 @@ class LazyFolder implements \OCP\Files\Folder {
* @inheritDoc
*/
public function isReadable() {
+ if (isset($this->data['permissions'])) {
+ return ($this->data['permissions'] & Constants::PERMISSION_READ) == Constants::PERMISSION_READ;
+ }
return $this->__call(__FUNCTION__, func_get_args());
}
@@ -244,6 +259,9 @@ class LazyFolder implements \OCP\Files\Folder {
* @inheritDoc
*/
public function isUpdateable() {
+ if (isset($this->data['permissions'])) {
+ return ($this->data['permissions'] & Constants::PERMISSION_UPDATE) == Constants::PERMISSION_UPDATE;
+ }
return $this->__call(__FUNCTION__, func_get_args());
}
@@ -251,6 +269,9 @@ class LazyFolder implements \OCP\Files\Folder {
* @inheritDoc
*/
public function isDeletable() {
+ if (isset($this->data['permissions'])) {
+ return ($this->data['permissions'] & Constants::PERMISSION_DELETE) == Constants::PERMISSION_DELETE;
+ }
return $this->__call(__FUNCTION__, func_get_args());
}
@@ -258,6 +279,9 @@ class LazyFolder implements \OCP\Files\Folder {
* @inheritDoc
*/
public function isShareable() {
+ if (isset($this->data['permissions'])) {
+ return ($this->data['permissions'] & Constants::PERMISSION_SHARE) == Constants::PERMISSION_SHARE;
+ }
return $this->__call(__FUNCTION__, func_get_args());
}
@@ -359,13 +383,6 @@ class LazyFolder implements \OCP\Files\Folder {
/**
* @inheritDoc
*/
- public function getRelativePath($path) {
- return $this->__call(__FUNCTION__, func_get_args());
- }
-
- /**
- * @inheritDoc
- */
public function isSubNode($node) {
return $this->__call(__FUNCTION__, func_get_args());
}
@@ -495,4 +512,8 @@ class LazyFolder implements \OCP\Files\Folder {
public function getUploadTime(): int {
return $this->__call(__FUNCTION__, func_get_args());
}
+
+ public function getRelativePath($path) {
+ return PathHelper::getRelativePath($this->getPath(), $path);
+ }
}
diff --git a/lib/private/Files/Node/LazyRoot.php b/lib/private/Files/Node/LazyRoot.php
index c4d61f653e4..c01b9fdbb83 100644
--- a/lib/private/Files/Node/LazyRoot.php
+++ b/lib/private/Files/Node/LazyRoot.php
@@ -39,4 +39,8 @@ class LazyRoot extends LazyFolder implements IRootFolder {
public function getUserFolder($userId) {
return $this->__call(__FUNCTION__, func_get_args());
}
+
+ public function getByIdInPath(int $id, string $path) {
+ return $this->__call(__FUNCTION__, func_get_args());
+ }
}
diff --git a/lib/private/Files/Node/LazyUserFolder.php b/lib/private/Files/Node/LazyUserFolder.php
new file mode 100644
index 00000000000..d91759117c1
--- /dev/null
+++ b/lib/private/Files/Node/LazyUserFolder.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\Node;
+
+use OCP\Constants;
+use OCP\Files\IRootFolder;
+use OCP\Files\NotFoundException;
+use OCP\IUser;
+
+class LazyUserFolder extends LazyFolder {
+ private IRootFolder $root;
+ private IUser $user;
+ private string $path;
+
+ public function __construct(IRootFolder $rootFolder, IUser $user) {
+ $this->root = $rootFolder;
+ $this->user = $user;
+ $this->path = '/' . $user->getUID() . '/files';
+ parent::__construct(function () use ($user) {
+ try {
+ return $this->root->get('/' . $user->getUID() . '/files');
+ } catch (NotFoundException $e) {
+ if (!$this->root->nodeExists('/' . $user->getUID())) {
+ $this->root->newFolder('/' . $user->getUID());
+ }
+ return $this->root->newFolder('/' . $user->getUID() . '/files');
+ }
+ }, [
+ 'path' => $this->path,
+ 'permissions' => Constants::PERMISSION_ALL,
+ ]);
+ }
+
+ public function get($path) {
+ return $this->root->get('/' . $this->user->getUID() . '/files/' . ltrim($path, '/'));
+ }
+
+ /**
+ * @param int $id
+ * @return \OC\Files\Node\Node[]
+ */
+ public function getById($id) {
+ return $this->root->getByIdInPath((int)$id, $this->getPath());
+ }
+}
diff --git a/lib/private/Files/Node/Node.php b/lib/private/Files/Node/Node.php
index b939bfce945..c8975154059 100644
--- a/lib/private/Files/Node/Node.php
+++ b/lib/private/Files/Node/Node.php
@@ -31,6 +31,7 @@ namespace OC\Files\Node;
use OC\Files\Filesystem;
use OC\Files\Mount\MoveableMount;
+use OC\Files\Utils\PathHelper;
use OCP\Files\FileInfo;
use OCP\Files\InvalidPathException;
use OCP\Files\NotFoundException;
@@ -153,12 +154,11 @@ class Node implements \OCP\Files\Node {
}
}
- /**
- * @return \OC\Files\Storage\Storage
- * @throws \OCP\Files\NotFoundException
- */
public function getStorage() {
- [$storage,] = $this->view->resolvePath($this->path);
+ $storage = $this->getMountPoint()->getStorage();
+ if (!$storage) {
+ throw new \Exception("No storage for node");
+ }
return $storage;
}
@@ -173,8 +173,7 @@ class Node implements \OCP\Files\Node {
* @return string
*/
public function getInternalPath() {
- [, $internalPath] = $this->view->resolvePath($this->path);
- return $internalPath;
+ return $this->getFileInfo()->getInternalPath();
}
/**
@@ -298,23 +297,7 @@ class Node implements \OCP\Files\Node {
* @return string
*/
protected function normalizePath($path) {
- if ($path === '' or $path === '/') {
- return '/';
- }
- //no windows style slashes
- $path = str_replace('\\', '/', $path);
- //add leading slash
- if ($path[0] !== '/') {
- $path = '/' . $path;
- }
- //remove duplicate slashes
- while (strpos($path, '//') !== false) {
- $path = str_replace('//', '/', $path);
- }
- //remove trailing slash
- $path = rtrim($path, '/');
-
- return $path;
+ return PathHelper::normalizePath($path);
}
/**
@@ -447,6 +430,15 @@ class Node implements \OCP\Files\Node {
if (!$this->view->rename($this->path, $targetPath)) {
throw new NotPermittedException('Could not move ' . $this->path . ' to ' . $targetPath);
}
+
+ $mountPoint = $this->getMountPoint();
+ if ($mountPoint) {
+ // update the cached fileinfo with the new (internal) path
+ /** @var \OC\Files\FileInfo $oldFileInfo */
+ $oldFileInfo = $this->getFileInfo();
+ $this->fileInfo = new \OC\Files\FileInfo($targetPath, $oldFileInfo->getStorage(), $mountPoint->getInternalPath($targetPath), $oldFileInfo->getData(), $mountPoint, $oldFileInfo->getOwner());
+ }
+
$targetNode = $this->root->get($targetPath);
$this->sendHooks(['postRename'], [$this, $targetNode]);
$this->sendHooks(['postWrite'], [$targetNode]);
diff --git a/lib/private/Files/Node/Root.php b/lib/private/Files/Node/Root.php
index 88ac4a31d34..7592d4caf37 100644
--- a/lib/private/Files/Node/Root.php
+++ b/lib/private/Files/Node/Root.php
@@ -33,8 +33,10 @@
namespace OC\Files\Node;
use OC\Cache\CappedMemoryCache;
+use OC\Files\FileInfo;
use OC\Files\Mount\Manager;
use OC\Files\Mount\MountPoint;
+use OC\Files\Utils\PathHelper;
use OC\Files\View;
use OC\Hooks\PublicEmitter;
use OC\User\NoUserException;
@@ -42,11 +44,12 @@ use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\Config\IUserMountCache;
use OCP\Files\Events\Node\FilesystemTornDownEvent;
use OCP\Files\IRootFolder;
+use OCP\Files\Mount\IMountPoint;
use OCP\Files\NotFoundException;
use OCP\Files\NotPermittedException;
-use OCP\ILogger;
use OCP\IUser;
use OCP\IUserManager;
+use Psr\Log\LoggerInterface;
/**
* Class Root
@@ -73,7 +76,7 @@ class Root extends Folder implements IRootFolder {
private ?IUser $user;
private CappedMemoryCache $userFolderCache;
private IUserMountCache $userMountCache;
- private ILogger $logger;
+ private LoggerInterface $logger;
private IUserManager $userManager;
private IEventDispatcher $eventDispatcher;
@@ -81,16 +84,13 @@ class Root extends Folder implements IRootFolder {
* @param Manager $manager
* @param View $view
* @param IUser|null $user
- * @param IUserMountCache $userMountCache
- * @param ILogger $logger
- * @param IUserManager $userManager
*/
public function __construct(
$manager,
$view,
$user,
IUserMountCache $userMountCache,
- ILogger $logger,
+ LoggerInterface $logger,
IUserManager $userManager,
IEventDispatcher $eventDispatcher
) {
@@ -217,7 +217,7 @@ class Root extends Folder implements IRootFolder {
/**
* @param string $targetPath
- * @return \OC\Files\Node\Node
+ * @return Node
* @throws \OCP\Files\NotPermittedException
*/
public function rename($targetPath) {
@@ -230,7 +230,7 @@ class Root extends Folder implements IRootFolder {
/**
* @param string $targetPath
- * @return \OC\Files\Node\Node
+ * @return Node
* @throws \OCP\Files\NotPermittedException
*/
public function copy($targetPath) {
@@ -380,15 +380,20 @@ class Root extends Folder implements IRootFolder {
$userId = $userObject->getUID();
if (!$this->userFolderCache->hasKey($userId)) {
- \OC\Files\Filesystem::initMountPoints($userId);
-
- try {
- $folder = $this->get('/' . $userId . '/files');
- } catch (NotFoundException $e) {
- if (!$this->nodeExists('/' . $userId)) {
- $this->newFolder('/' . $userId);
+ if ($this->mountManager->getSetupManager()->isSetupComplete($userObject)) {
+ try {
+ $folder = $this->get('/' . $userId . '/files');
+ if (!$folder instanceof \OCP\Files\Folder) {
+ throw new \Exception("User folder for $userId exists as a file");
+ }
+ } catch (NotFoundException $e) {
+ if (!$this->nodeExists('/' . $userId)) {
+ $this->newFolder('/' . $userId);
+ }
+ $folder = $this->newFolder('/' . $userId . '/files');
}
- $folder = $this->newFolder('/' . $userId . '/files');
+ } else {
+ $folder = new LazyUserFolder($this, $userObject);
}
$this->userFolderCache->set($userId, $folder);
@@ -400,4 +405,82 @@ class Root extends Folder implements IRootFolder {
public function getUserMountCache() {
return $this->userMountCache;
}
+
+ /**
+ * @param int $id
+ * @return Node[]
+ */
+ public function getByIdInPath(int $id, string $path): array {
+ $mountCache = $this->getUserMountCache();
+ if (strpos($path, '/', 1) > 0) {
+ [, $user] = explode('/', $path);
+ } else {
+ $user = null;
+ }
+ $mountsContainingFile = $mountCache->getMountsForFileId($id, $user);
+
+ // when a user has access trough the same storage trough multiple paths
+ // (such as an external storage that is both mounted for a user and shared to the user)
+ // the mount cache will only hold a single entry for the storage
+ // this can lead to issues as the different ways the user has access to a storage can have different permissions
+ //
+ // so instead of using the cached entries directly, we instead filter the current mounts by the rootid of the cache entry
+
+ $mountRootIds = array_map(function ($mount) {
+ return $mount->getRootId();
+ }, $mountsContainingFile);
+ $mountRootPaths = array_map(function ($mount) {
+ return $mount->getRootInternalPath();
+ }, $mountsContainingFile);
+ $mountProviders = array_unique(array_map(function ($mount) {
+ return $mount->getMountProvider();
+ }, $mountsContainingFile));
+ $mountRoots = array_combine($mountRootIds, $mountRootPaths);
+
+ $mounts = $this->mountManager->getMountsByMountProvider($path, $mountProviders);
+
+ $mountsContainingFile = array_filter($mounts, function ($mount) use ($mountRoots) {
+ return isset($mountRoots[$mount->getStorageRootId()]);
+ });
+
+ if (count($mountsContainingFile) === 0) {
+ if ($user === $this->getAppDataDirectoryName()) {
+ $folder = $this->get($path);
+ if ($folder instanceof Folder) {
+ return $folder->getByIdInRootMount($id);
+ } else {
+ throw new \Exception("getByIdInPath with non folder");
+ }
+ }
+ return [];
+ }
+
+ $nodes = array_map(function (IMountPoint $mount) use ($id, $mountRoots) {
+ $rootInternalPath = $mountRoots[$mount->getStorageRootId()];
+ $cacheEntry = $mount->getStorage()->getCache()->get($id);
+ if (!$cacheEntry) {
+ return null;
+ }
+
+ // cache jails will hide the "true" internal path
+ $internalPath = ltrim($rootInternalPath . '/' . $cacheEntry->getPath(), '/');
+ $pathRelativeToMount = substr($internalPath, strlen($rootInternalPath));
+ $pathRelativeToMount = ltrim($pathRelativeToMount, '/');
+ $absolutePath = rtrim($mount->getMountPoint() . $pathRelativeToMount, '/');
+ return $this->createNode($absolutePath, new FileInfo(
+ $absolutePath, $mount->getStorage(), $cacheEntry->getPath(), $cacheEntry, $mount,
+ \OC::$server->getUserManager()->get($mount->getStorage()->getOwner($pathRelativeToMount))
+ ));
+ }, $mountsContainingFile);
+
+ $nodes = array_filter($nodes);
+
+ $folders = array_filter($nodes, function (Node $node) use ($path) {
+ return PathHelper::getRelativePath($path, $node->getPath()) !== null;
+ });
+ usort($folders, function ($a, $b) {
+ return $b->getPath() <=> $a->getPath();
+ });
+ return $folders;
+ }
}
diff --git a/lib/private/Files/ObjectStore/Swift.php b/lib/private/Files/ObjectStore/Swift.php
index a3c8d92f3d2..b463cb9d44d 100644
--- a/lib/private/Files/ObjectStore/Swift.php
+++ b/lib/private/Files/ObjectStore/Swift.php
@@ -32,6 +32,7 @@ use Icewind\Streams\RetryWrapper;
use OCP\Files\NotFoundException;
use OCP\Files\ObjectStore\IObjectStore;
use OCP\Files\StorageAuthException;
+use Psr\Log\LoggerInterface;
const SWIFT_SEGMENT_SIZE = 1073741824; // 1GB
@@ -48,7 +49,7 @@ class Swift implements IObjectStore {
$this->swiftFactory = $connectionFactory ?: new SwiftFactory(
\OC::$server->getMemCacheFactory()->createDistributed('swift::'),
$params,
- \OC::$server->getLogger()
+ \OC::$server->get(LoggerInterface::class)
);
$this->params = $params;
}
diff --git a/lib/private/Files/ObjectStore/SwiftFactory.php b/lib/private/Files/ObjectStore/SwiftFactory.php
index df4b5a93678..bd75ccada2e 100644
--- a/lib/private/Files/ObjectStore/SwiftFactory.php
+++ b/lib/private/Files/ObjectStore/SwiftFactory.php
@@ -40,7 +40,6 @@ use GuzzleHttp\HandlerStack;
use OCP\Files\StorageAuthException;
use OCP\Files\StorageNotAvailableException;
use OCP\ICache;
-use OCP\ILogger;
use OpenStack\Common\Auth\Token;
use OpenStack\Common\Error\BadResponseError;
use OpenStack\Common\Transport\Utils as TransportUtils;
@@ -50,13 +49,14 @@ use OpenStack\Identity\v3\Service as IdentityV3Service;
use OpenStack\ObjectStore\v1\Models\Container;
use OpenStack\OpenStack;
use Psr\Http\Message\RequestInterface;
+use Psr\Log\LoggerInterface;
class SwiftFactory {
private $cache;
private $params;
/** @var Container|null */
private $container = null;
- private $logger;
+ private LoggerInterface $logger;
public const DEFAULT_OPTIONS = [
'autocreate' => false,
@@ -65,7 +65,7 @@ class SwiftFactory {
'catalogType' => 'object-store'
];
- public function __construct(ICache $cache, array $params, ILogger $logger) {
+ public function __construct(ICache $cache, array $params, LoggerInterface $logger) {
$this->cache = $cache;
$this->params = $params;
$this->logger = $logger;
@@ -203,7 +203,7 @@ class SwiftFactory {
$this->logger->debug('Cached token for swift expired');
}
} catch (\Exception $e) {
- $this->logger->logException($e);
+ $this->logger->error($e->getMessage(), ['exception' => $e]);
}
}
}
@@ -279,7 +279,7 @@ class SwiftFactory {
/** @var RequestInterface $request */
$request = $e->getRequest();
$host = $request->getUri()->getHost() . ':' . $request->getUri()->getPort();
- \OC::$server->getLogger()->error("Can't connect to object storage server at $host");
+ $this->logger->error("Can't connect to object storage server at $host", ['exception' => $e]);
throw new StorageNotAvailableException("Can't connect to object storage server at $host", StorageNotAvailableException::STATUS_ERROR, $e);
}
}
diff --git a/lib/private/Files/SetupManager.php b/lib/private/Files/SetupManager.php
index 9726fbef428..ddb0bbceb81 100644
--- a/lib/private/Files/SetupManager.php
+++ b/lib/private/Files/SetupManager.php
@@ -40,16 +40,26 @@ use OC_Util;
use OCP\Constants;
use OCP\Diagnostics\IEventLogger;
use OCP\EventDispatcher\IEventDispatcher;
+use OCP\Files\Config\IHomeMountProvider;
use OCP\Files\Config\IMountProvider;
use OCP\Files\Config\IUserMountCache;
+use OCP\Files\Events\InvalidateMountCacheEvent;
use OCP\Files\Events\Node\FilesystemTornDownEvent;
use OCP\Files\Mount\IMountManager;
use OCP\Files\Mount\IMountPoint;
+use OCP\Files\NotFoundException;
use OCP\Files\Storage\IStorage;
+use OCP\Group\Events\UserAddedEvent;
+use OCP\Group\Events\UserRemovedEvent;
+use OCP\ICache;
+use OCP\ICacheFactory;
+use OCP\IConfig;
use OCP\IUser;
use OCP\IUserManager;
use OCP\IUserSession;
use OCP\Lockdown\ILockdownManager;
+use OCP\Share\Events\ShareCreatedEvent;
+use Psr\Log\LoggerInterface;
class SetupManager {
private bool $rootSetup = false;
@@ -57,11 +67,19 @@ class SetupManager {
private MountProviderCollection $mountProviderCollection;
private IMountManager $mountManager;
private IUserManager $userManager;
+ // List of users for which at least one mount is setup
private array $setupUsers = [];
+ // List of users for which all mounts are setup
+ private array $setupUsersComplete = [];
+ /** @var array<string, string[]> */
+ private array $setupUserMountProviders = [];
private IEventDispatcher $eventDispatcher;
private IUserMountCache $userMountCache;
private ILockdownManager $lockdownManager;
private IUserSession $userSession;
+ private ICache $cache;
+ private LoggerInterface $logger;
+ private IConfig $config;
private bool $listeningForProviders;
public function __construct(
@@ -72,7 +90,10 @@ class SetupManager {
IEventDispatcher $eventDispatcher,
IUserMountCache $userMountCache,
ILockdownManager $lockdownManager,
- IUserSession $userSession
+ IUserSession $userSession,
+ ICacheFactory $cacheFactory,
+ LoggerInterface $logger,
+ IConfig $config
) {
$this->eventLogger = $eventLogger;
$this->mountProviderCollection = $mountProviderCollection;
@@ -81,8 +102,21 @@ class SetupManager {
$this->eventDispatcher = $eventDispatcher;
$this->userMountCache = $userMountCache;
$this->lockdownManager = $lockdownManager;
+ $this->logger = $logger;
$this->userSession = $userSession;
+ $this->cache = $cacheFactory->createDistributed('setupmanager::');
$this->listeningForProviders = false;
+ $this->config = $config;
+
+ $this->setupListeners();
+ }
+
+ private function isSetupStarted(IUser $user): bool {
+ return in_array($user->getUID(), $this->setupUsers, true);
+ }
+
+ public function isSetupComplete(IUser $user): bool {
+ return in_array($user->getUID(), $this->setupUsersComplete, true);
}
private function setupBuiltinWrappers() {
@@ -159,15 +193,33 @@ class SetupManager {
* Setup the full filesystem for the specified user
*/
public function setupForUser(IUser $user): void {
- $this->setupRoot();
+ if ($this->isSetupComplete($user)) {
+ return;
+ }
+ $this->setupUsersComplete[] = $user->getUID();
+ if (!isset($this->setupUserMountProviders[$user->getUID()])) {
+ $this->setupUserMountProviders[$user->getUID()] = [];
+ }
+
+ $this->setupForUserWith($user, function () use ($user) {
+ $this->mountProviderCollection->addMountForUser($user, $this->mountManager, function (
+ IMountProvider $provider
+ ) use ($user) {
+ return !in_array(get_class($provider), $this->setupUserMountProviders[$user->getUID()]);
+ });
+ });
+ $this->afterUserFullySetup($user);
+ }
+
+ /**
+ * part of the user setup that is run only once per user
+ */
+ private function oneTimeUserSetup(IUser $user) {
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()]);
@@ -176,7 +228,7 @@ class SetupManager {
$userDir = '/' . $user->getUID() . '/files';
- Filesystem::init($user, $userDir);
+ Filesystem::initInternal($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
@@ -187,13 +239,6 @@ class SetupManager {
$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([]),
@@ -203,9 +248,51 @@ class SetupManager {
new NullStorage([]),
'/' . $user->getUID() . '/files'
));
+ $this->setupUsersComplete[] = $user->getUID();
+ }
+
+ $this->listenForNewMountProviders();
+ }
+
+ /**
+ * Final housekeeping after a user has been fully setup
+ */
+ private function afterUserFullySetup(IUser $user): void {
+ $userRoot = '/' . $user->getUID() . '/';
+ $mounts = $this->mountManager->getAll();
+ $mounts = array_filter($mounts, function (IMountPoint $mount) use ($userRoot) {
+ return strpos($mount->getMountPoint(), $userRoot) === 0;
+ });
+ $this->userMountCache->registerMounts($user, $mounts);
+
+ $cacheDuration = $this->config->getSystemValueInt('fs_mount_cache_duration', 5 * 60);
+ if ($cacheDuration > 0) {
+ $this->cache->set($user->getUID(), true, $cacheDuration);
+ }
+ }
+
+ /**
+ * @param IUser $user
+ * @param IMountPoint $mounts
+ * @return void
+ * @throws \OCP\HintException
+ * @throws \OC\ServerNotAvailableException
+ */
+ private function setupForUserWith(IUser $user, callable $mountCallback): void {
+ $this->setupRoot();
+
+ if (!$this->isSetupStarted($user)) {
+ $this->oneTimeUserSetup($user);
+ }
+
+ $this->eventLogger->start('setup_fs', 'Setup filesystem');
+
+ if ($this->lockdownManager->canAccessFilesystem()) {
+ $mountCallback();
}
\OC_Hook::emit('OC_Filesystem', 'post_initMountPoints', ['user' => $user->getUID()]);
+ $userDir = '/' . $user->getUID() . '/files';
OC_Hook::emit('OC_Filesystem', 'setup', ['user' => $user->getUID(), 'user_dir' => $userDir]);
$this->eventLogger->end('setup_fs');
@@ -240,35 +327,157 @@ class SetupManager {
}
/**
- * Set up the filesystem for the specified path
+ * Get the user to setup for a path or `null` if the root needs to be setup
+ *
+ * @param string $path
+ * @return IUser|null
*/
- public function setupForPath(string $path): void {
+ private function getUserForPath(string $path) {
if (substr_count($path, '/') < 2) {
if ($user = $this->userSession->getUser()) {
- $this->setupForUser($user);
+ return $user;
} else {
- $this->setupRoot();
+ return null;
}
- return;
} elseif (strpos($path, '/appdata_' . \OC_Util::getInstanceId()) === 0 || strpos($path, '/files_external/') === 0) {
- $this->setupRoot();
- return;
+ return null;
} else {
[, $userId] = explode('/', $path);
}
- $user = $this->userManager->get($userId);
+ return $this->userManager->get($userId);
+ }
+
+ /**
+ * Set up the filesystem for the specified path
+ */
+ public function setupForPath(string $path, bool $includeChildren = false): void {
+ $user = $this->getUserForPath($path);
+ if (!$user) {
+ $this->setupRoot();
+ return;
+ }
+
+ if ($this->isSetupComplete($user)) {
+ return;
+ }
+
+ if ($this->fullSetupRequired($user)) {
+ $this->setupForUser($user);
+ return;
+ }
+
+ if (!isset($this->setupUserMountProviders[$user->getUID()])) {
+ $this->setupUserMountProviders[$user->getUID()] = [];
+ }
+ $setupProviders = &$this->setupUserMountProviders[$user->getUID()];
+ $currentProviders = [];
+
+ try {
+ $cachedMount = $this->userMountCache->getMountForPath($user, $path);
+ } catch (NotFoundException $e) {
+ $this->setupForUser($user);
+ return;
+ }
+
+ $mounts = [];
+ if (!in_array($cachedMount->getMountProvider(), $setupProviders)) {
+ $setupProviders[] = $cachedMount->getMountProvider();
+ $currentProviders[] = $cachedMount->getMountProvider();
+ if ($cachedMount->getMountProvider()) {
+ $mounts = $this->mountProviderCollection->getUserMountsForProviderClasses($user, [$cachedMount->getMountProvider()]);
+ } else {
+ $this->logger->debug("mount at " . $cachedMount->getMountPoint() . " has no provider set, performing full setup");
+ $this->setupForUser($user);
+ return;
+ }
+ }
+ if ($includeChildren) {
+ $subCachedMounts = $this->userMountCache->getMountsInPath($user, $path);
+ foreach ($subCachedMounts as $cachedMount) {
+ if (!in_array($cachedMount->getMountProvider(), $setupProviders)) {
+ $setupProviders[] = $cachedMount->getMountProvider();
+ $currentProviders[] = $cachedMount->getMountProvider();
+ if ($cachedMount->getMountProvider()) {
+ $mounts = array_merge($mounts, $this->mountProviderCollection->getUserMountsForProviderClasses($user, [$cachedMount->getMountProvider()]));
+ } else {
+ $this->logger->debug("mount at " . $cachedMount->getMountPoint() . " has no provider set, performing full setup");
+ $this->setupForUser($user);
+ return;
+ }
+ }
+ }
+ }
+
+ if (count($mounts)) {
+ $this->userMountCache->registerMounts($user, $mounts, $currentProviders);
+ $this->setupForUserWith($user, function () use ($mounts) {
+ array_walk($mounts, [$this->mountManager, 'addMount']);
+ });
+ } elseif (!$this->isSetupStarted($user)) {
+ $this->oneTimeUserSetup($user);
+ }
+ }
+
+ private function fullSetupRequired(IUser $user): bool {
+ // we perform a "cached" setup only after having done the full setup recently
+ // this is also used to trigger a full setup after handling events that are likely
+ // to change the available mounts
+ return !$this->cache->get($user->getUID());
+ }
+
+ /**
+ * @param string $path
+ * @param string[] $providers
+ */
+ public function setupForProvider(string $path, array $providers): void {
+ $user = $this->getUserForPath($path);
if (!$user) {
$this->setupRoot();
return;
}
- $this->setupForUser($user);
+ if ($this->isSetupComplete($user)) {
+ return;
+ }
+
+ if ($this->fullSetupRequired($user)) {
+ $this->setupForUser($user);
+ return;
+ }
+
+ // home providers are always used
+ $providers = array_filter($providers, function (string $provider) {
+ return !is_subclass_of($provider, IHomeMountProvider::class);
+ });
+
+ if (in_array('', $providers)) {
+ $this->setupForUser($user);
+ }
+ $setupProviders = $this->setupUserMountProviders[$user->getUID()] ?? [];
+
+ $providers = array_diff($providers, $setupProviders);
+ if (count($providers) === 0) {
+ if (!$this->isSetupStarted($user)) {
+ $this->oneTimeUserSetup($user);
+ }
+ return;
+ } else {
+ $this->setupUserMountProviders[$user->getUID()] = array_merge($setupProviders, $providers);
+ $mounts = $this->mountProviderCollection->getUserMountsForProviderClasses($user, $providers);
+ }
+
+ $this->userMountCache->registerMounts($user, $mounts, $providers);
+ $this->setupForUserWith($user, function () use ($mounts) {
+ array_walk($mounts, [$this->mountManager, 'addMount']);
+ });
}
public function tearDown() {
$this->setupUsers = [];
+ $this->setupUsersComplete = [];
+ $this->setupUserMountProviders = [];
$this->rootSetup = false;
$this->mountManager->clear();
$this->eventDispatcher->dispatchTyped(new FilesystemTornDownEvent());
@@ -280,7 +489,9 @@ class SetupManager {
private function listenForNewMountProviders() {
if (!$this->listeningForProviders) {
$this->listeningForProviders = true;
- $this->mountProviderCollection->listen('\OC\Files\Config', 'registerMountProvider', function (IMountProvider $provider) {
+ $this->mountProviderCollection->listen('\OC\Files\Config', 'registerMountProvider', function (
+ IMountProvider $provider
+ ) {
foreach ($this->setupUsers as $userId) {
$user = $this->userManager->get($userId);
if ($user) {
@@ -291,4 +502,40 @@ class SetupManager {
});
}
}
+
+ private function setupListeners() {
+ // note that this event handling is intentionally pessimistic
+ // clearing the cache to often is better than not enough
+
+ $this->eventDispatcher->addListener(UserAddedEvent::class, function (UserAddedEvent $event) {
+ $this->cache->remove($event->getUser()->getUID());
+ });
+ $this->eventDispatcher->addListener(UserRemovedEvent::class, function (UserRemovedEvent $event) {
+ $this->cache->remove($event->getUser()->getUID());
+ });
+ $this->eventDispatcher->addListener(ShareCreatedEvent::class, function (ShareCreatedEvent $event) {
+ $this->cache->remove($event->getShare()->getSharedWith());
+ });
+ $this->eventDispatcher->addListener(InvalidateMountCacheEvent::class, function (InvalidateMountCacheEvent $event
+ ) {
+ if ($user = $event->getUser()) {
+ $this->cache->remove($user->getUID());
+ } else {
+ $this->cache->clear();
+ }
+ });
+
+ $genericEvents = [
+ '\OCA\Circles::onCircleCreation',
+ '\OCA\Circles::onCircleDestruction',
+ '\OCA\Circles::onMemberNew',
+ '\OCA\Circles::onMemberLeaving',
+ ];
+
+ foreach ($genericEvents as $genericEvent) {
+ $this->eventDispatcher->addListener($genericEvent, function ($event) {
+ $this->cache->clear();
+ });
+ }
+ }
}
diff --git a/lib/private/Files/SetupManagerFactory.php b/lib/private/Files/SetupManagerFactory.php
index 56e70d09961..1d9efbd411f 100644
--- a/lib/private/Files/SetupManagerFactory.php
+++ b/lib/private/Files/SetupManagerFactory.php
@@ -28,9 +28,12 @@ use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\Config\IMountProviderCollection;
use OCP\Files\Config\IUserMountCache;
use OCP\Files\Mount\IMountManager;
+use OCP\ICacheFactory;
+use OCP\IConfig;
use OCP\IUserManager;
use OCP\IUserSession;
use OCP\Lockdown\ILockdownManager;
+use Psr\Log\LoggerInterface;
class SetupManagerFactory {
private IEventLogger $eventLogger;
@@ -41,6 +44,9 @@ class SetupManagerFactory {
private ILockdownManager $lockdownManager;
private IUserSession $userSession;
private ?SetupManager $setupManager;
+ private ICacheFactory $cacheFactory;
+ private LoggerInterface $logger;
+ private IConfig $config;
public function __construct(
IEventLogger $eventLogger,
@@ -49,7 +55,10 @@ class SetupManagerFactory {
IEventDispatcher $eventDispatcher,
IUserMountCache $userMountCache,
ILockdownManager $lockdownManager,
- IUserSession $userSession
+ IUserSession $userSession,
+ ICacheFactory $cacheFactory,
+ LoggerInterface $logger,
+ IConfig $config
) {
$this->eventLogger = $eventLogger;
$this->mountProviderCollection = $mountProviderCollection;
@@ -58,6 +67,9 @@ class SetupManagerFactory {
$this->userMountCache = $userMountCache;
$this->lockdownManager = $lockdownManager;
$this->userSession = $userSession;
+ $this->cacheFactory = $cacheFactory;
+ $this->logger = $logger;
+ $this->config = $config;
$this->setupManager = null;
}
@@ -72,6 +84,9 @@ class SetupManagerFactory {
$this->userMountCache,
$this->lockdownManager,
$this->userSession,
+ $this->cacheFactory,
+ $this->logger,
+ $this->config
);
}
return $this->setupManager;
diff --git a/lib/private/Files/Storage/DAV.php b/lib/private/Files/Storage/DAV.php
index b4a85755b20..ee874d97b55 100644
--- a/lib/private/Files/Storage/DAV.php
+++ b/lib/private/Files/Storage/DAV.php
@@ -587,8 +587,8 @@ class DAV extends Common {
return false;
}
return [
- 'mtime' => strtotime($response['{DAV:}getlastmodified']),
- 'size' => (int)isset($response['{DAV:}getcontentlength']) ? $response['{DAV:}getcontentlength'] : 0,
+ 'mtime' => isset($response['{DAV:}getlastmodified']) ? strtotime($response['{DAV:}getlastmodified']) : null,
+ 'size' => (int)($response['{DAV:}getcontentlength'] ?? 0),
];
} catch (\Exception $e) {
$this->convertException($e, $path);
@@ -804,9 +804,12 @@ class DAV extends Common {
} else {
return false;
}
- } else {
+ } elseif (isset($response['{DAV:}getlastmodified'])) {
$remoteMtime = strtotime($response['{DAV:}getlastmodified']);
return $remoteMtime > $time;
+ } else {
+ // neither `getetag` nor `getlastmodified` is set
+ return false;
}
} catch (ClientHttpException $e) {
if ($e->getHttpStatus() === 405) {
diff --git a/lib/private/Files/Storage/Wrapper/Encryption.php b/lib/private/Files/Storage/Wrapper/Encryption.php
index 75611d1ab0f..4cfe932cc9f 100644
--- a/lib/private/Files/Storage/Wrapper/Encryption.php
+++ b/lib/private/Files/Storage/Wrapper/Encryption.php
@@ -50,7 +50,7 @@ use OCP\Encryption\Keys\IStorage;
use OCP\Files\Cache\ICacheEntry;
use OCP\Files\Mount\IMountPoint;
use OCP\Files\Storage;
-use OCP\ILogger;
+use Psr\Log\LoggerInterface;
class Encryption extends Wrapper {
use LocalTempFileTrait;
@@ -64,8 +64,7 @@ class Encryption extends Wrapper {
/** @var \OCP\Encryption\IManager */
private $encryptionManager;
- /** @var \OCP\ILogger */
- private $logger;
+ private LoggerInterface $logger;
/** @var string */
private $uid;
@@ -96,21 +95,12 @@ class Encryption extends Wrapper {
/**
* @param array $parameters
- * @param IManager $encryptionManager
- * @param Util $util
- * @param ILogger $logger
- * @param IFile $fileHelper
- * @param string $uid
- * @param IStorage $keyStorage
- * @param Update $update
- * @param Manager $mountManager
- * @param ArrayCache $arrayCache
*/
public function __construct(
$parameters,
IManager $encryptionManager = null,
Util $util = null,
- ILogger $logger = null,
+ LoggerInterface $logger = null,
IFile $fileHelper = null,
$uid = null,
IStorage $keyStorage = null,
@@ -448,9 +438,8 @@ class Encryption extends Wrapper {
}
}
} catch (ModuleDoesNotExistsException $e) {
- $this->logger->logException($e, [
- 'message' => 'Encryption module "' . $encryptionModuleId . '" not found, file will be stored unencrypted',
- 'level' => ILogger::WARN,
+ $this->logger->warning('Encryption module "' . $encryptionModuleId . '" not found, file will be stored unencrypted', [
+ 'exception' => $e,
'app' => 'core',
]);
}
@@ -503,8 +492,7 @@ class Encryption extends Wrapper {
try {
$result = $this->fixUnencryptedSize($path, $size, $unencryptedSize);
} catch (\Exception $e) {
- $this->logger->error('Couldn\'t re-calculate unencrypted size for ' . $path);
- $this->logger->logException($e);
+ $this->logger->error('Couldn\'t re-calculate unencrypted size for ' . $path, ['exception' => $e]);
}
unset($this->fixUnencryptedSizeOf[$this->getFullPath($path)]);
}
diff --git a/lib/private/Files/Type/Detection.php b/lib/private/Files/Type/Detection.php
index bd2bfb5f939..4cade024460 100644
--- a/lib/private/Files/Type/Detection.php
+++ b/lib/private/Files/Type/Detection.php
@@ -42,8 +42,8 @@ declare(strict_types=1);
namespace OC\Files\Type;
use OCP\Files\IMimeTypeDetector;
-use OCP\ILogger;
use OCP\IURLGenerator;
+use Psr\Log\LoggerInterface;
/**
* Class Detection
@@ -66,8 +66,7 @@ class Detection implements IMimeTypeDetector {
/** @var IURLGenerator */
private $urlGenerator;
- /** @var ILogger */
- private $logger;
+ private LoggerInterface $logger;
/** @var string */
private $customConfigDir;
@@ -75,14 +74,8 @@ class Detection implements IMimeTypeDetector {
/** @var string */
private $defaultConfigDir;
- /**
- * @param IURLGenerator $urlGenerator
- * @param ILogger $logger
- * @param string $customConfigDir
- * @param string $defaultConfigDir
- */
public function __construct(IURLGenerator $urlGenerator,
- ILogger $logger,
+ LoggerInterface $logger,
string $customConfigDir,
string $defaultConfigDir) {
$this->urlGenerator = $urlGenerator;
diff --git a/lib/private/Files/Utils/PathHelper.php b/lib/private/Files/Utils/PathHelper.php
new file mode 100644
index 00000000000..07985e884ce
--- /dev/null
+++ b/lib/private/Files/Utils/PathHelper.php
@@ -0,0 +1,71 @@
+<?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\Utils;
+
+class PathHelper {
+ /**
+ * Make a path relative to a root path, or return null if the path is outside the root
+ *
+ * @param string $root
+ * @param string $path
+ * @return ?string
+ */
+ public static function getRelativePath(string $root, string $path) {
+ if ($root === '' or $root === '/') {
+ return self::normalizePath($path);
+ }
+ if ($path === $root) {
+ return '/';
+ } elseif (strpos($path, $root . '/') !== 0) {
+ return null;
+ } else {
+ $path = substr($path, strlen($root));
+ return self::normalizePath($path);
+ }
+ }
+
+ /**
+ * @param string $path
+ * @return string
+ */
+ public static function normalizePath(string $path): string {
+ if ($path === '' or $path === '/') {
+ return '/';
+ }
+ //no windows style slashes
+ $path = str_replace('\\', '/', $path);
+ //add leading slash
+ if ($path[0] !== '/') {
+ $path = '/' . $path;
+ }
+ //remove duplicate slashes
+ while (strpos($path, '//') !== false) {
+ $path = str_replace('//', '/', $path);
+ }
+ //remove trailing slash
+ $path = rtrim($path, '/');
+
+ return $path;
+ }
+}
diff --git a/lib/private/Files/Utils/Scanner.php b/lib/private/Files/Utils/Scanner.php
index 5b633617608..dc220bc710d 100644
--- a/lib/private/Files/Utils/Scanner.php
+++ b/lib/private/Files/Utils/Scanner.php
@@ -48,7 +48,7 @@ use OCP\Files\NotFoundException;
use OCP\Files\Storage\IStorage;
use OCP\Files\StorageNotAvailableException;
use OCP\IDBConnection;
-use OCP\ILogger;
+use Psr\Log\LoggerInterface;
/**
* Class Scanner
@@ -71,8 +71,7 @@ class Scanner extends PublicEmitter {
/** @var IEventDispatcher */
private $dispatcher;
- /** @var ILogger */
- protected $logger;
+ protected LoggerInterface $logger;
/**
* Whether to use a DB transaction
@@ -92,9 +91,8 @@ class Scanner extends PublicEmitter {
* @param string $user
* @param IDBConnection|null $db
* @param IEventDispatcher $dispatcher
- * @param ILogger $logger
*/
- public function __construct($user, $db, IEventDispatcher $dispatcher, ILogger $logger) {
+ public function __construct($user, $db, IEventDispatcher $dispatcher, LoggerInterface $logger) {
$this->user = $user;
$this->db = $db;
$this->dispatcher = $dispatcher;
@@ -263,8 +261,7 @@ class Scanner extends PublicEmitter {
}
$propagator->commitBatch();
} catch (StorageNotAvailableException $e) {
- $this->logger->error('Storage ' . $storage->getId() . ' not available');
- $this->logger->logException($e);
+ $this->logger->error('Storage ' . $storage->getId() . ' not available', ['exception' => $e]);
$this->emit('\OC\Files\Utils\Scanner', 'StorageNotAvailable', [$e]);
}
if ($this->useTransaction) {
diff --git a/lib/private/Files/View.php b/lib/private/Files/View.php
index 779e0611591..e23dd4312aa 100644
--- a/lib/private/Files/View.php
+++ b/lib/private/Files/View.php
@@ -1099,6 +1099,7 @@ class View {
[Filesystem::signal_param_path => $this->getHookPath($path)]
);
}
+ /** @var Storage|null $storage */
[$storage, $internalPath] = Filesystem::resolvePath($absolutePath . $postFix);
if ($storage) {
return $storage->hash($type, $internalPath, $raw);
@@ -1179,7 +1180,7 @@ class View {
throw $e;
}
- if ($result && in_array('delete', $hooks) and $result) {
+ if ($result && in_array('delete', $hooks)) {
$this->removeUpdate($storage, $internalPath);
}
if ($result && in_array('write', $hooks, true) && $operation !== 'fopen' && $operation !== 'touch') {
@@ -1435,124 +1436,122 @@ class View {
if (!Filesystem::isValidPath($directory)) {
return [];
}
+
$path = $this->getAbsolutePath($directory);
$path = Filesystem::normalizePath($path);
$mount = $this->getMount($directory);
- if (!$mount) {
- return [];
- }
$storage = $mount->getStorage();
$internalPath = $mount->getInternalPath($path);
- if ($storage) {
- $cache = $storage->getCache($internalPath);
- $user = \OC_User::getUser();
+ if (!$storage) {
+ return [];
+ }
- $data = $this->getCacheEntry($storage, $internalPath, $directory);
+ $cache = $storage->getCache($internalPath);
+ $user = \OC_User::getUser();
- if (!$data instanceof ICacheEntry || !isset($data['fileid']) || !($data->getPermissions() && Constants::PERMISSION_READ)) {
- return [];
- }
+ $data = $this->getCacheEntry($storage, $internalPath, $directory);
- $folderId = $data['fileid'];
- $contents = $cache->getFolderContentsById($folderId); //TODO: mimetype_filter
+ if (!$data instanceof ICacheEntry || !isset($data['fileid']) || !($data->getPermissions() & Constants::PERMISSION_READ)) {
+ return [];
+ }
- $sharingDisabled = \OCP\Util::isSharingDisabledForUser();
+ $folderId = $data['fileid'];
+ $contents = $cache->getFolderContentsById($folderId); //TODO: mimetype_filter
- $fileNames = array_map(function (ICacheEntry $content) {
- return $content->getName();
- }, $contents);
- /**
- * @var \OC\Files\FileInfo[] $fileInfos
- */
- $fileInfos = array_map(function (ICacheEntry $content) use ($path, $storage, $mount, $sharingDisabled) {
- if ($sharingDisabled) {
- $content['permissions'] = $content['permissions'] & ~\OCP\Constants::PERMISSION_SHARE;
- }
- $owner = $this->getUserObjectForOwner($storage->getOwner($content['path']));
- return new FileInfo($path . '/' . $content['name'], $storage, $content['path'], $content, $mount, $owner);
- }, $contents);
- $files = array_combine($fileNames, $fileInfos);
-
- //add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders
- $mounts = Filesystem::getMountManager()->findIn($path);
- $dirLength = strlen($path);
- foreach ($mounts as $mount) {
- $mountPoint = $mount->getMountPoint();
- $subStorage = $mount->getStorage();
- if ($subStorage) {
- $subCache = $subStorage->getCache('');
+ $sharingDisabled = \OCP\Util::isSharingDisabledForUser();
- $rootEntry = $subCache->get('');
- if (!$rootEntry) {
- $subScanner = $subStorage->getScanner();
- try {
- $subScanner->scanFile('');
- } catch (\OCP\Files\StorageNotAvailableException $e) {
- continue;
- } catch (\OCP\Files\StorageInvalidException $e) {
- continue;
- } catch (\Exception $e) {
- // sometimes when the storage is not available it can be any exception
- \OC::$server->getLogger()->logException($e, [
- 'message' => 'Exception while scanning storage "' . $subStorage->getId() . '"',
- 'level' => ILogger::ERROR,
- 'app' => 'lib',
- ]);
- continue;
- }
- $rootEntry = $subCache->get('');
+ $fileNames = array_map(function (ICacheEntry $content) {
+ return $content->getName();
+ }, $contents);
+ /**
+ * @var \OC\Files\FileInfo[] $fileInfos
+ */
+ $fileInfos = array_map(function (ICacheEntry $content) use ($path, $storage, $mount, $sharingDisabled) {
+ if ($sharingDisabled) {
+ $content['permissions'] = $content['permissions'] & ~\OCP\Constants::PERMISSION_SHARE;
+ }
+ $owner = $this->getUserObjectForOwner($storage->getOwner($content['path']));
+ return new FileInfo($path . '/' . $content['name'], $storage, $content['path'], $content, $mount, $owner);
+ }, $contents);
+ $files = array_combine($fileNames, $fileInfos);
+
+ //add a folder for any mountpoint in this directory and add the sizes of other mountpoints to the folders
+ $mounts = Filesystem::getMountManager()->findIn($path);
+ $dirLength = strlen($path);
+ foreach ($mounts as $mount) {
+ $mountPoint = $mount->getMountPoint();
+ $subStorage = $mount->getStorage();
+ if ($subStorage) {
+ $subCache = $subStorage->getCache('');
+
+ $rootEntry = $subCache->get('');
+ if (!$rootEntry) {
+ $subScanner = $subStorage->getScanner();
+ try {
+ $subScanner->scanFile('');
+ } catch (\OCP\Files\StorageNotAvailableException $e) {
+ continue;
+ } catch (\OCP\Files\StorageInvalidException $e) {
+ continue;
+ } catch (\Exception $e) {
+ // sometimes when the storage is not available it can be any exception
+ \OC::$server->getLogger()->logException($e, [
+ 'message' => 'Exception while scanning storage "' . $subStorage->getId() . '"',
+ 'level' => ILogger::ERROR,
+ 'app' => 'lib',
+ ]);
+ continue;
}
+ $rootEntry = $subCache->get('');
+ }
- if ($rootEntry && ($rootEntry->getPermissions() && Constants::PERMISSION_READ)) {
- $relativePath = trim(substr($mountPoint, $dirLength), '/');
- if ($pos = strpos($relativePath, '/')) {
- //mountpoint inside subfolder add size to the correct folder
- $entryName = substr($relativePath, 0, $pos);
- foreach ($files as &$entry) {
- if ($entry->getName() === $entryName) {
- $entry->addSubEntry($rootEntry, $mountPoint);
- }
+ if ($rootEntry && ($rootEntry->getPermissions() & Constants::PERMISSION_READ)) {
+ $relativePath = trim(substr($mountPoint, $dirLength), '/');
+ if ($pos = strpos($relativePath, '/')) {
+ //mountpoint inside subfolder add size to the correct folder
+ $entryName = substr($relativePath, 0, $pos);
+ foreach ($files as &$entry) {
+ if ($entry->getName() === $entryName) {
+ $entry->addSubEntry($rootEntry, $mountPoint);
}
- } else { //mountpoint in this folder, add an entry for it
- $rootEntry['name'] = $relativePath;
- $rootEntry['type'] = $rootEntry['mimetype'] === 'httpd/unix-directory' ? 'dir' : 'file';
- $permissions = $rootEntry['permissions'];
- // do not allow renaming/deleting the mount point if they are not shared files/folders
- // for shared files/folders we use the permissions given by the owner
- if ($mount instanceof MoveableMount) {
- $rootEntry['permissions'] = $permissions | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE;
- } else {
- $rootEntry['permissions'] = $permissions & (\OCP\Constants::PERMISSION_ALL - (\OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE));
- }
-
- $rootEntry['path'] = substr(Filesystem::normalizePath($path . '/' . $rootEntry['name']), strlen($user) + 2); // full path without /$user/
+ }
+ } else { //mountpoint in this folder, add an entry for it
+ $rootEntry['name'] = $relativePath;
+ $rootEntry['type'] = $rootEntry['mimetype'] === 'httpd/unix-directory' ? 'dir' : 'file';
+ $permissions = $rootEntry['permissions'];
+ // do not allow renaming/deleting the mount point if they are not shared files/folders
+ // for shared files/folders we use the permissions given by the owner
+ if ($mount instanceof MoveableMount) {
+ $rootEntry['permissions'] = $permissions | \OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE;
+ } else {
+ $rootEntry['permissions'] = $permissions & (\OCP\Constants::PERMISSION_ALL - (\OCP\Constants::PERMISSION_UPDATE | \OCP\Constants::PERMISSION_DELETE));
+ }
- // if sharing was disabled for the user we remove the share permissions
- if (\OCP\Util::isSharingDisabledForUser()) {
- $rootEntry['permissions'] = $rootEntry['permissions'] & ~\OCP\Constants::PERMISSION_SHARE;
- }
+ $rootEntry['path'] = substr(Filesystem::normalizePath($path . '/' . $rootEntry['name']), strlen($user) + 2); // full path without /$user/
- $owner = $this->getUserObjectForOwner($subStorage->getOwner(''));
- $files[$rootEntry->getName()] = new FileInfo($path . '/' . $rootEntry['name'], $subStorage, '', $rootEntry, $mount, $owner);
+ // if sharing was disabled for the user we remove the share permissions
+ if (\OCP\Util::isSharingDisabledForUser()) {
+ $rootEntry['permissions'] = $rootEntry['permissions'] & ~\OCP\Constants::PERMISSION_SHARE;
}
- }
- }
- }
- if ($mimetype_filter) {
- $files = array_filter($files, function (FileInfo $file) use ($mimetype_filter) {
- if (strpos($mimetype_filter, '/')) {
- return $file->getMimetype() === $mimetype_filter;
- } else {
- return $file->getMimePart() === $mimetype_filter;
+ $owner = $this->getUserObjectForOwner($subStorage->getOwner(''));
+ $files[$rootEntry->getName()] = new FileInfo($path . '/' . $rootEntry['name'], $subStorage, '', $rootEntry, $mount, $owner);
}
- });
+ }
}
+ }
- return array_values($files);
- } else {
- return [];
+ if ($mimetype_filter) {
+ $files = array_filter($files, function (FileInfo $file) use ($mimetype_filter) {
+ if (strpos($mimetype_filter, '/')) {
+ return $file->getMimetype() === $mimetype_filter;
+ } else {
+ return $file->getMimePart() === $mimetype_filter;
+ }
+ });
}
+
+ return array_values($files);
}
/**
diff --git a/lib/private/Group/Group.php b/lib/private/Group/Group.php
index 9a9996f7f60..2ef4d2ee23f 100644
--- a/lib/private/Group/Group.php
+++ b/lib/private/Group/Group.php
@@ -354,8 +354,7 @@ class Group implements IGroup {
}
foreach ($this->backends as $backend) {
if ($backend->implementsActions(\OC\Group\Backend::DELETE_GROUP)) {
- $result = true;
- $backend->deleteGroup($this->gid);
+ $result = $result || $backend->deleteGroup($this->gid);
}
}
if ($result) {
diff --git a/lib/private/Group/Manager.php b/lib/private/Group/Manager.php
index e1bd009e79c..28f7a400b41 100644
--- a/lib/private/Group/Manager.php
+++ b/lib/private/Group/Manager.php
@@ -44,8 +44,8 @@ use OCP\EventDispatcher\IEventDispatcher;
use OCP\GroupInterface;
use OCP\IGroup;
use OCP\IGroupManager;
-use OCP\ILogger;
use OCP\IUser;
+use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
@@ -71,8 +71,7 @@ class Manager extends PublicEmitter implements IGroupManager {
private $userManager;
/** @var EventDispatcherInterface */
private $dispatcher;
- /** @var ILogger */
- private $logger;
+ private LoggerInterface $logger;
/** @var \OC\Group\Group[] */
private $cachedGroups = [];
@@ -83,14 +82,9 @@ class Manager extends PublicEmitter implements IGroupManager {
/** @var \OC\SubAdmin */
private $subAdmin = null;
- /**
- * @param \OC\User\Manager $userManager
- * @param EventDispatcherInterface $dispatcher
- * @param ILogger $logger
- */
public function __construct(\OC\User\Manager $userManager,
EventDispatcherInterface $dispatcher,
- ILogger $logger) {
+ LoggerInterface $logger) {
$this->userManager = $userManager;
$this->dispatcher = $dispatcher;
$this->logger = $logger;
diff --git a/lib/private/Http/Client/Client.php b/lib/private/Http/Client/Client.php
index 673f566e354..3ba85a2dd9f 100644
--- a/lib/private/Http/Client/Client.php
+++ b/lib/private/Http/Client/Client.php
@@ -39,7 +39,6 @@ use OCP\Http\Client\IClient;
use OCP\Http\Client\IResponse;
use OCP\ICertificateManager;
use OCP\IConfig;
-use OCP\ILogger;
/**
* Class Client
@@ -51,8 +50,6 @@ class Client implements IClient {
private $client;
/** @var IConfig */
private $config;
- /** @var ILogger */
- private $logger;
/** @var ICertificateManager */
private $certificateManager;
/** @var LocalAddressChecker */
@@ -60,13 +57,11 @@ class Client implements IClient {
public function __construct(
IConfig $config,
- ILogger $logger,
ICertificateManager $certificateManager,
GuzzleClient $client,
LocalAddressChecker $localAddressChecker
) {
$this->config = $config;
- $this->logger = $logger;
$this->client = $client;
$this->certificateManager = $certificateManager;
$this->localAddressChecker = $localAddressChecker;
diff --git a/lib/private/Http/Client/ClientService.php b/lib/private/Http/Client/ClientService.php
index d1aed2d7883..e868d4af7a5 100644
--- a/lib/private/Http/Client/ClientService.php
+++ b/lib/private/Http/Client/ClientService.php
@@ -33,7 +33,6 @@ use OCP\Http\Client\IClient;
use OCP\Http\Client\IClientService;
use OCP\ICertificateManager;
use OCP\IConfig;
-use OCP\ILogger;
/**
* Class ClientService
@@ -43,8 +42,6 @@ use OCP\ILogger;
class ClientService implements IClientService {
/** @var IConfig */
private $config;
- /** @var ILogger */
- private $logger;
/** @var ICertificateManager */
private $certificateManager;
/** @var DnsPinMiddleware */
@@ -53,12 +50,10 @@ class ClientService implements IClientService {
private $localAddressChecker;
public function __construct(IConfig $config,
- ILogger $logger,
ICertificateManager $certificateManager,
DnsPinMiddleware $dnsPinMiddleware,
LocalAddressChecker $localAddressChecker) {
$this->config = $config;
- $this->logger = $logger;
$this->certificateManager = $certificateManager;
$this->dnsPinMiddleware = $dnsPinMiddleware;
$this->localAddressChecker = $localAddressChecker;
@@ -76,7 +71,6 @@ class ClientService implements IClientService {
return new Client(
$this->config,
- $this->logger,
$this->certificateManager,
$client,
$this->localAddressChecker
diff --git a/lib/private/Http/Client/LocalAddressChecker.php b/lib/private/Http/Client/LocalAddressChecker.php
index c534c5971d1..2789b1b5935 100644
--- a/lib/private/Http/Client/LocalAddressChecker.php
+++ b/lib/private/Http/Client/LocalAddressChecker.php
@@ -25,14 +25,13 @@ declare(strict_types=1);
*/
namespace OC\Http\Client;
-use OCP\ILogger;
use OCP\Http\Client\LocalServerException;
+use Psr\Log\LoggerInterface;
class LocalAddressChecker {
- /** @var ILogger */
- private $logger;
+ private LoggerInterface $logger;
- public function __construct(ILogger $logger) {
+ public function __construct(LoggerInterface $logger) {
$this->logger = $logger;
}
diff --git a/lib/private/Lock/DBLockingProvider.php b/lib/private/Lock/DBLockingProvider.php
index 1ea78d047d2..5eb03ad856b 100644
--- a/lib/private/Lock/DBLockingProvider.php
+++ b/lib/private/Lock/DBLockingProvider.php
@@ -31,9 +31,9 @@ use OC\DB\QueryBuilder\Literal;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
-use OCP\ILogger;
use OCP\Lock\ILockingProvider;
use OCP\Lock\LockedException;
+use Psr\Log\LoggerInterface;
/**
* Locking provider that stores the locks in the database
@@ -44,10 +44,7 @@ class DBLockingProvider extends AbstractLockingProvider {
*/
private $connection;
- /**
- * @var \OCP\ILogger
- */
- private $logger;
+ private LoggerInterface $logger;
/**
* @var \OCP\AppFramework\Utility\ITimeFactory
@@ -104,15 +101,11 @@ class DBLockingProvider extends AbstractLockingProvider {
}
/**
- * @param \OCP\IDBConnection $connection
- * @param \OCP\ILogger $logger
- * @param \OCP\AppFramework\Utility\ITimeFactory $timeFactory
- * @param int $ttl
* @param bool $cacheSharedLocks
*/
public function __construct(
IDBConnection $connection,
- ILogger $logger,
+ LoggerInterface $logger,
ITimeFactory $timeFactory,
int $ttl = 3600,
$cacheSharedLocks = true
diff --git a/lib/private/Mail/Mailer.php b/lib/private/Mail/Mailer.php
index 61f506d2676..2f3480498be 100644
--- a/lib/private/Mail/Mailer.php
+++ b/lib/private/Mail/Mailer.php
@@ -41,7 +41,6 @@ use OCP\Defaults;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\IConfig;
use OCP\IL10N;
-use OCP\ILogger;
use OCP\IURLGenerator;
use OCP\L10N\IFactory;
use OCP\Mail\Events\BeforeMessageSent;
@@ -49,6 +48,7 @@ use OCP\Mail\IAttachment;
use OCP\Mail\IEMailTemplate;
use OCP\Mail\IMailer;
use OCP\Mail\IMessage;
+use Psr\Log\LoggerInterface;
/**
* Class Mailer provides some basic functions to create a mail message that can be used in combination with
@@ -73,8 +73,7 @@ class Mailer implements IMailer {
private $instance = null;
/** @var IConfig */
private $config;
- /** @var ILogger */
- private $logger;
+ private LoggerInterface $logger;
/** @var Defaults */
private $defaults;
/** @var IURLGenerator */
@@ -86,16 +85,8 @@ class Mailer implements IMailer {
/** @var IFactory */
private $l10nFactory;
- /**
- * @param IConfig $config
- * @param ILogger $logger
- * @param Defaults $defaults
- * @param IURLGenerator $urlGenerator
- * @param IL10N $l10n
- * @param IEventDispatcher $dispatcher
- */
public function __construct(IConfig $config,
- ILogger $logger,
+ LoggerInterface $logger,
Defaults $defaults,
IURLGenerator $urlGenerator,
IL10N $l10n,
diff --git a/lib/private/Memcache/APCu.php b/lib/private/Memcache/APCu.php
index 56345890bf2..f0eb98b9db2 100644
--- a/lib/private/Memcache/APCu.php
+++ b/lib/private/Memcache/APCu.php
@@ -148,10 +148,7 @@ class APCu extends Cache implements IMemcache {
}
}
- /**
- * @return bool
- */
- public static function isAvailable() {
+ public static function isAvailable(): bool {
if (!extension_loaded('apcu')) {
return false;
} elseif (!\OC::$server->get(IniGetWrapper::class)->getBool('apc.enabled')) {
diff --git a/lib/private/Memcache/ArrayCache.php b/lib/private/Memcache/ArrayCache.php
index b89aff0b7ed..13597a068b3 100644
--- a/lib/private/Memcache/ArrayCache.php
+++ b/lib/private/Memcache/ArrayCache.php
@@ -153,7 +153,7 @@ class ArrayCache extends Cache implements IMemcache {
/**
* {@inheritDoc}
*/
- public static function isAvailable() {
+ public static function isAvailable(): bool {
return true;
}
}
diff --git a/lib/private/Memcache/Factory.php b/lib/private/Memcache/Factory.php
index 7791c4beae9..604f764c03c 100644
--- a/lib/private/Memcache/Factory.php
+++ b/lib/private/Memcache/Factory.php
@@ -31,52 +31,48 @@
*/
namespace OC\Memcache;
+use OCP\Profiler\IProfiler;
use OCP\ICache;
use OCP\ICacheFactory;
-use OCP\ILogger;
use OCP\IMemcache;
+use Psr\Log\LoggerInterface;
class Factory implements ICacheFactory {
public const NULL_CACHE = NullCache::class;
- /**
- * @var string $globalPrefix
- */
- private $globalPrefix;
+ private string $globalPrefix;
- /**
- * @var ILogger $logger
- */
- private $logger;
+ private LoggerInterface $logger;
/**
- * @var string $localCacheClass
+ * @var ?class-string<ICache> $localCacheClass
*/
- private $localCacheClass;
+ private ?string $localCacheClass;
/**
- * @var string $distributedCacheClass
+ * @var ?class-string<ICache> $distributedCacheClass
*/
- private $distributedCacheClass;
+ private ?string $distributedCacheClass;
/**
- * @var string $lockingCacheClass
+ * @var ?class-string<IMemcache> $lockingCacheClass
*/
- private $lockingCacheClass;
+ private ?string $lockingCacheClass;
- /** @var string */
- private $logFile;
+ private string $logFile;
+
+ private IProfiler $profiler;
/**
* @param string $globalPrefix
- * @param ILogger $logger
- * @param string|null $localCacheClass
- * @param string|null $distributedCacheClass
- * @param string|null $lockingCacheClass
+ * @param LoggerInterface $logger
+ * @param ?class-string<ICache> $localCacheClass
+ * @param ?class-string<ICache> $distributedCacheClass
+ * @param ?class-string<IMemcache> $lockingCacheClass
* @param string $logFile
*/
- public function __construct(string $globalPrefix, ILogger $logger,
- $localCacheClass = null, $distributedCacheClass = null, $lockingCacheClass = null, string $logFile = '') {
+ public function __construct(string $globalPrefix, LoggerInterface $logger, IProfiler $profiler,
+ ?string $localCacheClass = null, ?string $distributedCacheClass = null, ?string $lockingCacheClass = null, string $logFile = '') {
$this->logger = $logger;
$this->logFile = $logFile;
$this->globalPrefix = $globalPrefix;
@@ -108,6 +104,7 @@ class Factory implements ICacheFactory {
$this->localCacheClass = $localCacheClass;
$this->distributedCacheClass = $distributedCacheClass;
$this->lockingCacheClass = $lockingCacheClass;
+ $this->profiler = $profiler;
}
/**
@@ -117,7 +114,19 @@ class Factory implements ICacheFactory {
* @return IMemcache
*/
public function createLocking(string $prefix = ''): IMemcache {
- return new $this->lockingCacheClass($this->globalPrefix . '/' . $prefix, $this->logFile);
+ assert($this->lockingCacheClass !== null);
+ $cache = new $this->lockingCacheClass($this->globalPrefix . '/' . $prefix);
+ if ($this->profiler->isEnabled() && $this->lockingCacheClass === '\OC\Memcache\Redis') {
+ // We only support the profiler with Redis
+ $cache = new ProfilerWrapperCache($cache, 'Locking');
+ $this->profiler->add($cache);
+ }
+
+ if ($this->lockingCacheClass === Redis::class &&
+ $this->logFile !== '' && is_writable(dirname($this->logFile)) && (!file_exists($this->logFile) || is_writable($this->logFile))) {
+ $cache = new LoggerWrapperCache($cache, $this->logFile);
+ }
+ return $cache;
}
/**
@@ -127,7 +136,19 @@ class Factory implements ICacheFactory {
* @return ICache
*/
public function createDistributed(string $prefix = ''): ICache {
- return new $this->distributedCacheClass($this->globalPrefix . '/' . $prefix, $this->logFile);
+ assert($this->distributedCacheClass !== null);
+ $cache = new $this->distributedCacheClass($this->globalPrefix . '/' . $prefix);
+ if ($this->profiler->isEnabled() && $this->distributedCacheClass === '\OC\Memcache\Redis') {
+ // We only support the profiler with Redis
+ $cache = new ProfilerWrapperCache($cache, 'Distributed');
+ $this->profiler->add($cache);
+ }
+
+ if ($this->distributedCacheClass === Redis::class && $this->logFile !== ''
+ && is_writable(dirname($this->logFile)) && (!file_exists($this->logFile) || is_writable($this->logFile))) {
+ $cache = new LoggerWrapperCache($cache, $this->logFile);
+ }
+ return $cache;
}
/**
@@ -137,7 +158,19 @@ class Factory implements ICacheFactory {
* @return ICache
*/
public function createLocal(string $prefix = ''): ICache {
- return new $this->localCacheClass($this->globalPrefix . '/' . $prefix, $this->logFile);
+ assert($this->localCacheClass !== null);
+ $cache = new $this->localCacheClass($this->globalPrefix . '/' . $prefix);
+ if ($this->profiler->isEnabled() && $this->localCacheClass === '\OC\Memcache\Redis') {
+ // We only support the profiler with Redis
+ $cache = new ProfilerWrapperCache($cache, 'Local');
+ $this->profiler->add($cache);
+ }
+
+ if ($this->localCacheClass === Redis::class && $this->logFile !== ''
+ && is_writable(dirname($this->logFile)) && (!file_exists($this->logFile) || is_writable($this->logFile))) {
+ $cache = new LoggerWrapperCache($cache, $this->logFile);
+ }
+ return $cache;
}
/**
diff --git a/lib/private/Memcache/LoggerWrapperCache.php b/lib/private/Memcache/LoggerWrapperCache.php
new file mode 100644
index 00000000000..55c0e76db79
--- /dev/null
+++ b/lib/private/Memcache/LoggerWrapperCache.php
@@ -0,0 +1,177 @@
+<?php
+
+declare(strict_types = 1);
+/**
+ * @copyright 2022 Carl Schwan <carl@carlschwan.eu>
+ *
+ * @author Carl Schwan <carl@carlschwan.eu>
+ *
+ * @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\Memcache;
+
+use OCP\IMemcacheTTL;
+
+/**
+ * Cache wrapper that logs the cache operation in a log file
+ */
+class LoggerWrapperCache extends Cache implements IMemcacheTTL {
+ /** @var Redis */
+ protected $wrappedCache;
+
+ /** @var string $logFile */
+ private $logFile;
+
+ /** @var string $prefix */
+ protected $prefix;
+
+ public function __construct(Redis $wrappedCache, string $logFile) {
+ parent::__construct($wrappedCache->getPrefix());
+ $this->wrappedCache = $wrappedCache;
+ $this->logFile = $logFile;
+ }
+
+ /**
+ * @return string Prefix used for caching purposes
+ */
+ public function getPrefix() {
+ return $this->prefix;
+ }
+
+ protected function getNameSpace() {
+ return $this->prefix;
+ }
+
+ /** @inheritDoc */
+ public function get($key) {
+ file_put_contents(
+ $this->logFile,
+ $this->getNameSpace() . '::get::' . $key . "\n",
+ FILE_APPEND
+ );
+ return $this->wrappedCache->get($key);
+ }
+
+ /** @inheritDoc */
+ public function set($key, $value, $ttl = 0) {
+ file_put_contents(
+ $this->logFile,
+ $this->getNameSpace() . '::set::' . $key . '::' . $ttl . '::' . json_encode($value) . "\n",
+ FILE_APPEND
+ );
+
+ return $this->wrappedCache->set($key, $value, $$ttl);
+ }
+
+ /** @inheritDoc */
+ public function hasKey($key) {
+ file_put_contents(
+ $this->logFile,
+ $this->getNameSpace() . '::hasKey::' . $key . "\n",
+ FILE_APPEND
+ );
+
+ return $this->wrappedCache->hasKey($key);
+ }
+
+ /** @inheritDoc */
+ public function remove($key) {
+ file_put_contents(
+ $this->logFile,
+ $this->getNameSpace() . '::remove::' . $key . "\n",
+ FILE_APPEND
+ );
+
+ return $this->wrappedCache->remove($key);
+ }
+
+ /** @inheritDoc */
+ public function clear($prefix = '') {
+ file_put_contents(
+ $this->logFile,
+ $this->getNameSpace() . '::clear::' . $prefix . "\n",
+ FILE_APPEND
+ );
+
+ return $this->wrappedCache->clear($prefix);
+ }
+
+ /** @inheritDoc */
+ public function add($key, $value, $ttl = 0) {
+ file_put_contents(
+ $this->logFile,
+ $this->getNameSpace() . '::add::' . $key . '::' . $value . "\n",
+ FILE_APPEND
+ );
+
+ return $this->wrappedCache->add($key, $value, $ttl);
+ }
+
+ /** @inheritDoc */
+ public function inc($key, $step = 1) {
+ file_put_contents(
+ $this->logFile,
+ $this->getNameSpace() . '::inc::' . $key . "\n",
+ FILE_APPEND
+ );
+
+ return $this->wrappedCache->inc($key, $step);
+ }
+
+ /** @inheritDoc */
+ public function dec($key, $step = 1) {
+ file_put_contents(
+ $this->logFile,
+ $this->getNameSpace() . '::dec::' . $key . "\n",
+ FILE_APPEND
+ );
+
+ return $this->wrappedCache->dec($key, $step);
+ }
+
+ /** @inheritDoc */
+ public function cas($key, $old, $new) {
+ file_put_contents(
+ $this->logFile,
+ $this->getNameSpace() . '::cas::' . $key . "\n",
+ FILE_APPEND
+ );
+
+ return $this->wrappedCache->cas($key, $old, $new);
+ }
+
+ /** @inheritDoc */
+ public function cad($key, $old) {
+ file_put_contents(
+ $this->logFile,
+ $this->getNameSpace() . '::cad::' . $key . "\n",
+ FILE_APPEND
+ );
+
+ return $this->wrappedCache->cad($key, $old);
+ }
+
+ /** @inheritDoc */
+ public function setTTL($key, $ttl) {
+ $this->wrappedCache->setTTL($key, $ttl);
+ }
+
+ public static function isAvailable(): bool {
+ return true;
+ }
+}
diff --git a/lib/private/Memcache/Memcached.php b/lib/private/Memcache/Memcached.php
index f78be581d63..db4aa7ba9cc 100644
--- a/lib/private/Memcache/Memcached.php
+++ b/lib/private/Memcache/Memcached.php
@@ -196,7 +196,7 @@ class Memcached extends Cache implements IMemcache {
return $result;
}
- public static function isAvailable() {
+ public static function isAvailable(): bool {
return extension_loaded('memcached');
}
diff --git a/lib/private/Memcache/NullCache.php b/lib/private/Memcache/NullCache.php
index 7b56ec932f4..fc41595dfe1 100644
--- a/lib/private/Memcache/NullCache.php
+++ b/lib/private/Memcache/NullCache.php
@@ -67,7 +67,7 @@ class NullCache extends Cache implements \OCP\IMemcache {
return true;
}
- public static function isAvailable() {
+ public static function isAvailable(): bool {
return true;
}
}
diff --git a/lib/private/Memcache/ProfilerWrapperCache.php b/lib/private/Memcache/ProfilerWrapperCache.php
new file mode 100644
index 00000000000..8e9b160ba0e
--- /dev/null
+++ b/lib/private/Memcache/ProfilerWrapperCache.php
@@ -0,0 +1,220 @@
+<?php
+
+declare(strict_types = 1);
+/**
+ * @copyright 2022 Carl Schwan <carl@carlschwan.eu>
+ *
+ * @author Carl Schwan <carl@carlschwan.eu>
+ *
+ * @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\Memcache;
+
+use OC\AppFramework\Http\Request;
+use OCP\AppFramework\Http\Response;
+use OCP\DataCollector\AbstractDataCollector;
+use OCP\IMemcacheTTL;
+
+/**
+ * Cache wrapper that logs profiling information
+ */
+class ProfilerWrapperCache extends AbstractDataCollector implements IMemcacheTTL, \ArrayAccess {
+ /** @var Redis $wrappedCache*/
+ protected $wrappedCache;
+
+ /** @var string $prefix */
+ protected $prefix;
+
+ /** @var string $type */
+ private $type;
+
+ public function __construct(Redis $wrappedCache, string $type) {
+ $this->prefix = $wrappedCache->getPrefix();
+ $this->wrappedCache = $wrappedCache;
+ $this->type = $type;
+ $this->data['queries'] = [];
+ $this->data['cacheHit'] = 0;
+ $this->data['cacheMiss'] = 0;
+ }
+
+ public function getPrefix(): string {
+ return $this->prefix;
+ }
+
+ /** @inheritDoc */
+ public function get($key) {
+ $start = microtime(true);
+ $ret = $this->wrappedCache->get($key);
+ if ($ret === null) {
+ $this->data['cacheMiss']++;
+ } else {
+ $this->data['cacheHit']++;
+ }
+ $this->data['queries'][] = [
+ 'start' => $start,
+ 'end' => microtime(true),
+ 'op' => $this->getPrefix() . '::get::' . $key,
+ ];
+ return $ret;
+ }
+
+ /** @inheritDoc */
+ public function set($key, $value, $ttl = 0) {
+ $start = microtime(true);
+ $ret = $this->wrappedCache->set($key, $value, $ttl);
+ $this->data['queries'][] = [
+ 'start' => $start,
+ 'end' => microtime(true),
+ 'op' => $this->getPrefix() . '::set::' . $key,
+ ];
+ return $ret;
+ }
+
+ /** @inheritDoc */
+ public function hasKey($key) {
+ $start = microtime(true);
+ $ret = $this->wrappedCache->hasKey($key);
+ $this->data['queries'][] = [
+ 'start' => $start,
+ 'end' => microtime(true),
+ 'op' => $this->getPrefix() . '::hasKey::' . $key,
+ ];
+ return $ret;
+ }
+
+ /** @inheritDoc */
+ public function remove($key) {
+ $start = microtime(true);
+ $ret = $this->wrappedCache->remove($key);
+ $this->data['queries'][] = [
+ 'start' => $start,
+ 'end' => microtime(true),
+ 'op' => $this->getPrefix() . '::remove::' . $key,
+ ];
+ return $ret;
+ }
+
+ /** @inheritDoc */
+ public function clear($prefix = '') {
+ $start = microtime(true);
+ $ret = $this->wrappedCache->clear($prefix);
+ $this->data['queries'][] = [
+ 'start' => $start,
+ 'end' => microtime(true),
+ 'op' => $this->getPrefix() . '::clear::' . $prefix,
+ ];
+ return $ret;
+ }
+
+ /** @inheritDoc */
+ public function add($key, $value, $ttl = 0) {
+ $start = microtime(true);
+ $ret = $this->wrappedCache->add($key, $value, $ttl);
+ $this->data['queries'][] = [
+ 'start' => $start,
+ 'end' => microtime(true),
+ 'op' => $this->getPrefix() . '::add::' . $key,
+ ];
+ return $ret;
+ }
+
+ /** @inheritDoc */
+ public function inc($key, $step = 1) {
+ $start = microtime(true);
+ $ret = $this->wrappedCache->inc($key, $step);
+ $this->data['queries'][] = [
+ 'start' => $start,
+ 'end' => microtime(true),
+ 'op' => $this->getPrefix() . '::inc::' . $key,
+ ];
+ return $ret;
+ }
+
+ /** @inheritDoc */
+ public function dec($key, $step = 1) {
+ $start = microtime(true);
+ $ret = $this->wrappedCache->dec($key, $step);
+ $this->data['queries'][] = [
+ 'start' => $start,
+ 'end' => microtime(true),
+ 'op' => $this->getPrefix() . '::dev::' . $key,
+ ];
+ return $ret;
+ }
+
+ /** @inheritDoc */
+ public function cas($key, $old, $new) {
+ $start = microtime(true);
+ $ret = $this->wrappedCache->cas($key, $old, $new);
+ $this->data['queries'][] = [
+ 'start' => $start,
+ 'end' => microtime(true),
+ 'op' => $this->getPrefix() . '::cas::' . $key,
+ ];
+ return $ret;
+ }
+
+ /** @inheritDoc */
+ public function cad($key, $old) {
+ $start = microtime(true);
+ $ret = $this->wrappedCache->cad($key, $old);
+ $this->data['queries'][] = [
+ 'start' => $start,
+ 'end' => microtime(true),
+ 'op' => $this->getPrefix() . '::cad::' . $key,
+ ];
+ return $ret;
+ }
+
+ /** @inheritDoc */
+ public function setTTL($key, $ttl) {
+ $this->wrappedCache->setTTL($key, $ttl);
+ }
+
+ public function offsetExists($offset): bool {
+ return $this->hasKey($offset);
+ }
+
+ public function offsetSet($offset, $value): void {
+ $this->set($offset, $value);
+ }
+
+ /**
+ * @return mixed
+ */
+ #[\ReturnTypeWillChange]
+ public function offsetGet($offset) {
+ return $this->get($offset);
+ }
+
+ public function offsetUnset($offset): void {
+ $this->remove($offset);
+ }
+
+ public function collect(Request $request, Response $response, \Throwable $exception = null): void {
+ // Nothing to do here $data is already ready
+ }
+
+ public function getName(): string {
+ return 'cache/' . $this->type . '/' . $this->prefix;
+ }
+
+ public static function isAvailable(): bool {
+ return true;
+ }
+}
diff --git a/lib/private/Memcache/Redis.php b/lib/private/Memcache/Redis.php
index 63180dd8066..9b07da2d99c 100644
--- a/lib/private/Memcache/Redis.php
+++ b/lib/private/Memcache/Redis.php
@@ -37,38 +37,16 @@ class Redis extends Cache implements IMemcacheTTL {
*/
private static $cache = null;
- private $logFile;
-
public function __construct($prefix = '', string $logFile = '') {
parent::__construct($prefix);
- $this->logFile = $logFile;
if (is_null(self::$cache)) {
self::$cache = \OC::$server->getGetRedisFactory()->getInstance();
}
}
- /**
- * entries in redis get namespaced to prevent collisions between ownCloud instances and users
- */
- protected function getNameSpace() {
- return $this->prefix;
- }
-
- private function logEnabled(): bool {
- return $this->logFile !== '' && is_writable(dirname($this->logFile)) && (!file_exists($this->logFile) || is_writable($this->logFile));
- }
-
public function get($key) {
- if ($this->logEnabled()) {
- file_put_contents(
- $this->logFile,
- $this->getNameSpace() . '::get::' . $key . "\n",
- FILE_APPEND
- );
- }
-
- $result = self::$cache->get($this->getNameSpace() . $key);
- if ($result === false && !self::$cache->exists($this->getNameSpace() . $key)) {
+ $result = self::$cache->get($this->getPrefix() . $key);
+ if ($result === false && !self::$cache->exists($this->getPrefix() . $key)) {
return null;
} else {
return json_decode($result, true);
@@ -76,43 +54,19 @@ class Redis extends Cache implements IMemcacheTTL {
}
public function set($key, $value, $ttl = 0) {
- if ($this->logEnabled()) {
- file_put_contents(
- $this->logFile,
- $this->getNameSpace() . '::set::' . $key . '::' . $ttl . '::' . json_encode($value) . "\n",
- FILE_APPEND
- );
- }
-
if ($ttl > 0) {
- return self::$cache->setex($this->getNameSpace() . $key, $ttl, json_encode($value));
+ return self::$cache->setex($this->getPrefix() . $key, $ttl, json_encode($value));
} else {
- return self::$cache->set($this->getNameSpace() . $key, json_encode($value));
+ return self::$cache->set($this->getPrefix() . $key, json_encode($value));
}
}
public function hasKey($key) {
- if ($this->logEnabled()) {
- file_put_contents(
- $this->logFile,
- $this->getNameSpace() . '::hasKey::' . $key . "\n",
- FILE_APPEND
- );
- }
-
- return (bool)self::$cache->exists($this->getNameSpace() . $key);
+ return (bool)self::$cache->exists($this->getPrefix() . $key);
}
public function remove($key) {
- if ($this->logEnabled()) {
- file_put_contents(
- $this->logFile,
- $this->getNameSpace() . '::remove::' . $key . "\n",
- FILE_APPEND
- );
- }
-
- if (self::$cache->del($this->getNameSpace() . $key)) {
+ if (self::$cache->del($this->getPrefix() . $key)) {
return true;
} else {
return false;
@@ -120,15 +74,7 @@ class Redis extends Cache implements IMemcacheTTL {
}
public function clear($prefix = '') {
- if ($this->logEnabled()) {
- file_put_contents(
- $this->logFile,
- $this->getNameSpace() . '::clear::' . $prefix . "\n",
- FILE_APPEND
- );
- }
-
- $prefix = $this->getNameSpace() . $prefix . '*';
+ $prefix = $this->getPrefix() . $prefix . '*';
$keys = self::$cache->keys($prefix);
$deleted = self::$cache->del($keys);
@@ -153,14 +99,6 @@ class Redis extends Cache implements IMemcacheTTL {
if ($ttl !== 0 && is_int($ttl)) {
$args['ex'] = $ttl;
}
- if ($this->logEnabled()) {
- file_put_contents(
- $this->logFile,
- $this->getNameSpace() . '::add::' . $key . '::' . $value . "\n",
- FILE_APPEND
- );
- }
-
return self::$cache->set($this->getPrefix() . $key, $value, $args);
}
@@ -173,15 +111,7 @@ class Redis extends Cache implements IMemcacheTTL {
* @return int | bool
*/
public function inc($key, $step = 1) {
- if ($this->logEnabled()) {
- file_put_contents(
- $this->logFile,
- $this->getNameSpace() . '::inc::' . $key . "\n",
- FILE_APPEND
- );
- }
-
- return self::$cache->incrBy($this->getNameSpace() . $key, $step);
+ return self::$cache->incrBy($this->getPrefix() . $key, $step);
}
/**
@@ -192,18 +122,10 @@ class Redis extends Cache implements IMemcacheTTL {
* @return int | bool
*/
public function dec($key, $step = 1) {
- if ($this->logEnabled()) {
- file_put_contents(
- $this->logFile,
- $this->getNameSpace() . '::dec::' . $key . "\n",
- FILE_APPEND
- );
- }
-
if (!$this->hasKey($key)) {
return false;
}
- return self::$cache->decrBy($this->getNameSpace() . $key, $step);
+ return self::$cache->decrBy($this->getPrefix() . $key, $step);
}
/**
@@ -215,21 +137,13 @@ class Redis extends Cache implements IMemcacheTTL {
* @return bool
*/
public function cas($key, $old, $new) {
- if ($this->logEnabled()) {
- file_put_contents(
- $this->logFile,
- $this->getNameSpace() . '::cas::' . $key . "\n",
- FILE_APPEND
- );
- }
-
if (!is_int($new)) {
$new = json_encode($new);
}
- self::$cache->watch($this->getNameSpace() . $key);
+ self::$cache->watch($this->getPrefix() . $key);
if ($this->get($key) === $old) {
$result = self::$cache->multi()
- ->set($this->getNameSpace() . $key, $new)
+ ->set($this->getPrefix() . $key, $new)
->exec();
return $result !== false;
}
@@ -245,18 +159,10 @@ class Redis extends Cache implements IMemcacheTTL {
* @return bool
*/
public function cad($key, $old) {
- if ($this->logEnabled()) {
- file_put_contents(
- $this->logFile,
- $this->getNameSpace() . '::cad::' . $key . "\n",
- FILE_APPEND
- );
- }
-
- self::$cache->watch($this->getNameSpace() . $key);
+ self::$cache->watch($this->getPrefix() . $key);
if ($this->get($key) === $old) {
$result = self::$cache->multi()
- ->del($this->getNameSpace() . $key)
+ ->del($this->getPrefix() . $key)
->exec();
return $result !== false;
}
@@ -265,10 +171,10 @@ class Redis extends Cache implements IMemcacheTTL {
}
public function setTTL($key, $ttl) {
- self::$cache->expire($this->getNameSpace() . $key, $ttl);
+ self::$cache->expire($this->getPrefix() . $key, $ttl);
}
- public static function isAvailable() {
+ public static function isAvailable(): bool {
return \OC::$server->getGetRedisFactory()->isAvailable();
}
}
diff --git a/lib/private/Migration/SimpleOutput.php b/lib/private/Migration/SimpleOutput.php
index 5024fdac585..f97bcb767f8 100644
--- a/lib/private/Migration/SimpleOutput.php
+++ b/lib/private/Migration/SimpleOutput.php
@@ -21,8 +21,8 @@
*/
namespace OC\Migration;
-use OCP\ILogger;
use OCP\Migration\IOutput;
+use Psr\Log\LoggerInterface;
/**
* Class SimpleOutput
@@ -33,12 +33,10 @@ use OCP\Migration\IOutput;
* @package OC\Migration
*/
class SimpleOutput implements IOutput {
-
- /** @var ILogger */
- private $logger;
+ private LoggerInterface $logger;
private $appName;
- public function __construct(ILogger $logger, $appName) {
+ public function __construct(LoggerInterface $logger, $appName) {
$this->logger = $logger;
$this->appName = $appName;
}
diff --git a/lib/private/Preview/Imaginary.php b/lib/private/Preview/Imaginary.php
index 7e6ce86d4eb..4da88f1ab26 100644
--- a/lib/private/Preview/Imaginary.php
+++ b/lib/private/Preview/Imaginary.php
@@ -89,18 +89,26 @@ class Imaginary extends ProviderV2 {
$mimeType = 'jpeg';
}
- $parameters = [
- 'width' => $maxX,
- 'height' => $maxY,
- 'stripmeta' => 'true',
- 'type' => $mimeType,
+ $operations = [
+ [
+ 'operation' => 'autorotate',
+ ],
+ [
+ 'operation' => ($crop ? 'smartcrop' : 'fit'),
+ 'params' => [
+ 'width' => $maxX,
+ 'height' => $maxY,
+ 'stripmeta' => 'true',
+ 'type' => $mimeType,
+ 'norotation' => 'true',
+ ]
+ ]
];
-
try {
$response = $httpClient->post(
- $imaginaryUrl . ($crop ? '/smartcrop' : '/fit'), [
- 'query' => $parameters,
+ $imaginaryUrl . '/pipeline', [
+ 'query' => ['operations' => json_encode($operations)],
'stream' => true,
'content-type' => $file->getMimeType(),
'body' => $stream,
diff --git a/lib/private/Profiler/FileProfilerStorage.php b/lib/private/Profiler/FileProfilerStorage.php
new file mode 100644
index 00000000000..ce09ed51ed9
--- /dev/null
+++ b/lib/private/Profiler/FileProfilerStorage.php
@@ -0,0 +1,286 @@
+<?php
+
+declare(strict_types = 1);
+/**
+ * @copyright 2022 Carl Schwan <carl@carlschwan.eu>
+ *
+ * @author Carl Schwan <carl@carlschwan.eu>
+ * @author Alexandre Salomé <alexandre.salome@gmail.com>
+ *
+ * @license AGPL-3.0-or-later AND MIT
+ *
+ * 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\Profiler;
+
+use OCP\Profiler\IProfile;
+
+/**
+ * Storage for profiler using files.
+ */
+class FileProfilerStorage {
+ // Folder where profiler data are stored.
+ private string $folder;
+
+ /**
+ * Constructs the file storage using a "dsn-like" path.
+ *
+ * Example : "file:/path/to/the/storage/folder"
+ *
+ * @throws \RuntimeException
+ */
+ public function __construct(string $folder) {
+ $this->folder = $folder;
+
+ if (!is_dir($this->folder) && false === @mkdir($this->folder, 0777, true) && !is_dir($this->folder)) {
+ throw new \RuntimeException(sprintf('Unable to create the storage directory (%s).', $this->folder));
+ }
+ }
+
+ public function find(?string $url, ?int $limit, ?string $method, int $start = null, int $end = null, string $statusCode = null): array {
+ $file = $this->getIndexFilename();
+
+ if (!file_exists($file)) {
+ return [];
+ }
+
+ $file = fopen($file, 'r');
+ fseek($file, 0, \SEEK_END);
+
+ $result = [];
+ while (\count($result) < $limit && $line = $this->readLineFromFile($file)) {
+ $values = str_getcsv($line);
+ [$csvToken, $csvMethod, $csvUrl, $csvTime, $csvParent, $csvStatusCode] = $values;
+ $csvTime = (int) $csvTime;
+
+ if ($url && false === strpos($csvUrl, $url) || $method && false === strpos($csvMethod, $method) || $statusCode && false === strpos($csvStatusCode, $statusCode)) {
+ continue;
+ }
+
+ if (!empty($start) && $csvTime < $start) {
+ continue;
+ }
+
+ if (!empty($end) && $csvTime > $end) {
+ continue;
+ }
+
+ $result[$csvToken] = [
+ 'token' => $csvToken,
+ 'method' => $csvMethod,
+ 'url' => $csvUrl,
+ 'time' => $csvTime,
+ 'parent' => $csvParent,
+ 'status_code' => $csvStatusCode,
+ ];
+ }
+
+ fclose($file);
+
+ return array_values($result);
+ }
+
+ public function purge(): void {
+ $flags = \FilesystemIterator::SKIP_DOTS;
+ $iterator = new \RecursiveDirectoryIterator($this->folder, $flags);
+ $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::CHILD_FIRST);
+
+ foreach ($iterator as $file) {
+ if (is_file($file)) {
+ unlink($file);
+ } else {
+ rmdir($file);
+ }
+ }
+ }
+
+ public function read(string $token): ?IProfile {
+ if (!$token || !file_exists($file = $this->getFilename($token))) {
+ return null;
+ }
+
+ if (\function_exists('gzcompress')) {
+ $file = 'compress.zlib://'.$file;
+ }
+
+ return $this->createProfileFromData($token, unserialize(file_get_contents($file)));
+ }
+
+ /**
+ * @throws \RuntimeException
+ */
+ public function write(IProfile $profile): bool {
+ $file = $this->getFilename($profile->getToken());
+
+ $profileIndexed = is_file($file);
+ if (!$profileIndexed) {
+ // Create directory
+ $dir = \dirname($file);
+ if (!is_dir($dir) && false === @mkdir($dir, 0777, true) && !is_dir($dir)) {
+ throw new \RuntimeException(sprintf('Unable to create the storage directory (%s).', $dir));
+ }
+ }
+
+ $profileToken = $profile->getToken();
+ // when there are errors in sub-requests, the parent and/or children tokens
+ // may equal the profile token, resulting in infinite loops
+ $parentToken = $profile->getParentToken() !== $profileToken ? $profile->getParentToken() : null;
+ $childrenToken = array_filter(array_map(function (IProfile $p) use ($profileToken) {
+ return $profileToken !== $p->getToken() ? $p->getToken() : null;
+ }, $profile->getChildren()));
+
+ // Store profile
+ $data = [
+ 'token' => $profileToken,
+ 'parent' => $parentToken,
+ 'children' => $childrenToken,
+ 'data' => $profile->getCollectors(),
+ 'method' => $profile->getMethod(),
+ 'url' => $profile->getUrl(),
+ 'time' => $profile->getTime(),
+ 'status_code' => $profile->getStatusCode(),
+ ];
+
+ $context = stream_context_create();
+
+ if (\function_exists('gzcompress')) {
+ $file = 'compress.zlib://'.$file;
+ stream_context_set_option($context, 'zlib', 'level', 3);
+ }
+
+ if (false === file_put_contents($file, serialize($data), 0, $context)) {
+ return false;
+ }
+
+ if (!$profileIndexed) {
+ // Add to index
+ if (false === $file = fopen($this->getIndexFilename(), 'a')) {
+ return false;
+ }
+
+ fputcsv($file, [
+ $profile->getToken(),
+ $profile->getMethod(),
+ $profile->getUrl(),
+ $profile->getTime(),
+ $profile->getParentToken(),
+ $profile->getStatusCode(),
+ ]);
+ fclose($file);
+ }
+
+ return true;
+ }
+
+ /**
+ * Gets filename to store data, associated to the token.
+ *
+ * @return string The profile filename
+ */
+ protected function getFilename(string $token): string {
+ // Uses 4 last characters, because first are mostly the same.
+ $folderA = substr($token, -2, 2);
+ $folderB = substr($token, -4, 2);
+
+ return $this->folder.'/'.$folderA.'/'.$folderB.'/'.$token;
+ }
+
+ /**
+ * Gets the index filename.
+ *
+ * @return string The index filename
+ */
+ protected function getIndexFilename(): string {
+ return $this->folder.'/index.csv';
+ }
+
+ /**
+ * Reads a line in the file, backward.
+ *
+ * This function automatically skips the empty lines and do not include the line return in result value.
+ *
+ * @param resource $file The file resource, with the pointer placed at the end of the line to read
+ *
+ * @return ?string A string representing the line or null if beginning of file is reached
+ */
+ protected function readLineFromFile($file): ?string {
+ $line = '';
+ $position = ftell($file);
+
+ if (0 === $position) {
+ return null;
+ }
+
+ while (true) {
+ $chunkSize = min($position, 1024);
+ $position -= $chunkSize;
+ fseek($file, $position);
+
+ if (0 === $chunkSize) {
+ // bof reached
+ break;
+ }
+
+ $buffer = fread($file, $chunkSize);
+
+ if (false === ($upTo = strrpos($buffer, "\n"))) {
+ $line = $buffer.$line;
+ continue;
+ }
+
+ $position += $upTo;
+ $line = substr($buffer, $upTo + 1).$line;
+ fseek($file, max(0, $position), \SEEK_SET);
+
+ if ('' !== $line) {
+ break;
+ }
+ }
+
+ return '' === $line ? null : $line;
+ }
+
+ protected function createProfileFromData(string $token, array $data, IProfile $parent = null): IProfile {
+ $profile = new Profile($token);
+ $profile->setMethod($data['method']);
+ $profile->setUrl($data['url']);
+ $profile->setTime($data['time']);
+ $profile->setStatusCode($data['status_code']);
+ $profile->setCollectors($data['data']);
+
+ if (!$parent && $data['parent']) {
+ $parent = $this->read($data['parent']);
+ }
+
+ if ($parent) {
+ $profile->setParent($parent);
+ }
+
+ foreach ($data['children'] as $token) {
+ if (!$token || !file_exists($file = $this->getFilename($token))) {
+ continue;
+ }
+
+ if (\function_exists('gzcompress')) {
+ $file = 'compress.zlib://'.$file;
+ }
+
+ $profile->addChild($this->createProfileFromData($token, unserialize(file_get_contents($file)), $profile));
+ }
+
+ return $profile;
+ }
+}
diff --git a/lib/private/Profiler/Profile.php b/lib/private/Profiler/Profile.php
new file mode 100644
index 00000000000..648c49c0330
--- /dev/null
+++ b/lib/private/Profiler/Profile.php
@@ -0,0 +1,168 @@
+<?php
+
+declare(strict_types = 1);
+/**
+ * @copyright 2022 Carl Schwan <carl@carlschwan.eu>
+ *
+ * @author Carl Schwan <carl@carlschwan.eu>
+ *
+ * @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\Profiler;
+
+use OCP\DataCollector\IDataCollector;
+use OCP\Profiler\IProfile;
+
+class Profile implements \JsonSerializable, IProfile {
+ private string $token;
+
+ private ?int $time = null;
+
+ private ?string $url = null;
+
+ private ?string $method = null;
+
+ private ?int $statusCode = null;
+
+ /** @var array<string, IDataCollector> */
+ private array $collectors = [];
+
+ private ?IProfile $parent = null;
+
+ /** @var IProfile[] */
+ private array $children = [];
+
+ public function __construct(string $token) {
+ $this->token = $token;
+ }
+
+ public function getToken(): string {
+ return $this->token;
+ }
+
+ public function setToken(string $token): void {
+ $this->token = $token;
+ }
+
+ public function getTime(): ?int {
+ return $this->time;
+ }
+
+ public function setTime(int $time): void {
+ $this->time = $time;
+ }
+
+ public function getUrl(): ?string {
+ return $this->url;
+ }
+
+ public function setUrl(string $url): void {
+ $this->url = $url;
+ }
+
+ public function getMethod(): ?string {
+ return $this->method;
+ }
+
+ public function setMethod(string $method): void {
+ $this->method = $method;
+ }
+
+ public function getStatusCode(): ?int {
+ return $this->statusCode;
+ }
+
+ public function setStatusCode(int $statusCode): void {
+ $this->statusCode = $statusCode;
+ }
+
+ public function addCollector(IDataCollector $collector) {
+ $this->collectors[$collector->getName()] = $collector;
+ }
+
+ public function getParent(): ?IProfile {
+ return $this->parent;
+ }
+
+ public function setParent(?IProfile $parent): void {
+ $this->parent = $parent;
+ }
+
+ public function getParentToken(): ?string {
+ return $this->parent ? $this->parent->getToken() : null;
+ }
+
+ /** @return IProfile[] */
+ public function getChildren(): array {
+ return $this->children;
+ }
+
+ /**
+ * @param IProfile[] $children
+ */
+ public function setChildren(array $children): void {
+ $this->children = [];
+ foreach ($children as $child) {
+ $this->addChild($child);
+ }
+ }
+
+ public function addChild(IProfile $profile): void {
+ $this->children[] = $profile;
+ $profile->setParent($this);
+ }
+
+ /**
+ * @return IDataCollector[]
+ */
+ public function getCollectors(): array {
+ return $this->collectors;
+ }
+
+ /**
+ * @param IDataCollector[] $collectors
+ */
+ public function setCollectors(array $collectors): void {
+ $this->collectors = $collectors;
+ }
+
+ public function __sleep(): array {
+ return ['token', 'parent', 'children', 'collectors', 'method', 'url', 'time', 'statusCode'];
+ }
+
+ #[\ReturnTypeWillChange]
+ public function jsonSerialize() {
+ // Everything but parent
+ return [
+ 'token' => $this->token,
+ 'method' => $this->method,
+ 'children' => $this->children,
+ 'url' => $this->url,
+ 'statusCode' => $this->statusCode,
+ 'time' => $this->time,
+ 'collectors' => $this->collectors,
+ ];
+ }
+
+ public function getCollector(string $collectorName): ?IDataCollector {
+ if (!array_key_exists($collectorName, $this->collectors)) {
+ return null;
+ }
+ return $this->collectors[$collectorName];
+ }
+}
diff --git a/lib/private/Profiler/Profiler.php b/lib/private/Profiler/Profiler.php
new file mode 100644
index 00000000000..8aa800fbc6d
--- /dev/null
+++ b/lib/private/Profiler/Profiler.php
@@ -0,0 +1,105 @@
+<?php
+
+declare(strict_types = 1);
+
+/**
+ * @copyright 2021 Carl Schwan <carl@carlschwan.eu>
+ *
+ * @author Carl Schwan <carl@carlschwan.eu>
+ *
+ * @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\Profiler;
+
+use OC\AppFramework\Http\Request;
+use OCP\AppFramework\Http\Response;
+use OCP\DataCollector\IDataCollector;
+use OCP\Profiler\IProfiler;
+use OCP\Profiler\IProfile;
+use OC\SystemConfig;
+
+class Profiler implements IProfiler {
+ /** @var array<string, IDataCollector> */
+ private array $dataCollectors = [];
+
+ private ?FileProfilerStorage $storage = null;
+
+ private bool $enabled = false;
+
+ public function __construct(SystemConfig $config) {
+ $this->enabled = $config->getValue('profiler', false);
+ if ($this->enabled) {
+ $this->storage = new FileProfilerStorage($config->getValue('datadirectory', \OC::$SERVERROOT . '/data') . '/profiler');
+ }
+ }
+
+ public function add(IDataCollector $dataCollector): void {
+ $this->dataCollectors[$dataCollector->getName()] = $dataCollector;
+ }
+
+ public function loadProfileFromResponse(Response $response): ?IProfile {
+ if (!$token = $response->getHeaders()['X-Debug-Token']) {
+ return null;
+ }
+
+ return $this->loadProfile($token);
+ }
+
+ public function loadProfile(string $token): ?IProfile {
+ return $this->storage->read($token);
+ }
+
+ public function saveProfile(IProfile $profile): bool {
+ return $this->storage->write($profile);
+ }
+
+ public function collect(Request $request, Response $response): IProfile {
+ $profile = new Profile($request->getId());
+ $profile->setTime(time());
+ $profile->setUrl($request->getRequestUri());
+ $profile->setMethod($request->getMethod());
+ $profile->setStatusCode($response->getStatus());
+ foreach ($this->dataCollectors as $dataCollector) {
+ $dataCollector->collect($request, $response, null);
+
+ // We clone for subrequests
+ $profile->addCollector(clone $dataCollector);
+ }
+ return $profile;
+ }
+
+ /**
+ * @return array[]
+ */
+ public function find(?string $url, ?int $limit, ?string $method, ?int $start, ?int $end,
+ string $statusCode = null): array {
+ return $this->storage->find($url, $limit, $method, $start, $end, $statusCode);
+ }
+
+ public function dataProviders(): array {
+ return array_keys($this->dataCollectors);
+ }
+
+ public function isEnabled(): bool {
+ return $this->enabled;
+ }
+
+ public function setEnabled(bool $enabled): void {
+ $this->enabled = $enabled;
+ }
+}
diff --git a/lib/private/Profiler/RoutingDataCollector.php b/lib/private/Profiler/RoutingDataCollector.php
new file mode 100644
index 00000000000..e6659230879
--- /dev/null
+++ b/lib/private/Profiler/RoutingDataCollector.php
@@ -0,0 +1,55 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2022 Carl Schwan <carl@carlschwan.eu>
+ *
+ * @author Carl Schwan <carl@carlschwan.eu>
+ *
+ * @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\Profiler;
+
+use OC\AppFramework\Http\Request;
+use OCP\AppFramework\Http\Response;
+use OCP\DataCollector\AbstractDataCollector;
+
+class RoutingDataCollector extends AbstractDataCollector {
+ private string $appName;
+ private string $controllerName;
+ private string $actionName;
+
+ public function __construct(string $appName, string $controllerName, string $actionName) {
+ $this->appName = $appName;
+ $this->controllerName = $controllerName;
+ $this->actionName = $actionName;
+ }
+
+ public function collect(Request $request, Response $response, \Throwable $exception = null): void {
+ $this->data = [
+ 'appName' => $this->appName,
+ 'controllerName' => $this->controllerName,
+ 'actionName' => $this->actionName,
+ ];
+ }
+
+ public function getName(): string {
+ return 'router';
+ }
+}
diff --git a/lib/private/Repair.php b/lib/private/Repair.php
index 408d0f1b7aa..91bfd47f5de 100644
--- a/lib/private/Repair.php
+++ b/lib/private/Repair.php
@@ -47,6 +47,7 @@ use OC\Repair\Collation;
use OC\Repair\MoveUpdaterStepFile;
use OC\Repair\NC22\LookupServerSendCheck;
use OC\Repair\Owncloud\CleanPreviews;
+use OC\Repair\Owncloud\MigrateOauthTables;
use OC\Repair\NC11\FixMountStorages;
use OC\Repair\Owncloud\MoveAvatars;
use OC\Repair\Owncloud\InstallCoreBundle;
@@ -93,13 +94,12 @@ class Repair implements IOutput {
/** @var string */
private $currentStep;
- private $logger;
+ private LoggerInterface $logger;
/**
* Creates a new repair step runner
*
* @param IRepairStep[] $repairSteps array of RepairStep instances
- * @param EventDispatcherInterface $dispatcher
*/
public function __construct(array $repairSteps, EventDispatcherInterface $dispatcher, LoggerInterface $logger) {
$this->repairSteps = $repairSteps;
@@ -171,7 +171,7 @@ class Repair implements IOutput {
*/
public static function getRepairSteps() {
return [
- new Collation(\OC::$server->getConfig(), \OC::$server->getLogger(), \OC::$server->getDatabaseConnection(), false),
+ new Collation(\OC::$server->getConfig(), \OC::$server->get(LoggerInterface::class), \OC::$server->getDatabaseConnection(), false),
new RepairMimeTypes(\OC::$server->getConfig(), \OC::$server->getDatabaseConnection()),
new CleanTags(\OC::$server->getDatabaseConnection(), \OC::$server->getUserManager()),
new RepairInvalidShares(\OC::$server->getConfig(), \OC::$server->getDatabaseConnection()),
@@ -185,6 +185,7 @@ class Repair implements IOutput {
\OC::$server->getUserManager(),
\OC::$server->getConfig()
),
+ new MigrateOauthTables(\OC::$server->get(Connection::class)),
new FixMountStorages(\OC::$server->getDatabaseConnection()),
new UpdateLanguageCodes(\OC::$server->getDatabaseConnection(), \OC::$server->getConfig()),
new InstallCoreBundle(
@@ -197,7 +198,7 @@ class Repair implements IOutput {
new ClearGeneratedAvatarCache(\OC::$server->getConfig(), \OC::$server->query(AvatarManager::class)),
new AddPreviewBackgroundCleanupJob(\OC::$server->getJobList()),
new AddCleanupUpdaterBackupsJob(\OC::$server->getJobList()),
- new CleanupCardDAVPhotoCache(\OC::$server->getConfig(), \OC::$server->getAppDataDir('dav-photocache'), \OC::$server->getLogger()),
+ new CleanupCardDAVPhotoCache(\OC::$server->getConfig(), \OC::$server->getAppDataDir('dav-photocache'), \OC::$server->get(LoggerInterface::class)),
new AddClenupLoginFlowV2BackgroundJob(\OC::$server->getJobList()),
new RemoveLinkShares(\OC::$server->getDatabaseConnection(), \OC::$server->getConfig(), \OC::$server->getGroupManager(), \OC::$server->getNotificationManager(), \OC::$server->query(ITimeFactory::class)),
new ClearCollectionsAccessCache(\OC::$server->getConfig(), \OC::$server->query(IManager::class)),
@@ -238,7 +239,7 @@ class Repair implements IOutput {
$connectionAdapter = \OC::$server->get(ConnectionAdapter::class);
$config = \OC::$server->getConfig();
$steps = [
- new Collation(\OC::$server->getConfig(), \OC::$server->getLogger(), $connectionAdapter, true),
+ new Collation(\OC::$server->getConfig(), \OC::$server->get(LoggerInterface::class), $connectionAdapter, true),
new SqliteAutoincrement($connection),
new SaveAccountsTableData($connectionAdapter, $config),
new DropAccountTermsTable($connectionAdapter),
diff --git a/lib/private/Repair/Collation.php b/lib/private/Repair/Collation.php
index e949c261b80..25e85f00af8 100644
--- a/lib/private/Repair/Collation.php
+++ b/lib/private/Repair/Collation.php
@@ -30,16 +30,15 @@ use Doctrine\DBAL\Exception\DriverException;
use Doctrine\DBAL\Platforms\MySQLPlatform;
use OCP\IConfig;
use OCP\IDBConnection;
-use OCP\ILogger;
use OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
+use Psr\Log\LoggerInterface;
class Collation implements IRepairStep {
/** @var IConfig */
protected $config;
- /** @var ILogger */
- protected $logger;
+ protected LoggerInterface $logger;
/** @var IDBConnection */
protected $connection;
@@ -48,12 +47,14 @@ class Collation implements IRepairStep {
protected $ignoreFailures;
/**
- * @param IConfig $config
- * @param ILogger $logger
- * @param IDBConnection $connection
* @param bool $ignoreFailures
*/
- public function __construct(IConfig $config, ILogger $logger, IDBConnection $connection, $ignoreFailures) {
+ public function __construct(
+ IConfig $config,
+ LoggerInterface $logger,
+ IDBConnection $connection,
+ $ignoreFailures
+ ) {
$this->connection = $connection;
$this->config = $config;
$this->logger = $logger;
@@ -83,7 +84,7 @@ class Collation implements IRepairStep {
$query->execute();
} catch (DriverException $e) {
// Just log this
- $this->logger->logException($e);
+ $this->logger->error($e->getMessage(), ['exception' => $e]);
if (!$this->ignoreFailures) {
throw $e;
}
@@ -95,7 +96,7 @@ class Collation implements IRepairStep {
$query->execute();
} catch (DriverException $e) {
// Just log this
- $this->logger->logException($e);
+ $this->logger->error($e->getMessage(), ['exception' => $e]);
if (!$this->ignoreFailures) {
throw $e;
}
diff --git a/lib/private/Repair/NC16/CleanupCardDAVPhotoCache.php b/lib/private/Repair/NC16/CleanupCardDAVPhotoCache.php
index 39b48562791..25dc24fb66c 100644
--- a/lib/private/Repair/NC16/CleanupCardDAVPhotoCache.php
+++ b/lib/private/Repair/NC16/CleanupCardDAVPhotoCache.php
@@ -30,9 +30,9 @@ use OCP\Files\IAppData;
use OCP\Files\NotFoundException;
use OCP\Files\SimpleFS\ISimpleFolder;
use OCP\IConfig;
-use OCP\ILogger;
use OCP\Migration\IOutput;
use OCP\Migration\IRepairStep;
+use Psr\Log\LoggerInterface;
use RuntimeException;
/**
@@ -52,10 +52,9 @@ class CleanupCardDAVPhotoCache implements IRepairStep {
/** @var IAppData */
private $appData;
- /** @var ILogger */
- private $logger;
+ private LoggerInterface $logger;
- public function __construct(IConfig $config, IAppData $appData, ILogger $logger) {
+ public function __construct(IConfig $config, IAppData $appData, LoggerInterface $logger) {
$this->config = $config;
$this->appData = $appData;
$this->logger = $logger;
@@ -71,7 +70,7 @@ class CleanupCardDAVPhotoCache implements IRepairStep {
} catch (NotFoundException $e) {
return;
} catch (RuntimeException $e) {
- $this->logger->logException($e, ['message' => 'Failed to fetch directory listing in CleanupCardDAVPhotoCache']);
+ $this->logger->error('Failed to fetch directory listing in CleanupCardDAVPhotoCache', ['exception' => $e]);
return;
}
@@ -90,7 +89,7 @@ class CleanupCardDAVPhotoCache implements IRepairStep {
/** @var ISimpleFolder $folder */
$folder->getFile('photo.')->delete();
} catch (\Exception $e) {
- $this->logger->logException($e);
+ $this->logger->error($e->getMessage(), ['exception' => $e]);
$output->warning('Could not delete file "dav-photocache/' . $folder->getName() . '/photo."');
}
}
diff --git a/lib/private/Repair/Owncloud/CleanPreviewsBackgroundJob.php b/lib/private/Repair/Owncloud/CleanPreviewsBackgroundJob.php
index 67f9d6912d9..7f4bbc35c17 100644
--- a/lib/private/Repair/Owncloud/CleanPreviewsBackgroundJob.php
+++ b/lib/private/Repair/Owncloud/CleanPreviewsBackgroundJob.php
@@ -29,15 +29,14 @@ use OCP\Files\Folder;
use OCP\Files\IRootFolder;
use OCP\Files\NotFoundException;
use OCP\Files\NotPermittedException;
-use OCP\ILogger;
use OCP\IUserManager;
+use Psr\Log\LoggerInterface;
class CleanPreviewsBackgroundJob extends QueuedJob {
/** @var IRootFolder */
private $rootFolder;
- /** @var ILogger */
- private $logger;
+ private LoggerInterface $logger;
/** @var IJobList */
private $jobList;
@@ -50,15 +49,9 @@ class CleanPreviewsBackgroundJob extends QueuedJob {
/**
* CleanPreviewsBackgroundJob constructor.
- *
- * @param IRootFolder $rootFolder
- * @param ILogger $logger
- * @param IJobList $jobList
- * @param ITimeFactory $timeFactory
- * @param IUserManager $userManager
*/
public function __construct(IRootFolder $rootFolder,
- ILogger $logger,
+ LoggerInterface $logger,
IJobList $jobList,
ITimeFactory $timeFactory,
IUserManager $userManager) {
diff --git a/lib/private/Repair/Owncloud/MigrateOauthTables.php b/lib/private/Repair/Owncloud/MigrateOauthTables.php
new file mode 100644
index 00000000000..4011a043f20
--- /dev/null
+++ b/lib/private/Repair/Owncloud/MigrateOauthTables.php
@@ -0,0 +1,124 @@
+<?php
+/**
+ * @copyright 2021 Louis Chemineau <louis@chmn.me>
+ *
+ * @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\Repair\Owncloud;
+
+use OCP\Migration\IOutput;
+use OCP\Migration\IRepairStep;
+use OC\DB\Connection;
+use OC\DB\SchemaWrapper;
+use OCP\DB\QueryBuilder\IQueryBuilder;
+
+class MigrateOauthTables implements IRepairStep {
+
+ /** @var Connection */
+ protected $db;
+
+ /**
+ * @param Connection $db
+ */
+ public function __construct(Connection $db) {
+ $this->db = $db;
+ }
+
+ /**
+ * @return string
+ */
+ public function getName() {
+ return 'Migrate oauth2_clients table to nextcloud schema';
+ }
+
+ public function run(IOutput $output) {
+ $schema = new SchemaWrapper($this->db);
+ if (!$schema->hasTable('oauth2_clients')) {
+ $output->info("oauth2_clients table does not exist.");
+ return;
+ }
+
+ $output->info("Update the oauth2_access_tokens table schema.");
+ $schema = new SchemaWrapper($this->db);
+ $table = $schema->getTable('oauth2_access_tokens');
+ if (!$table->hasColumn('hashed_code')) {
+ $table->addColumn('hashed_code', 'string', [
+ 'notnull' => true,
+ 'length' => 128,
+ ]);
+ }
+ if (!$table->hasColumn('encrypted_token')) {
+ $table->addColumn('encrypted_token', 'string', [
+ 'notnull' => true,
+ 'length' => 786,
+ ]);
+ }
+ if (!$table->hasIndex('oauth2_access_hash_idx')) {
+ $table->addUniqueIndex(['hashed_code'], 'oauth2_access_hash_idx');
+ }
+ if (!$table->hasIndex('oauth2_access_client_id_idx')) {
+ $table->addIndex(['client_id'], 'oauth2_access_client_id_idx');
+ }
+
+ $output->info("Update the oauth2_clients table schema.");
+ $schema = new SchemaWrapper($this->db);
+ $table = $schema->getTable('oauth2_clients');
+ if ($table->getColumn('name')->getLength() !== 64) {
+ $table->getColumn('name')->setLength(64);
+ }
+ if ($table->hasColumn('allow_subdomains')) {
+ $table->dropColumn('allow_subdomains');
+ }
+
+ if (!$schema->getTable('oauth2_clients')->hasColumn('client_identifier')) {
+ $table->addColumn('client_identifier', 'string', [
+ 'notnull' => true,
+ 'length' => 64,
+ 'default' => ''
+ ]);
+ $table->addIndex(['client_identifier'], 'oauth2_client_id_idx');
+ }
+
+ $this->db->migrateToSchema($schema->getWrappedSchema());
+
+
+ if ($schema->getTable('oauth2_clients')->hasColumn('identifier')) {
+ $output->info("Move identifier column's data to the new client_identifier column.");
+ // 1. Fetch all [id, identifier] couple.
+ $selectQuery = $this->db->getQueryBuilder();
+ $selectQuery->select('id', 'identifier')->from('oauth2_clients');
+ $result = $selectQuery->executeQuery();
+ $identifiers = $result->fetchAll();
+ $result->closeCursor();
+
+ // 2. Insert them into the client_identifier column.
+ foreach ($identifiers as ["id" => $id, "identifier" => $clientIdentifier]) {
+ $insertQuery = $this->db->getQueryBuilder();
+ $insertQuery->update('oauth2_clients')
+ ->set('client_identifier', $insertQuery->createNamedParameter($clientIdentifier, IQueryBuilder::PARAM_STR))
+ ->where($insertQuery->expr()->eq('id', $insertQuery->createNamedParameter($id, IQueryBuilder::PARAM_INT)))
+ ->executeStatement();
+ }
+
+ $output->info("Drop the identifier column.");
+ $schema = new SchemaWrapper($this->db);
+ $table = $schema->getTable('oauth2_clients');
+ $table->dropColumn('identifier');
+ $this->db->migrateToSchema($schema->getWrappedSchema());
+ }
+ }
+}
diff --git a/lib/private/Route/CachingRouter.php b/lib/private/Route/CachingRouter.php
index 553ea285fd4..f65060e710b 100644
--- a/lib/private/Route/CachingRouter.php
+++ b/lib/private/Route/CachingRouter.php
@@ -24,7 +24,7 @@
*/
namespace OC\Route;
-use OCP\ILogger;
+use Psr\Log\LoggerInterface;
class CachingRouter extends Router {
/**
@@ -34,9 +34,8 @@ class CachingRouter extends Router {
/**
* @param \OCP\ICache $cache
- * @param ILogger $logger
*/
- public function __construct($cache, ILogger $logger) {
+ public function __construct($cache, LoggerInterface $logger) {
$this->cache = $cache;
parent::__construct($logger);
}
diff --git a/lib/private/Route/Router.php b/lib/private/Route/Router.php
index fcde8f08897..b957173cacc 100644
--- a/lib/private/Route/Router.php
+++ b/lib/private/Route/Router.php
@@ -34,9 +34,9 @@ namespace OC\Route;
use OC\AppFramework\Routing\RouteParser;
use OCP\AppFramework\App;
-use OCP\ILogger;
use OCP\Route\IRouter;
use OCP\Util;
+use Psr\Log\LoggerInterface;
use Symfony\Component\Routing\Exception\ResourceNotFoundException;
use Symfony\Component\Routing\Exception\RouteNotFoundException;
use Symfony\Component\Routing\Generator\UrlGenerator;
@@ -61,15 +61,11 @@ class Router implements IRouter {
protected $loaded = false;
/** @var array */
protected $loadedApps = [];
- /** @var ILogger */
- protected $logger;
+ protected LoggerInterface $logger;
/** @var RequestContext */
protected $context;
- /**
- * @param ILogger $logger
- */
- public function __construct(ILogger $logger) {
+ public function __construct(LoggerInterface $logger) {
$this->logger = $logger;
$baseUrl = \OC::$WEBROOT;
if (!(\OC::$server->getConfig()->getSystemValue('htaccess.IgnoreFrontController', false) === true || getenv('front_controller_active') === 'true')) {
@@ -364,7 +360,7 @@ class Router implements IRouter {
try {
return $this->getGenerator()->generate($name, $parameters, $referenceType);
} catch (RouteNotFoundException $e) {
- $this->logger->logException($e, ['level' => ILogger::INFO]);
+ $this->logger->info($e->getMessage(), ['exception' => $e]);
return '';
}
}
diff --git a/lib/private/Search/SearchComposer.php b/lib/private/Search/SearchComposer.php
index d5f35f504e0..3c228261ec2 100644
--- a/lib/private/Search/SearchComposer.php
+++ b/lib/private/Search/SearchComposer.php
@@ -28,14 +28,14 @@ declare(strict_types=1);
namespace OC\Search;
use InvalidArgumentException;
-use OC\AppFramework\Bootstrap\Coordinator;
use OCP\AppFramework\QueryException;
-use OCP\ILogger;
use OCP\IServerContainer;
use OCP\IUser;
use OCP\Search\IProvider;
use OCP\Search\ISearchQuery;
use OCP\Search\SearchResult;
+use OC\AppFramework\Bootstrap\Coordinator;
+use Psr\Log\LoggerInterface;
use function array_map;
/**
@@ -68,12 +68,11 @@ class SearchComposer {
/** @var IServerContainer */
private $container;
- /** @var ILogger */
- private $logger;
+ private LoggerInterface $logger;
public function __construct(Coordinator $bootstrapCoordinator,
IServerContainer $container,
- ILogger $logger) {
+ LoggerInterface $logger) {
$this->container = $container;
$this->logger = $logger;
$this->bootstrapCoordinator = $bootstrapCoordinator;
@@ -99,9 +98,8 @@ class SearchComposer {
$this->providers[$provider->getId()] = $provider;
} catch (QueryException $e) {
// Log an continue. We can be fault tolerant here.
- $this->logger->logException($e, [
- 'message' => 'Could not load search provider dynamically: ' . $e->getMessage(),
- 'level' => ILogger::ERROR,
+ $this->logger->error('Could not load search provider dynamically: ' . $e->getMessage(), [
+ 'exception' => $e,
'app' => $registration->getAppId(),
]);
}
diff --git a/lib/private/Security/Bruteforce/Throttler.php b/lib/private/Security/Bruteforce/Throttler.php
index abbe77c6637..c47d102b881 100644
--- a/lib/private/Security/Bruteforce/Throttler.php
+++ b/lib/private/Security/Bruteforce/Throttler.php
@@ -36,8 +36,8 @@ use OC\Security\Normalizer\IpAddress;
use OCP\AppFramework\Utility\ITimeFactory;
use OCP\IConfig;
use OCP\IDBConnection;
-use OCP\ILogger;
use OCP\Security\Bruteforce\MaxDelayReached;
+use Psr\Log\LoggerInterface;
/**
* Class Throttler implements the bruteforce protection for security actions in
@@ -62,22 +62,15 @@ class Throttler {
private $db;
/** @var ITimeFactory */
private $timeFactory;
- /** @var ILogger */
- private $logger;
+ private LoggerInterface $logger;
/** @var IConfig */
private $config;
/** @var bool */
private $hasAttemptsDeleted = false;
- /**
- * @param IDBConnection $db
- * @param ITimeFactory $timeFactory
- * @param ILogger $logger
- * @param IConfig $config
- */
public function __construct(IDBConnection $db,
ITimeFactory $timeFactory,
- ILogger $logger,
+ LoggerInterface $logger,
IConfig $config) {
$this->db = $db;
$this->timeFactory = $timeFactory;
diff --git a/lib/private/Security/CertificateManager.php b/lib/private/Security/CertificateManager.php
index 6f3b01e23b9..fa26c19ceae 100644
--- a/lib/private/Security/CertificateManager.php
+++ b/lib/private/Security/CertificateManager.php
@@ -36,8 +36,8 @@ use OC\Files\Filesystem;
use OCP\ICertificate;
use OCP\ICertificateManager;
use OCP\IConfig;
-use OCP\ILogger;
use OCP\Security\ISecureRandom;
+use Psr\Log\LoggerInterface;
/**
* Manage trusted certificates for users
@@ -53,23 +53,16 @@ class CertificateManager implements ICertificateManager {
*/
protected $config;
- /**
- * @var ILogger
- */
- protected $logger;
+ protected LoggerInterface $logger;
/** @var ISecureRandom */
protected $random;
- /**
- * @param \OC\Files\View $view relative to data/
- * @param IConfig $config
- * @param ILogger $logger
- * @param ISecureRandom $random
- */
+ private ?string $bundlePath = null;
+
public function __construct(\OC\Files\View $view,
IConfig $config,
- ILogger $logger,
+ LoggerInterface $logger,
ISecureRandom $random) {
$this->view = $view;
$this->config = $config;
@@ -145,7 +138,8 @@ class CertificateManager implements ICertificateManager {
$defaultCertificates = file_get_contents(\OC::$SERVERROOT . '/resources/config/ca-bundle.crt');
if (strlen($defaultCertificates) < 1024) { // sanity check to verify that we have some content for our bundle
// log as exception so we have a stacktrace
- $this->logger->logException(new \Exception('Shipped ca-bundle is empty, refusing to create certificate bundle'));
+ $e = new \Exception('Shipped ca-bundle is empty, refusing to create certificate bundle');
+ $this->logger->error($e->getMessage(), ['exception' => $e]);
return;
}
@@ -190,6 +184,7 @@ class CertificateManager implements ICertificateManager {
if (!Filesystem::isValidPath($name) or Filesystem::isFileBlacklisted($name)) {
throw new \Exception('Filename is not valid');
}
+ $this->bundlePath = null;
$dir = $this->getPathToCertificates() . 'uploads/';
if (!$this->view->file_exists($dir)) {
@@ -217,6 +212,8 @@ class CertificateManager implements ICertificateManager {
if (!Filesystem::isValidPath($name)) {
return false;
}
+ $this->bundlePath = null;
+
$path = $this->getPathToCertificates() . 'uploads/';
if ($this->view->file_exists($path . $name)) {
$this->view->unlink($path . $name);
@@ -241,15 +238,18 @@ class CertificateManager implements ICertificateManager {
*/
public function getAbsoluteBundlePath(): string {
try {
- if (!$this->hasCertificates()) {
- return \OC::$SERVERROOT . '/resources/config/ca-bundle.crt';
- }
+ if (!$this->bundlePath) {
+ if (!$this->hasCertificates()) {
+ $this->bundlePath = \OC::$SERVERROOT . '/resources/config/ca-bundle.crt';
+ }
- if ($this->needsRebundling()) {
- $this->createCertificateBundle();
- }
+ if ($this->needsRebundling()) {
+ $this->createCertificateBundle();
+ }
- return $this->view->getLocalFile($this->getCertificateBundle());
+ $this->bundlePath = $this->view->getLocalFile($this->getCertificateBundle());
+ }
+ return $this->bundlePath;
} catch (\Exception $e) {
return \OC::$SERVERROOT . '/resources/config/ca-bundle.crt';
}
diff --git a/lib/private/Security/IdentityProof/Manager.php b/lib/private/Security/IdentityProof/Manager.php
index 0878efeebc7..c92d7390969 100644
--- a/lib/private/Security/IdentityProof/Manager.php
+++ b/lib/private/Security/IdentityProof/Manager.php
@@ -32,9 +32,9 @@ namespace OC\Security\IdentityProof;
use OC\Files\AppData\Factory;
use OCP\Files\IAppData;
use OCP\IConfig;
-use OCP\ILogger;
use OCP\IUser;
use OCP\Security\ICrypto;
+use Psr\Log\LoggerInterface;
class Manager {
/** @var IAppData */
@@ -43,13 +43,12 @@ class Manager {
private $crypto;
/** @var IConfig */
private $config;
- /** @var ILogger */
- private $logger;
+ private LoggerInterface $logger;
public function __construct(Factory $appDataFactory,
ICrypto $crypto,
IConfig $config,
- ILogger $logger
+ LoggerInterface $logger
) {
$this->appData = $appDataFactory->get('identityproof');
$this->crypto = $crypto;
diff --git a/lib/private/Server.php b/lib/private/Server.php
index 00afaf1d6a9..b214ba3ce54 100644
--- a/lib/private/Server.php
+++ b/lib/private/Server.php
@@ -60,6 +60,7 @@ use OC\App\AppStore\Fetcher\AppFetcher;
use OC\App\AppStore\Fetcher\CategoryFetcher;
use OC\AppFramework\Bootstrap\Coordinator;
use OC\AppFramework\Http\Request;
+use OC\AppFramework\Http\RequestId;
use OC\AppFramework\Utility\TimeFactory;
use OC\Authentication\Events\LoginFailed;
use OC\Authentication\Listeners\LoginFailedListener;
@@ -205,6 +206,7 @@ use OCP\ILogger;
use OCP\INavigationManager;
use OCP\IPreview;
use OCP\IRequest;
+use OCP\IRequestId;
use OCP\ISearch;
use OCP\IServerContainer;
use OCP\ISession;
@@ -258,6 +260,8 @@ use OCA\Files_External\Service\UserStoragesService;
use OCA\Files_External\Service\UserGlobalStoragesService;
use OCA\Files_External\Service\GlobalStoragesService;
use OCA\Files_External\Service\BackendService;
+use OCP\Profiler\IProfiler;
+use OC\Profiler\Profiler;
/**
* Class Server
@@ -342,6 +346,10 @@ class Server extends ServerContainer implements IServerContainer {
);
});
+ $this->registerService(IProfiler::class, function (Server $c) {
+ return new Profiler($c->get(SystemConfig::class));
+ });
+
$this->registerService(\OCP\Encryption\IManager::class, function (Server $c) {
$view = new View();
$util = new Encryption\Util(
@@ -352,7 +360,7 @@ class Server extends ServerContainer implements IServerContainer {
);
return new Encryption\Manager(
$c->get(\OCP\IConfig::class),
- $c->get(ILogger::class),
+ $c->get(LoggerInterface::class),
$c->getL10N('core'),
new View(),
$util,
@@ -426,7 +434,7 @@ class Server extends ServerContainer implements IServerContainer {
$view,
null,
$c->get(IUserMountCache::class),
- $this->get(ILogger::class),
+ $this->get(LoggerInterface::class),
$this->get(IUserManager::class),
$this->get(IEventDispatcher::class),
);
@@ -464,7 +472,11 @@ class Server extends ServerContainer implements IServerContainer {
$this->registerAlias(\OCP\IUserManager::class, \OC\User\Manager::class);
$this->registerService(\OCP\IGroupManager::class, function (ContainerInterface $c) {
- $groupManager = new \OC\Group\Manager($this->get(IUserManager::class), $c->get(SymfonyAdapter::class), $this->get(ILogger::class));
+ $groupManager = new \OC\Group\Manager(
+ $this->get(IUserManager::class),
+ $c->get(SymfonyAdapter::class),
+ $this->get(LoggerInterface::class)
+ );
$groupManager->listen('\OC\Group', 'preCreate', function ($gid) {
/** @var IEventDispatcher $dispatcher */
$dispatcher = $this->get(IEventDispatcher::class);
@@ -545,7 +557,7 @@ class Server extends ServerContainer implements IServerContainer {
$c->get(\OCP\IConfig::class),
$c->get(ISecureRandom::class),
$c->getLockdownManager(),
- $c->get(ILogger::class),
+ $c->get(LoggerInterface::class),
$c->get(IEventDispatcher::class)
);
/** @deprecated 21.0.0 use BeforeUserCreatedEvent event with the IEventDispatcher instead */
@@ -685,7 +697,9 @@ class Server extends ServerContainer implements IServerContainer {
$this->registerDeprecatedAlias('UserCache', ICache::class);
$this->registerService(Factory::class, function (Server $c) {
- $arrayCacheFactory = new \OC\Memcache\Factory('', $c->get(ILogger::class),
+ $profiler = $c->get(IProfiler::class);
+ $arrayCacheFactory = new \OC\Memcache\Factory('', $c->get(LoggerInterface::class),
+ $profiler,
ArrayCache::class,
ArrayCache::class,
ArrayCache::class
@@ -709,7 +723,9 @@ class Server extends ServerContainer implements IServerContainer {
$instanceId = \OC_Util::getInstanceId();
$path = \OC::$SERVERROOT;
$prefix = md5($instanceId . '-' . $version . '-' . $path);
- return new \OC\Memcache\Factory($prefix, $c->get(ILogger::class),
+ return new \OC\Memcache\Factory($prefix,
+ $c->get(LoggerInterface::class),
+ $profiler,
$config->getSystemValue('memcache.local', null),
$config->getSystemValue('memcache.distributed', null),
$config->getSystemValue('memcache.locking', null),
@@ -759,6 +775,7 @@ class Server extends ServerContainer implements IServerContainer {
$c->get(KnownUserService::class)
);
});
+
$this->registerAlias(IAvatarManager::class, AvatarManager::class);
/** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('AvatarManager', AvatarManager::class);
@@ -790,7 +807,7 @@ class Server extends ServerContainer implements IServerContainer {
$this->registerService(Router::class, function (Server $c) {
$cacheFactory = $c->get(ICacheFactory::class);
- $logger = $c->get(ILogger::class);
+ $logger = $c->get(LoggerInterface::class);
if ($cacheFactory->isLocalCacheAvailable()) {
$router = new \OC\Route\CachingRouter($cacheFactory->createLocal('route'), $logger);
} else {
@@ -851,7 +868,6 @@ class Server extends ServerContainer implements IServerContainer {
}
$connectionParams = $factory->createConnectionParams();
$connection = $factory->getConnection($type, $connectionParams);
- $connection->getConfiguration()->setSQLLogger($c->getQueryLogger());
return $connection;
});
/** @deprecated 19.0.0 */
@@ -861,7 +877,7 @@ class Server extends ServerContainer implements IServerContainer {
$this->registerAlias(IClientService::class, ClientService::class);
$this->registerService(LocalAddressChecker::class, function (ContainerInterface $c) {
return new LocalAddressChecker(
- $c->get(ILogger::class),
+ $c->get(LoggerInterface::class),
);
});
$this->registerService(NegativeDnsCache::class, function (ContainerInterface $c) {
@@ -932,7 +948,7 @@ class Server extends ServerContainer implements IServerContainer {
$mountCache = new UserMountCache(
$c->get(IDBConnection::class),
$c->get(IUserManager::class),
- $c->get(ILogger::class)
+ $c->get(LoggerInterface::class)
);
$listener = new UserMountCacheListener($mountCache);
$listener->listen($c->get(IUserManager::class));
@@ -949,7 +965,7 @@ class Server extends ServerContainer implements IServerContainer {
// builtin providers
$config = $c->get(\OCP\IConfig::class);
- $logger = $c->get(ILogger::class);
+ $logger = $c->get(LoggerInterface::class);
$manager->registerProvider(new CacheMountProvider($config));
$manager->registerHomeProvider(new LocalHomeMountProvider());
$manager->registerHomeProvider(new ObjectHomeMountProvider($config));
@@ -1033,7 +1049,7 @@ class Server extends ServerContainer implements IServerContainer {
: '',
'urlParams' => $urlParams,
],
- $this->get(ISecureRandom::class),
+ $this->get(IRequestId::class),
$this->get(\OCP\IConfig::class),
$this->get(CsrfTokenManager::class),
$stream
@@ -1042,10 +1058,17 @@ class Server extends ServerContainer implements IServerContainer {
/** @deprecated 19.0.0 */
$this->registerDeprecatedAlias('Request', \OCP\IRequest::class);
+ $this->registerService(IRequestId::class, function (ContainerInterface $c): IRequestId {
+ return new RequestId(
+ $_SERVER['UNIQUE_ID'] ?? '',
+ $this->get(ISecureRandom::class)
+ );
+ });
+
$this->registerService(IMailer::class, function (Server $c) {
return new Mailer(
$c->get(\OCP\IConfig::class),
- $c->get(ILogger::class),
+ $c->get(LoggerInterface::class),
$c->get(Defaults::class),
$c->get(IURLGenerator::class),
$c->getL10N('lib'),
@@ -1085,7 +1108,7 @@ class Server extends ServerContainer implements IServerContainer {
}
return new DBLockingProvider(
$c->get(IDBConnection::class),
- $c->get(ILogger::class),
+ $c->get(LoggerInterface::class),
new TimeFactory(),
$ttl,
!\OC::$CLI
@@ -1108,7 +1131,7 @@ class Server extends ServerContainer implements IServerContainer {
$this->registerService(IMimeTypeDetector::class, function (ContainerInterface $c) {
return new \OC\Files\Type\Detection(
$c->get(IURLGenerator::class),
- $c->get(ILogger::class),
+ $c->get(LoggerInterface::class),
\OC::$configDir,
\OC::$SERVERROOT . '/resources/config/'
);
@@ -1205,7 +1228,7 @@ class Server extends ServerContainer implements IServerContainer {
$c->get(IURLGenerator::class),
$this->get(ICacheFactory::class),
$c->get(SystemConfig::class),
- $c->get(ILogger::class)
+ $c->get(LoggerInterface::class)
);
});
$this->registerAlias(\OCP\EventDispatcher\IEventDispatcher::class, \OC\EventDispatcher\EventDispatcher::class);
@@ -1214,7 +1237,7 @@ class Server extends ServerContainer implements IServerContainer {
$this->registerAlias(EventDispatcherInterface::class, \OC\EventDispatcher\SymfonyAdapter::class);
$this->registerService('CryptoWrapper', function (ContainerInterface $c) {
- // FIXME: Instantiiated here due to cyclic dependency
+ // FIXME: Instantiated here due to cyclic dependency
$request = new Request(
[
'get' => $_GET,
@@ -1227,7 +1250,7 @@ class Server extends ServerContainer implements IServerContainer {
? $_SERVER['REQUEST_METHOD']
: null,
],
- $c->get(ISecureRandom::class),
+ $c->get(IRequestId::class),
$c->get(\OCP\IConfig::class)
);
@@ -1254,7 +1277,7 @@ class Server extends ServerContainer implements IServerContainer {
$factory = new $factoryClass($this);
$manager = new \OC\Share20\Manager(
- $c->get(ILogger::class),
+ $c->get(LoggerInterface::class),
$c->get(\OCP\IConfig::class),
$c->get(ISecureRandom::class),
$c->get(IHasher::class),
@@ -1333,7 +1356,7 @@ class Server extends ServerContainer implements IServerContainer {
$c->get(IAppManager::class),
$c->get(IClientService::class),
$c->get(ICloudIdManager::class),
- $c->get(ILogger::class)
+ $c->get(LoggerInterface::class)
);
});
@@ -1442,7 +1465,7 @@ class Server extends ServerContainer implements IServerContainer {
// Delete avatar on user deletion
$dispatcher->addListener('OCP\IUser::preDelete', function (GenericEvent $e) {
- $logger = $this->get(ILogger::class);
+ $logger = $this->get(LoggerInterface::class);
$manager = $this->getAvatarManager();
/** @var IUser $user */
$user = $e->getSubject();
@@ -2351,8 +2374,8 @@ class Server extends ServerContainer implements IServerContainer {
private function registerDeprecatedAlias(string $alias, string $target) {
$this->registerService($alias, function (ContainerInterface $container) use ($target, $alias) {
try {
- /** @var ILogger $logger */
- $logger = $container->get(ILogger::class);
+ /** @var LoggerInterface $logger */
+ $logger = $container->get(LoggerInterface::class);
$logger->debug('The requested alias "' . $alias . '" is deprecated. Please request "' . $target . '" directly. This alias will be removed in a future Nextcloud version.', ['app' => 'serverDI']);
} catch (ContainerExceptionInterface $e) {
// Could not get logger. Continue
diff --git a/lib/private/Share20/Manager.php b/lib/private/Share20/Manager.php
index b634d41a640..3fca9e3fe14 100644
--- a/lib/private/Share20/Manager.php
+++ b/lib/private/Share20/Manager.php
@@ -57,7 +57,6 @@ use OCP\HintException;
use OCP\IConfig;
use OCP\IGroupManager;
use OCP\IL10N;
-use OCP\ILogger;
use OCP\IURLGenerator;
use OCP\IUser;
use OCP\IUserManager;
@@ -75,6 +74,7 @@ use OCP\Share\IManager;
use OCP\Share\IProviderFactory;
use OCP\Share\IShare;
use OCP\Share\IShareProvider;
+use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\EventDispatcher\GenericEvent;
@@ -85,8 +85,7 @@ class Manager implements IManager {
/** @var IProviderFactory */
private $factory;
- /** @var ILogger */
- private $logger;
+ private LoggerInterface $logger;
/** @var IConfig */
private $config;
/** @var ISecureRandom */
@@ -125,7 +124,7 @@ class Manager implements IManager {
private $knownUserService;
public function __construct(
- ILogger $logger,
+ LoggerInterface $logger,
IConfig $config,
ISecureRandom $secureRandom,
IHasher $hasher,
@@ -951,7 +950,7 @@ class Manager implements IManager {
return;
}
} catch (\Exception $e) {
- $this->logger->logException($e, ['message' => 'Share notification mail could not be sent']);
+ $this->logger->error('Share notification mail could not be sent', ['exception' => $e]);
}
}
diff --git a/lib/private/Template/CSSResourceLocator.php b/lib/private/Template/CSSResourceLocator.php
index 9ee11e723e5..a038ba7ce9b 100644
--- a/lib/private/Template/CSSResourceLocator.php
+++ b/lib/private/Template/CSSResourceLocator.php
@@ -31,7 +31,7 @@
*/
namespace OC\Template;
-use OCP\ILogger;
+use Psr\Log\LoggerInterface;
class CSSResourceLocator extends ResourceLocator {
@@ -39,13 +39,12 @@ class CSSResourceLocator extends ResourceLocator {
protected $scssCacher;
/**
- * @param ILogger $logger
* @param string $theme
* @param array $core_map
* @param array $party_map
* @param SCSSCacher $scssCacher
*/
- public function __construct(ILogger $logger, $theme, $core_map, $party_map, $scssCacher) {
+ public function __construct(LoggerInterface $logger, $theme, $core_map, $party_map, $scssCacher) {
$this->scssCacher = $scssCacher;
parent::__construct($logger, $theme, $core_map, $party_map);
diff --git a/lib/private/Template/IconsCacher.php b/lib/private/Template/IconsCacher.php
index 01500aa2e9c..c2956d5712a 100644
--- a/lib/private/Template/IconsCacher.php
+++ b/lib/private/Template/IconsCacher.php
@@ -36,13 +36,11 @@ use OCP\Files\IAppData;
use OCP\Files\NotFoundException;
use OCP\Files\SimpleFS\ISimpleFile;
use OCP\Files\SimpleFS\ISimpleFolder;
-use OCP\ILogger;
use OCP\IURLGenerator;
+use Psr\Log\LoggerInterface;
class IconsCacher {
-
- /** @var ILogger */
- protected $logger;
+ protected LoggerInterface $logger;
/** @var IAppData */
protected $appData;
@@ -68,13 +66,9 @@ class IconsCacher {
private $cachedList;
/**
- * @param ILogger $logger
- * @param Factory $appDataFactory
- * @param IURLGenerator $urlGenerator
- * @param ITimeFactory $timeFactory
* @throws \OCP\Files\NotPermittedException
*/
- public function __construct(ILogger $logger,
+ public function __construct(LoggerInterface $logger,
Factory $appDataFactory,
IURLGenerator $urlGenerator,
ITimeFactory $timeFactory) {
diff --git a/lib/private/Template/JSCombiner.php b/lib/private/Template/JSCombiner.php
index d2073fbbb83..a6d9f0ee558 100644
--- a/lib/private/Template/JSCombiner.php
+++ b/lib/private/Template/JSCombiner.php
@@ -33,8 +33,8 @@ use OCP\Files\NotPermittedException;
use OCP\Files\SimpleFS\ISimpleFolder;
use OCP\ICache;
use OCP\ICacheFactory;
-use OCP\ILogger;
use OCP\IURLGenerator;
+use Psr\Log\LoggerInterface;
class JSCombiner {
@@ -50,24 +50,16 @@ class JSCombiner {
/** @var SystemConfig */
protected $config;
- /** @var ILogger */
- protected $logger;
+ protected LoggerInterface $logger;
/** @var ICacheFactory */
private $cacheFactory;
- /**
- * @param IAppData $appData
- * @param IURLGenerator $urlGenerator
- * @param ICacheFactory $cacheFactory
- * @param SystemConfig $config
- * @param ILogger $logger
- */
public function __construct(IAppData $appData,
IURLGenerator $urlGenerator,
ICacheFactory $cacheFactory,
SystemConfig $config,
- ILogger $logger) {
+ LoggerInterface $logger) {
$this->appData = $appData;
$this->urlGenerator = $urlGenerator;
$this->cacheFactory = $cacheFactory;
diff --git a/lib/private/Template/JSResourceLocator.php b/lib/private/Template/JSResourceLocator.php
index bf84e1ae958..95ae0d3d832 100644
--- a/lib/private/Template/JSResourceLocator.php
+++ b/lib/private/Template/JSResourceLocator.php
@@ -27,12 +27,14 @@
*/
namespace OC\Template;
+use Psr\Log\LoggerInterface;
+
class JSResourceLocator extends ResourceLocator {
/** @var JSCombiner */
protected $jsCombiner;
- public function __construct(\OCP\ILogger $logger, $theme, array $core_map, array $party_map, JSCombiner $JSCombiner) {
+ public function __construct(LoggerInterface $logger, $theme, array $core_map, array $party_map, JSCombiner $JSCombiner) {
parent::__construct($logger, $theme, $core_map, $party_map);
$this->jsCombiner = $JSCombiner;
diff --git a/lib/private/Template/ResourceLocator.php b/lib/private/Template/ResourceLocator.php
index 3ca34259907..5a50cc6fd1b 100755
--- a/lib/private/Template/ResourceLocator.php
+++ b/lib/private/Template/ResourceLocator.php
@@ -29,6 +29,8 @@
*/
namespace OC\Template;
+use Psr\Log\LoggerInterface;
+
abstract class ResourceLocator {
protected $theme;
@@ -39,16 +41,14 @@ abstract class ResourceLocator {
protected $resources = [];
- /** @var \OCP\ILogger */
- protected $logger;
+ protected LoggerInterface $logger;
/**
- * @param \OCP\ILogger $logger
* @param string $theme
* @param array $core_map
* @param array $party_map
*/
- public function __construct(\OCP\ILogger $logger, $theme, $core_map, $party_map) {
+ public function __construct(LoggerInterface $logger, $theme, $core_map, $party_map) {
$this->logger = $logger;
$this->theme = $theme;
$this->mapping = $core_map + $party_map;
diff --git a/lib/private/Template/SCSSCacher.php b/lib/private/Template/SCSSCacher.php
index 536557e7a3d..a552122b358 100644
--- a/lib/private/Template/SCSSCacher.php
+++ b/lib/private/Template/SCSSCacher.php
@@ -41,16 +41,14 @@ use OCP\Files\SimpleFS\ISimpleFolder;
use OCP\ICache;
use OCP\ICacheFactory;
use OCP\IConfig;
-use OCP\ILogger;
use OCP\IMemcache;
use OCP\IURLGenerator;
+use Psr\Log\LoggerInterface;
use ScssPhp\ScssPhp\Compiler;
use ScssPhp\ScssPhp\OutputStyle;
class SCSSCacher {
-
- /** @var ILogger */
- protected $logger;
+ protected LoggerInterface $logger;
/** @var IAppData */
protected $appData;
@@ -91,17 +89,9 @@ class SCSSCacher {
private $appConfig;
/**
- * @param ILogger $logger
- * @param Factory $appDataFactory
- * @param IURLGenerator $urlGenerator
- * @param IConfig $config
- * @param \OC_Defaults $defaults
* @param string $serverRoot
- * @param ICacheFactory $cacheFactory
- * @param IconsCacher $iconsCacher
- * @param ITimeFactory $timeFactory
*/
- public function __construct(ILogger $logger,
+ public function __construct(LoggerInterface $logger,
Factory $appDataFactory,
IURLGenerator $urlGenerator,
IConfig $config,
@@ -340,7 +330,7 @@ class SCSSCacher {
'@import "functions.scss";' .
'@import "' . $fileNameSCSS . '";');
} catch (\Exception $e) {
- $this->logger->logException($e, ['app' => 'scss_cacher']);
+ $this->logger->error($e->getMessage(), ['app' => 'scss_cacher', 'exception' => $e]);
return false;
}
@@ -395,7 +385,7 @@ class SCSSCacher {
try {
$file->delete();
} catch (NotPermittedException $e) {
- $this->logger->logException($e, ['message' => 'SCSSCacher::resetCache unable to delete file: ' . $file->getName(), 'app' => 'scss_cacher']);
+ $this->logger->error('SCSSCacher::resetCache unable to delete file: ' . $file->getName(), ['exception' => $e, 'app' => 'scss_cacher']);
}
}
}
@@ -431,7 +421,7 @@ class SCSSCacher {
$scss->compile($variables);
$this->injectedVariables = $variables;
} catch (\Exception $e) {
- $this->logger->logException($e, ['app' => 'scss_cacher']);
+ $this->logger->error($e->getMessage(), ['exception' => $e, 'app' => 'scss_cacher']);
}
return $variables;
diff --git a/lib/private/TemplateLayout.php b/lib/private/TemplateLayout.php
index d7a86ff92bf..cf06f021590 100644
--- a/lib/private/TemplateLayout.php
+++ b/lib/private/TemplateLayout.php
@@ -57,6 +57,7 @@ use OCP\IUserSession;
use OCP\Support\Subscription\IRegistry;
use OCP\UserStatus\IManager as IUserStatusManager;
use OCP\Util;
+use Psr\Log\LoggerInterface;
class TemplateLayout extends \OC_Template {
private static $versionHash = '';
@@ -345,7 +346,7 @@ class TemplateLayout extends \OC_Template {
}
$locator = new \OC\Template\CSSResourceLocator(
- \OC::$server->getLogger(),
+ \OC::$server->get(LoggerInterface::class),
$theme,
[ \OC::$SERVERROOT => \OC::$WEBROOT ],
[ \OC::$SERVERROOT => \OC::$WEBROOT ],
@@ -380,7 +381,7 @@ class TemplateLayout extends \OC_Template {
$theme = \OC_Util::getTheme();
$locator = new \OC\Template\JSResourceLocator(
- \OC::$server->getLogger(),
+ \OC::$server->get(LoggerInterface::class),
$theme,
[ \OC::$SERVERROOT => \OC::$WEBROOT ],
[ \OC::$SERVERROOT => \OC::$WEBROOT ],
diff --git a/lib/private/Updater/ChangesCheck.php b/lib/private/Updater/ChangesCheck.php
index e3ced6e5b12..e2b66853788 100644
--- a/lib/private/Updater/ChangesCheck.php
+++ b/lib/private/Updater/ChangesCheck.php
@@ -30,21 +30,20 @@ namespace OC\Updater;
use OCP\AppFramework\Db\DoesNotExistException;
use OCP\Http\Client\IClientService;
use OCP\Http\Client\IResponse;
-use OCP\ILogger;
+use Psr\Log\LoggerInterface;
class ChangesCheck {
/** @var IClientService */
protected $clientService;
/** @var ChangesMapper */
private $mapper;
- /** @var ILogger */
- private $logger;
+ private LoggerInterface $logger;
public const RESPONSE_NO_CONTENT = 0;
public const RESPONSE_USE_CACHE = 1;
public const RESPONSE_HAS_CONTENT = 2;
- public function __construct(IClientService $clientService, ChangesMapper $mapper, ILogger $logger) {
+ public function __construct(IClientService $clientService, ChangesMapper $mapper, LoggerInterface $logger) {
$this->clientService = $clientService;
$this->mapper = $mapper;
$this->logger = $logger;
diff --git a/lib/private/User/Session.php b/lib/private/User/Session.php
index cd26337cd20..365a01c4595 100644
--- a/lib/private/User/Session.php
+++ b/lib/private/User/Session.php
@@ -54,7 +54,6 @@ use OCP\AppFramework\Utility\ITimeFactory;
use OCP\EventDispatcher\IEventDispatcher;
use OCP\Files\NotPermittedException;
use OCP\IConfig;
-use OCP\ILogger;
use OCP\IRequest;
use OCP\ISession;
use OCP\IUser;
@@ -64,6 +63,7 @@ use OCP\Security\ISecureRandom;
use OCP\Session\Exceptions\SessionNotAvailableException;
use OCP\User\Events\PostLoginEvent;
use OCP\Util;
+use Psr\Log\LoggerInterface;
use Symfony\Component\EventDispatcher\GenericEvent;
/**
@@ -114,21 +114,10 @@ class Session implements IUserSession, Emitter {
/** @var ILockdownManager */
private $lockdownManager;
- /** @var ILogger */
- private $logger;
+ private LoggerInterface $logger;
/** @var IEventDispatcher */
private $dispatcher;
- /**
- * @param Manager $manager
- * @param ISession $session
- * @param ITimeFactory $timeFactory
- * @param IProvider|null $tokenProvider
- * @param IConfig $config
- * @param ISecureRandom $random
- * @param ILockdownManager $lockdownManager
- * @param ILogger $logger
- */
public function __construct(Manager $manager,
ISession $session,
ITimeFactory $timeFactory,
@@ -136,7 +125,7 @@ class Session implements IUserSession, Emitter {
IConfig $config,
ISecureRandom $random,
ILockdownManager $lockdownManager,
- ILogger $logger,
+ LoggerInterface $logger,
IEventDispatcher $dispatcher
) {
$this->manager = $manager;
@@ -533,9 +522,8 @@ class Session implements IUserSession, Emitter {
} catch (ExpiredTokenException $e) {
throw $e;
} catch (InvalidTokenException $ex) {
- $this->logger->logException($ex, [
- 'level' => ILogger::DEBUG,
- 'message' => 'Token is not valid: ' . $ex->getMessage(),
+ $this->logger->debug('Token is not valid: ' . $ex->getMessage(), [
+ 'exception' => $ex,
]);
return false;
}
@@ -890,7 +878,7 @@ class Session implements IUserSession, Emitter {
} catch (SessionNotAvailableException $ex) {
return false;
} catch (InvalidTokenException $ex) {
- \OC::$server->getLogger()->warning('Renewing session token failed', ['app' => 'core']);
+ $this->logger->warning('Renewing session token failed', ['app' => 'core']);
return false;
}
diff --git a/lib/private/legacy/OC_Helper.php b/lib/private/legacy/OC_Helper.php
index efb9252e346..547ffef8607 100644
--- a/lib/private/legacy/OC_Helper.php
+++ b/lib/private/legacy/OC_Helper.php
@@ -485,7 +485,7 @@ class OC_Helper {
* @return array
* @throws \OCP\Files\NotFoundException
*/
- public static function getStorageInfo($path, $rootInfo = null) {
+ public static function getStorageInfo($path, $rootInfo = null, $includeMountPoints = true) {
// return storage info without adding mount points
$includeExtStorage = \OC::$server->getSystemConfig()->getValue('quota_include_external_storage', false);
@@ -495,7 +495,7 @@ class OC_Helper {
if (!$rootInfo instanceof \OCP\Files\FileInfo) {
throw new \OCP\Files\NotFoundException();
}
- $used = $rootInfo->getSize();
+ $used = $rootInfo->getSize($includeMountPoints);
if ($used < 0) {
$used = 0;
}
diff --git a/lib/private/legacy/OC_Response.php b/lib/private/legacy/OC_Response.php
index 6cfd53d2651..e4525fe9e10 100644
--- a/lib/private/legacy/OC_Response.php
+++ b/lib/private/legacy/OC_Response.php
@@ -97,7 +97,6 @@ class OC_Response {
if (getenv('modHeadersAvailable') !== 'true') {
header('Referrer-Policy: no-referrer'); // https://www.w3.org/TR/referrer-policy/
header('X-Content-Type-Options: nosniff'); // Disable sniffing the content type for IE
- header('X-Download-Options: noopen'); // https://msdn.microsoft.com/en-us/library/jj542450(v=vs.85).aspx
header('X-Frame-Options: SAMEORIGIN'); // Disallow iFraming from other domains
header('X-Permitted-Cross-Domain-Policies: none'); // https://www.adobe.com/devnet/adobe-media-server/articles/cross-domain-xml-for-streaming.html
header('X-Robots-Tag: none'); // https://developers.google.com/webmasters/control-crawl-index/docs/robots_meta_tag
diff --git a/lib/public/DB/QueryBuilder/IFunctionBuilder.php b/lib/public/DB/QueryBuilder/IFunctionBuilder.php
index 04c5cbd07bd..d4edc8ea9f8 100644
--- a/lib/public/DB/QueryBuilder/IFunctionBuilder.php
+++ b/lib/public/DB/QueryBuilder/IFunctionBuilder.php
@@ -124,6 +124,24 @@ interface IFunctionBuilder {
public function count($count = '', $alias = ''): IQueryFunction;
/**
+ * @param string|ILiteral|IParameter|IQueryFunction $field The input to be measured
+ * @param string $alias Alias for the length
+ *
+ * @return IQueryFunction
+ * @since 24.0.0
+ */
+ public function octetLength($field, $alias = ''): IQueryFunction;
+
+ /**
+ * @param string|ILiteral|IParameter|IQueryFunction $field The input to be measured
+ * @param string $alias Alias for the length
+ *
+ * @return IQueryFunction
+ * @since 24.0.0
+ */
+ public function charLength($field, $alias = ''): IQueryFunction;
+
+ /**
* Takes the maximum of all rows in a column
*
* If you want to get the maximum value of multiple columns in the same row, use `greatest` instead
diff --git a/lib/public/DataCollector/AbstractDataCollector.php b/lib/public/DataCollector/AbstractDataCollector.php
new file mode 100644
index 00000000000..68298671b7b
--- /dev/null
+++ b/lib/public/DataCollector/AbstractDataCollector.php
@@ -0,0 +1,87 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright 2022 Carl Schwan <carl@carlschwan.eu>
+ *
+ * @author Carl Schwan <carl@carlschwan.eu>
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @license AGPL-3.0-or-later AND MIT
+ *
+ * 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\DataCollector;
+
+/**
+ * Children of this class must store the collected data in
+ * the data property.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ * @author Bernhard Schussek <bschussek@symfony.com>
+ * @author Carl Schwan <carl@carlschwan.eu>
+ * @since 24.0.0
+ */
+abstract class AbstractDataCollector implements IDataCollector, \JsonSerializable {
+ /** @var array */
+ protected $data = [];
+
+ /**
+ * @since 24.0.0
+ */
+ public function getName(): string {
+ return static::class;
+ }
+
+ /**
+ * Reset the state of the profiler. By default it only empties the
+ * $this->data contents, but you can override this method to do
+ * additional cleaning.
+ * @since 24.0.0
+ */
+ public function reset(): void {
+ $this->data = [];
+ }
+
+ /**
+ * @since 24.0.0
+ */
+ public function __sleep(): array {
+ return ['data'];
+ }
+
+ /**
+ * @internal to prevent implementing \Serializable
+ * @since 24.0.0
+ */
+ final protected function serialize() {
+ }
+
+ /**
+ * @internal to prevent implementing \Serializable
+ * @since 24.0.0
+ */
+ final protected function unserialize(string $data) {
+ }
+
+ /**
+ * @since 24.0.0
+ */
+ #[\ReturnTypeWillChange]
+ public function jsonSerialize() {
+ return $this->data;
+ }
+}
diff --git a/lib/public/DataCollector/IDataCollector.php b/lib/public/DataCollector/IDataCollector.php
new file mode 100644
index 00000000000..0fb914727df
--- /dev/null
+++ b/lib/public/DataCollector/IDataCollector.php
@@ -0,0 +1,55 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright 2022 Carl Schwan <carl@carlschwan.eu>
+ *
+ * @author Carl Schwan <carl@carlschwan.eu>
+ * @author Fabien Potencier <fabien@symfony.com>
+ *
+ * @license AGPL-3.0-or-later AND MIT
+ *
+ * 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\DataCollector;
+
+use OC\AppFramework\Http\Request;
+use OCP\AppFramework\Http\Response;
+
+/**
+ * DataCollectorInterface.
+ *
+ * @since 24.0.0
+ */
+interface IDataCollector {
+ /**
+ * Collects data for the given Request and Response.
+ * @since 24.0.0
+ */
+ public function collect(Request $request, Response $response, \Throwable $exception = null): void;
+
+ /**
+ * Reset the state of the profiler.
+ * @since 24.0.0
+ */
+ public function reset(): void;
+
+ /**
+ * Returns the name of the collector.
+ * @since 24.0.0
+ */
+ public function getName(): string;
+}
diff --git a/lib/public/Files/Config/IMountProviderCollection.php b/lib/public/Files/Config/IMountProviderCollection.php
index f845d72cee6..2d42246b863 100644
--- a/lib/public/Files/Config/IMountProviderCollection.php
+++ b/lib/public/Files/Config/IMountProviderCollection.php
@@ -39,6 +39,16 @@ interface IMountProviderCollection {
public function getMountsForUser(IUser $user);
/**
+ * Get the configured mount points for the user from a specific mount provider
+ *
+ * @param \OCP\IUser $user
+ * @param class-string<IMountProvider>[] $mountProviderClasses
+ * @return \OCP\Files\Mount\IMountPoint[]
+ * @since 24.0.0
+ */
+ public function getUserMountsForProviderClasses(IUser $user, array $mountProviderClasses): array;
+
+ /**
* Get the configured home mount for this user
*
* @param \OCP\IUser $user
diff --git a/lib/public/Files/Config/IUserMountCache.php b/lib/public/Files/Config/IUserMountCache.php
index 08f95990d3c..4411200c7ae 100644
--- a/lib/public/Files/Config/IUserMountCache.php
+++ b/lib/public/Files/Config/IUserMountCache.php
@@ -25,6 +25,7 @@
namespace OCP\Files\Config;
use OCP\Files\Mount\IMountPoint;
+use OCP\Files\NotFoundException;
use OCP\IUser;
/**
@@ -38,9 +39,10 @@ interface IUserMountCache {
*
* @param IUser $user
* @param IMountPoint[] $mounts
+ * @param array|null $mountProviderClasses
* @since 9.0.0
*/
- public function registerMounts(IUser $user, array $mounts);
+ public function registerMounts(IUser $user, array $mounts, array $mountProviderClasses = null);
/**
* Get all cached mounts for a user
@@ -125,4 +127,26 @@ interface IUserMountCache {
* @since 20.0.0
*/
public function clear(): void;
+
+ /**
+ * Get all cached mounts for a user
+ *
+ * @param IUser $user
+ * @param string $path
+ * @return ICachedMountInfo
+ * @throws NotFoundException
+ * @since 24.0.0
+ */
+ public function getMountForPath(IUser $user, string $path): ICachedMountInfo;
+
+ /**
+ * Get all cached mounts for a user inside a path
+ *
+ * @param IUser $user
+ * @param string $path
+ * @return ICachedMountInfo[]
+ * @throws NotFoundException
+ * @since 24.0.0
+ */
+ public function getMountsInPath(IUser $user, string $path): array;
}
diff --git a/lib/public/Files/Events/InvalidateMountCacheEvent.php b/lib/public/Files/Events/InvalidateMountCacheEvent.php
new file mode 100644
index 00000000000..6508e168d4c
--- /dev/null
+++ b/lib/public/Files/Events/InvalidateMountCacheEvent.php
@@ -0,0 +1,55 @@
+<?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;
+
+use OCP\EventDispatcher\Event;
+use OCP\IUser;
+
+/**
+ * Used to notify the filesystem setup manager that the available mounts for a user have changed
+ *
+ * @since 24.0.0
+ */
+class InvalidateMountCacheEvent extends Event {
+ private ?IUser $user;
+
+ /**
+ * @param IUser|null $user user
+ *
+ * @since 24.0.0
+ */
+ public function __construct(?IUser $user) {
+ parent::__construct();
+ $this->user = $user;
+ }
+
+ /**
+ * @return IUser|null user
+ *
+ * @since 24.0.0
+ */
+ public function getUser(): ?IUser {
+ return $this->user;
+ }
+}
diff --git a/lib/public/Files/IRootFolder.php b/lib/public/Files/IRootFolder.php
index f89a0041146..7d007cb690c 100644
--- a/lib/public/Files/IRootFolder.php
+++ b/lib/public/Files/IRootFolder.php
@@ -38,11 +38,22 @@ interface IRootFolder extends Folder, Emitter {
* Returns a view to user's files folder
*
* @param string $userId user ID
- * @return \OCP\Files\Folder
+ * @return Folder
* @throws NoUserException
* @throws NotPermittedException
*
* @since 8.2.0
*/
public function getUserFolder($userId);
+
+ /**
+ * Get a file or folder by fileid, inside a parent path
+ *
+ * @param int $id
+ * @param string $path
+ * @return Node[]
+ *
+ * @since 24.0.0
+ */
+ public function getByIdInPath(int $id, string $path);
}
diff --git a/lib/public/ICache.php b/lib/public/ICache.php
index 47b0e2f4c3d..0e818277f60 100644
--- a/lib/public/ICache.php
+++ b/lib/public/ICache.php
@@ -76,4 +76,10 @@ interface ICache {
* @since 6.0.0
*/
public function clear($prefix = '');
+
+ /**
+ * Check if the cache implementation is available
+ * @since 24.0.0
+ */
+ public static function isAvailable(): bool;
}
diff --git a/lib/public/IRequestId.php b/lib/public/IRequestId.php
new file mode 100644
index 00000000000..dba06088cc9
--- /dev/null
+++ b/lib/public/IRequestId.php
@@ -0,0 +1,39 @@
+<?php
+
+declare(strict_types=1);
+/**
+ * @copyright Copyright (c) 2022, Joas Schilling <coding@schilljs.com>
+ *
+ * @author Joas Schilling <coding@schilljs.com>
+ *
+ * @license AGPL-3.0
+ *
+ * This code is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License, version 3,
+ * as published by the Free Software Foundation.
+ *
+ * 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, version 3,
+ * along with this program. If not, see <http://www.gnu.org/licenses/>
+ *
+ */
+
+namespace OCP;
+
+/**
+ * @since 24.0.0
+ */
+interface IRequestId {
+ /**
+ * Returns an ID for the request, value is not guaranteed to be unique and is mostly meant for logging
+ * If `mod_unique_id` is installed this value will be taken.
+ *
+ * @return string
+ * @since 24.0.0
+ */
+ public function getId(): string;
+}
diff --git a/lib/public/Profiler/IProfile.php b/lib/public/Profiler/IProfile.php
new file mode 100644
index 00000000000..1831496a5a7
--- /dev/null
+++ b/lib/public/Profiler/IProfile.php
@@ -0,0 +1,168 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2022 Carl Schwan <carl@carlschwan.eu>
+ *
+ * @author Carl Schwan <carl@carlschwan.eu>
+ *
+ * @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\Profiler;
+
+use OCP\DataCollector\IDataCollector;
+
+/**
+ * This interface store the results of the profiling of one
+ * request. You can get the saved profiles from the @see IProfiler.
+ *
+ * ```php
+ * <?php
+ * $profiler = \OC::$server->get(IProfiler::class);
+ * $profiles = $profiler->find('/settings/users', 10);
+ * ```
+ *
+ * This interface is meant to be used directly and not extended.
+ * @since 24.0.0
+ */
+interface IProfile {
+ /**
+ * Get the token of the profile
+ * @since 24.0.0
+ */
+ public function getToken(): string;
+
+ /**
+ * Set the token of the profile
+ * @since 24.0.0
+ */
+ public function setToken(string $token): void;
+
+ /**
+ * Get the time of the profile
+ * @since 24.0.0
+ */
+ public function getTime(): ?int;
+
+ /**
+ * Set the time of the profile
+ * @since 24.0.0
+ */
+ public function setTime(int $time): void;
+
+ /**
+ * Get the url of the profile
+ * @since 24.0.0
+ */
+ public function getUrl(): ?string;
+
+ /**
+ * Set the url of the profile
+ * @since 24.0.0
+ */
+ public function setUrl(string $url): void;
+
+ /**
+ * Get the method of the profile
+ * @since 24.0.0
+ */
+ public function getMethod(): ?string;
+
+ /**
+ * Set the method of the profile
+ * @since 24.0.0
+ */
+ public function setMethod(string $method): void;
+
+ /**
+ * Get the status code of the profile
+ * @since 24.0.0
+ */
+ public function getStatusCode(): ?int;
+
+ /**
+ * Set the status code of the profile
+ * @since 24.0.0
+ */
+ public function setStatusCode(int $statusCode): void;
+
+ /**
+ * Add a data collector to the profile
+ * @since 24.0.0
+ */
+ public function addCollector(IDataCollector $collector);
+
+ /**
+ * Get the parent profile to this profile
+ * @since 24.0.0
+ */
+ public function getParent(): ?IProfile;
+
+ /**
+ * Set the parent profile to this profile
+ * @since 24.0.0
+ */
+ public function setParent(?IProfile $parent): void;
+
+ /**
+ * Get the parent token to this profile
+ * @since 24.0.0
+ */
+ public function getParentToken(): ?string;
+
+ /**
+ * Get the profile's children
+ * @return IProfile[]
+ * @since 24.0.0
+ **/
+ public function getChildren(): array;
+
+ /**
+ * Set the profile's children
+ * @param IProfile[] $children
+ * @since 24.0.0
+ */
+ public function setChildren(array $children): void;
+
+ /**
+ * Add the child profile
+ * @since 24.0.0
+ */
+ public function addChild(IProfile $profile): void;
+
+ /**
+ * Get all the data collectors
+ * @return IDataCollector[]
+ * @since 24.0.0
+ */
+ public function getCollectors(): array;
+
+ /**
+ * Set all the data collectors
+ * @param IDataCollector[] $collectors
+ * @since 24.0.0
+ */
+ public function setCollectors(array $collectors): void;
+
+ /**
+ * Get a data collector by name
+ * @since 24.0.0
+ */
+ public function getCollector(string $collectorName): ?IDataCollector;
+}
diff --git a/lib/public/Profiler/IProfiler.php b/lib/public/Profiler/IProfiler.php
new file mode 100644
index 00000000000..78325089523
--- /dev/null
+++ b/lib/public/Profiler/IProfiler.php
@@ -0,0 +1,101 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * @copyright 2022 Carl Schwan <carl@carlschwan.eu>
+ *
+ * @author Carl Schwan <carl@carlschwan.eu>
+ *
+ * @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\Profiler;
+
+use OC\AppFramework\Http\Request;
+use OCP\AppFramework\Http\Response;
+use OCP\DataCollector\IDataCollector;
+
+/**
+ * This interface allows to interact with the built-in Nextcloud profiler.
+ * @since 24.0.0
+ */
+interface IProfiler {
+ /**
+ * Add a new data collector to the profiler. This allows to later on
+ * collect all the data from every registered collector.
+ *
+ * @see IDataCollector
+ * @since 24.0.0
+ */
+ public function add(IDataCollector $dataCollector): void;
+
+ /**
+ * Load a profile from a response object
+ * @since 24.0.0
+ */
+ public function loadProfileFromResponse(Response $response): ?IProfile;
+
+ /**
+ * Load a profile from the response token
+ * @since 24.0.0
+ */
+ public function loadProfile(string $token): ?IProfile;
+
+ /**
+ * Save a profile on the disk. This allows to later load it again in the
+ * profiler user interface.
+ * @since 24.0.0
+ */
+ public function saveProfile(IProfile $profile): bool;
+
+ /**
+ * Find a profile from various search parameters
+ * @since 24.0.0
+ */
+ public function find(?string $url, ?int $limit, ?string $method, ?int $start, ?int $end, string $statusCode = null): array;
+
+ /**
+ * Get the list of data providers by identifier
+ * @return string[]
+ * @since 24.0.0
+ */
+ public function dataProviders(): array;
+
+ /**
+ * Check if the profiler is enabled.
+ *
+ * If it is not enabled, data provider shouldn't be created and
+ * shouldn't collect any data.
+ * @since 24.0.0
+ */
+ public function isEnabled(): bool;
+
+ /**
+ * Set if the profiler is enabled.
+ * @see isEnabled
+ * @since 24.0.0
+ */
+ public function setEnabled(bool $enabled): void;
+
+ /**
+ * Collect all the information from the current request and construct
+ * a IProfile from it.
+ * @since 24.0.0
+ */
+ public function collect(Request $request, Response $response): IProfile;
+}