diff --git a/build/psalm-baseline.xml b/build/psalm-baseline.xml
index 2386288f863c9..98d07a2ab20b6 100644
--- a/build/psalm-baseline.xml
+++ b/build/psalm-baseline.xml
@@ -3896,14 +3896,7 @@
-
-
-
-
-
-
-
diff --git a/lib/private/Files/Storage/Wrapper/Encryption.php b/lib/private/Files/Storage/Wrapper/Encryption.php
index 9e6164e0615d0..33d13a01f4004 100644
--- a/lib/private/Files/Storage/Wrapper/Encryption.php
+++ b/lib/private/Files/Storage/Wrapper/Encryption.php
@@ -418,7 +418,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);
@@ -453,8 +453,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 6b7f9b01a869f..3380c3e14c389 100644
--- a/tests/lib/Files/Storage/Wrapper/EncryptionTest.php
+++ b/tests/lib/Files/Storage/Wrapper/EncryptionTest.php
@@ -457,6 +457,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