From 80324117891b75135129eb9c372c6b4a5be9f92a Mon Sep 17 00:00:00 2001 From: Dillard Blom Date: Thu, 22 Oct 2026 19:50:27 +0200 Subject: [PATCH] Restore: the warning for a blob read again says how the first read differed (zeros, shifted, other bytes) --- lib/Repository/Repository.php | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/lib/Repository/Repository.php b/lib/Repository/Repository.php index 1c34ea0..bfd01e9 100644 --- a/lib/Repository/Repository.php +++ b/lib/Repository/Repository.php @@ -918,12 +918,31 @@ final class Repository { } $data = $this->decodeBlob($id, $again); if (function_exists('OCP\Log\logger')) { - \OCP\Log\logger('ng_backup')->warning('NG Backup: blob ' . $id . ' did not decrypt as first read from pack ' . $pack . '; read again, it is fine'); + \OCP\Log\logger('ng_backup')->warning('NG Backup: blob ' . $id . ' did not decrypt as first read from pack ' . $pack . ' at ' . $offset . '; read again, it is fine. First read: ' . self::howItDiffered($encrypted, $again)); } return $data; } } + /** + * What a read that went wrong looked like next to the right bytes, for the log: where it starts + * to differ, and whether the rest is zeros or the right bytes from another place (a stream that + * lost its place). + */ + private static function howItDiffered(string $wrong, string $right): string { + $at = strspn($wrong ^ $right, "\0"); + $text = strlen($wrong) . ' bytes, differ from byte ' . $at . ' of ' . strlen($right); + $tail = substr($wrong, $at, 64); + if ($tail === '') { + return $text . ' (too short)'; + } + if (trim($tail, "\0") === '') { + return $text . ' (zeros)'; + } + $found = strpos($right, $tail); + return $text . ($found !== false ? ' (the right bytes from ' . ($found - $at) . ' bytes further on)' : ' (other bytes)'); + } + /** Decrypts and checks a blob read from its pack; throws when it is corrupted or tampered with. */ private function decodeBlob(string $id, string $encrypted): string { [, , , $raw, $flags] = $this->index->get($id);