mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-02-04 17:05:23 -05:00
Correct saving files to DropBox/Drive/OneDrive
* Replaces QSaveFile with QTemporaryFile * Added backup before save config setting * This method may cause data loss (see comments)
This commit is contained in:
parent
490f77137d
commit
d7f408e455
@ -114,6 +114,7 @@ void Config::init(const QString& fileName)
|
|||||||
m_defaults.insert("AutoSaveAfterEveryChange", false);
|
m_defaults.insert("AutoSaveAfterEveryChange", false);
|
||||||
m_defaults.insert("AutoReloadOnChange", true);
|
m_defaults.insert("AutoReloadOnChange", true);
|
||||||
m_defaults.insert("AutoSaveOnExit", false);
|
m_defaults.insert("AutoSaveOnExit", false);
|
||||||
|
m_defaults.insert("BackupBeforeSave", false);
|
||||||
m_defaults.insert("SearchLimitGroup", false);
|
m_defaults.insert("SearchLimitGroup", false);
|
||||||
m_defaults.insert("MinimizeOnCopy", false);
|
m_defaults.insert("MinimizeOnCopy", false);
|
||||||
m_defaults.insert("UseGroupIconOnEntryCreation", false);
|
m_defaults.insert("UseGroupIconOnEntryCreation", false);
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
#include "Database.h"
|
#include "Database.h"
|
||||||
|
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QSaveFile>
|
#include <QTemporaryFile>
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
#include <QXmlStreamReader>
|
#include <QXmlStreamReader>
|
||||||
@ -470,30 +470,52 @@ Database* Database::unlockFromStdin(QString databaseFilename, QString keyFilenam
|
|||||||
return Database::openDatabaseFile(databaseFilename, compositeKey);
|
return Database::openDatabaseFile(databaseFilename, compositeKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
QString Database::saveToFile(QString filePath)
|
/**
|
||||||
|
* Save the database to a file.
|
||||||
|
*
|
||||||
|
* This function uses QTemporaryFile instead of QSaveFile due to a bug
|
||||||
|
* in Qt (https://bugreports.qt.io/browse/QTBUG-57299) that may prevent
|
||||||
|
* the QSaveFile from renaming itself when using DropBox, Drive, or OneDrive.
|
||||||
|
*
|
||||||
|
* The risk in using QTemporaryFile is that the rename function is not atomic
|
||||||
|
* and may result in loss of data if there is a crash or power loss at the
|
||||||
|
* wrong moment.
|
||||||
|
*
|
||||||
|
* @param filePath Absolute path of the file to save
|
||||||
|
* @param keepOld Rename the original database file instead of deleting
|
||||||
|
* @return error string, if any
|
||||||
|
*/
|
||||||
|
QString Database::saveToFile(QString filePath, bool keepOld)
|
||||||
{
|
{
|
||||||
KeePass2Writer writer;
|
KeePass2Writer writer;
|
||||||
QSaveFile saveFile(filePath);
|
QTemporaryFile saveFile;
|
||||||
if (saveFile.open(QIODevice::WriteOnly)) {
|
if (saveFile.open()) {
|
||||||
|
|
||||||
// write the database to the file
|
// write the database to the file
|
||||||
setEmitModified(false);
|
setEmitModified(false);
|
||||||
writer.writeDatabase(&saveFile, this);
|
writer.writeDatabase(&saveFile, this);
|
||||||
setEmitModified(true);
|
setEmitModified(true);
|
||||||
|
|
||||||
if (writer.hasError()) {
|
if (writer.hasError()) {
|
||||||
|
// the writer failed
|
||||||
return writer.errorString();
|
return writer.errorString();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (saveFile.commit()) {
|
saveFile.close(); // flush to disk
|
||||||
// successfully saved database file
|
|
||||||
return QString();
|
if (keepOld) {
|
||||||
} else {
|
QFile::remove(filePath + ".old");
|
||||||
return saveFile.errorString();
|
QFile::rename(filePath, filePath + ".old");
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile::remove(filePath);
|
||||||
|
if (saveFile.rename(filePath)) {
|
||||||
|
// successfully saved database file
|
||||||
|
saveFile.setAutoRemove(false);
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
return saveFile.errorString();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return saveFile.errorString();
|
||||||
}
|
}
|
||||||
|
|
||||||
QSharedPointer<Kdf> Database::kdf() const
|
QSharedPointer<Kdf> Database::kdf() const
|
||||||
|
@ -111,7 +111,7 @@ public:
|
|||||||
void emptyRecycleBin();
|
void emptyRecycleBin();
|
||||||
void setEmitModified(bool value);
|
void setEmitModified(bool value);
|
||||||
void merge(const Database* other);
|
void merge(const Database* other);
|
||||||
QString saveToFile(QString filePath);
|
QString saveToFile(QString filePath, bool keepOld = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a unique id that is only valid as long as the Database exists.
|
* Returns a unique id that is only valid as long as the Database exists.
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "core/Database.h"
|
#include "core/Database.h"
|
||||||
#include "core/Group.h"
|
#include "core/Group.h"
|
||||||
#include "core/Metadata.h"
|
#include "core/Metadata.h"
|
||||||
|
#include "core/AsyncTask.h"
|
||||||
#include "format/CsvExporter.h"
|
#include "format/CsvExporter.h"
|
||||||
#include "gui/Clipboard.h"
|
#include "gui/Clipboard.h"
|
||||||
#include "gui/DatabaseWidget.h"
|
#include "gui/DatabaseWidget.h"
|
||||||
@ -322,7 +323,8 @@ bool DatabaseTabWidget::saveDatabase(Database* db, QString filePath)
|
|||||||
}
|
}
|
||||||
|
|
||||||
dbStruct.dbWidget->blockAutoReload(true);
|
dbStruct.dbWidget->blockAutoReload(true);
|
||||||
QString errorMessage = db->saveToFile(filePath);
|
// TODO: Make this async, but lock out the database widget to prevent re-entrance
|
||||||
|
QString errorMessage = db->saveToFile(filePath, config()->get("BackupBeforeSave").toBool());
|
||||||
dbStruct.dbWidget->blockAutoReload(false);
|
dbStruct.dbWidget->blockAutoReload(false);
|
||||||
|
|
||||||
if (errorMessage.isEmpty()) {
|
if (errorMessage.isEmpty()) {
|
||||||
|
@ -117,6 +117,7 @@ void SettingsWidget::loadSettings()
|
|||||||
config()->get("OpenPreviousDatabasesOnStartup").toBool());
|
config()->get("OpenPreviousDatabasesOnStartup").toBool());
|
||||||
m_generalUi->autoSaveAfterEveryChangeCheckBox->setChecked(config()->get("AutoSaveAfterEveryChange").toBool());
|
m_generalUi->autoSaveAfterEveryChangeCheckBox->setChecked(config()->get("AutoSaveAfterEveryChange").toBool());
|
||||||
m_generalUi->autoSaveOnExitCheckBox->setChecked(config()->get("AutoSaveOnExit").toBool());
|
m_generalUi->autoSaveOnExitCheckBox->setChecked(config()->get("AutoSaveOnExit").toBool());
|
||||||
|
m_generalUi->backupBeforeSaveCheckBox->setChecked(config()->get("BackupBeforeSave").toBool());
|
||||||
m_generalUi->autoReloadOnChangeCheckBox->setChecked(config()->get("AutoReloadOnChange").toBool());
|
m_generalUi->autoReloadOnChangeCheckBox->setChecked(config()->get("AutoReloadOnChange").toBool());
|
||||||
m_generalUi->minimizeOnCopyCheckBox->setChecked(config()->get("MinimizeOnCopy").toBool());
|
m_generalUi->minimizeOnCopyCheckBox->setChecked(config()->get("MinimizeOnCopy").toBool());
|
||||||
m_generalUi->useGroupIconOnEntryCreationCheckBox->setChecked(config()->get("UseGroupIconOnEntryCreation").toBool());
|
m_generalUi->useGroupIconOnEntryCreationCheckBox->setChecked(config()->get("UseGroupIconOnEntryCreation").toBool());
|
||||||
@ -193,6 +194,7 @@ void SettingsWidget::saveSettings()
|
|||||||
config()->set("AutoSaveAfterEveryChange",
|
config()->set("AutoSaveAfterEveryChange",
|
||||||
m_generalUi->autoSaveAfterEveryChangeCheckBox->isChecked());
|
m_generalUi->autoSaveAfterEveryChangeCheckBox->isChecked());
|
||||||
config()->set("AutoSaveOnExit", m_generalUi->autoSaveOnExitCheckBox->isChecked());
|
config()->set("AutoSaveOnExit", m_generalUi->autoSaveOnExitCheckBox->isChecked());
|
||||||
|
config()->set("BackupBeforeSave", m_generalUi->backupBeforeSaveCheckBox->isChecked());
|
||||||
config()->set("AutoReloadOnChange", m_generalUi->autoReloadOnChangeCheckBox->isChecked());
|
config()->set("AutoReloadOnChange", m_generalUi->autoReloadOnChangeCheckBox->isChecked());
|
||||||
config()->set("MinimizeOnCopy", m_generalUi->minimizeOnCopyCheckBox->isChecked());
|
config()->set("MinimizeOnCopy", m_generalUi->minimizeOnCopyCheckBox->isChecked());
|
||||||
config()->set("UseGroupIconOnEntryCreation",
|
config()->set("UseGroupIconOnEntryCreation",
|
||||||
|
@ -84,6 +84,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="backupBeforeSaveCheckBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Backup database file before saving</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="autoReloadOnChangeCheckBox">
|
<widget class="QCheckBox" name="autoReloadOnChangeCheckBox">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user