From 34824c044e4bd4b7774c0b8b78af6879270339b5 Mon Sep 17 00:00:00 2001
From: Yuri <yuri@tsoft.com>
Date: Sun, 14 Sep 2014 23:34:33 -0700
Subject: [PATCH 1/4] Moved all keys.dat writing code into writeKeysFile in
 shared.py

---
 src/api.py                       |  6 ++---
 src/bitmessagecurses/__init__.py | 15 ++++--------
 src/bitmessageqt/__init__.py     | 41 ++++++++++----------------------
 src/class_addressGenerator.py    |  6 ++---
 src/class_singleWorker.py        |  9 +++----
 src/class_sqlThread.py           | 21 ++++++----------
 src/helper_startup.py            |  3 +--
 src/shared.py                    |  9 +++++++
 8 files changed, 41 insertions(+), 69 deletions(-)

diff --git a/src/api.py b/src/api.py
index bd28d923..42cae15d 100644
--- a/src/api.py
+++ b/src/api.py
@@ -429,8 +429,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
             if not shared.safeConfigGetBoolean(address, 'chan'):
                 raise APIError(25, 'Specified address is not a chan address. Use deleteAddress API call instead.')
             shared.config.remove_section(address)
-            with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-                shared.config.write(configfile)
+            shared.writeKeysFile()
             return 'success'
 
         elif method == 'deleteAddress':
@@ -443,8 +442,7 @@ class MySimpleXMLRPCRequestHandler(SimpleXMLRPCRequestHandler):
             if not shared.config.has_section(address):
                 raise APIError(13, 'Could not find this address in your keys.dat file.')
             shared.config.remove_section(address)
-            with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-                shared.config.write(configfile)
+            shared.writeKeysFile()
             shared.UISignalQueue.put(('rerenderInboxFromLabels',''))
             shared.UISignalQueue.put(('rerenderSentToLabels',''))
             shared.reloadMyAddressHashes()
diff --git a/src/bitmessagecurses/__init__.py b/src/bitmessagecurses/__init__.py
index 91c99df8..89fa6783 100644
--- a/src/bitmessagecurses/__init__.py
+++ b/src/bitmessagecurses/__init__.py
@@ -470,15 +470,13 @@ def handlech(c, stdscr):
                                 label = t
                                 shared.config.set(a, "label", label)
                                 # Write config
-                                with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-                                    shared.config.write(configfile)
+                                shared.writeKeysFile()
                                 addresses[addrcur][0] = label
                         elif t == "4": # Enable address
                             a = addresses[addrcur][2]
                             shared.config.set(a, "enabled", "true") # Set config
                             # Write config
-                            with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-                                shared.config.write(configfile)
+                            shared.writeKeysFile()
                             # Change color
                             if shared.safeConfigGetBoolean(a, 'chan'):
                                 addresses[addrcur][3] = 9 # orange
@@ -493,16 +491,14 @@ def handlech(c, stdscr):
                             shared.config.set(a, "enabled", "false") # Set config
                             addresses[addrcur][3] = 8 # Set color to gray
                             # Write config
-                            with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-                                shared.config.write(configfile)
+                            shared.writeKeysFile()
                             addresses[addrcur][1] = False
                             shared.reloadMyAddressHashes() # Reload address hashes
                         elif t == "6": # Delete address
                             r, t = d.inputbox("Type in \"I want to delete this address\"", width=50)
                             if r == d.DIALOG_OK and t == "I want to delete this address":
                                     shared.config.remove_section(addresses[addrcur][2])
-                                    with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-                                        shared.config.write(configfile)
+                                    shared.writeKeysFile()
                                     del addresses[addrcur]
                         elif t == "7": # Special address behavior
                             a = addresses[addrcur][2]
@@ -533,8 +529,7 @@ def handlech(c, stdscr):
                                             shared.config.set(a, "mailinglistname", mn)
                                             addresses[addrcur][3] = 6 # Set color to magenta
                                     # Write config
