diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/base.php | 11 | ||||
-rw-r--r-- | lib/composer/composer/autoload_classmap.php | 1 | ||||
-rw-r--r-- | lib/composer/composer/autoload_static.php | 1 | ||||
-rw-r--r-- | lib/private/Files/AppData/Factory.php | 21 | ||||
-rw-r--r-- | lib/private/Lock/AbstractLockingProvider.php | 53 | ||||
-rw-r--r-- | lib/private/Lock/DBLockingProvider.php | 223 | ||||
-rw-r--r-- | lib/private/Lock/MemcacheLockingProvider.php | 41 | ||||
-rw-r--r-- | lib/private/Lock/NoopLockingProvider.php | 8 | ||||
-rw-r--r-- | lib/private/Security/SecureRandom.php | 7 | ||||
-rw-r--r-- | lib/private/Server.php | 5 | ||||
-rw-r--r-- | lib/private/Share20/DefaultShareProvider.php | 25 | ||||
-rw-r--r-- | lib/private/legacy/OC_Files.php | 15 | ||||
-rw-r--r-- | lib/private/legacy/OC_Helper.php | 5 | ||||
-rw-r--r-- | lib/public/AppFramework/Db/QBMapper.php | 17 | ||||
-rw-r--r-- | lib/public/Files/AppData/IAppDataFactory.php | 21 | ||||
-rw-r--r-- | lib/public/Lock/ILockingProvider.php | 36 | ||||
-rw-r--r-- | lib/public/RichObjectStrings/Definitions.php | 19 |
17 files changed, 231 insertions, 278 deletions
diff --git a/lib/base.php b/lib/base.php index 21889272dd7..8cf5360b084 100644 --- a/lib/base.php +++ b/lib/base.php @@ -141,7 +141,7 @@ class OC { public static function initPaths() { if (defined('PHPUNIT_CONFIG_DIR')) { self::$configDir = OC::$SERVERROOT . '/' . PHPUNIT_CONFIG_DIR . '/'; - } elseif (defined('PHPUNIT_RUN') and PHPUNIT_RUN and is_dir(OC::$SERVERROOT . '/tests/config/')) { + } elseif (defined('PHPUNIT_RUN') && PHPUNIT_RUN && is_dir(OC::$SERVERROOT . '/tests/config/')) { self::$configDir = OC::$SERVERROOT . '/tests/config/'; } elseif ($dir = getenv('NEXTCLOUD_CONFIG_DIR')) { self::$configDir = rtrim($dir, '/') . '/'; @@ -463,14 +463,6 @@ class OC { } /** - * Try to set some values to the required Nextcloud default - */ - public static function setRequiredIniValues() { - @ini_set('default_charset', 'UTF-8'); - @ini_set('gd.jpeg_ignore_warning', '1'); - } - - /** * Send the same site cookies */ private static function sendSameSiteCookies() { @@ -634,7 +626,6 @@ class OC { @ini_set('max_execution_time', '3600'); @ini_set('max_input_time', '3600'); - self::setRequiredIniValues(); self::handleAuthHeaders(); $systemConfig = \OC::$server->get(\OC\SystemConfig::class); self::registerAutoloaderCache($systemConfig); diff --git a/lib/composer/composer/autoload_classmap.php b/lib/composer/composer/autoload_classmap.php index 233c374edbf..d1fb89098c5 100644 --- a/lib/composer/composer/autoload_classmap.php +++ b/lib/composer/composer/autoload_classmap.php @@ -236,6 +236,7 @@ return array( 'OCP\\Federation\\ICloudIdManager' => $baseDir . '/lib/public/Federation/ICloudIdManager.php', 'OCP\\Files' => $baseDir . '/lib/public/Files.php', 'OCP\\Files\\AlreadyExistsException' => $baseDir . '/lib/public/Files/AlreadyExistsException.php', + 'OCP\\Files\\AppData\\IAppDataFactory' => $baseDir . '/lib/public/Files/AppData/IAppDataFactory.php', 'OCP\\Files\\Cache\\AbstractCacheEvent' => $baseDir . '/lib/public/Files/Cache/AbstractCacheEvent.php', 'OCP\\Files\\Cache\\CacheEntryInsertedEvent' => $baseDir . '/lib/public/Files/Cache/CacheEntryInsertedEvent.php', 'OCP\\Files\\Cache\\CacheEntryRemovedEvent' => $baseDir . '/lib/public/Files/Cache/CacheEntryRemovedEvent.php', diff --git a/lib/composer/composer/autoload_static.php b/lib/composer/composer/autoload_static.php index 0b59d14657d..0aae979596c 100644 --- a/lib/composer/composer/autoload_static.php +++ b/lib/composer/composer/autoload_static.php @@ -265,6 +265,7 @@ class ComposerStaticInit53792487c5a8370acc0b06b1a864ff4c 'OCP\\Federation\\ICloudIdManager' => __DIR__ . '/../../..' . '/lib/public/Federation/ICloudIdManager.php', 'OCP\\Files' => __DIR__ . '/../../..' . '/lib/public/Files.php', 'OCP\\Files\\AlreadyExistsException' => __DIR__ . '/../../..' . '/lib/public/Files/AlreadyExistsException.php', + 'OCP\\Files\\AppData\\IAppDataFactory' => __DIR__ . '/../../..' . '/lib/public/Files/AppData/IAppDataFactory.php', 'OCP\\Files\\Cache\\AbstractCacheEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Cache/AbstractCacheEvent.php', 'OCP\\Files\\Cache\\CacheEntryInsertedEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Cache/CacheEntryInsertedEvent.php', 'OCP\\Files\\Cache\\CacheEntryRemovedEvent' => __DIR__ . '/../../..' . '/lib/public/Files/Cache/CacheEntryRemovedEvent.php', diff --git a/lib/private/Files/AppData/Factory.php b/lib/private/Files/AppData/Factory.php index 6d7483158f6..03f8fdedcbd 100644 --- a/lib/private/Files/AppData/Factory.php +++ b/lib/private/Files/AppData/Factory.php @@ -27,17 +27,16 @@ declare(strict_types=1); namespace OC\Files\AppData; use OC\SystemConfig; +use OCP\Files\AppData\IAppDataFactory; +use OCP\Files\IAppData; use OCP\Files\IRootFolder; -class Factory { +class Factory implements IAppDataFactory { + private IRootFolder $rootFolder; + private SystemConfig $config; - /** @var IRootFolder */ - private $rootFolder; - - /** @var SystemConfig */ - private $config; - - private $folders = []; + /** @var array<string, IAppData> */ + private array $folders = []; public function __construct(IRootFolder $rootFolder, SystemConfig $systemConfig) { @@ -45,11 +44,7 @@ class Factory { $this->config = $systemConfig; } - /** - * @param string $appId - * @return AppData - */ - public function get(string $appId): AppData { + public function get(string $appId): IAppData { if (!isset($this->folders[$appId])) { $this->folders[$appId] = new AppData($this->rootFolder, $this->config, $appId); } diff --git a/lib/private/Lock/AbstractLockingProvider.php b/lib/private/Lock/AbstractLockingProvider.php index f4899bbb2b2..6e8289db12e 100644 --- a/lib/private/Lock/AbstractLockingProvider.php +++ b/lib/private/Lock/AbstractLockingProvider.php @@ -30,24 +30,18 @@ use OCP\Lock\ILockingProvider; /** * Base locking provider that keeps track of locks acquired during the current request - * to release any left over locks at the end of the request + * to release any leftover locks at the end of the request */ abstract class AbstractLockingProvider implements ILockingProvider { - /** @var int $ttl */ - protected $ttl; // how long until we clear stray locks in seconds + /** how long until we clear stray locks in seconds */ + protected int $ttl; protected $acquiredLocks = [ 'shared' => [], 'exclusive' => [] ]; - /** - * Check if we've locally acquired a lock - * - * @param string $path - * @param int $type - * @return bool - */ + /** @inheritDoc */ protected function hasAcquiredLock(string $path, int $type): bool { if ($type === self::LOCK_SHARED) { return isset($this->acquiredLocks['shared'][$path]) && $this->acquiredLocks['shared'][$path] > 0; @@ -56,14 +50,9 @@ abstract class AbstractLockingProvider implements ILockingProvider { } } - /** - * Mark a locally acquired lock - * - * @param string $path - * @param int $type self::LOCK_SHARED or self::LOCK_EXCLUSIVE - */ - protected function markAcquire(string $path, int $type) { - if ($type === self::LOCK_SHARED) { + /** @inheritDoc */ + protected function markAcquire(string $path, int $targetType): void { + if ($targetType === self::LOCK_SHARED) { if (!isset($this->acquiredLocks['shared'][$path])) { $this->acquiredLocks['shared'][$path] = 0; } @@ -73,13 +62,8 @@ abstract class AbstractLockingProvider implements ILockingProvider { } } - /** - * Mark a release of a locally acquired lock - * - * @param string $path - * @param int $type self::LOCK_SHARED or self::LOCK_EXCLUSIVE - */ - protected function markRelease(string $path, int $type) { + /** @inheritDoc */ + protected function markRelease(string $path, int $type): void { if ($type === self::LOCK_SHARED) { if (isset($this->acquiredLocks['shared'][$path]) and $this->acquiredLocks['shared'][$path] > 0) { $this->acquiredLocks['shared'][$path]--; @@ -92,13 +76,8 @@ abstract class AbstractLockingProvider implements ILockingProvider { } } - /** - * Change the type of an existing tracked lock - * - * @param string $path - * @param int $targetType self::LOCK_SHARED or self::LOCK_EXCLUSIVE - */ - protected function markChange(string $path, int $targetType) { + /** @inheritDoc */ + protected function markChange(string $path, int $targetType): void { if ($targetType === self::LOCK_SHARED) { unset($this->acquiredLocks['exclusive'][$path]); if (!isset($this->acquiredLocks['shared'][$path])) { @@ -111,10 +90,8 @@ abstract class AbstractLockingProvider implements ILockingProvider { } } - /** - * release all lock acquired by this instance which were marked using the mark* methods - */ - public function releaseAll() { + /** @inheritDoc */ + public function releaseAll(): void { foreach ($this->acquiredLocks['shared'] as $path => $count) { for ($i = 0; $i < $count; $i++) { $this->releaseLock($path, self::LOCK_SHARED); @@ -126,7 +103,7 @@ abstract class AbstractLockingProvider implements ILockingProvider { } } - protected function getOwnSharedLockCount(string $path) { - return isset($this->acquiredLocks['shared'][$path]) ? $this->acquiredLocks['shared'][$path] : 0; + protected function getOwnSharedLockCount(string $path): int { + return $this->acquiredLocks['shared'][$path] ?? 0; } } diff --git a/lib/private/Lock/DBLockingProvider.php b/lib/private/Lock/DBLockingProvider.php index 5eb03ad856b..fb8af8ac55b 100644 --- a/lib/private/Lock/DBLockingProvider.php +++ b/lib/private/Lock/DBLockingProvider.php @@ -9,6 +9,7 @@ * @author Ole Ostergaard <ole.c.ostergaard@gmail.com> * @author Robin Appelman <robin@icewind.nl> * @author Roeland Jago Douma <roeland@famdouma.nl> + * @author Carl Schwan <carl@carlschwan.eu> * * @license AGPL-3.0 * @@ -33,51 +34,40 @@ use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; use OCP\Lock\ILockingProvider; use OCP\Lock\LockedException; -use Psr\Log\LoggerInterface; /** * Locking provider that stores the locks in the database */ class DBLockingProvider extends AbstractLockingProvider { - /** - * @var \OCP\IDBConnection - */ - private $connection; - - private LoggerInterface $logger; - - /** - * @var \OCP\AppFramework\Utility\ITimeFactory - */ - private $timeFactory; - - private $sharedLocks = []; + private IDBConnection $connection; + private ITimeFactory $timeFactory; + private array $sharedLocks = []; + private bool $cacheSharedLocks; - /** - * @var bool - */ - private $cacheSharedLocks; + public function __construct( + IDBConnection $connection, + ITimeFactory $timeFactory, + int $ttl = 3600, + bool $cacheSharedLocks = true + ) { + $this->connection = $connection; + $this->timeFactory = $timeFactory; + $this->ttl = $ttl; + $this->cacheSharedLocks = $cacheSharedLocks; + } /** * Check if we have an open shared lock for a path - * - * @param string $path - * @return bool */ protected function isLocallyLocked(string $path): bool { return isset($this->sharedLocks[$path]) && $this->sharedLocks[$path]; } - /** - * Mark a locally acquired lock - * - * @param string $path - * @param int $type self::LOCK_SHARED or self::LOCK_EXCLUSIVE - */ - protected function markAcquire(string $path, int $type) { - parent::markAcquire($path, $type); + /** @inheritDoc */ + protected function markAcquire(string $path, int $targetType): void { + parent::markAcquire($path, $targetType); if ($this->cacheSharedLocks) { - if ($type === self::LOCK_SHARED) { + if ($targetType === self::LOCK_SHARED) { $this->sharedLocks[$path] = true; } } @@ -85,11 +75,8 @@ class DBLockingProvider extends AbstractLockingProvider { /** * Change the type of an existing tracked lock - * - * @param string $path - * @param int $targetType self::LOCK_SHARED or self::LOCK_EXCLUSIVE */ - protected function markChange(string $path, int $targetType) { + protected function markChange(string $path, int $targetType): void { parent::markChange($path, $targetType); if ($this->cacheSharedLocks) { if ($targetType === self::LOCK_SHARED) { @@ -101,28 +88,7 @@ class DBLockingProvider extends AbstractLockingProvider { } /** - * @param bool $cacheSharedLocks - */ - public function __construct( - IDBConnection $connection, - LoggerInterface $logger, - ITimeFactory $timeFactory, - int $ttl = 3600, - $cacheSharedLocks = true - ) { - $this->connection = $connection; - $this->logger = $logger; - $this->timeFactory = $timeFactory; - $this->ttl = $ttl; - $this->cacheSharedLocks = $cacheSharedLocks; - } - - /** * Insert a file locking row if it does not exists. - * - * @param string $path - * @param int $lock - * @return int number of inserted rows */ protected function initLockField(string $path, int $lock = 0): int { $expire = $this->getExpireTime(); @@ -133,25 +99,21 @@ class DBLockingProvider extends AbstractLockingProvider { ]); } - /** - * @return int - */ protected function getExpireTime(): int { return $this->timeFactory->getTime() + $this->ttl; } - /** - * @param string $path - * @param int $type self::LOCK_SHARED or self::LOCK_EXCLUSIVE - * @return bool - */ + /** @inheritDoc */ public function isLocked(string $path, int $type): bool { if ($this->hasAcquiredLock($path, $type)) { return true; } - $query = $this->connection->prepare('SELECT `lock` from `*PREFIX*file_locks` WHERE `key` = ?'); - $query->execute([$path]); - $lockValue = (int)$query->fetchOne(); + $query = $this->connection->getQueryBuilder(); + $query->select('lock') + ->from('file_locks') + ->where($query->expr()->eq('key', $query->createNamedParameter($path))); + $result = $query->executeQuery(); + $lockValue = (int)$result->fetchOne(); if ($type === self::LOCK_SHARED) { if ($this->isLocallyLocked($path)) { // if we have a shared lock we kept open locally but it's released we always have at least 1 shared lock in the db @@ -166,21 +128,20 @@ class DBLockingProvider extends AbstractLockingProvider { } } - /** - * @param string $path - * @param int $type self::LOCK_SHARED or self::LOCK_EXCLUSIVE - * @throws \OCP\Lock\LockedException - */ - public function acquireLock(string $path, int $type, string $readablePath = null) { + /** @inheritDoc */ + public function acquireLock(string $path, int $type, ?string $readablePath = null): void { $expire = $this->getExpireTime(); if ($type === self::LOCK_SHARED) { if (!$this->isLocallyLocked($path)) { $result = $this->initLockField($path, 1); if ($result <= 0) { - $result = $this->connection->executeUpdate( - 'UPDATE `*PREFIX*file_locks` SET `lock` = `lock` + 1, `ttl` = ? WHERE `key` = ? AND `lock` >= 0', - [$expire, $path] - ); + $query = $this->connection->getQueryBuilder(); + $query->update('file_locks') + ->set('lock', $query->func()->add('lock', $query->createNamedParameter(1, IQueryBuilder::PARAM_INT))) + ->set('ttl', $query->createNamedParameter($expire)) + ->where($query->expr()->eq('key', $query->createNamedParameter($path))) + ->andWhere($query->expr()->gte('lock', $query->createNamedParameter(0, IQueryBuilder::PARAM_INT))); + $result = $query->executeStatement(); } } else { $result = 1; @@ -192,10 +153,13 @@ class DBLockingProvider extends AbstractLockingProvider { } $result = $this->initLockField($path, -1); if ($result <= 0) { - $result = $this->connection->executeUpdate( - 'UPDATE `*PREFIX*file_locks` SET `lock` = -1, `ttl` = ? WHERE `key` = ? AND `lock` = ?', - [$expire, $path, $existing] - ); + $query = $this->connection->getQueryBuilder(); + $query->update('file_locks') + ->set('lock', $query->createNamedParameter(-1, IQueryBuilder::PARAM_INT)) + ->set('ttl', $query->createNamedParameter($expire, IQueryBuilder::PARAM_INT)) + ->where($query->expr()->eq('key', $query->createNamedParameter($path))) + ->andWhere($query->expr()->eq('lock', $query->createNamedParameter($existing))); + $result = $query->executeStatement(); } } if ($result !== 1) { @@ -204,52 +168,53 @@ class DBLockingProvider extends AbstractLockingProvider { $this->markAcquire($path, $type); } - /** - * @param string $path - * @param int $type self::LOCK_SHARED or self::LOCK_EXCLUSIVE - */ - public function releaseLock(string $path, int $type) { + /** @inheritDoc */ + public function releaseLock(string $path, int $type): void { $this->markRelease($path, $type); // we keep shared locks till the end of the request so we can re-use them if ($type === self::LOCK_EXCLUSIVE) { - $this->connection->executeUpdate( - 'UPDATE `*PREFIX*file_locks` SET `lock` = 0 WHERE `key` = ? AND `lock` = -1', - [$path] - ); + $qb = $this->connection->getQueryBuilder(); + $qb->update('file_locks') + ->set('lock', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT)) + ->where($qb->expr()->eq('key', $qb->createNamedParameter($path))) + ->andWhere($qb->expr()->eq('lock', $qb->createNamedParameter(-1, IQueryBuilder::PARAM_INT))); + $qb->executeStatement(); } elseif (!$this->cacheSharedLocks) { - $query = $this->connection->getQueryBuilder(); - $query->update('file_locks') - ->set('lock', $query->func()->subtract('lock', $query->createNamedParameter(1))) - ->where($query->expr()->eq('key', $query->createNamedParameter($path))) - ->andWhere($query->expr()->gt('lock', $query->createNamedParameter(0))); - $query->execute(); + $qb = $this->connection->getQueryBuilder(); + $qb->update('file_locks') + ->set('lock', $qb->func()->subtract('lock', $qb->createNamedParameter(1, IQueryBuilder::PARAM_INT))) + ->where($qb->expr()->eq('key', $qb->createNamedParameter($path))) + ->andWhere($qb->expr()->gt('lock', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT))); + $qb->executeStatement(); } } - /** - * Change the type of an existing lock - * - * @param string $path - * @param int $targetType self::LOCK_SHARED or self::LOCK_EXCLUSIVE - * @throws \OCP\Lock\LockedException - */ - public function changeLock(string $path, int $targetType) { + /** @inheritDoc */ + public function changeLock(string $path, int $targetType): void { $expire = $this->getExpireTime(); if ($targetType === self::LOCK_SHARED) { - $result = $this->connection->executeUpdate( - 'UPDATE `*PREFIX*file_locks` SET `lock` = 1, `ttl` = ? WHERE `key` = ? AND `lock` = -1', - [$expire, $path] - ); + $qb = $this->connection->getQueryBuilder(); + $result = $qb->update('file_locks') + ->set('lock', $qb->createNamedParameter(1, IQueryBuilder::PARAM_INT)) + ->set('ttl', $qb->createNamedParameter($expire, IQueryBuilder::PARAM_INT)) + ->where($qb->expr()->andX( + $qb->expr()->eq('key', $qb->createNamedParameter($path)), + $qb->expr()->eq('lock', $qb->createNamedParameter(-1, IQueryBuilder::PARAM_INT)) + ))->executeStatement(); } else { // since we only keep one shared lock in the db we need to check if we have more then one shared lock locally manually if (isset($this->acquiredLocks['shared'][$path]) && $this->acquiredLocks['shared'][$path] > 1) { throw new LockedException($path); } - $result = $this->connection->executeUpdate( - 'UPDATE `*PREFIX*file_locks` SET `lock` = -1, `ttl` = ? WHERE `key` = ? AND `lock` = 1', - [$expire, $path] - ); + $qb = $this->connection->getQueryBuilder(); + $result = $qb->update('file_locks') + ->set('lock', $qb->createNamedParameter(-1, IQueryBuilder::PARAM_INT)) + ->set('ttl', $qb->createNamedParameter($expire, IQueryBuilder::PARAM_INT)) + ->where($qb->expr()->andX( + $qb->expr()->eq('key', $qb->createNamedParameter($path)), + $qb->expr()->eq('lock', $qb->createNamedParameter(1, IQueryBuilder::PARAM_INT)) + ))->executeStatement(); } if ($result !== 1) { throw new LockedException($path); @@ -257,16 +222,14 @@ class DBLockingProvider extends AbstractLockingProvider { $this->markChange($path, $targetType); } - /** - * cleanup empty locks - */ - public function cleanExpiredLocks() { + /** @inheritDoc */ + public function cleanExpiredLocks(): void { $expire = $this->timeFactory->getTime(); try { - $this->connection->executeUpdate( - 'DELETE FROM `*PREFIX*file_locks` WHERE `ttl` < ?', - [$expire] - ); + $qb = $this->connection->getQueryBuilder(); + $qb->delete('file_locks') + ->where($qb->expr()->lt('ttl', $qb->createNamedParameter($expire, IQueryBuilder::PARAM_INT))) + ->executeStatement(); } catch (\Exception $e) { // If the table is missing, the clean up was successful if ($this->connection->tableExists('file_locks')) { @@ -275,10 +238,8 @@ class DBLockingProvider extends AbstractLockingProvider { } } - /** - * release all lock acquired by this instance which were marked using the mark* methods - */ - public function releaseAll() { + /** @inheritDoc */ + public function releaseAll(): void { parent::releaseAll(); if (!$this->cacheSharedLocks) { @@ -292,15 +253,15 @@ class DBLockingProvider extends AbstractLockingProvider { $chunkedPaths = array_chunk($lockedPaths, 100); - foreach ($chunkedPaths as $chunk) { - $builder = $this->connection->getQueryBuilder(); - - $query = $builder->update('file_locks') - ->set('lock', $builder->func()->subtract('lock', $builder->expr()->literal(1))) - ->where($builder->expr()->in('key', $builder->createNamedParameter($chunk, IQueryBuilder::PARAM_STR_ARRAY))) - ->andWhere($builder->expr()->gt('lock', new Literal(0))); + $qb = $this->connection->getQueryBuilder(); + $qb->update('file_locks') + ->set('lock', $qb->func()->subtract('lock', $qb->expr()->literal(1))) + ->where($qb->expr()->in('key', $qb->createParameter('chunk'))) + ->andWhere($qb->expr()->gt('lock', new Literal(0))); - $query->execute(); + foreach ($chunkedPaths as $chunk) { + $qb->setParameter('chunk', $chunk, IQueryBuilder::PARAM_STR_ARRAY); + $qb->executeStatement(); } } } diff --git a/lib/private/Lock/MemcacheLockingProvider.php b/lib/private/Lock/MemcacheLockingProvider.php index 008a7875d7e..d4eebd7c302 100644 --- a/lib/private/Lock/MemcacheLockingProvider.php +++ b/lib/private/Lock/MemcacheLockingProvider.php @@ -32,31 +32,19 @@ use OCP\IMemcacheTTL; use OCP\Lock\LockedException; class MemcacheLockingProvider extends AbstractLockingProvider { - /** - * @var \OCP\IMemcache - */ - private $memcache; + private IMemcache $memcache; - /** - * @param \OCP\IMemcache $memcache - * @param int $ttl - */ public function __construct(IMemcache $memcache, int $ttl = 3600) { $this->memcache = $memcache; $this->ttl = $ttl; } - private function setTTL(string $path) { + private function setTTL(string $path): void { if ($this->memcache instanceof IMemcacheTTL) { $this->memcache->setTTL($path, $this->ttl); } } - /** - * @param string $path - * @param int $type self::LOCK_SHARED or self::LOCK_EXCLUSIVE - * @return bool - */ public function isLocked(string $path, int $type): bool { $lockValue = $this->memcache->get($path); if ($type === self::LOCK_SHARED) { @@ -68,13 +56,7 @@ class MemcacheLockingProvider extends AbstractLockingProvider { } } - /** - * @param string $path - * @param int $type self::LOCK_SHARED or self::LOCK_EXCLUSIVE - * @param string $readablePath human readable path to use in error messages - * @throws \OCP\Lock\LockedException - */ - public function acquireLock(string $path, int $type, string $readablePath = null) { + public function acquireLock(string $path, int $type, ?string $readablePath = null): void { if ($type === self::LOCK_SHARED) { if (!$this->memcache->inc($path)) { throw new LockedException($path, null, $this->getExistingLockForException($path), $readablePath); @@ -89,11 +71,7 @@ class MemcacheLockingProvider extends AbstractLockingProvider { $this->markAcquire($path, $type); } - /** - * @param string $path - * @param int $type self::LOCK_SHARED or self::LOCK_EXCLUSIVE - */ - public function releaseLock(string $path, int $type) { + public function releaseLock(string $path, int $type): void { if ($type === self::LOCK_SHARED) { $ownSharedLockCount = $this->getOwnSharedLockCount($path); $newValue = 0; @@ -120,14 +98,7 @@ class MemcacheLockingProvider extends AbstractLockingProvider { $this->markRelease($path, $type); } - /** - * Change the type of an existing lock - * - * @param string $path - * @param int $targetType self::LOCK_SHARED or self::LOCK_EXCLUSIVE - * @throws \OCP\Lock\LockedException - */ - public function changeLock(string $path, int $targetType) { + public function changeLock(string $path, int $targetType): void { if ($targetType === self::LOCK_SHARED) { if (!$this->memcache->cas($path, 'exclusive', 1)) { throw new LockedException($path, null, $this->getExistingLockForException($path)); @@ -142,7 +113,7 @@ class MemcacheLockingProvider extends AbstractLockingProvider { $this->markChange($path, $targetType); } - private function getExistingLockForException($path) { + private function getExistingLockForException(string $path): string { $existing = $this->memcache->get($path); if (!$existing) { return 'none'; diff --git a/lib/private/Lock/NoopLockingProvider.php b/lib/private/Lock/NoopLockingProvider.php index 95ae8cf0cda..ff56932a894 100644 --- a/lib/private/Lock/NoopLockingProvider.php +++ b/lib/private/Lock/NoopLockingProvider.php @@ -45,28 +45,28 @@ class NoopLockingProvider implements ILockingProvider { /** * {@inheritdoc} */ - public function acquireLock(string $path, int $type, string $readablePath = null) { + public function acquireLock(string $path, int $type, ?string $readablePath = null): void { // do nothing } /** * {@inheritdoc} */ - public function releaseLock(string $path, int $type) { + public function releaseLock(string $path, int $type): void { // do nothing } /**1 * {@inheritdoc} */ - public function releaseAll() { + public function releaseAll(): void { // do nothing } /** * {@inheritdoc} */ - public function changeLock(string $path, int $targetType) { + public function changeLock(string $path, int $targetType): void { // do nothing } } diff --git a/lib/private/Security/SecureRandom.php b/lib/private/Security/SecureRandom.php index 4bf8995d737..cbd1dc8db6d 100644 --- a/lib/private/Security/SecureRandom.php +++ b/lib/private/Security/SecureRandom.php @@ -40,14 +40,19 @@ use OCP\Security\ISecureRandom; */ class SecureRandom implements ISecureRandom { /** - * Generate a random string of specified length. + * Generate a secure random string of specified length. * @param int $length The length of the generated string * @param string $characters An optional list of characters to use if no character list is * specified all valid base64 characters are used. * @return string + * @throws \LengthException if an invalid length is requested */ public function generate(int $length, string $characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'): string { + if ($length <= 0) { + throw new \LengthException('Invalid length specified: ' . $length . ' must be bigger than 0'); + } + $maxCharIndex = \strlen($characters) - 1; $randomString = ''; diff --git a/lib/private/Server.php b/lib/private/Server.php index 5308de21f51..6e6fa430489 100644 --- a/lib/private/Server.php +++ b/lib/private/Server.php @@ -1109,7 +1109,6 @@ class Server extends ServerContainer implements IServerContainer { } return new DBLockingProvider( $c->get(IDBConnection::class), - $c->get(LoggerInterface::class), new TimeFactory(), $ttl, !\OC::$CLI @@ -1439,6 +1438,8 @@ class Server extends ServerContainer implements IServerContainer { $this->registerAlias(IMetadataManager::class, MetadataManager::class); + $this->registerAlias(\OCP\Files\AppData\IAppDataFactory::class, \OC\Files\AppData\Factory::class); + $this->connectDispatcher(); } @@ -2300,7 +2301,7 @@ class Server extends ServerContainer implements IServerContainer { /** * @return \OCP\Files\IAppData - * @deprecated 20.0.0 + * @deprecated 20.0.0 Use get(\OCP\Files\AppData\IAppDataFactory::class)->get($app) instead */ public function getAppDataDir($app) { /** @var \OC\Files\AppData\Factory $factory */ diff --git a/lib/private/Share20/DefaultShareProvider.php b/lib/private/Share20/DefaultShareProvider.php index 9638706025b..520bd17d3cf 100644 --- a/lib/private/Share20/DefaultShareProvider.php +++ b/lib/private/Share20/DefaultShareProvider.php @@ -671,10 +671,10 @@ class DefaultShareProvider implements IShareProvider { } // todo? maybe get these from the oc_mounts table - $childMountNodes = array_filter($node->getDirectoryListing(), function (Node $node) { + $childMountNodes = array_filter($node->getDirectoryListing(), function (Node $node): bool { return $node->getInternalPath() === ''; }); - $childMountRootIds = array_map(function (Node $node) { + $childMountRootIds = array_map(function (Node $node): int { return $node->getId(); }, $childMountNodes); @@ -682,18 +682,29 @@ class DefaultShareProvider implements IShareProvider { $qb->andWhere( $qb->expr()->orX( $qb->expr()->eq('f.parent', $qb->createNamedParameter($node->getId())), - $qb->expr()->in('f.fileid', $qb->createNamedParameter($childMountRootIds, IQueryBuilder::PARAM_INT_ARRAY)) + $qb->expr()->in('f.fileid', $qb->createParameter('chunk')) ) ); $qb->orderBy('id'); - $cursor = $qb->execute(); $shares = []; - while ($data = $cursor->fetch()) { - $shares[$data['fileid']][] = $this->createShare($data); + + $chunks = array_chunk($childMountRootIds, 1000); + + // Force the request to be run when there is 0 mount. + if (count($chunks) === 0) { + $chunks = [[]]; + } + + foreach ($chunks as $chunk) { + $qb->setParameter('chunk', $chunk, IQueryBuilder::PARAM_INT_ARRAY); + $cursor = $qb->executeQuery(); + while ($data = $cursor->fetch()) { + $shares[$data['fileid']][] = $this->createShare($data); + } + $cursor->closeCursor(); } - $cursor->closeCursor(); return $shares; } diff --git a/lib/private/legacy/OC_Files.php b/lib/private/legacy/OC_Files.php index 41ac20577b2..02e15fd08d5 100644 --- a/lib/private/legacy/OC_Files.php +++ b/lib/private/legacy/OC_Files.php @@ -145,21 +145,26 @@ class OC_Files { } self::lockFiles($view, $dir, $files); + $numberOfFiles = 0; + $fileSize = 0; /* Calculate filesize and number of files */ if ($getType === self::ZIP_FILES) { $fileInfos = []; - $fileSize = 0; foreach ($files as $file) { $fileInfo = \OC\Files\Filesystem::getFileInfo($dir . '/' . $file); - $fileSize += $fileInfo->getSize(); - $fileInfos[] = $fileInfo; + if ($fileInfo) { + $fileSize += $fileInfo->getSize(); + $fileInfos[] = $fileInfo; + } } $numberOfFiles = self::getNumberOfFiles($fileInfos); } elseif ($getType === self::ZIP_DIR) { $fileInfo = \OC\Files\Filesystem::getFileInfo($dir . '/' . $files); - $fileSize = $fileInfo->getSize(); - $numberOfFiles = self::getNumberOfFiles([$fileInfo]); + if ($fileInfo) { + $fileSize = $fileInfo->getSize(); + $numberOfFiles = self::getNumberOfFiles([$fileInfo]); + } } $streamer = new Streamer(\OC::$server->getRequest(), $fileSize, $numberOfFiles); diff --git a/lib/private/legacy/OC_Helper.php b/lib/private/legacy/OC_Helper.php index 0d1903007c2..6aa0b582c21 100644 --- a/lib/private/legacy/OC_Helper.php +++ b/lib/private/legacy/OC_Helper.php @@ -519,9 +519,6 @@ class OC_Helper { $sourceStorage = $storage; if ($storage->instanceOfStorage('\OCA\Files_Sharing\SharedStorage')) { $includeExtStorage = false; - $internalPath = $storage->getUnjailedPath($rootInfo->getInternalPath()); - } else { - $internalPath = $rootInfo->getInternalPath(); } if ($includeExtStorage) { if ($storage->instanceOfStorage('\OC\Files\Storage\Home') @@ -545,7 +542,7 @@ class OC_Helper { $quota = $sourceStorage->getQuota(); } try { - $free = $sourceStorage->free_space($internalPath); + $free = $sourceStorage->free_space($rootInfo->getInternalPath()); } catch (\Exception $e) { if ($path === "") { throw $e; diff --git a/lib/public/AppFramework/Db/QBMapper.php b/lib/public/AppFramework/Db/QBMapper.php index fa753a09dcf..2491fd83f4a 100644 --- a/lib/public/AppFramework/Db/QBMapper.php +++ b/lib/public/AppFramework/Db/QBMapper.php @@ -334,16 +334,15 @@ abstract class QBMapper { */ protected function findEntities(IQueryBuilder $query): array { $result = $query->executeQuery(); - - $entities = []; - - while ($row = $result->fetch()) { - $entities[] = $this->mapRowToEntity($row); + try { + $entities = []; + while ($row = $result->fetch()) { + $entities[] = $this->mapRowToEntity($row); + } + return $entities; + } finally { + $result->closeCursor(); } - - $result->closeCursor(); - - return $entities; } diff --git a/lib/public/Files/AppData/IAppDataFactory.php b/lib/public/Files/AppData/IAppDataFactory.php new file mode 100644 index 00000000000..b689da36b83 --- /dev/null +++ b/lib/public/Files/AppData/IAppDataFactory.php @@ -0,0 +1,21 @@ +<?php + +namespace OCP\Files\AppData; + +use OCP\Files\IAppData; + +/** + * A factory allows you to get the AppData folder for an application. + * + * @since 25.0.0 + */ +interface IAppDataFactory { + + /** + * Get the AppData folder for the specified $appId + * @param string $appId + * @return IAppData + * @since 25.0.0 + */ + public function get(string $appId): IAppData; +} diff --git a/lib/public/Lock/ILockingProvider.php b/lib/public/Lock/ILockingProvider.php index 3dc7c73b6eb..a2015d42f47 100644 --- a/lib/public/Lock/ILockingProvider.php +++ b/lib/public/Lock/ILockingProvider.php @@ -28,7 +28,10 @@ declare(strict_types=1); namespace OCP\Lock; /** - * Interface ILockingProvider + * This interface allows locking and unlocking filesystem paths + * + * This interface should be used directly and not implemented by an application. + * The implementation is provided by the server. * * @since 8.1.0 */ @@ -43,42 +46,37 @@ interface ILockingProvider { public const LOCK_EXCLUSIVE = 2; /** - * @param string $path - * @param int $type self::LOCK_SHARED or self::LOCK_EXCLUSIVE - * @return bool + * @psalm-param self::LOCK_SHARED|self::LOCK_EXCLUSIVE $type * @since 8.1.0 */ public function isLocked(string $path, int $type): bool; /** - * @param string $path - * @param int $type self::LOCK_SHARED or self::LOCK_EXCLUSIVE - * @param string $readablePath human readable path to use in error messages, since 20.0.0 - * @throws \OCP\Lock\LockedException + * @psalm-param self::LOCK_SHARED|self::LOCK_EXCLUSIVE $type + * @param ?string $readablePath A human-readable path to use in error messages, since 20.0.0 + * @throws LockedException * @since 8.1.0 */ - public function acquireLock(string $path, int $type, string $readablePath = null); + public function acquireLock(string $path, int $type, ?string $readablePath = null): void; /** - * @param string $path - * @param int $type self::LOCK_SHARED or self::LOCK_EXCLUSIVE + * @psalm-param self::LOCK_SHARED|self::LOCK_EXCLUSIVE $type * @since 8.1.0 */ - public function releaseLock(string $path, int $type); + public function releaseLock(string $path, int $type): void; /** - * Change the type of an existing lock + * Change the target type of an existing lock * - * @param string $path - * @param int $targetType self::LOCK_SHARED or self::LOCK_EXCLUSIVE - * @throws \OCP\Lock\LockedException + * @psalm-param self::LOCK_SHARED|self::LOCK_EXCLUSIVE $targetType + * @throws LockedException * @since 8.1.0 */ - public function changeLock(string $path, int $targetType); + public function changeLock(string $path, int $targetType): void; /** - * release all lock acquired by this instance + * Release all lock acquired by this instance * @since 8.1.0 */ - public function releaseAll(); + public function releaseAll(): void; } diff --git a/lib/public/RichObjectStrings/Definitions.php b/lib/public/RichObjectStrings/Definitions.php index 676979170a6..383d626c155 100644 --- a/lib/public/RichObjectStrings/Definitions.php +++ b/lib/public/RichObjectStrings/Definitions.php @@ -579,6 +579,25 @@ class Definitions { ], ], ], + 'talk-poll' => [ + 'author' => 'Nextcloud', + 'app' => 'talk', + 'since' => '25.0.0', + 'parameters' => [ + 'id' => [ + 'since' => '25.0.0', + 'required' => true, + 'description' => 'The id used to identify the poll on the instance', + 'example' => '12345', + ], + 'name' => [ + 'since' => '25.0.0', + 'required' => true, + 'description' => 'The poll question', + 'example' => 'What is the question?', + ], + ], + ], 'user' => [ 'author' => 'Nextcloud', 'app' => 'core', |