diff --git a/share/translations/keepassxc_en.ts b/share/translations/keepassxc_en.ts index 301d888ff..81895f9ea 100644 --- a/share/translations/keepassxc_en.ts +++ b/share/translations/keepassxc_en.ts @@ -2825,6 +2825,10 @@ Disable safe saves and try again? Database file on disk cannot be unlocked with current credentials.<br>Enter new credentials and/or present hardware key to continue. + + Failed to save backup database: %1 + + EditEntryWidget diff --git a/src/gui/DatabaseWidget.cpp b/src/gui/DatabaseWidget.cpp index 465df1367..7b8f9e5cc 100644 --- a/src/gui/DatabaseWidget.cpp +++ b/src/gui/DatabaseWidget.cpp @@ -2615,45 +2615,45 @@ bool DatabaseWidget::performSave(QString& errorMessage, const QString& fileName) */ bool DatabaseWidget::saveBackup() { - while (true) { - QString oldFilePath = m_db->filePath(); - if (!QFileInfo::exists(oldFilePath)) { - QString defaultFileName = config()->get(Config::DefaultDatabaseFileName).toString(); - oldFilePath = QDir::toNativeSeparators( - FileDialog::getLastDir("db") + "/" - + (defaultFileName.isEmpty() ? tr("Passwords").append(".kdbx") : defaultFileName)); - } + QString oldFilePath = m_db->filePath(); + if (!QFileInfo::exists(oldFilePath)) { + QString defaultFileName = config()->get(Config::DefaultDatabaseFileName).toString(); + oldFilePath = + QDir::toNativeSeparators(FileDialog::getLastDir("db") + "/" + + (defaultFileName.isEmpty() ? tr("Passwords").append(".kdbx") : defaultFileName)); + } - const QString newFilePath = fileDialog()->getSaveFileName(this, - tr("Save database backup"), - FileDialog::getLastDir("backup", oldFilePath), - tr("KeePass 2 Database").append(" (*.kdbx)")); + const QString newFilePath = fileDialog()->getSaveFileName(this, + tr("Save database backup"), + FileDialog::getLastDir("backup", oldFilePath), + tr("KeePass 2 Database").append(" (*.kdbx)")); - if (!newFilePath.isEmpty()) { - // Ensure we don't recurse back into this function - m_db->setFilePath(newFilePath); - m_saveAttempts = 0; - - bool modified = m_db->isModified(); - - if (!save()) { - // Failed to save, try again - m_db->setFilePath(oldFilePath); - continue; - } - - m_db->setFilePath(oldFilePath); - if (modified) { - // Source database is marked as clean when copy is saved, even if source has unsaved changes - m_db->markAsModified(); - } - FileDialog::saveLastDir("backup", newFilePath, true); - return true; - } - - // Canceled file selection + // Early out if we canceled the file selection + if (newFilePath.isEmpty()) { return false; } + + // Record modified state so we can restore after save + bool modified = m_db->isModified(); + + QString error; + bool ok = m_db->saveAs(newFilePath, Database::DirectWrite, {}, &error); + + // Restore database to original state + m_db->setFilePath(oldFilePath); + if (modified) { + // Source database is marked as clean when copy is saved, even if source has unsaved changes + m_db->markAsModified(); + } + + if (!ok) { + // Failed to save backup, post the error + showErrorMessage(tr("Failed to save backup database: %1").arg(error)); + return false; + } + + FileDialog::saveLastDir("backup", newFilePath, true); + return true; } void DatabaseWidget::showMessage(const QString& text,