Write files atomically

Signed-off-by: Graham <gpe@openrs2.dev>
Graham 4 years ago
parent 45d59101b2
commit 8370ad104e
  1. 3
      asm/src/main/java/dev/openrs2/asm/classpath/Library.kt
  2. 2
      crypto/build.gradle.kts
  3. 3
      crypto/src/main/java/dev/openrs2/crypto/Pkcs12KeyStore.kt
  4. 7
      crypto/src/main/java/dev/openrs2/crypto/Rsa.kt
  5. 3
      decompiler/src/main/java/dev/openrs2/decompiler/DecompilerIo.kt
  6. 3
      deob-processor/src/main/java/dev/openrs2/deob/processor/NameMapProcessor.kt
  7. 44
      util/src/main/java/dev/openrs2/util/io/PathExtensions.kt

@ -3,6 +3,7 @@ package dev.openrs2.asm.classpath
import com.github.michaelbull.logging.InlineLogger
import dev.openrs2.asm.io.LibraryReader
import dev.openrs2.asm.io.LibraryWriter
import dev.openrs2.util.io.useAtomicOutputStream
import org.objectweb.asm.tree.ClassNode
import java.nio.file.Files
import java.nio.file.Path
@ -47,7 +48,7 @@ class Library(val name: String) : Iterable<ClassNode> {
fun write(path: Path, writer: LibraryWriter, classPath: ClassPath) {
logger.info { "Writing library $path" }
Files.newOutputStream(path).use { output ->
path.useAtomicOutputStream { output ->
writer.write(output, classPath, classes.values)
}
}

@ -9,6 +9,8 @@ dependencies {
api("org.bouncycastle:bcpkix-jdk15on:${Versions.bouncyCastlePkix}")
api("org.bouncycastle:bcprov-jdk15on:${Versions.bouncyCastleProvider}")
implementation(project(":util"))
testImplementation("com.google.jimfs:jimfs:${Versions.jimfs}")
}

@ -1,5 +1,6 @@
package dev.openrs2.crypto
import dev.openrs2.util.io.useAtomicOutputStream
import jdk.security.jarsigner.JarSigner
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers
@ -66,7 +67,7 @@ class Pkcs12KeyStore private constructor(privateKeyEntry: KeyStore.PrivateKeyEnt
val entry = createPrivateKeyEntry(signerName)
keyStore.setEntry(ALIAS, entry, PASSWORD_PARAMETER)
Files.newOutputStream(path).use { output ->
path.useAtomicOutputStream { output ->
keyStore.store(output, PASSWORD_CHARS)
}

@ -1,5 +1,6 @@
package dev.openrs2.crypto
import dev.openrs2.util.io.useAtomicBufferedWriter
import io.netty.buffer.ByteBuf
import io.netty.buffer.ByteBufUtil
import io.netty.buffer.Unpooled
@ -201,8 +202,10 @@ object Rsa {
}
private fun writeSinglePemObject(path: Path, type: String, content: ByteArray) {
PemWriter(Files.newBufferedWriter(path)).use {
it.writeObject(PemObject(type, content))
path.useAtomicBufferedWriter { writer ->
PemWriter(writer).use {
it.writeObject(PemObject(type, content))
}
}
}
}

@ -1,5 +1,6 @@
package dev.openrs2.decompiler
import dev.openrs2.util.io.useAtomicBufferedWriter
import org.jetbrains.java.decompiler.main.extern.IBytecodeProvider
import org.jetbrains.java.decompiler.main.extern.IResultSaver
import java.io.Closeable
@ -64,7 +65,7 @@ class DecompilerIo(private val destination: Path) : IBytecodeProvider, IResultSa
) {
val p = destination.resolve(entryName)
Files.createDirectories(p.parent)
Files.newBufferedWriter(p).use {
p.useAtomicBufferedWriter {
it.write(content)
}
}

@ -11,6 +11,7 @@ import dev.openrs2.deob.annotation.OriginalMember
import dev.openrs2.deob.map.Field
import dev.openrs2.deob.map.Method
import dev.openrs2.deob.map.NameMap
import dev.openrs2.util.io.useAtomicBufferedWriter
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
@ -106,7 +107,7 @@ class NameMapProcessor : AbstractProcessor() {
combinedMap = map
}
Files.newBufferedWriter(mapPath).use { writer ->
mapPath.useAtomicBufferedWriter { writer ->
mapper.writeValue(writer, combinedMap)
}
}

@ -0,0 +1,44 @@
package dev.openrs2.util.io
import java.io.BufferedWriter
import java.io.OutputStream
import java.nio.charset.Charset
import java.nio.file.Files
import java.nio.file.OpenOption
import java.nio.file.Path
import java.nio.file.StandardCopyOption
inline fun <T> Path.atomicWrite(f: (Path) -> T): T {
val tempFile = Files.createTempFile(parent, ".$fileName", ".tmp")
try {
val result = f(tempFile)
Files.move(tempFile, this, StandardCopyOption.ATOMIC_MOVE, StandardCopyOption.REPLACE_EXISTING)
return result
} finally {
Files.deleteIfExists(tempFile)
}
}
inline fun <T> Path.useAtomicBufferedWriter(vararg options: OpenOption, f: (BufferedWriter) -> T): T {
return atomicWrite { path ->
Files.newBufferedWriter(path, *options).use { writer ->
f(writer)
}
}
}
inline fun <T> Path.useAtomicBufferedWriter(cs: Charset, vararg options: OpenOption, f: (BufferedWriter) -> T): T {
return atomicWrite { path ->
Files.newBufferedWriter(path, cs, *options).use { writer ->
f(writer)
}
}
}
inline fun <T> Path.useAtomicOutputStream(vararg options: OpenOption, f: (OutputStream) -> T): T {
return atomicWrite { path ->
Files.newOutputStream(path, *options).use { output ->
f(output)
}
}
}
Loading…
Cancel
Save