fix windows file rename bug

This commit is contained in:
Manfred Karrer 2014-07-09 13:34:35 +02:00
parent d221ae3aec
commit 2778779414
7 changed files with 129 additions and 119 deletions

View file

@ -76,7 +76,7 @@ public class BitSquare extends Application
// use a local data dir as default storage dir (can be overwritten in the settings) // use a local data dir as default storage dir (can be overwritten in the settings)
// TODO save root preferences always in app dir top get preferred storage location // TODO save root preferences always in app dir top get preferred storage location
StorageDirectory.setStorageDirectory(new File(StorageDirectory.getApplicationDirectory().getAbsolutePath() + "/data")); StorageDirectory.setStorageDirectory(new File(StorageDirectory.getApplicationDirectory().getCanonicalPath() + "/data"));
// currently there is not SystemTray support for java fx (planned for version 3) so we use the old AWT // currently there is not SystemTray support for java fx (planned for version 3) so we use the old AWT

View file

@ -29,7 +29,7 @@ public class BitSquareWalletAppKit extends WalletAppKit
{ {
if (!directory.mkdir()) if (!directory.mkdir())
{ {
throw new IOException("Could not create named directory " + directory.getAbsolutePath()); throw new IOException("Could not create named directory " + directory.getCanonicalPath());
} }
} }
FileInputStream walletStream = null; FileInputStream walletStream = null;

View file

@ -665,7 +665,13 @@ public class MessageFacade
private void setupStorage() private void setupStorage()
{ {
myPeer.getPeerBean().setStorage(new StorageDisk(StorageDirectory.getStorageDirectory().getAbsolutePath() + "/" + BitSquare.getAppName() + "_tomP2P")); try
{
myPeer.getPeerBean().setStorage(new StorageDisk(StorageDirectory.getStorageDirectory().getCanonicalPath() + "/" + BitSquare.getAppName() + "_tomP2P"));
} catch (IOException e)
{
e.printStackTrace();
}
} }
private void saveMyAddressToDHT() throws IOException private void saveMyAddressToDHT() throws IOException

View file

