profilesafe: extended to three modes

Saving configuration is now extended to three
basic modes, from just saving registrymodifiications
to adding user-defined config stuff to saving all
information in the user profile, additionally
configuration information for Extensions is saved.
Added configuration entries for this and tested
saving/restoring.

Change-Id: I79b09c37617803bf656826f76a7e3db79cda49ac
Reviewed-on: https://gerrit.libreoffice.org/29770
Tested-by: Jenkins <ci@libreoffice.org>
Reviewed-by: Armin Le Grand <Armin.Le.Grand@cib.de>
This commit is contained in:
Armin Le Grand
2016-10-13 14:16:56 +02:00
parent 83cc9a3fae
commit 5f55b7d00a
4 changed files with 631 additions and 221 deletions

View File

@@ -27,11 +27,12 @@
#include <zlib.h>
using namespace css;
typedef std::shared_ptr< osl::File > FileSharedPtr;
static const sal_uInt32 BACKUP_FILE_HELPER_BLOCK_SIZE = 16384;
namespace
{
typedef std::shared_ptr< osl::File > FileSharedPtr;
OUString splitAtLastToken(const OUString& rSrc, sal_Unicode aToken, OUString& rRight)
{
const sal_Int32 nIndex(rSrc.lastIndexOf(aToken));
@@ -170,6 +171,41 @@ namespace
return false;
}
OUString createFileURL(const OUString& rURL, const OUString& rName, const OUString& rExt)
{
OUString aRetval;
if (!rURL.isEmpty() && !rName.isEmpty())
{
aRetval = rURL;
aRetval += "/";
aRetval += rName;
if (!rExt.isEmpty())
{
aRetval += ".";
aRetval += rExt;
}
}
return aRetval;
}
OUString createPackURL(const OUString& rURL, const OUString& rName)
{
OUString aRetval;
if (!rURL.isEmpty() && !rName.isEmpty())
{
aRetval = rURL;
aRetval += "/";
aRetval += rName;
aRetval += ".pack";
}
return aRetval;
}
bool fileExists(const OUString& rBaseURL)
{
if (!rBaseURL.isEmpty())
@@ -181,6 +217,51 @@ namespace
return false;
}
void scanDirsAndFiles(
const OUString& rDirURL,
std::set< OUString >& rDirs,
std::set< std::pair< OUString, OUString > >& rFiles)
{
if (!rDirURL.isEmpty())
{
osl::Directory aDirectory(rDirURL);
if (osl::FileBase::E_None == aDirectory.open())
{
osl::DirectoryItem aDirectoryItem;
while (osl::FileBase::E_None == aDirectory.getNextItem(aDirectoryItem))
{
osl::FileStatus aFileStatus(osl_FileStatus_Mask_Type | osl_FileStatus_Mask_FileURL | osl_FileStatus_Mask_FileName);
if (osl::FileBase::E_None == aDirectoryItem.getFileStatus(aFileStatus))
{
if (aFileStatus.isDirectory())
{
const OUString aFileName(aFileStatus.getFileName());
if (!aFileName.isEmpty())
{
rDirs.insert(aFileName);
}
}
else if (aFileStatus.isRegular())
{
OUString aFileName(aFileStatus.getFileName());
OUString aExtension;
aFileName = splitAtLastToken(aFileName, '.', aExtension);
if (!aFileName.isEmpty())
{
rFiles.insert(std::pair< OUString, OUString >(aFileName, aExtension));
}
}
}
}
}
}
}
}
namespace
@@ -1176,15 +1257,96 @@ namespace comphelper
sal_uInt16 BackupFileHelper::mnMaxAllowedBackups = 10;
bool BackupFileHelper::mbExitWasCalled = false;
BackupFileHelper::BackupFileHelper(
const OUString& rBaseURL,
sal_uInt16 nNumBackups)
: mrBaseURL(rBaseURL),
mnNumBackups(::std::min(::std::max(nNumBackups, sal_uInt16(1)), mnMaxAllowedBackups)),
maBase(),
maName(),
maExt()
BackupFileHelper::BackupFileHelper()
: maInitialBaseURL(),
maUserConfigBaseURL(),
maRegModName(),
maExt(),
maDirs(),
maFiles(),
mnNumBackups(2),
mnMode(0),
mbActive(false),
mbExtensions(true),
mbCompress(true)
{
OUString sTokenOut;
// read configuration item 'SecureUserConfig' -> bool on/off
if (rtl::Bootstrap::get("SecureUserConfig", sTokenOut))
{
mbActive = sTokenOut.toBoolean();
}
if (mbActive && rtl::Bootstrap::get("SecureUserConfigNumCopies", sTokenOut))
{
const sal_uInt16 nConfigNumCopies(static_cast<sal_uInt16>(sTokenOut.toUInt32()));
// limit to range [1..mnMaxAllowedBackups]
mnNumBackups = ::std::min(::std::max(nConfigNumCopies, mnNumBackups), mnMaxAllowedBackups);
}
if (mbActive && rtl::Bootstrap::get("SecureUserConfigMode", sTokenOut))
{
const sal_uInt16 nMode(static_cast<sal_uInt16>(sTokenOut.toUInt32()));
// limit to range [0..2]
mnMode = ::std::min(nMode, sal_uInt16(2));
}
if (mbActive && rtl::Bootstrap::get("SecureUserConfigExtensions", sTokenOut))
{
mbExtensions = sTokenOut.toBoolean();
}
if (mbActive && rtl::Bootstrap::get("SecureUserConfigCompress", sTokenOut))
{
mbCompress = sTokenOut.toBoolean();
}
if (mbActive)
{
// try to access user layer configuration file URL, the one that
// points to registrymodifications.xcu
OUString conf("${CONFIGURATION_LAYERS}");
rtl::Bootstrap::expandMacros(conf);
const OUString aTokenUser("user:");
sal_Int32 nStart(conf.indexOf(aTokenUser));
if (-1 != nStart)
{
nStart += aTokenUser.getLength();
sal_Int32 nEnd(conf.indexOf(' ', nStart));
if (-1 == nEnd)
{
nEnd = conf.getLength();
}
maInitialBaseURL = conf.copy(nStart, nEnd - nStart);
maInitialBaseURL.startsWith("!", &maInitialBaseURL);
}
if (maInitialBaseURL.isEmpty())
{
// if not found, we are out of business
mbActive = false;
}
}
if (mbActive)
{
// split to path_to_user_config (maUserConfigBaseURL),
// name_of_regMod (maRegModName)
// and extension (maExt)
if (maUserConfigBaseURL.isEmpty() && !maInitialBaseURL.isEmpty())
{
// split URL at extension and at last path separator
maUserConfigBaseURL = splitAtLastToken(splitAtLastToken(maInitialBaseURL, '.', maExt), '/', maRegModName);
}
mbActive = !maUserConfigBaseURL.isEmpty() && !maRegModName.isEmpty();
}
}
void BackupFileHelper::setExitWasCalled()
@@ -1197,40 +1359,32 @@ namespace comphelper
return mbExitWasCalled;
}
bool BackupFileHelper::getSecureUserConfig(sal_uInt16& rnSecureUserConfigNumCopies)
{
// init to not active
bool bRetval(false);
rnSecureUserConfigNumCopies = 0;
OUString sTokenOut;
if (rtl::Bootstrap::get("SecureUserConfig", sTokenOut))
{
bRetval = sTokenOut.toBoolean();
}
if (bRetval && rtl::Bootstrap::get("SecureUserConfigNumCopies", sTokenOut))
{
rnSecureUserConfigNumCopies = static_cast< sal_uInt16 >(sTokenOut.toUInt32());
}
return bRetval;
}
bool BackupFileHelper::tryPush(bool bCompress)
bool BackupFileHelper::tryPush()
{
bool bDidPush(false);
if (splitBaseURL())
if (mbActive)
{
// ensure directory existence
osl::Directory::createPath(getPackDirName());
const OUString aPackURL(getPackURL());
// try push for base file (usually registrymodifications)
bDidPush = tryPush_basefile(bCompress);
// ensure dir and file vectors
fillDirFileInfo();
// proccess all files in question recursively
if (!maDirs.empty() || !maFiles.empty())
{
bDidPush = tryPush_Files(
maDirs,
maFiles,
maUserConfigBaseURL,
aPackURL);
}
// Try Push of ExtensionInfo
bDidPush |= tryPush_extensionInfo(bCompress);
if (mbExtensions)
{
bDidPush |= tryPush_extensionInfo(aPackURL);
}
}
return bDidPush;
@@ -1240,13 +1394,28 @@ namespace comphelper
{
bool bPopPossible(false);
if (splitBaseURL())
if (mbActive)
{
// try for base file (usually registrymodifications)
bPopPossible = isPopPossible_basefile();
const OUString aPackURL(getPackURL());
// ensure dir and file vectors
fillDirFileInfo();
// proccess all files in question recursively
if (!maDirs.empty() || !maFiles.empty())
{
bPopPossible = isPopPossible_files(
maDirs,
maFiles,
maUserConfigBaseURL,
aPackURL);
}
// try for ExtensionInfo
bPopPossible |= isPopPossible_extensionInfo();
if (mbExtensions)
{
bPopPossible |= isPopPossible_extensionInfo(aPackURL);
}
}
return bPopPossible;
@@ -1256,53 +1425,116 @@ namespace comphelper
{
bool bDidPop(false);
if (splitBaseURL())
if (mbActive)
{
// try for base file (usually registrymodifications)
bDidPop = tryPop_basefile();
const OUString aPackURL(getPackURL());
// ensure dir and file vectors
fillDirFileInfo();
// proccess all files in question recursively
if (!maDirs.empty() || !maFiles.empty())
{
bDidPop = tryPop_files(
maDirs,
maFiles,
maUserConfigBaseURL,
aPackURL);
}
// try for ExtensionInfo
bDidPop |= tryPop_extensionInfo();
if (mbExtensions)
{
bDidPop |= tryPop_extensionInfo(aPackURL);
}
if (bDidPop)
{
// try removal of evtl. empty directory
osl::Directory::remove(getPackDirName());
osl::Directory::remove(aPackURL);
}
}
return bDidPop;
}
bool BackupFileHelper::splitBaseURL()
/////////////////// helpers ///////////////////////
const rtl::OUString BackupFileHelper::getPackURL() const
{
if (maBase.isEmpty() && !mrBaseURL.isEmpty())
return rtl::OUString(maUserConfigBaseURL + "/pack");
}
/////////////////// file push helpers ///////////////////////
bool BackupFileHelper::tryPush_Files(
const std::set< OUString >& rDirs,
const std::set< std::pair< OUString, OUString > >& rFiles,
const OUString& rSourceURL, // source dir without trailing '/'
const OUString& rTargetURL // target dir without trailing '/'
)
{
bool bDidPush(false);
osl::Directory::createPath(rTargetURL);
// proccess files
for (const auto& file : rFiles)
{
// split URL at extension and at last path separator
maBase = splitAtLastToken(splitAtLastToken(mrBaseURL, '.', maExt), '/', maName);
bDidPush |= tryPush_file(
rSourceURL,
rTargetURL,
file.first,
file.second);
}
return !maBase.isEmpty() && !maName.isEmpty();
}
const rtl::OUString BackupFileHelper::getPackDirName() const
{
return rtl::OUString(maBase + "/pack");
}
const rtl::OUString BackupFileHelper::getPackFileName(const rtl::OUString& rFileName) const
{
return rtl::OUString(getPackDirName() + "/" + rFileName + ".pack");
}
bool BackupFileHelper::tryPush_basefile(bool bCompress)
{
if (fileExists(mrBaseURL))
// proccess dirs
for (const auto& dir : rDirs)
{
PackedFile aPackedFile(getPackFileName(maName));
FileSharedPtr aBaseFile(new osl::File(mrBaseURL));
OUString aNewSourceURL(rSourceURL + "/" + dir);
OUString aNewTargetURL(rTargetURL + "/" + dir);
std::set< OUString > aNewDirs;
std::set< std::pair< OUString, OUString > > aNewFiles;
if (aPackedFile.tryPush(aBaseFile, bCompress))
scanDirsAndFiles(
aNewSourceURL,
aNewDirs,
aNewFiles);
if (!aNewDirs.empty() || !aNewFiles.empty())
{
bDidPush |= tryPush_Files(
aNewDirs,
aNewFiles,
aNewSourceURL,
aNewTargetURL);
}
}
if (!bDidPush)
{
// try removal of evtl. empty directory
osl::Directory::remove(rTargetURL);
}
return bDidPush;
}
bool BackupFileHelper::tryPush_file(
const OUString& rSourceURL, // source dir without trailing '/'
const OUString& rTargetURL, // target dir without trailing '/'
const OUString& rName, // filename
const OUString& rExt // extension (or empty)
)
{
const OUString aFileURL(createFileURL(rSourceURL, rName, rExt));
if (fileExists(aFileURL))
{
const OUString aPackURL(createPackURL(rTargetURL, rName));
PackedFile aPackedFile(aPackURL);
FileSharedPtr aBaseFile(new osl::File(aFileURL));
if (aPackedFile.tryPush(aBaseFile, mbCompress))
{
// reduce to allowed number and flush
aPackedFile.tryReduceToNumBackups(mnNumBackups);
@@ -1315,37 +1547,66 @@ namespace comphelper
return false;
}
bool BackupFileHelper::tryPush_extensionInfo(bool bCompress)
/////////////////// file pop possibilities helper ///////////////////////
bool BackupFileHelper::isPopPossible_files(
const std::set< OUString >& rDirs,
const std::set< std::pair< OUString, OUString > >& rFiles,
const OUString& rSourceURL, // source dir without trailing '/'
const OUString& rTargetURL // target dir without trailing '/'
)
{
ExtensionInfo aExtensionInfo;
OUString aTempURL;
bool bRetval(false);
bool bPopPossible(false);
// create current configuration and write to temp file - it exists until deleted
if (aExtensionInfo.createTempFile(aTempURL))
// proccess files
for (const auto& file : rFiles)
{
PackedFile aPackedFile(getPackFileName("ExtensionInfo"));
FileSharedPtr aBaseFile(new osl::File(aTempURL));
bPopPossible |= isPopPossible_file(
rSourceURL,
rTargetURL,
file.first,
file.second);
}
if (aPackedFile.tryPush(aBaseFile, bCompress))
// proccess dirs
for (const auto& dir : rDirs)
{
OUString aNewSourceURL(rSourceURL + "/" + dir);
OUString aNewTargetURL(rTargetURL + "/" + dir);
std::set< OUString > aNewDirs;
std::set< std::pair< OUString, OUString > > aNewFiles;
scanDirsAndFiles(
aNewSourceURL,
aNewDirs,
aNewFiles);
if (!aNewDirs.empty() || !aNewFiles.empty())
{
// reduce to allowed number and flush
aPackedFile.tryReduceToNumBackups(mnNumBackups);
aPackedFile.flush();
bRetval = true;
bPopPossible |= isPopPossible_files(
aNewDirs,
aNewFiles,
aNewSourceURL,
aNewTargetURL);
}
}
// delete temp file (in all cases)
osl::File::remove(aTempURL);
return bRetval;
return bPopPossible;
}
bool BackupFileHelper::isPopPossible_basefile()
bool BackupFileHelper::isPopPossible_file(
const OUString& rSourceURL, // source dir without trailing '/'
const OUString& rTargetURL, // target dir without trailing '/'
const OUString& rName, // filename
const OUString& rExt // extension (or empty)
)
{
if (fileExists(mrBaseURL))
const OUString aFileURL(createFileURL(rSourceURL, rName, rExt));
if (fileExists(aFileURL))
{
PackedFile aPackedFile(getPackFileName(maName));
const OUString aPackURL(createPackURL(rTargetURL, rName));
PackedFile aPackedFile(aPackURL);
return !aPackedFile.empty();
}
@@ -1353,20 +1614,73 @@ namespace comphelper
return false;
}
bool BackupFileHelper::isPopPossible_extensionInfo()
{
// extensionInfo always exists internally, no test needed
PackedFile aPackedFile(getPackFileName("ExtensionInfo"));
/////////////////// file pop helpers ///////////////////////
return !aPackedFile.empty();
bool BackupFileHelper::tryPop_files(
const std::set< OUString >& rDirs,
const std::set< std::pair< OUString, OUString > >& rFiles,
const OUString& rSourceURL, // source dir without trailing '/'
const OUString& rTargetURL // target dir without trailing '/'
)
{
bool bDidPop(false);
// proccess files
for (const auto& file : rFiles)
{
bDidPop |= tryPop_file(
rSourceURL,
rTargetURL,
file.first,
file.second);
}
// proccess dirs
for (const auto& dir : rDirs)
{
OUString aNewSourceURL(rSourceURL + "/" + dir);
OUString aNewTargetURL(rTargetURL + "/" + dir);
std::set< OUString > aNewDirs;
std::set< std::pair< OUString, OUString > > aNewFiles;
scanDirsAndFiles(
aNewSourceURL,
aNewDirs,
aNewFiles);
if (!aNewDirs.empty() || !aNewFiles.empty())
{
bDidPop |= tryPop_files(
aNewDirs,
aNewFiles,
aNewSourceURL,
aNewTargetURL);
}
}
if (bDidPop)
{
// try removal of evtl. empty directory
osl::Directory::remove(rTargetURL);
}
return bDidPop;
}
bool BackupFileHelper::tryPop_basefile()
bool BackupFileHelper::tryPop_file(
const OUString& rSourceURL, // source dir without trailing '/'
const OUString& rTargetURL, // target dir without trailing '/'
const OUString& rName, // filename
const OUString& rExt // extension (or empty)
)
{
if (fileExists(mrBaseURL))
const OUString aFileURL(createFileURL(rSourceURL, rName, rExt));
if (fileExists(aFileURL))
{
// try Pop for base file (usually registrymodifications)
PackedFile aPackedFile(getPackFileName(maName));
// try Pop for base file
const OUString aPackURL(createPackURL(rTargetURL, rName));
PackedFile aPackedFile(aPackURL);
if (!aPackedFile.empty())
{
@@ -1385,8 +1699,8 @@ namespace comphelper
{
// copy over existing file by first deleting original
// and moving the temp file to old original
osl::File::remove(mrBaseURL);
osl::File::move(aTempURL, mrBaseURL);
osl::File::remove(aFileURL);
osl::File::move(aTempURL, aFileURL);
// reduce to allowed number and flush
aPackedFile.tryReduceToNumBackups(mnNumBackups);
@@ -1404,10 +1718,55 @@ namespace comphelper
return false;
}
bool BackupFileHelper::tryPop_extensionInfo()
/////////////////// ExtensionInfo helpers ///////////////////////
bool BackupFileHelper::tryPush_extensionInfo(
const OUString& rTargetURL // target dir without trailing '/'
)
{
ExtensionInfo aExtensionInfo;
OUString aTempURL;
bool bRetval(false);
// create current configuration and write to temp file - it exists until deleted
if (aExtensionInfo.createTempFile(aTempURL))
{
const OUString aPackURL(createPackURL(rTargetURL, "ExtensionInfo"));
PackedFile aPackedFile(aPackURL);
FileSharedPtr aBaseFile(new osl::File(aTempURL));
if (aPackedFile.tryPush(aBaseFile, mbCompress))
{
// reduce to allowed number and flush
aPackedFile.tryReduceToNumBackups(mnNumBackups);
aPackedFile.flush();
bRetval = true;
}
}
// delete temp file (in all cases)
osl::File::remove(aTempURL);
return bRetval;
}
bool BackupFileHelper::isPopPossible_extensionInfo(
const OUString& rTargetURL // target dir without trailing '/'
)
{
// extensionInfo always exists internally, no test needed
PackedFile aPackedFile(getPackFileName("ExtensionInfo"));
const OUString aPackURL(createPackURL(rTargetURL, "ExtensionInfo"));
PackedFile aPackedFile(aPackURL);
return !aPackedFile.empty();
}
bool BackupFileHelper::tryPop_extensionInfo(
const OUString& rTargetURL // target dir without trailing '/'
)
{
// extensionInfo always exists internally, no test needed
const OUString aPackURL(createPackURL(rTargetURL, "ExtensionInfo"));
PackedFile aPackedFile(aPackURL);
if (!aPackedFile.empty())
{
@@ -1436,7 +1795,9 @@ namespace comphelper
aCurrentExtensionInfo.createCurrent();
// now we have loaded and current ExtensionInfo and may react on differences
// now we have loaded last_working (aLoadedExtensionInfo) and
// current (aCurrentExtensionInfo) ExtensionInfo and may react on
// differences by de/activating these as needed
@@ -1460,6 +1821,95 @@ namespace comphelper
return false;
}
/////////////////// FileDirInfo helpers ///////////////////////
void BackupFileHelper::fillDirFileInfo()
{
if (!maDirs.empty() || !maFiles.empty())
{
// already done
return;
}
// fill dir and file info list to work with dependent on work mode
switch (mnMode)
{
case 0:
{
// add registrymodifications (the orig file in maInitialBaseURL)
maFiles.insert(std::pair< OUString, OUString >(maRegModName, maExt));
break;
}
case 1:
{
// add registrymodifications (the orig file in maInitialBaseURL)
maFiles.insert(std::pair< OUString, OUString >(maRegModName, maExt));
// Add a selection of dirs containing User-Defined and thus
// valuable configuration information (see https://wiki.documentfoundation.org/UserProfile).
// This is clearly discussable in every single point and may be adapted/corrected
// over time. Main focus is to secure User-Defined/adapted values
// User-defined substitution table (Tools/AutoCorrect)
maDirs.insert("autocorr");
// User-Defined AutoText (Edit/AutoText)
maDirs.insert("autotext");
// User-defined Macros
maDirs.insert("basic");
// User-adapted toolbars for modules
maDirs.insert("config");
// Initial and User-defined Databases
maDirs.insert("database");
// User-Defined Galleries
maDirs.insert("gallery");
// most part of registry files
maDirs.insert("registry");
// User-Defined Scripts
maDirs.insert("Scripts");
// Template files
maDirs.insert("template");
// Custom Dictionaries
maDirs.insert("wordbook");
// Questionable - where and how is Extension stuff held and how
// does this interact with enabled/disabled states which are extra handled?
// Keep out of business until deeper evaluated
// maDirs.insert("extensions");
// maDirs.insert("uno-packages");
break;
}
case 2:
{
// whole directory. To do so, scan directory and exclude some dirs
// from which we know they do not need to be secured explicitely. This
// should alrteady include registrymodifications, too.
scanDirsAndFiles(
maUserConfigBaseURL,
maDirs,
maFiles);
// not really needed, can be abandoned
maDirs.erase("psprint");
// not really needed, can be abandoned
maDirs.erase("store");
// not really needed, can be abandoned
maDirs.erase("temp");
break;
}
}
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

View File

@@ -818,42 +818,6 @@ OUString Desktop::CreateErrorMsgString(
return MakeStartupErrorMessage( aMsg );
}
// helper method to test if SecureUserConfig is active, detect the num copies
// and extract the User's config directory URL
bool testSecureUserConfigActive(sal_uInt16& rnSecureUserConfigNumCopies, OUString& raUserConfigDir)
{
// read configuration from soffice.ini
if(comphelper::BackupFileHelper::getSecureUserConfig(rnSecureUserConfigNumCopies))
{
// 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));
if (-1 != nStart)
{
nStart += aTokenUser.getLength();
sal_Int32 nEnd(conf.indexOf(' ', nStart));
if (-1 == nEnd)
{
nEnd = conf.getLength();
}
raUserConfigDir = conf.copy(nStart, nEnd - nStart);
raUserConfigDir.startsWith("!", &raUserConfigDir);
}
if (!raUserConfigDir.isEmpty())
{
return true;
}
}
return false;
}
void Desktop::HandleBootstrapErrors(
BootstrapError aBootstrapError, OUString const & aErrorMessage )
{
@@ -987,43 +951,37 @@ void Desktop::HandleBootstrapErrors(
}
else if ( aBootstrapError == BE_OFFICECONFIG_BROKEN )
{
// test if SecureUserConfig is active
sal_uInt16 nSecureUserConfigNumCopies(0);
OUString aUserConfigDir;
bool bFireOriginalError(true);
comphelper::BackupFileHelper aBackupFileHelper;
if (testSecureUserConfigActive(nSecureUserConfigNumCopies, aUserConfigDir))
// crerate BackupFileHelper and check if active and if pop is possible
if (aBackupFileHelper.isPopPossible())
{
comphelper::BackupFileHelper aBackupFileHelper(aUserConfigDir, nSecureUserConfigNumCopies);
// 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);
if (aBackupFileHelper.isPopPossible())
ScopedVclPtrInstance< MessageDialog > aQueryShouldRestore(
Application::GetDefDialogParent(),
"QueryTryToRestoreConfigurationDialog",
"desktop/ui/querytrytorestoreconfigurationdialog.ui");
if (aQueryShouldRestore.get())
{
// 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())
{
if (!aErrorMessage.isEmpty())
{
OUString aPrimaryText(aQueryShouldRestore->get_primary_text());
OUString aPrimaryText(aQueryShouldRestore->get_primary_text());
aPrimaryText += "\n(\"" + aErrorMessage + "\")";
aQueryShouldRestore->set_primary_text(aPrimaryText);
}
aPrimaryText += "\n(\"" + aErrorMessage + "\")";
aQueryShouldRestore->set_primary_text(aPrimaryText);
}
if (RET_YES == aQueryShouldRestore->Execute())
{
aBackupFileHelper.tryPop();
bFireOriginalError = false;
}
if (RET_YES == aQueryShouldRestore->Execute())
{
aBackupFileHelper.tryPop();
bFireOriginalError = false;
}
}
}
@@ -1863,16 +1821,9 @@ int Desktop::doShutdown()
// Test if SecureUserConfig is active. If yes and we are at this point, regular shutdown
// is in progress and the currently used configuration was working. Try to secure this
// working configuration for later eventually necessary restores
sal_uInt16 nSecureUserConfigNumCopies(0);
OUString aUserConfigDir;
comphelper::BackupFileHelper aBackupFileHelper;
if (testSecureUserConfigActive(nSecureUserConfigNumCopies, aUserConfigDir))
{
// try to push registrymodifications.xcu
comphelper::BackupFileHelper aBackupFileHelper(aUserConfigDir, nSecureUserConfigNumCopies);
aBackupFileHelper.tryPush();
}
aBackupFileHelper.tryPush();
}
// The acceptors in the AcceptorMap must be released (in DeregisterServices)

View File

@@ -16,6 +16,7 @@
#include <rtl/ustring.hxx>
#include <osl/file.hxx>
#include <memory>
#include <set>
namespace comphelper
{
@@ -59,11 +60,20 @@ namespace comphelper
{
private:
// internal data
const OUString& mrBaseURL;
sal_uInt16 mnNumBackups;
OUString maBase;
OUString maName;
OUString maExt;
OUString maInitialBaseURL;
OUString maUserConfigBaseURL;
OUString maRegModName;
OUString maExt;
std::set< OUString > maDirs;
std::set< std::pair< OUString, OUString > > maFiles;
sal_uInt16 mnNumBackups;
sal_uInt16 mnMode;
bool mbActive;
bool mbExtensions;
bool mbCompress;
// internal flag if _exit() was called already - a hint to evtl.
// not create copies of potentially not well-defined data. This
@@ -78,51 +88,26 @@ namespace comphelper
static sal_uInt16 mnMaxAllowedBackups;
public:
/** Constructor to handle Backups of the given file
*
* @param rxContext
* ComponentContext to use internally; needs to be handed
* over due to usages after DeInit() and thus no access
* anymore using comphelper::getProcessComponentContext()
* @param rBaseURL
* URL to an existing file that needs to be backed up
*
* @param nNumBackups
* Specifies the maximum number of backups to allow for
* the file. This value gets truncated to [1..max] where
* max currently is 10 and defined in the implementation.
* It is used in tryPush() and tryPop() calls to cleanup/
* reduce the number of existing backups
/** Constructor to handle Backups of the given file, will internally
* detect configuration values and URL to initial registrymodifications
* and thus the User configuration directory
*/
BackupFileHelper(
const OUString& rBaseURL,
sal_uInt16 nNumBackups = 5);
BackupFileHelper();
// allow to set static global flag when app had to call _exit()
static void setExitWasCalled();
static bool getExitWasCalled();
// static helper to read config values - these are derived from
// soffice.ini due to cui not being available in all cases. The
// boolean SecureUserConfig is returned.
// Default for SecureUserConfig is false
// Default for SecureUserConfigNumCopies is 0 (zero)
static bool getSecureUserConfig(sal_uInt16& rnSecureUserConfigNumCopies);
/** 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.
* Also may cleanup older backups when NumBackups given in the
* constructor has changed.
*
* @param bCompress
* Defines if the new backup will be compressed when
* added. Default is true
*
* @return bool
* returns true if a new backup was actually created
*/
bool tryPush(bool bCompress = true);
bool tryPush();
/** finds out if a restore is possible
*
@@ -143,15 +128,27 @@ namespace comphelper
private:
// internal helper methods
bool splitBaseURL();
const rtl::OUString getPackDirName() const;
const rtl::OUString getPackFileName(const rtl::OUString& rFileName) const;
bool tryPush_basefile(bool bCompress);
bool tryPush_extensionInfo(bool bCompress);
bool isPopPossible_basefile();
bool isPopPossible_extensionInfo();
bool tryPop_basefile();
bool tryPop_extensionInfo();
const rtl::OUString getPackURL() const;
// file push helpers
bool tryPush_Files(const std::set< OUString >& rDirs, const std::set< std::pair< OUString, OUString > >& rFiles, const OUString& rSourceURL, const OUString& rTargetURL);
bool tryPush_file(const OUString& rSourceURL, const OUString& rTargetURL, const OUString& rName, const OUString& rExt);
// file pop possibilities helper
bool isPopPossible_files(const std::set< OUString >& rDirs, const std::set< std::pair< OUString, OUString > >& rFiles, const OUString& rSourceURL, const OUString& rTargetURL);
static bool isPopPossible_file(const OUString& rSourceURL, const OUString& rTargetURL, const OUString& rName, const OUString& rExt);
// file pop helpers
bool tryPop_files(const std::set< OUString >& rDirs, const std::set< std::pair< OUString, OUString > >& rFiles, const OUString& rSourceURL, const OUString& rTargetURL);
bool tryPop_file(const OUString& rSourceURL, const OUString& rTargetURL, const OUString& rName, const OUString& rExt);
// ExtensionInfo helpers
bool tryPush_extensionInfo(const OUString& rTargetURL);
static bool isPopPossible_extensionInfo(const OUString& rTargetURL);
bool tryPop_extensionInfo(const OUString& rTargetURL);
// FileDirInfo helpers
void fillDirFileInfo();
};
}

View File

@@ -104,7 +104,16 @@ $(call gb_CustomTarget_get_workdir,instsetoo_native/setup)/$(call gb_Helper_get_
) > $@
# for release-builds (building installers) adjust values in openoffice.lst.in
# Added 'SecureUserConfig' flags to enable and safe three registrymodifications.xcu versions
# Added 'SecureUserConfig' flags to enable and safe user config files
# SecureUserConfig : boolean - switches securing on/off - default false
# SecureUserConfigCompress : boolean - defines if backup data will be compressed - default true
# SecureUserConfigNumCopies : integer - defines how many compressed copies of saved content will be kept - default 2
# SecureUserConfigMode: integer - defines what to secure, default is 0
# 0 : only registrymodifications.xcu
# 1 : a selected amount of user-defined configs
# 2 : everything in the user config directory
# SecureUserConfigExtensions: boolean - defines to also safe the extension configuration (which extensions
# are installed, which are activated) - default is true
$(call gb_CustomTarget_get_workdir,instsetoo_native/setup)/$(call gb_Helper_get_rcfile,soffice) :
$(call gb_Output_announce,$(subst $(WORKDIR)/,,$@),$(true),ECH,1)
( \
@@ -120,7 +129,10 @@ $(call gb_CustomTarget_get_workdir,instsetoo_native/setup)/$(call gb_Helper_get_
&& echo 'ProgressTextColor=255,255,255' \
&& echo 'URE_BOOTSTRAP=$${ORIGIN}/$(call gb_Helper_get_rcfile,fundamental)' \
&& echo 'SecureUserConfig=true' \
&& echo 'SecureUserConfigNumCopies=3' \
&& echo 'SecureUserConfigCompress=true' \
&& echo 'SecureUserConfigNumCopies=2' \
&& echo 'SecureUserConfigMode=0' \
&& echo 'SecureUserConfigExtensions=true' \
) > $@
$(call gb_CustomTarget_get_workdir,instsetoo_native/setup)/$(call gb_Helper_get_rcfile,uno) :