Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix truncation of files upon read when using object store and encryption #28389

Merged
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 30 additions & 2 deletions lib/private/Files/Storage/Wrapper/Encryption.php
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,7 @@ public function fopen($path, $mode) {
$handle = \OC\Files\Stream\Encryption::wrap($source, $path, $fullPath, $header,
$this->uid, $encryptionModule, $this->storage, $this, $this->util, $this->fileHelper, $mode,
$size, $unencryptedSize, $headerSize, $signed);

return $handle;
}
}
Expand Down Expand Up @@ -540,7 +541,7 @@ protected function fixUnencryptedSize($path, $size, $unencryptedSize) {

// if a header exists we skip it
if ($headerSize > 0) {
fread($stream, $headerSize);
$this->fread_block($stream, $headerSize);
}

// fast path, else the calculation for $lastChunkNr is bogus
Expand All @@ -567,7 +568,7 @@ protected function fixUnencryptedSize($path, $size, $unencryptedSize) {
$count = $blockSize;

while ($count > 0) {
$data = fread($stream, $blockSize);
$data = $this->fread_block($stream, $blockSize);
$count = strlen($data);
$lastChunkContentEncrypted .= $data;
if (strlen($lastChunkContentEncrypted) > $blockSize) {
Expand Down Expand Up @@ -598,6 +599,33 @@ protected function fixUnencryptedSize($path, $size, $unencryptedSize) {
return $newUnencryptedSize;
}

/**
* fread_block
*
* This function is a wrapper around the fread function. It is based on the
* stream_read_block function from lib/private/Files/Streams/Encryption.php
* It calls stream read until the requested $blockSize was received or no remaining data is present.
* This is required as stream_read only returns smaller chunks of data when the stream fetches from a
* remote storage over the internet and it does not care about the given $blockSize.
*
* @param handle the stream to read from
* @param int $blockSize Length of requested data block in bytes
* @return string Data fetched from stream.
*/
private function fread_block($handle, int $blockSize): string {
$remaining = $blockSize;
$data = '';

do {
$chunk = fread($handle, $remaining);
$chunk_len = strlen($chunk);
$data .= $chunk;
$remaining -= $chunk_len;
} while (($remaining > 0) && ($chunk_len > 0));

return $data;
}

/**
* @param Storage\IStorage $sourceStorage
* @param string $sourceInternalPath
Expand Down