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:
@@ -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: */
|
||||
|
@@ -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)
|
||||
|
@@ -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();
|
||||
};
|
||||
}
|
||||
|
||||
|
@@ -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) :
|
||||
|
Reference in New Issue
Block a user