From bd91c56539ba23bed3bff5dbc594950ef93799e0 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Thu, 18 Aug 2022 11:43:18 +0200 Subject: [PATCH] get quota for user only when needed always apply the wrapper but have the wrapper get the quota lazily only when an operation where quota is applied is performed Signed-off-by: Robin Appelman --- lib/private/Files/SetupManager.php | 8 +- lib/private/Files/Storage/Wrapper/Quota.php | 71 +++++++++++----- .../Files/Storage/HomeStorageQuotaTest.php | 84 ------------------- 3 files changed, 55 insertions(+), 108 deletions(-) delete mode 100644 tests/lib/Files/Storage/HomeStorageQuotaTest.php diff --git a/lib/private/Files/SetupManager.php b/lib/private/Files/SetupManager.php index 5782a5a72a6..d52a291cd99 100644 --- a/lib/private/Files/SetupManager.php +++ b/lib/private/Files/SetupManager.php @@ -172,10 +172,10 @@ class SetupManager { */ if ($storage->instanceOfStorage(HomeObjectStoreStorage::class) || $storage->instanceOfStorage(Home::class)) { if (is_object($storage->getUser())) { - $quota = OC_Util::getUserQuota($storage->getUser()); - if ($quota !== \OCP\Files\FileInfo::SPACE_UNLIMITED) { - return new Quota(['storage' => $storage, 'quota' => $quota, 'root' => 'files']); - } + $user = $storage->getUser(); + return new Quota(['storage' => $storage, 'quotaCallback' => function () use ($user) { + return OC_Util::getUserQuota($user); + }, 'root' => 'files']); } } diff --git a/lib/private/Files/Storage/Wrapper/Quota.php b/lib/private/Files/Storage/Wrapper/Quota.php index 4cd0a5e0b4a..8b129472eb0 100644 --- a/lib/private/Files/Storage/Wrapper/Quota.php +++ b/lib/private/Files/Storage/Wrapper/Quota.php @@ -33,40 +33,47 @@ namespace OC\Files\Storage\Wrapper; use OC\Files\Filesystem; +use OC\SystemConfig; use OCP\Files\Cache\ICacheEntry; +use OCP\Files\FileInfo; use OCP\Files\Storage\IStorage; class Quota extends Wrapper { - - /** - * @var int $quota - */ - protected $quota; - - /** - * @var string $sizeRoot - */ - protected $sizeRoot; - - private $config; + /** @var callable|null */ + protected $quotaCallback; + protected ?int $quota; + protected string $sizeRoot; + private SystemConfig $config; /** * @param array $parameters */ public function __construct($parameters) { parent::__construct($parameters); - $this->quota = $parameters['quota']; - $this->sizeRoot = isset($parameters['root']) ? $parameters['root'] : ''; - $this->config = \OC::$server->getSystemConfig(); + $this->quota = $parameters['quota'] ?? null; + $this->quotaCallback = $parameters['quotaCallback'] ?? null; + $this->sizeRoot = $parameters['root'] ?? ''; + $this->config = \OC::$server->get(SystemConfig::class); } /** * @return int quota value */ - public function getQuota() { + public function getQuota(): int { + if ($this->quota === null) { + $quotaCallback = $this->quotaCallback; + if ($quotaCallback === null) { + throw new \Exception("No quota or quota callback provider"); + } + $this->quota = $quotaCallback(); + } return $this->quota; } + private function hasQuota(): bool { + return $this->getQuota() !== FileInfo::SPACE_UNLIMITED; + } + /** * @param string $path * @param \OC\Files\Storage\Storage $storage @@ -100,7 +107,10 @@ class Quota extends Wrapper { * @return int|bool */ public function free_space($path) { - if ($this->quota < 0 || strpos($path, 'cache') === 0 || strpos($path, 'uploads') === 0) { + if (!$this->hasQuota()) { + return $this->storage->free_space($path); + } + if ($this->getQuota() < 0 || strpos($path, 'cache') === 0 || strpos($path, 'uploads') === 0) { return $this->storage->free_space($path); } else { $used = $this->getSize($this->sizeRoot); @@ -108,7 +118,7 @@ class Quota extends Wrapper { return \OCP\Files\FileInfo::SPACE_NOT_COMPUTED; } else { $free = $this->storage->free_space($path); - $quotaFree = max($this->quota - $used, 0); + $quotaFree = max($this->getQuota() - $used, 0); // if free space is known if ($free >= 0) { $free = min($free, $quotaFree); @@ -128,6 +138,9 @@ class Quota extends Wrapper { * @return int|false */ public function file_put_contents($path, $data) { + if (!$this->hasQuota()) { + return $this->storage->file_put_contents($path, $data); + } $free = $this->free_space($path); if ($free < 0 or strlen($data) < $free) { return $this->storage->file_put_contents($path, $data); @@ -144,6 +157,9 @@ class Quota extends Wrapper { * @return bool */ public function copy($source, $target) { + if (!$this->hasQuota()) { + return $this->storage->copy($source, $target); + } $free = $this->free_space($target); if ($free < 0 or $this->getSize($source) < $free) { return $this->storage->copy($source, $target); @@ -160,6 +176,9 @@ class Quota extends Wrapper { * @return resource|bool */ public function fopen($path, $mode) { + if (!$this->hasQuota()) { + return $this->storage->fopen($path, $mode); + } $source = $this->storage->fopen($path, $mode); // don't apply quota for part files @@ -202,6 +221,9 @@ class Quota extends Wrapper { * @return bool */ public function copyFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) { + if (!$this->hasQuota()) { + return $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); + } $free = $this->free_space($targetInternalPath); if ($free < 0 or $this->getSize($sourceInternalPath, $sourceStorage) < $free) { return $this->storage->copyFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); @@ -217,6 +239,9 @@ class Quota extends Wrapper { * @return bool */ public function moveFromStorage(IStorage $sourceStorage, $sourceInternalPath, $targetInternalPath) { + if (!$this->hasQuota()) { + return $this->storage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); + } $free = $this->free_space($targetInternalPath); if ($free < 0 or $this->getSize($sourceInternalPath, $sourceStorage) < $free) { return $this->storage->moveFromStorage($sourceStorage, $sourceInternalPath, $targetInternalPath); @@ -226,8 +251,11 @@ class Quota extends Wrapper { } public function mkdir($path) { + if (!$this->hasQuota()) { + return $this->storage->mkdir($path); + } $free = $this->free_space($path); - if ($this->shouldApplyQuota($path) && $free === 0.0) { + if ($this->shouldApplyQuota($path) && $free == 0) { return false; } @@ -235,8 +263,11 @@ class Quota extends Wrapper { } public function touch($path, $mtime = null) { + if (!$this->hasQuota()) { + return $this->storage->touch($path, $mtime); + } $free = $this->free_space($path); - if ($free === 0.0) { + if ($free == 0) { return false; } diff --git a/tests/lib/Files/Storage/HomeStorageQuotaTest.php b/tests/lib/Files/Storage/HomeStorageQuotaTest.php deleted file mode 100644 index 177fe1b4f6c..00000000000 --- a/tests/lib/Files/Storage/HomeStorageQuotaTest.php +++ /dev/null @@ -1,84 +0,0 @@ - - * - * @copyright Copyright (c) 2015, ownCloud, Inc. - * @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 - * - */ - -namespace Test\Files\Storage; - -/** - * Class HomeStorageQuotaTest - * - * @group DB - */ -class HomeStorageQuotaTest extends \Test\TestCase { - /** - * Tests that the home storage is not wrapped when no quota exists. - */ - public function testHomeStorageWrapperWithoutQuota() { - $user1 = $this->getUniqueID(); - \OC::$server->getUserManager()->createUser($user1, 'test'); - \OC::$server->getConfig()->setUserValue($user1, 'files', 'quota', 'none'); - \OC_User::setUserId($user1); - - \OC_Util::setupFS($user1); - - $userMount = \OC\Files\Filesystem::getMountManager()->find('/' . $user1 . '/'); - $this->assertNotNull($userMount); - $this->assertNotInstanceOf('\OC\Files\Storage\Wrapper\Quota', $userMount->getStorage()); - - // clean up - \OC_User::setUserId(''); - $user = \OC::$server->getUserManager()->get($user1); - if ($user !== null) { - $user->delete(); - } - \OC::$server->getConfig()->deleteAllUserValues($user1); - \OC_Util::tearDownFS(); - } - - /** - * Tests that the home storage is not wrapped when no quota exists. - */ - public function testHomeStorageWrapperWithQuota() { - $user1 = $this->getUniqueID(); - \OC::$server->getUserManager()->createUser($user1, 'test'); - \OC::$server->getConfig()->setUserValue($user1, 'files', 'quota', '1024'); - \OC_User::setUserId($user1); - - \OC_Util::setupFS($user1); - - $userMount = \OC\Files\Filesystem::getMountManager()->find('/' . $user1 . '/'); - $this->assertNotNull($userMount); - $this->assertTrue($userMount->getStorage()->instanceOfStorage('\OC\Files\Storage\Wrapper\Quota')); - - // ensure that root wasn't wrapped - $rootMount = \OC\Files\Filesystem::getMountManager()->find('/'); - $this->assertNotNull($rootMount); - $this->assertNotInstanceOf('\OC\Files\Storage\Wrapper\Quota', $rootMount->getStorage()); - - // clean up - \OC_User::setUserId(''); - $user = \OC::$server->getUserManager()->get($user1); - if ($user !== null) { - $user->delete(); - } - \OC::$server->getConfig()->deleteAllUserValues($user1); - \OC_Util::tearDownFS(); - } -}