-                                    with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-                                        shared.config.write(configfile)
+                                    shared.writeKeysFile()
                 elif menutab == 5:
                     d.set_background_title("Subscriptions Dialog Box")
                     r, t = d.menu("Do what with subscription to \""+subscriptions[subcur][0]+"\"?",
diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py
index 47870046..6b46c9fa 100644
--- a/src/bitmessageqt/__init__.py
+++ b/src/bitmessageqt/__init__.py
@@ -462,8 +462,7 @@ class MyForm(QtGui.QMainWindow):
                         self, 'Message', displayMsg, QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
                     if reply == QtGui.QMessageBox.Yes:
                         shared.config.remove_section(addressInKeysFile)
-                        with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-                            shared.config.write(configfile)
+                        shared.writeKeysFile()
 
         # Configure Bitmessage to start on startup (or remove the
         # configuration) based on the setting in the keys.dat file
@@ -1338,7 +1337,7 @@ class MyForm(QtGui.QMainWindow):
                 reply = QtGui.QMessageBox.question(self, _translate("MainWindow", "Open keys.dat?"), _translate(
                     "MainWindow", "You may manage your keys by editing the keys.dat file stored in\n %1 \nIt is important that you back up this file. Would you like to open the file now? (Be sure to close Bitmessage before making any changes.)").arg(shared.appdata), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No)
             if reply == QtGui.QMessageBox.Yes:
-                self.openKeysFile()
+                shared.openKeysFile()
 
     def click_actionDeleteAllTrashedMessages(self):
         if QtGui.QMessageBox.question(self, _translate("MainWindow", "Delete trash?"), _translate("MainWindow", "Are you sure you want to delete all trashed messages?"), QtGui.QMessageBox.Yes, QtGui.QMessageBox.No) == QtGui.QMessageBox.No:
@@ -1428,17 +1427,10 @@ class MyForm(QtGui.QMainWindow):
         if self.connectDialogInstance.exec_():
             if self.connectDialogInstance.ui.radioButtonConnectNow.isChecked():
                 shared.config.remove_option('bitmessagesettings', 'dontconnect')
-                with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-                    shared.config.write(configfile)
+                shared.writeKeysFile()
             else:
                 self.click_actionSettings()
 
-    def openKeysFile(self):
-        if 'linux' in sys.platform:
-            subprocess.call(["xdg-open", shared.appdata + 'keys.dat'])
-        else:
-            os.startfile(shared.appdata + 'keys.dat')
-
     def changeEvent(self, event):
         if event.type() == QtCore.QEvent.WindowStateChange:
             if self.windowState() & QtCore.Qt.WindowMinimized:
@@ -2385,8 +2377,7 @@ class MyForm(QtGui.QMainWindow):
             # shared.config.set('bitmessagesettings', 'maxcores',
             # str(self.settingsDialogInstance.ui.comboBoxMaxCores.currentText()))
 
-            with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-                shared.config.write(configfile)
+            shared.writeKeysFile()
 
             if 'win32' in sys.platform or 'win64' in sys.platform:
             # Auto-startup for Windows
@@ -2406,8 +2397,7 @@ class MyForm(QtGui.QMainWindow):
             if shared.appdata != '' and self.settingsDialogInstance.ui.checkBoxPortableMode.isChecked():  # If we are NOT using portable mode now but the user selected that we should...
                 # Write the keys.dat file to disk in the new location
                 sqlStoredProcedure('movemessagstoprog')
-                with open('keys.dat', 'wb') as configfile:
-                    shared.config.write(configfile)
+                shared.writeKeysFile()
                 # Write the knownnodes.dat file to disk in the new location
                 shared.knownNodesLock.acquire()
                 output = open('knownnodes.dat', 'wb')
@@ -2431,8 +2421,7 @@ class MyForm(QtGui.QMainWindow):
                     os.makedirs(shared.appdata)
                 sqlStoredProcedure('movemessagstoappdata')
                 # Write the keys.dat file to disk in the new location
-                with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-                    shared.config.write(configfile)
+                shared.writeKeysFile()
                 # Write the knownnodes.dat file to disk in the new location
                 shared.knownNodesLock.acquire()
                 output = open(shared.appdata + 'knownnodes.dat', 'wb')
@@ -2451,8 +2440,7 @@ class MyForm(QtGui.QMainWindow):
     def click_radioButtonBlacklist(self):
         if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'white':
             shared.config.set('bitmessagesettings', 'blackwhitelist', 'black')
-            with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-                shared.config.write(configfile)
+            shared.writeKeysFile()
             # self.ui.tableWidgetBlacklist.clearContents()
             self.ui.tableWidgetBlacklist.setRowCount(0)
             self.loadBlackWhiteList()
@@ -2461,8 +2449,7 @@ class MyForm(QtGui.QMainWindow):
     def click_radioButtonWhitelist(self):
         if shared.config.get('bitmessagesettings', 'blackwhitelist') == 'black':
             shared.config.set('bitmessagesettings', 'blackwhitelist', 'white')
-            with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-                shared.config.write(configfile)
+            shared.writeKeysFile()
             # self.ui.tableWidgetBlacklist.clearContents()
             self.ui.tableWidgetBlacklist.setRowCount(0)
             self.loadBlackWhiteList()
@@ -2534,8 +2521,7 @@ class MyForm(QtGui.QMainWindow):
                 shared.config.set(str(addressAtCurrentRow), 'mailinglistname', str(
                     self.dialog.ui.lineEditMailingListName.text().toUtf8()))
                 self.ui.tableWidgetYourIdentities.item(currentRow, 1).setTextColor(QtGui.QColor(137, 04, 177)) # magenta
-            with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-                shared.config.write(configfile)
+            shared.writeKeysFile()
             self.rerenderInboxToLabels()
 
     def click_NewAddressDialog(self):
@@ -3037,8 +3023,7 @@ class MyForm(QtGui.QMainWindow):
         addressAtCurrentRow = str(
             self.ui.tableWidgetYourIdentities.item(currentRow, 1).text())
         shared.config.set(addressAtCurrentRow, 'enabled', 'true')
-        with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-            shared.config.write(configfile)
+        shared.writeKeysFile()
         self.ui.tableWidgetYourIdentities.item(
             currentRow, 0).setTextColor(QApplication.palette().text().color())
         self.ui.tableWidgetYourIdentities.item(
@@ -3064,8 +3049,7 @@ class MyForm(QtGui.QMainWindow):
             currentRow, 2).setTextColor(QtGui.QColor(128, 128, 128))
         if shared.safeConfigGetBoolean(addressAtCurrentRow, 'mailinglist'):
             self.ui.tableWidgetYourIdentities.item(currentRow, 1).setTextColor(QtGui.QColor(137, 04, 177)) # magenta
-        with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-            shared.config.write(configfile)
+        shared.writeKeysFile()
         shared.reloadMyAddressHashes()
 
     def on_action_YourIdentitiesClipboard(self):
@@ -3262,8 +3246,7 @@ class MyForm(QtGui.QMainWindow):
                 currentRow, 1).text()
             shared.config.set(str(addressAtCurrentRow), 'label', str(
                 self.ui.tableWidgetYourIdentities.item(currentRow, 0).text().toUtf8()))
