From dafdd6167e0c0d88074fa5407e22dacd8e3e8f1c Mon Sep 17 00:00:00 2001 From: Louis Chemineau Date: Fri, 16 May 2025 16:20:29 +0200 Subject: [PATCH 1/3] fix(S3): Use original folder size during copy This prevent having copied folders with a wrongly set size of 0KB. - Fix https://github.com/nextcloud/server/issues/51916 Signed-off-by: Louis Chemineau --- lib/private/Files/ObjectStore/ObjectStoreStorage.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/private/Files/ObjectStore/ObjectStoreStorage.php b/lib/private/Files/ObjectStore/ObjectStoreStorage.php index d8431b1bd687f..c01fc99ac2fbf 100644 --- a/lib/private/Files/ObjectStore/ObjectStoreStorage.php +++ b/lib/private/Files/ObjectStore/ObjectStoreStorage.php @@ -732,6 +732,10 @@ private function copyInner(ICache $sourceCache, ICacheEntry $sourceEntry, string $cache->remove($to); } $this->mkdir($to); + $cacheEntry = $cache->get(($to)); + $cache->update($cacheEntry->getId(), [ + 'size' => $sourceEntry->getSize(), + ]); foreach ($sourceCache->getFolderContentsById($sourceEntry->getId()) as $child) { $this->copyInner($sourceCache, $child, $to . '/' . $child->getName()); From 662129ca0a42b7573c6cbe2b213b10ac37530591 Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Tue, 27 May 2025 19:29:44 +0200 Subject: [PATCH 2/3] perf: set the folder size in the same query as we create it Signed-off-by: Robin Appelman --- lib/private/Files/ObjectStore/ObjectStoreStorage.php | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/lib/private/Files/ObjectStore/ObjectStoreStorage.php b/lib/private/Files/ObjectStore/ObjectStoreStorage.php index c01fc99ac2fbf..8ee056e5b442a 100644 --- a/lib/private/Files/ObjectStore/ObjectStoreStorage.php +++ b/lib/private/Files/ObjectStore/ObjectStoreStorage.php @@ -88,7 +88,7 @@ public function __construct($params) { $this->logger = \OCP\Server::get(LoggerInterface::class); } - public function mkdir($path, bool $force = false) { + public function mkdir($path, bool $force = false, array $metadata = []) { $path = $this->normalizePath($path); if (!$force && $this->file_exists($path)) { $this->logger->warning("Tried to create an object store folder that already exists: $path"); @@ -98,7 +98,7 @@ public function mkdir($path, bool $force = false) { $mTime = time(); $data = [ 'mimetype' => 'httpd/unix-directory', - 'size' => 0, + 'size' => $metadata['size'] ?? 0, 'mtime' => $mTime, 'storage_mtime' => $mTime, 'permissions' => \OCP\Constants::PERMISSION_ALL, @@ -731,11 +731,7 @@ private function copyInner(ICache $sourceCache, ICacheEntry $sourceEntry, string if ($cache->inCache($to)) { $cache->remove($to); } - $this->mkdir($to); - $cacheEntry = $cache->get(($to)); - $cache->update($cacheEntry->getId(), [ - 'size' => $sourceEntry->getSize(), - ]); + $this->mkdir($to, false, ['size' => $sourceEntry->getSize()]); foreach ($sourceCache->getFolderContentsById($sourceEntry->getId()) as $child) { $this->copyInner($sourceCache, $child, $to . '/' . $child->getName()); From 077f65455bfbd38c63acc100472d92cdf28a752f Mon Sep 17 00:00:00 2001 From: Robin Appelman Date: Tue, 27 May 2025 19:35:41 +0200 Subject: [PATCH 3/3] test: add test that object store folder copy preserves folder size Signed-off-by: Robin Appelman --- .../Files/ObjectStore/ObjectStoreStorageTest.php | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/lib/Files/ObjectStore/ObjectStoreStorageTest.php b/tests/lib/Files/ObjectStore/ObjectStoreStorageTest.php index a07104a590d64..cd3ac963cc92e 100644 --- a/tests/lib/Files/ObjectStore/ObjectStoreStorageTest.php +++ b/tests/lib/Files/ObjectStore/ObjectStoreStorageTest.php @@ -275,4 +275,17 @@ public function testCopyGrantsPermissions() { $this->assertTrue($cache->inCache('new.txt')); $this->assertEquals(\OCP\Constants::PERMISSION_ALL, $instance->getPermissions('new.txt')); } + + public function testCopyFolderSize(): void { + $cache = $this->instance->getCache(); + + $this->instance->mkdir('source'); + $this->instance->file_put_contents('source/test.txt', 'foo'); + $this->instance->getUpdater()->update('source/test.txt'); + $this->assertEquals(3, $cache->get('source')->getSize()); + + $this->assertTrue($this->instance->copy('source', 'target')); + + $this->assertEquals(3, $cache->get('target')->getSize()); + } }