diff --git a/build/psalm-baseline.xml b/build/psalm-baseline.xml index f43a9e4aa7b31..496f92d52f4d8 100644 --- a/build/psalm-baseline.xml +++ b/build/psalm-baseline.xml @@ -3807,14 +3807,7 @@ - - - - - - - diff --git a/lib/private/Files/Storage/Wrapper/Encryption.php b/lib/private/Files/Storage/Wrapper/Encryption.php index 4bc4d92661f2a..6f900ecf0bc69 100644 --- a/lib/private/Files/Storage/Wrapper/Encryption.php +++ b/lib/private/Files/Storage/Wrapper/Encryption.php @@ -406,7 +406,7 @@ protected function verifyUnencryptedSize(string $path, int $unencryptedSize): in * @param int $size size of the physical file * @param int $unencryptedSize size of the unencrypted file */ - protected function fixUnencryptedSize(string $path, int $size, int $unencryptedSize): int|float { + protected function fixUnencryptedSize(string $path, int $size, int $unencryptedSize): int { $headerSize = $this->getHeaderSize($path); $header = $this->getHeader($path); $encryptionModule = $this->getEncryptionModule($path); @@ -441,8 +441,7 @@ protected function fixUnencryptedSize(string $path, int $size, int $unencryptedS // calculate last chunk nr // next highest is end of chunks, one subtracted is last one // we have to read the last chunk, we can't just calculate it (because of padding etc) - - $lastChunkNr = ceil($size / $blockSize) - 1; + $lastChunkNr = (int)ceil($size / $blockSize) - 1; // calculate last chunk position $lastChunkPos = ($lastChunkNr * $blockSize); // try to fseek to the last chunk, if it fails we have to read the whole file diff --git a/tests/lib/Files/Storage/Wrapper/EncryptionTest.php b/tests/lib/Files/Storage/Wrapper/EncryptionTest.php index ddcfe5e89347f..d63c4dc00aa7d 100644 --- a/tests/lib/Files/Storage/Wrapper/EncryptionTest.php +++ b/tests/lib/Files/Storage/Wrapper/EncryptionTest.php @@ -456,6 +456,67 @@ public function testFixUnencryptedSizeUsesBlockSizeOfFileEncoding(): void { ); } + /** + * filesize() remembers a recalculated size and updates the file cache whenever the + * remembered size is not identical to the cached one, which also dispatches an event. + */ + public function testFilesizeUpdatesRecalculatedSizeOnce(): void { + $module = $this->createMock(IEncryptionModule::class); + $module->method('begin')->willReturn([]); + $module->method('getUnencryptedBlockSize')->willReturn(6072); + $module->method('decrypt')->willReturn(str_repeat('a', 42)); + $module->method('end')->willReturn(''); + + $header = ['cipher' => 'AES-256-CTR', 'signed' => 'true', 'oc_encryption_module' => 'UNIT_TEST_MODULE']; + $content = str_pad(Util::HEADER_START, $this->headerSize, '-') . str_repeat('x', 2 * 8192 + 100); + $stream = fopen('php://memory', 'r+'); + fwrite($stream, $content); + rewind($stream); + + $entry = new CacheEntry(['fileid' => 42, 'encrypted' => true, 'encryptedVersion' => 1, 'size' => 0, 'unencrypted_size' => 0]); + $cache = $this->createMock(ICache::class); + $cache->method('get')->with('file.003')->willReturnCallback(function () use (&$entry) { + return $entry; + }); + $cache->expects($this->once())->method('update') + ->willReturnCallback(function (int $id, array $data) use (&$entry): void { + $entry = new CacheEntry(array_merge($entry->getData(), $data)); + }); + $sourceStorage = $this->createMock(\OC\Files\Storage\Storage::class); + $sourceStorage->method('filesize')->with('file.003')->willReturn(strlen($content)); + $sourceStorage->method('fopen')->with('file.003', 'r')->willReturn($stream); + $sourceStorage->method('getCache')->willReturn($cache); + + $instance = $this->getMockBuilder(Encryption::class) + ->setConstructorArgs( + [ + [ + 'storage' => $sourceStorage, + 'root' => 'foo', + 'mountPoint' => '/', + 'mount' => $this->mount + ], + $this->encryptionManager, + $this->util, + $this->logger, + $this->file, + null, + $this->keyStore, + $this->mountManager, + $this->arrayCache, + ] + ) + ->onlyMethods(['getHeader', 'getHeaderSize', 'getEncryptionModule']) + ->getMock(); + $instance->method('getHeader')->willReturn($header); + $instance->method('getHeaderSize')->willReturn($this->headerSize); + $instance->method('getEncryptionModule')->willReturn($module); + + $expected = 2 * 6072 + 42; + $this->assertSame($expected, $instance->filesize('file.003')); + $this->assertSame($expected, $instance->filesize('file.003')); + } + /** * * @param string $source