-            with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-                shared.config.write(configfile)
+            shared.writeKeysFile()
             self.rerenderComboBoxSendFrom()
             # self.rerenderInboxFromLabels()
             self.rerenderInboxToLabels()
diff --git a/src/class_addressGenerator.py b/src/class_addressGenerator.py
index 2e215606..1a3ff5bc 100644
--- a/src/class_addressGenerator.py
+++ b/src/class_addressGenerator.py
@@ -129,8 +129,7 @@ class addressGenerator(threading.Thread):
                     address, 'privSigningKey', privSigningKeyWIF)
                 shared.config.set(
                     address, 'privEncryptionKey', privEncryptionKeyWIF)
-                with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-                    shared.config.write(configfile)
+                shared.writeKeysFile()
 
                 # The API and the join and create Chan functionality
                 # both need information back from the address generator.
@@ -244,8 +243,7 @@ class addressGenerator(threading.Thread):
                                 address, 'privSigningKey', privSigningKeyWIF)
                             shared.config.set(
                                 address, 'privEncryptionKey', privEncryptionKeyWIF)
-                            with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-                                shared.config.write(configfile)
+                            shared.writeKeysFile()
 
                             shared.UISignalQueue.put(('writeNewAddressToTable', (
                                 label, address, str(streamNumber))))
