From df941670a81547ac1af852a575e268195488b725 Mon Sep 17 00:00:00 2001 From: Stypox Date: Sun, 24 Nov 2024 18:34:22 +0100 Subject: [PATCH 1/3] Fix downloading/exporting when overwriting file would not truncate --- .../services/SubscriptionsExportService.java | 2 +- .../newpipe/settings/export/ImportExportManager.kt | 3 +-- .../schabi/newpipe/streams/io/StoredFileHelper.java | 13 +++++++++++++ 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/schabi/newpipe/local/subscription/services/SubscriptionsExportService.java b/app/src/main/java/org/schabi/newpipe/local/subscription/services/SubscriptionsExportService.java index 54809068a..641f044bf 100644 --- a/app/src/main/java/org/schabi/newpipe/local/subscription/services/SubscriptionsExportService.java +++ b/app/src/main/java/org/schabi/newpipe/local/subscription/services/SubscriptionsExportService.java @@ -76,7 +76,7 @@ public class SubscriptionsExportService extends BaseImportExportService { try { outFile = new StoredFileHelper(this, path, "application/json"); - outputStream = new SharpOutputStream(outFile.getStream()); + outputStream = new SharpOutputStream(outFile.openAndTruncateStream()); } catch (final IOException e) { handleError(e); return START_NOT_STICKY; diff --git a/app/src/main/java/org/schabi/newpipe/settings/export/ImportExportManager.kt b/app/src/main/java/org/schabi/newpipe/settings/export/ImportExportManager.kt index 93c1bfb81..1a92a8a00 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/export/ImportExportManager.kt +++ b/app/src/main/java/org/schabi/newpipe/settings/export/ImportExportManager.kt @@ -24,8 +24,7 @@ class ImportExportManager(private val fileLocator: BackupFileLocator) { */ @Throws(Exception::class) fun exportDatabase(preferences: SharedPreferences, file: StoredFileHelper) { - file.create() - ZipOutputStream(SharpOutputStream(file.stream).buffered()).use { outZip -> + ZipOutputStream(SharpOutputStream(file.openAndTruncateStream()).buffered()).use { outZip -> // add the database ZipHelper.addFileToZip( outZip, diff --git a/app/src/main/java/org/schabi/newpipe/streams/io/StoredFileHelper.java b/app/src/main/java/org/schabi/newpipe/streams/io/StoredFileHelper.java index 5404426c4..1e2c178bf 100644 --- a/app/src/main/java/org/schabi/newpipe/streams/io/StoredFileHelper.java +++ b/app/src/main/java/org/schabi/newpipe/streams/io/StoredFileHelper.java @@ -189,6 +189,19 @@ public class StoredFileHelper implements Serializable { } } + public SharpStream openAndTruncateStream() throws IOException { + final SharpStream sharpStream = getStream(); + try { + sharpStream.setLength(0); + } catch (final Throwable e) { + // we can't use try-with-resources here, since we only want to close the stream if an + // exception occurs, but leave it open if everything goes well + sharpStream.close(); + throw e; + } + return sharpStream; + } + /** * Indicates whether it's using the {@code java.io} API. * From b21981a9c714255e52766263be72534275e04781 Mon Sep 17 00:00:00 2001 From: Stypox Date: Wed, 27 Nov 2024 16:34:50 +0100 Subject: [PATCH 2/3] Add comments to explain why openAndTruncateStream() --- .../subscription/services/SubscriptionsExportService.java | 3 +++ .../org/schabi/newpipe/settings/export/ImportExportManager.kt | 2 ++ 2 files changed, 5 insertions(+) diff --git a/app/src/main/java/org/schabi/newpipe/local/subscription/services/SubscriptionsExportService.java b/app/src/main/java/org/schabi/newpipe/local/subscription/services/SubscriptionsExportService.java index 641f044bf..ab1a5a10c 100644 --- a/app/src/main/java/org/schabi/newpipe/local/subscription/services/SubscriptionsExportService.java +++ b/app/src/main/java/org/schabi/newpipe/local/subscription/services/SubscriptionsExportService.java @@ -76,6 +76,9 @@ public class SubscriptionsExportService extends BaseImportExportService { try { outFile = new StoredFileHelper(this, path, "application/json"); + // truncate the file before writing to it, otherwise if the new content is smaller than + // the previous file size, the file will retain part of the previous content and be + // corrupted outputStream = new SharpOutputStream(outFile.openAndTruncateStream()); } catch (final IOException e) { handleError(e); diff --git a/app/src/main/java/org/schabi/newpipe/settings/export/ImportExportManager.kt b/app/src/main/java/org/schabi/newpipe/settings/export/ImportExportManager.kt index 1a92a8a00..36e0b9ce1 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/export/ImportExportManager.kt +++ b/app/src/main/java/org/schabi/newpipe/settings/export/ImportExportManager.kt @@ -24,6 +24,8 @@ class ImportExportManager(private val fileLocator: BackupFileLocator) { */ @Throws(Exception::class) fun exportDatabase(preferences: SharedPreferences, file: StoredFileHelper) { + // truncate the file before writing to it, otherwise if the new content is smaller than the + // previous file size, the file will retain part of the previous content and be corrupted ZipOutputStream(SharpOutputStream(file.openAndTruncateStream()).buffered()).use { outZip -> // add the database ZipHelper.addFileToZip( From e31a8ad7a2e983e06236fd9692d71f472926f0fd Mon Sep 17 00:00:00 2001 From: Stypox Date: Wed, 27 Nov 2024 16:37:25 +0100 Subject: [PATCH 3/3] Mock openAndTruncateStream instead of getStream in test --- .../java/org/schabi/newpipe/settings/ImportExportManagerTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/test/java/org/schabi/newpipe/settings/ImportExportManagerTest.kt b/app/src/test/java/org/schabi/newpipe/settings/ImportExportManagerTest.kt index a524f64f3..5b8023561 100644 --- a/app/src/test/java/org/schabi/newpipe/settings/ImportExportManagerTest.kt +++ b/app/src/test/java/org/schabi/newpipe/settings/ImportExportManagerTest.kt @@ -55,7 +55,7 @@ class ImportExportManagerTest { `when`(sharedPreferences.all).thenReturn(expectedPreferences) val output = File.createTempFile("newpipe_", "") - `when`(storedFileHelper.stream).thenReturn(FileStream(output)) + `when`(storedFileHelper.openAndTruncateStream()).thenReturn(FileStream(output)) ImportExportManager(fileLocator).exportDatabase(sharedPreferences, storedFileHelper) val zipFile = ZipFile(output)