Fix concurrent creation of the same directory

This commit is contained in:
FooIbar committed 2024-09-24 21:36:42 +08:00
1 parent ae3a66903a
commit 7bfa5be53c
4 files changed
+32 -33

No files matched your search

@@ -7,9 +7,9 @@ import com.hippo.ehviewer.EhApplication.Companion.imageCache
import com.hippo.ehviewer.download.downloadLocation
import com.hippo.ehviewer.spider.DownloadInfoMagics.decodeMagicRequestOrUrl
import com.hippo.ehviewer.util.sendTo
import com.hippo.files.isDirectory
import com.hippo.files.isFile
import com.hippo.files.toUri
import eu.kanade.tachiyomi.util.lang.withIOContext
object DownloadThumbInterceptor : Interceptor {
private const val THUMB_FILE = "thumb.jpg"
@@ -18,22 +18,20 @@ object DownloadThumbInterceptor : Interceptor {
if (magicOrUrl != null) {
val (url, location) = decodeMagicRequestOrUrl(magicOrUrl)
if (location != null) {
val thumb = withIOContext { downloadLocation / location / THUMB_FILE }
if (withIOContext { thumb.isFile }) {
val thumb = downloadLocation / location / THUMB_FILE
if (thumb.isFile) {
val new = chain.request.newBuilder().data(thumb.toUri()).build()
val result = chain.withRequest(new).proceed()
if (result is SuccessResult) return result
}
val new = chain.request.newBuilder().data(url).build()
val result = chain.withRequest(new).proceed()
if (result is SuccessResult) {
withIOContext {
// Accessing the recreated file immediately after deleting it throws
// FileNotFoundException, so we just overwrite the existing file.
val key = requireNotNull(chain.request.memoryCacheKey)
imageCache.read(key) {
data sendTo thumb
}
if (result is SuccessResult && thumb.parent?.isDirectory == true) {
// Accessing the recreated file immediately after deleting it throws
// FileNotFoundException, so we just overwrite the existing file.
val key = requireNotNull(chain.request.memoryCacheKey)
imageCache.read(key) {
data sendTo thumb
}
}
return result
@@ -46,6 +46,7 @@ import com.hippo.files.exists
import com.hippo.files.find
import com.hippo.files.isDirectory
import com.hippo.files.list
import com.hippo.files.mkdirs
import com.hippo.files.moveTo
import com.hippo.files.openFileDescriptor
import com.hippo.files.openOutputStream
@@ -91,10 +92,10 @@ class SpiderDen(val info: GalleryInfo) {
mode = value
if (mode == SpiderQueen.MODE_DOWNLOAD) {
if (downloadDir == null) {
downloadDir = getGalleryDownloadDir(info)
downloadDir = getGalleryDownloadDir(info).apply { mkdirs() }
}
if (saveAsCbz && tempDownloadDir == null) {
tempDownloadDir = info.tempDownloadDir!!
tempDownloadDir = info.tempDownloadDir!!.apply { mkdirs() }
}
}
}
@@ -342,7 +343,7 @@ class SpiderDen(val info: GalleryInfo) {
}
suspend fun initDownloadDir() {
downloadDir = getGalleryDownloadDir(info)
downloadDir = getGalleryDownloadDir(info).apply { mkdirs() }
}
suspend fun writeComicInfo(fetchMetadata: Boolean = true) {
@@ -30,8 +30,9 @@ class AndroidFileSystem(context: Context) : FileSystem() {
return physicalFileSystem.atomicMove(source, target)
}
DocumentsContract.renameDocument(contentResolver, source.toUri(), target.name)
?: throw IOException("Failed to move $source to $target")
source.runCatching {
DocumentsContract.renameDocument(contentResolver, toUri(), target.name)
}.getOrNull() ?: throw IOException("Failed to move $source to $target")
}
override fun canonicalize(path: Path): Path {
@@ -52,9 +53,9 @@ class AndroidFileSystem(context: Context) : FileSystem() {
}
}
dir.parent?.let {
DocumentsContract.createDocument(contentResolver, it.toUri(), Document.MIME_TYPE_DIR, dir.name)
} ?: throw IOException("Failed to create directory: $dir")
dir.parent?.runCatching {
DocumentsContract.createDocument(contentResolver, toUri(), Document.MIME_TYPE_DIR, dir.name)
}?.getOrNull() ?: throw IOException("Failed to create directory: $dir")
}
override fun createSymlink(source: Path, target: Path) {
@@ -74,7 +75,9 @@ class AndroidFileSystem(context: Context) : FileSystem() {
uri = DocumentsContract.buildDocumentUriUsingTree(uri, DocumentsContract.getDocumentId(uri) + '/')
}
val deleted = DocumentsContract.deleteDocument(contentResolver, uri)
val deleted = runCatching {
DocumentsContract.deleteDocument(contentResolver, uri)
}.getOrDefault(false)
if (!deleted) {
throw IOException("Failed to delete $path")
}
@@ -173,25 +176,20 @@ class AndroidFileSystem(context: Context) : FileSystem() {
}
fun openFileDescriptor(path: Path, mode: String): ParcelFileDescriptor {
if (path.isPhysicalFile()) {
return ParcelFileDescriptor.open(path.toFile(), ParcelFileDescriptor.parseMode(mode))
}
if ('w' in mode && !exists(path)) {
val parent = path.parent ?: throw IOException("Failed to open file: $path")
createDirectories(parent)
if (path.isPhysicalFile()) {
physicalFileSystem.openReadWrite(path).close()
} else {
path.parent?.runCatching {
val displayName = path.name
val extension = displayName.substringAfterLast('.', "").ifEmpty { null }?.lowercase()
val mimeType = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension) ?: "application/octet-stream"
DocumentsContract.createDocument(contentResolver, parent.toUri(), mimeType, displayName)
?: throw IOException("Failed to open file: $path")
}
DocumentsContract.createDocument(contentResolver, toUri(), mimeType, displayName)
}?.getOrNull() ?: throw IOException("Failed to open file: $path")
}
return if (path.isPhysicalFile()) {
ParcelFileDescriptor.open(path.toFile(), ParcelFileDescriptor.parseMode(mode))
} else {
contentResolver.openFileDescriptor(path.toUri(), mode)
} ?: throw IOException("Failed to open file: $path")
return contentResolver.openFileDescriptor(path.toUri(), mode) ?: throw IOException("Failed to open file: $path")
}
}
@@ -23,6 +23,8 @@ fun Path.delete() = SystemFileSystem.deleteRecursively(this)
fun Path.list() = SystemFileSystem.listOrNull(this).orEmpty()
fun Path.mkdirs() = SystemFileSystem.createDirectories(this)
fun Path.moveTo(target: Path) = SystemFileSystem.atomicMove(this, target)
fun Path.openFileDescriptor(mode: String) = SystemFileSystem.openFileDescriptor(this, mode)