diff --git a/src/class_singleWorker.py b/src/class_singleWorker.py
index 5e8f11e8..1d590e63 100644
--- a/src/class_singleWorker.py
+++ b/src/class_singleWorker.py
@@ -150,8 +150,7 @@ class singleWorker(threading.Thread):
         try:
             shared.config.set(
                 myAddress, 'lastpubkeysendtime', str(int(time.time())))
-            with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-                shared.config.write(configfile)
+            shared.writeKeysFile()
         except:
             # The user deleted the address out of the keys.dat file before this
             # finished.
@@ -236,8 +235,7 @@ class singleWorker(threading.Thread):
         try:
             shared.config.set(
                 myAddress, 'lastpubkeysendtime', str(int(time.time())))
-            with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-                shared.config.write(configfile)
+            shared.writeKeysFile()
         except:
             # The user deleted the address out of the keys.dat file before this
             # finished.
@@ -332,8 +330,7 @@ class singleWorker(threading.Thread):
         try:
             shared.config.set(
                 myAddress, 'lastpubkeysendtime', str(int(time.time())))
-            with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-                shared.config.write(configfile)
+            shared.writeKeysFile()
         except Exception as err:
             logger.error('Error: Couldn\'t add the lastpubkeysendtime to the keys.dat file. Error message: %s' % err)
 
diff --git a/src/class_sqlThread.py b/src/class_sqlThread.py
index 2df6c05f..fdc793d1 100644
--- a/src/class_sqlThread.py
+++ b/src/class_sqlThread.py
@@ -86,8 +86,7 @@ class sqlThread(threading.Thread):
             shared.config.set('bitmessagesettings', 'sockslisten', 'false')
             shared.config.set('bitmessagesettings', 'keysencrypted', 'false')
             shared.config.set('bitmessagesettings', 'messagesencrypted', 'false')
-            with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-                shared.config.write(configfile)
+            shared.writeKeysFile()
 
         # People running earlier versions of PyBitmessage do not have the
         # usedpersonally field in their pubkeys table. Let's add it.
@@ -98,8 +97,7 @@ class sqlThread(threading.Thread):
             self.conn.commit()
 
             shared.config.set('bitmessagesettings', 'settingsversion', '3')
-            with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-                shared.config.write(configfile)
+            shared.writeKeysFile()
 
         # People running earlier versions of PyBitmessage do not have the
         # encodingtype field in their inbox and sent tables or the read field
@@ -119,8 +117,7 @@ class sqlThread(threading.Thread):
             self.conn.commit()
 
             shared.config.set('bitmessagesettings', 'settingsversion', '4')
