diff options
-rw-r--r-- | comphelper/source/misc/backupfilehelper.cxx | 11 | ||||
-rw-r--r-- | configmgr/source/components.cxx | 43 | ||||
-rw-r--r-- | desktop/source/app/app.cxx | 99 | ||||
-rw-r--r-- | desktop/uiconfig/ui/querytrytorestoreconfigurationdialog.ui | 37 | ||||
-rw-r--r-- | include/comphelper/backupfilehelper.hxx | 14 |
5 files changed, 188 insertions, 16 deletions
diff --git a/comphelper/source/misc/backupfilehelper.cxx b/comphelper/source/misc/backupfilehelper.cxx index 778f0a0e7d27..7a353b8e90bb 100644 --- a/comphelper/source/misc/backupfilehelper.cxx +++ b/comphelper/source/misc/backupfilehelper.cxx @@ -15,6 +15,7 @@ namespace comphelper { sal_uInt16 BackupFileHelper::mnMaxAllowedBackups = 10; + bool BackupFileHelper::mbExitWasCalled = false; BackupFileHelper::BackupFileHelper( const OUString& rBaseURL, @@ -28,6 +29,16 @@ namespace comphelper { } + void BackupFileHelper::setExitWasCalled() + { + mbExitWasCalled = true; + } + + bool BackupFileHelper::getExitWasCalled() + { + return mbExitWasCalled; + } + bool BackupFileHelper::tryPush() { if (isDifferentOrNew()) diff --git a/configmgr/source/components.cxx b/configmgr/source/components.cxx index f7c473c53899..a193da06b167 100644 --- a/configmgr/source/components.cxx +++ b/configmgr/source/components.cxx @@ -613,25 +613,48 @@ Components::Components( Components::~Components() { - flushModifications(); + SAL_WARN("configmgr", "################# Components::~Components() #####################"); + + // get flag if _exit was already called which is a sign to not to secure user config + const bool bExitWasCalled(comphelper::BackupFileHelper::getExitWasCalled()); + +#ifndef WNT + // we can add a SAL_WARN here for other systems where the destructor gets called after + // an _exit() call - which should not happen. Still safe - the getExitWasCalled() is + // used, but a hint that _exit behaves different on a system + SAL_WARN_IF(bExitWasCalled, "configmgr", "Components::~Components() called after _exit() call"); +#endif + + if (bExitWasCalled) + { + osl::MutexGuard g(*lock_); + + if (writeThread_.is()) + { + writeThread_->join(); + } + } + else + { + flushModifications(); + } + for (WeakRootSet::iterator i(roots_.begin()); i != roots_.end(); ++i) { (*i)->setAlive(false); } - // test backup of registrymodifications (currently off) - static bool bFeatureSecureUserConfig(false); + // test backup of registrymodifications + static bool bFeatureSecureUserConfig(true); - if (bFeatureSecureUserConfig && ModificationTarget::File == modificationTarget_ && !modificationFileUrl_.isEmpty()) + if (!bExitWasCalled && + bFeatureSecureUserConfig && + ModificationTarget::File == modificationTarget_ && + !modificationFileUrl_.isEmpty()) { static sal_uInt16 nNumCopies(5); comphelper::BackupFileHelper aBackupFileHelper(modificationFileUrl_, nNumCopies); - aBackupFileHelper.tryPush(); - static bool bTryPop(false); - if (bTryPop) - { - aBackupFileHelper.tryPop(); - } + aBackupFileHelper.tryPush(); } } diff --git a/desktop/source/app/app.cxx b/desktop/source/app/app.cxx index bb836d235b6d..4c52d79183cd 100644 --- a/desktop/source/app/app.cxx +++ b/desktop/source/app/app.cxx @@ -81,6 +81,7 @@ #include <comphelper/configuration.hxx> #include <comphelper/fileurl.hxx> #include <comphelper/processfactory.hxx> +#include <comphelper/backupfilehelper.hxx> #include <unotools/bootstrap.hxx> #include <unotools/configmgr.hxx> #include <unotools/moduleoptions.hxx> @@ -567,6 +568,14 @@ void Desktop::Init() { SetBootstrapError( BE_OFFICECONFIG_BROKEN, e.Message ); } + + static bool bTryHardOfficeconfigBroken(false); + + if (bTryHardOfficeconfigBroken) + { + SAL_WARN("configmgr", "################# Desktop::Init() #####################"); + SetBootstrapError(BE_OFFICECONFIG_BROKEN, OUString()); + } } if ( true ) @@ -938,15 +947,93 @@ void Desktop::HandleBootstrapErrors( } else if ( aBootstrapError == BE_OFFICECONFIG_BROKEN ) { - OUString msg( - GetMsgString( + // test restore of registrymodifications + static bool bFeatureSecureUserConfig(true); + static sal_uInt16 nNumCopies(5); + bool bFireOriginalError(true); + + if (bFeatureSecureUserConfig) + { + // try to asccess user layer configuration file + OUString conf("${CONFIGURATION_LAYERS}"); + rtl::Bootstrap::expandMacros(conf); + const OUString aTokenUser("user:"); + sal_Int32 nStart(conf.indexOf(aTokenUser)); + OUString aUser; + + if (-1 != nStart) + { + nStart += aTokenUser.getLength(); + sal_Int32 nEnd(conf.indexOf(' ', nStart)); + + if (-1 == nEnd) + { + nEnd = conf.getLength(); + } + + aUser = conf.copy(nStart, nEnd - nStart); + aUser.startsWith("!", &aUser); + } + + if (!aUser.isEmpty()) + { + comphelper::BackupFileHelper aBackupFileHelper(aUser, nNumCopies); + + if (aBackupFileHelper.isPopPossible()) + { + // for linux (and probably others?) we need to instantiate XDesktop2 + // to be able to open a *.ui-file based dialog, so do this here locally. + // does no harm on win, so better always do this (in error case only anyways) + Reference< XComponentContext > xLocalContext = ::comphelper::getProcessComponentContext(); + Reference< XDesktop2 > xDesktop = css::frame::Desktop::create(xLocalContext); + + ScopedVclPtrInstance< MessageDialog > aQueryShouldRestore( + Application::GetDefDialogParent(), + "QueryTryToRestoreConfigurationDialog", + "desktop/ui/querytrytorestoreconfigurationdialog.ui"); + + if (aQueryShouldRestore.get()) + { + if (!aErrorMessage.isEmpty()) + { + OUString aPrimaryText(aQueryShouldRestore->get_primary_text()); + + aPrimaryText += "\n(\"" + aErrorMessage + "\")"; + aQueryShouldRestore->set_primary_text(aPrimaryText); + } + + if (RET_YES == aQueryShouldRestore->Execute()) + { + aBackupFileHelper.tryPop(); + bFireOriginalError = false; + } + } + } + } + } + + // set flag at BackupFileHelper to be able to know if _exit was called and + // actions are executed after this + comphelper::BackupFileHelper::setExitWasCalled(); + + if (bFireOriginalError) + { + OUString msg( + GetMsgString( STR_CONFIG_ERR_ACCESS_GENERAL, ("A general error occurred while accessing your central" - " configuration."))); - if (!aErrorMessage.isEmpty()) { - msg += "\n(\"" + aErrorMessage + "\")"; + " configuration."))); + if (!aErrorMessage.isEmpty()) { + msg += "\n(\"" + aErrorMessage + "\")"; + } + FatalError(MakeStartupErrorMessage(msg)); + } + else + { + // Already presented all information to the user. + // just do what FatalError does at it's end + _exit(EXITHELPER_FATAL_ERROR); } - FatalError(MakeStartupErrorMessage(msg)); } else if ( aBootstrapError == BE_USERINSTALL_FAILED ) { diff --git a/desktop/uiconfig/ui/querytrytorestoreconfigurationdialog.ui b/desktop/uiconfig/ui/querytrytorestoreconfigurationdialog.ui new file mode 100644 index 000000000000..4c332d1889d6 --- /dev/null +++ b/desktop/uiconfig/ui/querytrytorestoreconfigurationdialog.ui @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + <!-- interface-requires gtk+ 3.0 --> + <object class="GtkMessageDialog" id="QueryTryToRestoreConfigurationDialog"> + <property name="can_focus">False</property> + <property name="border_width">6</property> + <property name="title" translatable="yes">LibreOffice Startup: General Configuration Error</property> + <property name="resizable">False</property> + <property name="type_hint">dialog</property> + <property name="skip_taskbar_hint">True</property> + <property name="message_type">question</property> + <property name="buttons">yes-no</property> + <property name="text" translatable="yes">A general error occurred during startup while accessing the central configuration.</property> + <property name="secondary_text" translatable="yes">A Backup of your configuration was detected. Restoring the configuration might solve this problem, but is not guaranteed to work. A restart of the Program is needed. + +Do you want to restore the configuration?</property> + <child internal-child="vbox"> + <object class="GtkBox" id="messagedialog-vbox5"> + <property name="can_focus">False</property> + <property name="orientation">vertical</property> + <property name="spacing">12</property> + <child internal-child="action_area"> + <object class="GtkButtonBox" id="messagedialog-action_area5"> + <property name="can_focus">False</property> + <property name="layout_style">end</property> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="pack_type">end</property> + <property name="position">0</property> + </packing> + </child> + </object> + </child> + </object> +</interface> diff --git a/include/comphelper/backupfilehelper.hxx b/include/comphelper/backupfilehelper.hxx index 3061254615ae..f407d2b8815c 100644 --- a/include/comphelper/backupfilehelper.hxx +++ b/include/comphelper/backupfilehelper.hxx @@ -14,6 +14,7 @@ #include <comphelper/comphelperdllapi.h> #include <rtl/ustring.hxx> +#include <osl/file.hxx> namespace comphelper { @@ -51,6 +52,15 @@ namespace comphelper osl::File maBaseFile; bool mbBaseFileIsOpen; + // internal flag if _exit() was called already - a hint to evtl. + // not create copies of potentially not well-defined data. This + // may be used in destructors of static instances - which unfortunately + // get called on WNT but not on linux. Thus I thought about encapsulating + // in some '#ifdefs', but it's just more safe to always do it and + // allows to add a SAL_WARN when one of these destructors is called + // after _exit() + static bool mbExitWasCalled; + // internal upper limit (max) of allowed backups static sal_uInt16 mnMaxAllowedBackups; @@ -69,6 +79,10 @@ namespace comphelper */ BackupFileHelper(const OUString& rBaseURL, sal_uInt16 nNumBackups = 5); + // allow to set flag when app had to call _exit() + static void setExitWasCalled(); + static bool getExitWasCalled(); + /** tries to create a new backup, if there is none yet, or if the * last differs from the base file. It will then put a new verion * on the 'stack' of copies and evtl. delete the oldest backup. |