@@ -131,8 +131,14 @@ internal class DefaultFileService @Inject constructor(
131
131
Timber .v(" Response size ${response.body?.contentLength()} - Stream available: ${! source.exhausted()} " )
132
132
133
133
// Write the file to cache (encrypted version if the file is encrypted)
134
- writeToFile(source.inputStream(), cachedFiles.file)
134
+ // Write to a tmp file first, so if we abort before done, we don't have a broken cached file
135
+ val tmpFile = File (cachedFiles.file.parentFile, " ${cachedFiles.file.name} .tmp" )
136
+ if (tmpFile.exists()) {
137
+ Timber .v(" ## FileService: discard aborted tmp file ${tmpFile.path} " )
138
+ }
139
+ writeToFile(source.inputStream(), tmpFile)
135
140
response.close()
141
+ tmpFile.renameTo(cachedFiles.file)
136
142
} else {
137
143
Timber .v(" ## FileService: cache hit for $url " )
138
144
}
@@ -145,15 +151,21 @@ internal class DefaultFileService @Inject constructor(
145
151
Timber .v(" ## FileService: decrypt file" )
146
152
// Ensure the parent folder exists
147
153
cachedFiles.decryptedFile.parentFile?.mkdirs()
154
+ // Write to a tmp file first, so if we abort before done, we don't have a broken cached file
155
+ val tmpFile = File (cachedFiles.decryptedFile.parentFile, " ${cachedFiles.decryptedFile.name} .tmp" )
156
+ if (tmpFile.exists()) {
157
+ Timber .v(" ## FileService: discard aborted tmp file ${tmpFile.path} " )
158
+ }
148
159
val decryptSuccess = cachedFiles.file.inputStream().use { inputStream ->
149
- cachedFiles.decryptedFile .outputStream().buffered().use { outputStream ->
160
+ tmpFile .outputStream().buffered().use { outputStream ->
150
161
MXEncryptedAttachments .decryptAttachment(
151
162
inputStream,
152
163
elementToDecrypt,
153
164
outputStream
154
165
)
155
166
}
156
167
}
168
+ tmpFile.renameTo(cachedFiles.decryptedFile)
157
169
if (! decryptSuccess) {
158
170
throw IllegalStateException (" Decryption error" )
159
171
}
0 commit comments