@ -1,6 +1,5 @@
package io.bitsquare.storage; package io.bitsquare.storage;
import com.google.bitcoin.core.Utils;
import com.google.bitcoin.utils.Threading; import com.google.bitcoin.utils.Threading;
import io.bitsquare.BitSquare; import io.bitsquare.BitSquare;
import io.bitsquare.util.FileUtil; import io.bitsquare.util.FileUtil;
@ -54,7 +53,7 @@ public class Storage
lock.lock(); lock.lock();
try try
{ {
saveObjectToFile((Serializable) rootMap); FileUtil.saveFile(prefix, storageFile, (Serializable) rootMap);
} finally } finally
{ {
lock.unlock(); lock.unlock();
@ -120,7 +119,7 @@ public class Storage
{ {
lock.lock(); lock.lock();
rootMap.put(key, value); rootMap.put(key, value);
saveObjectToFile((Serializable) rootMap); FileUtil.saveFile(prefix, storageFile, (Serializable) rootMap);
} finally } finally
{ {
lock.unlock(); lock.unlock();
@ -217,63 +216,6 @@ public class Storage
} }
} }
private void saveObjectToFile(Serializable serializable)
{
try
{
final File tempFile = FileUtil.getTempFile("temp_" + prefix);
try (final FileOutputStream fileOutputStream = new FileOutputStream(tempFile);
final ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream))
{
objectOutputStream.writeObject(serializable);
// 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.
fileOutputStream.flush();
fileOutputStream.getFD().sync();
if (Utils.isWindows())
{
final File canonical = storageFile.getCanonicalFile();
if (!canonical.exists())
{
if (!canonical.createNewFile())
{
throw new IOException("Failed to create new file " + canonical);
}
}
if (!tempFile.renameTo(canonical))
{
throw new IOException("Failed to rename " + tempFile + " to " + canonical);
}
}
else if (!tempFile.renameTo(storageFile))
{
throw new IOException("Failed to rename " + tempFile + " to " + storageFile);
}
} catch (IOException e)
{
e.printStackTrace();
log.error("saveObjectToFile failed." + e);
if (tempFile.exists())
{
log.warn("Temp file still exists after failed save.");
if (!tempFile.delete())
{
log.warn("Cannot delete temp file.");
}
}
}
} catch (IOException e)
{
e.printStackTrace();
log.error("getTempFile failed." + e);
}
}
private Object readObjectFromFile(File file) throws IOException, ClassNotFoundException private Object readObjectFromFile(File file) throws IOException, ClassNotFoundException
{ {

View file

@ -113,40 +113,9 @@ public class DSAKeyUtil
privKeyFileOutputStream.flush(); privKeyFileOutputStream.flush();
privKeyFileOutputStream.getFD().sync(); privKeyFileOutputStream.getFD().sync();
if (Utils.isWindows())
{
// Work around an issue on Windows whereby you can't rename over existing files.
final File pubKeyCanonicalFile = pubKeyFile.getCanonicalFile();
if (pubKeyCanonicalFile.exists() && !pubKeyCanonicalFile.delete())
{
throw new IOException("Failed to delete pubKeyCanonicalFile for replacement with save");
}
if (!pubKeyTempFile.renameTo(pubKeyCanonicalFile))
{
throw new IOException("Failed to rename " + pubKeyTempFile + " to " + pubKeyCanonicalFile);
}
final File privKeyCanonicalFile = privKeyFile.getCanonicalFile(); FileUtil.saveTempFileToFile(pubKeyTempFile, pubKeyFile);
if (privKeyCanonicalFile.exists() && !privKeyCanonicalFile.delete()) FileUtil.saveTempFileToFile(privKeyTempFile, privKeyFile);
{
throw new IOException("Failed to delete privKeyCanonicalFile for replacement with save");
}
if (!privKeyTempFile.renameTo(privKeyCanonicalFile))
{
throw new IOException("Failed to rename " + privKeyTempFile + " to " + privKeyCanonicalFile);
}
}
else
{
if (!pubKeyTempFile.renameTo(pubKeyFile))
{
throw new IOException("Failed to rename " + pubKeyTempFile + " to " + pubKeyFile);
}
if (!privKeyTempFile.renameTo(privKeyFile))
{
throw new IOException("Failed to rename " + privKeyTempFile + " to " + privKeyFile);
}
}
} finally } finally
{ {
if (pubKeyTempFile.exists()) if (pubKeyTempFile.exists())
@ -170,7 +139,6 @@ public class DSAKeyUtil
} }
} }
private static KeyPair readKeyPairFromFiles(File pubKeyFile, File privKeyFile) throws IOException, InvalidKeySpecException, NoSuchAlgorithmException private static KeyPair readKeyPairFromFiles(File pubKeyFile, File privKeyFile) throws IOException, InvalidKeySpecException, NoSuchAlgorithmException
{ {
lock.lock(); lock.lock();

View file

@ -1,8 +1,8 @@
package io.bitsquare.util; package io.bitsquare.util;
import com.google.bitcoin.core.Utils;
import io.bitsquare.BitSquare; import io.bitsquare.BitSquare;
import java.io.File; import java.io.*;
import java.io.IOException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -24,9 +24,17 @@ public class FileUtil
public static String getApplicationFileName() public static String getApplicationFileName()
{ {
File executionRoot = new File(StorageDirectory.class.getProtectionDomain().getCodeSource().getLocation().getFile()); File executionRoot = new File(StorageDirectory.class.getProtectionDomain().getCodeSource().getLocation().getFile());
log.trace("getApplicationFileName " + executionRoot.getAbsolutePath()); try
{
log.trace("getApplicationFileName " + executionRoot.getCanonicalPath());
} catch (IOException e)
{
e.printStackTrace();
}
// check if it is packed into a mac app (e.g.: "/Users/mk/Desktop/bitsquare.app/Contents/Java/bitsquare.jar") // check if it is packed into a mac app (e.g.: "/Users/mk/Desktop/bitsquare.app/Contents/Java/bitsquare.jar")
if (executionRoot.getAbsolutePath().endsWith(".app/Contents/Java/bitsquare.jar") && System.getProperty("os.name").startsWith("Mac")) try
{
if (executionRoot.getCanonicalPath().endsWith(".app/Contents/Java/bitsquare.jar") && System.getProperty("os.name").startsWith("Mac"))
{ {
File appFile = executionRoot.getParentFile().getParentFile().getParentFile(); File appFile = executionRoot.getParentFile().getParentFile().getParentFile();
try try
@ -38,7 +46,84 @@ public class FileUtil
e.printStackTrace(); e.printStackTrace();
} }
} }
} catch (IOException e)
{
e.printStackTrace();
}
return BitSquare.getAppName(); return BitSquare.getAppName();
} }
public static void saveFile(String fileName, File sourceFile, Serializable serializable)
{
try
{
File tempFile;
if (Utils.isWindows())
tempFile = sourceFile;
else
tempFile = FileUtil.getTempFile("temp_" + fileName);
try (final FileOutputStream fileOutputStream = new FileOutputStream(tempFile);
final ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream))
{
objectOutputStream.writeObject(serializable);
// 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.
fileOutputStream.flush();
fileOutputStream.getFD().sync();
} catch (IOException e)
{
e.printStackTrace();
log.error("save serializable object to file failed." + e);
if (tempFile.exists())
{
log.warn("Temp file still exists after failed save.");
if (!tempFile.delete())
{
log.warn("Cannot delete temp file.");
}
}
}
if (!Utils.isWindows())
{
if (!tempFile.renameTo(sourceFile))
{
log.error("Failed to rename " + tempFile.toString() + " to " + sourceFile.toString());
}
}
} catch (IOException e)
{
e.printStackTrace();
log.error("Exception at saveFile " + e);
}
}
public static void saveTempFileToFile(File tempFile, File file) throws IOException
{
if (Utils.isWindows())
{
// Work around an issue on Windows whereby you can't rename over existing files.
final File canonicalFile = file.getCanonicalFile();
if (canonicalFile.exists() && !canonicalFile.delete())
{
throw new IOException("Failed to delete pubKeyCanonicalFile for replacement with save");
}
if (!tempFile.renameTo(canonicalFile))
{
throw new IOException("Failed to rename " + tempFile + " to " + canonicalFile);
}
}
else
{
if (!tempFile.renameTo(file))
{
throw new IOException("Failed to rename " + tempFile + " to " + file);
}
}
}
} }

