Write files atomically

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

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

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

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

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

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