-            with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-                shared.config.write(configfile)
+            shared.writeKeysFile()
 
         if shared.config.getint('bitmessagesettings', 'settingsversion') == 4:
             shared.config.set('bitmessagesettings', 'defaultnoncetrialsperbyte', str(
@@ -135,8 +132,7 @@ class sqlThread(threading.Thread):
             shared.config.set(
                 'bitmessagesettings', 'maxacceptablepayloadlengthextrabytes', '0')
             shared.config.set('bitmessagesettings', 'settingsversion', '6')
-            with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-                shared.config.write(configfile)
+            shared.writeKeysFile()
 
         # From now on, let us keep a 'version' embedded in the messages.dat
         # file so that when we make changes to the database, the database
@@ -251,8 +247,7 @@ class sqlThread(threading.Thread):
             if int(shared.config.get('bitmessagesettings','defaultnoncetrialsperbyte')) == shared.networkDefaultProofOfWorkNonceTrialsPerByte:
                 shared.config.set('bitmessagesettings','defaultnoncetrialsperbyte', str(shared.networkDefaultProofOfWorkNonceTrialsPerByte * 2))
             shared.config.set('bitmessagesettings', 'settingsversion', '7')
-            with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-                shared.config.write(configfile)
+            shared.writeKeysFile()
 
         # Add a new column to the pubkeys table to store the address version.
         # We're going to trash all of our pubkeys and let them be redownloaded.
@@ -275,8 +270,7 @@ class sqlThread(threading.Thread):
         if not shared.config.has_option('bitmessagesettings', 'identiconsuffix'): # acts as a salt
             shared.config.set('bitmessagesettings', 'identiconsuffix', ''.join(random.choice("123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz") for x in range(12))) # a twelve character pseudo-password to salt the identicons
             # Since we've added a new config entry, let's write keys.dat to disk.
-            with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-                shared.config.write(configfile)
+            shared.writeKeysFile()
 
         #Adjusting time period to stop sending messages
         if shared.config.getint('bitmessagesettings', 'settingsversion') == 7:
@@ -286,8 +280,7 @@ class sqlThread(threading.Thread):
                 'bitmessagesettings', 'stopresendingafterxmonths', '')
             #shared.config.set(
             shared.config.set('bitmessagesettings', 'settingsversion', '8') 
-            with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-                shared.config.write(configfile)
+            shared.writeKeysFile()
 
         # Add a new table: objectprocessorqueue with which to hold objects
         # that have yet to be processed if the user shuts down Bitmessage.
diff --git a/src/helper_startup.py b/src/helper_startup.py
index fd14e528..0e69865e 100644
--- a/src/helper_startup.py
+++ b/src/helper_startup.py
@@ -131,8 +131,7 @@ def loadConfig():
                 os.makedirs(shared.appdata)
         if not sys.platform.startswith('win'):
             os.umask(0o077)
-        with open(shared.appdata + 'keys.dat', 'wb') as configfile:
-            shared.config.write(configfile)
+        shared.writeKeysFile()
 
     _loadTrustedPeer()
 
diff --git a/src/shared.py b/src/shared.py
index 3f60a852..14a82f41 100644
--- a/src/shared.py
+++ b/src/shared.py
@@ -792,6 +792,15 @@ def checkAndShareBroadcastWithPeers(data):
         shared.objectProcessorQueueSize += len(data)
         objectProcessorQueue.put((objectType,data))
 
+def openKeysFile():
+    if 'linux' in sys.platform:
+        subprocess.call(["xdg-open", shared.appdata + 'keys.dat'])
+    else:
+        os.startfile(shared.appdata + 'keys.dat')
+
+def writeKeysFile():
+    with open(shared.appdata + 'keys.dat', 'wb') as configfile:
+        shared.config.write(configfile)
 
 helper_startup.loadConfig()
 from debug import logger

From d3c91eea3bb960bcc85a1875d95fad3465265177 Mon Sep 17 00:00:00 2001
From: Yuri <yuri@tsoft.com>
Date: Sun, 14 Sep 2014 23:53:21 -0700
Subject: [PATCH 2/4] Added backup copy creation during keys.dat write to
 prevent an accidental file loss due to the disk failure.

---
 src/shared.py | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/src/shared.py b/src/shared.py
index 14a82f41..32e4b118 100644
--- a/src/shared.py
+++ b/src/shared.py
@@ -20,6 +20,7 @@ import sys
 import stat
 import threading
 import time
+import shutil  # used for moving the data folder and copying keys.dat
 from os import path, environ
 from struct import Struct
 
@@ -799,8 +800,14 @@ def openKeysFile():
         os.startfile(shared.appdata + 'keys.dat')
 
 def writeKeysFile():
-    with open(shared.appdata + 'keys.dat', 'wb') as configfile:
+    fileName = shared.appdata + 'keys.dat'
+    # create a backup copy to prevent the accidental loss due to the disk write failure
+    shutil.copyfile(fileName, fileName + '.bak')
+    # write the file
+    with open(fileName, 'wb') as configfile:
         shared.config.write(configfile)
+    # delete a backup
+    os.remove(fileName + '.bak')
 
 helper_startup.loadConfig()
 from debug import logger

From 5beaeff2e2dec032468f34464eb7a0b329efa41f Mon Sep 17 00:00:00 2001
From: Yuri <yuri@tsoft.com>
Date: Tue, 16 Sep 2014 10:04:56 -0700
Subject: [PATCH 3/4] TImestamped the keys.dat backup file.

---
 src/shared.py | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/shared.py b/src/shared.py
index 32e4b118..37a5cca7 100644
--- a/src/shared.py
+++ b/src/shared.py
@@ -21,6 +21,7 @@ import stat
 import threading
 import time
 import shutil  # used for moving the data folder and copying keys.dat
+import datetime
 from os import path, environ
 from struct import Struct
 
@@ -801,13 +802,14 @@ def openKeysFile():
 
 def writeKeysFile():
     fileName = shared.appdata + 'keys.dat'
+    fileNameBak = fileName + "." + datetime.datetime.now().strftime("%Y%j%H%M%S%f") + '.bak'
     # create a backup copy to prevent the accidental loss due to the disk write failure
-    shutil.copyfile(fileName, fileName + '.bak')
+    shutil.copyfile(fileName, fileNameBak)
     # write the file
     with open(fileName, 'wb') as configfile:
         shared.config.write(configfile)
     # delete a backup
-    os.remove(fileName + '.bak')
+    os.remove(fileNameBak)
 
 helper_startup.loadConfig()
 from debug import logger

From 9b6bc26144395e05bdc3ae06098a92260f2b48b8 Mon Sep 17 00:00:00 2001
From: Jonathan Warren <Atheros1@users.noreply.github.com>
Date: Thu, 25 Dec 2014 21:06:10 -0500
Subject: [PATCH 4/4] fix bug in #715

---
 src/bitmessageqt/__init__.py |  3 ++-
 src/shared.py                | 11 ++++++++---
 2 files changed, 10 insertions(+), 4 deletions(-)

diff --git a/src/bitmessageqt/__init__.py b/src/bitmessageqt/__init__.py
index 95eb7d12..d3bf8dae 100644
--- a/src/bitmessageqt/__init__.py
+++ b/src/bitmessageqt/__init__.py
@@ -2426,7 +2426,8 @@ class MyForm(QtGui.QMainWindow):
             if shared.appdata != '' and self.settingsDialogInstance.ui.checkBoxPortableMode.isChecked():  # If we are NOT using portable mode now but the user selected that we should...
                 # Write the keys.dat file to disk in the new location
                 sqlStoredProcedure('movemessagstoprog')
-                shared.writeKeysFile()
+                with open('keys.dat', 'wb') as configfile:
+                    shared.config.write(configfile)
                 # Write the knownnodes.dat file to disk in the new location
                 shared.knownNodesLock.acquire()
                 output = open('knownnodes.dat', 'wb')
diff --git a/src/shared.py b/src/shared.py
index df37c1b4..8f4be2ff 100644
--- a/src/shared.py
+++ b/src/shared.py
@@ -850,12 +850,17 @@ def writeKeysFile():
     fileName = shared.appdata + 'keys.dat'
     fileNameBak = fileName + "." + datetime.datetime.now().strftime("%Y%j%H%M%S%f") + '.bak'
     # create a backup copy to prevent the accidental loss due to the disk write failure
-    shutil.copyfile(fileName, fileNameBak)
+    try:
+        shutil.copyfile(fileName, fileNameBak)
+        # The backup succeeded. This can fail if the file didn't exist before. 
+        existingFileNameExisted = True
+    except:
+        existingFileNameExisted = False
     # write the file
     with open(fileName, 'wb') as configfile:
         shared.config.write(configfile)
     # delete a backup
-    os.remove(fileNameBak)
+    if existingFileNameExisted:
+        os.remove(fileNameBak)
 
-helper_startup.loadConfig()
 from debug import logger