View file

@ -1,6 +1,7 @@
package io.bitsquare.util; package io.bitsquare.util;
import java.io.File; import java.io.File;
import java.io.IOException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@ -42,16 +43,24 @@ public class StorageDirectory
public static File getApplicationDirectory() public static File getApplicationDirectory()
{ {
File executionRoot = new File(StorageDirectory.class.getProtectionDomain().getCodeSource().getLocation().getFile()); File executionRoot = new File(StorageDirectory.class.getProtectionDomain().getCodeSource().getLocation().getFile());
log.trace("executionRoot " + executionRoot.getAbsolutePath()); try
{
log.trace("executionRoot " + executionRoot.getCanonicalPath());
// check if it is packed into a mac app (e.g.: "/Users/mk/Desktop/bitsquare.app/Contents/Java/bitsquare.jar") // check if it is packed into a mac app (e.g.: "/Users/mk/Desktop/bitsquare.app/Contents/Java/bitsquare.jar")
if (executionRoot.getAbsolutePath().endsWith(".app/Contents/Java/bitsquare.jar") && System.getProperty("os.name").startsWith("Mac")) if (executionRoot.getCanonicalPath().endsWith(".app/Contents/Java/bitsquare.jar") && System.getProperty("os.name").startsWith("Mac"))
return executionRoot.getParentFile().getParentFile().getParentFile().getParentFile(); return executionRoot.getParentFile().getParentFile().getParentFile().getParentFile();
else if (executionRoot.getAbsolutePath().endsWith("/target/classes")) else if (executionRoot.getCanonicalPath().endsWith("/target/classes"))
return executionRoot.getParentFile(); // dev e.g.: /Users/mk/Documents/_intellij/bitsquare/target/classes -> use target as root return executionRoot.getParentFile(); // dev e.g.: /Users/mk/Documents/_intellij/bitsquare/target/classes -> use target as root
else if (executionRoot.getAbsolutePath().endsWith("/bitsquare.jar")) else if (executionRoot.getCanonicalPath().endsWith("/bitsquare.jar"))
return executionRoot.getParentFile(); // dev with jar e.g.: Users/mk/Documents/_intellij/bitsquare/out/artifacts/bitsquare2/bitsquare.jar -> use target as root return executionRoot.getParentFile(); // dev with jar e.g.: Users/mk/Documents/_intellij/bitsquare/out/artifacts/bitsquare2/bitsquare.jar -> use target as root
else else
return executionRoot; return executionRoot;
} catch (IOException e)
{
e.printStackTrace();
return null;
}
} }