From e515069b5361e4b6a7e689cc5e7cce9df388ed3e Mon Sep 17 00:00:00 2001 From: Koitharu Date: Fri, 11 Oct 2024 10:55:47 +0300 Subject: [PATCH] Fix zip closing (cherry picked from commit 144e66bedb5618c0041acd955d11f7ffba05c436) --- .../kotatsu/core/backup/BackupZipInput.kt | 15 +++------ .../koitharu/kotatsu/core/util/ext/File.kt | 8 ----- .../org/koitharu/kotatsu/core/util/ext/Uri.kt | 10 ++++-- .../ui/pager/pages/MangaPageFetcher.kt | 29 ++++++++++------- .../koitharu/kotatsu/local/data/CbzFetcher.kt | 31 +++++++++++-------- .../settings/backup/RestoreViewModel.kt | 7 ++++- 6 files changed, 53 insertions(+), 47 deletions(-) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/BackupZipInput.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/BackupZipInput.kt index 2fb7cd110..a1499afc7 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/BackupZipInput.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/backup/BackupZipInput.kt @@ -1,14 +1,11 @@ package org.koitharu.kotatsu.core.backup -import kotlinx.coroutines.CoroutineStart import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch import kotlinx.coroutines.runInterruptible import okhttp3.internal.closeQuietly import okio.Closeable import org.json.JSONArray import org.koitharu.kotatsu.core.exceptions.BadBackupFormatException -import org.koitharu.kotatsu.core.util.ext.processLifecycleScope import java.io.File import java.util.EnumSet import java.util.zip.ZipException @@ -36,13 +33,9 @@ class BackupZipInput private constructor(val file: File) : Closeable { zipFile.close() } - fun cleanupAsync() { - processLifecycleScope.launch(Dispatchers.IO, CoroutineStart.ATOMIC) { - runCatching { - closeQuietly() - file.delete() - } - } + fun closeAndDelete() { + closeQuietly() + file.delete() } companion object { @@ -55,7 +48,7 @@ class BackupZipInput private constructor(val file: File) : Closeable { throw BadBackupFormatException(null) } res - } catch (exception: Exception) { + } catch (exception: Throwable) { res?.closeQuietly() throw if (exception is ZipException) { BadBackupFormatException(exception) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/File.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/File.kt index 2343f8ec7..174b0715c 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/File.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/File.kt @@ -39,14 +39,6 @@ fun ZipFile.readText(entry: ZipEntry) = getInputStream(entry).bufferedReader().u it.readText() } -@Blocking -fun ZipFile.getInputStreamOrClose(entry: ZipEntry): InputStream = try { - getInputStream(entry) -} catch (e: Throwable) { - closeQuietly() - throw e -} - fun File.getStorageName(context: Context): String = runCatching { val manager = context.getSystemService(Context.STORAGE_SERVICE) as StorageManager if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Uri.kt b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Uri.kt index 152aebd14..5664a180d 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Uri.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/core/util/ext/Uri.kt @@ -2,6 +2,7 @@ package org.koitharu.kotatsu.core.util.ext import android.net.Uri import androidx.core.net.toFile +import okhttp3.internal.closeQuietly import okio.Source import okio.source import okio.use @@ -40,8 +41,13 @@ fun Uri.source(): Source = when (scheme) { URI_SCHEME_FILE -> toFile().source() URI_SCHEME_ZIP -> { val zip = ZipFile(schemeSpecificPart) - val entry = zip.getEntry(fragment) - zip.getInputStreamOrClose(entry).source().withExtraCloseable(zip) + try { + val entry = zip.getEntry(fragment) + zip.getInputStream(entry).source().withExtraCloseable(zip) + } catch (e: Throwable) { + zip.closeQuietly() + throw e + } } else -> unsupportedUri(this) diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/pages/MangaPageFetcher.kt b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/pages/MangaPageFetcher.kt index e2d541e64..a5d8b7082 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/pages/MangaPageFetcher.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/details/ui/pager/pages/MangaPageFetcher.kt @@ -16,13 +16,13 @@ import dagger.hilt.android.qualifiers.ApplicationContext import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runInterruptible import okhttp3.OkHttpClient +import okhttp3.internal.closeQuietly import okio.Path.Companion.toOkioPath import okio.buffer import okio.source import org.koitharu.kotatsu.core.network.MangaHttpClient import org.koitharu.kotatsu.core.network.imageproxy.ImageProxyInterceptor import org.koitharu.kotatsu.core.parser.MangaRepository -import org.koitharu.kotatsu.core.util.ext.getInputStreamOrClose import org.koitharu.kotatsu.local.data.PagesCache import org.koitharu.kotatsu.local.data.isFileUri import org.koitharu.kotatsu.local.data.isZipUri @@ -67,17 +67,22 @@ class MangaPageFetcher( return when { uri.isZipUri() -> runInterruptible(Dispatchers.IO) { val zip = ZipFile(uri.schemeSpecificPart) - val entry = zip.getEntry(uri.fragment) - SourceResult( - source = ImageSource( - source = zip.getInputStreamOrClose(entry).source().withExtraCloseable(zip).buffer(), - context = context, - metadata = MangaPageMetadata(page), - ), - mimeType = MimeTypeMap.getSingleton() - .getMimeTypeFromExtension(entry.name.substringAfterLast('.', "")), - dataSource = DataSource.DISK, - ) + try { + val entry = zip.getEntry(uri.fragment) + SourceResult( + source = ImageSource( + source = zip.getInputStream(entry).source().withExtraCloseable(zip).buffer(), + context = context, + metadata = MangaPageMetadata(page), + ), + mimeType = MimeTypeMap.getSingleton() + .getMimeTypeFromExtension(entry.name.substringAfterLast('.', "")), + dataSource = DataSource.DISK, + ) + } catch (e: Throwable) { + zip.closeQuietly() + throw e + } } uri.isFileUri() -> runInterruptible(Dispatchers.IO) { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/local/data/CbzFetcher.kt b/app/src/main/kotlin/org/koitharu/kotatsu/local/data/CbzFetcher.kt index 0ce579bd3..c80fefa1e 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/local/data/CbzFetcher.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/local/data/CbzFetcher.kt @@ -10,9 +10,9 @@ import coil.fetch.SourceResult import coil.request.Options import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.runInterruptible +import okhttp3.internal.closeQuietly import okio.buffer import okio.source -import org.koitharu.kotatsu.core.util.ext.getInputStreamOrClose import org.koitharu.kotatsu.local.data.util.withExtraCloseable import java.util.zip.ZipFile @@ -23,18 +23,23 @@ class CbzFetcher( override suspend fun fetch() = runInterruptible(Dispatchers.IO) { val zip = ZipFile(uri.schemeSpecificPart) - val entry = zip.getEntry(uri.fragment) - val ext = MimeTypeMap.getFileExtensionFromUrl(entry.name) - val bufferedSource = zip.getInputStreamOrClose(entry).source().withExtraCloseable(zip).buffer() - SourceResult( - source = ImageSource( - source = bufferedSource, - context = options.context, - metadata = CbzMetadata(uri), - ), - mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext), - dataSource = DataSource.DISK, - ) + try { + val entry = zip.getEntry(uri.fragment) + val ext = MimeTypeMap.getFileExtensionFromUrl(entry.name) + val bufferedSource = zip.getInputStream(entry).source().withExtraCloseable(zip).buffer() + SourceResult( + source = ImageSource( + source = bufferedSource, + context = options.context, + metadata = CbzMetadata(uri), + ), + mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext), + dataSource = DataSource.DISK, + ) + } catch (e: Throwable) { + zip.closeQuietly() + throw e + } } class Factory : Fetcher.Factory { diff --git a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/RestoreViewModel.kt b/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/RestoreViewModel.kt index bef9212ad..3af75946f 100644 --- a/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/RestoreViewModel.kt +++ b/app/src/main/kotlin/org/koitharu/kotatsu/settings/backup/RestoreViewModel.kt @@ -14,6 +14,7 @@ import org.koitharu.kotatsu.core.backup.CompositeResult import org.koitharu.kotatsu.core.ui.BaseViewModel import org.koitharu.kotatsu.core.util.ext.MutableEventFlow import org.koitharu.kotatsu.core.util.ext.call +import org.koitharu.kotatsu.core.util.ext.printStackTraceDebug import org.koitharu.kotatsu.core.util.ext.toUriOrNull import org.koitharu.kotatsu.parsers.util.SuspendLazy import java.io.File @@ -71,7 +72,11 @@ class RestoreViewModel @Inject constructor( override fun onCleared() { super.onCleared() - backupInput.peek()?.cleanupAsync() + runCatching { + backupInput.peek()?.closeAndDelete() + }.onFailure { + it.printStackTraceDebug() + } } fun onItemClick(item: BackupEntryModel) {