Fix zip closing

(cherry picked from commit 144e66bedb)
This commit is contained in:
Koitharu
2024-10-11 10:55:47 +03:00
parent 05d22167c4
commit e515069b53
6 changed files with 53 additions and 47 deletions

View File

@@ -1,14 +1,11 @@
package org.koitharu.kotatsu.core.backup package org.koitharu.kotatsu.core.backup
import kotlinx.coroutines.CoroutineStart
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runInterruptible import kotlinx.coroutines.runInterruptible
import okhttp3.internal.closeQuietly import okhttp3.internal.closeQuietly
import okio.Closeable import okio.Closeable
import org.json.JSONArray import org.json.JSONArray
import org.koitharu.kotatsu.core.exceptions.BadBackupFormatException import org.koitharu.kotatsu.core.exceptions.BadBackupFormatException
import org.koitharu.kotatsu.core.util.ext.processLifecycleScope
import java.io.File import java.io.File
import java.util.EnumSet import java.util.EnumSet
import java.util.zip.ZipException import java.util.zip.ZipException
@@ -36,13 +33,9 @@ class BackupZipInput private constructor(val file: File) : Closeable {
zipFile.close() zipFile.close()
} }
fun cleanupAsync() { fun closeAndDelete() {
processLifecycleScope.launch(Dispatchers.IO, CoroutineStart.ATOMIC) { closeQuietly()
runCatching { file.delete()
closeQuietly()
file.delete()
}
}
} }
companion object { companion object {
@@ -55,7 +48,7 @@ class BackupZipInput private constructor(val file: File) : Closeable {
throw BadBackupFormatException(null) throw BadBackupFormatException(null)
} }
res res
} catch (exception: Exception) { } catch (exception: Throwable) {
res?.closeQuietly() res?.closeQuietly()
throw if (exception is ZipException) { throw if (exception is ZipException) {
BadBackupFormatException(exception) BadBackupFormatException(exception)

View File

@@ -39,14 +39,6 @@ fun ZipFile.readText(entry: ZipEntry) = getInputStream(entry).bufferedReader().u
it.readText() 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 { fun File.getStorageName(context: Context): String = runCatching {
val manager = context.getSystemService(Context.STORAGE_SERVICE) as StorageManager val manager = context.getSystemService(Context.STORAGE_SERVICE) as StorageManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {

View File

@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.core.util.ext
import android.net.Uri import android.net.Uri
import androidx.core.net.toFile import androidx.core.net.toFile
import okhttp3.internal.closeQuietly
import okio.Source import okio.Source
import okio.source import okio.source
import okio.use import okio.use
@@ -40,8 +41,13 @@ fun Uri.source(): Source = when (scheme) {
URI_SCHEME_FILE -> toFile().source() URI_SCHEME_FILE -> toFile().source()
URI_SCHEME_ZIP -> { URI_SCHEME_ZIP -> {
val zip = ZipFile(schemeSpecificPart) val zip = ZipFile(schemeSpecificPart)
val entry = zip.getEntry(fragment) try {
zip.getInputStreamOrClose(entry).source().withExtraCloseable(zip) val entry = zip.getEntry(fragment)
zip.getInputStream(entry).source().withExtraCloseable(zip)
} catch (e: Throwable) {
zip.closeQuietly()
throw e
}
} }
else -> unsupportedUri(this) else -> unsupportedUri(this)

View File

@@ -16,13 +16,13 @@ import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runInterruptible import kotlinx.coroutines.runInterruptible
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.internal.closeQuietly
import okio.Path.Companion.toOkioPath import okio.Path.Companion.toOkioPath
import okio.buffer import okio.buffer
import okio.source import okio.source
import org.koitharu.kotatsu.core.network.MangaHttpClient import org.koitharu.kotatsu.core.network.MangaHttpClient
import org.koitharu.kotatsu.core.network.imageproxy.ImageProxyInterceptor import org.koitharu.kotatsu.core.network.imageproxy.ImageProxyInterceptor
import org.koitharu.kotatsu.core.parser.MangaRepository 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.PagesCache
import org.koitharu.kotatsu.local.data.isFileUri import org.koitharu.kotatsu.local.data.isFileUri
import org.koitharu.kotatsu.local.data.isZipUri import org.koitharu.kotatsu.local.data.isZipUri
@@ -67,17 +67,22 @@ class MangaPageFetcher(
return when { return when {
uri.isZipUri() -> runInterruptible(Dispatchers.IO) { uri.isZipUri() -> runInterruptible(Dispatchers.IO) {
val zip = ZipFile(uri.schemeSpecificPart) val zip = ZipFile(uri.schemeSpecificPart)
val entry = zip.getEntry(uri.fragment) try {
SourceResult( val entry = zip.getEntry(uri.fragment)
source = ImageSource( SourceResult(
source = zip.getInputStreamOrClose(entry).source().withExtraCloseable(zip).buffer(), source = ImageSource(
context = context, source = zip.getInputStream(entry).source().withExtraCloseable(zip).buffer(),
metadata = MangaPageMetadata(page), context = context,
), metadata = MangaPageMetadata(page),
mimeType = MimeTypeMap.getSingleton() ),
.getMimeTypeFromExtension(entry.name.substringAfterLast('.', "")), mimeType = MimeTypeMap.getSingleton()
dataSource = DataSource.DISK, .getMimeTypeFromExtension(entry.name.substringAfterLast('.', "")),
) dataSource = DataSource.DISK,
)
} catch (e: Throwable) {
zip.closeQuietly()
throw e
}
} }
uri.isFileUri() -> runInterruptible(Dispatchers.IO) { uri.isFileUri() -> runInterruptible(Dispatchers.IO) {

View File

@@ -10,9 +10,9 @@ import coil.fetch.SourceResult
import coil.request.Options import coil.request.Options
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.runInterruptible import kotlinx.coroutines.runInterruptible
import okhttp3.internal.closeQuietly
import okio.buffer import okio.buffer
import okio.source import okio.source
import org.koitharu.kotatsu.core.util.ext.getInputStreamOrClose
import org.koitharu.kotatsu.local.data.util.withExtraCloseable import org.koitharu.kotatsu.local.data.util.withExtraCloseable
import java.util.zip.ZipFile import java.util.zip.ZipFile
@@ -23,18 +23,23 @@ class CbzFetcher(
override suspend fun fetch() = runInterruptible(Dispatchers.IO) { override suspend fun fetch() = runInterruptible(Dispatchers.IO) {
val zip = ZipFile(uri.schemeSpecificPart) val zip = ZipFile(uri.schemeSpecificPart)
val entry = zip.getEntry(uri.fragment) try {
val ext = MimeTypeMap.getFileExtensionFromUrl(entry.name) val entry = zip.getEntry(uri.fragment)
val bufferedSource = zip.getInputStreamOrClose(entry).source().withExtraCloseable(zip).buffer() val ext = MimeTypeMap.getFileExtensionFromUrl(entry.name)
SourceResult( val bufferedSource = zip.getInputStream(entry).source().withExtraCloseable(zip).buffer()
source = ImageSource( SourceResult(
source = bufferedSource, source = ImageSource(
context = options.context, source = bufferedSource,
metadata = CbzMetadata(uri), context = options.context,
), metadata = CbzMetadata(uri),
mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext), ),
dataSource = DataSource.DISK, mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(ext),
) dataSource = DataSource.DISK,
)
} catch (e: Throwable) {
zip.closeQuietly()
throw e
}
} }
class Factory : Fetcher.Factory<Uri> { class Factory : Fetcher.Factory<Uri> {

View File

@@ -14,6 +14,7 @@ import org.koitharu.kotatsu.core.backup.CompositeResult
import org.koitharu.kotatsu.core.ui.BaseViewModel import org.koitharu.kotatsu.core.ui.BaseViewModel
import org.koitharu.kotatsu.core.util.ext.MutableEventFlow import org.koitharu.kotatsu.core.util.ext.MutableEventFlow
import org.koitharu.kotatsu.core.util.ext.call 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.core.util.ext.toUriOrNull
import org.koitharu.kotatsu.parsers.util.SuspendLazy import org.koitharu.kotatsu.parsers.util.SuspendLazy
import java.io.File import java.io.File
@@ -71,7 +72,11 @@ class RestoreViewModel @Inject constructor(
override fun onCleared() { override fun onCleared() {
super.onCleared() super.onCleared()
backupInput.peek()?.cleanupAsync() runCatching {
backupInput.peek()?.closeAndDelete()
}.onFailure {
it.printStackTraceDebug()
}
} }
fun onItemClick(item: BackupEntryModel) { fun onItemClick(item: BackupEntryModel) {