diff --git a/apps/encryption/tests/CopySizeTest.php b/apps/encryption/tests/CopySizeTest.php new file mode 100644 index 0000000000000..b04aecbd6f449 --- /dev/null +++ b/apps/encryption/tests/CopySizeTest.php @@ -0,0 +1,69 @@ +validateMasterKey(); + Server::get(KeyManager::class)->validateShareKey(); + $this->createUser('test1', 'test2'); + $this->setupForUser('test1', 'test2'); + $this->registerMount('test1', new Temporary(), '/test1/files/other'); + $this->loginWithEncryption('test1'); + + return new View('/test1/files'); + } + + public function testCopyKeepsTheSize(): void { + $view = $this->setUpView(); + + $view->file_put_contents('source.bin', str_repeat('a', 20000)); + $this->assertTrue($view->copy('source.bin', 'target.bin')); + + $this->assertEquals(20000, $view->getFileInfo('target.bin')->getSize()); + } + + public function testCopyToAnotherStorageKeepsTheSize(): void { + $view = $this->setUpView(); + + $view->file_put_contents('source.bin', str_repeat('a', 20000)); + $this->assertTrue($view->copy('source.bin', 'other/target.bin')); + + $this->assertEquals(20000, $view->getFileInfo('other/target.bin')->getSize()); + } + + public function testCopyOfAFolderKeepsTheSizes(): void { + $view = $this->setUpView(); + + $view->mkdir('source'); + $view->file_put_contents('source/file.bin', str_repeat('a', 20000)); + $this->assertTrue($view->copy('source', 'target')); + + $this->assertEquals(20000, $view->getFileInfo('target/file.bin')->getSize()); + } +} diff --git a/build/integration/encryption_features/encryption.feature b/build/integration/encryption_features/encryption.feature index 15704609d79df..91854555a538f 100644 --- a/build/integration/encryption_features/encryption.feature +++ b/build/integration/encryption_features/encryption.feature @@ -26,6 +26,7 @@ Feature: encryption And User "user0" adds a file of 20000 bytes to "/big.bin" When User "user0" copies file "/big.bin" to "/copy.bin" Then the HTTP status code should be "201" + And File "/copy.bin" should have prop "d:getcontentlength" equal to "20000" When Downloading file "/copy.bin" Then the HTTP status code should be "200" diff --git a/lib/private/Files/Cache/Cache.php b/lib/private/Files/Cache/Cache.php index 7c8023c90c1d6..1e729c33cd1fd 100644 --- a/lib/private/Files/Cache/Cache.php +++ b/lib/private/Files/Cache/Cache.php @@ -1316,8 +1316,14 @@ private function cacheEntryToArray(ICacheEntry $entry): array { $data['permissions'] = $entry['scan_permissions']; } - if ($entry->isEncrypted() && isset($entry['encryptedVersion'])) { - $data['encryptedVersion'] = $entry['encryptedVersion']; + if ($entry->isEncrypted()) { + // the size of an encrypted file is stored in its own column, which every + // reader prefers over `size`, so the copy is reported as empty without it + $data['unencrypted_size'] = $entry->getUnencryptedSize(); + + if (isset($entry['encryptedVersion'])) { + $data['encryptedVersion'] = $entry['encryptedVersion']; + } } return $data; diff --git a/tests/lib/Files/Cache/CacheTest.php b/tests/lib/Files/Cache/CacheTest.php index 39e05c590ee98..023e4a76d256f 100644 --- a/tests/lib/Files/Cache/CacheTest.php +++ b/tests/lib/Files/Cache/CacheTest.php @@ -602,10 +602,25 @@ public function testCopyFromCachePreservesEncryptedVersion(): void { $this->assertSame(3, $targetEntry['encryptedVersion']); } + public function testCopyFromCachePreservesUnencryptedSize(): void { + $data = [ + 'size' => 128, 'mtime' => 50, 'mimetype' => 'foo/bar', + 'encrypted' => true, 'encryptedVersion' => 3, 'unencrypted_size' => 100, + ]; + $this->cache->put('source', $data); + $sourceEntry = $this->cache->get('source'); + $this->assertEquals(100, $sourceEntry->getUnencryptedSize()); + + $this->cache->copyFromCache($this->cache, $sourceEntry, 'target'); + + $targetEntry = $this->cache->get('target'); + $this->assertEquals(100, $targetEntry->getUnencryptedSize()); + } + public function testCopyFromCacheClearsEncryptedVersionWhenCopyingToNonEncryptedStorage(): void { $data = [ - 'size' => 100, 'mtime' => 50, 'mimetype' => 'foo/bar', - 'encrypted' => true, 'encryptedVersion' => 3, + 'size' => 128, 'mtime' => 50, 'mimetype' => 'foo/bar', + 'encrypted' => true, 'encryptedVersion' => 3, 'unencrypted_size' => 100, ]; $this->cache2->put('source', $data); $sourceEntry = $this->cache2->get('source'); @@ -627,6 +642,9 @@ public function testCopyFromCacheClearsEncryptedVersionWhenCopyingToNonEncrypted $targetEntry = $targetCache->get('target'); $this->assertFalse($targetEntry->isEncrypted()); $this->assertSame(0, $targetEntry['encryptedVersion']); + // the target is not marked as encrypted, so its size is read from `size` + $this->assertEquals(0, $targetEntry['unencrypted_size']); + $this->assertEquals(128, $targetEntry->getSize()); } public function testGetIncomplete(): void {