From 32aff32c73b108cd9554aaf22fd49cefd2d059af Mon Sep 17 00:00:00 2001
From: Torsten Grote <t@grobox.de>
Date: Thu, 14 Nov 2024 14:51:11 -0300
Subject: [PATCH] Fix FullRestore when Loader#loadFiles() throws an error for a
 later blob stream.

---
 .../transport/restore/FullRestore.kt          |  2 +-
 .../transport/restore/FullRestoreTest.kt      | 33 +++++++++++++++++++
 2 files changed, 34 insertions(+), 1 deletion(-)

diff --git a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/FullRestore.kt b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/FullRestore.kt
index a5240362..9b70e64f 100644
--- a/app/src/main/java/com/stevesoltys/seedvault/transport/restore/FullRestore.kt
+++ b/app/src/main/java/com/stevesoltys/seedvault/transport/restore/FullRestore.kt
@@ -161,7 +161,7 @@ internal class FullRestore(
         return outputFactory.getOutputStream(pfd).use { outputStream ->
             try {
                 copyInputStream(outputStream)
-            } catch (e: IOException) {
+            } catch (e: Exception) {
                 Log.w(TAG, "Error copying stream for package $packageName.", e)
                 return TRANSPORT_PACKAGE_REJECTED
             }
diff --git a/app/src/test/java/com/stevesoltys/seedvault/transport/restore/FullRestoreTest.kt b/app/src/test/java/com/stevesoltys/seedvault/transport/restore/FullRestoreTest.kt
index 724d644f..c26a602f 100644
--- a/app/src/test/java/com/stevesoltys/seedvault/transport/restore/FullRestoreTest.kt
+++ b/app/src/test/java/com/stevesoltys/seedvault/transport/restore/FullRestoreTest.kt
@@ -15,6 +15,7 @@ import com.stevesoltys.seedvault.coAssertThrows
 import com.stevesoltys.seedvault.getRandomByteArray
 import com.stevesoltys.seedvault.header.MAX_SEGMENT_LENGTH
 import com.stevesoltys.seedvault.header.VERSION
+import com.stevesoltys.seedvault.repo.HashMismatchException
 import com.stevesoltys.seedvault.repo.Loader
 import io.mockk.CapturingSlot
 import io.mockk.Runs
@@ -32,7 +33,9 @@ import org.junit.jupiter.api.Assertions.assertTrue
 import org.junit.jupiter.api.Test
 import java.io.ByteArrayInputStream
 import java.io.ByteArrayOutputStream
+import java.io.FilterInputStream
 import java.io.IOException
+import java.io.SequenceInputStream
 import java.security.GeneralSecurityException
 import kotlin.random.Random
 
@@ -114,6 +117,36 @@ internal class FullRestoreTest : RestoreTest() {
         verify { fileDescriptor.close() }
     }
 
+    @Test
+    fun `reading from stream throws HashMismatchException in SequenceInputStream`() = runBlocking {
+        restore.initializeState(VERSION, packageInfo, blobHandles)
+        val bytes = getRandomByteArray()
+
+        val inputStream = SequenceInputStream(
+            ByteArrayInputStream(bytes),
+            object : FilterInputStream(ByteArrayInputStream(bytes)) {
+                override fun read(): Int {
+                    throw HashMismatchException()
+                }
+
+                override fun read(b: ByteArray, off: Int, len: Int): Int {
+                    throw HashMismatchException()
+                }
+            },
+        )
+        coEvery { loader.loadFiles(blobHandles) } returns inputStream
+        every { outputFactory.getOutputStream(fileDescriptor) } returns outputStream
+        every { fileDescriptor.close() } just Runs
+
+        assertEquals(bytes.size, restore.getNextFullRestoreDataChunk(fileDescriptor))
+        assertEquals(
+            TRANSPORT_PACKAGE_REJECTED,
+            restore.getNextFullRestoreDataChunk(fileDescriptor),
+        )
+
+        verify { fileDescriptor.close() }
+    }
+
     @Test
     fun `full chunk gets decrypted`() = runBlocking {
         restore.initializeState(VERSION, packageInfo, blobHandles)