Fix crashes on database save

* Add saving mutex to database class to prevent re-entrant saving
* Prevent saving multiple times to the same file if the database is not marked as modified
* Prevent locking the database while saving. This also prevents closing the application and database tab while saving.
* FileWatcher: only perform async checksum calculations when triggered by timer (prevents random GUI freezes)
* Re-attempt database lock when requested during save operation
* Prevent database tabs from closing before all databases are locked on quit
This commit is contained in:
Jonathan White 2020-03-05 22:59:07 -05:00
parent 6bce5836f9
commit 7ac292e09b
12 changed files with 122 additions and 40 deletions

View file

@ -255,15 +255,15 @@ QSharedPointer<Database> DatabaseWidget::database() const
DatabaseWidget::Mode DatabaseWidget::currentMode() const
{
if (currentWidget() == nullptr) {
return DatabaseWidget::Mode::None;
return Mode::None;
} else if (currentWidget() == m_mainWidget) {
return DatabaseWidget::Mode::ViewMode;
return Mode::ViewMode;
} else if (currentWidget() == m_databaseOpenWidget || currentWidget() == m_keepass1OpenWidget) {
return DatabaseWidget::Mode::LockedMode;
return Mode::LockedMode;
} else if (currentWidget() == m_csvImportWizard) {
return DatabaseWidget::Mode::ImportMode;
return Mode::ImportMode;
} else {
return DatabaseWidget::Mode::EditMode;
return Mode::EditMode;
}
}
@ -272,6 +272,11 @@ bool DatabaseWidget::isLocked() const
return currentMode() == Mode::LockedMode;
}
bool DatabaseWidget::isSaving() const
{
return m_db->isSaving();
}
bool DatabaseWidget::isSearchActive() const
{
return m_entryView->inSearchMode();
@ -1380,6 +1385,12 @@ bool DatabaseWidget::lock()
return true;
}
// Don't try to lock the database while saving, this will cause a deadlock
if (m_db->isSaving()) {
QTimer::singleShot(200, this, SLOT(lock()));
return false;
}
emit databaseLockRequested();
clipboard()->clearCopiedText();
@ -1660,7 +1671,6 @@ bool DatabaseWidget::save()
auto focusWidget = qApp->focusWidget();
// TODO: Make this async
// Lock out interactions
m_entryView->setDisabled(true);
m_groupView->setDisabled(true);