From 3c9265878a9fe3ff267bf9765178cc3d7b5ba836 Mon Sep 17 00:00:00 2001 From: THEAccess Date: Tue, 26 Aug 2025 00:10:33 +0200 Subject: [PATCH] Implement copy-and-delete fallback for atomicMove This change introduces a fallback mechanism for `atomicMove` in `FileCodec.kt`. If `atomicMove` is unsupported (e.g., on Android 7 and below), it now attempts to copy the temporary file to the destination and then deletes the temporary file. Error handling is included to ensure the temporary file is cleaned up in case of a copy failure. --- .../io/github/xxfast/kstore/file/FileCodec.kt | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/kstore-file/src/commonMain/kotlin/io/github/xxfast/kstore/file/FileCodec.kt b/kstore-file/src/commonMain/kotlin/io/github/xxfast/kstore/file/FileCodec.kt index b5c0bfa..7e13bb1 100644 --- a/kstore-file/src/commonMain/kotlin/io/github/xxfast/kstore/file/FileCodec.kt +++ b/kstore-file/src/commonMain/kotlin/io/github/xxfast/kstore/file/FileCodec.kt @@ -57,6 +57,7 @@ public class FileCodec( * If the value is null, the file is deleted. * If the encoding fails, the temp file is deleted. * If the encoding succeeds, the temp file is atomically moved to the target file - completing the transaction. + * Uses fallback copy-and-delete for platforms where atomic move is not supported (e.g., Android 7 and below). * @param value optional value to encode */ @OptIn(ExperimentalSerializationApi::class) @@ -73,6 +74,25 @@ public class FileCodec( throw e } - SystemFileSystem.atomicMove(source = tempFile, destination = file) + // Try atomic move first, fallback to copy-and-delete if not supported + try { + SystemFileSystem.atomicMove(source = tempFile, destination = file) + } catch (_: UnsupportedOperationException) { + // Fallback for platforms where atomic move is not supported (e.g., Android 7 and below) + try { + // Copy temp file to destination + SystemFileSystem.source(tempFile).buffered().use { source -> + SystemFileSystem.sink(file).buffered().use { destination -> + source.transferTo(destination) + } + } + // Delete temp file after successful copy + SystemFileSystem.delete(tempFile, mustExist = false) + } catch (copyException: Throwable) { + // Clean up temp file and rethrow + SystemFileSystem.delete(tempFile, mustExist = false) + throw copyException + } + } } }