From e42063806c56876523237b5a50285deaa8ba62b6 Mon Sep 17 00:00:00 2001 From: Mike Hearn Date: Mon, 21 May 2012 15:31:21 +0200 Subject: [PATCH] Write+rename wallet files. --- .../java/com/google/bitcoin/core/Wallet.java | 21 ++++++++++++++++--- .../com/google/bitcoin/tools/WalletTool.java | 11 ++-------- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/core/src/main/java/com/google/bitcoin/core/Wallet.java b/core/src/main/java/com/google/bitcoin/core/Wallet.java index debb21fa..595b2a2e 100644 --- a/core/src/main/java/com/google/bitcoin/core/Wallet.java +++ b/core/src/main/java/com/google/bitcoin/core/Wallet.java @@ -19,6 +19,7 @@ package com.google.bitcoin.core; import com.google.bitcoin.core.WalletTransaction.Pool; import com.google.bitcoin.store.WalletProtobufSerializer; import com.google.bitcoin.utils.EventListenerInvoker; +import com.google.common.base.Preconditions; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -180,15 +181,29 @@ public class Wallet implements Serializable { /** * Uses protobuf serialization to save the wallet to the given file. To learn more about this file format, see - * {@link WalletProtobufSerializer}. + * {@link WalletProtobufSerializer}. Writes out first to a temporary file in the same directory and then renames + * once written. */ public synchronized void saveToFile(File f) throws IOException { + Preconditions.checkArgument(f.isFile()); FileOutputStream stream = null; + File temp = null; try { - stream = new FileOutputStream(f); + File directory = f.getParentFile(); + temp = File.createTempFile("wallet", null, directory); + stream = new FileOutputStream(temp); saveToFileStream(stream); } finally { - if (stream != null) stream.close(); + if (stream != null) { + // Attempt to force the bits to hit the disk. In reality the OS or hard disk itself may still decide + // to not write through to physical media for at least a few seconds, but this is the best we can do. + stream.flush(); + stream.getFD().sync(); + stream.close(); + if (!temp.renameTo(f)) { + throw new IOException("Failed to rename " + temp + " to " + f); + } + } } } diff --git a/tools/src/main/java/com/google/bitcoin/tools/WalletTool.java b/tools/src/main/java/com/google/bitcoin/tools/WalletTool.java index 806b07fe..de42aee3 100644 --- a/tools/src/main/java/com/google/bitcoin/tools/WalletTool.java +++ b/tools/src/main/java/com/google/bitcoin/tools/WalletTool.java @@ -524,16 +524,9 @@ public class WalletTool { } private static void saveWallet(File walletFile) { - // Save the new state of the wallet to a temp file then rename, in case anything goes wrong. - File tmp; try { - // Create tmp in same directory as wallet to ensure we create on the same drive/volume. - tmp = File.createTempFile("wallet", null, walletFile.getParentFile()); - tmp.deleteOnExit(); - wallet.saveToFile(tmp); - if (!tmp.renameTo(walletFile)) { - throw new IOException("Failed to rename wallet"); - } + // This will save the new state of the wallet to a temp file then rename, in case anything goes wrong. + wallet.saveToFile(walletFile); } catch (IOException e) { System.err.println("Failed to save wallet! Old wallet should be left untouched."); e.printStackTrace();