@@ -268,24 +268,39 @@ internal fun writeAtomically(
268268 target : File ,
269269 write : (java.io.OutputStream ) -> Unit ,
270270) {
271- target.parentFile?.mkdirs()
272- val tempFile = File (target.parentFile, " ${target.name} .tmp" )
273- try {
274- tempFile.outputStream().use(write)
275- if (tempFile.length() <= 0 ) {
276- tempFile.delete()
277- error(" ${target.name} is empty" )
278- }
279- if (target.exists()) {
280- target.delete()
271+ val parent = target.parentFile ? : error(" Parent directory is unavailable for ${target.absolutePath} " )
272+ parent.mkdirs()
273+ synchronized(writeLockFor(target)) {
274+ val tempPrefix = " ${target.name} ." .let { prefix ->
275+ if (prefix.length >= 3 ) prefix else prefix.padEnd(3 , ' _' )
281276 }
282- if (! tempFile.renameTo(target)) {
277+ val tempFile = File .createTempFile(tempPrefix, " .tmp" , parent)
278+ try {
279+ tempFile.outputStream().use(write)
280+ if (tempFile.length() <= 0 ) {
281+ tempFile.delete()
282+ error(" ${target.name} is empty" )
283+ }
284+ if (target.exists() && ! target.delete()) {
285+ tempFile.delete()
286+ error(" Failed to replace ${target.name} " )
287+ }
288+ if (! tempFile.renameTo(target)) {
289+ tempFile.delete()
290+ error(" Failed to replace ${target.name} " )
291+ }
292+ } catch (error: Throwable ) {
283293 tempFile.delete()
284- error( " Failed to replace ${target.name} " )
294+ throw error
285295 }
286- } catch (error: Throwable ) {
287- tempFile.delete()
288- throw error
296+ }
297+ }
298+
299+ private val WriteLocks = mutableMapOf<String , Any >()
300+
301+ private fun writeLockFor (target : File ): Any {
302+ return synchronized(WriteLocks ) {
303+ WriteLocks .getOrPut(target.absolutePath) { Any () }
289304 }
290305}
291306
0 commit comments